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