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