]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-routing-policy-rule.c
Merge pull request #15891 from bluca/host_os_release
[thirdparty/systemd.git] / src / network / networkd-routing-policy-rule.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <net/if.h>
4 #include <linux/fib_rules.h>
5
6 #include "af-list.h"
7 #include "alloc-util.h"
8 #include "conf-parser.h"
9 #include "fileio.h"
10 #include "format-util.h"
11 #include "ip-protocol-list.h"
12 #include "networkd-routing-policy-rule.h"
13 #include "netlink-util.h"
14 #include "networkd-manager.h"
15 #include "networkd-util.h"
16 #include "parse-util.h"
17 #include "socket-util.h"
18 #include "string-util.h"
19 #include "strv.h"
20 #include "user-util.h"
21
22 int routing_policy_rule_new(RoutingPolicyRule **ret) {
23 RoutingPolicyRule *rule;
24
25 rule = new(RoutingPolicyRule, 1);
26 if (!rule)
27 return -ENOMEM;
28
29 *rule = (RoutingPolicyRule) {
30 .table = RT_TABLE_MAIN,
31 .uid_range.start = UID_INVALID,
32 .uid_range.end = UID_INVALID,
33 .suppress_prefixlen = -1,
34 };
35
36 *ret = rule;
37 return 0;
38 }
39
40 void routing_policy_rule_free(RoutingPolicyRule *rule) {
41
42 if (!rule)
43 return;
44
45 if (rule->network) {
46 LIST_REMOVE(rules, rule->network->rules, rule);
47 assert(rule->network->n_rules > 0);
48 rule->network->n_rules--;
49
50 if (rule->section)
51 hashmap_remove(rule->network->rules_by_section, rule->section);
52 }
53
54 if (rule->manager) {
55 if (set_get(rule->manager->rules, rule) == rule)
56 set_remove(rule->manager->rules, rule);
57 if (set_get(rule->manager->rules_foreign, rule) == rule)
58 set_remove(rule->manager->rules_foreign, rule);
59 }
60
61 network_config_section_free(rule->section);
62 free(rule->iif);
63 free(rule->oif);
64 free(rule);
65 }
66
67 static int routing_policy_rule_copy(RoutingPolicyRule *dest, RoutingPolicyRule *src) {
68 _cleanup_free_ char *iif = NULL, *oif = NULL;
69
70 assert(dest);
71 assert(src);
72
73 if (src->iif) {
74 iif = strdup(src->iif);
75 if (!iif)
76 return -ENOMEM;
77 }
78
79 if (src->oif) {
80 oif = strdup(src->oif);
81 if (!oif)
82 return -ENOMEM;
83 }
84
85 dest->family = src->family;
86 dest->from = src->from;
87 dest->from_prefixlen = src->from_prefixlen;
88 dest->to = src->to;
89 dest->to_prefixlen = src->to_prefixlen;
90 dest->invert_rule = src->invert_rule;
91 dest->tos = src->tos;
92 dest->fwmark = src->fwmark;
93 dest->fwmask = src->fwmask;
94 dest->priority = src->priority;
95 dest->table = src->table;
96 dest->iif = TAKE_PTR(iif);
97 dest->oif = TAKE_PTR(oif);
98 dest->protocol = src->protocol;
99 dest->sport = src->sport;
100 dest->dport = src->dport;
101 dest->uid_range = src->uid_range;
102 dest->suppress_prefixlen = src->suppress_prefixlen;
103
104 return 0;
105 }
106
107 static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash *state) {
108 assert(rule);
109
110 siphash24_compress(&rule->family, sizeof(rule->family), state);
111
112 switch (rule->family) {
113 case AF_INET:
114 case AF_INET6:
115 siphash24_compress(&rule->from, FAMILY_ADDRESS_SIZE(rule->family), state);
116 siphash24_compress(&rule->from_prefixlen, sizeof(rule->from_prefixlen), state);
117
118 siphash24_compress(&rule->to, FAMILY_ADDRESS_SIZE(rule->family), state);
119 siphash24_compress(&rule->to_prefixlen, sizeof(rule->to_prefixlen), state);
120
121 siphash24_compress_boolean(rule->invert_rule, state);
122
123 siphash24_compress(&rule->tos, sizeof(rule->tos), state);
124 siphash24_compress(&rule->fwmark, sizeof(rule->fwmark), state);
125 siphash24_compress(&rule->fwmask, sizeof(rule->fwmask), state);
126 siphash24_compress(&rule->priority, sizeof(rule->priority), state);
127 siphash24_compress(&rule->table, sizeof(rule->table), state);
128 siphash24_compress(&rule->suppress_prefixlen, sizeof(rule->suppress_prefixlen), state);
129
130 siphash24_compress(&rule->protocol, sizeof(rule->protocol), state);
131 siphash24_compress(&rule->sport, sizeof(rule->sport), state);
132 siphash24_compress(&rule->dport, sizeof(rule->dport), state);
133 siphash24_compress(&rule->uid_range, sizeof(rule->uid_range), state);
134
135 if (rule->iif)
136 siphash24_compress(rule->iif, strlen(rule->iif), state);
137
138 if (rule->oif)
139 siphash24_compress(rule->oif, strlen(rule->oif), state);
140
141 break;
142 default:
143 /* treat any other address family as AF_UNSPEC */
144 break;
145 }
146 }
147
148 static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPolicyRule *b) {
149 int r;
150
151 r = CMP(a->family, b->family);
152 if (r != 0)
153 return r;
154
155 switch (a->family) {
156 case AF_INET:
157 case AF_INET6:
158 r = CMP(a->from_prefixlen, b->from_prefixlen);
159 if (r != 0)
160 return r;
161
162 r = memcmp(&a->from, &b->from, FAMILY_ADDRESS_SIZE(a->family));
163 if (r != 0)
164 return r;
165
166 r = CMP(a->to_prefixlen, b->to_prefixlen);
167 if (r != 0)
168 return r;
169
170 r = memcmp(&a->to, &b->to, FAMILY_ADDRESS_SIZE(a->family));
171 if (r != 0)
172 return r;
173
174 r = CMP(a->invert_rule, b->invert_rule);
175 if (r != 0)
176 return r;
177
178 r = CMP(a->tos, b->tos);
179 if (r != 0)
180 return r;
181
182 r = CMP(a->fwmark, b->fwmark);
183 if (r != 0)
184 return r;
185
186 r = CMP(a->fwmask, b->fwmask);
187 if (r != 0)
188 return r;
189
190 r = CMP(a->priority, b->priority);
191 if (r != 0)
192 return r;
193
194 r = CMP(a->table, b->table);
195 if (r != 0)
196 return r;
197
198 r = CMP(a->suppress_prefixlen, b->suppress_prefixlen);
199 if (r != 0)
200 return r;
201
202 r = CMP(a->protocol, b->protocol);
203 if (r != 0)
204 return r;
205
206 r = memcmp(&a->sport, &b->sport, sizeof(a->sport));
207 if (r != 0)
208 return r;
209
210 r = memcmp(&a->dport, &b->dport, sizeof(a->dport));
211 if (r != 0)
212 return r;
213
214 r = memcmp(&a->uid_range, &b->uid_range, sizeof(a->uid_range));
215 if (r != 0)
216 return r;
217
218 r = strcmp_ptr(a->iif, b->iif);
219 if (r != 0)
220 return r;
221
222 r = strcmp_ptr(a->oif, b->oif);
223 if (r != 0)
224 return r;
225
226 return 0;
227 default:
228 /* treat any other address family as AF_UNSPEC */
229 return 0;
230 }
231 }
232
233 DEFINE_PRIVATE_HASH_OPS(routing_policy_rule_hash_ops, RoutingPolicyRule, routing_policy_rule_hash_func, routing_policy_rule_compare_func);
234
235 int routing_policy_rule_get(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
236
237 RoutingPolicyRule *existing;
238
239 assert(m);
240
241 existing = set_get(m->rules, rule);
242 if (existing) {
243 if (ret)
244 *ret = existing;
245 return 1;
246 }
247
248 existing = set_get(m->rules_foreign, rule);
249 if (existing) {
250 if (ret)
251 *ret = existing;
252 return 0;
253 }
254
255 return -ENOENT;
256 }
257
258 int routing_policy_rule_make_local(Manager *m, RoutingPolicyRule *rule) {
259 int r;
260
261 assert(m);
262
263 if (set_contains(m->rules_foreign, rule)) {
264 set_remove(m->rules_foreign, rule);
265
266 r = set_ensure_put(&m->rules, &routing_policy_rule_hash_ops, rule);
267 if (r < 0)
268 return r;
269 if (r == 0)
270 routing_policy_rule_free(rule);
271 }
272
273 return -ENOENT;
274 }
275
276 static int routing_policy_rule_add_internal(Manager *m, Set **rules, RoutingPolicyRule *in, RoutingPolicyRule **ret) {
277 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
278 int r;
279
280 assert(m);
281 assert(rules);
282 assert(in);
283
284 r = routing_policy_rule_new(&rule);
285 if (r < 0)
286 return r;
287
288 rule->manager = m;
289
290 r = routing_policy_rule_copy(rule, in);
291 if (r < 0)
292 return r;
293
294 r = set_ensure_put(rules, &routing_policy_rule_hash_ops, rule);
295 if (r < 0)
296 return r;
297 if (r == 0)
298 return -EEXIST;
299
300 if (ret)
301 *ret = rule;
302
303 TAKE_PTR(rule);
304 return 0;
305 }
306
307 static int routing_policy_rule_add(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
308 return routing_policy_rule_add_internal(m, &m->rules, rule, ret);
309 }
310
311 int routing_policy_rule_add_foreign(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
312 return routing_policy_rule_add_internal(m, &m->rules_foreign, rule, ret);
313 }
314
315 static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
316 int r;
317
318 assert(m);
319 assert(link);
320 assert(link->ifname);
321
322 link->routing_policy_rule_remove_messages--;
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_message_warning_errno(link, m, r, "Could not drop routing policy rule");
330
331 return 1;
332 }
333
334 int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, link_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_link_error_errno(link, r, "Could not allocate RTM_DELRULE message: %m");
348
349 if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->from) == 0) {
350 r = netlink_message_append_in_addr_union(m, FRA_SRC, routing_policy_rule->family, &routing_policy_rule->from);
351 if (r < 0)
352 return log_link_error_errno(link, r, "Could not append FRA_SRC attribute: %m");
353
354 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, routing_policy_rule->from_prefixlen);
355 if (r < 0)
356 return log_link_error_errno(link, r, "Could not set source prefix length: %m");
357 }
358
359 if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->to) == 0) {
360 r = netlink_message_append_in_addr_union(m, FRA_DST, routing_policy_rule->family, &routing_policy_rule->to);
361 if (r < 0)
362 return log_link_error_errno(link, r, "Could not append FRA_DST attribute: %m");
363
364 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, routing_policy_rule->to_prefixlen);
365 if (r < 0)
366 return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
367 }
368
369 r = netlink_call_async(link->manager->rtnl, NULL, m,
370 callback ?: routing_policy_rule_remove_handler,
371 link_netlink_destroy_callback, link);
372 if (r < 0)
373 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
374
375 link_ref(link);
376
377 return 0;
378 }
379
380 static int routing_policy_rule_new_static(Network *network, const char *filename, unsigned section_line, RoutingPolicyRule **ret) {
381 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
382 _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
383 int r;
384
385 assert(network);
386 assert(ret);
387 assert(!!filename == (section_line > 0));
388
389 if (filename) {
390 r = network_config_section_new(filename, section_line, &n);
391 if (r < 0)
392 return r;
393
394 rule = hashmap_get(network->rules_by_section, n);
395 if (rule) {
396 *ret = TAKE_PTR(rule);
397
398 return 0;
399 }
400 }
401
402 r = routing_policy_rule_new(&rule);
403 if (r < 0)
404 return r;
405
406 rule->network = network;
407 LIST_APPEND(rules, network->rules, rule);
408 network->n_rules++;
409
410 if (filename) {
411 rule->section = TAKE_PTR(n);
412
413 r = hashmap_ensure_allocated(&network->rules_by_section, &network_config_hash_ops);
414 if (r < 0)
415 return r;
416
417 r = hashmap_put(network->rules_by_section, rule->section, rule);
418 if (r < 0)
419 return r;
420 }
421
422 *ret = TAKE_PTR(rule);
423
424 return 0;
425 }
426
427 static int routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
428 int r;
429
430 assert(rtnl);
431 assert(m);
432 assert(link);
433 assert(link->ifname);
434 assert(link->routing_policy_rule_messages > 0);
435
436 link->routing_policy_rule_messages--;
437
438 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
439 return 1;
440
441 r = sd_netlink_message_get_errno(m);
442 if (r < 0 && r != -EEXIST) {
443 log_link_message_warning_errno(link, m, r, "Could not add routing policy rule");
444 link_enter_failed(link);
445 return 1;
446 }
447
448 if (link->routing_policy_rule_messages == 0) {
449 log_link_debug(link, "Routing policy rule configured");
450 link->routing_policy_rules_configured = true;
451 link_check_ready(link);
452 }
453
454 return 1;
455 }
456
457 int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netlink_message_handler_t callback) {
458 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
459 int r;
460
461 assert(rule);
462 assert(link);
463 assert(link->ifindex > 0);
464 assert(link->manager);
465 assert(link->manager->rtnl);
466
467 if (DEBUG_LOGGING) {
468 _cleanup_free_ char *from = NULL, *to = NULL;
469
470 (void) in_addr_to_string(rule->family, &rule->from, &from);
471 (void) in_addr_to_string(rule->family, &rule->to, &to);
472
473 log_link_debug(link,
474 "Configuring routing policy rule: %s/%u -> %s/%u, iif: %s, oif: %s, table: %u",
475 from, rule->from_prefixlen, to, rule->to_prefixlen, strna(rule->iif), strna(rule->oif), rule->table);
476 }
477
478 r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
479 if (r < 0)
480 return log_link_error_errno(link, r, "Could not allocate RTM_NEWRULE message: %m");
481
482 if (in_addr_is_null(rule->family, &rule->from) == 0) {
483 r = netlink_message_append_in_addr_union(m, FRA_SRC, rule->family, &rule->from);
484 if (r < 0)
485 return log_link_error_errno(link, r, "Could not append FRA_SRC attribute: %m");
486
487 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen);
488 if (r < 0)
489 return log_link_error_errno(link, r, "Could not set source prefix length: %m");
490 }
491
492 if (in_addr_is_null(rule->family, &rule->to) == 0) {
493 r = netlink_message_append_in_addr_union(m, FRA_DST, rule->family, &rule->to);
494 if (r < 0)
495 return log_link_error_errno(link, r, "Could not append FRA_DST attribute: %m");
496
497 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen);
498 if (r < 0)
499 return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
500 }
501
502 r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
503 if (r < 0)
504 return log_link_error_errno(link, r, "Could not append FRA_PRIORITY attribute: %m");
505
506 if (rule->tos > 0) {
507 r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
508 if (r < 0)
509 return log_link_error_errno(link, r, "Could not set IP rule TOS: %m");
510 }
511
512 if (rule->table < 256) {
513 r = sd_rtnl_message_routing_policy_rule_set_table(m, rule->table);
514 if (r < 0)
515 return log_link_error_errno(link, r, "Could not set IP rule table: %m");
516 } else {
517 r = sd_rtnl_message_routing_policy_rule_set_table(m, RT_TABLE_UNSPEC);
518 if (r < 0)
519 return log_link_error_errno(link, r, "Could not set IP rule table: %m");
520
521 r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table);
522 if (r < 0)
523 return log_link_error_errno(link, r, "Could not append FRA_TABLE attribute: %m");
524 }
525
526 if (rule->fwmark > 0) {
527 r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark);
528 if (r < 0)
529 return log_link_error_errno(link, r, "Could not append FRA_FWMARK attribute: %m");
530 }
531
532 if (rule->fwmask > 0) {
533 r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
534 if (r < 0)
535 return log_link_error_errno(link, r, "Could not append FRA_FWMASK attribute: %m");
536 }
537
538 if (rule->iif) {
539 r = sd_netlink_message_append_string(m, FRA_IFNAME, rule->iif);
540 if (r < 0)
541 return log_link_error_errno(link, r, "Could not append FRA_IFNAME attribute: %m");
542 }
543
544 if (rule->oif) {
545 r = sd_netlink_message_append_string(m, FRA_OIFNAME, rule->oif);
546 if (r < 0)
547 return log_link_error_errno(link, r, "Could not append FRA_OIFNAME attribute: %m");
548 }
549
550 r = sd_netlink_message_append_u8(m, FRA_IP_PROTO, rule->protocol);
551 if (r < 0)
552 return log_link_error_errno(link, r, "Could not append FRA_IP_PROTO attribute: %m");
553
554 if (rule->sport.start != 0 || rule->sport.end != 0) {
555 r = sd_netlink_message_append_data(m, FRA_SPORT_RANGE, &rule->sport, sizeof(rule->sport));
556 if (r < 0)
557 return log_link_error_errno(link, r, "Could not append FRA_SPORT_RANGE attribute: %m");
558 }
559
560 if (rule->dport.start != 0 || rule->dport.end != 0) {
561 r = sd_netlink_message_append_data(m, FRA_DPORT_RANGE, &rule->dport, sizeof(rule->dport));
562 if (r < 0)
563 return log_link_error_errno(link, r, "Could not append FRA_DPORT_RANGE attribute: %m");
564 }
565
566 if (rule->uid_range.start != UID_INVALID && rule->uid_range.end != UID_INVALID) {
567 r = sd_netlink_message_append_data(m, FRA_UID_RANGE, &rule->uid_range, sizeof(rule->uid_range));
568 if (r < 0)
569 return log_link_error_errno(link, r, "Could not append FRA_UID_RANGE attribute: %m");
570 }
571
572 if (rule->invert_rule) {
573 r = sd_rtnl_message_routing_policy_rule_set_flags(m, FIB_RULE_INVERT);
574 if (r < 0)
575 return log_link_error_errno(link, r, "Could not append FIB_RULE_INVERT attribute: %m");
576 }
577
578 if (rule->suppress_prefixlen >= 0) {
579 r = sd_netlink_message_append_u32(m, FRA_SUPPRESS_PREFIXLEN, (uint32_t) rule->suppress_prefixlen);
580 if (r < 0)
581 return log_link_error_errno(link, r, "Could not append FRA_SUPPRESS_PREFIXLEN attribute: %m");
582 }
583
584 rule->link = link;
585
586 r = netlink_call_async(link->manager->rtnl, NULL, m,
587 callback ?: routing_policy_rule_handler,
588 link_netlink_destroy_callback, link);
589 if (r < 0)
590 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
591
592 link_ref(link);
593
594 r = routing_policy_rule_add(link->manager, rule, NULL);
595 if (r < 0)
596 return log_link_error_errno(link, r, "Could not add rule: %m");
597
598 return 1;
599 }
600
601 int routing_policy_rule_section_verify(RoutingPolicyRule *rule) {
602 int r;
603
604 if (section_is_invalid(rule->section))
605 return -EINVAL;
606
607 if ((rule->family == AF_INET && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6)) ||
608 (rule->family == AF_INET6 && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4)))
609 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
610 "%s: address family specified by Family= conflicts with the address "
611 "specified by To= or From=. Ignoring [RoutingPolicyRule] section from line %u.",
612 rule->section->filename, rule->section->line);
613
614 if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_IPV6)) {
615 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule6 = NULL;
616
617 assert(rule->family == AF_UNSPEC);
618
619 /* When Family=both, we need to copy the section, AF_INET and AF_INET6. */
620
621 r = routing_policy_rule_new_static(rule->network, NULL, 0, &rule6);
622 if (r < 0)
623 return r;
624
625 r = routing_policy_rule_copy(rule6, rule);
626 if (r < 0)
627 return r;
628
629 rule->family = AF_INET;
630 rule6->family = AF_INET6;
631
632 TAKE_PTR(rule6);
633 }
634
635 if (rule->family == AF_UNSPEC) {
636 if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6))
637 rule->family = AF_INET6;
638 else
639 rule->family = AF_INET;
640 }
641
642 return 0;
643 }
644
645 static int parse_fwmark_fwmask(const char *s, uint32_t *fwmark, uint32_t *fwmask) {
646 _cleanup_free_ char *f = NULL;
647 char *p;
648 int r;
649
650 assert(s);
651
652 f = strdup(s);
653 if (!f)
654 return -ENOMEM;
655
656 p = strchr(f, '/');
657 if (p)
658 *p++ = '\0';
659
660 r = safe_atou32(f, fwmark);
661 if (r < 0)
662 return log_error_errno(r, "Failed to parse RPDB rule firewall mark, ignoring: %s", f);
663
664 if (p) {
665 r = safe_atou32(p, fwmask);
666 if (r < 0)
667 return log_error_errno(r, "Failed to parse RPDB rule mask, ignoring: %s", f);
668 }
669
670 return 0;
671 }
672
673 int config_parse_routing_policy_rule_tos(
674 const char *unit,
675 const char *filename,
676 unsigned line,
677 const char *section,
678 unsigned section_line,
679 const char *lvalue,
680 int ltype,
681 const char *rvalue,
682 void *data,
683 void *userdata) {
684
685 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
686 Network *network = userdata;
687 int r;
688
689 assert(filename);
690 assert(section);
691 assert(lvalue);
692 assert(rvalue);
693 assert(data);
694
695 r = routing_policy_rule_new_static(network, filename, section_line, &n);
696 if (r < 0)
697 return r;
698
699 r = safe_atou8(rvalue, &n->tos);
700 if (r < 0) {
701 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule TOS, ignoring: %s", rvalue);
702 return 0;
703 }
704
705 n = NULL;
706
707 return 0;
708 }
709
710 int config_parse_routing_policy_rule_priority(
711 const char *unit,
712 const char *filename,
713 unsigned line,
714 const char *section,
715 unsigned section_line,
716 const char *lvalue,
717 int ltype,
718 const char *rvalue,
719 void *data,
720 void *userdata) {
721
722 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
723 Network *network = userdata;
724 int r;
725
726 assert(filename);
727 assert(section);
728 assert(lvalue);
729 assert(rvalue);
730 assert(data);
731
732 r = routing_policy_rule_new_static(network, filename, section_line, &n);
733 if (r < 0)
734 return r;
735
736 r = safe_atou32(rvalue, &n->priority);
737 if (r < 0) {
738 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule priority, ignoring: %s", rvalue);
739 return 0;
740 }
741
742 n = NULL;
743
744 return 0;
745 }
746
747 int config_parse_routing_policy_rule_table(
748 const char *unit,
749 const char *filename,
750 unsigned line,
751 const char *section,
752 unsigned section_line,
753 const char *lvalue,
754 int ltype,
755 const char *rvalue,
756 void *data,
757 void *userdata) {
758
759 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
760 Network *network = userdata;
761 int r;
762
763 assert(filename);
764 assert(section);
765 assert(lvalue);
766 assert(rvalue);
767 assert(data);
768
769 r = routing_policy_rule_new_static(network, filename, section_line, &n);
770 if (r < 0)
771 return r;
772
773 r = safe_atou32(rvalue, &n->table);
774 if (r < 0) {
775 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule table, ignoring: %s", rvalue);
776 return 0;
777 }
778
779 n = NULL;
780
781 return 0;
782 }
783
784 int config_parse_routing_policy_rule_fwmark_mask(
785 const char *unit,
786 const char *filename,
787 unsigned line,
788 const char *section,
789 unsigned section_line,
790 const char *lvalue,
791 int ltype,
792 const char *rvalue,
793 void *data,
794 void *userdata) {
795
796 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
797 Network *network = userdata;
798 int r;
799
800 assert(filename);
801 assert(section);
802 assert(lvalue);
803 assert(rvalue);
804 assert(data);
805
806 r = routing_policy_rule_new_static(network, filename, section_line, &n);
807 if (r < 0)
808 return r;
809
810 r = parse_fwmark_fwmask(rvalue, &n->fwmark, &n->fwmask);
811 if (r < 0) {
812 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue);
813 return 0;
814 }
815
816 n = NULL;
817
818 return 0;
819 }
820
821 int config_parse_routing_policy_rule_prefix(
822 const char *unit,
823 const char *filename,
824 unsigned line,
825 const char *section,
826 unsigned section_line,
827 const char *lvalue,
828 int ltype,
829 const char *rvalue,
830 void *data,
831 void *userdata) {
832
833 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
834 Network *network = userdata;
835 union in_addr_union *buffer;
836 uint8_t *prefixlen;
837 int r;
838
839 assert(filename);
840 assert(section);
841 assert(lvalue);
842 assert(rvalue);
843 assert(data);
844
845 r = routing_policy_rule_new_static(network, filename, section_line, &n);
846 if (r < 0)
847 return r;
848
849 if (streq(lvalue, "To")) {
850 buffer = &n->to;
851 prefixlen = &n->to_prefixlen;
852 } else {
853 buffer = &n->from;
854 prefixlen = &n->from_prefixlen;
855 }
856
857 if (n->family == AF_UNSPEC)
858 r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
859 else
860 r = in_addr_prefix_from_string(rvalue, n->family, buffer, prefixlen);
861 if (r < 0) {
862 log_syntax(unit, LOG_ERR, filename, line, r, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue);
863 return 0;
864 }
865
866 n = NULL;
867
868 return 0;
869 }
870
871 int config_parse_routing_policy_rule_device(
872 const char *unit,
873 const char *filename,
874 unsigned line,
875 const char *section,
876 unsigned section_line,
877 const char *lvalue,
878 int ltype,
879 const char *rvalue,
880 void *data,
881 void *userdata) {
882
883 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
884 Network *network = userdata;
885 int r;
886
887 assert(filename);
888 assert(section);
889 assert(lvalue);
890 assert(rvalue);
891 assert(data);
892
893 r = routing_policy_rule_new_static(network, filename, section_line, &n);
894 if (r < 0)
895 return r;
896
897 if (!ifname_valid(rvalue)) {
898 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse '%s' interface name, ignoring: %s", lvalue, rvalue);
899 return 0;
900 }
901
902 if (streq(lvalue, "IncomingInterface")) {
903 r = free_and_strdup(&n->iif, rvalue);
904 if (r < 0)
905 return log_oom();
906 } else {
907 r = free_and_strdup(&n->oif, rvalue);
908 if (r < 0)
909 return log_oom();
910 }
911
912 n = NULL;
913
914 return 0;
915 }
916
917 int config_parse_routing_policy_rule_port_range(
918 const char *unit,
919 const char *filename,
920 unsigned line,
921 const char *section,
922 unsigned section_line,
923 const char *lvalue,
924 int ltype,
925 const char *rvalue,
926 void *data,
927 void *userdata) {
928 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
929 Network *network = userdata;
930 uint16_t low, high;
931 int r;
932
933 assert(filename);
934 assert(section);
935 assert(lvalue);
936 assert(rvalue);
937 assert(data);
938
939 r = routing_policy_rule_new_static(network, filename, section_line, &n);
940 if (r < 0)
941 return r;
942
943 r = parse_ip_port_range(rvalue, &low, &high);
944 if (r < 0) {
945 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse routing policy rule port range '%s'", rvalue);
946 return 0;
947 }
948
949 if (streq(lvalue, "SourcePort")) {
950 n->sport.start = low;
951 n->sport.end = high;
952 } else {
953 n->dport.start = low;
954 n->dport.end = high;
955 }
956
957 n = NULL;
958
959 return 0;
960 }
961
962 int config_parse_routing_policy_rule_ip_protocol(
963 const char *unit,
964 const char *filename,
965 unsigned line,
966 const char *section,
967 unsigned section_line,
968 const char *lvalue,
969 int ltype,
970 const char *rvalue,
971 void *data,
972 void *userdata) {
973
974 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
975 Network *network = userdata;
976 int r;
977
978 assert(filename);
979 assert(section);
980 assert(lvalue);
981 assert(rvalue);
982 assert(data);
983
984 r = routing_policy_rule_new_static(network, filename, section_line, &n);
985 if (r < 0)
986 return r;
987
988 r = parse_ip_protocol(rvalue);
989 if (r < 0) {
990 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IP protocol '%s' for routing policy rule, ignoring: %m", rvalue);
991 return 0;
992 }
993
994 n->protocol = r;
995
996 n = NULL;
997
998 return 0;
999 }
1000
1001 int config_parse_routing_policy_rule_invert(
1002 const char *unit,
1003 const char *filename,
1004 unsigned line,
1005 const char *section,
1006 unsigned section_line,
1007 const char *lvalue,
1008 int ltype,
1009 const char *rvalue,
1010 void *data,
1011 void *userdata) {
1012
1013 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1014 Network *network = userdata;
1015 int r;
1016
1017 assert(filename);
1018 assert(section);
1019 assert(lvalue);
1020 assert(rvalue);
1021 assert(data);
1022
1023 r = routing_policy_rule_new_static(network, filename, section_line, &n);
1024 if (r < 0)
1025 return r;
1026
1027 r = parse_boolean(rvalue);
1028 if (r < 0) {
1029 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule invert, ignoring: %s", rvalue);
1030 return 0;
1031 }
1032
1033 n->invert_rule = r;
1034
1035 n = NULL;
1036
1037 return 0;
1038 }
1039
1040 int config_parse_routing_policy_rule_family(
1041 const char *unit,
1042 const char *filename,
1043 unsigned line,
1044 const char *section,
1045 unsigned section_line,
1046 const char *lvalue,
1047 int ltype,
1048 const char *rvalue,
1049 void *data,
1050 void *userdata) {
1051
1052 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1053 Network *network = userdata;
1054 AddressFamily a;
1055 int r;
1056
1057 assert(filename);
1058 assert(section);
1059 assert(lvalue);
1060 assert(rvalue);
1061 assert(data);
1062
1063 r = routing_policy_rule_new_static(network, filename, section_line, &n);
1064 if (r < 0)
1065 return r;
1066
1067 a = routing_policy_rule_address_family_from_string(rvalue);
1068 if (a < 0) {
1069 log_syntax(unit, LOG_ERR, filename, line, 0,
1070 "Invalid address family '%s', ignoring.", rvalue);
1071 return 0;
1072 }
1073
1074 n->address_family = a;
1075 n = NULL;
1076
1077 return 0;
1078 }
1079
1080 int config_parse_routing_policy_rule_uid_range(
1081 const char *unit,
1082 const char *filename,
1083 unsigned line,
1084 const char *section,
1085 unsigned section_line,
1086 const char *lvalue,
1087 int ltype,
1088 const char *rvalue,
1089 void *data,
1090 void *userdata) {
1091
1092 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1093 Network *network = userdata;
1094 uid_t start, end;
1095 int r;
1096
1097 assert(filename);
1098 assert(section);
1099 assert(lvalue);
1100 assert(rvalue);
1101 assert(data);
1102
1103 r = routing_policy_rule_new_static(network, filename, section_line, &n);
1104 if (r < 0)
1105 return r;
1106
1107 r = get_user_creds(&rvalue, &start, NULL, NULL, NULL, 0);
1108 if (r >= 0)
1109 end = start;
1110 else {
1111 r = parse_uid_range(rvalue, &start, &end);
1112 if (r < 0) {
1113 log_syntax(unit, LOG_ERR, filename, line, r,
1114 "Invalid uid or uid range '%s', ignoring: %m", rvalue);
1115 return 0;
1116 }
1117 }
1118
1119 n->uid_range.start = start;
1120 n->uid_range.end = end;
1121 n = NULL;
1122
1123 return 0;
1124 }
1125
1126 int config_parse_routing_policy_rule_suppress_prefixlen(
1127 const char *unit,
1128 const char *filename,
1129 unsigned line,
1130 const char *section,
1131 unsigned section_line,
1132 const char *lvalue,
1133 int ltype,
1134 const char *rvalue,
1135 void *data,
1136 void *userdata) {
1137
1138 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1139 Network *network = userdata;
1140 int r;
1141
1142 assert(filename);
1143 assert(section);
1144 assert(lvalue);
1145 assert(rvalue);
1146 assert(data);
1147
1148 r = routing_policy_rule_new_static(network, filename, section_line, &n);
1149 if (r < 0)
1150 return r;
1151
1152 r = parse_ip_prefix_length(rvalue, &n->suppress_prefixlen);
1153 if (r == -ERANGE) {
1154 log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length outside of valid range 0-128, ignoring: %s", rvalue);
1155 return 0;
1156 }
1157 if (r < 0) {
1158 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule suppress_prefixlen, ignoring: %s", rvalue);
1159 return 0;
1160 }
1161
1162 n = NULL;
1163
1164 return 0;
1165 }
1166
1167 static int routing_policy_rule_read_full_file(const char *state_file, char **ret) {
1168 _cleanup_free_ char *s = NULL;
1169 size_t size;
1170 int r;
1171
1172 assert(state_file);
1173
1174 r = read_full_file(state_file, &s, &size);
1175 if (r == -ENOENT)
1176 return -ENODATA;
1177 if (r < 0)
1178 return r;
1179 if (size <= 0)
1180 return -ENODATA;
1181
1182 *ret = TAKE_PTR(s);
1183
1184 return size;
1185 }
1186
1187 int routing_policy_serialize_rules(Set *rules, FILE *f) {
1188 RoutingPolicyRule *rule = NULL;
1189 Iterator i;
1190 int r;
1191
1192 assert(f);
1193
1194 SET_FOREACH(rule, rules, i) {
1195 _cleanup_free_ char *from_str = NULL, *to_str = NULL;
1196 bool space = false;
1197 const char *family_str;
1198
1199 fputs("RULE=", f);
1200
1201 if (!in_addr_is_null(rule->family, &rule->from)) {
1202 r = in_addr_to_string(rule->family, &rule->from, &from_str);
1203 if (r < 0)
1204 return r;
1205
1206 fprintf(f, "from=%s/%hhu",
1207 from_str, rule->from_prefixlen);
1208 space = true;
1209 }
1210
1211 if (!in_addr_is_null(rule->family, &rule->to)) {
1212 r = in_addr_to_string(rule->family, &rule->to, &to_str);
1213 if (r < 0)
1214 return r;
1215
1216 fprintf(f, "%sto=%s/%hhu",
1217 space ? " " : "",
1218 to_str, rule->to_prefixlen);
1219 space = true;
1220 }
1221
1222 family_str = af_to_name(rule->family);
1223 if (family_str)
1224 fprintf(f, "%sfamily=%s",
1225 space ? " " : "",
1226 family_str);
1227
1228 if (rule->tos != 0) {
1229 fprintf(f, "%stos=%hhu",
1230 space ? " " : "",
1231 rule->tos);
1232 space = true;
1233 }
1234
1235 fprintf(f, "%spriority=%"PRIu32,
1236 space ? " " : "",
1237 rule->priority);
1238
1239 if (rule->fwmark != 0) {
1240 fprintf(f, "%sfwmark=%"PRIu32"/%"PRIu32,
1241 space ? " " : "",
1242 rule->fwmark, rule->fwmask);
1243 space = true;
1244 }
1245
1246 if (rule->iif) {
1247 fprintf(f, "%siif=%s",
1248 space ? " " : "",
1249 rule->iif);
1250 space = true;
1251 }
1252
1253 if (rule->oif) {
1254 fprintf(f, "%soif=%s",
1255 space ? " " : "",
1256 rule->oif);
1257 space = true;
1258 }
1259
1260 if (rule->protocol != 0) {
1261 fprintf(f, "%sprotocol=%hhu",
1262 space ? " " : "",
1263 rule->protocol);
1264 space = true;
1265 }
1266
1267 if (rule->sport.start != 0 || rule->sport.end != 0) {
1268 fprintf(f, "%ssourcesport=%"PRIu16"-%"PRIu16,
1269 space ? " " : "",
1270 rule->sport.start, rule->sport.end);
1271 space = true;
1272 }
1273
1274 if (rule->dport.start != 0 || rule->dport.end != 0) {
1275 fprintf(f, "%sdestinationport=%"PRIu16"-%"PRIu16,
1276 space ? " " : "",
1277 rule->dport.start, rule->dport.end);
1278 space = true;
1279 }
1280
1281 if (rule->uid_range.start != UID_INVALID && rule->uid_range.end != UID_INVALID) {
1282 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
1283 fprintf(f, "%suidrange="UID_FMT"-"UID_FMT,
1284 space ? " " : "",
1285 rule->uid_range.start, rule->uid_range.end);
1286 space = true;
1287 }
1288
1289 if (rule->suppress_prefixlen >= 0) {
1290 fprintf(f, "%ssuppress_prefixlen=%d",
1291 space ? " " : "",
1292 rule->suppress_prefixlen);
1293 space = true;
1294 }
1295
1296 fprintf(f, "%stable=%"PRIu32 "\n",
1297 space ? " " : "",
1298 rule->table);
1299 }
1300
1301 return 0;
1302 }
1303
1304 int routing_policy_load_rules(const char *state_file, Set **rules) {
1305 _cleanup_strv_free_ char **l = NULL;
1306 _cleanup_free_ char *data = NULL;
1307 uint16_t low = 0, high = 0;
1308 const char *p;
1309 char **i;
1310 int r;
1311
1312 assert(state_file);
1313 assert(rules);
1314
1315 r = routing_policy_rule_read_full_file(state_file, &data);
1316 if (r <= 0)
1317 return r;
1318
1319 l = strv_split_newlines(data);
1320 if (!l)
1321 return -ENOMEM;
1322
1323 STRV_FOREACH(i, l) {
1324 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
1325
1326 p = startswith(*i, "RULE=");
1327 if (!p)
1328 continue;
1329
1330 r = routing_policy_rule_new(&rule);
1331 if (r < 0)
1332 return r;
1333
1334 for (;;) {
1335 _cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
1336
1337 r = extract_first_word(&p, &word, NULL, 0);
1338 if (r < 0)
1339 return r;
1340 if (r == 0)
1341 break;
1342
1343 r = split_pair(word, "=", &a, &b);
1344 if (r < 0)
1345 continue;
1346
1347 if (STR_IN_SET(a, "from", "to")) {
1348 union in_addr_union *buffer;
1349 uint8_t *prefixlen;
1350
1351 if (streq(a, "to")) {
1352 buffer = &rule->to;
1353 prefixlen = &rule->to_prefixlen;
1354 } else {
1355 buffer = &rule->from;
1356 prefixlen = &rule->from_prefixlen;
1357 }
1358
1359 r = in_addr_prefix_from_string_auto(b, &rule->family, buffer, prefixlen);
1360 if (r < 0) {
1361 log_error_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
1362 continue;
1363 }
1364
1365 } else if (streq(a, "family")) {
1366 r = af_from_name(b);
1367 if (r < 0) {
1368 log_error_errno(r, "Failed to parse RPDB rule family, ignoring: %s", b);
1369 continue;
1370 }
1371 rule->family = r;
1372 } else if (streq(a, "tos")) {
1373 r = safe_atou8(b, &rule->tos);
1374 if (r < 0) {
1375 log_error_errno(r, "Failed to parse RPDB rule TOS, ignoring: %s", b);
1376 continue;
1377 }
1378 } else if (streq(a, "table")) {
1379 r = safe_atou32(b, &rule->table);
1380 if (r < 0) {
1381 log_error_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b);
1382 continue;
1383 }
1384 } else if (streq(a, "priority")) {
1385 r = safe_atou32(b, &rule->priority);
1386 if (r < 0) {
1387 log_error_errno(r, "Failed to parse RPDB rule priority, ignoring: %s", b);
1388 continue;
1389 }
1390 } else if (streq(a, "fwmark")) {
1391 r = parse_fwmark_fwmask(b, &rule->fwmark, &rule->fwmask);
1392 if (r < 0) {
1393 log_error_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
1394 continue;
1395 }
1396 } else if (streq(a, "iif")) {
1397 if (free_and_strdup(&rule->iif, b) < 0)
1398 return log_oom();
1399
1400 } else if (streq(a, "oif")) {
1401
1402 if (free_and_strdup(&rule->oif, b) < 0)
1403 return log_oom();
1404 } else if (streq(a, "protocol")) {
1405 r = safe_atou8(b, &rule->protocol);
1406 if (r < 0) {
1407 log_error_errno(r, "Failed to parse RPDB rule protocol, ignoring: %s", b);
1408 continue;
1409 }
1410 } else if (streq(a, "sourceport")) {
1411 r = parse_ip_port_range(b, &low, &high);
1412 if (r < 0) {
1413 log_error_errno(r, "Invalid routing policy rule source port range, ignoring assignment: '%s'", b);
1414 continue;
1415 }
1416
1417 rule->sport.start = low;
1418 rule->sport.end = high;
1419 } else if (streq(a, "destinationport")) {
1420 r = parse_ip_port_range(b, &low, &high);
1421 if (r < 0) {
1422 log_error_errno(r, "Invalid routing policy rule destination port range, ignoring assignment: '%s'", b);
1423 continue;
1424 }
1425
1426 rule->dport.start = low;
1427 rule->dport.end = high;
1428 } else if (streq(a, "uidrange")) {
1429 uid_t lower, upper;
1430
1431 r = parse_uid_range(b, &lower, &upper);
1432 if (r < 0) {
1433 log_error_errno(r, "Invalid routing policy rule uid range, ignoring assignment: '%s'", b);
1434 continue;
1435 }
1436
1437 rule->uid_range.start = lower;
1438 rule->uid_range.end = upper;
1439 } else if (streq(a, "suppress_prefixlen")) {
1440 r = parse_ip_prefix_length(b, &rule->suppress_prefixlen);
1441 if (r == -ERANGE) {
1442 log_error_errno(r, "Prefix length outside of valid range 0-128, ignoring: %s", b);
1443 continue;
1444 }
1445 if (r < 0) {
1446 log_error_errno(r, "Failed to parse RPDB rule suppress_prefixlen, ignoring: %s", b);
1447 continue;
1448 }
1449 }
1450 }
1451
1452 r = set_ensure_put(rules, &routing_policy_rule_hash_ops, rule);
1453 if (r < 0) {
1454 log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", p);
1455 continue;
1456 }
1457 if (r > 0)
1458 rule = NULL;
1459 }
1460
1461 return 0;
1462 }
1463
1464 static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule *rule) {
1465 RoutingPolicyRule *link_rule;
1466 Iterator i;
1467 Link *link;
1468
1469 assert(m);
1470 assert(rule);
1471
1472 HASHMAP_FOREACH(link, m->links, i) {
1473 if (!link->network)
1474 continue;
1475
1476 LIST_FOREACH(rules, link_rule, link->network->rules)
1477 if (routing_policy_rule_compare_func(link_rule, rule) == 0)
1478 return true;
1479 }
1480
1481 return false;
1482 }
1483
1484 void routing_policy_rule_purge(Manager *m, Link *link) {
1485 RoutingPolicyRule *rule, *existing;
1486 Iterator i;
1487 int r;
1488
1489 assert(m);
1490 assert(link);
1491
1492 SET_FOREACH(rule, m->rules_saved, i) {
1493 existing = set_get(m->rules_foreign, rule);
1494 if (!existing)
1495 continue; /* Saved rule does not exist anymore. */
1496
1497 if (manager_links_have_routing_policy_rule(m, existing))
1498 continue; /* Existing links have the saved rule. */
1499
1500 /* Existing links do not have the saved rule. Let's drop the rule now, and re-configure it
1501 * later when it is requested. */
1502
1503 r = routing_policy_rule_remove(existing, link, NULL);
1504 if (r < 0) {
1505 log_warning_errno(r, "Could not remove routing policy rules: %m");
1506 continue;
1507 }
1508
1509 link->routing_policy_rule_remove_messages++;
1510
1511 assert_se(set_remove(m->rules_foreign, existing) == existing);
1512 routing_policy_rule_free(existing);
1513 }
1514 }