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