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