]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-routing-policy-rule.c
manager: fix connecting to bus when dbus is actually around (#7205)
[thirdparty/systemd.git] / src / network / networkd-routing-policy-rule.c
CommitLineData
bce67bbe
SS
1/***
2 This file is part of systemd.
3
4 Copyright 2017 Susant Sahani
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
20#include <net/if.h>
21#include <linux/fib_rules.h>
22
23#include "alloc-util.h"
24#include "conf-parser.h"
25#include "fileio.h"
26#include "networkd-routing-policy-rule.h"
27#include "netlink-util.h"
28#include "networkd-manager.h"
29#include "parse-util.h"
30#include "socket-util.h"
31#include "string-util.h"
32
33int routing_policy_rule_new(RoutingPolicyRule **ret) {
34 RoutingPolicyRule *rule;
35
36 rule = new0(RoutingPolicyRule, 1);
37 if (!rule)
38 return -ENOMEM;
39
40 rule->family = AF_INET;
41 rule->table = RT_TABLE_MAIN;
42
43 *ret = rule;
44 return 0;
45}
46
47void routing_policy_rule_free(RoutingPolicyRule *rule) {
48
49 if (!rule)
50 return;
51
52 if (rule->network) {
53 LIST_REMOVE(rules, rule->network->rules, rule);
54 assert(rule->network->n_rules > 0);
55 rule->network->n_rules--;
56
57 if (rule->section) {
58 hashmap_remove(rule->network->rules_by_section, rule->section);
59 network_config_section_free(rule->section);
60 }
61
62 if (rule->network->manager) {
63 set_remove(rule->network->manager->rules, rule);
64 set_remove(rule->network->manager->rules_foreign, rule);
65 }
66 }
67
68 free(rule);
69}
70
71static void routing_policy_rule_hash_func(const void *b, struct siphash *state) {
72 const RoutingPolicyRule *rule = b;
73
74 assert(rule);
75
76 siphash24_compress(&rule->family, sizeof(rule->family), state);
77
78 switch (rule->family) {
79 case AF_INET:
80 case AF_INET6:
81
82 siphash24_compress(&rule->from, FAMILY_ADDRESS_SIZE(rule->family), state);
83 siphash24_compress(&rule->from_prefixlen, sizeof(rule->from_prefixlen), state);
84
85 siphash24_compress(&rule->to, FAMILY_ADDRESS_SIZE(rule->family), state);
86 siphash24_compress(&rule->to_prefixlen, sizeof(rule->to_prefixlen), state);
87
88 siphash24_compress(&rule->tos, sizeof(rule->tos), state);
89 siphash24_compress(&rule->fwmark, sizeof(rule->fwmark), state);
90 siphash24_compress(&rule->table, sizeof(rule->table), state);
91
92 break;
93 default:
94 /* treat any other address family as AF_UNSPEC */
95 break;
96 }
97}
98
99static int routing_policy_rule_compare_func(const void *_a, const void *_b) {
100 const RoutingPolicyRule *a = _a, *b = _b;
101 int r;
102
103 if (a->family < b->family)
104 return -1;
105 if (a->family > b->family)
106 return 1;
107
108 switch (a->family) {
109 case AF_INET:
110 case AF_INET6:
111 if (a->from_prefixlen < b->from_prefixlen)
112 return -1;
113 if (a->from_prefixlen > b->from_prefixlen)
114 return 1;
115
116 if (a->to_prefixlen < b->to_prefixlen)
117 return -1;
118 if (a->to_prefixlen > b->to_prefixlen)
119 return 1;
120
121 if (a->tos < b->tos)
122 return -1;
123 if (a->tos > b->tos)
124 return 1;
125
126 if (a->fwmask < b->fwmark)
127 return -1;
128 if (a->fwmask > b->fwmark)
129 return 1;
130
131 if (a->table < b->table)
132 return -1;
133 if (a->table > b->table)
134 return 1;
135
136 r = memcmp(&a->from, &b->from, FAMILY_ADDRESS_SIZE(a->family));
137 if (r != 0)
138 return r;
139
140 return memcmp(&a->to, &b->to, FAMILY_ADDRESS_SIZE(a->family));
141
142 default:
143 /* treat any other address family as AF_UNSPEC */
144 return 0;
145 }
146}
147
148const struct hash_ops routing_policy_rule_hash_ops = {
149 .hash = routing_policy_rule_hash_func,
150 .compare = routing_policy_rule_compare_func
151};
152
153int routing_policy_rule_get(Manager *m,
154 int family,
155 const union in_addr_union *from,
156 uint8_t from_prefixlen,
157 const union in_addr_union *to,
158 uint8_t to_prefixlen,
159 uint8_t tos,
160 uint32_t fwmark,
161 uint32_t table,
162 RoutingPolicyRule **ret) {
163
164 RoutingPolicyRule rule, *existing;
165
166 assert_return(m, -1);
167
168 rule = (RoutingPolicyRule) {
169 .family = family,
170 .from = *from,
171 .from_prefixlen = from_prefixlen,
172 .to = *to,
173 .to_prefixlen = to_prefixlen,
174 .tos = tos,
175 .fwmark = fwmark,
176 .table = table,
177 };
178
179 if (m->rules) {
180 existing = set_get(m->rules, &rule);
181 if (existing) {
182 if (ret)
183 *ret = existing;
184 return 1;
185 }
186 }
187
188 if (m->rules_foreign) {
189 existing = set_get(m->rules_foreign, &rule);
190 if (existing) {
191 if (ret)
192 *ret = existing;
193 return 1;
194 }
195 }
196
197 return -ENOENT;
198}
199
200int routing_policy_rule_make_local(Manager *m, RoutingPolicyRule *rule) {
201 int r;
202
203 assert(m);
204
205 if (set_contains(m->rules_foreign, rule)) {
206 set_remove(m->rules_foreign, rule);
207
208 r = set_ensure_allocated(&m->rules, &routing_policy_rule_hash_ops);
209 if (r < 0)
210 return r;
211
212 return set_put(m->rules, rule);
213 }
214
215 return -ENOENT;
216}
217
218static int routing_policy_rule_add_internal(Set **rules,
219 int family,
220 const union in_addr_union *from,
221 uint8_t from_prefixlen,
222 const union in_addr_union *to,
223 uint8_t to_prefixlen,
224 uint8_t tos,
225 uint32_t fwmark,
226 uint32_t table,
227 RoutingPolicyRule **ret) {
228
229 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *rule = NULL;
230 int r;
231
232 assert_return(rules, -EINVAL);
233
234 r = routing_policy_rule_new(&rule);
235 if (r < 0)
236 return r;
237
238 rule->family = family;
239 rule->from = *from;
240 rule->from_prefixlen = from_prefixlen;
241 rule->to = *to;
242 rule->to_prefixlen = to_prefixlen;
243 rule->tos = tos;
244 rule->fwmark = fwmark;
245 rule->table = table;
246
247 r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
248 if (r < 0)
249 return r;
250
251 r = set_put(*rules, rule);
252 if (r < 0)
253 return r;
254
255 if (ret)
256 *ret = rule;
257
258 rule = NULL;
259
260 return 0;
261}
262
263int routing_policy_rule_add(Manager *m,
264 int family,
265 const union in_addr_union *from,
266 uint8_t from_prefixlen,
267 const union in_addr_union *to,
268 uint8_t to_prefixlen,
269 uint8_t tos,
270 uint32_t fwmark,
271 uint32_t table,
272 RoutingPolicyRule **ret) {
273
274 return routing_policy_rule_add_internal(&m->rules, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, ret);
275}
276
277int routing_policy_rule_add_foreign(Manager *m,
278 int family,
279 const union in_addr_union *from,
280 uint8_t from_prefixlen,
281 const union in_addr_union *to,
282 uint8_t to_prefixlen,
283 uint8_t tos,
284 uint32_t fwmark,
285 uint32_t table,
286 RoutingPolicyRule **ret) {
287 return routing_policy_rule_add_internal(&m->rules_foreign, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, ret);
288}
289
290static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
291 _cleanup_link_unref_ Link *link = userdata;
292 int r;
293
294 assert(m);
295 assert(link);
296 assert(link->ifname);
297
298 link->link_messages--;
299
300 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
301 return 1;
302
303 r = sd_netlink_message_get_errno(m);
304 if (r < 0)
305 log_link_warning_errno(link, r, "Could not drop routing policy rule: %m");
306
307 return 1;
308}
309
310int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, sd_netlink_message_handler_t callback) {
311 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
312 int r;
313
314 assert(routing_policy_rule);
315 assert(link);
316 assert(link->manager);
317 assert(link->manager->rtnl);
318 assert(link->ifindex > 0);
319 assert(IN_SET(routing_policy_rule->family, AF_INET, AF_INET6));
320
321 r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_DELRULE, routing_policy_rule->family);
322 if (r < 0)
323 return log_error_errno(r, "Could not allocate RTM_DELRULE message: %m");
324
325 if (!in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->from)) {
326 if (routing_policy_rule->family == AF_INET)
327 r = sd_netlink_message_append_in_addr(m, FRA_SRC, &routing_policy_rule->from.in);
328 else
329 r = sd_netlink_message_append_in6_addr(m, FRA_SRC, &routing_policy_rule->from.in6);
330
331 if (r < 0)
332 return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
333
334 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, routing_policy_rule->from_prefixlen);
335 if (r < 0)
336 return log_error_errno(r, "Could not set source prefix length: %m");
337 }
338
339 if (!in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->to)) {
340 if (routing_policy_rule->family == AF_INET)
341 r = sd_netlink_message_append_in_addr(m, FRA_DST, &routing_policy_rule->to.in);
342 else
343 r = sd_netlink_message_append_in6_addr(m, FRA_DST, &routing_policy_rule->to.in6);
344
345 if (r < 0)
346 return log_error_errno(r, "Could not append FRA_DST attribute: %m");
347
348 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, routing_policy_rule->to_prefixlen);
349 if (r < 0)
350 return log_error_errno(r, "Could not set destination prefix length: %m");
351 }
352
353 r = sd_netlink_call_async(link->manager->rtnl, m, callback, link, 0, NULL);
354 if (r < 0)
355 return log_error_errno(r, "Could not send rtnetlink message: %m");
356
357 link_ref(link);
358
359 return 0;
360}
361
362static int routing_policy_rule_new_static(Network *network, const char *filename, unsigned section_line, RoutingPolicyRule **ret) {
363 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *rule = NULL;
364 _cleanup_network_config_section_free_ NetworkConfigSection *n = NULL;
365 int r;
366
367 assert(network);
368 assert(ret);
369 assert(!!filename == (section_line > 0));
370
371 r = network_config_section_new(filename, section_line, &n);
372 if (r < 0)
373 return r;
374
375 rule = hashmap_get(network->rules_by_section, n);
376 if (rule) {
377 *ret = rule;
378 rule = NULL;
379
380 return 0;
381 }
382
383 r = routing_policy_rule_new(&rule);
384 if (r < 0)
385 return r;
386
387 rule->section = n;
388 rule->network = network;
389 n = NULL;
390
391 r = hashmap_put(network->rules_by_section, rule->section, rule);
392 if (r < 0)
393 return r;
394
395 LIST_APPEND(rules, network->rules, rule);
396 network->n_rules++;
397
398 *ret = rule;
399 rule = NULL;
400
401 return 0;
402}
403
404int link_routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
405 _cleanup_link_unref_ Link *link = userdata;
406 int r;
407
408 assert(rtnl);
409 assert(m);
410 assert(link);
411 assert(link->ifname);
412 assert(link->link_messages > 0);
413
414 link->link_messages--;
415
416 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
417 return 1;
418
419 r = sd_netlink_message_get_errno(m);
420 if (r < 0 && r != -EEXIST)
421 log_link_warning_errno(link, r, "Could not add routing policy rule: %m");
422
423 if (link->link_messages == 0)
424 log_link_debug(link, "Routing policy rule configured");
425
426 return 1;
427}
428
429int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, sd_netlink_message_handler_t callback, bool update) {
430 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
431 int r;
432
433 assert(rule);
434 assert(link);
435 assert(link->ifindex > 0);
436 assert(link->manager);
437 assert(link->manager->rtnl);
438
439 r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
440 if (r < 0)
441 return log_error_errno(r, "Could not allocate RTM_NEWRULE message: %m");
442
443 if (!in_addr_is_null(rule->family, &rule->from)) {
444 if (rule->family == AF_INET)
445 r = sd_netlink_message_append_in_addr(m, FRA_SRC, &rule->from.in);
446 else
447 r = sd_netlink_message_append_in6_addr(m, FRA_SRC, &rule->from.in6);
448
449 if (r < 0)
450 return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
451
452 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen);
453 if (r < 0)
454 return log_error_errno(r, "Could not set source prefix length: %m");
455 }
456
457 if (!in_addr_is_null(rule->family, &rule->to)) {
458 if (rule->family == AF_INET)
459 r = sd_netlink_message_append_in_addr(m, FRA_DST, &rule->to.in);
460 else
461 r = sd_netlink_message_append_in6_addr(m, FRA_DST, &rule->to.in6);
462
463 if (r < 0)
464 return log_error_errno(r, "Could not append FRA_DST attribute: %m");
465
466 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen);
467 if (r < 0)
468 return log_error_errno(r, "Could not set destination prefix length: %m");
469 }
470
471 r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
472 if (r < 0)
473 return log_error_errno(r, "Could not append FRA_PRIORITY attribute: %m");
474
475 if (rule->tos > 0) {
476 r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
477 if (r < 0)
478 return log_error_errno(r, "Could not set ip rule tos: %m");
479 }
480
481 if (rule->table < 256) {
482 r = sd_rtnl_message_routing_policy_rule_set_table(m, rule->table);
483 if (r < 0)
484 return log_error_errno(r, "Could not set ip rule table: %m");
485 } else {
486 r = sd_rtnl_message_routing_policy_rule_set_table(m, RT_TABLE_UNSPEC);
487 if (r < 0)
488 return log_error_errno(r, "Could not set ip rule table: %m");
489
490 r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table);
491 if (r < 0)
492 return log_error_errno(r, "Could not append FRA_TABLE attribute: %m");
493 }
494
495 if (rule->fwmark > 0) {
496 r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark);
497 if (r < 0)
498 return log_error_errno(r, "Could not append FRA_FWMARK attribute: %m");
499 }
500
501 if (rule->fwmask > 0) {
502 r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
503 if (r < 0)
504 return log_error_errno(r, "Could not append FRA_FWMASK attribute: %m");
505 }
506
507 rule->link = link;
508
509 r = sd_netlink_call_async(link->manager->rtnl, m, callback, link, 0, NULL);
510 if (r < 0)
511 return log_error_errno(r, "Could not send rtnetlink message: %m");
512
513 link_ref(link);
514
515 r = routing_policy_rule_add(link->manager, rule->family, &rule->from, rule->from_prefixlen, &rule->to,
516 rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, NULL);
517 if (r < 0)
518 return log_error_errno(r, "Could not add rule : %m");
519
520 return 0;
521}
522
523static int parse_fwmark_fwmask(const char *s, uint32_t *fwmark, uint32_t *fwmask) {
524 _cleanup_free_ char *f = NULL;
525 char *p;
526 int r;
527
528 assert(s);
529
530 f = strdup(s);
531 if (!f)
532 return -ENOMEM;
533
534 p = strchr(f, '/');
535 if (p)
536 *p++ = '\0';
537
538 r = safe_atou32(f, fwmark);
539 if (r < 0)
540 return log_error_errno(r, "Failed to parse RPDB rule firewall mark, ignoring: %s", f);
541
542 if (p) {
543 r = safe_atou32(p, fwmask);
544 if (r < 0)
545 return log_error_errno(r, "Failed to parse RPDB rule mask, ignoring: %s", f);
546 }
547
548 return 0;
549}
550
551int config_parse_routing_policy_rule_tos(
552 const char *unit,
553 const char *filename,
554 unsigned line,
555 const char *section,
556 unsigned section_line,
557 const char *lvalue,
558 int ltype,
559 const char *rvalue,
560 void *data,
561 void *userdata) {
562
563 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
564 Network *network = userdata;
565 int r;
566
567 assert(filename);
568 assert(section);
569 assert(lvalue);
570 assert(rvalue);
571 assert(data);
572
573 r = routing_policy_rule_new_static(network, filename, section_line, &n);
574 if (r < 0)
575 return r;
576
577 r = safe_atou8(rvalue, &n->tos);
578 if (r < 0) {
579 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule tos, ignoring: %s", rvalue);
580 return 0;
581 }
582
583 n = NULL;
584
585 return 0;
586}
587
588int config_parse_routing_policy_rule_priority(
589 const char *unit,
590 const char *filename,
591 unsigned line,
592 const char *section,
593 unsigned section_line,
594 const char *lvalue,
595 int ltype,
596 const char *rvalue,
597 void *data,
598 void *userdata) {
599
600 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
601 Network *network = userdata;
602 int r;
603
604 assert(filename);
605 assert(section);
606 assert(lvalue);
607 assert(rvalue);
608 assert(data);
609
610 r = routing_policy_rule_new_static(network, filename, section_line, &n);
611 if (r < 0)
612 return r;
613
614 r = safe_atou32(rvalue, &n->priority);
615 if (r < 0) {
616 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule priority, ignoring: %s", rvalue);
617 return 0;
618 }
619
620 n = NULL;
621
622 return 0;
623}
624
625int config_parse_routing_policy_rule_table(
626 const char *unit,
627 const char *filename,
628 unsigned line,
629 const char *section,
630 unsigned section_line,
631 const char *lvalue,
632 int ltype,
633 const char *rvalue,
634 void *data,
635 void *userdata) {
636
637 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
638 Network *network = userdata;
639 int r;
640
641 assert(filename);
642 assert(section);
643 assert(lvalue);
644 assert(rvalue);
645 assert(data);
646
647 r = routing_policy_rule_new_static(network, filename, section_line, &n);
648 if (r < 0)
649 return r;
650
651 r = safe_atou32(rvalue, &n->table);
652 if (r < 0) {
653 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule table, ignoring: %s", rvalue);
654 return 0;
655 }
656
657 n = NULL;
658
659 return 0;
660}
661
662int config_parse_routing_policy_rule_fwmark_mask(
663 const char *unit,
664 const char *filename,
665 unsigned line,
666 const char *section,
667 unsigned section_line,
668 const char *lvalue,
669 int ltype,
670 const char *rvalue,
671 void *data,
672 void *userdata) {
673
674 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
675 _cleanup_free_ char *fwmark = 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
700int 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
753static int routing_policy_rule_read_full_file(char *state_file, char **ret) {
754 _cleanup_free_ char *s = NULL, *p = 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
774int 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
879void 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}