]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-routing-policy-rule.c
network: read link specific sysctl value
[thirdparty/systemd.git] / src / network / networkd-routing-policy-rule.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <net/if.h>
4 #include <linux/fib_rules.h>
5
6 #include "alloc-util.h"
7 #include "conf-parser.h"
8 #include "fileio.h"
9 #include "ip-protocol-list.h"
10 #include "networkd-routing-policy-rule.h"
11 #include "netlink-util.h"
12 #include "networkd-manager.h"
13 #include "parse-util.h"
14 #include "socket-util.h"
15 #include "string-util.h"
16 #include "strv.h"
17
18 int routing_policy_rule_new(RoutingPolicyRule **ret) {
19 RoutingPolicyRule *rule;
20
21 rule = new(RoutingPolicyRule, 1);
22 if (!rule)
23 return -ENOMEM;
24
25 *rule = (RoutingPolicyRule) {
26 .family = AF_INET,
27 .table = RT_TABLE_MAIN,
28 };
29
30 *ret = rule;
31 return 0;
32 }
33
34 void routing_policy_rule_free(RoutingPolicyRule *rule) {
35
36 if (!rule)
37 return;
38
39 if (rule->network) {
40 LIST_REMOVE(rules, rule->network->rules, rule);
41 assert(rule->network->n_rules > 0);
42 rule->network->n_rules--;
43
44 if (rule->section)
45 hashmap_remove(rule->network->rules_by_section, rule->section);
46 }
47
48 if (rule->manager) {
49 if (set_get(rule->manager->rules, rule) == rule)
50 set_remove(rule->manager->rules, rule);
51 if (set_get(rule->manager->rules_foreign, rule) == rule)
52 set_remove(rule->manager->rules_foreign, rule);
53 }
54
55 network_config_section_free(rule->section);
56 free(rule->iif);
57 free(rule->oif);
58 free(rule);
59 }
60
61 static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash *state) {
62 assert(rule);
63
64 siphash24_compress(&rule->family, sizeof(rule->family), state);
65
66 switch (rule->family) {
67 case AF_INET:
68 case AF_INET6:
69
70 siphash24_compress(&rule->from, FAMILY_ADDRESS_SIZE(rule->family), state);
71 siphash24_compress(&rule->from_prefixlen, sizeof(rule->from_prefixlen), state);
72
73 siphash24_compress(&rule->to, FAMILY_ADDRESS_SIZE(rule->family), state);
74 siphash24_compress(&rule->to_prefixlen, sizeof(rule->to_prefixlen), state);
75
76 siphash24_compress(&rule->tos, sizeof(rule->tos), state);
77 siphash24_compress(&rule->fwmark, sizeof(rule->fwmark), state);
78 siphash24_compress(&rule->table, sizeof(rule->table), state);
79
80 siphash24_compress(&rule->protocol, sizeof(rule->protocol), state);
81 siphash24_compress(&rule->sport, sizeof(rule->sport), state);
82 siphash24_compress(&rule->dport, sizeof(rule->dport), state);
83
84 if (rule->iif)
85 siphash24_compress(rule->iif, strlen(rule->iif), state);
86
87 if (rule->oif)
88 siphash24_compress(rule->oif, strlen(rule->oif), state);
89
90 break;
91 default:
92 /* treat any other address family as AF_UNSPEC */
93 break;
94 }
95 }
96
97 static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPolicyRule *b) {
98 int r;
99
100 r = CMP(a->family, b->family);
101 if (r != 0)
102 return r;
103
104 switch (a->family) {
105 case AF_INET:
106 case AF_INET6:
107 r = CMP(a->from_prefixlen, b->from_prefixlen);
108 if (r != 0)
109 return r;
110
111 r = CMP(a->to_prefixlen, b->to_prefixlen);
112 if (r != 0)
113 return r;
114
115 r = CMP(a->tos, b->tos);
116 if (r != 0)
117 return r;
118
119 r = CMP(a->fwmask, b->fwmask);
120 if (r != 0)
121 return r;
122
123 r = CMP(a->table, b->table);
124 if (r != 0)
125 return r;
126
127 r = strcmp_ptr(a->iif, b->iif);
128 if (!r)
129 return r;
130
131 r = strcmp_ptr(a->oif, b->oif);
132 if (!r)
133 return r;
134
135 r = CMP(a->protocol, b->protocol);
136 if (r != 0)
137 return r;
138
139 r = memcmp(&a->sport, &b->sport, sizeof(a->sport));
140 if (r != 0)
141 return r;
142
143 r = memcmp(&a->dport, &b->dport, sizeof(a->dport));
144 if (r != 0)
145 return r;
146
147 r = memcmp(&a->from, &b->from, FAMILY_ADDRESS_SIZE(a->family));
148 if (r != 0)
149 return r;
150
151 return memcmp(&a->to, &b->to, FAMILY_ADDRESS_SIZE(a->family));
152
153 default:
154 /* treat any other address family as AF_UNSPEC */
155 return 0;
156 }
157 }
158
159 DEFINE_PRIVATE_HASH_OPS(routing_policy_rule_hash_ops, RoutingPolicyRule, routing_policy_rule_hash_func, routing_policy_rule_compare_func);
160
161 int routing_policy_rule_get(Manager *m,
162 int family,
163 const union in_addr_union *from,
164 uint8_t from_prefixlen,
165 const union in_addr_union *to,
166 uint8_t to_prefixlen,
167 uint8_t tos,
168 uint32_t fwmark,
169 uint32_t table,
170 const char *iif,
171 const char *oif,
172 uint8_t protocol,
173 struct fib_rule_port_range *sport,
174 struct fib_rule_port_range *dport,
175 RoutingPolicyRule **ret) {
176
177 RoutingPolicyRule rule, *existing;
178
179 assert_return(m, -1);
180
181 rule = (RoutingPolicyRule) {
182 .family = family,
183 .from = *from,
184 .from_prefixlen = from_prefixlen,
185 .to = *to,
186 .to_prefixlen = to_prefixlen,
187 .tos = tos,
188 .fwmark = fwmark,
189 .table = table,
190 .iif = (char*) iif,
191 .oif = (char*) oif,
192 .protocol = protocol,
193 .sport = *sport,
194 .dport = *dport,
195 };
196
197 existing = set_get(m->rules, &rule);
198 if (existing) {
199 if (ret)
200 *ret = existing;
201 return 1;
202 }
203
204 existing = set_get(m->rules_foreign, &rule);
205 if (existing) {
206 if (ret)
207 *ret = existing;
208 return 0;
209 }
210
211 return -ENOENT;
212 }
213
214 int routing_policy_rule_make_local(Manager *m, RoutingPolicyRule *rule) {
215 int r;
216
217 assert(m);
218
219 if (set_contains(m->rules_foreign, rule)) {
220 set_remove(m->rules_foreign, rule);
221
222 r = set_ensure_allocated(&m->rules, &routing_policy_rule_hash_ops);
223 if (r < 0)
224 return r;
225
226 return set_put(m->rules, rule);
227 }
228
229 return -ENOENT;
230 }
231
232 static int routing_policy_rule_add_internal(Manager *m,
233 Set **rules,
234 int family,
235 const union in_addr_union *from,
236 uint8_t from_prefixlen,
237 const union in_addr_union *to,
238 uint8_t to_prefixlen,
239 uint8_t tos,
240 uint32_t fwmark,
241 uint32_t table,
242 const char *_iif,
243 const char *_oif,
244 uint8_t protocol,
245 const struct fib_rule_port_range *sport,
246 const struct fib_rule_port_range *dport,
247 RoutingPolicyRule **ret) {
248
249 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
250 _cleanup_free_ char *iif = NULL, *oif = NULL;
251 int r;
252
253 assert_return(rules, -EINVAL);
254
255 if (_iif) {
256 iif = strdup(_iif);
257 if (!iif)
258 return -ENOMEM;
259 }
260
261 if (_oif) {
262 oif = strdup(_oif);
263 if (!oif)
264 return -ENOMEM;
265 }
266
267 r = routing_policy_rule_new(&rule);
268 if (r < 0)
269 return r;
270
271 rule->manager = m;
272 rule->family = family;
273 rule->from = *from;
274 rule->from_prefixlen = from_prefixlen;
275 rule->to = *to;
276 rule->to_prefixlen = to_prefixlen;
277 rule->tos = tos;
278 rule->fwmark = fwmark;
279 rule->table = table;
280 rule->iif = TAKE_PTR(iif);
281 rule->oif = TAKE_PTR(oif);
282 rule->protocol = protocol;
283 rule->sport = *sport;
284 rule->dport = *dport;
285
286 r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
287 if (r < 0)
288 return r;
289
290 r = set_put(*rules, rule);
291 if (r < 0)
292 return r;
293
294 if (ret)
295 *ret = rule;
296
297 TAKE_PTR(rule);
298 return 0;
299 }
300
301 int routing_policy_rule_add(Manager *m,
302 int family,
303 const union in_addr_union *from,
304 uint8_t from_prefixlen,
305 const union in_addr_union *to,
306 uint8_t to_prefixlen,
307 uint8_t tos,
308 uint32_t fwmark,
309 uint32_t table,
310 const char *iif,
311 const char *oif,
312 uint8_t protocol,
313 const struct fib_rule_port_range *sport,
314 const struct fib_rule_port_range *dport,
315 RoutingPolicyRule **ret) {
316
317 return routing_policy_rule_add_internal(m, &m->rules, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, iif, oif, protocol, sport, dport, ret);
318 }
319
320 int routing_policy_rule_add_foreign(Manager *m,
321 int family,
322 const union in_addr_union *from,
323 uint8_t from_prefixlen,
324 const union in_addr_union *to,
325 uint8_t to_prefixlen,
326 uint8_t tos,
327 uint32_t fwmark,
328 uint32_t table,
329 const char *iif,
330 const char *oif,
331 uint8_t protocol,
332 const struct fib_rule_port_range *sport,
333 const struct fib_rule_port_range *dport,
334 RoutingPolicyRule **ret) {
335 return routing_policy_rule_add_internal(m, &m->rules_foreign, family, from, from_prefixlen, to, to_prefixlen, tos, fwmark, table, iif, oif, protocol, sport, dport, ret);
336 }
337
338 static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
339 int r;
340
341 assert(m);
342 assert(link);
343 assert(link->ifname);
344
345 link->routing_policy_rule_remove_messages--;
346
347 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
348 return 1;
349
350 r = sd_netlink_message_get_errno(m);
351 if (r < 0)
352 log_link_warning_errno(link, r, "Could not drop routing policy rule: %m");
353
354 return 1;
355 }
356
357 int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, link_netlink_message_handler_t callback) {
358 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
359 int r;
360
361 assert(routing_policy_rule);
362 assert(link);
363 assert(link->manager);
364 assert(link->manager->rtnl);
365 assert(link->ifindex > 0);
366 assert(IN_SET(routing_policy_rule->family, AF_INET, AF_INET6));
367
368 r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_DELRULE, routing_policy_rule->family);
369 if (r < 0)
370 return log_error_errno(r, "Could not allocate RTM_DELRULE message: %m");
371
372 if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->from) == 0) {
373 r = netlink_message_append_in_addr_union(m, FRA_SRC, routing_policy_rule->family, &routing_policy_rule->from);
374 if (r < 0)
375 return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
376
377 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, routing_policy_rule->from_prefixlen);
378 if (r < 0)
379 return log_error_errno(r, "Could not set source prefix length: %m");
380 }
381
382 if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->to) == 0) {
383 r = netlink_message_append_in_addr_union(m, FRA_DST, routing_policy_rule->family, &routing_policy_rule->to);
384 if (r < 0)
385 return log_error_errno(r, "Could not append FRA_DST attribute: %m");
386
387 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, routing_policy_rule->to_prefixlen);
388 if (r < 0)
389 return log_error_errno(r, "Could not set destination prefix length: %m");
390 }
391
392 r = netlink_call_async(link->manager->rtnl, NULL, m,
393 callback ?: routing_policy_rule_remove_handler,
394 link_netlink_destroy_callback, link);
395 if (r < 0)
396 return log_error_errno(r, "Could not send rtnetlink message: %m");
397
398 link_ref(link);
399
400 return 0;
401 }
402
403 static int routing_policy_rule_new_static(Network *network, const char *filename, unsigned section_line, RoutingPolicyRule **ret) {
404 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
405 _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
406 int r;
407
408 assert(network);
409 assert(ret);
410 assert(!!filename == (section_line > 0));
411
412 if (filename) {
413 r = network_config_section_new(filename, section_line, &n);
414 if (r < 0)
415 return r;
416
417 rule = hashmap_get(network->rules_by_section, n);
418 if (rule) {
419 *ret = TAKE_PTR(rule);
420
421 return 0;
422 }
423 }
424
425 r = routing_policy_rule_new(&rule);
426 if (r < 0)
427 return r;
428
429 rule->network = network;
430 LIST_APPEND(rules, network->rules, rule);
431 network->n_rules++;
432
433 if (filename) {
434 rule->section = TAKE_PTR(n);
435
436 r = hashmap_ensure_allocated(&network->rules_by_section, &network_config_hash_ops);
437 if (r < 0)
438 return r;
439
440 r = hashmap_put(network->rules_by_section, rule->section, rule);
441 if (r < 0)
442 return r;
443 }
444
445 *ret = TAKE_PTR(rule);
446
447 return 0;
448 }
449
450 static int routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
451 int r;
452
453 assert(rtnl);
454 assert(m);
455 assert(link);
456 assert(link->ifname);
457 assert(link->routing_policy_rule_messages > 0);
458
459 link->routing_policy_rule_messages--;
460
461 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
462 return 1;
463
464 r = sd_netlink_message_get_errno(m);
465 if (r < 0 && r != -EEXIST)
466 log_link_warning_errno(link, r, "Could not add routing policy rule: %m");
467
468 if (link->routing_policy_rule_messages == 0) {
469 log_link_debug(link, "Routing policy rule configured");
470 link->routing_policy_rules_configured = true;
471 link_check_ready(link);
472 }
473
474 return 1;
475 }
476
477 int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netlink_message_handler_t callback) {
478 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
479 int r;
480
481 assert(rule);
482 assert(link);
483 assert(link->ifindex > 0);
484 assert(link->manager);
485 assert(link->manager->rtnl);
486
487 if (rule->family == AF_INET6 && link_sysctl_ipv6_enabled(link) == 0) {
488 log_link_warning(link, "An IPv6 routing policy rule is requested, but IPv6 is disabled by sysctl, ignoring.");
489 return 0;
490 }
491
492 r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
493 if (r < 0)
494 return log_error_errno(r, "Could not allocate RTM_NEWRULE message: %m");
495
496 if (in_addr_is_null(rule->family, &rule->from) == 0) {
497 r = netlink_message_append_in_addr_union(m, FRA_SRC, rule->family, &rule->from);
498 if (r < 0)
499 return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
500
501 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen);
502 if (r < 0)
503 return log_error_errno(r, "Could not set source prefix length: %m");
504 }
505
506 if (in_addr_is_null(rule->family, &rule->to) == 0) {
507 r = netlink_message_append_in_addr_union(m, FRA_DST, rule->family, &rule->to);
508 if (r < 0)
509 return log_error_errno(r, "Could not append FRA_DST attribute: %m");
510
511 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen);
512 if (r < 0)
513 return log_error_errno(r, "Could not set destination prefix length: %m");
514 }
515
516 r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
517 if (r < 0)
518 return log_error_errno(r, "Could not append FRA_PRIORITY attribute: %m");
519
520 if (rule->tos > 0) {
521 r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
522 if (r < 0)
523 return log_error_errno(r, "Could not set ip rule tos: %m");
524 }
525
526 if (rule->table < 256) {
527 r = sd_rtnl_message_routing_policy_rule_set_table(m, rule->table);
528 if (r < 0)
529 return log_error_errno(r, "Could not set ip rule table: %m");
530 } else {
531 r = sd_rtnl_message_routing_policy_rule_set_table(m, RT_TABLE_UNSPEC);
532 if (r < 0)
533 return log_error_errno(r, "Could not set ip rule table: %m");
534
535 r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table);
536 if (r < 0)
537 return log_error_errno(r, "Could not append FRA_TABLE attribute: %m");
538 }
539
540 if (rule->fwmark > 0) {
541 r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark);
542 if (r < 0)
543 return log_error_errno(r, "Could not append FRA_FWMARK attribute: %m");
544 }
545
546 if (rule->fwmask > 0) {
547 r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
548 if (r < 0)
549 return log_error_errno(r, "Could not append FRA_FWMASK attribute: %m");
550 }
551
552 if (rule->iif) {
553 r = sd_netlink_message_append_string(m, FRA_IFNAME, rule->iif);
554 if (r < 0)
555 return log_error_errno(r, "Could not append FRA_IFNAME attribute: %m");
556 }
557
558 if (rule->oif) {
559 r = sd_netlink_message_append_string(m, FRA_OIFNAME, rule->oif);
560 if (r < 0)
561 return log_error_errno(r, "Could not append FRA_OIFNAME attribute: %m");
562 }
563
564 r = sd_netlink_message_append_u8(m, FRA_IP_PROTO, rule->protocol);
565 if (r < 0)
566 return log_error_errno(r, "Could not append FRA_IP_PROTO attribute: %m");
567
568 if (rule->sport.start != 0 || rule->sport.end != 0) {
569 r = sd_netlink_message_append_data(m, FRA_SPORT_RANGE, &rule->sport, sizeof(rule->sport));
570 if (r < 0)
571 return log_error_errno(r, "Could not append FRA_SPORT_RANGE attribute: %m");
572 }
573
574 if (rule->dport.start != 0 || rule->dport.end != 0) {
575 r = sd_netlink_message_append_data(m, FRA_DPORT_RANGE, &rule->dport, sizeof(rule->dport));
576 if (r < 0)
577 return log_error_errno(r, "Could not append FRA_DPORT_RANGE attribute: %m");
578 }
579
580 if (rule->invert_rule) {
581 r = sd_rtnl_message_routing_policy_rule_set_flags(m, FIB_RULE_INVERT);
582 if (r < 0)
583 return log_error_errno(r, "Could not append FIB_RULE_INVERT attribute: %m");
584 }
585
586 rule->link = link;
587
588 r = netlink_call_async(link->manager->rtnl, NULL, m,
589 callback ?: routing_policy_rule_handler,
590 link_netlink_destroy_callback, link);
591 if (r < 0)
592 return log_error_errno(r, "Could not send rtnetlink message: %m");
593
594 link_ref(link);
595
596 r = routing_policy_rule_add(link->manager, rule->family, &rule->from, rule->from_prefixlen, &rule->to,
597 rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, rule->iif, rule->oif, rule->protocol, &rule->sport, &rule->dport, NULL);
598 if (r < 0)
599 return log_error_errno(r, "Could not add rule: %m");
600
601 return 1;
602 }
603
604 static int parse_fwmark_fwmask(const char *s, uint32_t *fwmark, uint32_t *fwmask) {
605 _cleanup_free_ char *f = NULL;
606 char *p;
607 int r;
608
609 assert(s);
610
611 f = strdup(s);
612 if (!f)
613 return -ENOMEM;
614
615 p = strchr(f, '/');
616 if (p)
617 *p++ = '\0';
618
619 r = safe_atou32(f, fwmark);
620 if (r < 0)
621 return log_error_errno(r, "Failed to parse RPDB rule firewall mark, ignoring: %s", f);
622
623 if (p) {
624 r = safe_atou32(p, fwmask);
625 if (r < 0)
626 return log_error_errno(r, "Failed to parse RPDB rule mask, ignoring: %s", f);
627 }
628
629 return 0;
630 }
631
632 int config_parse_routing_policy_rule_tos(
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_or_set_invalidp) 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_atou8(rvalue, &n->tos);
659 if (r < 0) {
660 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule tos, ignoring: %s", rvalue);
661 return 0;
662 }
663
664 n = NULL;
665
666 return 0;
667 }
668
669 int config_parse_routing_policy_rule_priority(
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_or_set_invalidp) 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->priority);
696 if (r < 0) {
697 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule priority, ignoring: %s", rvalue);
698 return 0;
699 }
700
701 n = NULL;
702
703 return 0;
704 }
705
706 int config_parse_routing_policy_rule_table(
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_or_set_invalidp) RoutingPolicyRule *n = NULL;
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 = safe_atou32(rvalue, &n->table);
733 if (r < 0) {
734 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule table, ignoring: %s", rvalue);
735 return 0;
736 }
737
738 n = NULL;
739
740 return 0;
741 }
742
743 int config_parse_routing_policy_rule_fwmark_mask(
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_or_set_invalidp) RoutingPolicyRule *n = NULL;
756 Network *network = userdata;
757 int r;
758
759 assert(filename);
760 assert(section);
761 assert(lvalue);
762 assert(rvalue);
763 assert(data);
764
765 r = routing_policy_rule_new_static(network, filename, section_line, &n);
766 if (r < 0)
767 return r;
768
769 r = parse_fwmark_fwmask(rvalue, &n->fwmark, &n->fwmask);
770 if (r < 0) {
771 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue);
772 return 0;
773 }
774
775 n = NULL;
776
777 return 0;
778 }
779
780 int config_parse_routing_policy_rule_prefix(
781 const char *unit,
782 const char *filename,
783 unsigned line,
784 const char *section,
785 unsigned section_line,
786 const char *lvalue,
787 int ltype,
788 const char *rvalue,
789 void *data,
790 void *userdata) {
791
792 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
793 Network *network = userdata;
794 union in_addr_union *buffer;
795 uint8_t *prefixlen;
796 int r;
797
798 assert(filename);
799 assert(section);
800 assert(lvalue);
801 assert(rvalue);
802 assert(data);
803
804 r = routing_policy_rule_new_static(network, filename, section_line, &n);
805 if (r < 0)
806 return r;
807
808 if (streq(lvalue, "To")) {
809 buffer = &n->to;
810 prefixlen = &n->to_prefixlen;
811 } else {
812 buffer = &n->from;
813 prefixlen = &n->from_prefixlen;
814 }
815
816 r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
817 if (r < 0) {
818 log_syntax(unit, LOG_ERR, filename, line, r, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue);
819 return 0;
820 }
821
822 n = NULL;
823
824 return 0;
825 }
826
827 int config_parse_routing_policy_rule_device(
828 const char *unit,
829 const char *filename,
830 unsigned line,
831 const char *section,
832 unsigned section_line,
833 const char *lvalue,
834 int ltype,
835 const char *rvalue,
836 void *data,
837 void *userdata) {
838
839 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
840 Network *network = userdata;
841 int r;
842
843 assert(filename);
844 assert(section);
845 assert(lvalue);
846 assert(rvalue);
847 assert(data);
848
849 r = routing_policy_rule_new_static(network, filename, section_line, &n);
850 if (r < 0)
851 return r;
852
853 if (!ifname_valid(rvalue)) {
854 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse '%s' interface name, ignoring: %s", lvalue, rvalue);
855 return 0;
856 }
857
858 if (streq(lvalue, "IncomingInterface")) {
859 r = free_and_strdup(&n->iif, rvalue);
860 if (r < 0)
861 return log_oom();
862 } else {
863 r = free_and_strdup(&n->oif, rvalue);
864 if (r < 0)
865 return log_oom();
866 }
867
868 n = NULL;
869
870 return 0;
871 }
872
873 int config_parse_routing_policy_rule_port_range(
874 const char *unit,
875 const char *filename,
876 unsigned line,
877 const char *section,
878 unsigned section_line,
879 const char *lvalue,
880 int ltype,
881 const char *rvalue,
882 void *data,
883 void *userdata) {
884 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
885 Network *network = userdata;
886 uint16_t low, high;
887 int r;
888
889 assert(filename);
890 assert(section);
891 assert(lvalue);
892 assert(rvalue);
893 assert(data);
894
895 r = routing_policy_rule_new_static(network, filename, section_line, &n);
896 if (r < 0)
897 return r;
898
899 r = parse_ip_port_range(rvalue, &low, &high);
900 if (r < 0) {
901 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse routing policy rule port range '%s'", rvalue);
902 return 0;
903 }
904
905 if (streq(lvalue, "SourcePort")) {
906 n->sport.start = low;
907 n->sport.end = high;
908 } else {
909 n->dport.start = low;
910 n->dport.end = high;
911 }
912
913 n = NULL;
914
915 return 0;
916 }
917
918 int config_parse_routing_policy_rule_ip_protocol(
919 const char *unit,
920 const char *filename,
921 unsigned line,
922 const char *section,
923 unsigned section_line,
924 const char *lvalue,
925 int ltype,
926 const char *rvalue,
927 void *data,
928 void *userdata) {
929
930 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
931 Network *network = userdata;
932 int r;
933
934 assert(filename);
935 assert(section);
936 assert(lvalue);
937 assert(rvalue);
938 assert(data);
939
940 r = routing_policy_rule_new_static(network, filename, section_line, &n);
941 if (r < 0)
942 return r;
943
944 r = parse_ip_protocol(rvalue);
945 if (r < 0) {
946 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IP protocol '%s' for routing policy rule, ignoring: %m", rvalue);
947 return 0;
948 }
949
950 n->protocol = r;
951
952 n = NULL;
953
954 return 0;
955 }
956
957 int config_parse_routing_policy_rule_invert(
958 const char *unit,
959 const char *filename,
960 unsigned line,
961 const char *section,
962 unsigned section_line,
963 const char *lvalue,
964 int ltype,
965 const char *rvalue,
966 void *data,
967 void *userdata) {
968
969 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
970 Network *network = userdata;
971 int r;
972
973 assert(filename);
974 assert(section);
975 assert(lvalue);
976 assert(rvalue);
977 assert(data);
978
979 r = routing_policy_rule_new_static(network, filename, section_line, &n);
980 if (r < 0)
981 return r;
982
983 r = parse_boolean(rvalue);
984 if (r < 0) {
985 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule invert, ignoring: %s", rvalue);
986 return 0;
987 }
988
989 n->invert_rule = r;
990
991 n = NULL;
992
993 return 0;
994 }
995
996 static int routing_policy_rule_read_full_file(const char *state_file, char **ret) {
997 _cleanup_free_ char *s = NULL;
998 size_t size;
999 int r;
1000
1001 assert(state_file);
1002
1003 r = read_full_file(state_file, &s, &size);
1004 if (r == -ENOENT)
1005 return -ENODATA;
1006 if (r < 0)
1007 return r;
1008 if (size <= 0)
1009 return -ENODATA;
1010
1011 *ret = TAKE_PTR(s);
1012
1013 return size;
1014 }
1015
1016 int routing_policy_serialize_rules(Set *rules, FILE *f) {
1017 RoutingPolicyRule *rule = NULL;
1018 Iterator i;
1019 int r;
1020
1021 assert(f);
1022
1023 SET_FOREACH(rule, rules, i) {
1024 _cleanup_free_ char *from_str = NULL, *to_str = NULL;
1025 bool space = false;
1026
1027 fputs("RULE=", f);
1028
1029 if (!in_addr_is_null(rule->family, &rule->from)) {
1030 r = in_addr_to_string(rule->family, &rule->from, &from_str);
1031 if (r < 0)
1032 return r;
1033
1034 fprintf(f, "from=%s/%hhu",
1035 from_str, rule->from_prefixlen);
1036 space = true;
1037 }
1038
1039 if (!in_addr_is_null(rule->family, &rule->to)) {
1040 r = in_addr_to_string(rule->family, &rule->to, &to_str);
1041 if (r < 0)
1042 return r;
1043
1044 fprintf(f, "%sto=%s/%hhu",
1045 space ? " " : "",
1046 to_str, rule->to_prefixlen);
1047 space = true;
1048 }
1049
1050 if (rule->tos != 0) {
1051 fprintf(f, "%stos=%hhu",
1052 space ? " " : "",
1053 rule->tos);
1054 space = true;
1055 }
1056
1057 if (rule->fwmark != 0) {
1058 fprintf(f, "%sfwmark=%"PRIu32"/%"PRIu32,
1059 space ? " " : "",
1060 rule->fwmark, rule->fwmask);
1061 space = true;
1062 }
1063
1064 if (rule->iif) {
1065 fprintf(f, "%siif=%s",
1066 space ? " " : "",
1067 rule->iif);
1068 space = true;
1069 }
1070
1071 if (rule->oif) {
1072 fprintf(f, "%soif=%s",
1073 space ? " " : "",
1074 rule->oif);
1075 space = true;
1076 }
1077
1078 if (rule->protocol != 0) {
1079 fprintf(f, "%sprotocol=%hhu",
1080 space ? " " : "",
1081 rule->protocol);
1082 space = true;
1083 }
1084
1085 if (rule->sport.start != 0 || rule->sport.end != 0) {
1086 fprintf(f, "%ssourcesport=%"PRIu16"-%"PRIu16,
1087 space ? " " : "",
1088 rule->sport.start, rule->sport.end);
1089 space = true;
1090 }
1091
1092 if (rule->dport.start != 0 || rule->dport.end != 0) {
1093 fprintf(f, "%sdestinationport=%"PRIu16"-%"PRIu16,
1094 space ? " " : "",
1095 rule->dport.start, rule->dport.end);
1096 space = true;
1097 }
1098
1099 fprintf(f, "%stable=%"PRIu32 "\n",
1100 space ? " " : "",
1101 rule->table);
1102 }
1103
1104 return 0;
1105 }
1106
1107 int routing_policy_load_rules(const char *state_file, Set **rules) {
1108 _cleanup_strv_free_ char **l = NULL;
1109 _cleanup_free_ char *data = NULL;
1110 uint16_t low = 0, high = 0;
1111 const char *p;
1112 char **i;
1113 int r;
1114
1115 assert(state_file);
1116 assert(rules);
1117
1118 r = routing_policy_rule_read_full_file(state_file, &data);
1119 if (r <= 0)
1120 return r;
1121
1122 l = strv_split_newlines(data);
1123 if (!l)
1124 return -ENOMEM;
1125
1126 r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
1127 if (r < 0)
1128 return r;
1129
1130 STRV_FOREACH(i, l) {
1131 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
1132
1133 p = startswith(*i, "RULE=");
1134 if (!p)
1135 continue;
1136
1137 r = routing_policy_rule_new(&rule);
1138 if (r < 0)
1139 return r;
1140
1141 for (;;) {
1142 _cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
1143
1144 r = extract_first_word(&p, &word, NULL, 0);
1145 if (r < 0)
1146 return r;
1147 if (r == 0)
1148 break;
1149
1150 r = split_pair(word, "=", &a, &b);
1151 if (r < 0)
1152 continue;
1153
1154 if (STR_IN_SET(a, "from", "to")) {
1155 union in_addr_union *buffer;
1156 uint8_t *prefixlen;
1157
1158 if (streq(a, "to")) {
1159 buffer = &rule->to;
1160 prefixlen = &rule->to_prefixlen;
1161 } else {
1162 buffer = &rule->from;
1163 prefixlen = &rule->from_prefixlen;
1164 }
1165
1166 r = in_addr_prefix_from_string_auto(b, &rule->family, buffer, prefixlen);
1167 if (r < 0) {
1168 log_error_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
1169 continue;
1170 }
1171
1172 } else if (streq(a, "tos")) {
1173 r = safe_atou8(b, &rule->tos);
1174 if (r < 0) {
1175 log_error_errno(r, "Failed to parse RPDB rule tos, ignoring: %s", b);
1176 continue;
1177 }
1178 } else if (streq(a, "table")) {
1179 r = safe_atou32(b, &rule->table);
1180 if (r < 0) {
1181 log_error_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b);
1182 continue;
1183 }
1184 } else if (streq(a, "fwmark")) {
1185
1186 r = parse_fwmark_fwmask(b, &rule->fwmark, &rule->fwmask);
1187 if (r < 0) {
1188 log_error_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
1189 continue;
1190 }
1191 } else if (streq(a, "iif")) {
1192
1193 if (free_and_strdup(&rule->iif, b) < 0)
1194 return log_oom();
1195
1196 } else if (streq(a, "oif")) {
1197
1198 if (free_and_strdup(&rule->oif, b) < 0)
1199 return log_oom();
1200 } else if (streq(a, "protocol")) {
1201 r = safe_atou8(b, &rule->protocol);
1202 if (r < 0) {
1203 log_error_errno(r, "Failed to parse RPDB rule protocol, ignoring: %s", b);
1204 continue;
1205 }
1206 } else if (streq(a, "sourceport")) {
1207
1208 r = parse_ip_port_range(b, &low, &high);
1209 if (r < 0) {
1210 log_error_errno(r, "Invalid routing policy rule source port range, ignoring assignment:'%s'", b);
1211 continue;
1212 }
1213
1214 rule->sport.start = low;
1215 rule->sport.end = high;
1216
1217 } else if (streq(a, "destinationport")) {
1218
1219 r = parse_ip_port_range(b, &low, &high);
1220 if (r < 0) {
1221 log_error_errno(r, "Invalid routing policy rule destination port range, ignoring assignment:'%s'", b);
1222 continue;
1223 }
1224
1225 rule->dport.start = low;
1226 rule->dport.end = high;
1227 }
1228 }
1229
1230 r = set_put(*rules, rule);
1231 if (r < 0) {
1232 log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", p);
1233 continue;
1234 }
1235
1236 rule = NULL;
1237 }
1238
1239 return 0;
1240 }
1241
1242 static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule *rule) {
1243 RoutingPolicyRule *link_rule;
1244 Iterator i;
1245 Link *link;
1246
1247 assert(m);
1248 assert(rule);
1249
1250 HASHMAP_FOREACH(link, m->links, i) {
1251 if (!link->network)
1252 continue;
1253
1254 LIST_FOREACH(rules, link_rule, link->network->rules)
1255 if (routing_policy_rule_compare_func(link_rule, rule) == 0)
1256 return true;
1257 }
1258
1259 return false;
1260 }
1261
1262 void routing_policy_rule_purge(Manager *m, Link *link) {
1263 RoutingPolicyRule *rule, *existing;
1264 Iterator i;
1265 int r;
1266
1267 assert(m);
1268 assert(link);
1269
1270 SET_FOREACH(rule, m->rules_saved, i) {
1271 existing = set_get(m->rules_foreign, rule);
1272 if (!existing)
1273 continue; /* Saved rule does not exist anymore. */
1274
1275 if (manager_links_have_routing_policy_rule(m, existing))
1276 continue; /* Existing links have the saved rule. */
1277
1278 /* Existing links do not have the saved rule. Let's drop the rule now, and re-configure it
1279 * later when it is requested. */
1280
1281 r = routing_policy_rule_remove(existing, link, NULL);
1282 if (r < 0) {
1283 log_warning_errno(r, "Could not remove routing policy rules: %m");
1284 continue;
1285 }
1286
1287 link->routing_policy_rule_remove_messages++;
1288
1289 assert_se(set_remove(m->rules_foreign, existing) == existing);
1290 routing_policy_rule_free(existing);
1291 }
1292 }