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