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