]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-routing-policy-rule.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / network / networkd-routing-policy-rule.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2017 Susant Sahani
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <net/if.h>
22 #include <linux/fib_rules.h>
23
24 #include "alloc-util.h"
25 #include "conf-parser.h"
26 #include "fileio.h"
27 #include "networkd-routing-policy-rule.h"
28 #include "netlink-util.h"
29 #include "networkd-manager.h"
30 #include "parse-util.h"
31 #include "socket-util.h"
32 #include "string-util.h"
33
34 int routing_policy_rule_new(RoutingPolicyRule **ret) {
35 RoutingPolicyRule *rule;
36
37 rule = new0(RoutingPolicyRule, 1);
38 if (!rule)
39 return -ENOMEM;
40
41 rule->family = AF_INET;
42 rule->table = RT_TABLE_MAIN;
43
44 *ret = rule;
45 return 0;
46 }
47
48 void routing_policy_rule_free(RoutingPolicyRule *rule) {
49
50 if (!rule)
51 return;
52
53 if (rule->network) {
54 LIST_REMOVE(rules, rule->network->rules, rule);
55 assert(rule->network->n_rules > 0);
56 rule->network->n_rules--;
57
58 if (rule->section) {
59 hashmap_remove(rule->network->rules_by_section, rule->section);
60 network_config_section_free(rule->section);
61 }
62
63 if (rule->network->manager) {
64 set_remove(rule->network->manager->rules, rule);
65 set_remove(rule->network->manager->rules_foreign, rule);
66 }
67 }
68
69 free(rule);
70 }
71
72 static void routing_policy_rule_hash_func(const void *b, struct siphash *state) {
73 const RoutingPolicyRule *rule = b;
74
75 assert(rule);
76
77 siphash24_compress(&rule->family, sizeof(rule->family), state);
78
79 switch (rule->family) {
80 case AF_INET:
81 case AF_INET6:
82
83 siphash24_compress(&rule->from, FAMILY_ADDRESS_SIZE(rule->family), state);
84 siphash24_compress(&rule->from_prefixlen, sizeof(rule->from_prefixlen), state);
85
86 siphash24_compress(&rule->to, FAMILY_ADDRESS_SIZE(rule->family), state);
87 siphash24_compress(&rule->to_prefixlen, sizeof(rule->to_prefixlen), state);
88
89 siphash24_compress(&rule->tos, sizeof(rule->tos), state);
90 siphash24_compress(&rule->fwmark, sizeof(rule->fwmark), state);
91 siphash24_compress(&rule->table, sizeof(rule->table), state);
92
93 break;
94 default:
95 /* treat any other address family as AF_UNSPEC */
96 break;
97 }
98 }
99
100 static int routing_policy_rule_compare_func(const void *_a, const void *_b) {
101 const RoutingPolicyRule *a = _a, *b = _b;
102 int r;
103
104 if (a->family < b->family)
105 return -1;
106 if (a->family > b->family)
107 return 1;
108
109 switch (a->family) {
110 case AF_INET:
111 case AF_INET6:
112 if (a->from_prefixlen < b->from_prefixlen)
113 return -1;
114 if (a->from_prefixlen > b->from_prefixlen)
115 return 1;
116
117 if (a->to_prefixlen < b->to_prefixlen)
118 return -1;
119 if (a->to_prefixlen > b->to_prefixlen)
120 return 1;
121
122 if (a->tos < b->tos)
123 return -1;
124 if (a->tos > b->tos)
125 return 1;
126
127 if (a->fwmask < b->fwmark)
128 return -1;
129 if (a->fwmask > b->fwmark)
130 return 1;
131
132 if (a->table < b->table)
133 return -1;
134 if (a->table > b->table)
135 return 1;
136
137 r = memcmp(&a->from, &b->from, FAMILY_ADDRESS_SIZE(a->family));
138 if (r != 0)
139 return r;
140
141 return memcmp(&a->to, &b->to, FAMILY_ADDRESS_SIZE(a->family));
142
143 default:
144 /* treat any other address family as AF_UNSPEC */
145 return 0;
146 }
147 }
148
149 const struct hash_ops routing_policy_rule_hash_ops = {
150 .hash = routing_policy_rule_hash_func,
151 .compare = routing_policy_rule_compare_func
152 };
153
154 int routing_policy_rule_get(Manager *m,
155 int family,
156 const union in_addr_union *from,
157 uint8_t from_prefixlen,
158 const union in_addr_union *to,
159 uint8_t to_prefixlen,
160 uint8_t tos,
161 uint32_t fwmark,
162 uint32_t table,
163 RoutingPolicyRule **ret) {
164
165 RoutingPolicyRule rule, *existing;
166
167 assert_return(m, -1);
168
169 rule = (RoutingPolicyRule) {
170 .family = family,
171 .from = *from,
172 .from_prefixlen = from_prefixlen,
173 .to = *to,
174 .to_prefixlen = to_prefixlen,
175 .tos = tos,
176 .fwmark = fwmark,
177 .table = table,
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
201 int 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
219 static int routing_policy_rule_add_internal(Set **rules,
220 int family,
221 const union in_addr_union *from,
222 uint8_t from_prefixlen,
223 const union in_addr_union *to,
224 uint8_t to_prefixlen,
225 uint8_t tos,
226 uint32_t fwmark,
227 uint32_t table,
228 RoutingPolicyRule **ret) {
229
230 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *rule = NULL;
231 int r;
232
233 assert_return(rules, -EINVAL);
234
235 r = routing_policy_rule_new(&rule);
236 if (r < 0)
237 return r;
238
239 rule->family = family;
240 rule->from = *from;
241 rule->from_prefixlen = from_prefixlen;
242 rule->to = *to;
243 rule->to_prefixlen = to_prefixlen;
244 rule->tos = tos;
245 rule->fwmark = fwmark;
246 rule->table = table;
247
248 r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
249 if (r < 0)
250 return r;
251
252 r = set_put(*rules, rule);
253 if (r < 0)
254 return r;
255
256 if (ret)
257 *ret = rule;
258
259 rule = NULL;
260
261 return 0;
262 }
263
264 int routing_policy_rule_add(Manager *m,
265 int family,
266 const union in_addr_union *from,
267 uint8_t from_prefixlen,
268 const union in_addr_union *to,
269 uint8_t to_prefixlen,
270 uint8_t tos,
271 uint32_t fwmark,
272 uint32_t table,
273 RoutingPolicyRule **ret) {
274
275 return routing_policy_rule_add_internal(&m->rules, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, ret);
276 }
277
278 int routing_policy_rule_add_foreign(Manager *m,
279 int family,
280 const union in_addr_union *from,
281 uint8_t from_prefixlen,
282 const union in_addr_union *to,
283 uint8_t to_prefixlen,
284 uint8_t tos,
285 uint32_t fwmark,
286 uint32_t table,
287 RoutingPolicyRule **ret) {
288 return routing_policy_rule_add_internal(&m->rules_foreign, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, ret);
289 }
290
291 static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
292 _cleanup_link_unref_ Link *link = userdata;
293 int r;
294
295 assert(m);
296 assert(link);
297 assert(link->ifname);
298
299 link->link_messages--;
300
301 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
302 return 1;
303
304 r = sd_netlink_message_get_errno(m);
305 if (r < 0)
306 log_link_warning_errno(link, r, "Could not drop routing policy rule: %m");
307
308 return 1;
309 }
310
311 int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, sd_netlink_message_handler_t callback) {
312 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
313 int r;
314
315 assert(routing_policy_rule);
316 assert(link);
317 assert(link->manager);
318 assert(link->manager->rtnl);
319 assert(link->ifindex > 0);
320 assert(IN_SET(routing_policy_rule->family, AF_INET, AF_INET6));
321
322 r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_DELRULE, routing_policy_rule->family);
323 if (r < 0)
324 return log_error_errno(r, "Could not allocate RTM_DELRULE message: %m");
325
326 if (!in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->from)) {
327 if (routing_policy_rule->family == AF_INET)
328 r = sd_netlink_message_append_in_addr(m, FRA_SRC, &routing_policy_rule->from.in);
329 else
330 r = sd_netlink_message_append_in6_addr(m, FRA_SRC, &routing_policy_rule->from.in6);
331
332 if (r < 0)
333 return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
334
335 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, routing_policy_rule->from_prefixlen);
336 if (r < 0)
337 return log_error_errno(r, "Could not set source prefix length: %m");
338 }
339
340 if (!in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->to)) {
341 if (routing_policy_rule->family == AF_INET)
342 r = sd_netlink_message_append_in_addr(m, FRA_DST, &routing_policy_rule->to.in);
343 else
344 r = sd_netlink_message_append_in6_addr(m, FRA_DST, &routing_policy_rule->to.in6);
345
346 if (r < 0)
347 return log_error_errno(r, "Could not append FRA_DST attribute: %m");
348
349 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, routing_policy_rule->to_prefixlen);
350 if (r < 0)
351 return log_error_errno(r, "Could not set destination prefix length: %m");
352 }
353
354 r = sd_netlink_call_async(link->manager->rtnl, m, callback, link, 0, NULL);
355 if (r < 0)
356 return log_error_errno(r, "Could not send rtnetlink message: %m");
357
358 link_ref(link);
359
360 return 0;
361 }
362
363 static int routing_policy_rule_new_static(Network *network, const char *filename, unsigned section_line, RoutingPolicyRule **ret) {
364 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *rule = NULL;
365 _cleanup_network_config_section_free_ NetworkConfigSection *n = NULL;
366 int r;
367
368 assert(network);
369 assert(ret);
370 assert(!!filename == (section_line > 0));
371
372 r = network_config_section_new(filename, section_line, &n);
373 if (r < 0)
374 return r;
375
376 rule = hashmap_get(network->rules_by_section, n);
377 if (rule) {
378 *ret = rule;
379 rule = NULL;
380
381 return 0;
382 }
383
384 r = routing_policy_rule_new(&rule);
385 if (r < 0)
386 return r;
387
388 rule->section = n;
389 rule->network = network;
390 n = NULL;
391
392 r = hashmap_put(network->rules_by_section, rule->section, rule);
393 if (r < 0)
394 return r;
395
396 LIST_APPEND(rules, network->rules, rule);
397 network->n_rules++;
398
399 *ret = rule;
400 rule = NULL;
401
402 return 0;
403 }
404
405 int link_routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
406 _cleanup_link_unref_ Link *link = userdata;
407 int r;
408
409 assert(rtnl);
410 assert(m);
411 assert(link);
412 assert(link->ifname);
413 assert(link->link_messages > 0);
414
415 link->link_messages--;
416
417 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
418 return 1;
419
420 r = sd_netlink_message_get_errno(m);
421 if (r < 0 && r != -EEXIST)
422 log_link_warning_errno(link, r, "Could not add routing policy rule: %m");
423
424 if (link->link_messages == 0)
425 log_link_debug(link, "Routing policy rule configured");
426
427 return 1;
428 }
429
430 int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, sd_netlink_message_handler_t callback, bool update) {
431 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
432 int r;
433
434 assert(rule);
435 assert(link);
436 assert(link->ifindex > 0);
437 assert(link->manager);
438 assert(link->manager->rtnl);
439
440 r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
441 if (r < 0)
442 return log_error_errno(r, "Could not allocate RTM_NEWRULE message: %m");
443
444 if (!in_addr_is_null(rule->family, &rule->from)) {
445 if (rule->family == AF_INET)
446 r = sd_netlink_message_append_in_addr(m, FRA_SRC, &rule->from.in);
447 else
448 r = sd_netlink_message_append_in6_addr(m, FRA_SRC, &rule->from.in6);
449
450 if (r < 0)
451 return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
452
453 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen);
454 if (r < 0)
455 return log_error_errno(r, "Could not set source prefix length: %m");
456 }
457
458 if (!in_addr_is_null(rule->family, &rule->to)) {
459 if (rule->family == AF_INET)
460 r = sd_netlink_message_append_in_addr(m, FRA_DST, &rule->to.in);
461 else
462 r = sd_netlink_message_append_in6_addr(m, FRA_DST, &rule->to.in6);
463
464 if (r < 0)
465 return log_error_errno(r, "Could not append FRA_DST attribute: %m");
466
467 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen);
468 if (r < 0)
469 return log_error_errno(r, "Could not set destination prefix length: %m");
470 }
471
472 r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
473 if (r < 0)
474 return log_error_errno(r, "Could not append FRA_PRIORITY attribute: %m");
475
476 if (rule->tos > 0) {
477 r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
478 if (r < 0)
479 return log_error_errno(r, "Could not set ip rule tos: %m");
480 }
481
482 if (rule->table < 256) {
483 r = sd_rtnl_message_routing_policy_rule_set_table(m, rule->table);
484 if (r < 0)
485 return log_error_errno(r, "Could not set ip rule table: %m");
486 } else {
487 r = sd_rtnl_message_routing_policy_rule_set_table(m, RT_TABLE_UNSPEC);
488 if (r < 0)
489 return log_error_errno(r, "Could not set ip rule table: %m");
490
491 r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table);
492 if (r < 0)
493 return log_error_errno(r, "Could not append FRA_TABLE attribute: %m");
494 }
495
496 if (rule->fwmark > 0) {
497 r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark);
498 if (r < 0)
499 return log_error_errno(r, "Could not append FRA_FWMARK attribute: %m");
500 }
501
502 if (rule->fwmask > 0) {
503 r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
504 if (r < 0)
505 return log_error_errno(r, "Could not append FRA_FWMASK attribute: %m");
506 }
507
508 rule->link = link;
509
510 r = sd_netlink_call_async(link->manager->rtnl, m, callback, link, 0, NULL);
511 if (r < 0)
512 return log_error_errno(r, "Could not send rtnetlink message: %m");
513
514 link_ref(link);
515
516 r = routing_policy_rule_add(link->manager, rule->family, &rule->from, rule->from_prefixlen, &rule->to,
517 rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, NULL);
518 if (r < 0)
519 return log_error_errno(r, "Could not add rule : %m");
520
521 return 0;
522 }
523
524 static int parse_fwmark_fwmask(const char *s, uint32_t *fwmark, uint32_t *fwmask) {
525 _cleanup_free_ char *f = NULL;
526 char *p;
527 int r;
528
529 assert(s);
530
531 f = strdup(s);
532 if (!f)
533 return -ENOMEM;
534
535 p = strchr(f, '/');
536 if (p)
537 *p++ = '\0';
538
539 r = safe_atou32(f, fwmark);
540 if (r < 0)
541 return log_error_errno(r, "Failed to parse RPDB rule firewall mark, ignoring: %s", f);
542
543 if (p) {
544 r = safe_atou32(p, fwmask);
545 if (r < 0)
546 return log_error_errno(r, "Failed to parse RPDB rule mask, ignoring: %s", f);
547 }
548
549 return 0;
550 }
551
552 int config_parse_routing_policy_rule_tos(
553 const char *unit,
554 const char *filename,
555 unsigned line,
556 const char *section,
557 unsigned section_line,
558 const char *lvalue,
559 int ltype,
560 const char *rvalue,
561 void *data,
562 void *userdata) {
563
564 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
565 Network *network = userdata;
566 int r;
567
568 assert(filename);
569 assert(section);
570 assert(lvalue);
571 assert(rvalue);
572 assert(data);
573
574 r = routing_policy_rule_new_static(network, filename, section_line, &n);
575 if (r < 0)
576 return r;
577
578 r = safe_atou8(rvalue, &n->tos);
579 if (r < 0) {
580 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule tos, ignoring: %s", rvalue);
581 return 0;
582 }
583
584 n = NULL;
585
586 return 0;
587 }
588
589 int config_parse_routing_policy_rule_priority(
590 const char *unit,
591 const char *filename,
592 unsigned line,
593 const char *section,
594 unsigned section_line,
595 const char *lvalue,
596 int ltype,
597 const char *rvalue,
598 void *data,
599 void *userdata) {
600
601 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
602 Network *network = userdata;
603 int r;
604
605 assert(filename);
606 assert(section);
607 assert(lvalue);
608 assert(rvalue);
609 assert(data);
610
611 r = routing_policy_rule_new_static(network, filename, section_line, &n);
612 if (r < 0)
613 return r;
614
615 r = safe_atou32(rvalue, &n->priority);
616 if (r < 0) {
617 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule priority, ignoring: %s", rvalue);
618 return 0;
619 }
620
621 n = NULL;
622
623 return 0;
624 }
625
626 int config_parse_routing_policy_rule_table(
627 const char *unit,
628 const char *filename,
629 unsigned line,
630 const char *section,
631 unsigned section_line,
632 const char *lvalue,
633 int ltype,
634 const char *rvalue,
635 void *data,
636 void *userdata) {
637
638 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
639 Network *network = userdata;
640 int r;
641
642 assert(filename);
643 assert(section);
644 assert(lvalue);
645 assert(rvalue);
646 assert(data);
647
648 r = routing_policy_rule_new_static(network, filename, section_line, &n);
649 if (r < 0)
650 return r;
651
652 r = safe_atou32(rvalue, &n->table);
653 if (r < 0) {
654 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule table, ignoring: %s", rvalue);
655 return 0;
656 }
657
658 n = NULL;
659
660 return 0;
661 }
662
663 int config_parse_routing_policy_rule_fwmark_mask(
664 const char *unit,
665 const char *filename,
666 unsigned line,
667 const char *section,
668 unsigned section_line,
669 const char *lvalue,
670 int ltype,
671 const char *rvalue,
672 void *data,
673 void *userdata) {
674
675 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
676 Network *network = userdata;
677 int r;
678
679 assert(filename);
680 assert(section);
681 assert(lvalue);
682 assert(rvalue);
683 assert(data);
684
685 r = routing_policy_rule_new_static(network, filename, section_line, &n);
686 if (r < 0)
687 return r;
688
689 r = parse_fwmark_fwmask(rvalue, &n->fwmark, &n->fwmask);
690 if (r < 0) {
691 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue);
692 return 0;
693 }
694
695 n = NULL;
696
697 return 0;
698 }
699
700 int config_parse_routing_policy_rule_prefix(
701 const char *unit,
702 const char *filename,
703 unsigned line,
704 const char *section,
705 unsigned section_line,
706 const char *lvalue,
707 int ltype,
708 const char *rvalue,
709 void *data,
710 void *userdata) {
711
712 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
713 Network *network = userdata;
714 union in_addr_union buffer;
715 uint8_t prefixlen;
716 int r;
717
718 assert(filename);
719 assert(section);
720 assert(lvalue);
721 assert(rvalue);
722 assert(data);
723
724 r = routing_policy_rule_new_static(network, filename, section_line, &n);
725 if (r < 0)
726 return r;
727
728 r = in_addr_prefix_from_string(rvalue, AF_INET, &buffer, &prefixlen);
729 if (r < 0) {
730 r = in_addr_prefix_from_string(rvalue, AF_INET6, &buffer, &prefixlen);
731 if (r < 0) {
732 log_syntax(unit, LOG_ERR, filename, line, r, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue);
733 return 0;
734 }
735
736 n->family = AF_INET6;
737 } else
738 n->family = AF_INET;
739
740 if (streq(lvalue, "To")) {
741 n->to = buffer;
742 n->to_prefixlen = prefixlen;
743 } else {
744 n->from = buffer;
745 n->from_prefixlen = prefixlen;
746 }
747
748 n = NULL;
749
750 return 0;
751 }
752
753 static int routing_policy_rule_read_full_file(char *state_file, char **ret) {
754 _cleanup_free_ char *s = NULL;
755 size_t size;
756 int r;
757
758 assert(state_file);
759
760 r = read_full_file(state_file, &s, &size);
761 if (r == -ENOENT)
762 return -ENODATA;
763 if (r < 0)
764 return r;
765 if (size <= 0)
766 return -ENODATA;
767
768 *ret = s;
769 s = NULL;
770
771 return size;
772 }
773
774 int routing_policy_rule_load(Manager *m) {
775 _cleanup_strv_free_ char **l = NULL;
776 _cleanup_free_ char *data = NULL;
777 const char *p;
778 char **i;
779 int r;
780
781 assert(m);
782
783 r = routing_policy_rule_read_full_file(m->state_file, &data);
784 if (r <= 0)
785 return r;
786
787 l = strv_split_newlines(data);
788 if (!l)
789 return -ENOMEM;
790
791 r = set_ensure_allocated(&m->rules_saved, &routing_policy_rule_hash_ops);
792 if (r < 0)
793 return r;
794
795 STRV_FOREACH(i, l) {
796 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *rule = NULL;
797
798 p = startswith(*i, "RULE=");
799 if (!p)
800 continue;
801
802 p = strchr(*i, '=');
803 p++;
804
805 r = routing_policy_rule_new(&rule);
806 if (r < 0)
807 return r;
808
809 for (;;) {
810 _cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
811 union in_addr_union buffer;
812 uint8_t prefixlen;
813
814 r = extract_first_word(&p, &word, NULL, 0);
815 if (r < 0)
816 return r;
817 if (r == 0)
818 break;
819
820 r = split_pair(word, "=", &a, &b);
821 if (r < 0)
822 continue;
823
824 if (STR_IN_SET(a, "from", "to")) {
825
826 r = in_addr_prefix_from_string(b, AF_INET, &buffer, &prefixlen);
827 if (r < 0) {
828 r = in_addr_prefix_from_string(b, AF_INET6, &buffer, &prefixlen);
829 if (r < 0) {
830 log_error_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
831 continue;
832 }
833
834 rule->family = AF_INET6;
835 } else
836 rule->family = AF_INET;
837
838 if (streq(a, "to")) {
839 rule->to = buffer;
840 rule->to_prefixlen = prefixlen;
841 } else {
842 rule->from = buffer;
843 rule->from_prefixlen = prefixlen;
844 }
845 } else if (streq(a, "tos")) {
846 r = safe_atou8(b, &rule->tos);
847 if (r < 0) {
848 log_error_errno(r, "Failed to parse RPDB rule tos, ignoring: %s", b);
849 continue;
850 }
851 } else if (streq(a, "table")) {
852 r = safe_atou32(b, &rule->table);
853 if (r < 0) {
854 log_error_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b);
855 continue;
856 }
857 } else if (streq(a, "fwmark")) {
858
859 r = parse_fwmark_fwmask(a, &rule->fwmark, &rule->fwmask);
860 if (r < 0) {
861 log_error_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
862 continue;
863 }
864 }
865 }
866
867 r = set_put(m->rules_saved, rule);
868 if (r < 0) {
869 log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", p);
870 continue;
871 }
872
873 rule = NULL;
874 }
875
876 return 0;
877 }
878
879 void routing_policy_rule_purge(Manager *m, Link *link) {
880 RoutingPolicyRule *rule, *existing;
881 Iterator i;
882 int r;
883
884 assert(m);
885 assert(link);
886
887 SET_FOREACH(rule, m->rules_saved, i) {
888 existing = set_get(m->rules_foreign, rule);
889 if (existing) {
890
891 r = routing_policy_rule_remove(rule, link, routing_policy_rule_remove_handler);
892 if (r < 0) {
893 log_warning_errno(r, "Could not remove routing policy rules: %m");
894 continue;
895 }
896
897 link->link_messages++;
898 }
899 }
900 }