]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-routing-policy-rule.c
networkd: move rule loading to a separate function
[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
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
34int 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
48void 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
762e2659
SS
69 free(rule->iif);
70 free(rule->oif);
bce67bbe
SS
71 free(rule);
72}
73
74static 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
762e2659
SS
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
bce67bbe
SS
101 break;
102 default:
103 /* treat any other address family as AF_UNSPEC */
104 break;
105 }
106}
107
108static 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
762e2659
SS
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
bce67bbe
SS
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
165const struct hash_ops routing_policy_rule_hash_ops = {
166 .hash = routing_policy_rule_hash_func,
167 .compare = routing_policy_rule_compare_func
168};
169
170int 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,
762e2659
SS
179 char *iif,
180 char *oif,
bce67bbe
SS
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,
762e2659
SS
196 .iif = iif,
197 .oif = oif
bce67bbe
SS
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
221int 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
239static 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,
762e2659
SS
248 char *iif,
249 char *oif,
bce67bbe
SS
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;
762e2659
SS
269 rule->iif = iif;
270 rule->oif = oif;
bce67bbe
SS
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
288int 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,
762e2659
SS
297 char *iif,
298 char *oif,
bce67bbe
SS
299 RoutingPolicyRule **ret) {
300
762e2659 301 return routing_policy_rule_add_internal(&m->rules, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, iif, oif, ret);
bce67bbe
SS
302}
303
304int 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,
762e2659
SS
313 char *iif,
314 char *oif,
bce67bbe 315 RoutingPolicyRule **ret) {
762e2659 316 return routing_policy_rule_add_internal(&m->rules_foreign, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, iif, oif, ret);
bce67bbe
SS
317}
318
319static 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
339int 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
391static 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
433int 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
458int 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
762e2659
SS
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
bce67bbe
SS
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,
762e2659 557 rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, rule->iif, rule->oif, NULL);
bce67bbe
SS
558 if (r < 0)
559 return log_error_errno(r, "Could not add rule : %m");
560
561 return 0;
562}
563
564static 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
592int 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
629int 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
666int 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
703int 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;
bce67bbe
SS
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
740int 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
762e2659
SS
793int 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
458d8ae3 839static int routing_policy_rule_read_full_file(const char *state_file, char **ret) {
ac097c84 840 _cleanup_free_ char *s = NULL;
bce67bbe
SS
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
458d8ae3
ZJS
860int routing_policy_serialize_rules(Set *rules, FILE *f) {
861 RoutingPolicyRule *rule = NULL;
862 Iterator i;
863 int r;
864
865 assert(f);
866
867 SET_FOREACH(rule, rules, i) {
868 _cleanup_free_ char *from_str = NULL, *to_str = NULL;
869 bool space = false;
870
871 fputs("RULE=", f);
872
873 if (!in_addr_is_null(rule->family, &rule->from)) {
874 r = in_addr_to_string(rule->family, &rule->from, &from_str);
875 if (r < 0)
876 return r;
877
878 fprintf(f, "from=%s/%hhu",
879 from_str, rule->from_prefixlen);
880 space = true;
881 }
882
883 if (!in_addr_is_null(rule->family, &rule->to)) {
884 r = in_addr_to_string(rule->family, &rule->to, &to_str);
885 if (r < 0)
886 return r;
887
888 fprintf(f, "%sto=%s/%hhu",
889 space ? " " : "",
890 to_str, rule->to_prefixlen);
891 space = true;
892 }
893
894 if (rule->tos != 0) {
895 fprintf(f, "%stos=%hhu",
896 space ? " " : "",
897 rule->tos);
898 space = true;
899 }
900
901 if (rule->fwmark != 0) {
902 fprintf(f, "%sfwmark=%"PRIu32"/%"PRIu32,
903 space ? " " : "",
904 rule->fwmark, rule->fwmask);
905 space = true;
906 }
907
908 fprintf(f, "%stable=%"PRIu32 "\n",
909 space ? " " : "",
910 rule->table);
911 }
912
913 return 0;
914}
915
916int routing_policy_load_rules(const char *state_file, Set **rules) {
bce67bbe
SS
917 _cleanup_strv_free_ char **l = NULL;
918 _cleanup_free_ char *data = NULL;
919 const char *p;
920 char **i;
921 int r;
922
458d8ae3
ZJS
923 assert(state_file);
924 assert(rules);
bce67bbe 925
458d8ae3 926 r = routing_policy_rule_read_full_file(state_file, &data);
bce67bbe
SS
927 if (r <= 0)
928 return r;
929
930 l = strv_split_newlines(data);
931 if (!l)
932 return -ENOMEM;
933
458d8ae3 934 r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
bce67bbe
SS
935 if (r < 0)
936 return r;
937
938 STRV_FOREACH(i, l) {
939 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *rule = NULL;
940
941 p = startswith(*i, "RULE=");
942 if (!p)
943 continue;
944
bce67bbe
SS
945 r = routing_policy_rule_new(&rule);
946 if (r < 0)
947 return r;
948
949 for (;;) {
950 _cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
951 union in_addr_union buffer;
952 uint8_t prefixlen;
953
954 r = extract_first_word(&p, &word, NULL, 0);
955 if (r < 0)
956 return r;
957 if (r == 0)
958 break;
959
960 r = split_pair(word, "=", &a, &b);
961 if (r < 0)
962 continue;
963
964 if (STR_IN_SET(a, "from", "to")) {
965
966 r = in_addr_prefix_from_string(b, AF_INET, &buffer, &prefixlen);
967 if (r < 0) {
968 r = in_addr_prefix_from_string(b, AF_INET6, &buffer, &prefixlen);
969 if (r < 0) {
970 log_error_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
971 continue;
972 }
973
974 rule->family = AF_INET6;
975 } else
976 rule->family = AF_INET;
977
978 if (streq(a, "to")) {
979 rule->to = buffer;
980 rule->to_prefixlen = prefixlen;
981 } else {
982 rule->from = buffer;
983 rule->from_prefixlen = prefixlen;
984 }
985 } else if (streq(a, "tos")) {
986 r = safe_atou8(b, &rule->tos);
987 if (r < 0) {
988 log_error_errno(r, "Failed to parse RPDB rule tos, ignoring: %s", b);
989 continue;
990 }
991 } else if (streq(a, "table")) {
992 r = safe_atou32(b, &rule->table);
993 if (r < 0) {
994 log_error_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b);
995 continue;
996 }
997 } else if (streq(a, "fwmark")) {
998
999 r = parse_fwmark_fwmask(a, &rule->fwmark, &rule->fwmask);
1000 if (r < 0) {
1001 log_error_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
1002 continue;
1003 }
762e2659
SS
1004 } else if (streq(a, "IncomingInterface")) {
1005
1006 rule->iif = strdup(a);
1007 if (!rule->iif)
1008 return log_oom();
1009 } else if (streq(a, "OutgoingInterface")) {
1010
1011 rule->oif = strdup(a);
1012 if (!rule->oif)
1013 return log_oom();
bce67bbe
SS
1014 }
1015 }
1016
458d8ae3 1017 r = set_put(*rules, rule);
bce67bbe
SS
1018 if (r < 0) {
1019 log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", p);
1020 continue;
1021 }
1022
1023 rule = NULL;
1024 }
1025
1026 return 0;
1027}
1028
1029void routing_policy_rule_purge(Manager *m, Link *link) {
1030 RoutingPolicyRule *rule, *existing;
1031 Iterator i;
1032 int r;
1033
1034 assert(m);
1035 assert(link);
1036
1037 SET_FOREACH(rule, m->rules_saved, i) {
1038 existing = set_get(m->rules_foreign, rule);
1039 if (existing) {
1040
1041 r = routing_policy_rule_remove(rule, link, routing_policy_rule_remove_handler);
1042 if (r < 0) {
1043 log_warning_errno(r, "Could not remove routing policy rules: %m");
1044 continue;
1045 }
1046
1047 link->link_messages++;
1048 }
1049 }
1050}