]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-routing-policy-rule.c
Merge pull request #11021 from ssahani/isatap
[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
SS
48 if (rule->manager) {
49 set_remove(rule->manager->rules, rule);
50 set_remove(rule->manager->rules_foreign, rule);
bce67bbe
SS
51 }
52
0f7f2769 53 network_config_section_free(rule->section);
762e2659
SS
54 free(rule->iif);
55 free(rule->oif);
bce67bbe
SS
56 free(rule);
57}
58
7a08d314 59static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash *state) {
bce67bbe
SS
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
926062f0
SS
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
762e2659 82 if (rule->iif)
0d7febd0 83 siphash24_compress(rule->iif, strlen(rule->iif), state);
762e2659
SS
84
85 if (rule->oif)
0d7febd0 86 siphash24_compress(rule->oif, strlen(rule->oif), state);
762e2659 87
bce67bbe
SS
88 break;
89 default:
90 /* treat any other address family as AF_UNSPEC */
91 break;
92 }
93}
94
7a08d314 95static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPolicyRule *b) {
bce67bbe
SS
96 int r;
97
a0edd02e
FB
98 r = CMP(a->family, b->family);
99 if (r != 0)
100 return r;
bce67bbe
SS
101
102 switch (a->family) {
103 case AF_INET:
104 case AF_INET6:
a0edd02e
FB
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;
bce67bbe 124
762e2659
SS
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
926062f0
SS
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
bce67bbe
SS
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
7a08d314 157DEFINE_PRIVATE_HASH_OPS(routing_policy_rule_hash_ops, RoutingPolicyRule, routing_policy_rule_hash_func, routing_policy_rule_compare_func);
bce67bbe
SS
158
159int 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,
eeab051b
YW
168 const char *iif,
169 const char *oif,
926062f0
SS
170 uint8_t protocol,
171 struct fib_rule_port_range *sport,
172 struct fib_rule_port_range *dport,
bce67bbe
SS
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,
eeab051b 188 .iif = (char*) iif,
926062f0
SS
189 .oif = (char*) oif,
190 .protocol = protocol,
191 .sport = *sport,
192 .dport = *dport,
bce67bbe
SS
193 };
194
b87dadcd
ZJS
195 existing = set_get(m->rules, &rule);
196 if (existing) {
197 if (ret)
198 *ret = existing;
199 return 1;
bce67bbe
SS
200 }
201
b87dadcd
ZJS
202 existing = set_get(m->rules_foreign, &rule);
203 if (existing) {
204 if (ret)
205 *ret = existing;
e6b65ab7 206 return 0;
bce67bbe
SS
207 }
208
209 return -ENOENT;
210}
211
212int 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
36e6e28b
SS
230static int routing_policy_rule_add_internal(Manager *m,
231 Set **rules,
bce67bbe
SS
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,
eeab051b
YW
240 const char *_iif,
241 const char *_oif,
926062f0
SS
242 uint8_t protocol,
243 const struct fib_rule_port_range *sport,
244 const struct fib_rule_port_range *dport,
bce67bbe
SS
245 RoutingPolicyRule **ret) {
246
8e766630 247 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
eeab051b 248 _cleanup_free_ char *iif = NULL, *oif = NULL;
bce67bbe
SS
249 int r;
250
251 assert_return(rules, -EINVAL);
252
eeab051b
YW
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
bce67bbe
SS
265 r = routing_policy_rule_new(&rule);
266 if (r < 0)
267 return r;
268
6964cf45 269 rule->manager = m;
bce67bbe
SS
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;
a6276f0f
YW
278 rule->iif = iif;
279 rule->oif = oif;
926062f0
SS
280 rule->protocol = protocol;
281 rule->sport = *sport;
282 rule->dport = *dport;
bce67bbe
SS
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;
a6276f0f 296 iif = oif = NULL;
bce67bbe
SS
297
298 return 0;
299}
300
301int 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,
eeab051b
YW
310 const char *iif,
311 const char *oif,
926062f0
SS
312 uint8_t protocol,
313 const struct fib_rule_port_range *sport,
314 const struct fib_rule_port_range *dport,
bce67bbe
SS
315 RoutingPolicyRule **ret) {
316
926062f0 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);
bce67bbe
SS
318}
319
320int 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,
eeab051b
YW
329 const char *iif,
330 const char *oif,
926062f0
SS
331 uint8_t protocol,
332 const struct fib_rule_port_range *sport,
333 const struct fib_rule_port_range *dport,
bce67bbe 334 RoutingPolicyRule **ret) {
926062f0 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);
bce67bbe
SS
336}
337
302a796f 338static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
bce67bbe
SS
339 int r;
340
341 assert(m);
342 assert(link);
343 assert(link->ifname);
344
7715629e 345 link->routing_policy_rule_remove_messages--;
bce67bbe
SS
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
302a796f 357int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, link_netlink_message_handler_t callback) {
bce67bbe
SS
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)) {
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
378 if (r < 0)
379 return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
380
381 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, routing_policy_rule->from_prefixlen);
382 if (r < 0)
383 return log_error_errno(r, "Could not set source prefix length: %m");
384 }
385
386 if (!in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->to)) {
387 if (routing_policy_rule->family == AF_INET)
388 r = sd_netlink_message_append_in_addr(m, FRA_DST, &routing_policy_rule->to.in);
389 else
390 r = sd_netlink_message_append_in6_addr(m, FRA_DST, &routing_policy_rule->to.in6);
391
392 if (r < 0)
393 return log_error_errno(r, "Could not append FRA_DST attribute: %m");
394
395 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, routing_policy_rule->to_prefixlen);
396 if (r < 0)
397 return log_error_errno(r, "Could not set destination prefix length: %m");
398 }
399
302a796f
YW
400 r = netlink_call_async(link->manager->rtnl, NULL, m,
401 callback ?: routing_policy_rule_remove_handler,
402 link_netlink_destroy_callback, link);
bce67bbe
SS
403 if (r < 0)
404 return log_error_errno(r, "Could not send rtnetlink message: %m");
405
406 link_ref(link);
407
408 return 0;
409}
410
411static int routing_policy_rule_new_static(Network *network, const char *filename, unsigned section_line, RoutingPolicyRule **ret) {
8e766630
LP
412 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
413 _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
bce67bbe
SS
414 int r;
415
416 assert(network);
417 assert(ret);
418 assert(!!filename == (section_line > 0));
419
0f7f2769
YW
420 if (filename) {
421 r = network_config_section_new(filename, section_line, &n);
422 if (r < 0)
423 return r;
bce67bbe 424
0f7f2769
YW
425 rule = hashmap_get(network->rules_by_section, n);
426 if (rule) {
427 *ret = TAKE_PTR(rule);
bce67bbe 428
0f7f2769
YW
429 return 0;
430 }
bce67bbe
SS
431 }
432
433 r = routing_policy_rule_new(&rule);
434 if (r < 0)
435 return r;
436
bce67bbe 437 rule->network = network;
bce67bbe
SS
438 LIST_APPEND(rules, network->rules, rule);
439 network->n_rules++;
440
0f7f2769
YW
441 if (filename) {
442 rule->section = TAKE_PTR(n);
443
3e570042
YW
444 r = hashmap_ensure_allocated(&network->rules_by_section, &network_config_hash_ops);
445 if (r < 0)
446 return r;
447
0f7f2769
YW
448 r = hashmap_put(network->rules_by_section, rule->section, rule);
449 if (r < 0)
450 return r;
451 }
452
1cc6c93a 453 *ret = TAKE_PTR(rule);
bce67bbe
SS
454
455 return 0;
456}
457
302a796f 458static int routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
bce67bbe
SS
459 int r;
460
461 assert(rtnl);
462 assert(m);
463 assert(link);
464 assert(link->ifname);
7715629e 465 assert(link->routing_policy_rule_messages > 0);
bce67bbe 466
7715629e 467 link->routing_policy_rule_messages--;
bce67bbe
SS
468
469 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
470 return 1;
471
472 r = sd_netlink_message_get_errno(m);
473 if (r < 0 && r != -EEXIST)
474 log_link_warning_errno(link, r, "Could not add routing policy rule: %m");
475
7715629e 476 if (link->routing_policy_rule_messages == 0) {
bce67bbe 477 log_link_debug(link, "Routing policy rule configured");
7715629e
ST
478 link->routing_policy_rules_configured = true;
479 link_check_ready(link);
480 }
bce67bbe
SS
481
482 return 1;
483}
484
302a796f 485int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netlink_message_handler_t callback, bool update) {
bce67bbe
SS
486 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
487 int r;
488
489 assert(rule);
490 assert(link);
491 assert(link->ifindex > 0);
492 assert(link->manager);
493 assert(link->manager->rtnl);
494
495 r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
496 if (r < 0)
497 return log_error_errno(r, "Could not allocate RTM_NEWRULE message: %m");
498
499 if (!in_addr_is_null(rule->family, &rule->from)) {
500 if (rule->family == AF_INET)
501 r = sd_netlink_message_append_in_addr(m, FRA_SRC, &rule->from.in);
502 else
503 r = sd_netlink_message_append_in6_addr(m, FRA_SRC, &rule->from.in6);
504
505 if (r < 0)
506 return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
507
508 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen);
509 if (r < 0)
510 return log_error_errno(r, "Could not set source prefix length: %m");
511 }
512
513 if (!in_addr_is_null(rule->family, &rule->to)) {
514 if (rule->family == AF_INET)
515 r = sd_netlink_message_append_in_addr(m, FRA_DST, &rule->to.in);
516 else
517 r = sd_netlink_message_append_in6_addr(m, FRA_DST, &rule->to.in6);
518
519 if (r < 0)
520 return log_error_errno(r, "Could not append FRA_DST attribute: %m");
521
522 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen);
523 if (r < 0)
524 return log_error_errno(r, "Could not set destination prefix length: %m");
525 }
526
527 r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
528 if (r < 0)
529 return log_error_errno(r, "Could not append FRA_PRIORITY attribute: %m");
530
531 if (rule->tos > 0) {
532 r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
533 if (r < 0)
534 return log_error_errno(r, "Could not set ip rule tos: %m");
535 }
536
537 if (rule->table < 256) {
538 r = sd_rtnl_message_routing_policy_rule_set_table(m, rule->table);
539 if (r < 0)
540 return log_error_errno(r, "Could not set ip rule table: %m");
541 } else {
542 r = sd_rtnl_message_routing_policy_rule_set_table(m, RT_TABLE_UNSPEC);
543 if (r < 0)
544 return log_error_errno(r, "Could not set ip rule table: %m");
545
546 r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table);
547 if (r < 0)
548 return log_error_errno(r, "Could not append FRA_TABLE attribute: %m");
549 }
550
551 if (rule->fwmark > 0) {
552 r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark);
553 if (r < 0)
554 return log_error_errno(r, "Could not append FRA_FWMARK attribute: %m");
555 }
556
557 if (rule->fwmask > 0) {
558 r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
559 if (r < 0)
560 return log_error_errno(r, "Could not append FRA_FWMASK attribute: %m");
561 }
562
762e2659
SS
563 if (rule->iif) {
564 r = sd_netlink_message_append_string(m, FRA_IFNAME, rule->iif);
565 if (r < 0)
566 return log_error_errno(r, "Could not append FRA_IFNAME attribute: %m");
567 }
568
569 if (rule->oif) {
570 r = sd_netlink_message_append_string(m, FRA_OIFNAME, rule->oif);
571 if (r < 0)
572 return log_error_errno(r, "Could not append FRA_OIFNAME attribute: %m");
573 }
574
926062f0
SS
575 r = sd_netlink_message_append_u8(m, FRA_IP_PROTO, rule->protocol);
576 if (r < 0)
577 return log_error_errno(r, "Could not append FRA_IP_PROTO attribute: %m");
578
579 if (rule->sport.start != 0 || rule->sport.end != 0) {
580 r = sd_netlink_message_append_data(m, FRA_SPORT_RANGE, &rule->sport, sizeof(rule->sport));
581 if (r < 0)
582 return log_error_errno(r, "Could not append FRA_SPORT_RANGE attribute: %m");
583 }
584
585 if (rule->dport.start != 0 || rule->dport.end != 0) {
586 r = sd_netlink_message_append_data(m, FRA_DPORT_RANGE, &rule->dport, sizeof(rule->dport));
587 if (r < 0)
588 return log_error_errno(r, "Could not append FRA_DPORT_RANGE attribute: %m");
589 }
590
bce67bbe
SS
591 rule->link = link;
592
302a796f
YW
593 r = netlink_call_async(link->manager->rtnl, NULL, m,
594 callback ?: routing_policy_rule_handler,
595 link_netlink_destroy_callback, link);
bce67bbe
SS
596 if (r < 0)
597 return log_error_errno(r, "Could not send rtnetlink message: %m");
598
599 link_ref(link);
600
601 r = routing_policy_rule_add(link->manager, rule->family, &rule->from, rule->from_prefixlen, &rule->to,
926062f0 602 rule->to_prefixlen, rule->tos, rule->fwmark, rule->table, rule->iif, rule->oif, rule->protocol, &rule->sport, &rule->dport, NULL);
bce67bbe 603 if (r < 0)
cb700a11 604 return log_error_errno(r, "Could not add rule: %m");
bce67bbe
SS
605
606 return 0;
607}
608
609static int parse_fwmark_fwmask(const char *s, uint32_t *fwmark, uint32_t *fwmask) {
610 _cleanup_free_ char *f = NULL;
611 char *p;
612 int r;
613
614 assert(s);
615
616 f = strdup(s);
617 if (!f)
618 return -ENOMEM;
619
620 p = strchr(f, '/');
621 if (p)
622 *p++ = '\0';
623
624 r = safe_atou32(f, fwmark);
625 if (r < 0)
626 return log_error_errno(r, "Failed to parse RPDB rule firewall mark, ignoring: %s", f);
627
628 if (p) {
629 r = safe_atou32(p, fwmask);
630 if (r < 0)
631 return log_error_errno(r, "Failed to parse RPDB rule mask, ignoring: %s", f);
632 }
633
634 return 0;
635}
636
637int config_parse_routing_policy_rule_tos(
638 const char *unit,
639 const char *filename,
640 unsigned line,
641 const char *section,
642 unsigned section_line,
643 const char *lvalue,
644 int ltype,
645 const char *rvalue,
646 void *data,
647 void *userdata) {
648
8e766630 649 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
bce67bbe
SS
650 Network *network = userdata;
651 int r;
652
653 assert(filename);
654 assert(section);
655 assert(lvalue);
656 assert(rvalue);
657 assert(data);
658
659 r = routing_policy_rule_new_static(network, filename, section_line, &n);
660 if (r < 0)
661 return r;
662
663 r = safe_atou8(rvalue, &n->tos);
664 if (r < 0) {
665 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule tos, ignoring: %s", rvalue);
666 return 0;
667 }
668
669 n = NULL;
670
671 return 0;
672}
673
674int config_parse_routing_policy_rule_priority(
675 const char *unit,
676 const char *filename,
677 unsigned line,
678 const char *section,
679 unsigned section_line,
680 const char *lvalue,
681 int ltype,
682 const char *rvalue,
683 void *data,
684 void *userdata) {
685
8e766630 686 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
bce67bbe
SS
687 Network *network = userdata;
688 int r;
689
690 assert(filename);
691 assert(section);
692 assert(lvalue);
693 assert(rvalue);
694 assert(data);
695
696 r = routing_policy_rule_new_static(network, filename, section_line, &n);
697 if (r < 0)
698 return r;
699
700 r = safe_atou32(rvalue, &n->priority);
701 if (r < 0) {
702 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule priority, ignoring: %s", rvalue);
703 return 0;
704 }
705
706 n = NULL;
707
708 return 0;
709}
710
711int config_parse_routing_policy_rule_table(
712 const char *unit,
713 const char *filename,
714 unsigned line,
715 const char *section,
716 unsigned section_line,
717 const char *lvalue,
718 int ltype,
719 const char *rvalue,
720 void *data,
721 void *userdata) {
722
8e766630 723 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
bce67bbe
SS
724 Network *network = userdata;
725 int r;
726
727 assert(filename);
728 assert(section);
729 assert(lvalue);
730 assert(rvalue);
731 assert(data);
732
733 r = routing_policy_rule_new_static(network, filename, section_line, &n);
734 if (r < 0)
735 return r;
736
737 r = safe_atou32(rvalue, &n->table);
738 if (r < 0) {
739 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule table, ignoring: %s", rvalue);
740 return 0;
741 }
742
743 n = NULL;
744
745 return 0;
746}
747
748int config_parse_routing_policy_rule_fwmark_mask(
749 const char *unit,
750 const char *filename,
751 unsigned line,
752 const char *section,
753 unsigned section_line,
754 const char *lvalue,
755 int ltype,
756 const char *rvalue,
757 void *data,
758 void *userdata) {
759
8e766630 760 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
bce67bbe
SS
761 Network *network = userdata;
762 int r;
763
764 assert(filename);
765 assert(section);
766 assert(lvalue);
767 assert(rvalue);
768 assert(data);
769
770 r = routing_policy_rule_new_static(network, filename, section_line, &n);
771 if (r < 0)
772 return r;
773
774 r = parse_fwmark_fwmask(rvalue, &n->fwmark, &n->fwmask);
775 if (r < 0) {
776 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue);
777 return 0;
778 }
779
780 n = NULL;
781
782 return 0;
783}
784
785int config_parse_routing_policy_rule_prefix(
786 const char *unit,
787 const char *filename,
788 unsigned line,
789 const char *section,
790 unsigned section_line,
791 const char *lvalue,
792 int ltype,
793 const char *rvalue,
794 void *data,
795 void *userdata) {
796
8e766630 797 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
bce67bbe 798 Network *network = userdata;
7934dede
YW
799 union in_addr_union *buffer;
800 uint8_t *prefixlen;
bce67bbe
SS
801 int r;
802
803 assert(filename);
804 assert(section);
805 assert(lvalue);
806 assert(rvalue);
807 assert(data);
808
809 r = routing_policy_rule_new_static(network, filename, section_line, &n);
810 if (r < 0)
811 return r;
812
bce67bbe 813 if (streq(lvalue, "To")) {
7934dede
YW
814 buffer = &n->to;
815 prefixlen = &n->to_prefixlen;
bce67bbe 816 } else {
7934dede
YW
817 buffer = &n->from;
818 prefixlen = &n->from_prefixlen;
819 }
820
821 r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
822 if (r < 0) {
823 log_syntax(unit, LOG_ERR, filename, line, r, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue);
824 return 0;
bce67bbe
SS
825 }
826
827 n = NULL;
828
829 return 0;
830}
831
762e2659
SS
832int config_parse_routing_policy_rule_device(
833 const char *unit,
834 const char *filename,
835 unsigned line,
836 const char *section,
837 unsigned section_line,
838 const char *lvalue,
839 int ltype,
840 const char *rvalue,
841 void *data,
842 void *userdata) {
843
8e766630 844 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
762e2659
SS
845 Network *network = userdata;
846 int r;
847
848 assert(filename);
849 assert(section);
850 assert(lvalue);
851 assert(rvalue);
852 assert(data);
853
854 r = routing_policy_rule_new_static(network, filename, section_line, &n);
855 if (r < 0)
856 return r;
857
858 if (!ifname_valid(rvalue)) {
859 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse '%s' interface name, ignoring: %s", lvalue, rvalue);
860 return 0;
861 }
862
863 if (streq(lvalue, "IncomingInterface")) {
864 r = free_and_strdup(&n->iif, rvalue);
865 if (r < 0)
866 return log_oom();
867 } else {
868 r = free_and_strdup(&n->oif, rvalue);
869 if (r < 0)
870 return log_oom();
871 }
872
873 n = NULL;
874
875 return 0;
876}
877
926062f0
SS
878int config_parse_routing_policy_rule_port_range(
879 const char *unit,
880 const char *filename,
881 unsigned line,
882 const char *section,
883 unsigned section_line,
884 const char *lvalue,
885 int ltype,
886 const char *rvalue,
887 void *data,
888 void *userdata) {
889 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
890 Network *network = userdata;
891 uint16_t low, high;
892 int r;
893
894 assert(filename);
895 assert(section);
896 assert(lvalue);
897 assert(rvalue);
898 assert(data);
899
900 r = routing_policy_rule_new_static(network, filename, section_line, &n);
901 if (r < 0)
902 return r;
903
904 r = parse_ip_port_range(rvalue, &low, &high);
905 if (r < 0) {
906 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse routing policy rule port range '%s'", rvalue);
907 return 0;
908 }
909
910 if (streq(lvalue, "SourcePort")) {
911 n->sport.start = low;
912 n->sport.end = high;
913 } else {
914 n->dport.start = low;
915 n->dport.end = high;
916 }
917
918 n = NULL;
919
920 return 0;
921}
922
97f9df9e 923int config_parse_routing_policy_rule_ip_protocol(
926062f0
SS
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
935 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
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
3a269dcf 949 r = parse_ip_protocol(rvalue);
926062f0 950 if (r < 0) {
3a269dcf 951 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IP protocol '%s' for routing policy rule, ignoring: %m", rvalue);
926062f0
SS
952 return 0;
953 }
954
955 n->protocol = 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 }
1201
1202 rule = NULL;
1203 }
1204
1205 return 0;
1206}
1207
1208void routing_policy_rule_purge(Manager *m, Link *link) {
1209 RoutingPolicyRule *rule, *existing;
1210 Iterator i;
1211 int r;
1212
1213 assert(m);
1214 assert(link);
1215
1216 SET_FOREACH(rule, m->rules_saved, i) {
1217 existing = set_get(m->rules_foreign, rule);
1218 if (existing) {
1219
29889b4d 1220 r = routing_policy_rule_remove(rule, link, NULL);
bce67bbe
SS
1221 if (r < 0) {
1222 log_warning_errno(r, "Could not remove routing policy rules: %m");
1223 continue;
1224 }
1225
7715629e 1226 link->routing_policy_rule_remove_messages++;
bce67bbe
SS
1227 }
1228 }
1229}