1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <net/if.h>
4 #include <linux/fib_rules.h>
5 
6 #include "af-list.h"
7 #include "alloc-util.h"
8 #include "conf-parser.h"
9 #include "fileio.h"
10 #include "format-util.h"
11 #include "hashmap.h"
12 #include "ip-protocol-list.h"
13 #include "netlink-util.h"
14 #include "networkd-manager.h"
15 #include "networkd-queue.h"
16 #include "networkd-route-util.h"
17 #include "networkd-routing-policy-rule.h"
18 #include "networkd-util.h"
19 #include "parse-util.h"
20 #include "socket-util.h"
21 #include "string-table.h"
22 #include "string-util.h"
23 #include "strv.h"
24 #include "user-util.h"
25 
26 static const char *const fr_act_type_table[__FR_ACT_MAX] = {
27         [FR_ACT_BLACKHOLE]   = "blackhole",
28         [FR_ACT_UNREACHABLE] = "unreachable",
29         [FR_ACT_PROHIBIT]    = "prohibit",
30 };
31 
32 static const char *const fr_act_type_full_table[__FR_ACT_MAX] = {
33         [FR_ACT_TO_TBL]      = "table",
34         [FR_ACT_GOTO]        = "goto",
35         [FR_ACT_NOP]         = "nop",
36         [FR_ACT_BLACKHOLE]   = "blackhole",
37         [FR_ACT_UNREACHABLE] = "unreachable",
38         [FR_ACT_PROHIBIT]    = "prohibit",
39 };
40 
41 assert_cc(__FR_ACT_MAX <= UINT8_MAX);
42 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(fr_act_type, int);
43 DEFINE_STRING_TABLE_LOOKUP_TO_STRING(fr_act_type_full, int);
44 
routing_policy_rule_free(RoutingPolicyRule * rule)45 RoutingPolicyRule *routing_policy_rule_free(RoutingPolicyRule *rule) {
46         if (!rule)
47                 return NULL;
48 
49         if (rule->network) {
50                 assert(rule->section);
51                 hashmap_remove(rule->network->rules_by_section, rule->section);
52         }
53 
54         if (rule->manager)
55                 set_remove(rule->manager->rules, rule);
56 
57         config_section_free(rule->section);
58         free(rule->iif);
59         free(rule->oif);
60 
61         return mfree(rule);
62 }
63 
64 DEFINE_SECTION_CLEANUP_FUNCTIONS(RoutingPolicyRule, routing_policy_rule_free);
65 
routing_policy_rule_new(RoutingPolicyRule ** ret)66 static int routing_policy_rule_new(RoutingPolicyRule **ret) {
67         RoutingPolicyRule *rule;
68 
69         rule = new(RoutingPolicyRule, 1);
70         if (!rule)
71                 return -ENOMEM;
72 
73         *rule = (RoutingPolicyRule) {
74                 .table = RT_TABLE_MAIN,
75                 .uid_range.start = UID_INVALID,
76                 .uid_range.end = UID_INVALID,
77                 .suppress_prefixlen = -1,
78                 .suppress_ifgroup = -1,
79                 .protocol = RTPROT_UNSPEC,
80                 .type = FR_ACT_TO_TBL,
81         };
82 
83         *ret = rule;
84         return 0;
85 }
86 
routing_policy_rule_new_static(Network * network,const char * filename,unsigned section_line,RoutingPolicyRule ** ret)87 static int routing_policy_rule_new_static(Network *network, const char *filename, unsigned section_line, RoutingPolicyRule **ret) {
88         _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
89         _cleanup_(config_section_freep) ConfigSection *n = NULL;
90         int r;
91 
92         assert(network);
93         assert(ret);
94         assert(filename);
95         assert(section_line > 0);
96 
97         r = config_section_new(filename, section_line, &n);
98         if (r < 0)
99                 return r;
100 
101         rule = hashmap_get(network->rules_by_section, n);
102         if (rule) {
103                 *ret = TAKE_PTR(rule);
104                 return 0;
105         }
106 
107         r = routing_policy_rule_new(&rule);
108         if (r < 0)
109                 return r;
110 
111         rule->network = network;
112         rule->section = TAKE_PTR(n);
113         rule->source = NETWORK_CONFIG_SOURCE_STATIC;
114         rule->protocol = RTPROT_STATIC;
115 
116         r = hashmap_ensure_put(&network->rules_by_section, &config_section_hash_ops, rule->section, rule);
117         if (r < 0)
118                 return r;
119 
120         *ret = TAKE_PTR(rule);
121         return 0;
122 }
123 
routing_policy_rule_dup(const RoutingPolicyRule * src,RoutingPolicyRule ** ret)124 static int routing_policy_rule_dup(const RoutingPolicyRule *src, RoutingPolicyRule **ret) {
125         _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *dest = NULL;
126 
127         assert(src);
128         assert(ret);
129 
130         dest = newdup(RoutingPolicyRule, src, 1);
131         if (!dest)
132                 return -ENOMEM;
133 
134         /* Unset all pointers */
135         dest->manager = NULL;
136         dest->network = NULL;
137         dest->section = NULL;
138         dest->iif = dest->oif = NULL;
139 
140         if (src->iif) {
141                 dest->iif = strdup(src->iif);
142                 if (!dest->iif)
143                         return -ENOMEM;
144         }
145 
146         if (src->oif) {
147                 dest->oif = strdup(src->oif);
148                 if (!dest->oif)
149                         return -ENOMEM;
150         }
151 
152         *ret = TAKE_PTR(dest);
153         return 0;
154 }
155 
routing_policy_rule_hash_func(const RoutingPolicyRule * rule,struct siphash * state)156 static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash *state) {
157         assert(rule);
158 
159         siphash24_compress(&rule->family, sizeof(rule->family), state);
160 
161         switch (rule->family) {
162         case AF_INET:
163         case AF_INET6:
164                 siphash24_compress(&rule->from, FAMILY_ADDRESS_SIZE(rule->family), state);
165                 siphash24_compress(&rule->from_prefixlen, sizeof(rule->from_prefixlen), state);
166 
167                 siphash24_compress(&rule->to, FAMILY_ADDRESS_SIZE(rule->family), state);
168                 siphash24_compress(&rule->to_prefixlen, sizeof(rule->to_prefixlen), state);
169 
170                 siphash24_compress_boolean(rule->invert_rule, state);
171 
172                 siphash24_compress(&rule->tos, sizeof(rule->tos), state);
173                 siphash24_compress(&rule->type, sizeof(rule->type), state);
174                 siphash24_compress(&rule->fwmark, sizeof(rule->fwmark), state);
175                 siphash24_compress(&rule->fwmask, sizeof(rule->fwmask), state);
176                 siphash24_compress(&rule->priority, sizeof(rule->priority), state);
177                 siphash24_compress(&rule->table, sizeof(rule->table), state);
178                 siphash24_compress(&rule->suppress_prefixlen, sizeof(rule->suppress_prefixlen), state);
179                 siphash24_compress(&rule->suppress_ifgroup, sizeof(rule->suppress_ifgroup), state);
180 
181                 siphash24_compress(&rule->ipproto, sizeof(rule->ipproto), state);
182                 siphash24_compress(&rule->protocol, sizeof(rule->protocol), state);
183                 siphash24_compress(&rule->sport, sizeof(rule->sport), state);
184                 siphash24_compress(&rule->dport, sizeof(rule->dport), state);
185                 siphash24_compress(&rule->uid_range, sizeof(rule->uid_range), state);
186 
187                 siphash24_compress_string(rule->iif, state);
188                 siphash24_compress_string(rule->oif, state);
189 
190                 break;
191         default:
192                 /* treat any other address family as AF_UNSPEC */
193                 break;
194         }
195 }
196 
routing_policy_rule_compare_func(const RoutingPolicyRule * a,const RoutingPolicyRule * b)197 static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPolicyRule *b) {
198         int r;
199 
200         r = CMP(a->family, b->family);
201         if (r != 0)
202                 return r;
203 
204         switch (a->family) {
205         case AF_INET:
206         case AF_INET6:
207                 r = CMP(a->from_prefixlen, b->from_prefixlen);
208                 if (r != 0)
209                         return r;
210 
211                 r = memcmp(&a->from, &b->from, FAMILY_ADDRESS_SIZE(a->family));
212                 if (r != 0)
213                         return r;
214 
215                 r = CMP(a->to_prefixlen, b->to_prefixlen);
216                 if (r != 0)
217                         return r;
218 
219                 r = memcmp(&a->to, &b->to, FAMILY_ADDRESS_SIZE(a->family));
220                 if (r != 0)
221                         return r;
222 
223                 r = CMP(a->invert_rule, b->invert_rule);
224                 if (r != 0)
225                         return r;
226 
227                 r = CMP(a->tos, b->tos);
228                 if (r != 0)
229                         return r;
230 
231                 r = CMP(a->type, b->type);
232                 if (r != 0)
233                         return r;
234 
235                 r = CMP(a->fwmark, b->fwmark);
236                 if (r != 0)
237                         return r;
238 
239                 r = CMP(a->fwmask, b->fwmask);
240                 if (r != 0)
241                         return r;
242 
243                 r = CMP(a->priority, b->priority);
244                 if (r != 0)
245                         return r;
246 
247                 r = CMP(a->table, b->table);
248                 if (r != 0)
249                         return r;
250 
251                 r = CMP(a->suppress_prefixlen, b->suppress_prefixlen);
252                 if (r != 0)
253                         return r;
254 
255                 r = CMP(a->suppress_ifgroup, b->suppress_ifgroup);
256                 if (r != 0)
257                         return r;
258 
259                 r = CMP(a->ipproto, b->ipproto);
260                 if (r != 0)
261                         return r;
262 
263                 r = CMP(a->protocol, b->protocol);
264                 if (r != 0)
265                         return r;
266 
267                 r = memcmp(&a->sport, &b->sport, sizeof(a->sport));
268                 if (r != 0)
269                         return r;
270 
271                 r = memcmp(&a->dport, &b->dport, sizeof(a->dport));
272                 if (r != 0)
273                         return r;
274 
275                 r = memcmp(&a->uid_range, &b->uid_range, sizeof(a->uid_range));
276                 if (r != 0)
277                         return r;
278 
279                 r = strcmp_ptr(a->iif, b->iif);
280                 if (r != 0)
281                         return r;
282 
283                 r = strcmp_ptr(a->oif, b->oif);
284                 if (r != 0)
285                         return r;
286 
287                 return 0;
288         default:
289                 /* treat any other address family as AF_UNSPEC */
290                 return 0;
291         }
292 }
293 
routing_policy_rule_equal(const RoutingPolicyRule * rule1,const RoutingPolicyRule * rule2)294 static bool routing_policy_rule_equal(const RoutingPolicyRule *rule1, const RoutingPolicyRule *rule2) {
295         if (rule1 == rule2)
296                 return true;
297 
298         if (!rule1 || !rule2)
299                 return false;
300 
301         return routing_policy_rule_compare_func(rule1, rule2) == 0;
302 }
303 
304 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
305                 routing_policy_rule_hash_ops,
306                 RoutingPolicyRule,
307                 routing_policy_rule_hash_func,
308                 routing_policy_rule_compare_func,
309                 routing_policy_rule_free);
310 
routing_policy_rule_get(Manager * m,const RoutingPolicyRule * in,RoutingPolicyRule ** ret)311 static int routing_policy_rule_get(Manager *m, const RoutingPolicyRule *in, RoutingPolicyRule **ret) {
312         RoutingPolicyRule *rule;
313 
314         assert(m);
315         assert(in);
316 
317         rule = set_get(m->rules, in);
318         if (rule) {
319                 if (ret)
320                         *ret = rule;
321                 return 0;
322         }
323 
324         if (in->priority_set)
325                 return -ENOENT;
326 
327         /* Also find rules configured without priority. */
328         SET_FOREACH(rule, m->rules) {
329                 uint32_t priority;
330                 bool found;
331 
332                 if (rule->priority_set)
333                         /* The rule is configured with priority. */
334                         continue;
335 
336                 priority = rule->priority;
337                 rule->priority = 0;
338                 found = routing_policy_rule_equal(rule, in);
339                 rule->priority = priority;
340 
341                 if (found) {
342                         if (ret)
343                                 *ret = rule;
344                         return 0;
345                 }
346         }
347 
348         return -ENOENT;
349 }
350 
routing_policy_rule_add(Manager * m,RoutingPolicyRule * rule)351 static int routing_policy_rule_add(Manager *m, RoutingPolicyRule *rule) {
352         int r;
353 
354         assert(m);
355         assert(rule);
356         assert(IN_SET(rule->family, AF_INET, AF_INET6));
357 
358         r = set_ensure_put(&m->rules, &routing_policy_rule_hash_ops, rule);
359         if (r < 0)
360                 return r;
361         if (r == 0)
362                 return -EEXIST;
363 
364         rule->manager = m;
365         return 0;
366 }
367 
routing_policy_rule_acquire_priority(Manager * manager,RoutingPolicyRule * rule)368 static int routing_policy_rule_acquire_priority(Manager *manager, RoutingPolicyRule *rule) {
369         _cleanup_set_free_ Set *priorities = NULL;
370         RoutingPolicyRule *tmp;
371         uint32_t priority;
372         Network *network;
373         int r;
374 
375         assert(manager);
376         assert(rule);
377         assert(IN_SET(rule->family, AF_INET, AF_INET6));
378 
379         if (rule->priority_set)
380                 return 0;
381 
382         /* Find the highest unused priority. Note that 32766 is already used by kernel.
383          * See kernel_rules[] below. */
384 
385         SET_FOREACH(tmp, manager->rules) {
386                 if (tmp->family != rule->family)
387                         continue;
388                 if (tmp->priority == 0 || tmp->priority > 32765)
389                         continue;
390                 r = set_ensure_put(&priorities, NULL, UINT32_TO_PTR(tmp->priority));
391                 if (r < 0)
392                         return r;
393         }
394 
395         ORDERED_HASHMAP_FOREACH(network, manager->networks)
396                 HASHMAP_FOREACH(tmp, network->rules_by_section) {
397                         if (tmp->family != AF_UNSPEC && tmp->family != rule->family)
398                                 continue;
399                         if (!tmp->priority_set)
400                                 continue;
401                         if (tmp->priority == 0 || tmp->priority > 32765)
402                                 continue;
403                         r = set_ensure_put(&priorities, NULL, UINT32_TO_PTR(tmp->priority));
404                         if (r < 0)
405                                 return r;
406                 }
407 
408         for (priority = 32765; priority > 0; priority--)
409                 if (!set_contains(priorities, UINT32_TO_PTR(priority)))
410                         break;
411 
412         rule->priority = priority;
413         return 0;
414 }
415 
log_routing_policy_rule_debug(const RoutingPolicyRule * rule,const char * str,const Link * link,const Manager * m)416 static void log_routing_policy_rule_debug(const RoutingPolicyRule *rule, const char *str, const Link *link, const Manager *m) {
417         _cleanup_free_ char *state = NULL, *from = NULL, *to = NULL, *table = NULL;
418 
419         assert(rule);
420         assert(IN_SET(rule->family, AF_INET, AF_INET6));
421         assert(str);
422         assert(m);
423 
424         /* link may be NULL. */
425 
426         if (!DEBUG_LOGGING)
427                 return;
428 
429         (void) network_config_state_to_string_alloc(rule->state, &state);
430         (void) in_addr_prefix_to_string(rule->family, &rule->from, rule->from_prefixlen, &from);
431         (void) in_addr_prefix_to_string(rule->family, &rule->to, rule->to_prefixlen, &to);
432         (void) manager_get_route_table_to_string(m, rule->table, &table);
433 
434         log_link_debug(link,
435                        "%s %s routing policy rule (%s): priority: %"PRIu32", %s -> %s, iif: %s, oif: %s, table: %s",
436                        str, strna(network_config_source_to_string(rule->source)), strna(state),
437                        rule->priority, strna(from), strna(to),
438                        strna(rule->iif), strna(rule->oif), strna(table));
439 }
440 
routing_policy_rule_set_netlink_message(const RoutingPolicyRule * rule,sd_netlink_message * m,Link * link)441 static int routing_policy_rule_set_netlink_message(const RoutingPolicyRule *rule, sd_netlink_message *m, Link *link) {
442         int r;
443 
444         assert(rule);
445         assert(m);
446 
447         /* link may be NULL. */
448 
449         if (rule->from_prefixlen > 0) {
450                 r = netlink_message_append_in_addr_union(m, FRA_SRC, rule->family, &rule->from);
451                 if (r < 0)
452                         return r;
453 
454                 r = sd_rtnl_message_routing_policy_rule_set_fib_src_prefixlen(m, rule->from_prefixlen);
455                 if (r < 0)
456                         return r;
457         }
458 
459         if (rule->to_prefixlen > 0) {
460                 r = netlink_message_append_in_addr_union(m, FRA_DST, rule->family, &rule->to);
461                 if (r < 0)
462                         return r;
463 
464                 r = sd_rtnl_message_routing_policy_rule_set_fib_dst_prefixlen(m, rule->to_prefixlen);
465                 if (r < 0)
466                         return r;
467         }
468 
469         r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
470         if (r < 0)
471                 return r;
472 
473         if (rule->tos > 0) {
474                 r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
475                 if (r < 0)
476                         return r;
477         }
478 
479         if (rule->table < 256) {
480                 r = sd_rtnl_message_routing_policy_rule_set_table(m, rule->table);
481                 if (r < 0)
482                         return r;
483         } else {
484                 r = sd_rtnl_message_routing_policy_rule_set_table(m, RT_TABLE_UNSPEC);
485                 if (r < 0)
486                         return r;
487 
488                 r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table);
489                 if (r < 0)
490                         return r;
491         }
492 
493         if (rule->fwmark > 0) {
494                 r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark);
495                 if (r < 0)
496                         return r;
497 
498                 r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
499                 if (r < 0)
500                         return r;
501         }
502 
503         if (rule->iif) {
504                 r = sd_netlink_message_append_string(m, FRA_IIFNAME, rule->iif);
505                 if (r < 0)
506                         return r;
507         }
508 
509         if (rule->oif) {
510                 r = sd_netlink_message_append_string(m, FRA_OIFNAME, rule->oif);
511                 if (r < 0)
512                         return r;
513         }
514 
515         r = sd_netlink_message_append_u8(m, FRA_IP_PROTO, rule->ipproto);
516         if (r < 0)
517                 return r;
518 
519         r = sd_netlink_message_append_u8(m, FRA_PROTOCOL, rule->protocol);
520         if (r < 0)
521                 return r;
522 
523         if (rule->sport.start != 0 || rule->sport.end != 0) {
524                 r = sd_netlink_message_append_data(m, FRA_SPORT_RANGE, &rule->sport, sizeof(rule->sport));
525                 if (r < 0)
526                         return r;
527         }
528 
529         if (rule->dport.start != 0 || rule->dport.end != 0) {
530                 r = sd_netlink_message_append_data(m, FRA_DPORT_RANGE, &rule->dport, sizeof(rule->dport));
531                 if (r < 0)
532                         return r;
533         }
534 
535         if (rule->uid_range.start != UID_INVALID && rule->uid_range.end != UID_INVALID) {
536                 r = sd_netlink_message_append_data(m, FRA_UID_RANGE, &rule->uid_range, sizeof(rule->uid_range));
537                 if (r < 0)
538                         return r;
539         }
540 
541         if (rule->invert_rule) {
542                 r = sd_rtnl_message_routing_policy_rule_set_flags(m, FIB_RULE_INVERT);
543                 if (r < 0)
544                         return r;
545         }
546 
547         if (rule->suppress_prefixlen >= 0) {
548                 r = sd_netlink_message_append_u32(m, FRA_SUPPRESS_PREFIXLEN, (uint32_t) rule->suppress_prefixlen);
549                 if (r < 0)
550                         return r;
551         }
552 
553         if (rule->suppress_ifgroup >= 0) {
554                 r = sd_netlink_message_append_u32(m, FRA_SUPPRESS_IFGROUP, (uint32_t) rule->suppress_ifgroup);
555                 if (r < 0)
556                         return r;
557         }
558 
559         r = sd_rtnl_message_routing_policy_rule_set_fib_type(m, rule->type);
560         if (r < 0)
561                 return r;
562 
563         return 0;
564 }
565 
routing_policy_rule_remove_handler(sd_netlink * rtnl,sd_netlink_message * m,void * userdata)566 static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
567         int r;
568 
569         assert(m);
570 
571         r = sd_netlink_message_get_errno(m);
572         if (r < 0)
573                 log_message_warning_errno(m, r, "Could not drop routing policy rule");
574 
575         return 1;
576 }
577 
routing_policy_rule_remove(RoutingPolicyRule * rule)578 static int routing_policy_rule_remove(RoutingPolicyRule *rule) {
579         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
580         int r;
581 
582         assert(rule);
583         assert(rule->manager);
584         assert(rule->manager->rtnl);
585         assert(IN_SET(rule->family, AF_INET, AF_INET6));
586 
587         log_routing_policy_rule_debug(rule, "Removing", NULL, rule->manager);
588 
589         r = sd_rtnl_message_new_routing_policy_rule(rule->manager->rtnl, &m, RTM_DELRULE, rule->family);
590         if (r < 0)
591                 return log_warning_errno(r, "Could not allocate netlink message: %m");
592 
593         r = routing_policy_rule_set_netlink_message(rule, m, NULL);
594         if (r < 0)
595                 return log_warning_errno(r, "Could not create netlink message: %m");
596 
597         r = netlink_call_async(rule->manager->rtnl, NULL, m,
598                                routing_policy_rule_remove_handler,
599                                NULL, NULL);
600         if (r < 0)
601                 return log_warning_errno(r, "Could not send netlink message: %m");
602 
603         routing_policy_rule_enter_removing(rule);
604         return 0;
605 }
606 
routing_policy_rule_configure(RoutingPolicyRule * rule,Link * link,Request * req)607 static int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, Request *req) {
608         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
609         int r;
610 
611         assert(rule);
612         assert(IN_SET(rule->family, AF_INET, AF_INET6));
613         assert(link);
614         assert(link->ifindex > 0);
615         assert(link->manager);
616         assert(link->manager->rtnl);
617         assert(req);
618 
619         log_routing_policy_rule_debug(rule, "Configuring", link, link->manager);
620 
621         r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
622         if (r < 0)
623                 return r;
624 
625         r = routing_policy_rule_set_netlink_message(rule, m, link);
626         if (r < 0)
627                 return r;
628 
629         return request_call_netlink_async(link->manager->rtnl, m, req);
630 }
631 
manager_mark_routing_policy_rules(Manager * m,bool foreign,const Link * except)632 static void manager_mark_routing_policy_rules(Manager *m, bool foreign, const Link *except) {
633         RoutingPolicyRule *rule;
634         Link *link;
635 
636         assert(m);
637 
638         /* First, mark all existing rules. */
639         SET_FOREACH(rule, m->rules) {
640                 /* Do not touch rules managed by kernel. */
641                 if (rule->protocol == RTPROT_KERNEL)
642                         continue;
643 
644                 /* When 'foreign' is true, mark only foreign rules, and vice versa. */
645                 if (foreign != (rule->source == NETWORK_CONFIG_SOURCE_FOREIGN))
646                         continue;
647 
648                 /* Ignore rules not assigned yet or already removing. */
649                 if (!routing_policy_rule_exists(rule))
650                         continue;
651 
652                 routing_policy_rule_mark(rule);
653         }
654 
655         /* Then, unmark all rules requested by active links. */
656         HASHMAP_FOREACH(link, m->links_by_index) {
657                 if (link == except)
658                         continue;
659 
660                 if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
661                         continue;
662 
663                 HASHMAP_FOREACH(rule, link->network->rules_by_section) {
664                         RoutingPolicyRule *existing;
665 
666                         if (IN_SET(rule->family, AF_INET, AF_INET6)) {
667                                 if (routing_policy_rule_get(m, rule, &existing) >= 0)
668                                         routing_policy_rule_unmark(existing);
669                         } else {
670                                 /* The case Family=both. */
671                                 rule->family = AF_INET;
672                                 if (routing_policy_rule_get(m, rule, &existing) >= 0)
673                                         routing_policy_rule_unmark(existing);
674 
675                                 rule->family = AF_INET6;
676                                 if (routing_policy_rule_get(m, rule, &existing) >= 0)
677                                         routing_policy_rule_unmark(existing);
678 
679                                 rule->family = AF_UNSPEC;
680                         }
681                 }
682         }
683 }
684 
manager_drop_routing_policy_rules_internal(Manager * m,bool foreign,const Link * except)685 int manager_drop_routing_policy_rules_internal(Manager *m, bool foreign, const Link *except) {
686         RoutingPolicyRule *rule;
687         int k, r = 0;
688 
689         assert(m);
690 
691         manager_mark_routing_policy_rules(m, foreign, except);
692 
693         SET_FOREACH(rule, m->rules) {
694                 if (!routing_policy_rule_is_marked(rule))
695                         continue;
696 
697                 k = routing_policy_rule_remove(rule);
698                 if (k < 0 && r >= 0)
699                         r = k;
700         }
701 
702         return r;
703 }
704 
link_foreignize_routing_policy_rules(Link * link)705 void link_foreignize_routing_policy_rules(Link *link) {
706         RoutingPolicyRule *rule;
707 
708         assert(link);
709         assert(link->manager);
710 
711         manager_mark_routing_policy_rules(link->manager, /* foreign = */ false, link);
712 
713         SET_FOREACH(rule, link->manager->rules) {
714                 if (!routing_policy_rule_is_marked(rule))
715                         continue;
716 
717                 rule->source = NETWORK_CONFIG_SOURCE_FOREIGN;
718         }
719 }
720 
routing_policy_rule_process_request(Request * req,Link * link,RoutingPolicyRule * rule)721 static int routing_policy_rule_process_request(Request *req, Link *link, RoutingPolicyRule *rule) {
722         int r;
723 
724         assert(req);
725         assert(link);
726         assert(rule);
727 
728         if (!link_is_ready_to_configure(link, false))
729                 return 0;
730 
731         r = routing_policy_rule_configure(rule, link, req);
732         if (r < 0)
733                 return log_link_warning_errno(link, r, "Failed to configure routing policy rule: %m");
734 
735         routing_policy_rule_enter_configuring(rule);
736         return 1;
737 }
738 
static_routing_policy_rule_configure_handler(sd_netlink * rtnl,sd_netlink_message * m,Request * req,Link * link,RoutingPolicyRule * rule)739 static int static_routing_policy_rule_configure_handler(
740                 sd_netlink *rtnl,
741                 sd_netlink_message *m,
742                 Request *req,
743                 Link *link,
744                 RoutingPolicyRule *rule) {
745 
746         int r;
747 
748         assert(m);
749         assert(link);
750 
751         r = sd_netlink_message_get_errno(m);
752         if (r < 0 && r != -EEXIST) {
753                 log_link_message_warning_errno(link, m, r, "Could not add routing policy rule");
754                 link_enter_failed(link);
755                 return 1;
756         }
757 
758         if (link->static_routing_policy_rule_messages == 0) {
759                 log_link_debug(link, "Routing policy rule configured");
760                 link->static_routing_policy_rules_configured = true;
761                 link_check_ready(link);
762         }
763 
764         return 1;
765 }
766 
link_request_routing_policy_rule(Link * link,RoutingPolicyRule * rule)767 static int link_request_routing_policy_rule(Link *link, RoutingPolicyRule *rule) {
768         RoutingPolicyRule *existing;
769         int r;
770 
771         assert(link);
772         assert(link->manager);
773         assert(rule);
774         assert(rule->source != NETWORK_CONFIG_SOURCE_FOREIGN);
775 
776         if (routing_policy_rule_get(link->manager, rule, &existing) < 0) {
777                 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
778 
779                 r = routing_policy_rule_dup(rule, &tmp);
780                 if (r < 0)
781                         return r;
782 
783                 r = routing_policy_rule_acquire_priority(link->manager, tmp);
784                 if (r < 0)
785                         return r;
786 
787                 r = routing_policy_rule_add(link->manager, tmp);
788                 if (r < 0)
789                         return r;
790 
791                 existing = TAKE_PTR(tmp);
792         } else
793                 existing->source = rule->source;
794 
795         log_routing_policy_rule_debug(existing, "Requesting", link, link->manager);
796         r = link_queue_request_safe(link, REQUEST_TYPE_ROUTING_POLICY_RULE,
797                                     existing, NULL,
798                                     routing_policy_rule_hash_func,
799                                     routing_policy_rule_compare_func,
800                                     routing_policy_rule_process_request,
801                                     &link->static_routing_policy_rule_messages,
802                                     static_routing_policy_rule_configure_handler,
803                                     NULL);
804         if (r <= 0)
805                 return r;
806 
807         routing_policy_rule_enter_requesting(existing);
808         return 1;
809 }
810 
link_request_static_routing_policy_rule(Link * link,RoutingPolicyRule * rule)811 static int link_request_static_routing_policy_rule(Link *link, RoutingPolicyRule *rule) {
812         int r;
813 
814         if (IN_SET(rule->family, AF_INET, AF_INET6))
815                 return link_request_routing_policy_rule(link, rule);
816 
817         rule->family = AF_INET;
818         r = link_request_routing_policy_rule(link, rule);
819         if (r < 0) {
820                 rule->family = AF_UNSPEC;
821                 return r;
822         }
823 
824         rule->family = AF_INET6;
825         r = link_request_routing_policy_rule(link, rule);
826         rule->family = AF_UNSPEC;
827         return r;
828 }
829 
link_request_static_routing_policy_rules(Link * link)830 int link_request_static_routing_policy_rules(Link *link) {
831         RoutingPolicyRule *rule;
832         int r;
833 
834         assert(link);
835         assert(link->network);
836 
837         link->static_routing_policy_rules_configured = false;
838 
839         HASHMAP_FOREACH(rule, link->network->rules_by_section) {
840                 r = link_request_static_routing_policy_rule(link, rule);
841                 if (r < 0)
842                         return log_link_warning_errno(link, r, "Could not request routing policy rule: %m");
843         }
844 
845         if (link->static_routing_policy_rule_messages == 0) {
846                 link->static_routing_policy_rules_configured = true;
847                 link_check_ready(link);
848         } else {
849                 log_link_debug(link, "Requesting routing policy rules");
850                 link_set_state(link, LINK_STATE_CONFIGURING);
851         }
852 
853         return 0;
854 }
855 
856 static const RoutingPolicyRule kernel_rules[] = {
857         { .family = AF_INET,  .priority_set = true, .priority = 0,     .table = RT_TABLE_LOCAL,   .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, .suppress_ifgroup = -1, },
858         { .family = AF_INET,  .priority_set = true, .priority = 32766, .table = RT_TABLE_MAIN,    .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, .suppress_ifgroup = -1, },
859         { .family = AF_INET,  .priority_set = true, .priority = 32767, .table = RT_TABLE_DEFAULT, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, .suppress_ifgroup = -1, },
860         { .family = AF_INET6, .priority_set = true, .priority = 0,     .table = RT_TABLE_LOCAL,   .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, .suppress_ifgroup = -1, },
861         { .family = AF_INET6, .priority_set = true, .priority = 32766, .table = RT_TABLE_MAIN,    .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, .suppress_ifgroup = -1, },
862 };
863 
routing_policy_rule_is_created_by_kernel(const RoutingPolicyRule * rule)864 static bool routing_policy_rule_is_created_by_kernel(const RoutingPolicyRule *rule) {
865         assert(rule);
866 
867         if (rule->l3mdev > 0)
868                 /* Currently, [RoutingPolicyRule] does not explicitly set FRA_L3MDEV. So, if the flag
869                  * is set, it is safe to treat the rule as created by kernel. */
870                 return true;
871 
872         for (size_t i = 0; i < ELEMENTSOF(kernel_rules); i++)
873                 if (routing_policy_rule_equal(rule, &kernel_rules[i]))
874                         return true;
875 
876         return false;
877 }
878 
manager_rtnl_process_rule(sd_netlink * rtnl,sd_netlink_message * message,Manager * m)879 int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
880         _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL;
881         RoutingPolicyRule *rule = NULL;
882         bool adjust_protocol = false;
883         uint16_t type;
884         int r;
885 
886         assert(rtnl);
887         assert(message);
888 
889         if (sd_netlink_message_is_error(message)) {
890                 r = sd_netlink_message_get_errno(message);
891                 if (r < 0)
892                         log_message_warning_errno(message, r, "rtnl: failed to receive rule message, ignoring");
893 
894                 return 0;
895         }
896 
897         r = sd_netlink_message_get_type(message, &type);
898         if (r < 0) {
899                 log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
900                 return 0;
901         } else if (!IN_SET(type, RTM_NEWRULE, RTM_DELRULE)) {
902                 log_warning("rtnl: received unexpected message type %u when processing rule, ignoring.", type);
903                 return 0;
904         }
905 
906         r = routing_policy_rule_new(&tmp);
907         if (r < 0) {
908                 log_oom();
909                 return 0;
910         }
911 
912         r = sd_rtnl_message_get_family(message, &tmp->family);
913         if (r < 0) {
914                 log_warning_errno(r, "rtnl: could not get rule family, ignoring: %m");
915                 return 0;
916         } else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
917                 log_debug("rtnl: received rule message with invalid family %d, ignoring.", tmp->family);
918                 return 0;
919         }
920 
921         r = netlink_message_read_in_addr_union(message, FRA_SRC, tmp->family, &tmp->from);
922         if (r < 0 && r != -ENODATA) {
923                 log_warning_errno(r, "rtnl: could not get FRA_SRC attribute, ignoring: %m");
924                 return 0;
925         } else if (r >= 0) {
926                 r = sd_rtnl_message_routing_policy_rule_get_fib_src_prefixlen(message, &tmp->from_prefixlen);
927                 if (r < 0) {
928                         log_warning_errno(r, "rtnl: received rule message without valid source prefix length, ignoring: %m");
929                         return 0;
930                 }
931         }
932 
933         r = netlink_message_read_in_addr_union(message, FRA_DST, tmp->family, &tmp->to);
934         if (r < 0 && r != -ENODATA) {
935                 log_warning_errno(r, "rtnl: could not get FRA_DST attribute, ignoring: %m");
936                 return 0;
937         } else if (r >= 0) {
938                 r = sd_rtnl_message_routing_policy_rule_get_fib_dst_prefixlen(message, &tmp->to_prefixlen);
939                 if (r < 0) {
940                         log_warning_errno(r, "rtnl: received rule message without valid destination prefix length, ignoring: %m");
941                         return 0;
942                 }
943         }
944 
945         unsigned flags;
946         r = sd_rtnl_message_routing_policy_rule_get_flags(message, &flags);
947         if (r < 0) {
948                 log_warning_errno(r, "rtnl: received rule message without valid flag, ignoring: %m");
949                 return 0;
950         }
951         tmp->invert_rule = flags & FIB_RULE_INVERT;
952 
953         r = sd_netlink_message_read_u32(message, FRA_FWMARK, &tmp->fwmark);
954         if (r < 0 && r != -ENODATA) {
955                 log_warning_errno(r, "rtnl: could not get FRA_FWMARK attribute, ignoring: %m");
956                 return 0;
957         }
958 
959         r = sd_netlink_message_read_u32(message, FRA_FWMASK, &tmp->fwmask);
960         if (r < 0 && r != -ENODATA) {
961                 log_warning_errno(r, "rtnl: could not get FRA_FWMASK attribute, ignoring: %m");
962                 return 0;
963         }
964 
965         r = sd_netlink_message_read_u32(message, FRA_PRIORITY, &tmp->priority);
966         if (r < 0 && r != -ENODATA) {
967                 log_warning_errno(r, "rtnl: could not get FRA_PRIORITY attribute, ignoring: %m");
968                 return 0;
969         }
970         /* The kernel does not send priority if priority is zero. So, the flag below must be always set
971          * even if the message does not contain FRA_PRIORITY. */
972         tmp->priority_set = true;
973 
974         r = sd_netlink_message_read_u32(message, FRA_TABLE, &tmp->table);
975         if (r < 0 && r != -ENODATA) {
976                 log_warning_errno(r, "rtnl: could not get FRA_TABLE attribute, ignoring: %m");
977                 return 0;
978         }
979 
980         r = sd_rtnl_message_routing_policy_rule_get_tos(message, &tmp->tos);
981         if (r < 0 && r != -ENODATA) {
982                 log_warning_errno(r, "rtnl: could not get FIB rule TOS, ignoring: %m");
983                 return 0;
984         }
985 
986         r = sd_rtnl_message_routing_policy_rule_get_fib_type(message, &tmp->type);
987         if (r < 0 && r != -ENODATA) {
988                 log_warning_errno(r, "rtnl: could not get FIB rule type, ignoring: %m");
989                 return 0;
990         }
991 
992         r = sd_netlink_message_read_string_strdup(message, FRA_IIFNAME, &tmp->iif);
993         if (r < 0 && r != -ENODATA) {
994                 log_warning_errno(r, "rtnl: could not get FRA_IIFNAME attribute, ignoring: %m");
995                 return 0;
996         }
997 
998         r = sd_netlink_message_read_string_strdup(message, FRA_OIFNAME, &tmp->oif);
999         if (r < 0 && r != -ENODATA) {
1000                 log_warning_errno(r, "rtnl: could not get FRA_OIFNAME attribute, ignoring: %m");
1001                 return 0;
1002         }
1003 
1004         r = sd_netlink_message_read_u8(message, FRA_IP_PROTO, &tmp->ipproto);
1005         if (r < 0 && r != -ENODATA) {
1006                 log_warning_errno(r, "rtnl: could not get FRA_IP_PROTO attribute, ignoring: %m");
1007                 return 0;
1008         }
1009 
1010         r = sd_netlink_message_read_u8(message, FRA_PROTOCOL, &tmp->protocol);
1011         if (r == -ENODATA)
1012                 /* If FRA_PROTOCOL is supported by kernel, then the attribute is always appended.
1013                  * When the received message does not have FRA_PROTOCOL, then we need to adjust the
1014                  * protocol of the rule later. */
1015                 adjust_protocol = true;
1016         else if (r < 0) {
1017                 log_warning_errno(r, "rtnl: could not get FRA_PROTOCOL attribute, ignoring: %m");
1018                 return 0;
1019         }
1020 
1021         r = sd_netlink_message_read_u8(message, FRA_L3MDEV, &tmp->l3mdev);
1022         if (r < 0 && r != -ENODATA) {
1023                 log_warning_errno(r, "rtnl: could not get FRA_L3MDEV attribute, ignoring: %m");
1024                 return 0;
1025         }
1026 
1027         r = sd_netlink_message_read(message, FRA_SPORT_RANGE, sizeof(tmp->sport), &tmp->sport);
1028         if (r < 0 && r != -ENODATA) {
1029                 log_warning_errno(r, "rtnl: could not get FRA_SPORT_RANGE attribute, ignoring: %m");
1030                 return 0;
1031         }
1032 
1033         r = sd_netlink_message_read(message, FRA_DPORT_RANGE, sizeof(tmp->dport), &tmp->dport);
1034         if (r < 0 && r != -ENODATA) {
1035                 log_warning_errno(r, "rtnl: could not get FRA_DPORT_RANGE attribute, ignoring: %m");
1036                 return 0;
1037         }
1038 
1039         r = sd_netlink_message_read(message, FRA_UID_RANGE, sizeof(tmp->uid_range), &tmp->uid_range);
1040         if (r < 0 && r != -ENODATA) {
1041                 log_warning_errno(r, "rtnl: could not get FRA_UID_RANGE attribute, ignoring: %m");
1042                 return 0;
1043         }
1044 
1045         uint32_t suppress_prefixlen;
1046         r = sd_netlink_message_read_u32(message, FRA_SUPPRESS_PREFIXLEN, &suppress_prefixlen);
1047         if (r < 0 && r != -ENODATA) {
1048                 log_warning_errno(r, "rtnl: could not get FRA_SUPPRESS_PREFIXLEN attribute, ignoring: %m");
1049                 return 0;
1050         }
1051         if (r >= 0)
1052                 tmp->suppress_prefixlen = (int32_t) suppress_prefixlen;
1053 
1054         uint32_t suppress_ifgroup;
1055         r = sd_netlink_message_read_u32(message, FRA_SUPPRESS_IFGROUP, &suppress_ifgroup);
1056         if (r < 0 && r != -ENODATA) {
1057                 log_warning_errno(r, "rtnl: could not get FRA_SUPPRESS_IFGROUP attribute, ignoring: %m");
1058                 return 0;
1059         }
1060         if (r >= 0)
1061                 tmp->suppress_ifgroup = (int32_t) suppress_ifgroup;
1062 
1063         if (adjust_protocol)
1064                 /* As .network files does not have setting to specify protocol, we can assume the
1065                  * protocol of the received rule is RTPROT_KERNEL or RTPROT_STATIC. */
1066                 tmp->protocol = routing_policy_rule_is_created_by_kernel(tmp) ? RTPROT_KERNEL : RTPROT_STATIC;
1067 
1068         (void) routing_policy_rule_get(m, tmp, &rule);
1069 
1070         switch (type) {
1071         case RTM_NEWRULE:
1072                 if (rule) {
1073                         routing_policy_rule_enter_configured(rule);
1074                         log_routing_policy_rule_debug(rule, "Received remembered", NULL, m);
1075                 } else if (!m->manage_foreign_rules) {
1076                         routing_policy_rule_enter_configured(tmp);
1077                         log_routing_policy_rule_debug(tmp, "Ignoring received", NULL, m);
1078                 } else {
1079                         routing_policy_rule_enter_configured(tmp);
1080                         log_routing_policy_rule_debug(tmp, "Remembering", NULL, m);
1081                         r = routing_policy_rule_add(m, tmp);
1082                         if (r < 0) {
1083                                 log_warning_errno(r, "Could not remember foreign rule, ignoring: %m");
1084                                 return 0;
1085                         }
1086                         TAKE_PTR(tmp);
1087                 }
1088                 break;
1089         case RTM_DELRULE:
1090                 if (rule) {
1091                         routing_policy_rule_enter_removed(rule);
1092                         if (rule->state == 0) {
1093                                 log_routing_policy_rule_debug(rule, "Forgetting", NULL, m);
1094                                 routing_policy_rule_free(rule);
1095                         } else
1096                                 log_routing_policy_rule_debug(rule, "Removed", NULL, m);
1097                 } else
1098                         log_routing_policy_rule_debug(tmp, "Kernel removed unknown", NULL, m);
1099                 break;
1100 
1101         default:
1102                 assert_not_reached();
1103         }
1104 
1105         return 1;
1106 }
1107 
parse_fwmark_fwmask(const char * s,uint32_t * ret_fwmark,uint32_t * ret_fwmask)1108 static int parse_fwmark_fwmask(const char *s, uint32_t *ret_fwmark, uint32_t *ret_fwmask) {
1109         _cleanup_free_ char *fwmark_str = NULL;
1110         uint32_t fwmark, fwmask = 0;
1111         const char *slash;
1112         int r;
1113 
1114         assert(s);
1115         assert(ret_fwmark);
1116         assert(ret_fwmask);
1117 
1118         slash = strchr(s, '/');
1119         if (slash) {
1120                 fwmark_str = strndup(s, slash - s);
1121                 if (!fwmark_str)
1122                         return -ENOMEM;
1123         }
1124 
1125         r = safe_atou32(fwmark_str ?: s, &fwmark);
1126         if (r < 0)
1127                 return r;
1128 
1129         if (fwmark > 0) {
1130                 if (slash) {
1131                         r = safe_atou32(slash + 1, &fwmask);
1132                         if (r < 0)
1133                                 return r;
1134                 } else
1135                         fwmask = UINT32_MAX;
1136         }
1137 
1138         *ret_fwmark = fwmark;
1139         *ret_fwmask = fwmask;
1140 
1141         return 0;
1142 }
1143 
config_parse_routing_policy_rule_tos(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1144 int config_parse_routing_policy_rule_tos(
1145                 const char *unit,
1146                 const char *filename,
1147                 unsigned line,
1148                 const char *section,
1149                 unsigned section_line,
1150                 const char *lvalue,
1151                 int ltype,
1152                 const char *rvalue,
1153                 void *data,
1154                 void *userdata) {
1155 
1156         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1157         Network *network = userdata;
1158         int r;
1159 
1160         assert(filename);
1161         assert(section);
1162         assert(lvalue);
1163         assert(rvalue);
1164         assert(data);
1165 
1166         r = routing_policy_rule_new_static(network, filename, section_line, &n);
1167         if (r < 0)
1168                 return log_oom();
1169 
1170         r = safe_atou8(rvalue, &n->tos);
1171         if (r < 0) {
1172                 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule TOS, ignoring: %s", rvalue);
1173                 return 0;
1174         }
1175 
1176         TAKE_PTR(n);
1177         return 0;
1178 }
1179 
config_parse_routing_policy_rule_priority(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1180 int config_parse_routing_policy_rule_priority(
1181                 const char *unit,
1182                 const char *filename,
1183                 unsigned line,
1184                 const char *section,
1185                 unsigned section_line,
1186                 const char *lvalue,
1187                 int ltype,
1188                 const char *rvalue,
1189                 void *data,
1190                 void *userdata) {
1191 
1192         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1193         Network *network = userdata;
1194         int r;
1195 
1196         assert(filename);
1197         assert(section);
1198         assert(lvalue);
1199         assert(rvalue);
1200         assert(data);
1201 
1202         r = routing_policy_rule_new_static(network, filename, section_line, &n);
1203         if (r < 0)
1204                 return log_oom();
1205 
1206         if (isempty(rvalue)) {
1207                 n->priority = 0;
1208                 n->priority_set = false;
1209                 TAKE_PTR(n);
1210                 return 0;
1211         }
1212 
1213         r = safe_atou32(rvalue, &n->priority);
1214         if (r < 0) {
1215                 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule priority, ignoring: %s", rvalue);
1216                 return 0;
1217         }
1218         n->priority_set = true;
1219 
1220         TAKE_PTR(n);
1221         return 0;
1222 }
1223 
config_parse_routing_policy_rule_table(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1224 int config_parse_routing_policy_rule_table(
1225                 const char *unit,
1226                 const char *filename,
1227                 unsigned line,
1228                 const char *section,
1229                 unsigned section_line,
1230                 const char *lvalue,
1231                 int ltype,
1232                 const char *rvalue,
1233                 void *data,
1234                 void *userdata) {
1235 
1236         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1237         Network *network = userdata;
1238         int r;
1239 
1240         assert(filename);
1241         assert(section);
1242         assert(lvalue);
1243         assert(rvalue);
1244         assert(data);
1245 
1246         r = routing_policy_rule_new_static(network, filename, section_line, &n);
1247         if (r < 0)
1248                 return log_oom();
1249 
1250         r = manager_get_route_table_from_string(network->manager, rvalue, &n->table);
1251         if (r < 0) {
1252                 log_syntax(unit, LOG_WARNING, filename, line, r,
1253                            "Could not parse RPDB rule route table number \"%s\", ignoring assignment: %m", rvalue);
1254                 return 0;
1255         }
1256 
1257         TAKE_PTR(n);
1258         return 0;
1259 }
1260 
config_parse_routing_policy_rule_fwmark_mask(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1261 int config_parse_routing_policy_rule_fwmark_mask(
1262                 const char *unit,
1263                 const char *filename,
1264                 unsigned line,
1265                 const char *section,
1266                 unsigned section_line,
1267                 const char *lvalue,
1268                 int ltype,
1269                 const char *rvalue,
1270                 void *data,
1271                 void *userdata) {
1272 
1273         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1274         Network *network = userdata;
1275         int r;
1276 
1277         assert(filename);
1278         assert(section);
1279         assert(lvalue);
1280         assert(rvalue);
1281         assert(data);
1282 
1283         r = routing_policy_rule_new_static(network, filename, section_line, &n);
1284         if (r < 0)
1285                 return log_oom();
1286 
1287         r = parse_fwmark_fwmask(rvalue, &n->fwmark, &n->fwmask);
1288         if (r < 0) {
1289                 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue);
1290                 return 0;
1291         }
1292 
1293         TAKE_PTR(n);
1294         return 0;
1295 }
1296 
config_parse_routing_policy_rule_prefix(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1297 int config_parse_routing_policy_rule_prefix(
1298                 const char *unit,
1299                 const char *filename,
1300                 unsigned line,
1301                 const char *section,
1302                 unsigned section_line,
1303                 const char *lvalue,
1304                 int ltype,
1305                 const char *rvalue,
1306                 void *data,
1307                 void *userdata) {
1308 
1309         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1310         Network *network = userdata;
1311         union in_addr_union *buffer;
1312         uint8_t *prefixlen;
1313         int r;
1314 
1315         assert(filename);
1316         assert(section);
1317         assert(lvalue);
1318         assert(rvalue);
1319         assert(data);
1320 
1321         r = routing_policy_rule_new_static(network, filename, section_line, &n);
1322         if (r < 0)
1323                 return log_oom();
1324 
1325         if (streq(lvalue, "To")) {
1326                 buffer = &n->to;
1327                 prefixlen = &n->to_prefixlen;
1328         } else {
1329                 buffer = &n->from;
1330                 prefixlen = &n->from_prefixlen;
1331         }
1332 
1333         if (n->family == AF_UNSPEC)
1334                 r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
1335         else
1336                 r = in_addr_prefix_from_string(rvalue, n->family, buffer, prefixlen);
1337         if (r < 0) {
1338                 log_syntax(unit, LOG_WARNING, filename, line, r, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue);
1339                 return 0;
1340         }
1341 
1342         TAKE_PTR(n);
1343         return 0;
1344 }
1345 
config_parse_routing_policy_rule_device(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1346 int config_parse_routing_policy_rule_device(
1347                 const char *unit,
1348                 const char *filename,
1349                 unsigned line,
1350                 const char *section,
1351                 unsigned section_line,
1352                 const char *lvalue,
1353                 int ltype,
1354                 const char *rvalue,
1355                 void *data,
1356                 void *userdata) {
1357 
1358         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1359         Network *network = userdata;
1360         int r;
1361 
1362         assert(filename);
1363         assert(section);
1364         assert(lvalue);
1365         assert(rvalue);
1366         assert(data);
1367 
1368         r = routing_policy_rule_new_static(network, filename, section_line, &n);
1369         if (r < 0)
1370                 return log_oom();
1371 
1372         if (!ifname_valid(rvalue)) {
1373                 log_syntax(unit, LOG_WARNING, filename, line, 0,
1374                            "Invalid interface name '%s' in %s=, ignoring assignment.", rvalue, lvalue);
1375                 return 0;
1376         }
1377 
1378         r = free_and_strdup(streq(lvalue, "IncomingInterface") ? &n->iif : &n->oif, rvalue);
1379         if (r < 0)
1380                 return log_oom();
1381 
1382         TAKE_PTR(n);
1383         return 0;
1384 }
1385 
config_parse_routing_policy_rule_port_range(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1386 int config_parse_routing_policy_rule_port_range(
1387                 const char *unit,
1388                 const char *filename,
1389                 unsigned line,
1390                 const char *section,
1391                 unsigned section_line,
1392                 const char *lvalue,
1393                 int ltype,
1394                 const char *rvalue,
1395                 void *data,
1396                 void *userdata) {
1397 
1398         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1399         Network *network = userdata;
1400         uint16_t low, high;
1401         int r;
1402 
1403         assert(filename);
1404         assert(section);
1405         assert(lvalue);
1406         assert(rvalue);
1407         assert(data);
1408 
1409         r = routing_policy_rule_new_static(network, filename, section_line, &n);
1410         if (r < 0)
1411                 return log_oom();
1412 
1413         r = parse_ip_port_range(rvalue, &low, &high);
1414         if (r < 0) {
1415                 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse routing policy rule port range '%s'", rvalue);
1416                 return 0;
1417         }
1418 
1419         if (streq(lvalue, "SourcePort")) {
1420                 n->sport.start = low;
1421                 n->sport.end = high;
1422         } else {
1423                 n->dport.start = low;
1424                 n->dport.end = high;
1425         }
1426 
1427         TAKE_PTR(n);
1428         return 0;
1429 }
1430 
config_parse_routing_policy_rule_ip_protocol(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1431 int config_parse_routing_policy_rule_ip_protocol(
1432                 const char *unit,
1433                 const char *filename,
1434                 unsigned line,
1435                 const char *section,
1436                 unsigned section_line,
1437                 const char *lvalue,
1438                 int ltype,
1439                 const char *rvalue,
1440                 void *data,
1441                 void *userdata) {
1442 
1443         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1444         Network *network = userdata;
1445         int r;
1446 
1447         assert(filename);
1448         assert(section);
1449         assert(lvalue);
1450         assert(rvalue);
1451         assert(data);
1452 
1453         r = routing_policy_rule_new_static(network, filename, section_line, &n);
1454         if (r < 0)
1455                 return log_oom();
1456 
1457         r = parse_ip_protocol(rvalue);
1458         if (r < 0) {
1459                 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse IP protocol '%s' for routing policy rule, ignoring: %m", rvalue);
1460                 return 0;
1461         }
1462 
1463         n->ipproto = r;
1464 
1465         TAKE_PTR(n);
1466         return 0;
1467 }
1468 
config_parse_routing_policy_rule_invert(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1469 int config_parse_routing_policy_rule_invert(
1470                 const char *unit,
1471                 const char *filename,
1472                 unsigned line,
1473                 const char *section,
1474                 unsigned section_line,
1475                 const char *lvalue,
1476                 int ltype,
1477                 const char *rvalue,
1478                 void *data,
1479                 void *userdata) {
1480 
1481         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1482         Network *network = userdata;
1483         int r;
1484 
1485         assert(filename);
1486         assert(section);
1487         assert(lvalue);
1488         assert(rvalue);
1489         assert(data);
1490 
1491         r = routing_policy_rule_new_static(network, filename, section_line, &n);
1492         if (r < 0)
1493                 return log_oom();
1494 
1495         r = parse_boolean(rvalue);
1496         if (r < 0) {
1497                 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule invert, ignoring: %s", rvalue);
1498                 return 0;
1499         }
1500 
1501         n->invert_rule = r;
1502 
1503         TAKE_PTR(n);
1504         return 0;
1505 }
1506 
config_parse_routing_policy_rule_family(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1507 int config_parse_routing_policy_rule_family(
1508                 const char *unit,
1509                 const char *filename,
1510                 unsigned line,
1511                 const char *section,
1512                 unsigned section_line,
1513                 const char *lvalue,
1514                 int ltype,
1515                 const char *rvalue,
1516                 void *data,
1517                 void *userdata) {
1518 
1519         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1520         Network *network = userdata;
1521         AddressFamily a;
1522         int r;
1523 
1524         assert(filename);
1525         assert(section);
1526         assert(lvalue);
1527         assert(rvalue);
1528         assert(data);
1529 
1530         r = routing_policy_rule_new_static(network, filename, section_line, &n);
1531         if (r < 0)
1532                 return log_oom();
1533 
1534         a = routing_policy_rule_address_family_from_string(rvalue);
1535         if (a < 0) {
1536                 log_syntax(unit, LOG_WARNING, filename, line, a,
1537                            "Invalid address family '%s', ignoring.", rvalue);
1538                 return 0;
1539         }
1540 
1541         n->address_family = a;
1542 
1543         TAKE_PTR(n);
1544         return 0;
1545 }
1546 
config_parse_routing_policy_rule_uid_range(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1547 int config_parse_routing_policy_rule_uid_range(
1548                 const char *unit,
1549                 const char *filename,
1550                 unsigned line,
1551                 const char *section,
1552                 unsigned section_line,
1553                 const char *lvalue,
1554                 int ltype,
1555                 const char *rvalue,
1556                 void *data,
1557                 void *userdata) {
1558 
1559         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1560         Network *network = userdata;
1561         uid_t start, end;
1562         int r;
1563 
1564         assert(filename);
1565         assert(section);
1566         assert(lvalue);
1567         assert(rvalue);
1568         assert(data);
1569 
1570         r = routing_policy_rule_new_static(network, filename, section_line, &n);
1571         if (r < 0)
1572                 return log_oom();
1573 
1574         r = get_user_creds(&rvalue, &start, NULL, NULL, NULL, 0);
1575         if (r >= 0)
1576                 end = start;
1577         else {
1578                 r = parse_uid_range(rvalue, &start, &end);
1579                 if (r < 0) {
1580                         log_syntax(unit, LOG_WARNING, filename, line, r,
1581                                    "Invalid uid or uid range '%s', ignoring: %m", rvalue);
1582                         return 0;
1583                 }
1584         }
1585 
1586         n->uid_range.start = start;
1587         n->uid_range.end = end;
1588 
1589         TAKE_PTR(n);
1590         return 0;
1591 }
1592 
config_parse_routing_policy_rule_suppress_prefixlen(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1593 int config_parse_routing_policy_rule_suppress_prefixlen(
1594                 const char *unit,
1595                 const char *filename,
1596                 unsigned line,
1597                 const char *section,
1598                 unsigned section_line,
1599                 const char *lvalue,
1600                 int ltype,
1601                 const char *rvalue,
1602                 void *data,
1603                 void *userdata) {
1604 
1605         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1606         Network *network = userdata;
1607         int r;
1608 
1609         assert(filename);
1610         assert(section);
1611         assert(lvalue);
1612         assert(rvalue);
1613         assert(data);
1614 
1615         r = routing_policy_rule_new_static(network, filename, section_line, &n);
1616         if (r < 0)
1617                 return log_oom();
1618 
1619         r = parse_ip_prefix_length(rvalue, &n->suppress_prefixlen);
1620         if (r == -ERANGE) {
1621                 log_syntax(unit, LOG_WARNING, filename, line, r, "Prefix length outside of valid range 0-128, ignoring: %s", rvalue);
1622                 return 0;
1623         }
1624         if (r < 0) {
1625                 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule suppress_prefixlen, ignoring: %s", rvalue);
1626                 return 0;
1627         }
1628 
1629         TAKE_PTR(n);
1630         return 0;
1631 }
1632 
config_parse_routing_policy_rule_suppress_ifgroup(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1633 int config_parse_routing_policy_rule_suppress_ifgroup(
1634                 const char *unit,
1635                 const char *filename,
1636                 unsigned line,
1637                 const char *section,
1638                 unsigned section_line,
1639                 const char *lvalue,
1640                 int ltype,
1641                 const char *rvalue,
1642                 void *data,
1643                 void *userdata) {
1644 
1645         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1646         Network *network = userdata;
1647         int32_t suppress_ifgroup;
1648         int r;
1649 
1650         assert(filename);
1651         assert(section);
1652         assert(lvalue);
1653         assert(rvalue);
1654         assert(data);
1655 
1656         r = routing_policy_rule_new_static(network, filename, section_line, &n);
1657         if (r < 0)
1658                 return log_oom();
1659 
1660         if (isempty(rvalue)) {
1661                 n->suppress_ifgroup = -1;
1662                 return 0;
1663         }
1664 
1665         r = safe_atoi32(rvalue, &suppress_ifgroup);
1666         if (r < 0) {
1667                 log_syntax(unit, LOG_WARNING, filename, line, r,
1668                            "Failed to parse SuppressInterfaceGroup=, ignoring assignment: %s", rvalue);
1669                 return 0;
1670         }
1671         if (suppress_ifgroup < 0) {
1672                 log_syntax(unit, LOG_WARNING, filename, line, 0,
1673                            "Value of SuppressInterfaceGroup= must be in the range 0…2147483647, ignoring assignment: %s", rvalue);
1674                 return 0;
1675         }
1676         n->suppress_ifgroup = suppress_ifgroup;
1677         TAKE_PTR(n);
1678         return 0;
1679 }
1680 
config_parse_routing_policy_rule_type(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)1681 int config_parse_routing_policy_rule_type(
1682                 const char *unit,
1683                 const char *filename,
1684                 unsigned line,
1685                 const char *section,
1686                 unsigned section_line,
1687                 const char *lvalue,
1688                 int ltype,
1689                 const char *rvalue,
1690                 void *data,
1691                 void *userdata) {
1692 
1693         _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1694         Network *network = userdata;
1695         int r, t;
1696 
1697         assert(filename);
1698         assert(section);
1699         assert(lvalue);
1700         assert(rvalue);
1701         assert(data);
1702 
1703         r = routing_policy_rule_new_static(network, filename, section_line, &n);
1704         if (r < 0)
1705                 return log_oom();
1706 
1707         t = fr_act_type_from_string(rvalue);
1708         if (t < 0) {
1709                 log_syntax(unit, LOG_WARNING, filename, line, t,
1710                            "Could not parse FIB rule type \"%s\", ignoring assignment: %m", rvalue);
1711                 return 0;
1712         }
1713 
1714         n->type = (uint8_t) t;
1715 
1716         TAKE_PTR(n);
1717         return 0;
1718 }
1719 
routing_policy_rule_section_verify(RoutingPolicyRule * rule)1720 static int routing_policy_rule_section_verify(RoutingPolicyRule *rule) {
1721         if (section_is_invalid(rule->section))
1722                 return -EINVAL;
1723 
1724         if ((rule->family == AF_INET && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6)) ||
1725             (rule->family == AF_INET6 && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4)))
1726                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1727                                 "%s: address family specified by Family= conflicts with the address "
1728                                 "specified by To= or From=. Ignoring [RoutingPolicyRule] section from line %u.",
1729                                 rule->section->filename, rule->section->line);
1730 
1731         if (rule->family == AF_UNSPEC) {
1732                 if (IN_SET(rule->address_family, ADDRESS_FAMILY_IPV4, ADDRESS_FAMILY_NO))
1733                         rule->family = AF_INET;
1734                 else if (rule->address_family == ADDRESS_FAMILY_IPV6)
1735                         rule->family = AF_INET6;
1736                 /* rule->family can be AF_UNSPEC only when Family=both. */
1737         }
1738 
1739         /* Currently, [RoutingPolicyRule] does not have a setting to set FRA_L3MDEV flag. Please also
1740          * update routing_policy_rule_is_created_by_kernel() when a new setting which sets the flag is
1741          * added in the future. */
1742         if (rule->l3mdev > 0)
1743                 assert_not_reached();
1744 
1745         return 0;
1746 }
1747 
network_drop_invalid_routing_policy_rules(Network * network)1748 void network_drop_invalid_routing_policy_rules(Network *network) {
1749         RoutingPolicyRule *rule;
1750 
1751         assert(network);
1752 
1753         HASHMAP_FOREACH(rule, network->rules_by_section)
1754                 if (routing_policy_rule_section_verify(rule) < 0)
1755                         routing_policy_rule_free(rule);
1756 }
1757