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