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