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