]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-routing-policy-rule.c
Merge pull request #10094 from keszybz/wants-loading
[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 _cleanup_(link_unrefp) 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, m, callback, link, 0, NULL);
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 r = network_config_section_new(filename, section_line, &n);
392 if (r < 0)
393 return r;
394
395 rule = hashmap_get(network->rules_by_section, n);
396 if (rule) {
397 *ret = TAKE_PTR(rule);
398
399 return 0;
400 }
401
402 r = routing_policy_rule_new(&rule);
403 if (r < 0)
404 return r;
405
406 rule->section = TAKE_PTR(n);
407 rule->network = network;
408
409 r = hashmap_put(network->rules_by_section, rule->section, rule);
410 if (r < 0)
411 return r;
412
413 LIST_APPEND(rules, network->rules, rule);
414 network->n_rules++;
415
416 *ret = TAKE_PTR(rule);
417
418 return 0;
419 }
420
421 int link_routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
422 _cleanup_(link_unrefp) Link *link = userdata;
423 int r;
424
425 assert(rtnl);
426 assert(m);
427 assert(link);
428 assert(link->ifname);
429 assert(link->routing_policy_rule_messages > 0);
430
431 link->routing_policy_rule_messages--;
432
433 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
434 return 1;
435
436 r = sd_netlink_message_get_errno(m);
437 if (r < 0 && r != -EEXIST)
438 log_link_warning_errno(link, r, "Could not add routing policy rule: %m");
439
440 if (link->routing_policy_rule_messages == 0) {
441 log_link_debug(link, "Routing policy rule configured");
442 link->routing_policy_rules_configured = true;
443 link_check_ready(link);
444 }
445
446 return 1;
447 }
448
449 int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, sd_netlink_message_handler_t callback, bool update) {
450 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
451 int r;
452
453 assert(rule);
454 assert(link);
455 assert(link->ifindex > 0);
456 assert(link->manager);
457 assert(link->manager->rtnl);
458
459 r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
460 if (r < 0)
461 return log_error_errno(r, "Could not allocate RTM_NEWRULE message: %m");
462
463 if (!in_addr_is_null(rule->family, &rule->from)) {
464 if (rule->family == AF_INET)
465 r = sd_netlink_message_append_in_addr(m, FRA_SRC, &rule->from.in);
466 else
467 r = sd_netlink_message_append_in6_addr(m, FRA_SRC, &rule->from.in6);
468
469 if (r < 0)
470 return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
471
472 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen);
473 if (r < 0)
474 return log_error_errno(r, "Could not set source prefix length: %m");
475 }
476
477 if (!in_addr_is_null(rule->family, &rule->to)) {
478 if (rule->family == AF_INET)
479 r = sd_netlink_message_append_in_addr(m, FRA_DST, &rule->to.in);
480 else
481 r = sd_netlink_message_append_in6_addr(m, FRA_DST, &rule->to.in6);
482
483 if (r < 0)
484 return log_error_errno(r, "Could not append FRA_DST attribute: %m");
485
486 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen);
487 if (r < 0)
488 return log_error_errno(r, "Could not set destination prefix length: %m");
489 }
490
491 r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
492 if (r < 0)
493 return log_error_errno(r, "Could not append FRA_PRIORITY attribute: %m");
494
495 if (rule->tos > 0) {
496 r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
497 if (r < 0)
498 return log_error_errno(r, "Could not set ip rule tos: %m");
499 }
500
501 if (rule->table < 256) {
502 r = sd_rtnl_message_routing_policy_rule_set_table(m, rule->table);
503 if (r < 0)
504 return log_error_errno(r, "Could not set ip rule table: %m");
505 } else {
506 r = sd_rtnl_message_routing_policy_rule_set_table(m, RT_TABLE_UNSPEC);
507 if (r < 0)
508 return log_error_errno(r, "Could not set ip rule table: %m");
509
510 r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table);
511 if (r < 0)
512 return log_error_errno(r, "Could not append FRA_TABLE attribute: %m");
513 }
514
515 if (rule->fwmark > 0) {
516 r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark);
517 if (r < 0)
518 return log_error_errno(r, "Could not append FRA_FWMARK attribute: %m");
519 }
520
521 if (rule->fwmask > 0) {
522 r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
523 if (r < 0)
524 return log_error_errno(r, "Could not append FRA_FWMASK attribute: %m");
525 }
526
527 if (rule->iif) {
528 r = sd_netlink_message_append_string(m, FRA_IFNAME, rule->iif);
529 if (r < 0)
530 return log_error_errno(r, "Could not append FRA_IFNAME attribute: %m");
531 }
532
533 if (rule->oif) {
534 r = sd_netlink_message_append_string(m, FRA_OIFNAME, rule->oif);
535 if (r < 0)
536 return log_error_errno(r, "Could not append FRA_OIFNAME attribute: %m");
537 }
538
539 rule->link = link;
540
541 r = sd_netlink_call_async(link->manager->rtnl, m, callback, link, 0, NULL);
542 if (r < 0)
543 return log_error_errno(r, "Could not send rtnetlink message: %m");
544
545 link_ref(link);
546
547 r = routing_policy_rule_add(link->manager, rule->family, &rule->from, rule->from_prefixlen, &rule->to,
548 rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, rule->iif, rule->oif, NULL);
549 if (r < 0)
550 return log_error_errno(r, "Could not add rule : %m");
551
552 return 0;
553 }
554
555 static int parse_fwmark_fwmask(const char *s, uint32_t *fwmark, uint32_t *fwmask) {
556 _cleanup_free_ char *f = NULL;
557 char *p;
558 int r;
559
560 assert(s);
561
562 f = strdup(s);
563 if (!f)
564 return -ENOMEM;
565
566 p = strchr(f, '/');
567 if (p)
568 *p++ = '\0';
569
570 r = safe_atou32(f, fwmark);
571 if (r < 0)
572 return log_error_errno(r, "Failed to parse RPDB rule firewall mark, ignoring: %s", f);
573
574 if (p) {
575 r = safe_atou32(p, fwmask);
576 if (r < 0)
577 return log_error_errno(r, "Failed to parse RPDB rule mask, ignoring: %s", f);
578 }
579
580 return 0;
581 }
582
583 int config_parse_routing_policy_rule_tos(
584 const char *unit,
585 const char *filename,
586 unsigned line,
587 const char *section,
588 unsigned section_line,
589 const char *lvalue,
590 int ltype,
591 const char *rvalue,
592 void *data,
593 void *userdata) {
594
595 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
596 Network *network = userdata;
597 int r;
598
599 assert(filename);
600 assert(section);
601 assert(lvalue);
602 assert(rvalue);
603 assert(data);
604
605 r = routing_policy_rule_new_static(network, filename, section_line, &n);
606 if (r < 0)
607 return r;
608
609 r = safe_atou8(rvalue, &n->tos);
610 if (r < 0) {
611 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule tos, ignoring: %s", rvalue);
612 return 0;
613 }
614
615 n = NULL;
616
617 return 0;
618 }
619
620 int config_parse_routing_policy_rule_priority(
621 const char *unit,
622 const char *filename,
623 unsigned line,
624 const char *section,
625 unsigned section_line,
626 const char *lvalue,
627 int ltype,
628 const char *rvalue,
629 void *data,
630 void *userdata) {
631
632 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
633 Network *network = userdata;
634 int r;
635
636 assert(filename);
637 assert(section);
638 assert(lvalue);
639 assert(rvalue);
640 assert(data);
641
642 r = routing_policy_rule_new_static(network, filename, section_line, &n);
643 if (r < 0)
644 return r;
645
646 r = safe_atou32(rvalue, &n->priority);
647 if (r < 0) {
648 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule priority, ignoring: %s", rvalue);
649 return 0;
650 }
651
652 n = NULL;
653
654 return 0;
655 }
656
657 int config_parse_routing_policy_rule_table(
658 const char *unit,
659 const char *filename,
660 unsigned line,
661 const char *section,
662 unsigned section_line,
663 const char *lvalue,
664 int ltype,
665 const char *rvalue,
666 void *data,
667 void *userdata) {
668
669 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
670 Network *network = userdata;
671 int r;
672
673 assert(filename);
674 assert(section);
675 assert(lvalue);
676 assert(rvalue);
677 assert(data);
678
679 r = routing_policy_rule_new_static(network, filename, section_line, &n);
680 if (r < 0)
681 return r;
682
683 r = safe_atou32(rvalue, &n->table);
684 if (r < 0) {
685 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule table, ignoring: %s", rvalue);
686 return 0;
687 }
688
689 n = NULL;
690
691 return 0;
692 }
693
694 int config_parse_routing_policy_rule_fwmark_mask(
695 const char *unit,
696 const char *filename,
697 unsigned line,
698 const char *section,
699 unsigned section_line,
700 const char *lvalue,
701 int ltype,
702 const char *rvalue,
703 void *data,
704 void *userdata) {
705
706 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
707 Network *network = userdata;
708 int r;
709
710 assert(filename);
711 assert(section);
712 assert(lvalue);
713 assert(rvalue);
714 assert(data);
715
716 r = routing_policy_rule_new_static(network, filename, section_line, &n);
717 if (r < 0)
718 return r;
719
720 r = parse_fwmark_fwmask(rvalue, &n->fwmark, &n->fwmask);
721 if (r < 0) {
722 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue);
723 return 0;
724 }
725
726 n = NULL;
727
728 return 0;
729 }
730
731 int config_parse_routing_policy_rule_prefix(
732 const char *unit,
733 const char *filename,
734 unsigned line,
735 const char *section,
736 unsigned section_line,
737 const char *lvalue,
738 int ltype,
739 const char *rvalue,
740 void *data,
741 void *userdata) {
742
743 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
744 Network *network = userdata;
745 union in_addr_union buffer;
746 uint8_t prefixlen;
747 int r;
748
749 assert(filename);
750 assert(section);
751 assert(lvalue);
752 assert(rvalue);
753 assert(data);
754
755 r = routing_policy_rule_new_static(network, filename, section_line, &n);
756 if (r < 0)
757 return r;
758
759 r = in_addr_prefix_from_string(rvalue, AF_INET, &buffer, &prefixlen);
760 if (r < 0) {
761 r = in_addr_prefix_from_string(rvalue, AF_INET6, &buffer, &prefixlen);
762 if (r < 0) {
763 log_syntax(unit, LOG_ERR, filename, line, r, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue);
764 return 0;
765 }
766
767 n->family = AF_INET6;
768 } else
769 n->family = AF_INET;
770
771 if (streq(lvalue, "To")) {
772 n->to = buffer;
773 n->to_prefixlen = prefixlen;
774 } else {
775 n->from = buffer;
776 n->from_prefixlen = prefixlen;
777 }
778
779 n = NULL;
780
781 return 0;
782 }
783
784 int config_parse_routing_policy_rule_device(
785 const char *unit,
786 const char *filename,
787 unsigned line,
788 const char *section,
789 unsigned section_line,
790 const char *lvalue,
791 int ltype,
792 const char *rvalue,
793 void *data,
794 void *userdata) {
795
796 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
797 Network *network = userdata;
798 int r;
799
800 assert(filename);
801 assert(section);
802 assert(lvalue);
803 assert(rvalue);
804 assert(data);
805
806 r = routing_policy_rule_new_static(network, filename, section_line, &n);
807 if (r < 0)
808 return r;
809
810 if (!ifname_valid(rvalue)) {
811 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse '%s' interface name, ignoring: %s", lvalue, rvalue);
812 return 0;
813 }
814
815 if (streq(lvalue, "IncomingInterface")) {
816 r = free_and_strdup(&n->iif, rvalue);
817 if (r < 0)
818 return log_oom();
819 } else {
820 r = free_and_strdup(&n->oif, rvalue);
821 if (r < 0)
822 return log_oom();
823 }
824
825 n = NULL;
826
827 return 0;
828 }
829
830 static int routing_policy_rule_read_full_file(const char *state_file, char **ret) {
831 _cleanup_free_ char *s = NULL;
832 size_t size;
833 int r;
834
835 assert(state_file);
836
837 r = read_full_file(state_file, &s, &size);
838 if (r == -ENOENT)
839 return -ENODATA;
840 if (r < 0)
841 return r;
842 if (size <= 0)
843 return -ENODATA;
844
845 *ret = TAKE_PTR(s);
846
847 return size;
848 }
849
850 int routing_policy_serialize_rules(Set *rules, FILE *f) {
851 RoutingPolicyRule *rule = NULL;
852 Iterator i;
853 int r;
854
855 assert(f);
856
857 SET_FOREACH(rule, rules, i) {
858 _cleanup_free_ char *from_str = NULL, *to_str = NULL;
859 bool space = false;
860
861 fputs("RULE=", f);
862
863 if (!in_addr_is_null(rule->family, &rule->from)) {
864 r = in_addr_to_string(rule->family, &rule->from, &from_str);
865 if (r < 0)
866 return r;
867
868 fprintf(f, "from=%s/%hhu",
869 from_str, rule->from_prefixlen);
870 space = true;
871 }
872
873 if (!in_addr_is_null(rule->family, &rule->to)) {
874 r = in_addr_to_string(rule->family, &rule->to, &to_str);
875 if (r < 0)
876 return r;
877
878 fprintf(f, "%sto=%s/%hhu",
879 space ? " " : "",
880 to_str, rule->to_prefixlen);
881 space = true;
882 }
883
884 if (rule->tos != 0) {
885 fprintf(f, "%stos=%hhu",
886 space ? " " : "",
887 rule->tos);
888 space = true;
889 }
890
891 if (rule->fwmark != 0) {
892 fprintf(f, "%sfwmark=%"PRIu32"/%"PRIu32,
893 space ? " " : "",
894 rule->fwmark, rule->fwmask);
895 space = true;
896 }
897
898 if (rule->iif) {
899 fprintf(f, "%siif=%s",
900 space ? " " : "",
901 rule->iif);
902 space = true;
903 }
904
905 if (rule->oif) {
906 fprintf(f, "%soif=%s",
907 space ? " " : "",
908 rule->oif);
909 space = true;
910 }
911
912 fprintf(f, "%stable=%"PRIu32 "\n",
913 space ? " " : "",
914 rule->table);
915 }
916
917 return 0;
918 }
919
920 int routing_policy_load_rules(const char *state_file, Set **rules) {
921 _cleanup_strv_free_ char **l = NULL;
922 _cleanup_free_ char *data = NULL;
923 const char *p;
924 char **i;
925 int r;
926
927 assert(state_file);
928 assert(rules);
929
930 r = routing_policy_rule_read_full_file(state_file, &data);
931 if (r <= 0)
932 return r;
933
934 l = strv_split_newlines(data);
935 if (!l)
936 return -ENOMEM;
937
938 r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
939 if (r < 0)
940 return r;
941
942 STRV_FOREACH(i, l) {
943 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
944
945 p = startswith(*i, "RULE=");
946 if (!p)
947 continue;
948
949 r = routing_policy_rule_new(&rule);
950 if (r < 0)
951 return r;
952
953 for (;;) {
954 _cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
955 union in_addr_union buffer;
956 uint8_t prefixlen;
957
958 r = extract_first_word(&p, &word, NULL, 0);
959 if (r < 0)
960 return r;
961 if (r == 0)
962 break;
963
964 r = split_pair(word, "=", &a, &b);
965 if (r < 0)
966 continue;
967
968 if (STR_IN_SET(a, "from", "to")) {
969
970 r = in_addr_prefix_from_string(b, AF_INET, &buffer, &prefixlen);
971 if (r < 0) {
972 r = in_addr_prefix_from_string(b, AF_INET6, &buffer, &prefixlen);
973 if (r < 0) {
974 log_error_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
975 continue;
976 }
977
978 rule->family = AF_INET6;
979 } else
980 rule->family = AF_INET;
981
982 if (streq(a, "to")) {
983 rule->to = buffer;
984 rule->to_prefixlen = prefixlen;
985 } else {
986 rule->from = buffer;
987 rule->from_prefixlen = prefixlen;
988 }
989 } else if (streq(a, "tos")) {
990 r = safe_atou8(b, &rule->tos);
991 if (r < 0) {
992 log_error_errno(r, "Failed to parse RPDB rule tos, ignoring: %s", b);
993 continue;
994 }
995 } else if (streq(a, "table")) {
996 r = safe_atou32(b, &rule->table);
997 if (r < 0) {
998 log_error_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b);
999 continue;
1000 }
1001 } else if (streq(a, "fwmark")) {
1002
1003 r = parse_fwmark_fwmask(b, &rule->fwmark, &rule->fwmask);
1004 if (r < 0) {
1005 log_error_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
1006 continue;
1007 }
1008 } else if (streq(a, "iif")) {
1009
1010 if (free_and_strdup(&rule->iif, b) < 0)
1011 return log_oom();
1012
1013 } else if (streq(a, "oif")) {
1014
1015 if (free_and_strdup(&rule->oif, b) < 0)
1016 return log_oom();
1017 }
1018 }
1019
1020 r = set_put(*rules, rule);
1021 if (r < 0) {
1022 log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", p);
1023 continue;
1024 }
1025
1026 rule = NULL;
1027 }
1028
1029 return 0;
1030 }
1031
1032 void routing_policy_rule_purge(Manager *m, Link *link) {
1033 RoutingPolicyRule *rule, *existing;
1034 Iterator i;
1035 int r;
1036
1037 assert(m);
1038 assert(link);
1039
1040 SET_FOREACH(rule, m->rules_saved, i) {
1041 existing = set_get(m->rules_foreign, rule);
1042 if (existing) {
1043
1044 r = routing_policy_rule_remove(rule, link, routing_policy_rule_remove_handler);
1045 if (r < 0) {
1046 log_warning_errno(r, "Could not remove routing policy rules: %m");
1047 continue;
1048 }
1049
1050 link->routing_policy_rule_remove_messages++;
1051 }
1052 }
1053 }