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