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