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