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