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