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