]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-routing-policy-rule.c
network: add RoutingPolicyRule.Family= setting
[thirdparty/systemd.git] / src / network / networkd-routing-policy-rule.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <net/if.h>
4 #include <linux/fib_rules.h>
5
6 #include "af-list.h"
7 #include "alloc-util.h"
8 #include "conf-parser.h"
9 #include "fileio.h"
10 #include "ip-protocol-list.h"
11 #include "networkd-routing-policy-rule.h"
12 #include "netlink-util.h"
13 #include "networkd-manager.h"
14 #include "networkd-util.h"
15 #include "parse-util.h"
16 #include "socket-util.h"
17 #include "string-util.h"
18 #include "strv.h"
19
20 int routing_policy_rule_new(RoutingPolicyRule **ret) {
21 RoutingPolicyRule *rule;
22
23 rule = new(RoutingPolicyRule, 1);
24 if (!rule)
25 return -ENOMEM;
26
27 *rule = (RoutingPolicyRule) {
28 .table = RT_TABLE_MAIN,
29 };
30
31 *ret = rule;
32 return 0;
33 }
34
35 void routing_policy_rule_free(RoutingPolicyRule *rule) {
36
37 if (!rule)
38 return;
39
40 if (rule->network) {
41 LIST_REMOVE(rules, rule->network->rules, rule);
42 assert(rule->network->n_rules > 0);
43 rule->network->n_rules--;
44
45 if (rule->section)
46 hashmap_remove(rule->network->rules_by_section, rule->section);
47 }
48
49 if (rule->manager) {
50 if (set_get(rule->manager->rules, rule) == rule)
51 set_remove(rule->manager->rules, rule);
52 if (set_get(rule->manager->rules_foreign, rule) == rule)
53 set_remove(rule->manager->rules_foreign, rule);
54 }
55
56 network_config_section_free(rule->section);
57 free(rule->iif);
58 free(rule->oif);
59 free(rule);
60 }
61
62 static int routing_policy_rule_copy(RoutingPolicyRule *dest, RoutingPolicyRule *src) {
63 _cleanup_free_ char *iif = NULL, *oif = NULL;
64
65 assert(dest);
66 assert(src);
67
68 if (src->iif) {
69 iif = strdup(src->iif);
70 if (!iif)
71 return -ENOMEM;
72 }
73
74 if (src->oif) {
75 oif = strdup(src->oif);
76 if (!oif)
77 return -ENOMEM;
78 }
79
80 dest->family = src->family;
81 dest->from = src->from;
82 dest->from_prefixlen = src->from_prefixlen;
83 dest->to = src->to;
84 dest->to_prefixlen = src->to_prefixlen;
85 dest->invert_rule = src->invert_rule;
86 dest->tos = src->tos;
87 dest->fwmark = src->fwmark;
88 dest->fwmask = src->fwmask;
89 dest->priority = src->priority;
90 dest->table = src->table;
91 dest->iif = TAKE_PTR(iif);
92 dest->oif = TAKE_PTR(oif);
93 dest->protocol = src->protocol;
94 dest->sport = src->sport;
95 dest->dport = src->dport;
96
97 return 0;
98 }
99
100 static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash *state) {
101 assert(rule);
102
103 siphash24_compress(&rule->family, sizeof(rule->family), state);
104
105 switch (rule->family) {
106 case AF_INET:
107 case AF_INET6:
108
109 siphash24_compress(&rule->from, FAMILY_ADDRESS_SIZE(rule->family), state);
110 siphash24_compress(&rule->from_prefixlen, sizeof(rule->from_prefixlen), state);
111
112 siphash24_compress(&rule->to, FAMILY_ADDRESS_SIZE(rule->family), state);
113 siphash24_compress(&rule->to_prefixlen, sizeof(rule->to_prefixlen), state);
114
115 siphash24_compress_boolean(rule->invert_rule, state);
116
117 siphash24_compress(&rule->tos, sizeof(rule->tos), state);
118 siphash24_compress(&rule->fwmark, sizeof(rule->fwmark), state);
119 siphash24_compress(&rule->fwmask, sizeof(rule->fwmask), state);
120 siphash24_compress(&rule->priority, sizeof(rule->priority), state);
121 siphash24_compress(&rule->table, sizeof(rule->table), state);
122
123 siphash24_compress(&rule->protocol, sizeof(rule->protocol), state);
124 siphash24_compress(&rule->sport, sizeof(rule->sport), state);
125 siphash24_compress(&rule->dport, sizeof(rule->dport), state);
126
127 if (rule->iif)
128 siphash24_compress(rule->iif, strlen(rule->iif), state);
129
130 if (rule->oif)
131 siphash24_compress(rule->oif, strlen(rule->oif), state);
132
133 break;
134 default:
135 /* treat any other address family as AF_UNSPEC */
136 break;
137 }
138 }
139
140 static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPolicyRule *b) {
141 int r;
142
143 r = CMP(a->family, b->family);
144 if (r != 0)
145 return r;
146
147 switch (a->family) {
148 case AF_INET:
149 case AF_INET6:
150 r = CMP(a->from_prefixlen, b->from_prefixlen);
151 if (r != 0)
152 return r;
153
154 r = CMP(a->to_prefixlen, b->to_prefixlen);
155 if (r != 0)
156 return r;
157
158 r = CMP(a->invert_rule, b->invert_rule);
159 if (r != 0)
160 return r;
161
162 r = CMP(a->tos, b->tos);
163 if (r != 0)
164 return r;
165
166 r = CMP(a->fwmark, b->fwmark);
167 if (r != 0)
168 return r;
169
170 r = CMP(a->fwmask, b->fwmask);
171 if (r != 0)
172 return r;
173
174 r = CMP(a->priority, b->priority);
175 if (r != 0)
176 return r;
177
178 r = CMP(a->table, b->table);
179 if (r != 0)
180 return r;
181
182 r = strcmp_ptr(a->iif, b->iif);
183 if (!r)
184 return r;
185
186 r = strcmp_ptr(a->oif, b->oif);
187 if (!r)
188 return r;
189
190 r = CMP(a->protocol, b->protocol);
191 if (r != 0)
192 return r;
193
194 r = memcmp(&a->sport, &b->sport, sizeof(a->sport));
195 if (r != 0)
196 return r;
197
198 r = memcmp(&a->dport, &b->dport, sizeof(a->dport));
199 if (r != 0)
200 return r;
201
202 r = memcmp(&a->from, &b->from, FAMILY_ADDRESS_SIZE(a->family));
203 if (r != 0)
204 return r;
205
206 return memcmp(&a->to, &b->to, FAMILY_ADDRESS_SIZE(a->family));
207
208 default:
209 /* treat any other address family as AF_UNSPEC */
210 return 0;
211 }
212 }
213
214 DEFINE_PRIVATE_HASH_OPS(routing_policy_rule_hash_ops, RoutingPolicyRule, routing_policy_rule_hash_func, routing_policy_rule_compare_func);
215
216 int routing_policy_rule_get(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
217
218 RoutingPolicyRule *existing;
219
220 assert(m);
221
222 existing = set_get(m->rules, rule);
223 if (existing) {
224 if (ret)
225 *ret = existing;
226 return 1;
227 }
228
229 existing = set_get(m->rules_foreign, rule);
230 if (existing) {
231 if (ret)
232 *ret = existing;
233 return 0;
234 }
235
236 return -ENOENT;
237 }
238
239 int routing_policy_rule_make_local(Manager *m, RoutingPolicyRule *rule) {
240 int r;
241
242 assert(m);
243
244 if (set_contains(m->rules_foreign, rule)) {
245 set_remove(m->rules_foreign, rule);
246
247 r = set_ensure_allocated(&m->rules, &routing_policy_rule_hash_ops);
248 if (r < 0)
249 return r;
250
251 r = set_put(m->rules, rule);
252 if (r < 0)
253 return r;
254 if (r == 0)
255 routing_policy_rule_free(rule);
256 }
257
258 return -ENOENT;
259 }
260
261 static int routing_policy_rule_add_internal(Manager *m, Set **rules, RoutingPolicyRule *in, RoutingPolicyRule **ret) {
262 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
263 int r;
264
265 assert(m);
266 assert(rules);
267 assert(in);
268
269 r = routing_policy_rule_new(&rule);
270 if (r < 0)
271 return r;
272
273 rule->manager = m;
274
275 r = routing_policy_rule_copy(rule, in);
276 if (r < 0)
277 return r;
278
279 r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
280 if (r < 0)
281 return r;
282
283 r = set_put(*rules, rule);
284 if (r < 0)
285 return r;
286 if (r == 0)
287 return -EEXIST;
288
289 if (ret)
290 *ret = rule;
291
292 TAKE_PTR(rule);
293 return 0;
294 }
295
296 static int routing_policy_rule_add(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
297 return routing_policy_rule_add_internal(m, &m->rules, rule, ret);
298 }
299
300 int routing_policy_rule_add_foreign(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
301 return routing_policy_rule_add_internal(m, &m->rules_foreign, rule, ret);
302 }
303
304 static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
305 int r;
306
307 assert(m);
308 assert(link);
309 assert(link->ifname);
310
311 link->routing_policy_rule_remove_messages--;
312
313 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
314 return 1;
315
316 r = sd_netlink_message_get_errno(m);
317 if (r < 0)
318 log_link_warning_errno(link, r, "Could not drop routing policy rule: %m");
319
320 return 1;
321 }
322
323 int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, link_netlink_message_handler_t callback) {
324 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
325 int r;
326
327 assert(routing_policy_rule);
328 assert(link);
329 assert(link->manager);
330 assert(link->manager->rtnl);
331 assert(link->ifindex > 0);
332 assert(IN_SET(routing_policy_rule->family, AF_INET, AF_INET6));
333
334 r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_DELRULE, routing_policy_rule->family);
335 if (r < 0)
336 return log_error_errno(r, "Could not allocate RTM_DELRULE message: %m");
337
338 if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->from) == 0) {
339 r = netlink_message_append_in_addr_union(m, FRA_SRC, routing_policy_rule->family, &routing_policy_rule->from);
340 if (r < 0)
341 return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
342
343 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, routing_policy_rule->from_prefixlen);
344 if (r < 0)
345 return log_error_errno(r, "Could not set source prefix length: %m");
346 }
347
348 if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->to) == 0) {
349 r = netlink_message_append_in_addr_union(m, FRA_DST, routing_policy_rule->family, &routing_policy_rule->to);
350 if (r < 0)
351 return log_error_errno(r, "Could not append FRA_DST attribute: %m");
352
353 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, routing_policy_rule->to_prefixlen);
354 if (r < 0)
355 return log_error_errno(r, "Could not set destination prefix length: %m");
356 }
357
358 r = netlink_call_async(link->manager->rtnl, NULL, m,
359 callback ?: routing_policy_rule_remove_handler,
360 link_netlink_destroy_callback, link);
361 if (r < 0)
362 return log_error_errno(r, "Could not send rtnetlink message: %m");
363
364 link_ref(link);
365
366 return 0;
367 }
368
369 static int routing_policy_rule_new_static(Network *network, const char *filename, unsigned section_line, RoutingPolicyRule **ret) {
370 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
371 _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
372 int r;
373
374 assert(network);
375 assert(ret);
376 assert(!!filename == (section_line > 0));
377
378 if (filename) {
379 r = network_config_section_new(filename, section_line, &n);
380 if (r < 0)
381 return r;
382
383 rule = hashmap_get(network->rules_by_section, n);
384 if (rule) {
385 *ret = TAKE_PTR(rule);
386
387 return 0;
388 }
389 }
390
391 r = routing_policy_rule_new(&rule);
392 if (r < 0)
393 return r;
394
395 rule->network = network;
396 LIST_APPEND(rules, network->rules, rule);
397 network->n_rules++;
398
399 if (filename) {
400 rule->section = TAKE_PTR(n);
401
402 r = hashmap_ensure_allocated(&network->rules_by_section, &network_config_hash_ops);
403 if (r < 0)
404 return r;
405
406 r = hashmap_put(network->rules_by_section, rule->section, rule);
407 if (r < 0)
408 return r;
409 }
410
411 *ret = TAKE_PTR(rule);
412
413 return 0;
414 }
415
416 static int routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
417 int r;
418
419 assert(rtnl);
420 assert(m);
421 assert(link);
422 assert(link->ifname);
423 assert(link->routing_policy_rule_messages > 0);
424
425 link->routing_policy_rule_messages--;
426
427 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
428 return 1;
429
430 r = sd_netlink_message_get_errno(m);
431 if (r < 0 && r != -EEXIST) {
432 log_link_warning_errno(link, r, "Could not add routing policy rule: %m");
433 link_enter_failed(link);
434 return 1;
435 }
436
437 if (link->routing_policy_rule_messages == 0) {
438 log_link_debug(link, "Routing policy rule configured");
439 link->routing_policy_rules_configured = true;
440 link_check_ready(link);
441 }
442
443 return 1;
444 }
445
446 int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netlink_message_handler_t callback) {
447 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
448 int r;
449
450 assert(rule);
451 assert(link);
452 assert(link->ifindex > 0);
453 assert(link->manager);
454 assert(link->manager->rtnl);
455
456 if (rule->family == AF_INET6 && link_sysctl_ipv6_enabled(link) == 0) {
457 log_link_warning(link, "An IPv6 routing policy rule is requested, but IPv6 is disabled by sysctl, ignoring.");
458 return 0;
459 }
460
461 r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
462 if (r < 0)
463 return log_error_errno(r, "Could not allocate RTM_NEWRULE message: %m");
464
465 if (in_addr_is_null(rule->family, &rule->from) == 0) {
466 r = netlink_message_append_in_addr_union(m, FRA_SRC, rule->family, &rule->from);
467 if (r < 0)
468 return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
469
470 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen);
471 if (r < 0)
472 return log_error_errno(r, "Could not set source prefix length: %m");
473 }
474
475 if (in_addr_is_null(rule->family, &rule->to) == 0) {
476 r = netlink_message_append_in_addr_union(m, FRA_DST, rule->family, &rule->to);
477 if (r < 0)
478 return log_error_errno(r, "Could not append FRA_DST attribute: %m");
479
480 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen);
481 if (r < 0)
482 return log_error_errno(r, "Could not set destination prefix length: %m");
483 }
484
485 r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
486 if (r < 0)
487 return log_error_errno(r, "Could not append FRA_PRIORITY attribute: %m");
488
489 if (rule->tos > 0) {
490 r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
491 if (r < 0)
492 return log_error_errno(r, "Could not set ip rule tos: %m");
493 }
494
495 if (rule->table < 256) {
496 r = sd_rtnl_message_routing_policy_rule_set_table(m, rule->table);
497 if (r < 0)
498 return log_error_errno(r, "Could not set ip rule table: %m");
499 } else {
500 r = sd_rtnl_message_routing_policy_rule_set_table(m, RT_TABLE_UNSPEC);
501 if (r < 0)
502 return log_error_errno(r, "Could not set ip rule table: %m");
503
504 r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table);
505 if (r < 0)
506 return log_error_errno(r, "Could not append FRA_TABLE attribute: %m");
507 }
508
509 if (rule->fwmark > 0) {
510 r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark);
511 if (r < 0)
512 return log_error_errno(r, "Could not append FRA_FWMARK attribute: %m");
513 }
514
515 if (rule->fwmask > 0) {
516 r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
517 if (r < 0)
518 return log_error_errno(r, "Could not append FRA_FWMASK attribute: %m");
519 }
520
521 if (rule->iif) {
522 r = sd_netlink_message_append_string(m, FRA_IFNAME, rule->iif);
523 if (r < 0)
524 return log_error_errno(r, "Could not append FRA_IFNAME attribute: %m");
525 }
526
527 if (rule->oif) {
528 r = sd_netlink_message_append_string(m, FRA_OIFNAME, rule->oif);
529 if (r < 0)
530 return log_error_errno(r, "Could not append FRA_OIFNAME attribute: %m");
531 }
532
533 r = sd_netlink_message_append_u8(m, FRA_IP_PROTO, rule->protocol);
534 if (r < 0)
535 return log_error_errno(r, "Could not append FRA_IP_PROTO attribute: %m");
536
537 if (rule->sport.start != 0 || rule->sport.end != 0) {
538 r = sd_netlink_message_append_data(m, FRA_SPORT_RANGE, &rule->sport, sizeof(rule->sport));
539 if (r < 0)
540 return log_error_errno(r, "Could not append FRA_SPORT_RANGE attribute: %m");
541 }
542
543 if (rule->dport.start != 0 || rule->dport.end != 0) {
544 r = sd_netlink_message_append_data(m, FRA_DPORT_RANGE, &rule->dport, sizeof(rule->dport));
545 if (r < 0)
546 return log_error_errno(r, "Could not append FRA_DPORT_RANGE attribute: %m");
547 }
548
549 if (rule->invert_rule) {
550 r = sd_rtnl_message_routing_policy_rule_set_flags(m, FIB_RULE_INVERT);
551 if (r < 0)
552 return log_error_errno(r, "Could not append FIB_RULE_INVERT attribute: %m");
553 }
554
555 rule->link = link;
556
557 r = netlink_call_async(link->manager->rtnl, NULL, m,
558 callback ?: routing_policy_rule_handler,
559 link_netlink_destroy_callback, link);
560 if (r < 0)
561 return log_error_errno(r, "Could not send rtnetlink message: %m");
562
563 link_ref(link);
564
565 r = routing_policy_rule_add(link->manager, rule, NULL);
566 if (r < 0)
567 return log_error_errno(r, "Could not add rule: %m");
568
569 return 1;
570 }
571
572 int routing_policy_rule_section_verify(RoutingPolicyRule *rule) {
573 int r;
574
575 if (section_is_invalid(rule->section))
576 return -EINVAL;
577
578 if ((rule->family == AF_INET && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6)) ||
579 (rule->family == AF_INET6 && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4)))
580 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
581 "%s: address family specified by Family= conflicts with the address "
582 "specified by To= or From=. Ignoring [RoutingPolicyRule] section from line %u.",
583 rule->section->filename, rule->section->line);
584
585 if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_IPV6)) {
586 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule6 = NULL;
587
588 assert(rule->family == AF_UNSPEC);
589
590 /* When Family=both, we need to copy the section, AF_INET and AF_INET6. */
591
592 r = routing_policy_rule_new_static(rule->network, NULL, 0, &rule6);
593 if (r < 0)
594 return r;
595
596 r = routing_policy_rule_copy(rule6, rule);
597 if (r < 0)
598 return r;
599
600 rule->family = AF_INET;
601 rule6->family = AF_INET6;
602
603 TAKE_PTR(rule6);
604 }
605
606 if (rule->family == AF_UNSPEC) {
607 if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6))
608 rule->family = AF_INET6;
609 else
610 rule->family = AF_INET;
611 }
612
613 return 0;
614 }
615
616 static int parse_fwmark_fwmask(const char *s, uint32_t *fwmark, uint32_t *fwmask) {
617 _cleanup_free_ char *f = NULL;
618 char *p;
619 int r;
620
621 assert(s);
622
623 f = strdup(s);
624 if (!f)
625 return -ENOMEM;
626
627 p = strchr(f, '/');
628 if (p)
629 *p++ = '\0';
630
631 r = safe_atou32(f, fwmark);
632 if (r < 0)
633 return log_error_errno(r, "Failed to parse RPDB rule firewall mark, ignoring: %s", f);
634
635 if (p) {
636 r = safe_atou32(p, fwmask);
637 if (r < 0)
638 return log_error_errno(r, "Failed to parse RPDB rule mask, ignoring: %s", f);
639 }
640
641 return 0;
642 }
643
644 int config_parse_routing_policy_rule_tos(
645 const char *unit,
646 const char *filename,
647 unsigned line,
648 const char *section,
649 unsigned section_line,
650 const char *lvalue,
651 int ltype,
652 const char *rvalue,
653 void *data,
654 void *userdata) {
655
656 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
657 Network *network = userdata;
658 int r;
659
660 assert(filename);
661 assert(section);
662 assert(lvalue);
663 assert(rvalue);
664 assert(data);
665
666 r = routing_policy_rule_new_static(network, filename, section_line, &n);
667 if (r < 0)
668 return r;
669
670 r = safe_atou8(rvalue, &n->tos);
671 if (r < 0) {
672 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule tos, ignoring: %s", rvalue);
673 return 0;
674 }
675
676 n = NULL;
677
678 return 0;
679 }
680
681 int config_parse_routing_policy_rule_priority(
682 const char *unit,
683 const char *filename,
684 unsigned line,
685 const char *section,
686 unsigned section_line,
687 const char *lvalue,
688 int ltype,
689 const char *rvalue,
690 void *data,
691 void *userdata) {
692
693 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
694 Network *network = userdata;
695 int r;
696
697 assert(filename);
698 assert(section);
699 assert(lvalue);
700 assert(rvalue);
701 assert(data);
702
703 r = routing_policy_rule_new_static(network, filename, section_line, &n);
704 if (r < 0)
705 return r;
706
707 r = safe_atou32(rvalue, &n->priority);
708 if (r < 0) {
709 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule priority, ignoring: %s", rvalue);
710 return 0;
711 }
712
713 n = NULL;
714
715 return 0;
716 }
717
718 int config_parse_routing_policy_rule_table(
719 const char *unit,
720 const char *filename,
721 unsigned line,
722 const char *section,
723 unsigned section_line,
724 const char *lvalue,
725 int ltype,
726 const char *rvalue,
727 void *data,
728 void *userdata) {
729
730 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
731 Network *network = userdata;
732 int r;
733
734 assert(filename);
735 assert(section);
736 assert(lvalue);
737 assert(rvalue);
738 assert(data);
739
740 r = routing_policy_rule_new_static(network, filename, section_line, &n);
741 if (r < 0)
742 return r;
743
744 r = safe_atou32(rvalue, &n->table);
745 if (r < 0) {
746 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule table, ignoring: %s", rvalue);
747 return 0;
748 }
749
750 n = NULL;
751
752 return 0;
753 }
754
755 int config_parse_routing_policy_rule_fwmark_mask(
756 const char *unit,
757 const char *filename,
758 unsigned line,
759 const char *section,
760 unsigned section_line,
761 const char *lvalue,
762 int ltype,
763 const char *rvalue,
764 void *data,
765 void *userdata) {
766
767 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
768 Network *network = userdata;
769 int r;
770
771 assert(filename);
772 assert(section);
773 assert(lvalue);
774 assert(rvalue);
775 assert(data);
776
777 r = routing_policy_rule_new_static(network, filename, section_line, &n);
778 if (r < 0)
779 return r;
780
781 r = parse_fwmark_fwmask(rvalue, &n->fwmark, &n->fwmask);
782 if (r < 0) {
783 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue);
784 return 0;
785 }
786
787 n = NULL;
788
789 return 0;
790 }
791
792 int config_parse_routing_policy_rule_prefix(
793 const char *unit,
794 const char *filename,
795 unsigned line,
796 const char *section,
797 unsigned section_line,
798 const char *lvalue,
799 int ltype,
800 const char *rvalue,
801 void *data,
802 void *userdata) {
803
804 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
805 Network *network = userdata;
806 union in_addr_union *buffer;
807 uint8_t *prefixlen;
808 int r;
809
810 assert(filename);
811 assert(section);
812 assert(lvalue);
813 assert(rvalue);
814 assert(data);
815
816 r = routing_policy_rule_new_static(network, filename, section_line, &n);
817 if (r < 0)
818 return r;
819
820 if (streq(lvalue, "To")) {
821 buffer = &n->to;
822 prefixlen = &n->to_prefixlen;
823 } else {
824 buffer = &n->from;
825 prefixlen = &n->from_prefixlen;
826 }
827
828 if (n->family == AF_UNSPEC)
829 r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
830 else
831 r = in_addr_prefix_from_string(rvalue, n->family, buffer, prefixlen);
832 if (r < 0) {
833 log_syntax(unit, LOG_ERR, filename, line, r, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue);
834 return 0;
835 }
836
837 n = NULL;
838
839 return 0;
840 }
841
842 int config_parse_routing_policy_rule_device(
843 const char *unit,
844 const char *filename,
845 unsigned line,
846 const char *section,
847 unsigned section_line,
848 const char *lvalue,
849 int ltype,
850 const char *rvalue,
851 void *data,
852 void *userdata) {
853
854 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
855 Network *network = userdata;
856 int r;
857
858 assert(filename);
859 assert(section);
860 assert(lvalue);
861 assert(rvalue);
862 assert(data);
863
864 r = routing_policy_rule_new_static(network, filename, section_line, &n);
865 if (r < 0)
866 return r;
867
868 if (!ifname_valid(rvalue)) {
869 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse '%s' interface name, ignoring: %s", lvalue, rvalue);
870 return 0;
871 }
872
873 if (streq(lvalue, "IncomingInterface")) {
874 r = free_and_strdup(&n->iif, rvalue);
875 if (r < 0)
876 return log_oom();
877 } else {
878 r = free_and_strdup(&n->oif, rvalue);
879 if (r < 0)
880 return log_oom();
881 }
882
883 n = NULL;
884
885 return 0;
886 }
887
888 int config_parse_routing_policy_rule_port_range(
889 const char *unit,
890 const char *filename,
891 unsigned line,
892 const char *section,
893 unsigned section_line,
894 const char *lvalue,
895 int ltype,
896 const char *rvalue,
897 void *data,
898 void *userdata) {
899 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
900 Network *network = userdata;
901 uint16_t low, high;
902 int r;
903
904 assert(filename);
905 assert(section);
906 assert(lvalue);
907 assert(rvalue);
908 assert(data);
909
910 r = routing_policy_rule_new_static(network, filename, section_line, &n);
911 if (r < 0)
912 return r;
913
914 r = parse_ip_port_range(rvalue, &low, &high);
915 if (r < 0) {
916 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse routing policy rule port range '%s'", rvalue);
917 return 0;
918 }
919
920 if (streq(lvalue, "SourcePort")) {
921 n->sport.start = low;
922 n->sport.end = high;
923 } else {
924 n->dport.start = low;
925 n->dport.end = high;
926 }
927
928 n = NULL;
929
930 return 0;
931 }
932
933 int config_parse_routing_policy_rule_ip_protocol(
934 const char *unit,
935 const char *filename,
936 unsigned line,
937 const char *section,
938 unsigned section_line,
939 const char *lvalue,
940 int ltype,
941 const char *rvalue,
942 void *data,
943 void *userdata) {
944
945 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
946 Network *network = userdata;
947 int r;
948
949 assert(filename);
950 assert(section);
951 assert(lvalue);
952 assert(rvalue);
953 assert(data);
954
955 r = routing_policy_rule_new_static(network, filename, section_line, &n);
956 if (r < 0)
957 return r;
958
959 r = parse_ip_protocol(rvalue);
960 if (r < 0) {
961 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IP protocol '%s' for routing policy rule, ignoring: %m", rvalue);
962 return 0;
963 }
964
965 n->protocol = r;
966
967 n = NULL;
968
969 return 0;
970 }
971
972 int config_parse_routing_policy_rule_invert(
973 const char *unit,
974 const char *filename,
975 unsigned line,
976 const char *section,
977 unsigned section_line,
978 const char *lvalue,
979 int ltype,
980 const char *rvalue,
981 void *data,
982 void *userdata) {
983
984 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
985 Network *network = userdata;
986 int r;
987
988 assert(filename);
989 assert(section);
990 assert(lvalue);
991 assert(rvalue);
992 assert(data);
993
994 r = routing_policy_rule_new_static(network, filename, section_line, &n);
995 if (r < 0)
996 return r;
997
998 r = parse_boolean(rvalue);
999 if (r < 0) {
1000 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule invert, ignoring: %s", rvalue);
1001 return 0;
1002 }
1003
1004 n->invert_rule = r;
1005
1006 n = NULL;
1007
1008 return 0;
1009 }
1010
1011 int config_parse_routing_policy_rule_family(
1012 const char *unit,
1013 const char *filename,
1014 unsigned line,
1015 const char *section,
1016 unsigned section_line,
1017 const char *lvalue,
1018 int ltype,
1019 const char *rvalue,
1020 void *data,
1021 void *userdata) {
1022
1023 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1024 Network *network = userdata;
1025 AddressFamily a;
1026 int r;
1027
1028 assert(filename);
1029 assert(section);
1030 assert(lvalue);
1031 assert(rvalue);
1032 assert(data);
1033
1034 r = routing_policy_rule_new_static(network, filename, section_line, &n);
1035 if (r < 0)
1036 return r;
1037
1038 a = routing_policy_rule_address_family_from_string(rvalue);
1039 if (a < 0) {
1040 log_syntax(unit, LOG_ERR, filename, line, 0,
1041 "Invalid address family '%s', ignoring.", rvalue);
1042 return 0;
1043 }
1044
1045 n->address_family = a;
1046 n = NULL;
1047
1048 return 0;
1049 }
1050
1051 static int routing_policy_rule_read_full_file(const char *state_file, char **ret) {
1052 _cleanup_free_ char *s = NULL;
1053 size_t size;
1054 int r;
1055
1056 assert(state_file);
1057
1058 r = read_full_file(state_file, &s, &size);
1059 if (r == -ENOENT)
1060 return -ENODATA;
1061 if (r < 0)
1062 return r;
1063 if (size <= 0)
1064 return -ENODATA;
1065
1066 *ret = TAKE_PTR(s);
1067
1068 return size;
1069 }
1070
1071 int routing_policy_serialize_rules(Set *rules, FILE *f) {
1072 RoutingPolicyRule *rule = NULL;
1073 Iterator i;
1074 int r;
1075
1076 assert(f);
1077
1078 SET_FOREACH(rule, rules, i) {
1079 _cleanup_free_ char *from_str = NULL, *to_str = NULL;
1080 bool space = false;
1081 const char *family_str;
1082
1083 fputs("RULE=", f);
1084
1085 if (!in_addr_is_null(rule->family, &rule->from)) {
1086 r = in_addr_to_string(rule->family, &rule->from, &from_str);
1087 if (r < 0)
1088 return r;
1089
1090 fprintf(f, "from=%s/%hhu",
1091 from_str, rule->from_prefixlen);
1092 space = true;
1093 }
1094
1095 if (!in_addr_is_null(rule->family, &rule->to)) {
1096 r = in_addr_to_string(rule->family, &rule->to, &to_str);
1097 if (r < 0)
1098 return r;
1099
1100 fprintf(f, "%sto=%s/%hhu",
1101 space ? " " : "",
1102 to_str, rule->to_prefixlen);
1103 space = true;
1104 }
1105
1106 family_str = af_to_name(rule->family);
1107 if (family_str)
1108 fprintf(f, "%sfamily=%s",
1109 space ? " " : "",
1110 family_str);
1111
1112 if (rule->tos != 0) {
1113 fprintf(f, "%stos=%hhu",
1114 space ? " " : "",
1115 rule->tos);
1116 space = true;
1117 }
1118
1119 fprintf(f, "%spriority=%"PRIu32,
1120 space ? " " : "",
1121 rule->priority);
1122
1123 if (rule->fwmark != 0) {
1124 fprintf(f, "%sfwmark=%"PRIu32"/%"PRIu32,
1125 space ? " " : "",
1126 rule->fwmark, rule->fwmask);
1127 space = true;
1128 }
1129
1130 if (rule->iif) {
1131 fprintf(f, "%siif=%s",
1132 space ? " " : "",
1133 rule->iif);
1134 space = true;
1135 }
1136
1137 if (rule->oif) {
1138 fprintf(f, "%soif=%s",
1139 space ? " " : "",
1140 rule->oif);
1141 space = true;
1142 }
1143
1144 if (rule->protocol != 0) {
1145 fprintf(f, "%sprotocol=%hhu",
1146 space ? " " : "",
1147 rule->protocol);
1148 space = true;
1149 }
1150
1151 if (rule->sport.start != 0 || rule->sport.end != 0) {
1152 fprintf(f, "%ssourcesport=%"PRIu16"-%"PRIu16,
1153 space ? " " : "",
1154 rule->sport.start, rule->sport.end);
1155 space = true;
1156 }
1157
1158 if (rule->dport.start != 0 || rule->dport.end != 0) {
1159 fprintf(f, "%sdestinationport=%"PRIu16"-%"PRIu16,
1160 space ? " " : "",
1161 rule->dport.start, rule->dport.end);
1162 space = true;
1163 }
1164
1165 fprintf(f, "%stable=%"PRIu32 "\n",
1166 space ? " " : "",
1167 rule->table);
1168 }
1169
1170 return 0;
1171 }
1172
1173 int routing_policy_load_rules(const char *state_file, Set **rules) {
1174 _cleanup_strv_free_ char **l = NULL;
1175 _cleanup_free_ char *data = NULL;
1176 uint16_t low = 0, high = 0;
1177 const char *p;
1178 char **i;
1179 int r;
1180
1181 assert(state_file);
1182 assert(rules);
1183
1184 r = routing_policy_rule_read_full_file(state_file, &data);
1185 if (r <= 0)
1186 return r;
1187
1188 l = strv_split_newlines(data);
1189 if (!l)
1190 return -ENOMEM;
1191
1192 r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
1193 if (r < 0)
1194 return r;
1195
1196 STRV_FOREACH(i, l) {
1197 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
1198
1199 p = startswith(*i, "RULE=");
1200 if (!p)
1201 continue;
1202
1203 r = routing_policy_rule_new(&rule);
1204 if (r < 0)
1205 return r;
1206
1207 for (;;) {
1208 _cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
1209
1210 r = extract_first_word(&p, &word, NULL, 0);
1211 if (r < 0)
1212 return r;
1213 if (r == 0)
1214 break;
1215
1216 r = split_pair(word, "=", &a, &b);
1217 if (r < 0)
1218 continue;
1219
1220 if (STR_IN_SET(a, "from", "to")) {
1221 union in_addr_union *buffer;
1222 uint8_t *prefixlen;
1223
1224 if (streq(a, "to")) {
1225 buffer = &rule->to;
1226 prefixlen = &rule->to_prefixlen;
1227 } else {
1228 buffer = &rule->from;
1229 prefixlen = &rule->from_prefixlen;
1230 }
1231
1232 r = in_addr_prefix_from_string_auto(b, &rule->family, buffer, prefixlen);
1233 if (r < 0) {
1234 log_error_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
1235 continue;
1236 }
1237
1238 } else if (streq(a, "family")) {
1239 r = af_from_name(b);
1240 if (r < 0) {
1241 log_error_errno(r, "Failed to parse RPDB rule family, ignoring: %s", b);
1242 continue;
1243 }
1244 rule->family = r;
1245 } else if (streq(a, "tos")) {
1246 r = safe_atou8(b, &rule->tos);
1247 if (r < 0) {
1248 log_error_errno(r, "Failed to parse RPDB rule tos, ignoring: %s", b);
1249 continue;
1250 }
1251 } else if (streq(a, "table")) {
1252 r = safe_atou32(b, &rule->table);
1253 if (r < 0) {
1254 log_error_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b);
1255 continue;
1256 }
1257 } else if (streq(a, "priority")) {
1258 r = safe_atou32(b, &rule->priority);
1259 if (r < 0) {
1260 log_error_errno(r, "Failed to parse RPDB rule priority, ignoring: %s", b);
1261 continue;
1262 }
1263 } else if (streq(a, "fwmark")) {
1264
1265 r = parse_fwmark_fwmask(b, &rule->fwmark, &rule->fwmask);
1266 if (r < 0) {
1267 log_error_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
1268 continue;
1269 }
1270 } else if (streq(a, "iif")) {
1271
1272 if (free_and_strdup(&rule->iif, b) < 0)
1273 return log_oom();
1274
1275 } else if (streq(a, "oif")) {
1276
1277 if (free_and_strdup(&rule->oif, b) < 0)
1278 return log_oom();
1279 } else if (streq(a, "protocol")) {
1280 r = safe_atou8(b, &rule->protocol);
1281 if (r < 0) {
1282 log_error_errno(r, "Failed to parse RPDB rule protocol, ignoring: %s", b);
1283 continue;
1284 }
1285 } else if (streq(a, "sourceport")) {
1286
1287 r = parse_ip_port_range(b, &low, &high);
1288 if (r < 0) {
1289 log_error_errno(r, "Invalid routing policy rule source port range, ignoring assignment:'%s'", b);
1290 continue;
1291 }
1292
1293 rule->sport.start = low;
1294 rule->sport.end = high;
1295
1296 } else if (streq(a, "destinationport")) {
1297
1298 r = parse_ip_port_range(b, &low, &high);
1299 if (r < 0) {
1300 log_error_errno(r, "Invalid routing policy rule destination port range, ignoring assignment:'%s'", b);
1301 continue;
1302 }
1303
1304 rule->dport.start = low;
1305 rule->dport.end = high;
1306 }
1307 }
1308
1309 r = set_put(*rules, rule);
1310 if (r < 0) {
1311 log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", p);
1312 continue;
1313 }
1314 if (r > 0)
1315 rule = NULL;
1316 }
1317
1318 return 0;
1319 }
1320
1321 static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule *rule) {
1322 RoutingPolicyRule *link_rule;
1323 Iterator i;
1324 Link *link;
1325
1326 assert(m);
1327 assert(rule);
1328
1329 HASHMAP_FOREACH(link, m->links, i) {
1330 if (!link->network)
1331 continue;
1332
1333 LIST_FOREACH(rules, link_rule, link->network->rules)
1334 if (routing_policy_rule_compare_func(link_rule, rule) == 0)
1335 return true;
1336 }
1337
1338 return false;
1339 }
1340
1341 void routing_policy_rule_purge(Manager *m, Link *link) {
1342 RoutingPolicyRule *rule, *existing;
1343 Iterator i;
1344 int r;
1345
1346 assert(m);
1347 assert(link);
1348
1349 SET_FOREACH(rule, m->rules_saved, i) {
1350 existing = set_get(m->rules_foreign, rule);
1351 if (!existing)
1352 continue; /* Saved rule does not exist anymore. */
1353
1354 if (manager_links_have_routing_policy_rule(m, existing))
1355 continue; /* Existing links have the saved rule. */
1356
1357 /* Existing links do not have the saved rule. Let's drop the rule now, and re-configure it
1358 * later when it is requested. */
1359
1360 r = routing_policy_rule_remove(existing, link, NULL);
1361 if (r < 0) {
1362 log_warning_errno(r, "Could not remove routing policy rules: %m");
1363 continue;
1364 }
1365
1366 link->routing_policy_rule_remove_messages++;
1367
1368 assert_se(set_remove(m->rules_foreign, existing) == existing);
1369 routing_policy_rule_free(existing);
1370 }
1371 }