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