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