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