]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-routing-policy-rule.c
network: set key destructor in several hash_ops
[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
43e08c78 6#include "af-list.h"
bce67bbe
SS
7#include "alloc-util.h"
8#include "conf-parser.h"
9#include "fileio.h"
ea471a46 10#include "format-util.h"
da96ad5a 11#include "ip-protocol-list.h"
bce67bbe
SS
12#include "networkd-routing-policy-rule.h"
13#include "netlink-util.h"
14#include "networkd-manager.h"
f6c6ff97 15#include "networkd-util.h"
bce67bbe
SS
16#include "parse-util.h"
17#include "socket-util.h"
18#include "string-util.h"
51517f9e 19#include "strv.h"
ea471a46 20#include "user-util.h"
bce67bbe
SS
21
22int routing_policy_rule_new(RoutingPolicyRule **ret) {
23 RoutingPolicyRule *rule;
24
9d66b48c 25 rule = new(RoutingPolicyRule, 1);
bce67bbe
SS
26 if (!rule)
27 return -ENOMEM;
28
9d66b48c 29 *rule = (RoutingPolicyRule) {
9d66b48c 30 .table = RT_TABLE_MAIN,
ea471a46
YW
31 .uid_range.start = UID_INVALID,
32 .uid_range.end = UID_INVALID,
53e1ba28 33 .suppress_prefixlen = -1,
9d66b48c 34 };
bce67bbe
SS
35
36 *ret = rule;
37 return 0;
38}
39
40void routing_policy_rule_free(RoutingPolicyRule *rule) {
41
42 if (!rule)
43 return;
44
45 if (rule->network) {
46 LIST_REMOVE(rules, rule->network->rules, rule);
47 assert(rule->network->n_rules > 0);
48 rule->network->n_rules--;
49
0f7f2769 50 if (rule->section)
bce67bbe 51 hashmap_remove(rule->network->rules_by_section, rule->section);
36e6e28b
SS
52 }
53
6964cf45 54 if (rule->manager) {
9ee92e7e
YW
55 if (set_get(rule->manager->rules, rule) == rule)
56 set_remove(rule->manager->rules, rule);
57 if (set_get(rule->manager->rules_foreign, rule) == rule)
58 set_remove(rule->manager->rules_foreign, rule);
bce67bbe
SS
59 }
60
0f7f2769 61 network_config_section_free(rule->section);
762e2659
SS
62 free(rule->iif);
63 free(rule->oif);
bce67bbe
SS
64 free(rule);
65}
66
01fc8e4f
YW
67static int routing_policy_rule_copy(RoutingPolicyRule *dest, RoutingPolicyRule *src) {
68 _cleanup_free_ char *iif = NULL, *oif = NULL;
69
70 assert(dest);
71 assert(src);
72
73 if (src->iif) {
74 iif = strdup(src->iif);
75 if (!iif)
76 return -ENOMEM;
77 }
78
79 if (src->oif) {
80 oif = strdup(src->oif);
81 if (!oif)
82 return -ENOMEM;
83 }
84
85 dest->family = src->family;
86 dest->from = src->from;
87 dest->from_prefixlen = src->from_prefixlen;
88 dest->to = src->to;
89 dest->to_prefixlen = src->to_prefixlen;
90 dest->invert_rule = src->invert_rule;
91 dest->tos = src->tos;
92 dest->fwmark = src->fwmark;
93 dest->fwmask = src->fwmask;
94 dest->priority = src->priority;
95 dest->table = src->table;
96 dest->iif = TAKE_PTR(iif);
97 dest->oif = TAKE_PTR(oif);
98 dest->protocol = src->protocol;
99 dest->sport = src->sport;
100 dest->dport = src->dport;
ea471a46 101 dest->uid_range = src->uid_range;
53e1ba28 102 dest->suppress_prefixlen = src->suppress_prefixlen;
01fc8e4f
YW
103
104 return 0;
105}
106
7a08d314 107static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash *state) {
bce67bbe
SS
108 assert(rule);
109
110 siphash24_compress(&rule->family, sizeof(rule->family), state);
111
112 switch (rule->family) {
113 case AF_INET:
114 case AF_INET6:
bce67bbe
SS
115 siphash24_compress(&rule->from, FAMILY_ADDRESS_SIZE(rule->family), state);
116 siphash24_compress(&rule->from_prefixlen, sizeof(rule->from_prefixlen), state);
117
118 siphash24_compress(&rule->to, FAMILY_ADDRESS_SIZE(rule->family), state);
119 siphash24_compress(&rule->to_prefixlen, sizeof(rule->to_prefixlen), state);
120
b80a511b
YW
121 siphash24_compress_boolean(rule->invert_rule, state);
122
bce67bbe
SS
123 siphash24_compress(&rule->tos, sizeof(rule->tos), state);
124 siphash24_compress(&rule->fwmark, sizeof(rule->fwmark), state);
b80a511b
YW
125 siphash24_compress(&rule->fwmask, sizeof(rule->fwmask), state);
126 siphash24_compress(&rule->priority, sizeof(rule->priority), state);
bce67bbe 127 siphash24_compress(&rule->table, sizeof(rule->table), state);
53e1ba28 128 siphash24_compress(&rule->suppress_prefixlen, sizeof(rule->suppress_prefixlen), state);
bce67bbe 129
926062f0
SS
130 siphash24_compress(&rule->protocol, sizeof(rule->protocol), state);
131 siphash24_compress(&rule->sport, sizeof(rule->sport), state);
132 siphash24_compress(&rule->dport, sizeof(rule->dport), state);
ea471a46 133 siphash24_compress(&rule->uid_range, sizeof(rule->uid_range), state);
926062f0 134
f281fc1e
YW
135 siphash24_compress_string(rule->iif, state);
136 siphash24_compress_string(rule->oif, state);
762e2659 137
bce67bbe
SS
138 break;
139 default:
140 /* treat any other address family as AF_UNSPEC */
141 break;
142 }
143}
144
7a08d314 145static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPolicyRule *b) {
bce67bbe
SS
146 int r;
147
a0edd02e
FB
148 r = CMP(a->family, b->family);
149 if (r != 0)
150 return r;
bce67bbe
SS
151
152 switch (a->family) {
153 case AF_INET:
154 case AF_INET6:
a0edd02e
FB
155 r = CMP(a->from_prefixlen, b->from_prefixlen);
156 if (r != 0)
157 return r;
158
67e05dd8
ZJS
159 r = memcmp(&a->from, &b->from, FAMILY_ADDRESS_SIZE(a->family));
160 if (r != 0)
161 return r;
162
a0edd02e
FB
163 r = CMP(a->to_prefixlen, b->to_prefixlen);
164 if (r != 0)
165 return r;
166
67e05dd8
ZJS
167 r = memcmp(&a->to, &b->to, FAMILY_ADDRESS_SIZE(a->family));
168 if (r != 0)
169 return r;
170
b80a511b
YW
171 r = CMP(a->invert_rule, b->invert_rule);
172 if (r != 0)
173 return r;
174
a0edd02e
FB
175 r = CMP(a->tos, b->tos);
176 if (r != 0)
177 return r;
178
b80a511b
YW
179 r = CMP(a->fwmark, b->fwmark);
180 if (r != 0)
181 return r;
182
a0edd02e
FB
183 r = CMP(a->fwmask, b->fwmask);
184 if (r != 0)
185 return r;
186
b80a511b
YW
187 r = CMP(a->priority, b->priority);
188 if (r != 0)
189 return r;
190
a0edd02e
FB
191 r = CMP(a->table, b->table);
192 if (r != 0)
193 return r;
bce67bbe 194
53e1ba28
NF
195 r = CMP(a->suppress_prefixlen, b->suppress_prefixlen);
196 if (r != 0)
197 return r;
198
926062f0
SS
199 r = CMP(a->protocol, b->protocol);
200 if (r != 0)
201 return r;
202
203 r = memcmp(&a->sport, &b->sport, sizeof(a->sport));
204 if (r != 0)
205 return r;
206
207 r = memcmp(&a->dport, &b->dport, sizeof(a->dport));
208 if (r != 0)
209 return r;
210
ea471a46
YW
211 r = memcmp(&a->uid_range, &b->uid_range, sizeof(a->uid_range));
212 if (r != 0)
213 return r;
214
67e05dd8 215 r = strcmp_ptr(a->iif, b->iif);
314ed4f9 216 if (r != 0)
bce67bbe
SS
217 return r;
218
67e05dd8 219 r = strcmp_ptr(a->oif, b->oif);
314ed4f9 220 if (r != 0)
67e05dd8 221 return r;
bce67bbe 222
67e05dd8 223 return 0;
bce67bbe
SS
224 default:
225 /* treat any other address family as AF_UNSPEC */
226 return 0;
227 }
228}
229
8eec0b9d
YW
230DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
231 routing_policy_rule_hash_ops,
232 RoutingPolicyRule,
233 routing_policy_rule_hash_func,
234 routing_policy_rule_compare_func,
235 routing_policy_rule_free);
bce67bbe 236
b80a511b 237int routing_policy_rule_get(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
bce67bbe 238
b80a511b 239 RoutingPolicyRule *existing;
bce67bbe 240
b80a511b 241 assert(m);
bce67bbe 242
b80a511b 243 existing = set_get(m->rules, rule);
b87dadcd
ZJS
244 if (existing) {
245 if (ret)
246 *ret = existing;
247 return 1;
bce67bbe
SS
248 }
249
b80a511b 250 existing = set_get(m->rules_foreign, rule);
b87dadcd
ZJS
251 if (existing) {
252 if (ret)
253 *ret = existing;
e6b65ab7 254 return 0;
bce67bbe
SS
255 }
256
257 return -ENOENT;
258}
259
260int routing_policy_rule_make_local(Manager *m, RoutingPolicyRule *rule) {
261 int r;
262
263 assert(m);
264
265 if (set_contains(m->rules_foreign, rule)) {
266 set_remove(m->rules_foreign, rule);
267
de7fef4b 268 r = set_ensure_put(&m->rules, &routing_policy_rule_hash_ops, rule);
75a302b5
YW
269 if (r < 0)
270 return r;
271 if (r == 0)
272 routing_policy_rule_free(rule);
bce67bbe
SS
273 }
274
275 return -ENOENT;
276}
277
b80a511b 278static int routing_policy_rule_add_internal(Manager *m, Set **rules, RoutingPolicyRule *in, RoutingPolicyRule **ret) {
8e766630 279 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
bce67bbe
SS
280 int r;
281
b80a511b
YW
282 assert(m);
283 assert(rules);
284 assert(in);
bce67bbe
SS
285
286 r = routing_policy_rule_new(&rule);
287 if (r < 0)
288 return r;
289
6964cf45 290 rule->manager = m;
01fc8e4f
YW
291
292 r = routing_policy_rule_copy(rule, in);
293 if (r < 0)
294 return r;
bce67bbe 295
de7fef4b 296 r = set_ensure_put(rules, &routing_policy_rule_hash_ops, rule);
bce67bbe
SS
297 if (r < 0)
298 return r;
75a302b5
YW
299 if (r == 0)
300 return -EEXIST;
bce67bbe
SS
301
302 if (ret)
303 *ret = rule;
304
d26267dd 305 TAKE_PTR(rule);
bce67bbe
SS
306 return 0;
307}
308
b80a511b
YW
309static int routing_policy_rule_add(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
310 return routing_policy_rule_add_internal(m, &m->rules, rule, ret);
bce67bbe
SS
311}
312
b80a511b
YW
313int routing_policy_rule_add_foreign(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
314 return routing_policy_rule_add_internal(m, &m->rules_foreign, rule, ret);
bce67bbe
SS
315}
316
302a796f 317static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
bce67bbe
SS
318 int r;
319
320 assert(m);
321 assert(link);
322 assert(link->ifname);
323
7715629e 324 link->routing_policy_rule_remove_messages--;
bce67bbe
SS
325
326 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
327 return 1;
328
329 r = sd_netlink_message_get_errno(m);
330 if (r < 0)
5ecb131d 331 log_link_message_warning_errno(link, m, r, "Could not drop routing policy rule");
bce67bbe
SS
332
333 return 1;
334}
335
302a796f 336int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, link_netlink_message_handler_t callback) {
bce67bbe
SS
337 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
338 int r;
339
340 assert(routing_policy_rule);
341 assert(link);
342 assert(link->manager);
343 assert(link->manager->rtnl);
344 assert(link->ifindex > 0);
345 assert(IN_SET(routing_policy_rule->family, AF_INET, AF_INET6));
346
347 r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_DELRULE, routing_policy_rule->family);
348 if (r < 0)
98b02994 349 return log_link_error_errno(link, r, "Could not allocate RTM_DELRULE message: %m");
bce67bbe 350
d40b01e4 351 if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->from) == 0) {
43409486 352 r = netlink_message_append_in_addr_union(m, FRA_SRC, routing_policy_rule->family, &routing_policy_rule->from);
bce67bbe 353 if (r < 0)
98b02994 354 return log_link_error_errno(link, r, "Could not append FRA_SRC attribute: %m");
bce67bbe
SS
355
356 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, routing_policy_rule->from_prefixlen);
357 if (r < 0)
98b02994 358 return log_link_error_errno(link, r, "Could not set source prefix length: %m");
bce67bbe
SS
359 }
360
d40b01e4 361 if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->to) == 0) {
43409486 362 r = netlink_message_append_in_addr_union(m, FRA_DST, routing_policy_rule->family, &routing_policy_rule->to);
bce67bbe 363 if (r < 0)
98b02994 364 return log_link_error_errno(link, r, "Could not append FRA_DST attribute: %m");
bce67bbe
SS
365
366 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, routing_policy_rule->to_prefixlen);
367 if (r < 0)
98b02994 368 return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
bce67bbe
SS
369 }
370
302a796f
YW
371 r = netlink_call_async(link->manager->rtnl, NULL, m,
372 callback ?: routing_policy_rule_remove_handler,
373 link_netlink_destroy_callback, link);
bce67bbe 374 if (r < 0)
98b02994 375 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
bce67bbe
SS
376
377 link_ref(link);
378
379 return 0;
380}
381
382static int routing_policy_rule_new_static(Network *network, const char *filename, unsigned section_line, RoutingPolicyRule **ret) {
8e766630
LP
383 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
384 _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
bce67bbe
SS
385 int r;
386
387 assert(network);
388 assert(ret);
389 assert(!!filename == (section_line > 0));
390
0f7f2769
YW
391 if (filename) {
392 r = network_config_section_new(filename, section_line, &n);
393 if (r < 0)
394 return r;
bce67bbe 395
0f7f2769
YW
396 rule = hashmap_get(network->rules_by_section, n);
397 if (rule) {
398 *ret = TAKE_PTR(rule);
bce67bbe 399
0f7f2769
YW
400 return 0;
401 }
bce67bbe
SS
402 }
403
404 r = routing_policy_rule_new(&rule);
405 if (r < 0)
406 return r;
407
bce67bbe 408 rule->network = network;
bce67bbe
SS
409 LIST_APPEND(rules, network->rules, rule);
410 network->n_rules++;
411
0f7f2769
YW
412 if (filename) {
413 rule->section = TAKE_PTR(n);
414
3e570042
YW
415 r = hashmap_ensure_allocated(&network->rules_by_section, &network_config_hash_ops);
416 if (r < 0)
417 return r;
418
0f7f2769
YW
419 r = hashmap_put(network->rules_by_section, rule->section, rule);
420 if (r < 0)
421 return r;
422 }
423
1cc6c93a 424 *ret = TAKE_PTR(rule);
bce67bbe
SS
425
426 return 0;
427}
428
302a796f 429static int routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
bce67bbe
SS
430 int r;
431
432 assert(rtnl);
433 assert(m);
434 assert(link);
435 assert(link->ifname);
7715629e 436 assert(link->routing_policy_rule_messages > 0);
bce67bbe 437
7715629e 438 link->routing_policy_rule_messages--;
bce67bbe
SS
439
440 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
441 return 1;
442
443 r = sd_netlink_message_get_errno(m);
4ff296b0 444 if (r < 0 && r != -EEXIST) {
5ecb131d 445 log_link_message_warning_errno(link, m, r, "Could not add routing policy rule");
4ff296b0
YW
446 link_enter_failed(link);
447 return 1;
448 }
bce67bbe 449
7715629e 450 if (link->routing_policy_rule_messages == 0) {
bce67bbe 451 log_link_debug(link, "Routing policy rule configured");
7715629e
ST
452 link->routing_policy_rules_configured = true;
453 link_check_ready(link);
454 }
bce67bbe
SS
455
456 return 1;
457}
458
9f08a578 459int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netlink_message_handler_t callback) {
bce67bbe
SS
460 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
461 int r;
462
463 assert(rule);
464 assert(link);
465 assert(link->ifindex > 0);
466 assert(link->manager);
467 assert(link->manager->rtnl);
468
15201512
YW
469 if (DEBUG_LOGGING) {
470 _cleanup_free_ char *from = NULL, *to = NULL;
471
472 (void) in_addr_to_string(rule->family, &rule->from, &from);
473 (void) in_addr_to_string(rule->family, &rule->to, &to);
474
98b02994
YW
475 log_link_debug(link,
476 "Configuring routing policy rule: %s/%u -> %s/%u, iif: %s, oif: %s, table: %u",
477 from, rule->from_prefixlen, to, rule->to_prefixlen, strna(rule->iif), strna(rule->oif), rule->table);
15201512
YW
478 }
479
bce67bbe
SS
480 r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
481 if (r < 0)
98b02994 482 return log_link_error_errno(link, r, "Could not allocate RTM_NEWRULE message: %m");
bce67bbe 483
d40b01e4 484 if (in_addr_is_null(rule->family, &rule->from) == 0) {
43409486 485 r = netlink_message_append_in_addr_union(m, FRA_SRC, rule->family, &rule->from);
bce67bbe 486 if (r < 0)
98b02994 487 return log_link_error_errno(link, r, "Could not append FRA_SRC attribute: %m");
bce67bbe
SS
488
489 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen);
490 if (r < 0)
98b02994 491 return log_link_error_errno(link, r, "Could not set source prefix length: %m");
bce67bbe
SS
492 }
493
d40b01e4 494 if (in_addr_is_null(rule->family, &rule->to) == 0) {
43409486 495 r = netlink_message_append_in_addr_union(m, FRA_DST, rule->family, &rule->to);
bce67bbe 496 if (r < 0)
98b02994 497 return log_link_error_errno(link, r, "Could not append FRA_DST attribute: %m");
bce67bbe
SS
498
499 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen);
500 if (r < 0)
98b02994 501 return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
bce67bbe
SS
502 }
503
504 r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
505 if (r < 0)
98b02994 506 return log_link_error_errno(link, r, "Could not append FRA_PRIORITY attribute: %m");
bce67bbe
SS
507
508 if (rule->tos > 0) {
509 r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
510 if (r < 0)
0da425df 511 return log_link_error_errno(link, r, "Could not set IP rule TOS: %m");
bce67bbe
SS
512 }
513
514 if (rule->table < 256) {
515 r = sd_rtnl_message_routing_policy_rule_set_table(m, rule->table);
516 if (r < 0)
0da425df 517 return log_link_error_errno(link, r, "Could not set IP rule table: %m");
bce67bbe
SS
518 } else {
519 r = sd_rtnl_message_routing_policy_rule_set_table(m, RT_TABLE_UNSPEC);
520 if (r < 0)
0da425df 521 return log_link_error_errno(link, r, "Could not set IP rule table: %m");
bce67bbe
SS
522
523 r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table);
524 if (r < 0)
98b02994 525 return log_link_error_errno(link, r, "Could not append FRA_TABLE attribute: %m");
bce67bbe
SS
526 }
527
528 if (rule->fwmark > 0) {
529 r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark);
530 if (r < 0)
98b02994 531 return log_link_error_errno(link, r, "Could not append FRA_FWMARK attribute: %m");
bce67bbe
SS
532 }
533
534 if (rule->fwmask > 0) {
535 r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
536 if (r < 0)
98b02994 537 return log_link_error_errno(link, r, "Could not append FRA_FWMASK attribute: %m");
bce67bbe
SS
538 }
539
762e2659
SS
540 if (rule->iif) {
541 r = sd_netlink_message_append_string(m, FRA_IFNAME, rule->iif);
542 if (r < 0)
98b02994 543 return log_link_error_errno(link, r, "Could not append FRA_IFNAME attribute: %m");
762e2659
SS
544 }
545
546 if (rule->oif) {
547 r = sd_netlink_message_append_string(m, FRA_OIFNAME, rule->oif);
548 if (r < 0)
98b02994 549 return log_link_error_errno(link, r, "Could not append FRA_OIFNAME attribute: %m");
762e2659
SS
550 }
551
926062f0
SS
552 r = sd_netlink_message_append_u8(m, FRA_IP_PROTO, rule->protocol);
553 if (r < 0)
98b02994 554 return log_link_error_errno(link, r, "Could not append FRA_IP_PROTO attribute: %m");
926062f0
SS
555
556 if (rule->sport.start != 0 || rule->sport.end != 0) {
557 r = sd_netlink_message_append_data(m, FRA_SPORT_RANGE, &rule->sport, sizeof(rule->sport));
558 if (r < 0)
98b02994 559 return log_link_error_errno(link, r, "Could not append FRA_SPORT_RANGE attribute: %m");
926062f0
SS
560 }
561
562 if (rule->dport.start != 0 || rule->dport.end != 0) {
563 r = sd_netlink_message_append_data(m, FRA_DPORT_RANGE, &rule->dport, sizeof(rule->dport));
564 if (r < 0)
98b02994 565 return log_link_error_errno(link, r, "Could not append FRA_DPORT_RANGE attribute: %m");
926062f0
SS
566 }
567
ea471a46
YW
568 if (rule->uid_range.start != UID_INVALID && rule->uid_range.end != UID_INVALID) {
569 r = sd_netlink_message_append_data(m, FRA_UID_RANGE, &rule->uid_range, sizeof(rule->uid_range));
570 if (r < 0)
571 return log_link_error_errno(link, r, "Could not append FRA_UID_RANGE attribute: %m");
572 }
573
8b220643
SS
574 if (rule->invert_rule) {
575 r = sd_rtnl_message_routing_policy_rule_set_flags(m, FIB_RULE_INVERT);
576 if (r < 0)
98b02994 577 return log_link_error_errno(link, r, "Could not append FIB_RULE_INVERT attribute: %m");
8b220643
SS
578 }
579
53e1ba28
NF
580 if (rule->suppress_prefixlen >= 0) {
581 r = sd_netlink_message_append_u32(m, FRA_SUPPRESS_PREFIXLEN, (uint32_t) rule->suppress_prefixlen);
582 if (r < 0)
583 return log_link_error_errno(link, r, "Could not append FRA_SUPPRESS_PREFIXLEN attribute: %m");
584 }
585
bce67bbe
SS
586 rule->link = link;
587
302a796f
YW
588 r = netlink_call_async(link->manager->rtnl, NULL, m,
589 callback ?: routing_policy_rule_handler,
590 link_netlink_destroy_callback, link);
bce67bbe 591 if (r < 0)
98b02994 592 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
bce67bbe
SS
593
594 link_ref(link);
595
b80a511b 596 r = routing_policy_rule_add(link->manager, rule, NULL);
bce67bbe 597 if (r < 0)
98b02994 598 return log_link_error_errno(link, r, "Could not add rule: %m");
bce67bbe 599
7ef7e550 600 return 1;
bce67bbe
SS
601}
602
0aabccc8 603int routing_policy_rule_section_verify(RoutingPolicyRule *rule) {
f6c6ff97
YW
604 int r;
605
0aabccc8
YW
606 if (section_is_invalid(rule->section))
607 return -EINVAL;
608
f6c6ff97
YW
609 if ((rule->family == AF_INET && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6)) ||
610 (rule->family == AF_INET6 && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4)))
611 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
612 "%s: address family specified by Family= conflicts with the address "
613 "specified by To= or From=. Ignoring [RoutingPolicyRule] section from line %u.",
614 rule->section->filename, rule->section->line);
615
616 if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_IPV6)) {
617 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule6 = NULL;
618
619 assert(rule->family == AF_UNSPEC);
620
621 /* When Family=both, we need to copy the section, AF_INET and AF_INET6. */
622
623 r = routing_policy_rule_new_static(rule->network, NULL, 0, &rule6);
624 if (r < 0)
625 return r;
626
627 r = routing_policy_rule_copy(rule6, rule);
628 if (r < 0)
629 return r;
630
0aabccc8 631 rule->family = AF_INET;
f6c6ff97
YW
632 rule6->family = AF_INET6;
633
634 TAKE_PTR(rule6);
635 }
636
637 if (rule->family == AF_UNSPEC) {
638 if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6))
639 rule->family = AF_INET6;
640 else
641 rule->family = AF_INET;
642 }
0aabccc8
YW
643
644 return 0;
645}
646
bce67bbe
SS
647static int parse_fwmark_fwmask(const char *s, uint32_t *fwmark, uint32_t *fwmask) {
648 _cleanup_free_ char *f = NULL;
649 char *p;
650 int r;
651
652 assert(s);
653
654 f = strdup(s);
655 if (!f)
656 return -ENOMEM;
657
658 p = strchr(f, '/');
659 if (p)
660 *p++ = '\0';
661
662 r = safe_atou32(f, fwmark);
663 if (r < 0)
664 return log_error_errno(r, "Failed to parse RPDB rule firewall mark, ignoring: %s", f);
665
666 if (p) {
667 r = safe_atou32(p, fwmask);
668 if (r < 0)
669 return log_error_errno(r, "Failed to parse RPDB rule mask, ignoring: %s", f);
670 }
671
672 return 0;
673}
674
675int config_parse_routing_policy_rule_tos(
676 const char *unit,
677 const char *filename,
678 unsigned line,
679 const char *section,
680 unsigned section_line,
681 const char *lvalue,
682 int ltype,
683 const char *rvalue,
684 void *data,
685 void *userdata) {
686
fcbf4cb7 687 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
bce67bbe
SS
688 Network *network = userdata;
689 int r;
690
691 assert(filename);
692 assert(section);
693 assert(lvalue);
694 assert(rvalue);
695 assert(data);
696
697 r = routing_policy_rule_new_static(network, filename, section_line, &n);
698 if (r < 0)
d96edb2c 699 return log_oom();
bce67bbe
SS
700
701 r = safe_atou8(rvalue, &n->tos);
702 if (r < 0) {
d96edb2c 703 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule TOS, ignoring: %s", rvalue);
bce67bbe
SS
704 return 0;
705 }
706
707 n = NULL;
708
709 return 0;
710}
711
712int config_parse_routing_policy_rule_priority(
713 const char *unit,
714 const char *filename,
715 unsigned line,
716 const char *section,
717 unsigned section_line,
718 const char *lvalue,
719 int ltype,
720 const char *rvalue,
721 void *data,
722 void *userdata) {
723
fcbf4cb7 724 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
bce67bbe
SS
725 Network *network = userdata;
726 int r;
727
728 assert(filename);
729 assert(section);
730 assert(lvalue);
731 assert(rvalue);
732 assert(data);
733
734 r = routing_policy_rule_new_static(network, filename, section_line, &n);
735 if (r < 0)
d96edb2c 736 return log_oom();
bce67bbe
SS
737
738 r = safe_atou32(rvalue, &n->priority);
739 if (r < 0) {
d96edb2c 740 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule priority, ignoring: %s", rvalue);
bce67bbe
SS
741 return 0;
742 }
743
744 n = NULL;
745
746 return 0;
747}
748
749int config_parse_routing_policy_rule_table(
750 const char *unit,
751 const char *filename,
752 unsigned line,
753 const char *section,
754 unsigned section_line,
755 const char *lvalue,
756 int ltype,
757 const char *rvalue,
758 void *data,
759 void *userdata) {
760
fcbf4cb7 761 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
bce67bbe
SS
762 Network *network = userdata;
763 int r;
764
765 assert(filename);
766 assert(section);
767 assert(lvalue);
768 assert(rvalue);
769 assert(data);
770
771 r = routing_policy_rule_new_static(network, filename, section_line, &n);
772 if (r < 0)
d96edb2c 773 return log_oom();
bce67bbe
SS
774
775 r = safe_atou32(rvalue, &n->table);
776 if (r < 0) {
d96edb2c 777 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule table, ignoring: %s", rvalue);
bce67bbe
SS
778 return 0;
779 }
780
781 n = NULL;
782
783 return 0;
784}
785
786int config_parse_routing_policy_rule_fwmark_mask(
787 const char *unit,
788 const char *filename,
789 unsigned line,
790 const char *section,
791 unsigned section_line,
792 const char *lvalue,
793 int ltype,
794 const char *rvalue,
795 void *data,
796 void *userdata) {
797
fcbf4cb7 798 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
bce67bbe
SS
799 Network *network = userdata;
800 int r;
801
802 assert(filename);
803 assert(section);
804 assert(lvalue);
805 assert(rvalue);
806 assert(data);
807
808 r = routing_policy_rule_new_static(network, filename, section_line, &n);
809 if (r < 0)
d96edb2c 810 return log_oom();
bce67bbe
SS
811
812 r = parse_fwmark_fwmask(rvalue, &n->fwmark, &n->fwmask);
813 if (r < 0) {
d96edb2c 814 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue);
bce67bbe
SS
815 return 0;
816 }
817
818 n = NULL;
819
820 return 0;
821}
822
823int config_parse_routing_policy_rule_prefix(
824 const char *unit,
825 const char *filename,
826 unsigned line,
827 const char *section,
828 unsigned section_line,
829 const char *lvalue,
830 int ltype,
831 const char *rvalue,
832 void *data,
833 void *userdata) {
834
fcbf4cb7 835 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
bce67bbe 836 Network *network = userdata;
7934dede
YW
837 union in_addr_union *buffer;
838 uint8_t *prefixlen;
bce67bbe
SS
839 int r;
840
841 assert(filename);
842 assert(section);
843 assert(lvalue);
844 assert(rvalue);
845 assert(data);
846
847 r = routing_policy_rule_new_static(network, filename, section_line, &n);
848 if (r < 0)
d96edb2c 849 return log_oom();
bce67bbe 850
bce67bbe 851 if (streq(lvalue, "To")) {
7934dede
YW
852 buffer = &n->to;
853 prefixlen = &n->to_prefixlen;
bce67bbe 854 } else {
7934dede
YW
855 buffer = &n->from;
856 prefixlen = &n->from_prefixlen;
857 }
858
0aabccc8
YW
859 if (n->family == AF_UNSPEC)
860 r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
861 else
862 r = in_addr_prefix_from_string(rvalue, n->family, buffer, prefixlen);
7934dede 863 if (r < 0) {
d96edb2c 864 log_syntax(unit, LOG_WARNING, filename, line, r, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue);
7934dede 865 return 0;
bce67bbe
SS
866 }
867
868 n = NULL;
869
870 return 0;
871}
872
762e2659
SS
873int config_parse_routing_policy_rule_device(
874 const char *unit,
875 const char *filename,
876 unsigned line,
877 const char *section,
878 unsigned section_line,
879 const char *lvalue,
880 int ltype,
881 const char *rvalue,
882 void *data,
883 void *userdata) {
884
fcbf4cb7 885 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
762e2659
SS
886 Network *network = userdata;
887 int r;
888
889 assert(filename);
890 assert(section);
891 assert(lvalue);
892 assert(rvalue);
893 assert(data);
894
895 r = routing_policy_rule_new_static(network, filename, section_line, &n);
896 if (r < 0)
d96edb2c 897 return log_oom();
762e2659
SS
898
899 if (!ifname_valid(rvalue)) {
d96edb2c 900 log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse '%s' interface name, ignoring: %s", lvalue, rvalue);
762e2659
SS
901 return 0;
902 }
903
904 if (streq(lvalue, "IncomingInterface")) {
905 r = free_and_strdup(&n->iif, rvalue);
906 if (r < 0)
907 return log_oom();
908 } else {
909 r = free_and_strdup(&n->oif, rvalue);
910 if (r < 0)
911 return log_oom();
912 }
913
914 n = NULL;
915
916 return 0;
917}
918
926062f0
SS
919int config_parse_routing_policy_rule_port_range(
920 const char *unit,
921 const char *filename,
922 unsigned line,
923 const char *section,
924 unsigned section_line,
925 const char *lvalue,
926 int ltype,
927 const char *rvalue,
928 void *data,
929 void *userdata) {
fcbf4cb7 930 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
926062f0
SS
931 Network *network = userdata;
932 uint16_t low, high;
933 int r;
934
935 assert(filename);
936 assert(section);
937 assert(lvalue);
938 assert(rvalue);
939 assert(data);
940
941 r = routing_policy_rule_new_static(network, filename, section_line, &n);
942 if (r < 0)
d96edb2c 943 return log_oom();
926062f0
SS
944
945 r = parse_ip_port_range(rvalue, &low, &high);
946 if (r < 0) {
d96edb2c 947 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse routing policy rule port range '%s'", rvalue);
926062f0
SS
948 return 0;
949 }
950
951 if (streq(lvalue, "SourcePort")) {
952 n->sport.start = low;
953 n->sport.end = high;
954 } else {
955 n->dport.start = low;
956 n->dport.end = high;
957 }
958
959 n = NULL;
960
961 return 0;
962}
963
97f9df9e 964int config_parse_routing_policy_rule_ip_protocol(
926062f0
SS
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
fcbf4cb7 976 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
926062f0
SS
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)
d96edb2c 988 return log_oom();
926062f0 989
3a269dcf 990 r = parse_ip_protocol(rvalue);
926062f0 991 if (r < 0) {
d96edb2c 992 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse IP protocol '%s' for routing policy rule, ignoring: %m", rvalue);
926062f0
SS
993 return 0;
994 }
995
996 n->protocol = r;
997
998 n = NULL;
999
1000 return 0;
1001}
1002
8b220643
SS
1003int config_parse_routing_policy_rule_invert(
1004 const char *unit,
1005 const char *filename,
1006 unsigned line,
1007 const char *section,
1008 unsigned section_line,
1009 const char *lvalue,
1010 int ltype,
1011 const char *rvalue,
1012 void *data,
1013 void *userdata) {
1014
fcbf4cb7 1015 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
8b220643
SS
1016 Network *network = userdata;
1017 int r;
1018
1019 assert(filename);
1020 assert(section);
1021 assert(lvalue);
1022 assert(rvalue);
1023 assert(data);
1024
1025 r = routing_policy_rule_new_static(network, filename, section_line, &n);
1026 if (r < 0)
d96edb2c 1027 return log_oom();
8b220643
SS
1028
1029 r = parse_boolean(rvalue);
1030 if (r < 0) {
d96edb2c 1031 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule invert, ignoring: %s", rvalue);
8b220643
SS
1032 return 0;
1033 }
1034
1035 n->invert_rule = r;
1036
1037 n = NULL;
1038
1039 return 0;
1040}
1041
f6c6ff97
YW
1042int config_parse_routing_policy_rule_family(
1043 const char *unit,
1044 const char *filename,
1045 unsigned line,
1046 const char *section,
1047 unsigned section_line,
1048 const char *lvalue,
1049 int ltype,
1050 const char *rvalue,
1051 void *data,
1052 void *userdata) {
1053
1054 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1055 Network *network = userdata;
1056 AddressFamily a;
1057 int r;
1058
1059 assert(filename);
1060 assert(section);
1061 assert(lvalue);
1062 assert(rvalue);
1063 assert(data);
1064
1065 r = routing_policy_rule_new_static(network, filename, section_line, &n);
1066 if (r < 0)
d96edb2c 1067 return log_oom();
f6c6ff97
YW
1068
1069 a = routing_policy_rule_address_family_from_string(rvalue);
1070 if (a < 0) {
d96edb2c 1071 log_syntax(unit, LOG_WARNING, filename, line, 0,
f6c6ff97
YW
1072 "Invalid address family '%s', ignoring.", rvalue);
1073 return 0;
1074 }
1075
1076 n->address_family = a;
1077 n = NULL;
1078
1079 return 0;
1080}
1081
ea471a46
YW
1082int config_parse_routing_policy_rule_uid_range(
1083 const char *unit,
1084 const char *filename,
1085 unsigned line,
1086 const char *section,
1087 unsigned section_line,
1088 const char *lvalue,
1089 int ltype,
1090 const char *rvalue,
1091 void *data,
1092 void *userdata) {
1093
1094 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1095 Network *network = userdata;
1096 uid_t start, end;
1097 int r;
1098
1099 assert(filename);
1100 assert(section);
1101 assert(lvalue);
1102 assert(rvalue);
1103 assert(data);
1104
1105 r = routing_policy_rule_new_static(network, filename, section_line, &n);
1106 if (r < 0)
d96edb2c 1107 return log_oom();
ea471a46
YW
1108
1109 r = get_user_creds(&rvalue, &start, NULL, NULL, NULL, 0);
1110 if (r >= 0)
1111 end = start;
1112 else {
1113 r = parse_uid_range(rvalue, &start, &end);
1114 if (r < 0) {
d96edb2c 1115 log_syntax(unit, LOG_WARNING, filename, line, r,
ea471a46
YW
1116 "Invalid uid or uid range '%s', ignoring: %m", rvalue);
1117 return 0;
1118 }
1119 }
1120
1121 n->uid_range.start = start;
1122 n->uid_range.end = end;
1123 n = NULL;
53e1ba28
NF
1124
1125 return 0;
1126}
1127
1128int config_parse_routing_policy_rule_suppress_prefixlen(
1129 const char *unit,
1130 const char *filename,
1131 unsigned line,
1132 const char *section,
1133 unsigned section_line,
1134 const char *lvalue,
1135 int ltype,
1136 const char *rvalue,
1137 void *data,
1138 void *userdata) {
1139
1140 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1141 Network *network = userdata;
1142 int r;
1143
1144 assert(filename);
1145 assert(section);
1146 assert(lvalue);
1147 assert(rvalue);
1148 assert(data);
1149
1150 r = routing_policy_rule_new_static(network, filename, section_line, &n);
1151 if (r < 0)
d96edb2c 1152 return log_oom();
53e1ba28
NF
1153
1154 r = parse_ip_prefix_length(rvalue, &n->suppress_prefixlen);
1155 if (r == -ERANGE) {
d96edb2c 1156 log_syntax(unit, LOG_WARNING, filename, line, r, "Prefix length outside of valid range 0-128, ignoring: %s", rvalue);
53e1ba28
NF
1157 return 0;
1158 }
1159 if (r < 0) {
d96edb2c 1160 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule suppress_prefixlen, ignoring: %s", rvalue);
53e1ba28
NF
1161 return 0;
1162 }
1163
1164 n = NULL;
1165
ea471a46
YW
1166 return 0;
1167}
1168
458d8ae3 1169static int routing_policy_rule_read_full_file(const char *state_file, char **ret) {
ac097c84 1170 _cleanup_free_ char *s = NULL;
bce67bbe
SS
1171 size_t size;
1172 int r;
1173
1174 assert(state_file);
1175
1176 r = read_full_file(state_file, &s, &size);
1177 if (r == -ENOENT)
1178 return -ENODATA;
1179 if (r < 0)
1180 return r;
1181 if (size <= 0)
1182 return -ENODATA;
1183
ae2a15bc 1184 *ret = TAKE_PTR(s);
bce67bbe
SS
1185
1186 return size;
1187}
1188
458d8ae3
ZJS
1189int routing_policy_serialize_rules(Set *rules, FILE *f) {
1190 RoutingPolicyRule *rule = NULL;
1191 Iterator i;
1192 int r;
1193
1194 assert(f);
1195
1196 SET_FOREACH(rule, rules, i) {
1197 _cleanup_free_ char *from_str = NULL, *to_str = NULL;
1198 bool space = false;
43e08c78 1199 const char *family_str;
458d8ae3
ZJS
1200
1201 fputs("RULE=", f);
1202
1203 if (!in_addr_is_null(rule->family, &rule->from)) {
1204 r = in_addr_to_string(rule->family, &rule->from, &from_str);
1205 if (r < 0)
1206 return r;
1207
1208 fprintf(f, "from=%s/%hhu",
1209 from_str, rule->from_prefixlen);
1210 space = true;
1211 }
1212
1213 if (!in_addr_is_null(rule->family, &rule->to)) {
1214 r = in_addr_to_string(rule->family, &rule->to, &to_str);
1215 if (r < 0)
1216 return r;
1217
1218 fprintf(f, "%sto=%s/%hhu",
1219 space ? " " : "",
1220 to_str, rule->to_prefixlen);
1221 space = true;
1222 }
1223
43e08c78
YW
1224 family_str = af_to_name(rule->family);
1225 if (family_str)
1226 fprintf(f, "%sfamily=%s",
1227 space ? " " : "",
1228 family_str);
1229
458d8ae3
ZJS
1230 if (rule->tos != 0) {
1231 fprintf(f, "%stos=%hhu",
1232 space ? " " : "",
1233 rule->tos);
1234 space = true;
1235 }
1236
ec863cdc
YW
1237 fprintf(f, "%spriority=%"PRIu32,
1238 space ? " " : "",
1239 rule->priority);
1240
458d8ae3
ZJS
1241 if (rule->fwmark != 0) {
1242 fprintf(f, "%sfwmark=%"PRIu32"/%"PRIu32,
1243 space ? " " : "",
1244 rule->fwmark, rule->fwmask);
1245 space = true;
1246 }
1247
9491f55f
ZJS
1248 if (rule->iif) {
1249 fprintf(f, "%siif=%s",
1250 space ? " " : "",
1251 rule->iif);
1252 space = true;
1253 }
1254
1255 if (rule->oif) {
1256 fprintf(f, "%soif=%s",
1257 space ? " " : "",
1258 rule->oif);
1259 space = true;
1260 }
1261
926062f0
SS
1262 if (rule->protocol != 0) {
1263 fprintf(f, "%sprotocol=%hhu",
1264 space ? " " : "",
1265 rule->protocol);
1266 space = true;
1267 }
1268
1269 if (rule->sport.start != 0 || rule->sport.end != 0) {
58a02e4c 1270 fprintf(f, "%ssourcesport=%"PRIu16"-%"PRIu16,
926062f0
SS
1271 space ? " " : "",
1272 rule->sport.start, rule->sport.end);
1273 space = true;
1274 }
1275
1276 if (rule->dport.start != 0 || rule->dport.end != 0) {
58a02e4c 1277 fprintf(f, "%sdestinationport=%"PRIu16"-%"PRIu16,
926062f0
SS
1278 space ? " " : "",
1279 rule->dport.start, rule->dport.end);
1280 space = true;
1281 }
1282
ea471a46
YW
1283 if (rule->uid_range.start != UID_INVALID && rule->uid_range.end != UID_INVALID) {
1284 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
1285 fprintf(f, "%suidrange="UID_FMT"-"UID_FMT,
1286 space ? " " : "",
1287 rule->uid_range.start, rule->uid_range.end);
1288 space = true;
1289 }
1290
53e1ba28
NF
1291 if (rule->suppress_prefixlen >= 0) {
1292 fprintf(f, "%ssuppress_prefixlen=%d",
1293 space ? " " : "",
1294 rule->suppress_prefixlen);
1295 space = true;
1296 }
1297
458d8ae3
ZJS
1298 fprintf(f, "%stable=%"PRIu32 "\n",
1299 space ? " " : "",
1300 rule->table);
1301 }
1302
1303 return 0;
1304}
1305
1306int routing_policy_load_rules(const char *state_file, Set **rules) {
bce67bbe
SS
1307 _cleanup_strv_free_ char **l = NULL;
1308 _cleanup_free_ char *data = NULL;
926062f0 1309 uint16_t low = 0, high = 0;
bce67bbe
SS
1310 const char *p;
1311 char **i;
1312 int r;
1313
458d8ae3
ZJS
1314 assert(state_file);
1315 assert(rules);
bce67bbe 1316
458d8ae3 1317 r = routing_policy_rule_read_full_file(state_file, &data);
bce67bbe
SS
1318 if (r <= 0)
1319 return r;
1320
1321 l = strv_split_newlines(data);
1322 if (!l)
1323 return -ENOMEM;
1324
bce67bbe 1325 STRV_FOREACH(i, l) {
8e766630 1326 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
bce67bbe
SS
1327
1328 p = startswith(*i, "RULE=");
1329 if (!p)
1330 continue;
1331
bce67bbe
SS
1332 r = routing_policy_rule_new(&rule);
1333 if (r < 0)
1334 return r;
1335
1336 for (;;) {
1337 _cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
bce67bbe
SS
1338
1339 r = extract_first_word(&p, &word, NULL, 0);
1340 if (r < 0)
1341 return r;
1342 if (r == 0)
1343 break;
1344
1345 r = split_pair(word, "=", &a, &b);
1346 if (r < 0)
1347 continue;
1348
1349 if (STR_IN_SET(a, "from", "to")) {
7934dede
YW
1350 union in_addr_union *buffer;
1351 uint8_t *prefixlen;
bce67bbe
SS
1352
1353 if (streq(a, "to")) {
7934dede
YW
1354 buffer = &rule->to;
1355 prefixlen = &rule->to_prefixlen;
bce67bbe 1356 } else {
7934dede
YW
1357 buffer = &rule->from;
1358 prefixlen = &rule->from_prefixlen;
1359 }
1360
1361 r = in_addr_prefix_from_string_auto(b, &rule->family, buffer, prefixlen);
1362 if (r < 0) {
1363 log_error_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
1364 continue;
bce67bbe 1365 }
7934dede 1366
43e08c78
YW
1367 } else if (streq(a, "family")) {
1368 r = af_from_name(b);
1369 if (r < 0) {
1370 log_error_errno(r, "Failed to parse RPDB rule family, ignoring: %s", b);
1371 continue;
1372 }
1373 rule->family = r;
bce67bbe
SS
1374 } else if (streq(a, "tos")) {
1375 r = safe_atou8(b, &rule->tos);
1376 if (r < 0) {
0da425df 1377 log_error_errno(r, "Failed to parse RPDB rule TOS, ignoring: %s", b);
bce67bbe
SS
1378 continue;
1379 }
1380 } else if (streq(a, "table")) {
1381 r = safe_atou32(b, &rule->table);
1382 if (r < 0) {
1383 log_error_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b);
1384 continue;
1385 }
ec863cdc
YW
1386 } else if (streq(a, "priority")) {
1387 r = safe_atou32(b, &rule->priority);
1388 if (r < 0) {
1389 log_error_errno(r, "Failed to parse RPDB rule priority, ignoring: %s", b);
1390 continue;
1391 }
bce67bbe 1392 } else if (streq(a, "fwmark")) {
e4aca57d 1393 r = parse_fwmark_fwmask(b, &rule->fwmark, &rule->fwmask);
bce67bbe
SS
1394 if (r < 0) {
1395 log_error_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
1396 continue;
1397 }
9491f55f 1398 } else if (streq(a, "iif")) {
93f9da6e 1399 if (free_and_strdup(&rule->iif, b) < 0)
762e2659 1400 return log_oom();
93f9da6e 1401
9491f55f 1402 } else if (streq(a, "oif")) {
762e2659 1403
93f9da6e 1404 if (free_and_strdup(&rule->oif, b) < 0)
762e2659 1405 return log_oom();
926062f0
SS
1406 } else if (streq(a, "protocol")) {
1407 r = safe_atou8(b, &rule->protocol);
1408 if (r < 0) {
1409 log_error_errno(r, "Failed to parse RPDB rule protocol, ignoring: %s", b);
1410 continue;
1411 }
1412 } else if (streq(a, "sourceport")) {
926062f0
SS
1413 r = parse_ip_port_range(b, &low, &high);
1414 if (r < 0) {
ea471a46 1415 log_error_errno(r, "Invalid routing policy rule source port range, ignoring assignment: '%s'", b);
926062f0
SS
1416 continue;
1417 }
1418
1419 rule->sport.start = low;
1420 rule->sport.end = high;
926062f0 1421 } else if (streq(a, "destinationport")) {
926062f0
SS
1422 r = parse_ip_port_range(b, &low, &high);
1423 if (r < 0) {
ea471a46 1424 log_error_errno(r, "Invalid routing policy rule destination port range, ignoring assignment: '%s'", b);
926062f0
SS
1425 continue;
1426 }
1427
1428 rule->dport.start = low;
1429 rule->dport.end = high;
ea471a46
YW
1430 } else if (streq(a, "uidrange")) {
1431 uid_t lower, upper;
1432
1433 r = parse_uid_range(b, &lower, &upper);
1434 if (r < 0) {
1435 log_error_errno(r, "Invalid routing policy rule uid range, ignoring assignment: '%s'", b);
1436 continue;
1437 }
1438
1439 rule->uid_range.start = lower;
1440 rule->uid_range.end = upper;
53e1ba28
NF
1441 } else if (streq(a, "suppress_prefixlen")) {
1442 r = parse_ip_prefix_length(b, &rule->suppress_prefixlen);
1443 if (r == -ERANGE) {
1444 log_error_errno(r, "Prefix length outside of valid range 0-128, ignoring: %s", b);
1445 continue;
1446 }
1447 if (r < 0) {
1448 log_error_errno(r, "Failed to parse RPDB rule suppress_prefixlen, ignoring: %s", b);
1449 continue;
1450 }
bce67bbe
SS
1451 }
1452 }
1453
de7fef4b 1454 r = set_ensure_put(rules, &routing_policy_rule_hash_ops, rule);
bce67bbe
SS
1455 if (r < 0) {
1456 log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", p);
1457 continue;
1458 }
75a302b5
YW
1459 if (r > 0)
1460 rule = NULL;
bce67bbe
SS
1461 }
1462
1463 return 0;
1464}
1465
031fb59a
YW
1466static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule *rule) {
1467 RoutingPolicyRule *link_rule;
1468 Iterator i;
1469 Link *link;
1470
1471 assert(m);
1472 assert(rule);
1473
1474 HASHMAP_FOREACH(link, m->links, i) {
1475 if (!link->network)
1476 continue;
1477
1478 LIST_FOREACH(rules, link_rule, link->network->rules)
1479 if (routing_policy_rule_compare_func(link_rule, rule) == 0)
1480 return true;
1481 }
1482
1483 return false;
1484}
1485
bce67bbe
SS
1486void routing_policy_rule_purge(Manager *m, Link *link) {
1487 RoutingPolicyRule *rule, *existing;
1488 Iterator i;
1489 int r;
1490
1491 assert(m);
1492 assert(link);
1493
1494 SET_FOREACH(rule, m->rules_saved, i) {
1495 existing = set_get(m->rules_foreign, rule);
92cd00b9
YW
1496 if (!existing)
1497 continue; /* Saved rule does not exist anymore. */
bce67bbe 1498
031fb59a
YW
1499 if (manager_links_have_routing_policy_rule(m, existing))
1500 continue; /* Existing links have the saved rule. */
1501
1502 /* Existing links do not have the saved rule. Let's drop the rule now, and re-configure it
1503 * later when it is requested. */
1504
92cd00b9
YW
1505 r = routing_policy_rule_remove(existing, link, NULL);
1506 if (r < 0) {
1507 log_warning_errno(r, "Could not remove routing policy rules: %m");
1508 continue;
bce67bbe 1509 }
92cd00b9
YW
1510
1511 link->routing_policy_rule_remove_messages++;
1512
1513 assert_se(set_remove(m->rules_foreign, existing) == existing);
1514 routing_policy_rule_free(existing);
bce67bbe
SS
1515 }
1516}