]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-routing-policy-rule.c
network: in_addr_is_null() may return negative errno
[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 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, 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 if (routing_policy_rule->family == AF_INET)
374 r = sd_netlink_message_append_in_addr(m, FRA_SRC, &routing_policy_rule->from.in);
375 else
376 r = sd_netlink_message_append_in6_addr(m, FRA_SRC, &routing_policy_rule->from.in6);
377 if (r < 0)
378 return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
379
380 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, routing_policy_rule->from_prefixlen);
381 if (r < 0)
382 return log_error_errno(r, "Could not set source prefix length: %m");
383 }
384
385 if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->to) == 0) {
386 if (routing_policy_rule->family == AF_INET)
387 r = sd_netlink_message_append_in_addr(m, FRA_DST, &routing_policy_rule->to.in);
388 else
389 r = sd_netlink_message_append_in6_addr(m, FRA_DST, &routing_policy_rule->to.in6);
390 if (r < 0)
391 return log_error_errno(r, "Could not append FRA_DST attribute: %m");
392
393 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, routing_policy_rule->to_prefixlen);
394 if (r < 0)
395 return log_error_errno(r, "Could not set destination prefix length: %m");
396 }
397
398 r = netlink_call_async(link->manager->rtnl, NULL, m,
399 callback ?: routing_policy_rule_remove_handler,
400 link_netlink_destroy_callback, link);
401 if (r < 0)
402 return log_error_errno(r, "Could not send rtnetlink message: %m");
403
404 link_ref(link);
405
406 return 0;
407 }
408
409 static int routing_policy_rule_new_static(Network *network, const char *filename, unsigned section_line, RoutingPolicyRule **ret) {
410 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
411 _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
412 int r;
413
414 assert(network);
415 assert(ret);
416 assert(!!filename == (section_line > 0));
417
418 if (filename) {
419 r = network_config_section_new(filename, section_line, &n);
420 if (r < 0)
421 return r;
422
423 rule = hashmap_get(network->rules_by_section, n);
424 if (rule) {
425 *ret = TAKE_PTR(rule);
426
427 return 0;
428 }
429 }
430
431 r = routing_policy_rule_new(&rule);
432 if (r < 0)
433 return r;
434
435 rule->network = network;
436 LIST_APPEND(rules, network->rules, rule);
437 network->n_rules++;
438
439 if (filename) {
440 rule->section = TAKE_PTR(n);
441
442 r = hashmap_ensure_allocated(&network->rules_by_section, &network_config_hash_ops);
443 if (r < 0)
444 return r;
445
446 r = hashmap_put(network->rules_by_section, rule->section, rule);
447 if (r < 0)
448 return r;
449 }
450
451 *ret = TAKE_PTR(rule);
452
453 return 0;
454 }
455
456 static int routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
457 int r;
458
459 assert(rtnl);
460 assert(m);
461 assert(link);
462 assert(link->ifname);
463 assert(link->routing_policy_rule_messages > 0);
464
465 link->routing_policy_rule_messages--;
466
467 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
468 return 1;
469
470 r = sd_netlink_message_get_errno(m);
471 if (r < 0 && r != -EEXIST)
472 log_link_warning_errno(link, r, "Could not add routing policy rule: %m");
473
474 if (link->routing_policy_rule_messages == 0) {
475 log_link_debug(link, "Routing policy rule configured");
476 link->routing_policy_rules_configured = true;
477 link_check_ready(link);
478 }
479
480 return 1;
481 }
482
483 int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netlink_message_handler_t callback, bool update) {
484 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
485 int r;
486
487 assert(rule);
488 assert(link);
489 assert(link->ifindex > 0);
490 assert(link->manager);
491 assert(link->manager->rtnl);
492
493 r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
494 if (r < 0)
495 return log_error_errno(r, "Could not allocate RTM_NEWRULE message: %m");
496
497 if (in_addr_is_null(rule->family, &rule->from) == 0) {
498 if (rule->family == AF_INET)
499 r = sd_netlink_message_append_in_addr(m, FRA_SRC, &rule->from.in);
500 else
501 r = sd_netlink_message_append_in6_addr(m, FRA_SRC, &rule->from.in6);
502 if (r < 0)
503 return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
504
505 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen);
506 if (r < 0)
507 return log_error_errno(r, "Could not set source prefix length: %m");
508 }
509
510 if (in_addr_is_null(rule->family, &rule->to) == 0) {
511 if (rule->family == AF_INET)
512 r = sd_netlink_message_append_in_addr(m, FRA_DST, &rule->to.in);
513 else
514 r = sd_netlink_message_append_in6_addr(m, FRA_DST, &rule->to.in6);
515 if (r < 0)
516 return log_error_errno(r, "Could not append FRA_DST attribute: %m");
517
518 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen);
519 if (r < 0)
520 return log_error_errno(r, "Could not set destination prefix length: %m");
521 }
522
523 r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
524 if (r < 0)
525 return log_error_errno(r, "Could not append FRA_PRIORITY attribute: %m");
526
527 if (rule->tos > 0) {
528 r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
529 if (r < 0)
530 return log_error_errno(r, "Could not set ip rule tos: %m");
531 }
532
533 if (rule->table < 256) {
534 r = sd_rtnl_message_routing_policy_rule_set_table(m, rule->table);
535 if (r < 0)
536 return log_error_errno(r, "Could not set ip rule table: %m");
537 } else {
538 r = sd_rtnl_message_routing_policy_rule_set_table(m, RT_TABLE_UNSPEC);
539 if (r < 0)
540 return log_error_errno(r, "Could not set ip rule table: %m");
541
542 r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table);
543 if (r < 0)
544 return log_error_errno(r, "Could not append FRA_TABLE attribute: %m");
545 }
546
547 if (rule->fwmark > 0) {
548 r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark);
549 if (r < 0)
550 return log_error_errno(r, "Could not append FRA_FWMARK attribute: %m");
551 }
552
553 if (rule->fwmask > 0) {
554 r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
555 if (r < 0)
556 return log_error_errno(r, "Could not append FRA_FWMASK attribute: %m");
557 }
558
559 if (rule->iif) {
560 r = sd_netlink_message_append_string(m, FRA_IFNAME, rule->iif);
561 if (r < 0)
562 return log_error_errno(r, "Could not append FRA_IFNAME attribute: %m");
563 }
564
565 if (rule->oif) {
566 r = sd_netlink_message_append_string(m, FRA_OIFNAME, rule->oif);
567 if (r < 0)
568 return log_error_errno(r, "Could not append FRA_OIFNAME attribute: %m");
569 }
570
571 r = sd_netlink_message_append_u8(m, FRA_IP_PROTO, rule->protocol);
572 if (r < 0)
573 return log_error_errno(r, "Could not append FRA_IP_PROTO attribute: %m");
574
575 if (rule->sport.start != 0 || rule->sport.end != 0) {
576 r = sd_netlink_message_append_data(m, FRA_SPORT_RANGE, &rule->sport, sizeof(rule->sport));
577 if (r < 0)
578 return log_error_errno(r, "Could not append FRA_SPORT_RANGE attribute: %m");
579 }
580
581 if (rule->dport.start != 0 || rule->dport.end != 0) {
582 r = sd_netlink_message_append_data(m, FRA_DPORT_RANGE, &rule->dport, sizeof(rule->dport));
583 if (r < 0)
584 return log_error_errno(r, "Could not append FRA_DPORT_RANGE attribute: %m");
585 }
586
587 if (rule->invert_rule) {
588 r = sd_rtnl_message_routing_policy_rule_set_flags(m, FIB_RULE_INVERT);
589 if (r < 0)
590 return log_error_errno(r, "Could not append FIB_RULE_INVERT attribute: %m");
591 }
592
593 rule->link = link;
594
595 r = netlink_call_async(link->manager->rtnl, NULL, m,
596 callback ?: routing_policy_rule_handler,
597 link_netlink_destroy_callback, link);
598 if (r < 0)
599 return log_error_errno(r, "Could not send rtnetlink message: %m");
600
601 link_ref(link);
602
603 r = routing_policy_rule_add(link->manager, rule->family, &rule->from, rule->from_prefixlen, &rule->to,
604 rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, rule->iif, rule->oif, rule->protocol, &rule->sport, &rule->dport, NULL);
605 if (r < 0)
606 return log_error_errno(r, "Could not add rule: %m");
607
608 return 0;
609 }
610
611 static int parse_fwmark_fwmask(const char *s, uint32_t *fwmark, uint32_t *fwmask) {
612 _cleanup_free_ char *f = NULL;
613 char *p;
614 int r;
615
616 assert(s);
617
618 f = strdup(s);
619 if (!f)
620 return -ENOMEM;
621
622 p = strchr(f, '/');
623 if (p)
624 *p++ = '\0';
625
626 r = safe_atou32(f, fwmark);
627 if (r < 0)
628 return log_error_errno(r, "Failed to parse RPDB rule firewall mark, ignoring: %s", f);
629
630 if (p) {
631 r = safe_atou32(p, fwmask);
632 if (r < 0)
633 return log_error_errno(r, "Failed to parse RPDB rule mask, ignoring: %s", f);
634 }
635
636 return 0;
637 }
638
639 int config_parse_routing_policy_rule_tos(
640 const char *unit,
641 const char *filename,
642 unsigned line,
643 const char *section,
644 unsigned section_line,
645 const char *lvalue,
646 int ltype,
647 const char *rvalue,
648 void *data,
649 void *userdata) {
650
651 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
652 Network *network = userdata;
653 int r;
654
655 assert(filename);
656 assert(section);
657 assert(lvalue);
658 assert(rvalue);
659 assert(data);
660
661 r = routing_policy_rule_new_static(network, filename, section_line, &n);
662 if (r < 0)
663 return r;
664
665 r = safe_atou8(rvalue, &n->tos);
666 if (r < 0) {
667 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule tos, ignoring: %s", rvalue);
668 return 0;
669 }
670
671 n = NULL;
672
673 return 0;
674 }
675
676 int config_parse_routing_policy_rule_priority(
677 const char *unit,
678 const char *filename,
679 unsigned line,
680 const char *section,
681 unsigned section_line,
682 const char *lvalue,
683 int ltype,
684 const char *rvalue,
685 void *data,
686 void *userdata) {
687
688 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
689 Network *network = userdata;
690 int r;
691
692 assert(filename);
693 assert(section);
694 assert(lvalue);
695 assert(rvalue);
696 assert(data);
697
698 r = routing_policy_rule_new_static(network, filename, section_line, &n);
699 if (r < 0)
700 return r;
701
702 r = safe_atou32(rvalue, &n->priority);
703 if (r < 0) {
704 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule priority, ignoring: %s", rvalue);
705 return 0;
706 }
707
708 n = NULL;
709
710 return 0;
711 }
712
713 int config_parse_routing_policy_rule_table(
714 const char *unit,
715 const char *filename,
716 unsigned line,
717 const char *section,
718 unsigned section_line,
719 const char *lvalue,
720 int ltype,
721 const char *rvalue,
722 void *data,
723 void *userdata) {
724
725 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
726 Network *network = userdata;
727 int r;
728
729 assert(filename);
730 assert(section);
731 assert(lvalue);
732 assert(rvalue);
733 assert(data);
734
735 r = routing_policy_rule_new_static(network, filename, section_line, &n);
736 if (r < 0)
737 return r;
738
739 r = safe_atou32(rvalue, &n->table);
740 if (r < 0) {
741 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule table, ignoring: %s", rvalue);
742 return 0;
743 }
744
745 n = NULL;
746
747 return 0;
748 }
749
750 int config_parse_routing_policy_rule_fwmark_mask(
751 const char *unit,
752 const char *filename,
753 unsigned line,
754 const char *section,
755 unsigned section_line,
756 const char *lvalue,
757 int ltype,
758 const char *rvalue,
759 void *data,
760 void *userdata) {
761
762 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
763 Network *network = userdata;
764 int r;
765
766 assert(filename);
767 assert(section);
768 assert(lvalue);
769 assert(rvalue);
770 assert(data);
771
772 r = routing_policy_rule_new_static(network, filename, section_line, &n);
773 if (r < 0)
774 return r;
775
776 r = parse_fwmark_fwmask(rvalue, &n->fwmark, &n->fwmask);
777 if (r < 0) {
778 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue);
779 return 0;
780 }
781
782 n = NULL;
783
784 return 0;
785 }
786
787 int config_parse_routing_policy_rule_prefix(
788 const char *unit,
789 const char *filename,
790 unsigned line,
791 const char *section,
792 unsigned section_line,
793 const char *lvalue,
794 int ltype,
795 const char *rvalue,
796 void *data,
797 void *userdata) {
798
799 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
800 Network *network = userdata;
801 union in_addr_union *buffer;
802 uint8_t *prefixlen;
803 int r;
804
805 assert(filename);
806 assert(section);
807 assert(lvalue);
808 assert(rvalue);
809 assert(data);
810
811 r = routing_policy_rule_new_static(network, filename, section_line, &n);
812 if (r < 0)
813 return r;
814
815 if (streq(lvalue, "To")) {
816 buffer = &n->to;
817 prefixlen = &n->to_prefixlen;
818 } else {
819 buffer = &n->from;
820 prefixlen = &n->from_prefixlen;
821 }
822
823 r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
824 if (r < 0) {
825 log_syntax(unit, LOG_ERR, filename, line, r, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue);
826 return 0;
827 }
828
829 n = NULL;
830
831 return 0;
832 }
833
834 int config_parse_routing_policy_rule_device(
835 const char *unit,
836 const char *filename,
837 unsigned line,
838 const char *section,
839 unsigned section_line,
840 const char *lvalue,
841 int ltype,
842 const char *rvalue,
843 void *data,
844 void *userdata) {
845
846 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
847 Network *network = userdata;
848 int r;
849
850 assert(filename);
851 assert(section);
852 assert(lvalue);
853 assert(rvalue);
854 assert(data);
855
856 r = routing_policy_rule_new_static(network, filename, section_line, &n);
857 if (r < 0)
858 return r;
859
860 if (!ifname_valid(rvalue)) {
861 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse '%s' interface name, ignoring: %s", lvalue, rvalue);
862 return 0;
863 }
864
865 if (streq(lvalue, "IncomingInterface")) {
866 r = free_and_strdup(&n->iif, rvalue);
867 if (r < 0)
868 return log_oom();
869 } else {
870 r = free_and_strdup(&n->oif, rvalue);
871 if (r < 0)
872 return log_oom();
873 }
874
875 n = NULL;
876
877 return 0;
878 }
879
880 int config_parse_routing_policy_rule_port_range(
881 const char *unit,
882 const char *filename,
883 unsigned line,
884 const char *section,
885 unsigned section_line,
886 const char *lvalue,
887 int ltype,
888 const char *rvalue,
889 void *data,
890 void *userdata) {
891 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
892 Network *network = userdata;
893 uint16_t low, high;
894 int r;
895
896 assert(filename);
897 assert(section);
898 assert(lvalue);
899 assert(rvalue);
900 assert(data);
901
902 r = routing_policy_rule_new_static(network, filename, section_line, &n);
903 if (r < 0)
904 return r;
905
906 r = parse_ip_port_range(rvalue, &low, &high);
907 if (r < 0) {
908 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse routing policy rule port range '%s'", rvalue);
909 return 0;
910 }
911
912 if (streq(lvalue, "SourcePort")) {
913 n->sport.start = low;
914 n->sport.end = high;
915 } else {
916 n->dport.start = low;
917 n->dport.end = high;
918 }
919
920 n = NULL;
921
922 return 0;
923 }
924
925 int config_parse_routing_policy_rule_ip_protocol(
926 const char *unit,
927 const char *filename,
928 unsigned line,
929 const char *section,
930 unsigned section_line,
931 const char *lvalue,
932 int ltype,
933 const char *rvalue,
934 void *data,
935 void *userdata) {
936
937 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
938 Network *network = userdata;
939 int r;
940
941 assert(filename);
942 assert(section);
943 assert(lvalue);
944 assert(rvalue);
945 assert(data);
946
947 r = routing_policy_rule_new_static(network, filename, section_line, &n);
948 if (r < 0)
949 return r;
950
951 r = parse_ip_protocol(rvalue);
952 if (r < 0) {
953 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IP protocol '%s' for routing policy rule, ignoring: %m", rvalue);
954 return 0;
955 }
956
957 n->protocol = r;
958
959 n = NULL;
960
961 return 0;
962 }
963
964 int config_parse_routing_policy_rule_invert(
965 const char *unit,
966 const char *filename,
967 unsigned line,
968 const char *section,
969 unsigned section_line,
970 const char *lvalue,
971 int ltype,
972 const char *rvalue,
973 void *data,
974 void *userdata) {
975
976 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
977 Network *network = userdata;
978 int r;
979
980 assert(filename);
981 assert(section);
982 assert(lvalue);
983 assert(rvalue);
984 assert(data);
985
986 r = routing_policy_rule_new_static(network, filename, section_line, &n);
987 if (r < 0)
988 return r;
989
990 r = parse_boolean(rvalue);
991 if (r < 0) {
992 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule invert, ignoring: %s", rvalue);
993 return 0;
994 }
995
996 n->invert_rule = r;
997
998 n = NULL;
999
1000 return 0;
1001 }
1002
1003 static int routing_policy_rule_read_full_file(const char *state_file, char **ret) {
1004 _cleanup_free_ char *s = NULL;
1005 size_t size;
1006 int r;
1007
1008 assert(state_file);
1009
1010 r = read_full_file(state_file, &s, &size);
1011 if (r == -ENOENT)
1012 return -ENODATA;
1013 if (r < 0)
1014 return r;
1015 if (size <= 0)
1016 return -ENODATA;
1017
1018 *ret = TAKE_PTR(s);
1019
1020 return size;
1021 }
1022
1023 int routing_policy_serialize_rules(Set *rules, FILE *f) {
1024 RoutingPolicyRule *rule = NULL;
1025 Iterator i;
1026 int r;
1027
1028 assert(f);
1029
1030 SET_FOREACH(rule, rules, i) {
1031 _cleanup_free_ char *from_str = NULL, *to_str = NULL;
1032 bool space = false;
1033
1034 fputs("RULE=", f);
1035
1036 if (!in_addr_is_null(rule->family, &rule->from)) {
1037 r = in_addr_to_string(rule->family, &rule->from, &from_str);
1038 if (r < 0)
1039 return r;
1040
1041 fprintf(f, "from=%s/%hhu",
1042 from_str, rule->from_prefixlen);
1043 space = true;
1044 }
1045
1046 if (!in_addr_is_null(rule->family, &rule->to)) {
1047 r = in_addr_to_string(rule->family, &rule->to, &to_str);
1048 if (r < 0)
1049 return r;
1050
1051 fprintf(f, "%sto=%s/%hhu",
1052 space ? " " : "",
1053 to_str, rule->to_prefixlen);
1054 space = true;
1055 }
1056
1057 if (rule->tos != 0) {
1058 fprintf(f, "%stos=%hhu",
1059 space ? " " : "",
1060 rule->tos);
1061 space = true;
1062 }
1063
1064 if (rule->fwmark != 0) {
1065 fprintf(f, "%sfwmark=%"PRIu32"/%"PRIu32,
1066 space ? " " : "",
1067 rule->fwmark, rule->fwmask);
1068 space = true;
1069 }
1070
1071 if (rule->iif) {
1072 fprintf(f, "%siif=%s",
1073 space ? " " : "",
1074 rule->iif);
1075 space = true;
1076 }
1077
1078 if (rule->oif) {
1079 fprintf(f, "%soif=%s",
1080 space ? " " : "",
1081 rule->oif);
1082 space = true;
1083 }
1084
1085 if (rule->protocol != 0) {
1086 fprintf(f, "%sprotocol=%hhu",
1087 space ? " " : "",
1088 rule->protocol);
1089 space = true;
1090 }
1091
1092 if (rule->sport.start != 0 || rule->sport.end != 0) {
1093 fprintf(f, "%ssourcesport=%"PRIu16"-%"PRIu16,
1094 space ? " " : "",
1095 rule->sport.start, rule->sport.end);
1096 space = true;
1097 }
1098
1099 if (rule->dport.start != 0 || rule->dport.end != 0) {
1100 fprintf(f, "%sdestinationport=%"PRIu16"-%"PRIu16,
1101 space ? " " : "",
1102 rule->dport.start, rule->dport.end);
1103 space = true;
1104 }
1105
1106 fprintf(f, "%stable=%"PRIu32 "\n",
1107 space ? " " : "",
1108 rule->table);
1109 }
1110
1111 return 0;
1112 }
1113
1114 int routing_policy_load_rules(const char *state_file, Set **rules) {
1115 _cleanup_strv_free_ char **l = NULL;
1116 _cleanup_free_ char *data = NULL;
1117 uint16_t low = 0, high = 0;
1118 const char *p;
1119 char **i;
1120 int r;
1121
1122 assert(state_file);
1123 assert(rules);
1124
1125 r = routing_policy_rule_read_full_file(state_file, &data);
1126 if (r <= 0)
1127 return r;
1128
1129 l = strv_split_newlines(data);
1130 if (!l)
1131 return -ENOMEM;
1132
1133 r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
1134 if (r < 0)
1135 return r;
1136
1137 STRV_FOREACH(i, l) {
1138 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
1139
1140 p = startswith(*i, "RULE=");
1141 if (!p)
1142 continue;
1143
1144 r = routing_policy_rule_new(&rule);
1145 if (r < 0)
1146 return r;
1147
1148 for (;;) {
1149 _cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
1150
1151 r = extract_first_word(&p, &word, NULL, 0);
1152 if (r < 0)
1153 return r;
1154 if (r == 0)
1155 break;
1156
1157 r = split_pair(word, "=", &a, &b);
1158 if (r < 0)
1159 continue;
1160
1161 if (STR_IN_SET(a, "from", "to")) {
1162 union in_addr_union *buffer;
1163 uint8_t *prefixlen;
1164
1165 if (streq(a, "to")) {
1166 buffer = &rule->to;
1167 prefixlen = &rule->to_prefixlen;
1168 } else {
1169 buffer = &rule->from;
1170 prefixlen = &rule->from_prefixlen;
1171 }
1172
1173 r = in_addr_prefix_from_string_auto(b, &rule->family, buffer, prefixlen);
1174 if (r < 0) {
1175 log_error_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
1176 continue;
1177 }
1178
1179 } else if (streq(a, "tos")) {
1180 r = safe_atou8(b, &rule->tos);
1181 if (r < 0) {
1182 log_error_errno(r, "Failed to parse RPDB rule tos, ignoring: %s", b);
1183 continue;
1184 }
1185 } else if (streq(a, "table")) {
1186 r = safe_atou32(b, &rule->table);
1187 if (r < 0) {
1188 log_error_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b);
1189 continue;
1190 }
1191 } else if (streq(a, "fwmark")) {
1192
1193 r = parse_fwmark_fwmask(b, &rule->fwmark, &rule->fwmask);
1194 if (r < 0) {
1195 log_error_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
1196 continue;
1197 }
1198 } else if (streq(a, "iif")) {
1199
1200 if (free_and_strdup(&rule->iif, b) < 0)
1201 return log_oom();
1202
1203 } else if (streq(a, "oif")) {
1204
1205 if (free_and_strdup(&rule->oif, b) < 0)
1206 return log_oom();
1207 } else if (streq(a, "protocol")) {
1208 r = safe_atou8(b, &rule->protocol);
1209 if (r < 0) {
1210 log_error_errno(r, "Failed to parse RPDB rule protocol, ignoring: %s", b);
1211 continue;
1212 }
1213 } else if (streq(a, "sourceport")) {
1214
1215 r = parse_ip_port_range(b, &low, &high);
1216 if (r < 0) {
1217 log_error_errno(r, "Invalid routing policy rule source port range, ignoring assignment:'%s'", b);
1218 continue;
1219 }
1220
1221 rule->sport.start = low;
1222 rule->sport.end = high;
1223
1224 } else if (streq(a, "destinationport")) {
1225
1226 r = parse_ip_port_range(b, &low, &high);
1227 if (r < 0) {
1228 log_error_errno(r, "Invalid routing policy rule destination port range, ignoring assignment:'%s'", b);
1229 continue;
1230 }
1231
1232 rule->dport.start = low;
1233 rule->dport.end = high;
1234 }
1235 }
1236
1237 r = set_put(*rules, rule);
1238 if (r < 0) {
1239 log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", p);
1240 continue;
1241 }
1242
1243 rule = NULL;
1244 }
1245
1246 return 0;
1247 }
1248
1249 void routing_policy_rule_purge(Manager *m, Link *link) {
1250 RoutingPolicyRule *rule, *existing;
1251 Iterator i;
1252 int r;
1253
1254 assert(m);
1255 assert(link);
1256
1257 SET_FOREACH(rule, m->rules_saved, i) {
1258 existing = set_get(m->rules_foreign, rule);
1259 if (existing) {
1260
1261 r = routing_policy_rule_remove(rule, link, NULL);
1262 if (r < 0) {
1263 log_warning_errno(r, "Could not remove routing policy rules: %m");
1264 continue;
1265 }
1266
1267 link->routing_policy_rule_remove_messages++;
1268 }
1269 }
1270 }