]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-routing-policy-rule.c
network: fix typo in log message
[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
ae2a15bc 860 *ret = TAKE_PTR(s);
bce67bbe
SS
861
862 return size;
863}
864
458d8ae3
ZJS
865int routing_policy_serialize_rules(Set *rules, FILE *f) {
866 RoutingPolicyRule *rule = NULL;
867 Iterator i;
868 int r;
869
870 assert(f);
871
872 SET_FOREACH(rule, rules, i) {
873 _cleanup_free_ char *from_str = NULL, *to_str = NULL;
874 bool space = false;
875
876 fputs("RULE=", f);
877
878 if (!in_addr_is_null(rule->family, &rule->from)) {
879 r = in_addr_to_string(rule->family, &rule->from, &from_str);
880 if (r < 0)
881 return r;
882
883 fprintf(f, "from=%s/%hhu",
884 from_str, rule->from_prefixlen);
885 space = true;
886 }
887
888 if (!in_addr_is_null(rule->family, &rule->to)) {
889 r = in_addr_to_string(rule->family, &rule->to, &to_str);
890 if (r < 0)
891 return r;
892
893 fprintf(f, "%sto=%s/%hhu",
894 space ? " " : "",
895 to_str, rule->to_prefixlen);
896 space = true;
897 }
898
899 if (rule->tos != 0) {
900 fprintf(f, "%stos=%hhu",
901 space ? " " : "",
902 rule->tos);
903 space = true;
904 }
905
906 if (rule->fwmark != 0) {
907 fprintf(f, "%sfwmark=%"PRIu32"/%"PRIu32,
908 space ? " " : "",
909 rule->fwmark, rule->fwmask);
910 space = true;
911 }
912
9491f55f
ZJS
913 if (rule->iif) {
914 fprintf(f, "%siif=%s",
915 space ? " " : "",
916 rule->iif);
917 space = true;
918 }
919
920 if (rule->oif) {
921 fprintf(f, "%soif=%s",
922 space ? " " : "",
923 rule->oif);
924 space = true;
925 }
926
458d8ae3
ZJS
927 fprintf(f, "%stable=%"PRIu32 "\n",
928 space ? " " : "",
929 rule->table);
930 }
931
932 return 0;
933}
934
935int routing_policy_load_rules(const char *state_file, Set **rules) {
bce67bbe
SS
936 _cleanup_strv_free_ char **l = NULL;
937 _cleanup_free_ char *data = NULL;
938 const char *p;
939 char **i;
940 int r;
941
458d8ae3
ZJS
942 assert(state_file);
943 assert(rules);
bce67bbe 944
458d8ae3 945 r = routing_policy_rule_read_full_file(state_file, &data);
bce67bbe
SS
946 if (r <= 0)
947 return r;
948
949 l = strv_split_newlines(data);
950 if (!l)
951 return -ENOMEM;
952
458d8ae3 953 r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
bce67bbe
SS
954 if (r < 0)
955 return r;
956
957 STRV_FOREACH(i, l) {
958 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *rule = NULL;
959
960 p = startswith(*i, "RULE=");
961 if (!p)
962 continue;
963
bce67bbe
SS
964 r = routing_policy_rule_new(&rule);
965 if (r < 0)
966 return r;
967
968 for (;;) {
969 _cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
970 union in_addr_union buffer;
971 uint8_t prefixlen;
972
973 r = extract_first_word(&p, &word, NULL, 0);
974 if (r < 0)
975 return r;
976 if (r == 0)
977 break;
978
979 r = split_pair(word, "=", &a, &b);
980 if (r < 0)
981 continue;
982
983 if (STR_IN_SET(a, "from", "to")) {
984
985 r = in_addr_prefix_from_string(b, AF_INET, &buffer, &prefixlen);
986 if (r < 0) {
987 r = in_addr_prefix_from_string(b, AF_INET6, &buffer, &prefixlen);
988 if (r < 0) {
989 log_error_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
990 continue;
991 }
992
993 rule->family = AF_INET6;
994 } else
995 rule->family = AF_INET;
996
997 if (streq(a, "to")) {
998 rule->to = buffer;
999 rule->to_prefixlen = prefixlen;
1000 } else {
1001 rule->from = buffer;
1002 rule->from_prefixlen = prefixlen;
1003 }
1004 } else if (streq(a, "tos")) {
1005 r = safe_atou8(b, &rule->tos);
1006 if (r < 0) {
1007 log_error_errno(r, "Failed to parse RPDB rule tos, ignoring: %s", b);
1008 continue;
1009 }
1010 } else if (streq(a, "table")) {
1011 r = safe_atou32(b, &rule->table);
1012 if (r < 0) {
1013 log_error_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b);
1014 continue;
1015 }
1016 } else if (streq(a, "fwmark")) {
1017
e4aca57d 1018 r = parse_fwmark_fwmask(b, &rule->fwmark, &rule->fwmask);
bce67bbe
SS
1019 if (r < 0) {
1020 log_error_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
1021 continue;
1022 }
9491f55f 1023 } else if (streq(a, "iif")) {
762e2659 1024
93f9da6e 1025 if (free_and_strdup(&rule->iif, b) < 0)
762e2659 1026 return log_oom();
93f9da6e 1027
9491f55f 1028 } else if (streq(a, "oif")) {
762e2659 1029
93f9da6e 1030 if (free_and_strdup(&rule->oif, b) < 0)
762e2659 1031 return log_oom();
bce67bbe
SS
1032 }
1033 }
1034
458d8ae3 1035 r = set_put(*rules, rule);
bce67bbe
SS
1036 if (r < 0) {
1037 log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", p);
1038 continue;
1039 }
1040
1041 rule = NULL;
1042 }
1043
1044 return 0;
1045}
1046
1047void routing_policy_rule_purge(Manager *m, Link *link) {
1048 RoutingPolicyRule *rule, *existing;
1049 Iterator i;
1050 int r;
1051
1052 assert(m);
1053 assert(link);
1054
1055 SET_FOREACH(rule, m->rules_saved, i) {
1056 existing = set_get(m->rules_foreign, rule);
1057 if (existing) {
1058
1059 r = routing_policy_rule_remove(rule, link, routing_policy_rule_remove_handler);
1060 if (r < 0) {
1061 log_warning_errno(r, "Could not remove routing policy rules: %m");
1062 continue;
1063 }
1064
7715629e 1065 link->routing_policy_rule_remove_messages++;
bce67bbe
SS
1066 }
1067 }
1068}