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