]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-routing-policy-rule.c
network: fix memory leak when an netdev was skipped
[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
7715629e 327 link->routing_policy_rule_remove_messages--;
bce67bbe
SS
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);
7715629e 441 assert(link->routing_policy_rule_messages > 0);
bce67bbe 442
7715629e 443 link->routing_policy_rule_messages--;
bce67bbe
SS
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
7715629e 452 if (link->routing_policy_rule_messages == 0) {
bce67bbe 453 log_link_debug(link, "Routing policy rule configured");
7715629e
ST
454 link->routing_policy_rules_configured = true;
455 link_check_ready(link);
456 }
bce67bbe
SS
457
458 return 1;
459}
460
461int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, sd_netlink_message_handler_t callback, bool update) {
462 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
463 int r;
464
465 assert(rule);
466 assert(link);
467 assert(link->ifindex > 0);
468 assert(link->manager);
469 assert(link->manager->rtnl);
470
471 r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
472 if (r < 0)
473 return log_error_errno(r, "Could not allocate RTM_NEWRULE message: %m");
474
475 if (!in_addr_is_null(rule->family, &rule->from)) {
476 if (rule->family == AF_INET)
477 r = sd_netlink_message_append_in_addr(m, FRA_SRC, &rule->from.in);
478 else
479 r = sd_netlink_message_append_in6_addr(m, FRA_SRC, &rule->from.in6);
480
481 if (r < 0)
482 return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
483
484 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen);
485 if (r < 0)
486 return log_error_errno(r, "Could not set source prefix length: %m");
487 }
488
489 if (!in_addr_is_null(rule->family, &rule->to)) {
490 if (rule->family == AF_INET)
491 r = sd_netlink_message_append_in_addr(m, FRA_DST, &rule->to.in);
492 else
493 r = sd_netlink_message_append_in6_addr(m, FRA_DST, &rule->to.in6);
494
495 if (r < 0)
496 return log_error_errno(r, "Could not append FRA_DST attribute: %m");
497
498 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen);
499 if (r < 0)
500 return log_error_errno(r, "Could not set destination prefix length: %m");
501 }
502
503 r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
504 if (r < 0)
505 return log_error_errno(r, "Could not append FRA_PRIORITY attribute: %m");
506
507 if (rule->tos > 0) {
508 r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
509 if (r < 0)
510 return log_error_errno(r, "Could not set ip rule tos: %m");
511 }
512
513 if (rule->table < 256) {
514 r = sd_rtnl_message_routing_policy_rule_set_table(m, rule->table);
515 if (r < 0)
516 return log_error_errno(r, "Could not set ip rule table: %m");
517 } else {
518 r = sd_rtnl_message_routing_policy_rule_set_table(m, RT_TABLE_UNSPEC);
519 if (r < 0)
520 return log_error_errno(r, "Could not set ip rule table: %m");
521
522 r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table);
523 if (r < 0)
524 return log_error_errno(r, "Could not append FRA_TABLE attribute: %m");
525 }
526
527 if (rule->fwmark > 0) {
528 r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark);
529 if (r < 0)
530 return log_error_errno(r, "Could not append FRA_FWMARK attribute: %m");
531 }
532
533 if (rule->fwmask > 0) {
534 r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
535 if (r < 0)
536 return log_error_errno(r, "Could not append FRA_FWMASK attribute: %m");
537 }
538
762e2659
SS
539 if (rule->iif) {
540 r = sd_netlink_message_append_string(m, FRA_IFNAME, rule->iif);
541 if (r < 0)
542 return log_error_errno(r, "Could not append FRA_IFNAME attribute: %m");
543 }
544
545 if (rule->oif) {
546 r = sd_netlink_message_append_string(m, FRA_OIFNAME, rule->oif);
547 if (r < 0)
548 return log_error_errno(r, "Could not append FRA_OIFNAME attribute: %m");
549 }
550
bce67bbe
SS
551 rule->link = link;
552
553 r = sd_netlink_call_async(link->manager->rtnl, m, callback, link, 0, NULL);
554 if (r < 0)
555 return log_error_errno(r, "Could not send rtnetlink message: %m");
556
557 link_ref(link);
558
559 r = routing_policy_rule_add(link->manager, rule->family, &rule->from, rule->from_prefixlen, &rule->to,
762e2659 560 rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, rule->iif, rule->oif, NULL);
bce67bbe
SS
561 if (r < 0)
562 return log_error_errno(r, "Could not add rule : %m");
563
564 return 0;
565}
566
567static int parse_fwmark_fwmask(const char *s, uint32_t *fwmark, uint32_t *fwmask) {
568 _cleanup_free_ char *f = NULL;
569 char *p;
570 int r;
571
572 assert(s);
573
574 f = strdup(s);
575 if (!f)
576 return -ENOMEM;
577
578 p = strchr(f, '/');
579 if (p)
580 *p++ = '\0';
581
582 r = safe_atou32(f, fwmark);
583 if (r < 0)
584 return log_error_errno(r, "Failed to parse RPDB rule firewall mark, ignoring: %s", f);
585
586 if (p) {
587 r = safe_atou32(p, fwmask);
588 if (r < 0)
589 return log_error_errno(r, "Failed to parse RPDB rule mask, ignoring: %s", f);
590 }
591
592 return 0;
593}
594
595int config_parse_routing_policy_rule_tos(
596 const char *unit,
597 const char *filename,
598 unsigned line,
599 const char *section,
600 unsigned section_line,
601 const char *lvalue,
602 int ltype,
603 const char *rvalue,
604 void *data,
605 void *userdata) {
606
607 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
608 Network *network = userdata;
609 int r;
610
611 assert(filename);
612 assert(section);
613 assert(lvalue);
614 assert(rvalue);
615 assert(data);
616
617 r = routing_policy_rule_new_static(network, filename, section_line, &n);
618 if (r < 0)
619 return r;
620
621 r = safe_atou8(rvalue, &n->tos);
622 if (r < 0) {
623 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule tos, ignoring: %s", rvalue);
624 return 0;
625 }
626
627 n = NULL;
628
629 return 0;
630}
631
632int config_parse_routing_policy_rule_priority(
633 const char *unit,
634 const char *filename,
635 unsigned line,
636 const char *section,
637 unsigned section_line,
638 const char *lvalue,
639 int ltype,
640 const char *rvalue,
641 void *data,
642 void *userdata) {
643
644 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
645 Network *network = userdata;
646 int r;
647
648 assert(filename);
649 assert(section);
650 assert(lvalue);
651 assert(rvalue);
652 assert(data);
653
654 r = routing_policy_rule_new_static(network, filename, section_line, &n);
655 if (r < 0)
656 return r;
657
658 r = safe_atou32(rvalue, &n->priority);
659 if (r < 0) {
660 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule priority, ignoring: %s", rvalue);
661 return 0;
662 }
663
664 n = NULL;
665
666 return 0;
667}
668
669int config_parse_routing_policy_rule_table(
670 const char *unit,
671 const char *filename,
672 unsigned line,
673 const char *section,
674 unsigned section_line,
675 const char *lvalue,
676 int ltype,
677 const char *rvalue,
678 void *data,
679 void *userdata) {
680
681 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
682 Network *network = userdata;
683 int r;
684
685 assert(filename);
686 assert(section);
687 assert(lvalue);
688 assert(rvalue);
689 assert(data);
690
691 r = routing_policy_rule_new_static(network, filename, section_line, &n);
692 if (r < 0)
693 return r;
694
695 r = safe_atou32(rvalue, &n->table);
696 if (r < 0) {
697 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule table, ignoring: %s", rvalue);
698 return 0;
699 }
700
701 n = NULL;
702
703 return 0;
704}
705
706int config_parse_routing_policy_rule_fwmark_mask(
707 const char *unit,
708 const char *filename,
709 unsigned line,
710 const char *section,
711 unsigned section_line,
712 const char *lvalue,
713 int ltype,
714 const char *rvalue,
715 void *data,
716 void *userdata) {
717
718 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
bce67bbe
SS
719 Network *network = userdata;
720 int r;
721
722 assert(filename);
723 assert(section);
724 assert(lvalue);
725 assert(rvalue);
726 assert(data);
727
728 r = routing_policy_rule_new_static(network, filename, section_line, &n);
729 if (r < 0)
730 return r;
731
732 r = parse_fwmark_fwmask(rvalue, &n->fwmark, &n->fwmask);
733 if (r < 0) {
734 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue);
735 return 0;
736 }
737
738 n = NULL;
739
740 return 0;
741}
742
743int config_parse_routing_policy_rule_prefix(
744 const char *unit,
745 const char *filename,
746 unsigned line,
747 const char *section,
748 unsigned section_line,
749 const char *lvalue,
750 int ltype,
751 const char *rvalue,
752 void *data,
753 void *userdata) {
754
755 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
756 Network *network = userdata;
757 union in_addr_union buffer;
758 uint8_t prefixlen;
759 int r;
760
761 assert(filename);
762 assert(section);
763 assert(lvalue);
764 assert(rvalue);
765 assert(data);
766
767 r = routing_policy_rule_new_static(network, filename, section_line, &n);
768 if (r < 0)
769 return r;
770
771 r = in_addr_prefix_from_string(rvalue, AF_INET, &buffer, &prefixlen);
772 if (r < 0) {
773 r = in_addr_prefix_from_string(rvalue, AF_INET6, &buffer, &prefixlen);
774 if (r < 0) {
775 log_syntax(unit, LOG_ERR, filename, line, r, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue);
776 return 0;
777 }
778
779 n->family = AF_INET6;
780 } else
781 n->family = AF_INET;
782
783 if (streq(lvalue, "To")) {
784 n->to = buffer;
785 n->to_prefixlen = prefixlen;
786 } else {
787 n->from = buffer;
788 n->from_prefixlen = prefixlen;
789 }
790
791 n = NULL;
792
793 return 0;
794}
795
762e2659
SS
796int config_parse_routing_policy_rule_device(
797 const char *unit,
798 const char *filename,
799 unsigned line,
800 const char *section,
801 unsigned section_line,
802 const char *lvalue,
803 int ltype,
804 const char *rvalue,
805 void *data,
806 void *userdata) {
807
808 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *n = NULL;
809 Network *network = userdata;
810 int r;
811
812 assert(filename);
813 assert(section);
814 assert(lvalue);
815 assert(rvalue);
816 assert(data);
817
818 r = routing_policy_rule_new_static(network, filename, section_line, &n);
819 if (r < 0)
820 return r;
821
822 if (!ifname_valid(rvalue)) {
823 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse '%s' interface name, ignoring: %s", lvalue, rvalue);
824 return 0;
825 }
826
827 if (streq(lvalue, "IncomingInterface")) {
828 r = free_and_strdup(&n->iif, rvalue);
829 if (r < 0)
830 return log_oom();
831 } else {
832 r = free_and_strdup(&n->oif, rvalue);
833 if (r < 0)
834 return log_oom();
835 }
836
837 n = NULL;
838
839 return 0;
840}
841
458d8ae3 842static int routing_policy_rule_read_full_file(const char *state_file, char **ret) {
ac097c84 843 _cleanup_free_ char *s = NULL;
bce67bbe
SS
844 size_t size;
845 int r;
846
847 assert(state_file);
848
849 r = read_full_file(state_file, &s, &size);
850 if (r == -ENOENT)
851 return -ENODATA;
852 if (r < 0)
853 return r;
854 if (size <= 0)
855 return -ENODATA;
856
857 *ret = s;
858 s = NULL;
859
860 return size;
861}
862
458d8ae3
ZJS
863int routing_policy_serialize_rules(Set *rules, FILE *f) {
864 RoutingPolicyRule *rule = NULL;
865 Iterator i;
866 int r;
867
868 assert(f);
869
870 SET_FOREACH(rule, rules, i) {
871 _cleanup_free_ char *from_str = NULL, *to_str = NULL;
872 bool space = false;
873
874 fputs("RULE=", f);
875
876 if (!in_addr_is_null(rule->family, &rule->from)) {
877 r = in_addr_to_string(rule->family, &rule->from, &from_str);
878 if (r < 0)
879 return r;
880
881 fprintf(f, "from=%s/%hhu",
882 from_str, rule->from_prefixlen);
883 space = true;
884 }
885
886 if (!in_addr_is_null(rule->family, &rule->to)) {
887 r = in_addr_to_string(rule->family, &rule->to, &to_str);
888 if (r < 0)
889 return r;
890
891 fprintf(f, "%sto=%s/%hhu",
892 space ? " " : "",
893 to_str, rule->to_prefixlen);
894 space = true;
895 }
896
897 if (rule->tos != 0) {
898 fprintf(f, "%stos=%hhu",
899 space ? " " : "",
900 rule->tos);
901 space = true;
902 }
903
904 if (rule->fwmark != 0) {
905 fprintf(f, "%sfwmark=%"PRIu32"/%"PRIu32,
906 space ? " " : "",
907 rule->fwmark, rule->fwmask);
908 space = true;
909 }
910
9491f55f
ZJS
911 if (rule->iif) {
912 fprintf(f, "%siif=%s",
913 space ? " " : "",
914 rule->iif);
915 space = true;
916 }
917
918 if (rule->oif) {
919 fprintf(f, "%soif=%s",
920 space ? " " : "",
921 rule->oif);
922 space = true;
923 }
924
458d8ae3
ZJS
925 fprintf(f, "%stable=%"PRIu32 "\n",
926 space ? " " : "",
927 rule->table);
928 }
929
930 return 0;
931}
932
933int routing_policy_load_rules(const char *state_file, Set **rules) {
bce67bbe
SS
934 _cleanup_strv_free_ char **l = NULL;
935 _cleanup_free_ char *data = NULL;
936 const char *p;
937 char **i;
938 int r;
939
458d8ae3
ZJS
940 assert(state_file);
941 assert(rules);
bce67bbe 942
458d8ae3 943 r = routing_policy_rule_read_full_file(state_file, &data);
bce67bbe
SS
944 if (r <= 0)
945 return r;
946
947 l = strv_split_newlines(data);
948 if (!l)
949 return -ENOMEM;
950
458d8ae3 951 r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
bce67bbe
SS
952 if (r < 0)
953 return r;
954
955 STRV_FOREACH(i, l) {
956 _cleanup_routing_policy_rule_free_ RoutingPolicyRule *rule = NULL;
957
958 p = startswith(*i, "RULE=");
959 if (!p)
960 continue;
961
bce67bbe
SS
962 r = routing_policy_rule_new(&rule);
963 if (r < 0)
964 return r;
965
966 for (;;) {
967 _cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
968 union in_addr_union buffer;
969 uint8_t prefixlen;
970
971 r = extract_first_word(&p, &word, NULL, 0);
972 if (r < 0)
973 return r;
974 if (r == 0)
975 break;
976
977 r = split_pair(word, "=", &a, &b);
978 if (r < 0)
979 continue;
980
981 if (STR_IN_SET(a, "from", "to")) {
982
983 r = in_addr_prefix_from_string(b, AF_INET, &buffer, &prefixlen);
984 if (r < 0) {
985 r = in_addr_prefix_from_string(b, AF_INET6, &buffer, &prefixlen);
986 if (r < 0) {
987 log_error_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
988 continue;
989 }
990
991 rule->family = AF_INET6;
992 } else
993 rule->family = AF_INET;
994
995 if (streq(a, "to")) {
996 rule->to = buffer;
997 rule->to_prefixlen = prefixlen;
998 } else {
999 rule->from = buffer;
1000 rule->from_prefixlen = prefixlen;
1001 }
1002 } else if (streq(a, "tos")) {
1003 r = safe_atou8(b, &rule->tos);
1004 if (r < 0) {
1005 log_error_errno(r, "Failed to parse RPDB rule tos, ignoring: %s", b);
1006 continue;
1007 }
1008 } else if (streq(a, "table")) {
1009 r = safe_atou32(b, &rule->table);
1010 if (r < 0) {
1011 log_error_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b);
1012 continue;
1013 }
1014 } else if (streq(a, "fwmark")) {
1015
e4aca57d 1016 r = parse_fwmark_fwmask(b, &rule->fwmark, &rule->fwmask);
bce67bbe
SS
1017 if (r < 0) {
1018 log_error_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
1019 continue;
1020 }
9491f55f 1021 } else if (streq(a, "iif")) {
762e2659 1022
93f9da6e 1023 if (free_and_strdup(&rule->iif, b) < 0)
762e2659 1024 return log_oom();
93f9da6e 1025
9491f55f 1026 } else if (streq(a, "oif")) {
762e2659 1027
93f9da6e 1028 if (free_and_strdup(&rule->oif, b) < 0)
762e2659 1029 return log_oom();
bce67bbe
SS
1030 }
1031 }
1032
458d8ae3 1033 r = set_put(*rules, rule);
bce67bbe
SS
1034 if (r < 0) {
1035 log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", p);
1036 continue;
1037 }
1038
1039 rule = NULL;
1040 }
1041
1042 return 0;
1043}
1044
1045void routing_policy_rule_purge(Manager *m, Link *link) {
1046 RoutingPolicyRule *rule, *existing;
1047 Iterator i;
1048 int r;
1049
1050 assert(m);
1051 assert(link);
1052
1053 SET_FOREACH(rule, m->rules_saved, i) {
1054 existing = set_get(m->rules_foreign, rule);
1055 if (existing) {
1056
1057 r = routing_policy_rule_remove(rule, link, routing_policy_rule_remove_handler);
1058 if (r < 0) {
1059 log_warning_errno(r, "Could not remove routing policy rules: %m");
1060 continue;
1061 }
1062
7715629e 1063 link->routing_policy_rule_remove_messages++;
bce67bbe
SS
1064 }
1065 }
1066}