1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <linux/icmpv6.h>
4 #include <linux/ipv6_route.h>
5 #include <linux/nexthop.h>
6 
7 #include "alloc-util.h"
8 #include "event-util.h"
9 #include "netlink-util.h"
10 #include "networkd-address.h"
11 #include "networkd-ipv4ll.h"
12 #include "networkd-manager.h"
13 #include "networkd-network.h"
14 #include "networkd-nexthop.h"
15 #include "networkd-queue.h"
16 #include "networkd-route-util.h"
17 #include "networkd-route.h"
18 #include "parse-util.h"
19 #include "string-util.h"
20 #include "strv.h"
21 #include "vrf.h"
22 #include "wireguard.h"
23 
route_new(Route ** ret)24 int route_new(Route **ret) {
25         _cleanup_(route_freep) Route *route = NULL;
26 
27         route = new(Route, 1);
28         if (!route)
29                 return -ENOMEM;
30 
31         *route = (Route) {
32                 .family = AF_UNSPEC,
33                 .scope = RT_SCOPE_UNIVERSE,
34                 .protocol = RTPROT_UNSPEC,
35                 .type = RTN_UNICAST,
36                 .table = RT_TABLE_MAIN,
37                 .lifetime_usec = USEC_INFINITY,
38                 .quickack = -1,
39                 .fast_open_no_cookie = -1,
40                 .gateway_onlink = -1,
41                 .ttl_propagate = -1,
42         };
43 
44         *ret = TAKE_PTR(route);
45 
46         return 0;
47 }
48 
route_new_static(Network * network,const char * filename,unsigned section_line,Route ** ret)49 static int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) {
50         _cleanup_(config_section_freep) ConfigSection *n = NULL;
51         _cleanup_(route_freep) Route *route = NULL;
52         int r;
53 
54         assert(network);
55         assert(ret);
56         assert(filename);
57         assert(section_line > 0);
58 
59         r = config_section_new(filename, section_line, &n);
60         if (r < 0)
61                 return r;
62 
63         route = hashmap_get(network->routes_by_section, n);
64         if (route) {
65                 *ret = TAKE_PTR(route);
66                 return 0;
67         }
68 
69         if (hashmap_size(network->routes_by_section) >= routes_max())
70                 return -E2BIG;
71 
72         r = route_new(&route);
73         if (r < 0)
74                 return r;
75 
76         route->protocol = RTPROT_STATIC;
77         route->network = network;
78         route->section = TAKE_PTR(n);
79         route->source = NETWORK_CONFIG_SOURCE_STATIC;
80 
81         r = hashmap_ensure_put(&network->routes_by_section, &config_section_hash_ops, route->section, route);
82         if (r < 0)
83                 return r;
84 
85         *ret = TAKE_PTR(route);
86         return 0;
87 }
88 
route_free(Route * route)89 Route *route_free(Route *route) {
90         if (!route)
91                 return NULL;
92 
93         if (route->network) {
94                 assert(route->section);
95                 hashmap_remove(route->network->routes_by_section, route->section);
96         }
97 
98         config_section_free(route->section);
99 
100         if (route->link)
101                 set_remove(route->link->routes, route);
102 
103         if (route->manager)
104                 set_remove(route->manager->routes, route);
105 
106         ordered_set_free_with_destructor(route->multipath_routes, multipath_route_free);
107 
108         sd_event_source_disable_unref(route->expire);
109 
110         return mfree(route);
111 }
112 
route_hash_func(const Route * route,struct siphash * state)113 static void route_hash_func(const Route *route, struct siphash *state) {
114         assert(route);
115 
116         siphash24_compress(&route->family, sizeof(route->family), state);
117 
118         switch (route->family) {
119         case AF_INET:
120         case AF_INET6:
121                 siphash24_compress(&route->dst_prefixlen, sizeof(route->dst_prefixlen), state);
122                 siphash24_compress(&route->dst, FAMILY_ADDRESS_SIZE(route->family), state);
123 
124                 siphash24_compress(&route->src_prefixlen, sizeof(route->src_prefixlen), state);
125                 siphash24_compress(&route->src, FAMILY_ADDRESS_SIZE(route->family), state);
126 
127                 siphash24_compress(&route->gw_family, sizeof(route->gw_family), state);
128                 if (IN_SET(route->gw_family, AF_INET, AF_INET6)) {
129                         siphash24_compress(&route->gw, FAMILY_ADDRESS_SIZE(route->gw_family), state);
130                         siphash24_compress(&route->gw_weight, sizeof(route->gw_weight), state);
131                 }
132 
133                 siphash24_compress(&route->prefsrc, FAMILY_ADDRESS_SIZE(route->family), state);
134 
135                 siphash24_compress(&route->tos, sizeof(route->tos), state);
136                 siphash24_compress(&route->priority, sizeof(route->priority), state);
137                 siphash24_compress(&route->table, sizeof(route->table), state);
138                 siphash24_compress(&route->protocol, sizeof(route->protocol), state);
139                 siphash24_compress(&route->scope, sizeof(route->scope), state);
140                 siphash24_compress(&route->type, sizeof(route->type), state);
141 
142                 siphash24_compress(&route->initcwnd, sizeof(route->initcwnd), state);
143                 siphash24_compress(&route->initrwnd, sizeof(route->initrwnd), state);
144 
145                 siphash24_compress(&route->advmss, sizeof(route->advmss), state);
146                 siphash24_compress(&route->nexthop_id, sizeof(route->nexthop_id), state);
147 
148                 break;
149         default:
150                 /* treat any other address family as AF_UNSPEC */
151                 break;
152         }
153 }
154 
route_compare_func(const Route * a,const Route * b)155 static int route_compare_func(const Route *a, const Route *b) {
156         int r;
157 
158         r = CMP(a->family, b->family);
159         if (r != 0)
160                 return r;
161 
162         switch (a->family) {
163         case AF_INET:
164         case AF_INET6:
165                 r = CMP(a->dst_prefixlen, b->dst_prefixlen);
166                 if (r != 0)
167                         return r;
168 
169                 r = memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
170                 if (r != 0)
171                         return r;
172 
173                 r = CMP(a->src_prefixlen, b->src_prefixlen);
174                 if (r != 0)
175                         return r;
176 
177                 r = memcmp(&a->src, &b->src, FAMILY_ADDRESS_SIZE(a->family));
178                 if (r != 0)
179                         return r;
180 
181                 r = CMP(a->gw_family, b->gw_family);
182                 if (r != 0)
183                         return r;
184 
185                 if (IN_SET(a->gw_family, AF_INET, AF_INET6)) {
186                         r = memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
187                         if (r != 0)
188                                 return r;
189 
190                         r = CMP(a->gw_weight, b->gw_weight);
191                         if (r != 0)
192                                 return r;
193                 }
194 
195                 r = memcmp(&a->prefsrc, &b->prefsrc, FAMILY_ADDRESS_SIZE(a->family));
196                 if (r != 0)
197                         return r;
198 
199                 r = CMP(a->tos, b->tos);
200                 if (r != 0)
201                         return r;
202 
203                 r = CMP(a->priority, b->priority);
204                 if (r != 0)
205                         return r;
206 
207                 r = CMP(a->table, b->table);
208                 if (r != 0)
209                         return r;
210 
211                 r = CMP(a->protocol, b->protocol);
212                 if (r != 0)
213                         return r;
214 
215                 r = CMP(a->scope, b->scope);
216                 if (r != 0)
217                         return r;
218 
219                 r = CMP(a->type, b->type);
220                 if (r != 0)
221                         return r;
222 
223                 r = CMP(a->initcwnd, b->initcwnd);
224                 if (r != 0)
225                         return r;
226 
227                 r = CMP(a->initrwnd, b->initrwnd);
228                 if (r != 0)
229                         return r;
230 
231                 r = CMP(a->advmss, b->advmss);
232                 if (r != 0)
233                         return r;
234 
235                 r = CMP(a->nexthop_id, b->nexthop_id);
236                 if (r != 0)
237                         return r;
238 
239                 return 0;
240         default:
241                 /* treat any other address family as AF_UNSPEC */
242                 return 0;
243         }
244 }
245 
246 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
247                 route_hash_ops,
248                 Route,
249                 route_hash_func,
250                 route_compare_func,
251                 route_free);
252 
route_type_is_reject(const Route * route)253 static bool route_type_is_reject(const Route *route) {
254         assert(route);
255 
256         return IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW);
257 }
258 
route_needs_convert(const Route * route)259 static bool route_needs_convert(const Route *route) {
260         assert(route);
261 
262         return route->nexthop_id > 0 || !ordered_set_isempty(route->multipath_routes);
263 }
264 
route_add(Manager * manager,Link * link,Route * route)265 static int route_add(Manager *manager, Link *link, Route *route) {
266         int r;
267 
268         assert(route);
269 
270         if (route_type_is_reject(route)) {
271                 assert(manager);
272 
273                 r = set_ensure_put(&manager->routes, &route_hash_ops, route);
274                 if (r < 0)
275                         return r;
276                 if (r == 0)
277                         return -EEXIST;
278 
279                 route->manager = manager;
280         } else {
281                 assert(link);
282 
283                 r = set_ensure_put(&link->routes, &route_hash_ops, route);
284                 if (r < 0)
285                         return r;
286                 if (r == 0)
287                         return -EEXIST;
288 
289                 route->link = link;
290         }
291 
292         return 0;
293 }
294 
route_get(Manager * manager,Link * link,const Route * in,Route ** ret)295 int route_get(Manager *manager, Link *link, const Route *in, Route **ret) {
296         Route *route;
297 
298         assert(in);
299 
300         if (route_type_is_reject(in)) {
301                 if (!manager)
302                         return -ENOENT;
303 
304                 route = set_get(manager->routes, in);
305         } else {
306                 if (!link)
307                         return -ENOENT;
308 
309                 route = set_get(link->routes, in);
310         }
311         if (!route)
312                 return -ENOENT;
313 
314         if (ret)
315                 *ret = route;
316 
317         return 0;
318 }
319 
route_dup(const Route * src,Route ** ret)320 int route_dup(const Route *src, Route **ret) {
321         _cleanup_(route_freep) Route *dest = NULL;
322 
323         /* This does not copy mulipath routes. */
324 
325         assert(src);
326         assert(ret);
327 
328         dest = newdup(Route, src, 1);
329         if (!dest)
330                 return -ENOMEM;
331 
332         /* Unset all pointers */
333         dest->network = NULL;
334         dest->section = NULL;
335         dest->link = NULL;
336         dest->manager = NULL;
337         dest->multipath_routes = NULL;
338         dest->expire = NULL;
339 
340         *ret = TAKE_PTR(dest);
341         return 0;
342 }
343 
route_apply_nexthop(Route * route,const NextHop * nh,uint8_t nh_weight)344 static void route_apply_nexthop(Route *route, const NextHop *nh, uint8_t nh_weight) {
345         assert(route);
346         assert(nh);
347         assert(hashmap_isempty(nh->group));
348 
349         route->gw_family = nh->family;
350         route->gw = nh->gw;
351 
352         if (nh_weight != UINT8_MAX)
353                 route->gw_weight = nh_weight;
354 
355         if (nh->blackhole)
356                 route->type = RTN_BLACKHOLE;
357 }
358 
route_apply_multipath_route(Route * route,const MultipathRoute * m)359 static void route_apply_multipath_route(Route *route, const MultipathRoute *m) {
360         assert(route);
361         assert(m);
362 
363         route->gw_family = m->gateway.family;
364         route->gw = m->gateway.address;
365         route->gw_weight = m->weight;
366 }
367 
multipath_route_get_link(Manager * manager,const MultipathRoute * m,Link ** ret)368 static int multipath_route_get_link(Manager *manager, const MultipathRoute *m, Link **ret) {
369         int r;
370 
371         assert(manager);
372         assert(m);
373 
374         if (m->ifname) {
375                 r = link_get_by_name(manager, m->ifname, ret);
376                 return r < 0 ? r : 1;
377 
378         } else if (m->ifindex > 0) { /* Always ignore ifindex if ifname is set. */
379                 r = link_get_by_index(manager, m->ifindex, ret);
380                 return r < 0 ? r : 1;
381         }
382 
383         if (ret)
384                 *ret = NULL;
385         return 0;
386 }
387 
388 typedef struct ConvertedRoutes {
389         size_t n;
390         Route **routes;
391         Link **links;
392 } ConvertedRoutes;
393 
converted_routes_free(ConvertedRoutes * c)394 static ConvertedRoutes *converted_routes_free(ConvertedRoutes *c) {
395         if (!c)
396                 return NULL;
397 
398         for (size_t i = 0; i < c->n; i++)
399                 route_free(c->routes[i]);
400 
401         free(c->routes);
402         free(c->links);
403 
404         return mfree(c);
405 }
406 
407 DEFINE_TRIVIAL_CLEANUP_FUNC(ConvertedRoutes*, converted_routes_free);
408 
converted_routes_new(size_t n,ConvertedRoutes ** ret)409 static int converted_routes_new(size_t n, ConvertedRoutes **ret) {
410         _cleanup_(converted_routes_freep) ConvertedRoutes *c = NULL;
411         _cleanup_free_ Route **routes = NULL;
412         _cleanup_free_ Link **links = NULL;
413 
414         assert(n > 0);
415         assert(ret);
416 
417         routes = new0(Route*, n);
418         if (!routes)
419                 return -ENOMEM;
420 
421         links = new0(Link*, n);
422         if (!links)
423                 return -ENOMEM;
424 
425         c = new(ConvertedRoutes, 1);
426         if (!c)
427                 return -ENOMEM;
428 
429         *c = (ConvertedRoutes) {
430                 .n = n,
431                 .routes = TAKE_PTR(routes),
432                 .links = TAKE_PTR(links),
433         };
434 
435         *ret = TAKE_PTR(c);
436         return 0;
437 }
438 
route_convert(Manager * manager,const Route * route,ConvertedRoutes ** ret)439 static int route_convert(Manager *manager, const Route *route, ConvertedRoutes **ret) {
440         _cleanup_(converted_routes_freep) ConvertedRoutes *c = NULL;
441         int r;
442 
443         assert(manager);
444         assert(route);
445         assert(ret);
446 
447         if (!route_needs_convert(route)) {
448                 *ret = NULL;
449                 return 0;
450         }
451 
452         if (route->nexthop_id > 0) {
453                 struct nexthop_grp *nhg;
454                 NextHop *nh;
455 
456                 r = manager_get_nexthop_by_id(manager, route->nexthop_id, &nh);
457                 if (r < 0)
458                         return r;
459 
460                 if (hashmap_isempty(nh->group)) {
461                         r = converted_routes_new(1, &c);
462                         if (r < 0)
463                                 return r;
464 
465                         r = route_dup(route, &c->routes[0]);
466                         if (r < 0)
467                                 return r;
468 
469                         route_apply_nexthop(c->routes[0], nh, UINT8_MAX);
470                         c->links[0] = nh->link;
471 
472                         *ret = TAKE_PTR(c);
473                         return 1;
474                 }
475 
476                 r = converted_routes_new(hashmap_size(nh->group), &c);
477                 if (r < 0)
478                         return r;
479 
480                 size_t i = 0;
481                 HASHMAP_FOREACH(nhg, nh->group) {
482                         NextHop *h;
483 
484                         r = manager_get_nexthop_by_id(manager, nhg->id, &h);
485                         if (r < 0)
486                                 return r;
487 
488                         r = route_dup(route, &c->routes[i]);
489                         if (r < 0)
490                                 return r;
491 
492                         route_apply_nexthop(c->routes[i], h, nhg->weight);
493                         c->links[i] = h->link;
494 
495                         i++;
496                 }
497 
498                 *ret = TAKE_PTR(c);
499                 return 1;
500 
501         }
502 
503         assert(!ordered_set_isempty(route->multipath_routes));
504 
505         r = converted_routes_new(ordered_set_size(route->multipath_routes), &c);
506         if (r < 0)
507                 return r;
508 
509         size_t i = 0;
510         MultipathRoute *m;
511         ORDERED_SET_FOREACH(m, route->multipath_routes) {
512                 r = route_dup(route, &c->routes[i]);
513                 if (r < 0)
514                         return r;
515 
516                 route_apply_multipath_route(c->routes[i], m);
517 
518                 r = multipath_route_get_link(manager, m, &c->links[i]);
519                 if (r < 0)
520                         return r;
521 
522                 i++;
523         }
524 
525         *ret = TAKE_PTR(c);
526         return 1;
527 }
528 
link_mark_routes(Link * link,NetworkConfigSource source,const struct in6_addr * router)529 void link_mark_routes(Link *link, NetworkConfigSource source, const struct in6_addr *router) {
530         Route *route;
531 
532         assert(link);
533 
534         SET_FOREACH(route, link->routes) {
535                 if (route->source != source)
536                         continue;
537 
538                 if (source == NETWORK_CONFIG_SOURCE_NDISC &&
539                     router && !in6_addr_equal(router, &route->provider.in6))
540                         continue;
541 
542                 route_mark(route);
543         }
544 }
545 
log_route_debug(const Route * route,const char * str,const Link * link,const Manager * manager)546 static void log_route_debug(const Route *route, const char *str, const Link *link, const Manager *manager) {
547         _cleanup_free_ char *state = NULL, *dst = NULL, *src = NULL, *gw_alloc = NULL, *prefsrc = NULL,
548                 *table = NULL, *scope = NULL, *proto = NULL, *flags = NULL;
549         const char *gw = NULL;
550 
551         assert(route);
552         assert(str);
553         assert(manager);
554 
555         /* link may be NULL. */
556 
557         if (!DEBUG_LOGGING)
558                 return;
559 
560         (void) network_config_state_to_string_alloc(route->state, &state);
561         if (in_addr_is_set(route->family, &route->dst) || route->dst_prefixlen > 0)
562                 (void) in_addr_prefix_to_string(route->family, &route->dst, route->dst_prefixlen, &dst);
563         if (in_addr_is_set(route->family, &route->src) || route->src_prefixlen > 0)
564                 (void) in_addr_prefix_to_string(route->family, &route->src, route->src_prefixlen, &src);
565         if (in_addr_is_set(route->gw_family, &route->gw)) {
566                 (void) in_addr_to_string(route->gw_family, &route->gw, &gw_alloc);
567                 gw = gw_alloc;
568         } else if (route->gateway_from_dhcp_or_ra) {
569                 if (route->gw_family == AF_INET)
570                         gw = "_dhcp4";
571                 else if (route->gw_family == AF_INET6)
572                         gw = "_ipv6ra";
573         } else {
574                 MultipathRoute *m;
575 
576                 ORDERED_SET_FOREACH(m, route->multipath_routes) {
577                         _cleanup_free_ char *buf = NULL;
578                         union in_addr_union a = m->gateway.address;
579 
580                         (void) in_addr_to_string(m->gateway.family, &a, &buf);
581                         (void) strextend_with_separator(&gw_alloc, ",", strna(buf));
582                         if (m->ifname)
583                                 (void) strextend(&gw_alloc, "@", m->ifname);
584                         else if (m->ifindex > 0)
585                                 (void) strextendf(&gw_alloc, "@%"PRIu32, m->ifindex);
586                         /* See comments in config_parse_multipath_route(). */
587                         (void) strextendf(&gw_alloc, ":%"PRIu32, m->weight + 1);
588                 }
589                 gw = gw_alloc;
590         }
591         if (in_addr_is_set(route->family, &route->prefsrc))
592                 (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
593         (void) route_scope_to_string_alloc(route->scope, &scope);
594         (void) manager_get_route_table_to_string(manager, route->table, &table);
595         (void) route_protocol_full_to_string_alloc(route->protocol, &proto);
596         (void) route_flags_to_string_alloc(route->flags, &flags);
597 
598         log_link_debug(link,
599                        "%s %s route (%s): dst: %s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, "
600                        "proto: %s, type: %s, nexthop: %"PRIu32", priority: %"PRIu32", flags: %s",
601                        str, strna(network_config_source_to_string(route->source)), strna(state),
602                        strna(dst), strna(src), strna(gw), strna(prefsrc),
603                        strna(scope), strna(table), strna(proto),
604                        strna(route_type_to_string(route->type)),
605                        route->nexthop_id, route->priority, strna(flags));
606 }
607 
route_set_netlink_message(const Route * route,sd_netlink_message * req,Link * link)608 static int route_set_netlink_message(const Route *route, sd_netlink_message *req, Link *link) {
609         int r;
610 
611         assert(route);
612         assert(req);
613 
614         /* link may be NULL */
615 
616         if (in_addr_is_set(route->gw_family, &route->gw) && route->nexthop_id == 0) {
617                 if (route->gw_family == route->family) {
618                         r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->gw_family, &route->gw);
619                         if (r < 0)
620                                 return r;
621                 } else {
622                         RouteVia rtvia = {
623                                 .family = route->gw_family,
624                                 .address = route->gw,
625                         };
626 
627                         r = sd_netlink_message_append_data(req, RTA_VIA, &rtvia, sizeof(rtvia));
628                         if (r < 0)
629                                 return r;
630                 }
631         }
632 
633         if (route->dst_prefixlen > 0) {
634                 r = netlink_message_append_in_addr_union(req, RTA_DST, route->family, &route->dst);
635                 if (r < 0)
636                         return r;
637 
638                 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
639                 if (r < 0)
640                         return r;
641         }
642 
643         if (route->src_prefixlen > 0) {
644                 r = netlink_message_append_in_addr_union(req, RTA_SRC, route->family, &route->src);
645                 if (r < 0)
646                         return r;
647 
648                 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
649                 if (r < 0)
650                         return r;
651         }
652 
653         if (in_addr_is_set(route->family, &route->prefsrc)) {
654                 r = netlink_message_append_in_addr_union(req, RTA_PREFSRC, route->family, &route->prefsrc);
655                 if (r < 0)
656                         return r;
657         }
658 
659         r = sd_rtnl_message_route_set_scope(req, route->scope);
660         if (r < 0)
661                 return r;
662 
663         r = sd_rtnl_message_route_set_flags(req, route->flags & RTNH_F_ONLINK);
664         if (r < 0)
665                 return r;
666 
667         if (route->table < 256) {
668                 r = sd_rtnl_message_route_set_table(req, route->table);
669                 if (r < 0)
670                         return r;
671         } else {
672                 r = sd_rtnl_message_route_set_table(req, RT_TABLE_UNSPEC);
673                 if (r < 0)
674                         return r;
675 
676                 /* Table attribute to allow more than 256. */
677                 r = sd_netlink_message_append_u32(req, RTA_TABLE, route->table);
678                 if (r < 0)
679                         return r;
680         }
681 
682         if (!route_type_is_reject(route) &&
683             route->nexthop_id == 0 &&
684             ordered_set_isempty(route->multipath_routes)) {
685                 assert(link); /* Those routes must be attached to a specific link */
686 
687                 r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
688                 if (r < 0)
689                         return r;
690         }
691 
692         if (route->nexthop_id > 0) {
693                 r = sd_netlink_message_append_u32(req, RTA_NH_ID, route->nexthop_id);
694                 if (r < 0)
695                         return r;
696         }
697 
698         r = sd_netlink_message_append_u8(req, RTA_PREF, route->pref);
699         if (r < 0)
700                 return r;
701 
702         r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
703         if (r < 0)
704                 return r;
705 
706         return 0;
707 }
708 
route_remove_handler(sd_netlink * rtnl,sd_netlink_message * m,Link * link)709 static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
710         int r;
711 
712         assert(m);
713 
714         /* link may be NULL. */
715 
716         if (link && IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
717                 return 0;
718 
719         r = sd_netlink_message_get_errno(m);
720         if (r < 0 && r != -ESRCH)
721                 log_link_message_warning_errno(link, m, r, "Could not drop route, ignoring");
722 
723         return 1;
724 }
725 
route_remove(Route * route)726 int route_remove(Route *route) {
727         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
728         unsigned char type;
729         Manager *manager;
730         Link *link;
731         int r;
732 
733         assert(route);
734         assert(route->manager || (route->link && route->link->manager));
735         assert(IN_SET(route->family, AF_INET, AF_INET6));
736 
737         link = route->link;
738         manager = route->manager ?: link->manager;
739 
740         log_route_debug(route, "Removing", link, manager);
741 
742         r = sd_rtnl_message_new_route(manager->rtnl, &req,
743                                       RTM_DELROUTE, route->family,
744                                       route->protocol);
745         if (r < 0)
746                 return log_link_error_errno(link, r, "Could not create netlink message: %m");
747 
748         if (route->family == AF_INET && route->nexthop_id > 0 && route->type == RTN_BLACKHOLE)
749                 /* When IPv4 route has nexthop id and the nexthop type is blackhole, even though kernel
750                  * sends RTM_NEWROUTE netlink message with blackhole type, kernel's internal route type
751                  * fib_rt_info::type may not be blackhole. Thus, we cannot know the internal value.
752                  * Moreover, on route removal, the matching is done with the hidden value if we set
753                  * non-zero type in RTM_DELROUTE message. Note, sd_rtnl_message_new_route() sets
754                  * RTN_UNICAST by default. So, we need to clear the type here. */
755                 type = RTN_UNSPEC;
756         else
757                 type = route->type;
758 
759         r = sd_rtnl_message_route_set_type(req, type);
760         if (r < 0)
761                 return log_link_error_errno(link, r, "Could not set route type: %m");
762 
763         r = route_set_netlink_message(route, req, link);
764         if (r < 0)
765                 return log_error_errno(r, "Could not fill netlink message: %m");
766 
767         r = netlink_call_async(manager->rtnl, NULL, req, route_remove_handler,
768                                link ? link_netlink_destroy_callback : NULL, link);
769         if (r < 0)
770                 return log_link_error_errno(link, r, "Could not send netlink message: %m");
771 
772         link_ref(link);
773 
774         route_enter_removing(route);
775         return 0;
776 }
777 
manager_mark_routes(Manager * manager,bool foreign,const Link * except)778 static void manager_mark_routes(Manager *manager, bool foreign, const Link *except) {
779         Route *route;
780         Link *link;
781         int r;
782 
783         assert(manager);
784 
785         /* First, mark all routes. */
786         SET_FOREACH(route, manager->routes) {
787                 /* Do not touch routes managed by the kernel. */
788                 if (route->protocol == RTPROT_KERNEL)
789                         continue;
790 
791                 /* When 'foreign' is true, mark only foreign routes, and vice versa. */
792                 if (foreign != (route->source == NETWORK_CONFIG_SOURCE_FOREIGN))
793                         continue;
794 
795                 /* Do not touch dynamic routes. They will removed by dhcp_pd_prefix_lost() */
796                 if (IN_SET(route->source, NETWORK_CONFIG_SOURCE_DHCP4, NETWORK_CONFIG_SOURCE_DHCP6))
797                         continue;
798 
799                 /* Ignore routes not assigned yet or already removed. */
800                 if (!route_exists(route))
801                         continue;
802 
803                 route_mark(route);
804         }
805 
806         /* Then, unmark all routes requested by active links. */
807         HASHMAP_FOREACH(link, manager->links_by_index) {
808                 if (link == except)
809                         continue;
810 
811                 if (!link->network)
812                         continue;
813 
814                 if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
815                         continue;
816 
817                 HASHMAP_FOREACH(route, link->network->routes_by_section) {
818                         _cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL;
819                         Route *existing;
820 
821                         r = route_convert(manager, route, &converted);
822                         if (r < 0)
823                                 continue;
824                         if (r == 0) {
825                                 if (route_get(manager, NULL, route, &existing) >= 0)
826                                         route_unmark(existing);
827                                 continue;
828                         }
829 
830                         for (size_t i = 0; i < converted->n; i++)
831                                 if (route_get(manager, NULL, converted->routes[i], &existing) >= 0)
832                                         route_unmark(existing);
833                 }
834         }
835 }
836 
manager_drop_marked_routes(Manager * manager)837 static int manager_drop_marked_routes(Manager *manager) {
838         Route *route;
839         int k, r = 0;
840 
841         assert(manager);
842 
843         SET_FOREACH(route, manager->routes) {
844                 if (!route_is_marked(route))
845                         continue;
846 
847                 k = route_remove(route);
848                 if (k < 0 && r >= 0)
849                         r = k;
850         }
851 
852         return r;
853 }
854 
route_by_kernel(const Route * route)855 static bool route_by_kernel(const Route *route) {
856         assert(route);
857 
858         if (route->protocol == RTPROT_KERNEL)
859                 return true;
860 
861         /* The kernels older than a826b04303a40d52439aa141035fca5654ccaccd (v5.11) create the IPv6
862          * multicast with RTPROT_BOOT. Do not touch it. */
863         if (route->protocol == RTPROT_BOOT &&
864             route->family == AF_INET6 &&
865             route->dst_prefixlen == 8 &&
866             in6_addr_equal(&route->dst.in6, & (struct in6_addr) {{{ 0xff,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }}}))
867                 return true;
868 
869         return false;
870 }
871 
link_unmark_wireguard_routes(Link * link)872 static void link_unmark_wireguard_routes(Link *link) {
873         Route *route, *existing;
874         Wireguard *w;
875 
876         assert(link);
877 
878         w = WIREGUARD(link->netdev);
879         if (!w)
880                 return;
881 
882         SET_FOREACH(route, w->routes)
883                 if (route_get(NULL, link, route, &existing) >= 0)
884                         route_unmark(existing);
885 }
886 
link_drop_foreign_routes(Link * link)887 int link_drop_foreign_routes(Link *link) {
888         Route *route;
889         int k, r;
890 
891         assert(link);
892         assert(link->manager);
893         assert(link->network);
894 
895         SET_FOREACH(route, link->routes) {
896                 /* do not touch routes managed by the kernel */
897                 if (route_by_kernel(route))
898                         continue;
899 
900                 /* Do not remove routes we configured. */
901                 if (route->source != NETWORK_CONFIG_SOURCE_FOREIGN)
902                         continue;
903 
904                 /* Ignore routes not assigned yet or already removed. */
905                 if (!route_exists(route))
906                         continue;
907 
908                 if (route->protocol == RTPROT_STATIC &&
909                     FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
910                         continue;
911 
912                 if (route->protocol == RTPROT_DHCP &&
913                     FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
914                         continue;
915 
916                 route_mark(route);
917         }
918 
919         HASHMAP_FOREACH(route, link->network->routes_by_section) {
920                 _cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL;
921                 Route *existing;
922 
923                 r = route_convert(link->manager, route, &converted);
924                 if (r < 0)
925                         continue;
926                 if (r == 0) {
927                         if (route_get(NULL, link, route, &existing) >= 0)
928                                 route_unmark(existing);
929                         continue;
930                 }
931 
932                 for (size_t i = 0; i < converted->n; i++)
933                         if (route_get(NULL, link, converted->routes[i], &existing) >= 0)
934                                 route_unmark(existing);
935         }
936 
937         link_unmark_wireguard_routes(link);
938 
939         r = 0;
940         SET_FOREACH(route, link->routes) {
941                 if (!route_is_marked(route))
942                         continue;
943 
944                 k = route_remove(route);
945                 if (k < 0 && r >= 0)
946                         r = k;
947         }
948 
949         manager_mark_routes(link->manager, /* foreign = */ true, NULL);
950 
951         k = manager_drop_marked_routes(link->manager);
952         if (k < 0 && r >= 0)
953                 r = k;
954 
955         return r;
956 }
957 
link_drop_managed_routes(Link * link)958 int link_drop_managed_routes(Link *link) {
959         Route *route;
960         int k, r = 0;
961 
962         assert(link);
963 
964         SET_FOREACH(route, link->routes) {
965                 /* do not touch routes managed by the kernel */
966                 if (route_by_kernel(route))
967                         continue;
968 
969                 /* Do not touch routes managed by kernel or other tools. */
970                 if (route->source == NETWORK_CONFIG_SOURCE_FOREIGN)
971                         continue;
972 
973                 if (!route_exists(route))
974                         continue;
975 
976                 k = route_remove(route);
977                 if (k < 0 && r >= 0)
978                         r = k;
979         }
980 
981         manager_mark_routes(link->manager, /* foreign = */ false, link);
982 
983         k = manager_drop_marked_routes(link->manager);
984         if (k < 0 && r >= 0)
985                 r = k;
986 
987         return r;
988 }
989 
link_foreignize_routes(Link * link)990 void link_foreignize_routes(Link *link) {
991         Route *route;
992 
993         assert(link);
994 
995         SET_FOREACH(route, link->routes)
996                 route->source = NETWORK_CONFIG_SOURCE_FOREIGN;
997 
998         manager_mark_routes(link->manager, /* foreign = */ false, link);
999 
1000         SET_FOREACH(route, link->manager->routes) {
1001                 if (!route_is_marked(route))
1002                         continue;
1003 
1004                 route->source = NETWORK_CONFIG_SOURCE_FOREIGN;
1005         }
1006 }
1007 
route_expire_handler(sd_event_source * s,uint64_t usec,void * userdata)1008 static int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
1009         Route *route = userdata;
1010         Link *link;
1011         int r;
1012 
1013         assert(route);
1014         assert(route->manager || (route->link && route->link->manager));
1015 
1016         link = route->link; /* This may be NULL. */
1017 
1018         r = route_remove(route);
1019         if (r < 0) {
1020                 log_link_warning_errno(link, r, "Could not remove route: %m");
1021                 if (link)
1022                         link_enter_failed(link);
1023         }
1024 
1025         return 1;
1026 }
1027 
route_setup_timer(Route * route,const struct rta_cacheinfo * cacheinfo)1028 static int route_setup_timer(Route *route, const struct rta_cacheinfo *cacheinfo) {
1029         Manager *manager;
1030         int r;
1031 
1032         assert(route);
1033         assert(route->manager || (route->link && route->link->manager));
1034 
1035         manager = route->manager ?: route->link->manager;
1036 
1037         if (route->lifetime_usec == USEC_INFINITY)
1038                 return 0;
1039 
1040         if (cacheinfo && cacheinfo->rta_expires != 0)
1041                 /* Assume that non-zero rta_expires means kernel will handle the route expiration. */
1042                 return 0;
1043 
1044         r = event_reset_time(manager->event, &route->expire, CLOCK_BOOTTIME,
1045                              route->lifetime_usec, 0, route_expire_handler, route, 0, "route-expiration", true);
1046         if (r < 0)
1047                 return r;
1048 
1049         return 1;
1050 }
1051 
append_nexthop_one(const Link * link,const Route * route,const MultipathRoute * m,struct rtattr ** rta,size_t offset)1052 static int append_nexthop_one(const Link *link, const Route *route, const MultipathRoute *m, struct rtattr **rta, size_t offset) {
1053         struct rtnexthop *rtnh;
1054         struct rtattr *new_rta;
1055         int r;
1056 
1057         assert(route);
1058         assert(m);
1059         assert(rta);
1060         assert(*rta);
1061 
1062         new_rta = realloc(*rta, RTA_ALIGN((*rta)->rta_len) + RTA_SPACE(sizeof(struct rtnexthop)));
1063         if (!new_rta)
1064                 return -ENOMEM;
1065         *rta = new_rta;
1066 
1067         rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
1068         *rtnh = (struct rtnexthop) {
1069                 .rtnh_len = sizeof(*rtnh),
1070                 .rtnh_ifindex = m->ifindex > 0 ? m->ifindex : link->ifindex,
1071                 .rtnh_hops = m->weight,
1072         };
1073 
1074         (*rta)->rta_len += sizeof(struct rtnexthop);
1075 
1076         if (route->family == m->gateway.family) {
1077                 r = rtattr_append_attribute(rta, RTA_GATEWAY, &m->gateway.address, FAMILY_ADDRESS_SIZE(m->gateway.family));
1078                 if (r < 0)
1079                         goto clear;
1080                 rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
1081                 rtnh->rtnh_len += RTA_SPACE(FAMILY_ADDRESS_SIZE(m->gateway.family));
1082         } else {
1083                 r = rtattr_append_attribute(rta, RTA_VIA, &m->gateway, FAMILY_ADDRESS_SIZE(m->gateway.family) + sizeof(m->gateway.family));
1084                 if (r < 0)
1085                         goto clear;
1086                 rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
1087                 rtnh->rtnh_len += RTA_SPACE(FAMILY_ADDRESS_SIZE(m->gateway.family) + sizeof(m->gateway.family));
1088         }
1089 
1090         return 0;
1091 
1092 clear:
1093         (*rta)->rta_len -= sizeof(struct rtnexthop);
1094         return r;
1095 }
1096 
append_nexthops(const Link * link,const Route * route,sd_netlink_message * req)1097 static int append_nexthops(const Link *link, const Route *route, sd_netlink_message *req) {
1098         _cleanup_free_ struct rtattr *rta = NULL;
1099         struct rtnexthop *rtnh;
1100         MultipathRoute *m;
1101         size_t offset;
1102         int r;
1103 
1104         assert(link);
1105         assert(route);
1106         assert(req);
1107 
1108         if (ordered_set_isempty(route->multipath_routes))
1109                 return 0;
1110 
1111         rta = new(struct rtattr, 1);
1112         if (!rta)
1113                 return -ENOMEM;
1114 
1115         *rta = (struct rtattr) {
1116                 .rta_type = RTA_MULTIPATH,
1117                 .rta_len = RTA_LENGTH(0),
1118         };
1119         offset = (uint8_t *) RTA_DATA(rta) - (uint8_t *) rta;
1120 
1121         ORDERED_SET_FOREACH(m, route->multipath_routes) {
1122                 r = append_nexthop_one(link, route, m, &rta, offset);
1123                 if (r < 0)
1124                         return r;
1125 
1126                 rtnh = (struct rtnexthop *)((uint8_t *) rta + offset);
1127                 offset = (uint8_t *) RTNH_NEXT(rtnh) - (uint8_t *) rta;
1128         }
1129 
1130         r = sd_netlink_message_append_data(req, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
1131         if (r < 0)
1132                 return r;
1133 
1134         return 0;
1135 }
1136 
route_configure_handler_internal(sd_netlink * rtnl,sd_netlink_message * m,Link * link,const char * error_msg)1137 int route_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg) {
1138         int r;
1139 
1140         assert(m);
1141         assert(link);
1142         assert(error_msg);
1143 
1144         r = sd_netlink_message_get_errno(m);
1145         if (r < 0 && r != -EEXIST) {
1146                 log_link_message_warning_errno(link, m, r, "Could not set route");
1147                 link_enter_failed(link);
1148                 return 0;
1149         }
1150 
1151         return 1;
1152 }
1153 
route_configure(const Route * route,Link * link,Request * req)1154 static int route_configure(const Route *route, Link *link, Request *req) {
1155         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
1156         int r;
1157 
1158         assert(route);
1159         assert(IN_SET(route->family, AF_INET, AF_INET6));
1160         assert(link);
1161         assert(link->manager);
1162         assert(link->manager->rtnl);
1163         assert(link->ifindex > 0);
1164         assert(req);
1165 
1166         log_route_debug(route, "Configuring", link, link->manager);
1167 
1168         r = sd_rtnl_message_new_route(link->manager->rtnl, &m, RTM_NEWROUTE, route->family, route->protocol);
1169         if (r < 0)
1170                 return r;
1171 
1172         r = sd_rtnl_message_route_set_type(m, route->type);
1173         if (r < 0)
1174                 return r;
1175 
1176         r = route_set_netlink_message(route, m, link);
1177         if (r < 0)
1178                 return r;
1179 
1180         if (route->lifetime_usec != USEC_INFINITY) {
1181                 r = sd_netlink_message_append_u32(m, RTA_EXPIRES,
1182                         MIN(DIV_ROUND_UP(usec_sub_unsigned(route->lifetime_usec, now(CLOCK_BOOTTIME)), USEC_PER_SEC), UINT32_MAX));
1183                 if (r < 0)
1184                         return r;
1185         }
1186 
1187         if (route->ttl_propagate >= 0) {
1188                 r = sd_netlink_message_append_u8(m, RTA_TTL_PROPAGATE, route->ttl_propagate);
1189                 if (r < 0)
1190                         return r;
1191         }
1192 
1193         r = sd_netlink_message_open_container(m, RTA_METRICS);
1194         if (r < 0)
1195                 return r;
1196 
1197         if (route->mtu > 0) {
1198                 r = sd_netlink_message_append_u32(m, RTAX_MTU, route->mtu);
1199                 if (r < 0)
1200                         return r;
1201         }
1202 
1203         if (route->initcwnd > 0) {
1204                 r = sd_netlink_message_append_u32(m, RTAX_INITCWND, route->initcwnd);
1205                 if (r < 0)
1206                         return r;
1207         }
1208 
1209         if (route->initrwnd > 0) {
1210                 r = sd_netlink_message_append_u32(m, RTAX_INITRWND, route->initrwnd);
1211                 if (r < 0)
1212                         return r;
1213         }
1214 
1215         if (route->quickack >= 0) {
1216                 r = sd_netlink_message_append_u32(m, RTAX_QUICKACK, route->quickack);
1217                 if (r < 0)
1218                         return r;
1219         }
1220 
1221         if (route->fast_open_no_cookie >= 0) {
1222                 r = sd_netlink_message_append_u32(m, RTAX_FASTOPEN_NO_COOKIE, route->fast_open_no_cookie);
1223                 if (r < 0)
1224                         return r;
1225         }
1226 
1227         if (route->advmss > 0) {
1228                 r = sd_netlink_message_append_u32(m, RTAX_ADVMSS, route->advmss);
1229                 if (r < 0)
1230                         return r;
1231         }
1232 
1233         r = sd_netlink_message_close_container(m);
1234         if (r < 0)
1235                 return r;
1236 
1237         if (!ordered_set_isempty(route->multipath_routes)) {
1238                 assert(route->nexthop_id == 0);
1239                 assert(!in_addr_is_set(route->gw_family, &route->gw));
1240 
1241                 r = append_nexthops(link, route, m);
1242                 if (r < 0)
1243                         return r;
1244         }
1245 
1246         return request_call_netlink_async(link->manager->rtnl, m, req);
1247 }
1248 
route_is_ready_to_configure(const Route * route,Link * link)1249 static int route_is_ready_to_configure(const Route *route, Link *link) {
1250         int r;
1251 
1252         assert(route);
1253         assert(link);
1254 
1255         if (!link_is_ready_to_configure(link, false))
1256                 return false;
1257 
1258         if (set_size(link->routes) >= routes_max())
1259                 return false;
1260 
1261         if (route->nexthop_id > 0) {
1262                 struct nexthop_grp *nhg;
1263                 NextHop *nh;
1264 
1265                 if (manager_get_nexthop_by_id(link->manager, route->nexthop_id, &nh) < 0)
1266                         return false;
1267 
1268                 if (!nexthop_exists(nh))
1269                         return false;
1270 
1271                 HASHMAP_FOREACH(nhg, nh->group) {
1272                         NextHop *g;
1273 
1274                         if (manager_get_nexthop_by_id(link->manager, nhg->id, &g) < 0)
1275                                 return false;
1276 
1277                         if (!nexthop_exists(g))
1278                                 return false;
1279                 }
1280         }
1281 
1282         if (in_addr_is_set(route->family, &route->prefsrc) > 0) {
1283                 r = manager_has_address(link->manager, route->family, &route->prefsrc, route->family == AF_INET6);
1284                 if (r <= 0)
1285                         return r;
1286         }
1287 
1288         if (!gateway_is_ready(link, FLAGS_SET(route->flags, RTNH_F_ONLINK), route->gw_family, &route->gw))
1289                 return false;
1290 
1291         MultipathRoute *m;
1292         ORDERED_SET_FOREACH(m, route->multipath_routes) {
1293                 union in_addr_union a = m->gateway.address;
1294                 Link *l = NULL;
1295 
1296                 r = multipath_route_get_link(link->manager, m, &l);
1297                 if (r < 0)
1298                         return false;
1299                 if (r > 0) {
1300                         if (!link_is_ready_to_configure(l, true))
1301                                 return false;
1302 
1303                         m->ifindex = l->ifindex;
1304                 }
1305 
1306                 if (!gateway_is_ready(l ?: link, FLAGS_SET(route->flags, RTNH_F_ONLINK), m->gateway.family, &a))
1307                         return false;
1308         }
1309 
1310         return true;
1311 }
1312 
route_process_request(Request * req,Link * link,Route * route)1313 static int route_process_request(Request *req, Link *link, Route *route) {
1314         _cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL;
1315         int r;
1316 
1317         assert(req);
1318         assert(link);
1319         assert(route);
1320 
1321         r = route_is_ready_to_configure(route, link);
1322         if (r < 0)
1323                 return log_link_warning_errno(link, r, "Failed to check if route is ready to configure: %m");
1324         if (r == 0)
1325                 return 0;
1326 
1327         if (route_needs_convert(route)) {
1328                 r = route_convert(link->manager, route, &converted);
1329                 if (r < 0)
1330                         return log_link_warning_errno(link, r, "Failed to convert route: %m");
1331 
1332                 assert(r > 0);
1333                 assert(converted);
1334 
1335                 for (size_t i = 0; i < converted->n; i++) {
1336                         Route *existing;
1337 
1338                         if (route_get(link->manager, converted->links[i] ?: link, converted->routes[i], &existing) < 0) {
1339                                 _cleanup_(route_freep) Route *tmp = NULL;
1340 
1341                                 r = route_dup(converted->routes[i], &tmp);
1342                                 if (r < 0)
1343                                         return log_oom();
1344 
1345                                 r = route_add(link->manager, converted->links[i] ?: link, tmp);
1346                                 if (r < 0)
1347                                         return log_link_warning_errno(link, r, "Failed to add route: %m");
1348 
1349                                 TAKE_PTR(tmp);
1350                         } else {
1351                                 existing->source = converted->routes[i]->source;
1352                                 existing->provider = converted->routes[i]->provider;
1353                         }
1354                 }
1355         }
1356 
1357         r = route_configure(route, link, req);
1358         if (r < 0)
1359                 return log_link_warning_errno(link, r, "Failed to configure route: %m");
1360 
1361         if (converted)
1362                 for (size_t i = 0; i < converted->n; i++) {
1363                         Route *existing;
1364 
1365                         assert_se(route_get(link->manager, converted->links[i] ?: link, converted->routes[i], &existing) >= 0);
1366                         route_enter_configuring(existing);
1367                 }
1368         else
1369                 route_enter_configuring(route);
1370 
1371         return 1;
1372 }
1373 
link_request_route(Link * link,Route * route,bool consume_object,unsigned * message_counter,route_netlink_handler_t netlink_handler,Request ** ret)1374 int link_request_route(
1375                 Link *link,
1376                 Route *route,
1377                 bool consume_object,
1378                 unsigned *message_counter,
1379                 route_netlink_handler_t netlink_handler,
1380                 Request **ret) {
1381 
1382         Route *existing;
1383         int r;
1384 
1385         assert(link);
1386         assert(link->manager);
1387         assert(route);
1388         assert(route->source != NETWORK_CONFIG_SOURCE_FOREIGN);
1389         assert(!route_needs_convert(route));
1390 
1391         if (route_get(link->manager, link, route, &existing) < 0) {
1392                 _cleanup_(route_freep) Route *tmp = NULL;
1393 
1394                 if (consume_object)
1395                         tmp = route;
1396                 else {
1397                         r = route_dup(route, &tmp);
1398                         if (r < 0)
1399                                 return r;
1400                 }
1401 
1402                 r = route_add(link->manager, link, tmp);
1403                 if (r < 0)
1404                         return r;
1405 
1406                 existing = TAKE_PTR(tmp);
1407         } else {
1408                 existing->source = route->source;
1409                 existing->provider = route->provider;
1410                 existing->lifetime_usec = route->lifetime_usec;
1411                 if (consume_object)
1412                         route_free(route);
1413 
1414                 if (existing->expire) {
1415                         /* When re-configuring an existing route, kernel does not send RTM_NEWROUTE
1416                          * message, so we need to update the timer here. */
1417                         r = route_setup_timer(existing, NULL);
1418                         if (r < 0)
1419                                 log_link_warning_errno(link, r, "Failed to update expiration timer for route, ignoring: %m");
1420                         if (r > 0)
1421                                 log_route_debug(existing, "Updated expiration timer for", link, link->manager);
1422                 }
1423         }
1424 
1425         log_route_debug(existing, "Requesting", link, link->manager);
1426         r = link_queue_request_safe(link, REQUEST_TYPE_ROUTE,
1427                                     existing, NULL,
1428                                     route_hash_func,
1429                                     route_compare_func,
1430                                     route_process_request,
1431                                     message_counter, netlink_handler, ret);
1432         if (r <= 0)
1433                 return r;
1434 
1435         route_enter_requesting(existing);
1436         return 1;
1437 }
1438 
static_route_handler(sd_netlink * rtnl,sd_netlink_message * m,Request * req,Link * link,Route * route)1439 static int static_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
1440         int r;
1441 
1442         assert(link);
1443 
1444         r = route_configure_handler_internal(rtnl, m, link, "Could not set route");
1445         if (r <= 0)
1446                 return r;
1447 
1448         if (link->static_route_messages == 0) {
1449                 log_link_debug(link, "Routes set");
1450                 link->static_routes_configured = true;
1451                 link_check_ready(link);
1452         }
1453 
1454         return 1;
1455 }
1456 
link_request_static_route(Link * link,Route * route)1457 static int link_request_static_route(Link *link, Route *route) {
1458         assert(link);
1459         assert(link->manager);
1460         assert(route);
1461 
1462         if (!route_needs_convert(route))
1463                 return link_request_route(link, route, false, &link->static_route_messages,
1464                                           static_route_handler, NULL);
1465 
1466         log_route_debug(route, "Requesting", link, link->manager);
1467         return link_queue_request_safe(link, REQUEST_TYPE_ROUTE,
1468                                        route, NULL, route_hash_func, route_compare_func,
1469                                        route_process_request,
1470                                        &link->static_route_messages, static_route_handler, NULL);
1471 }
1472 
link_request_wireguard_routes(Link * link,bool only_ipv4)1473 static int link_request_wireguard_routes(Link *link, bool only_ipv4) {
1474         NetDev *netdev;
1475         Wireguard *w;
1476         Route *route;
1477         int r;
1478 
1479         assert(link);
1480 
1481         if (!streq_ptr(link->kind, "wireguard"))
1482                 return 0;
1483 
1484         if (netdev_get(link->manager, link->ifname, &netdev) < 0)
1485                 return 0;
1486 
1487         w = WIREGUARD(netdev);
1488         if (!w)
1489                 return 0;
1490 
1491         SET_FOREACH(route, w->routes) {
1492                 if (only_ipv4 && route->family != AF_INET)
1493                         continue;
1494 
1495                 r = link_request_static_route(link, route);
1496                 if (r < 0)
1497                         return r;
1498         }
1499 
1500         return 0;
1501 }
1502 
link_request_static_routes(Link * link,bool only_ipv4)1503 int link_request_static_routes(Link *link, bool only_ipv4) {
1504         Route *route;
1505         int r;
1506 
1507         assert(link);
1508         assert(link->network);
1509 
1510         link->static_routes_configured = false;
1511 
1512         HASHMAP_FOREACH(route, link->network->routes_by_section) {
1513                 if (route->gateway_from_dhcp_or_ra)
1514                         continue;
1515 
1516                 if (only_ipv4 && route->family != AF_INET)
1517                         continue;
1518 
1519                 r = link_request_static_route(link, route);
1520                 if (r < 0)
1521                         return r;
1522         }
1523 
1524         r = link_request_wireguard_routes(link, only_ipv4);
1525         if (r < 0)
1526                 return r;
1527 
1528         if (link->static_route_messages == 0) {
1529                 link->static_routes_configured = true;
1530                 link_check_ready(link);
1531         } else {
1532                 log_link_debug(link, "Requesting routes");
1533                 link_set_state(link, LINK_STATE_CONFIGURING);
1534         }
1535 
1536         return 0;
1537 }
1538 
route_cancel_request(Route * route,Link * link)1539 void route_cancel_request(Route *route, Link *link) {
1540         Request req;
1541 
1542         assert(route);
1543 
1544         link = route->link ?: link;
1545 
1546         assert(link);
1547 
1548         if (!route_is_requesting(route))
1549                 return;
1550 
1551         req = (Request) {
1552                 .link = link,
1553                 .type = REQUEST_TYPE_ROUTE,
1554                 .userdata = route,
1555                 .hash_func = (hash_func_t) route_hash_func,
1556                 .compare_func = (compare_func_t) route_compare_func,
1557         };
1558 
1559         request_detach(link->manager, &req);
1560         route_cancel_requesting(route);
1561 }
1562 
process_route_one(Manager * manager,Link * link,uint16_t type,Route * in,const struct rta_cacheinfo * cacheinfo)1563 static int process_route_one(
1564                 Manager *manager,
1565                 Link *link,
1566                 uint16_t type,
1567                 Route *in,
1568                 const struct rta_cacheinfo *cacheinfo) {
1569 
1570         _cleanup_(route_freep) Route *tmp = in;
1571         Route *route = NULL;
1572         int r;
1573 
1574         assert(manager);
1575         assert(tmp);
1576         assert(IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE));
1577 
1578         /* link may be NULL. This consumes 'in'. */
1579 
1580         (void) route_get(manager, link, tmp, &route);
1581 
1582         switch (type) {
1583         case RTM_NEWROUTE:
1584                 if (route) {
1585                         route->flags = tmp->flags;
1586                         route_enter_configured(route);
1587                         log_route_debug(route, "Received remembered", link, manager);
1588 
1589                         r = route_setup_timer(route, cacheinfo);
1590                         if (r < 0)
1591                                 log_link_warning_errno(link, r, "Failed to configure expiration timer for route, ignoring: %m");
1592                         if (r > 0)
1593                                 log_route_debug(route, "Configured expiration timer for", link, manager);
1594 
1595                 } else if (!manager->manage_foreign_routes) {
1596                         route_enter_configured(tmp);
1597                         log_route_debug(tmp, "Ignoring received", link, manager);
1598 
1599                 } else {
1600                         /* A route appeared that we did not request */
1601                         route_enter_configured(tmp);
1602                         log_route_debug(tmp, "Received new", link, manager);
1603                         r = route_add(manager, link, tmp);
1604                         if (r < 0) {
1605                                 log_link_warning_errno(link, r, "Failed to remember foreign route, ignoring: %m");
1606                                 return 0;
1607                         }
1608                         TAKE_PTR(tmp);
1609                 }
1610 
1611                 break;
1612 
1613         case RTM_DELROUTE:
1614                 if (route) {
1615                         route_enter_removed(route);
1616                         if (route->state == 0) {
1617                                 log_route_debug(route, "Forgetting", link, manager);
1618                                 route_free(route);
1619                         } else
1620                                 log_route_debug(route, "Removed", link, manager);
1621                 } else
1622                         log_route_debug(tmp,
1623                                         manager->manage_foreign_routes ? "Kernel removed unknown" : "Ignoring received",
1624                                         link, manager);
1625 
1626                 break;
1627 
1628         default:
1629                 assert_not_reached();
1630         }
1631 
1632         return 1;
1633 }
1634 
manager_rtnl_process_route(sd_netlink * rtnl,sd_netlink_message * message,Manager * m)1635 int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
1636         _cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL;
1637         _cleanup_(route_freep) Route *tmp = NULL;
1638         _cleanup_free_ void *rta_multipath = NULL;
1639         struct rta_cacheinfo cacheinfo;
1640         bool has_cacheinfo;
1641         Link *link = NULL;
1642         uint32_t ifindex;
1643         uint16_t type;
1644         size_t rta_len;
1645         int r;
1646 
1647         assert(rtnl);
1648         assert(message);
1649         assert(m);
1650 
1651         if (sd_netlink_message_is_error(message)) {
1652                 r = sd_netlink_message_get_errno(message);
1653                 if (r < 0)
1654                         log_message_warning_errno(message, r, "rtnl: failed to receive route message, ignoring");
1655 
1656                 return 0;
1657         }
1658 
1659         r = sd_netlink_message_get_type(message, &type);
1660         if (r < 0) {
1661                 log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
1662                 return 0;
1663         } else if (!IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE)) {
1664                 log_warning("rtnl: received unexpected message type %u when processing route, ignoring.", type);
1665                 return 0;
1666         }
1667 
1668         r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex);
1669         if (r < 0 && r != -ENODATA) {
1670                 log_warning_errno(r, "rtnl: could not get ifindex from route message, ignoring: %m");
1671                 return 0;
1672         } else if (r >= 0) {
1673                 if (ifindex <= 0) {
1674                         log_warning("rtnl: received route message with invalid ifindex %d, ignoring.", ifindex);
1675                         return 0;
1676                 }
1677 
1678                 r = link_get_by_index(m, ifindex, &link);
1679                 if (r < 0 || !link) {
1680                         /* when enumerating we might be out of sync, but we will
1681                          * get the route again, so just ignore it */
1682                         if (!m->enumerating)
1683                                 log_warning("rtnl: received route message for link (%d) we do not know about, ignoring", ifindex);
1684                         return 0;
1685                 }
1686         }
1687 
1688         r = route_new(&tmp);
1689         if (r < 0)
1690                 return log_oom();
1691 
1692         r = sd_rtnl_message_route_get_family(message, &tmp->family);
1693         if (r < 0) {
1694                 log_link_warning(link, "rtnl: received route message without family, ignoring");
1695                 return 0;
1696         } else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
1697                 log_link_debug(link, "rtnl: received route message with invalid family '%i', ignoring", tmp->family);
1698                 return 0;
1699         }
1700 
1701         r = sd_rtnl_message_route_get_protocol(message, &tmp->protocol);
1702         if (r < 0) {
1703                 log_warning_errno(r, "rtnl: received route message without route protocol, ignoring: %m");
1704                 return 0;
1705         }
1706 
1707         r = sd_rtnl_message_route_get_flags(message, &tmp->flags);
1708         if (r < 0) {
1709                 log_warning_errno(r, "rtnl: received route message without route flags, ignoring: %m");
1710                 return 0;
1711         }
1712 
1713         r = netlink_message_read_in_addr_union(message, RTA_DST, tmp->family, &tmp->dst);
1714         if (r < 0 && r != -ENODATA) {
1715                 log_link_warning_errno(link, r, "rtnl: received route message without valid destination, ignoring: %m");
1716                 return 0;
1717         }
1718 
1719         r = netlink_message_read_in_addr_union(message, RTA_GATEWAY, tmp->family, &tmp->gw);
1720         if (r < 0 && r != -ENODATA) {
1721                 log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
1722                 return 0;
1723         } else if (r >= 0)
1724                 tmp->gw_family = tmp->family;
1725         else if (tmp->family == AF_INET) {
1726                 RouteVia via;
1727 
1728                 r = sd_netlink_message_read(message, RTA_VIA, sizeof(via), &via);
1729                 if (r < 0 && r != -ENODATA) {
1730                         log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
1731                         return 0;
1732                 } else if (r >= 0) {
1733                         tmp->gw_family = via.family;
1734                         tmp->gw = via.address;
1735                 }
1736         }
1737 
1738         r = netlink_message_read_in_addr_union(message, RTA_SRC, tmp->family, &tmp->src);
1739         if (r < 0 && r != -ENODATA) {
1740                 log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m");
1741                 return 0;
1742         }
1743 
1744         r = netlink_message_read_in_addr_union(message, RTA_PREFSRC, tmp->family, &tmp->prefsrc);
1745         if (r < 0 && r != -ENODATA) {
1746                 log_link_warning_errno(link, r, "rtnl: received route message without valid preferred source, ignoring: %m");
1747                 return 0;
1748         }
1749 
1750         r = sd_rtnl_message_route_get_dst_prefixlen(message, &tmp->dst_prefixlen);
1751         if (r < 0) {
1752                 log_link_warning_errno(link, r, "rtnl: received route message with invalid destination prefixlen, ignoring: %m");
1753                 return 0;
1754         }
1755 
1756         r = sd_rtnl_message_route_get_src_prefixlen(message, &tmp->src_prefixlen);
1757         if (r < 0) {
1758                 log_link_warning_errno(link, r, "rtnl: received route message with invalid source prefixlen, ignoring: %m");
1759                 return 0;
1760         }
1761 
1762         r = sd_rtnl_message_route_get_scope(message, &tmp->scope);
1763         if (r < 0) {
1764                 log_link_warning_errno(link, r, "rtnl: received route message with invalid scope, ignoring: %m");
1765                 return 0;
1766         }
1767 
1768         r = sd_rtnl_message_route_get_tos(message, &tmp->tos);
1769         if (r < 0) {
1770                 log_link_warning_errno(link, r, "rtnl: received route message with invalid tos, ignoring: %m");
1771                 return 0;
1772         }
1773 
1774         r = sd_rtnl_message_route_get_type(message, &tmp->type);
1775         if (r < 0) {
1776                 log_link_warning_errno(link, r, "rtnl: received route message with invalid type, ignoring: %m");
1777                 return 0;
1778         }
1779 
1780         r = sd_netlink_message_read_u32(message, RTA_TABLE, &tmp->table);
1781         if (r == -ENODATA) {
1782                 unsigned char table;
1783 
1784                 r = sd_rtnl_message_route_get_table(message, &table);
1785                 if (r >= 0)
1786                         tmp->table = table;
1787         }
1788         if (r < 0) {
1789                 log_link_warning_errno(link, r, "rtnl: received route message with invalid table, ignoring: %m");
1790                 return 0;
1791         }
1792 
1793         r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &tmp->priority);
1794         if (r < 0 && r != -ENODATA) {
1795                 log_link_warning_errno(link, r, "rtnl: received route message with invalid priority, ignoring: %m");
1796                 return 0;
1797         }
1798 
1799         r = sd_netlink_message_read_u32(message, RTA_NH_ID, &tmp->nexthop_id);
1800         if (r < 0 && r != -ENODATA) {
1801                 log_link_warning_errno(link, r, "rtnl: received route message with invalid nexthop id, ignoring: %m");
1802                 return 0;
1803         }
1804 
1805         r = sd_netlink_message_enter_container(message, RTA_METRICS);
1806         if (r < 0 && r != -ENODATA) {
1807                 log_link_error_errno(link, r, "rtnl: Could not enter RTA_METRICS container, ignoring: %m");
1808                 return 0;
1809         }
1810         if (r >= 0) {
1811                 r = sd_netlink_message_read_u32(message, RTAX_INITCWND, &tmp->initcwnd);
1812                 if (r < 0 && r != -ENODATA) {
1813                         log_link_warning_errno(link, r, "rtnl: received route message with invalid initcwnd, ignoring: %m");
1814                         return 0;
1815                 }
1816 
1817                 r = sd_netlink_message_read_u32(message, RTAX_INITRWND, &tmp->initrwnd);
1818                 if (r < 0 && r != -ENODATA) {
1819                         log_link_warning_errno(link, r, "rtnl: received route message with invalid initrwnd, ignoring: %m");
1820                         return 0;
1821                 }
1822 
1823                 r = sd_netlink_message_read_u32(message, RTAX_ADVMSS, &tmp->advmss);
1824                 if (r < 0 && r != -ENODATA) {
1825                         log_link_warning_errno(link, r, "rtnl: received route message with invalid advmss, ignoring: %m");
1826                         return 0;
1827                 }
1828 
1829                 r = sd_netlink_message_exit_container(message);
1830                 if (r < 0) {
1831                         log_link_error_errno(link, r, "rtnl: Could not exit from RTA_METRICS container, ignoring: %m");
1832                         return 0;
1833                 }
1834         }
1835 
1836         r = sd_netlink_message_read_data(message, RTA_MULTIPATH, &rta_len, &rta_multipath);
1837         if (r < 0 && r != -ENODATA) {
1838                 log_link_warning_errno(link, r, "rtnl: failed to read RTA_MULTIPATH attribute, ignoring: %m");
1839                 return 0;
1840         } else if (r >= 0) {
1841                 r = rtattr_read_nexthop(rta_multipath, rta_len, tmp->family, &tmp->multipath_routes);
1842                 if (r < 0) {
1843                         log_link_warning_errno(link, r, "rtnl: failed to parse RTA_MULTIPATH attribute, ignoring: %m");
1844                         return 0;
1845                 }
1846         }
1847 
1848         r = sd_netlink_message_read(message, RTA_CACHEINFO, sizeof(cacheinfo), &cacheinfo);
1849         if (r < 0 && r != -ENODATA) {
1850                 log_link_warning_errno(link, r, "rtnl: failed to read RTA_CACHEINFO attribute, ignoring: %m");
1851                 return 0;
1852         }
1853         has_cacheinfo = r >= 0;
1854 
1855         /* IPv6 routes with reject type are always assigned to the loopback interface. See kernel's
1856          * fib6_nh_init() in net/ipv6/route.c. However, we'd like to manage them by Manager. Hence, set
1857          * link to NULL here. */
1858         if (route_type_is_reject(tmp))
1859                 link = NULL;
1860 
1861         if (!route_needs_convert(tmp))
1862                 return process_route_one(m, link, type, TAKE_PTR(tmp), has_cacheinfo ? &cacheinfo : NULL);
1863 
1864         r = route_convert(m, tmp, &converted);
1865         if (r < 0) {
1866                 log_link_warning_errno(link, r, "rtnl: failed to convert received route, ignoring: %m");
1867                 return 0;
1868         }
1869 
1870         assert(r > 0);
1871         assert(converted);
1872 
1873         for (size_t i = 0; i < converted->n; i++)
1874                 (void) process_route_one(m,
1875                                          converted->links[i] ?: link,
1876                                          type,
1877                                          TAKE_PTR(converted->routes[i]),
1878                                          has_cacheinfo ? &cacheinfo : NULL);
1879 
1880         return 1;
1881 }
1882 
network_add_ipv4ll_route(Network * network)1883 int network_add_ipv4ll_route(Network *network) {
1884         _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1885         unsigned section_line;
1886         int r;
1887 
1888         assert(network);
1889 
1890         if (!network->ipv4ll_route)
1891                 return 0;
1892 
1893         section_line = hashmap_find_free_section_line(network->routes_by_section);
1894 
1895         /* IPv4LLRoute= is in [Network] section. */
1896         r = route_new_static(network, network->filename, section_line, &n);
1897         if (r < 0)
1898                 return r;
1899 
1900         r = in_addr_from_string(AF_INET, "169.254.0.0", &n->dst);
1901         if (r < 0)
1902                 return r;
1903 
1904         n->family = AF_INET;
1905         n->dst_prefixlen = 16;
1906         n->scope = RT_SCOPE_LINK;
1907         n->scope_set = true;
1908         n->table_set = true;
1909         n->priority = IPV4LL_ROUTE_METRIC;
1910         n->protocol = RTPROT_STATIC;
1911 
1912         TAKE_PTR(n);
1913         return 0;
1914 }
1915 
network_add_default_route_on_device(Network * network)1916 int network_add_default_route_on_device(Network *network) {
1917         _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1918         unsigned section_line;
1919         int r;
1920 
1921         assert(network);
1922 
1923         if (!network->default_route_on_device)
1924                 return 0;
1925 
1926         section_line = hashmap_find_free_section_line(network->routes_by_section);
1927 
1928         /* DefaultRouteOnDevice= is in [Network] section. */
1929         r = route_new_static(network, network->filename, section_line, &n);
1930         if (r < 0)
1931                 return r;
1932 
1933         n->family = AF_INET;
1934         n->scope = RT_SCOPE_LINK;
1935         n->scope_set = true;
1936         n->protocol = RTPROT_STATIC;
1937 
1938         TAKE_PTR(n);
1939         return 0;
1940 }
1941 
config_parse_gateway(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)1942 int config_parse_gateway(
1943                 const char *unit,
1944                 const char *filename,
1945                 unsigned line,
1946                 const char *section,
1947                 unsigned section_line,
1948                 const char *lvalue,
1949                 int ltype,
1950                 const char *rvalue,
1951                 void *data,
1952                 void *userdata) {
1953 
1954         Network *network = userdata;
1955         _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1956         int r;
1957 
1958         assert(filename);
1959         assert(section);
1960         assert(lvalue);
1961         assert(rvalue);
1962         assert(data);
1963 
1964         if (streq(section, "Network")) {
1965                 /* we are not in an Route section, so use line number instead */
1966                 r = route_new_static(network, filename, line, &n);
1967                 if (r == -ENOMEM)
1968                         return log_oom();
1969                 if (r < 0) {
1970                         log_syntax(unit, LOG_WARNING, filename, line, r,
1971                                    "Failed to allocate route, ignoring assignment: %m");
1972                         return 0;
1973                 }
1974         } else {
1975                 r = route_new_static(network, filename, section_line, &n);
1976                 if (r == -ENOMEM)
1977                         return log_oom();
1978                 if (r < 0) {
1979                         log_syntax(unit, LOG_WARNING, filename, line, r,
1980                                    "Failed to allocate route, ignoring assignment: %m");
1981                         return 0;
1982                 }
1983 
1984                 if (isempty(rvalue)) {
1985                         n->gateway_from_dhcp_or_ra = false;
1986                         n->gw_family = AF_UNSPEC;
1987                         n->gw = IN_ADDR_NULL;
1988                         TAKE_PTR(n);
1989                         return 0;
1990                 }
1991 
1992                 if (streq(rvalue, "_dhcp")) {
1993                         n->gateway_from_dhcp_or_ra = true;
1994                         TAKE_PTR(n);
1995                         return 0;
1996                 }
1997 
1998                 if (streq(rvalue, "_dhcp4")) {
1999                         n->gw_family = AF_INET;
2000                         n->gateway_from_dhcp_or_ra = true;
2001                         TAKE_PTR(n);
2002                         return 0;
2003                 }
2004 
2005                 if (streq(rvalue, "_ipv6ra")) {
2006                         n->gw_family = AF_INET6;
2007                         n->gateway_from_dhcp_or_ra = true;
2008                         TAKE_PTR(n);
2009                         return 0;
2010                 }
2011         }
2012 
2013         r = in_addr_from_string_auto(rvalue, &n->gw_family, &n->gw);
2014         if (r < 0) {
2015                 log_syntax(unit, LOG_WARNING, filename, line, r,
2016                            "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
2017                 return 0;
2018         }
2019 
2020         n->gateway_from_dhcp_or_ra = false;
2021         TAKE_PTR(n);
2022         return 0;
2023 }
2024 
config_parse_preferred_src(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)2025 int config_parse_preferred_src(
2026                 const char *unit,
2027                 const char *filename,
2028                 unsigned line,
2029                 const char *section,
2030                 unsigned section_line,
2031                 const char *lvalue,
2032                 int ltype,
2033                 const char *rvalue,
2034                 void *data,
2035                 void *userdata) {
2036 
2037         Network *network = userdata;
2038         _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2039         int r;
2040 
2041         assert(filename);
2042         assert(section);
2043         assert(lvalue);
2044         assert(rvalue);
2045         assert(data);
2046 
2047         r = route_new_static(network, filename, section_line, &n);
2048         if (r == -ENOMEM)
2049                 return log_oom();
2050         if (r < 0) {
2051                 log_syntax(unit, LOG_WARNING, filename, line, r,
2052                            "Failed to allocate route, ignoring assignment: %m");
2053                 return 0;
2054         }
2055 
2056         if (n->family == AF_UNSPEC)
2057                 r = in_addr_from_string_auto(rvalue, &n->family, &n->prefsrc);
2058         else
2059                 r = in_addr_from_string(n->family, rvalue, &n->prefsrc);
2060         if (r < 0) {
2061                 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
2062                            "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
2063                 return 0;
2064         }
2065 
2066         TAKE_PTR(n);
2067         return 0;
2068 }
2069 
config_parse_destination(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)2070 int config_parse_destination(
2071                 const char *unit,
2072                 const char *filename,
2073                 unsigned line,
2074                 const char *section,
2075                 unsigned section_line,
2076                 const char *lvalue,
2077                 int ltype,
2078                 const char *rvalue,
2079                 void *data,
2080                 void *userdata) {
2081 
2082         Network *network = userdata;
2083         _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2084         union in_addr_union *buffer;
2085         unsigned char *prefixlen;
2086         int r;
2087 
2088         assert(filename);
2089         assert(section);
2090         assert(lvalue);
2091         assert(rvalue);
2092         assert(data);
2093 
2094         r = route_new_static(network, filename, section_line, &n);
2095         if (r == -ENOMEM)
2096                 return log_oom();
2097         if (r < 0) {
2098                 log_syntax(unit, LOG_WARNING, filename, line, r,
2099                            "Failed to allocate route, ignoring assignment: %m");
2100                 return 0;
2101         }
2102 
2103         if (streq(lvalue, "Destination")) {
2104                 buffer = &n->dst;
2105                 prefixlen = &n->dst_prefixlen;
2106         } else if (streq(lvalue, "Source")) {
2107                 buffer = &n->src;
2108                 prefixlen = &n->src_prefixlen;
2109         } else
2110                 assert_not_reached();
2111 
2112         if (n->family == AF_UNSPEC)
2113                 r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
2114         else
2115                 r = in_addr_prefix_from_string(rvalue, n->family, buffer, prefixlen);
2116         if (r < 0) {
2117                 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
2118                            "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
2119                 return 0;
2120         }
2121 
2122         (void) in_addr_mask(n->family, buffer, *prefixlen);
2123 
2124         TAKE_PTR(n);
2125         return 0;
2126 }
2127 
config_parse_route_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)2128 int config_parse_route_priority(
2129                 const char *unit,
2130                 const char *filename,
2131                 unsigned line,
2132                 const char *section,
2133                 unsigned section_line,
2134                 const char *lvalue,
2135                 int ltype,
2136                 const char *rvalue,
2137                 void *data,
2138                 void *userdata) {
2139 
2140         Network *network = userdata;
2141         _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2142         int r;
2143 
2144         assert(filename);
2145         assert(section);
2146         assert(lvalue);
2147         assert(rvalue);
2148         assert(data);
2149 
2150         r = route_new_static(network, filename, section_line, &n);
2151         if (r == -ENOMEM)
2152                 return log_oom();
2153         if (r < 0) {
2154                 log_syntax(unit, LOG_WARNING, filename, line, r,
2155                            "Failed to allocate route, ignoring assignment: %m");
2156                 return 0;
2157         }
2158 
2159         r = safe_atou32(rvalue, &n->priority);
2160         if (r < 0) {
2161                 log_syntax(unit, LOG_WARNING, filename, line, r,
2162                            "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue);
2163                 return 0;
2164         }
2165 
2166         n->priority_set = true;
2167         TAKE_PTR(n);
2168         return 0;
2169 }
2170 
config_parse_route_scope(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)2171 int config_parse_route_scope(
2172                 const char *unit,
2173                 const char *filename,
2174                 unsigned line,
2175                 const char *section,
2176                 unsigned section_line,
2177                 const char *lvalue,
2178                 int ltype,
2179                 const char *rvalue,
2180                 void *data,
2181                 void *userdata) {
2182 
2183         Network *network = userdata;
2184         _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2185         int r;
2186 
2187         assert(filename);
2188         assert(section);
2189         assert(lvalue);
2190         assert(rvalue);
2191         assert(data);
2192 
2193         r = route_new_static(network, filename, section_line, &n);
2194         if (r == -ENOMEM)
2195                 return log_oom();
2196         if (r < 0) {
2197                 log_syntax(unit, LOG_WARNING, filename, line, r,
2198                            "Failed to allocate route, ignoring assignment: %m");
2199                 return 0;
2200         }
2201 
2202         r = route_scope_from_string(rvalue);
2203         if (r < 0) {
2204                 log_syntax(unit, LOG_WARNING, filename, line, r, "Unknown route scope: %s", rvalue);
2205                 return 0;
2206         }
2207 
2208         n->scope = r;
2209         n->scope_set = true;
2210         TAKE_PTR(n);
2211         return 0;
2212 }
2213 
config_parse_route_nexthop(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)2214 int config_parse_route_nexthop(
2215                 const char *unit,
2216                 const char *filename,
2217                 unsigned line,
2218                 const char *section,
2219                 unsigned section_line,
2220                 const char *lvalue,
2221                 int ltype,
2222                 const char *rvalue,
2223                 void *data,
2224                 void *userdata) {
2225 
2226         Network *network = userdata;
2227         _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2228         uint32_t id;
2229         int r;
2230 
2231         assert(filename);
2232         assert(section);
2233         assert(lvalue);
2234         assert(rvalue);
2235         assert(data);
2236 
2237         r = route_new_static(network, filename, section_line, &n);
2238         if (r == -ENOMEM)
2239                 return log_oom();
2240         if (r < 0) {
2241                 log_syntax(unit, LOG_WARNING, filename, line, r,
2242                            "Failed to allocate route, ignoring assignment: %m");
2243                 return 0;
2244         }
2245 
2246         if (isempty(rvalue)) {
2247                 n->nexthop_id = 0;
2248                 TAKE_PTR(n);
2249                 return 0;
2250         }
2251 
2252         r = safe_atou32(rvalue, &id);
2253         if (r < 0) {
2254                 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse nexthop ID, ignoring assignment: %s", rvalue);
2255                 return 0;
2256         }
2257         if (id == 0) {
2258                 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid nexthop ID, ignoring assignment: %s", rvalue);
2259                 return 0;
2260         }
2261 
2262         n->nexthop_id = id;
2263         TAKE_PTR(n);
2264         return 0;
2265 }
2266 
config_parse_route_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)2267 int config_parse_route_table(
2268                 const char *unit,
2269                 const char *filename,
2270                 unsigned line,
2271                 const char *section,
2272                 unsigned section_line,
2273                 const char *lvalue,
2274                 int ltype,
2275                 const char *rvalue,
2276                 void *data,
2277                 void *userdata) {
2278 
2279         _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2280         Network *network = userdata;
2281         int r;
2282 
2283         assert(filename);
2284         assert(section);
2285         assert(lvalue);
2286         assert(rvalue);
2287         assert(data);
2288 
2289         r = route_new_static(network, filename, section_line, &n);
2290         if (r == -ENOMEM)
2291                 return log_oom();
2292         if (r < 0) {
2293                 log_syntax(unit, LOG_WARNING, filename, line, r,
2294                            "Failed to allocate route, ignoring assignment: %m");
2295                 return 0;
2296         }
2297 
2298         r = manager_get_route_table_from_string(network->manager, rvalue, &n->table);
2299         if (r < 0) {
2300                 log_syntax(unit, LOG_WARNING, filename, line, r,
2301                            "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue);
2302                 return 0;
2303         }
2304 
2305         n->table_set = true;
2306         TAKE_PTR(n);
2307         return 0;
2308 }
2309 
config_parse_route_boolean(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)2310 int config_parse_route_boolean(
2311                 const char *unit,
2312                 const char *filename,
2313                 unsigned line,
2314                 const char *section,
2315                 unsigned section_line,
2316                 const char *lvalue,
2317                 int ltype,
2318                 const char *rvalue,
2319                 void *data,
2320                 void *userdata) {
2321 
2322         Network *network = userdata;
2323         _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2324         int r;
2325 
2326         assert(filename);
2327         assert(section);
2328         assert(lvalue);
2329         assert(rvalue);
2330         assert(data);
2331 
2332         r = route_new_static(network, filename, section_line, &n);
2333         if (r == -ENOMEM)
2334                 return log_oom();
2335         if (r < 0) {
2336                 log_syntax(unit, LOG_WARNING, filename, line, r,
2337                            "Failed to allocate route, ignoring assignment: %m");
2338                 return 0;
2339         }
2340 
2341         r = parse_boolean(rvalue);
2342         if (r < 0) {
2343                 log_syntax(unit, LOG_WARNING, filename, line, r,
2344                            "Could not parse %s=\"%s\", ignoring assignment: %m", lvalue, rvalue);
2345                 return 0;
2346         }
2347 
2348         if (STR_IN_SET(lvalue, "GatewayOnLink", "GatewayOnlink"))
2349                 n->gateway_onlink = r;
2350         else if (streq(lvalue, "QuickAck"))
2351                 n->quickack = r;
2352         else if (streq(lvalue, "FastOpenNoCookie"))
2353                 n->fast_open_no_cookie = r;
2354         else if (streq(lvalue, "TTLPropagate"))
2355                 n->ttl_propagate = r;
2356         else
2357                 assert_not_reached();
2358 
2359         TAKE_PTR(n);
2360         return 0;
2361 }
2362 
config_parse_ipv6_route_preference(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)2363 int config_parse_ipv6_route_preference(
2364                 const char *unit,
2365                 const char *filename,
2366                 unsigned line,
2367                 const char *section,
2368                 unsigned section_line,
2369                 const char *lvalue,
2370                 int ltype,
2371                 const char *rvalue,
2372                 void *data,
2373                 void *userdata) {
2374 
2375         Network *network = userdata;
2376         _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2377         int r;
2378 
2379         r = route_new_static(network, filename, section_line, &n);
2380         if (r == -ENOMEM)
2381                 return log_oom();
2382         if (r < 0) {
2383                 log_syntax(unit, LOG_WARNING, filename, line, r,
2384                            "Failed to allocate route, ignoring assignment: %m");
2385                 return 0;
2386         }
2387 
2388         if (streq(rvalue, "low"))
2389                 n->pref = ICMPV6_ROUTER_PREF_LOW;
2390         else if (streq(rvalue, "medium"))
2391                 n->pref = ICMPV6_ROUTER_PREF_MEDIUM;
2392         else if (streq(rvalue, "high"))
2393                 n->pref = ICMPV6_ROUTER_PREF_HIGH;
2394         else {
2395                 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown route preference: %s", rvalue);
2396                 return 0;
2397         }
2398 
2399         n->pref_set = true;
2400         TAKE_PTR(n);
2401         return 0;
2402 }
2403 
config_parse_route_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)2404 int config_parse_route_protocol(
2405                 const char *unit,
2406                 const char *filename,
2407                 unsigned line,
2408                 const char *section,
2409                 unsigned section_line,
2410                 const char *lvalue,
2411                 int ltype,
2412                 const char *rvalue,
2413                 void *data,
2414                 void *userdata) {
2415 
2416         Network *network = userdata;
2417         _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2418         int r;
2419 
2420         r = route_new_static(network, filename, section_line, &n);
2421         if (r == -ENOMEM)
2422                 return log_oom();
2423         if (r < 0) {
2424                 log_syntax(unit, LOG_WARNING, filename, line, r,
2425                            "Failed to allocate route, ignoring assignment: %m");
2426                 return 0;
2427         }
2428 
2429         r = route_protocol_from_string(rvalue);
2430         if (r < 0) {
2431                 log_syntax(unit, LOG_WARNING, filename, line, r,
2432                            "Failed to parse route protocol \"%s\", ignoring assignment: %m", rvalue);
2433                 return 0;
2434         }
2435 
2436         n->protocol = r;
2437 
2438         TAKE_PTR(n);
2439         return 0;
2440 }
2441 
config_parse_route_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)2442 int config_parse_route_type(
2443                 const char *unit,
2444                 const char *filename,
2445                 unsigned line,
2446                 const char *section,
2447                 unsigned section_line,
2448                 const char *lvalue,
2449                 int ltype,
2450                 const char *rvalue,
2451                 void *data,
2452                 void *userdata) {
2453 
2454         Network *network = userdata;
2455         _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2456         int t, r;
2457 
2458         r = route_new_static(network, filename, section_line, &n);
2459         if (r == -ENOMEM)
2460                 return log_oom();
2461         if (r < 0) {
2462                 log_syntax(unit, LOG_WARNING, filename, line, r,
2463                            "Failed to allocate route, ignoring assignment: %m");
2464                 return 0;
2465         }
2466 
2467         t = route_type_from_string(rvalue);
2468         if (t < 0) {
2469                 log_syntax(unit, LOG_WARNING, filename, line, r,
2470                            "Could not parse route type \"%s\", ignoring assignment: %m", rvalue);
2471                 return 0;
2472         }
2473 
2474         n->type = (unsigned char) t;
2475 
2476         TAKE_PTR(n);
2477         return 0;
2478 }
2479 
config_parse_tcp_advmss(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)2480 int config_parse_tcp_advmss(
2481                 const char *unit,
2482                 const char *filename,
2483                 unsigned line,
2484                 const char *section,
2485                 unsigned section_line,
2486                 const char *lvalue,
2487                 int ltype,
2488                 const char *rvalue,
2489                 void *data,
2490                 void *userdata) {
2491 
2492         _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2493         Network *network = userdata;
2494         uint64_t u;
2495         int r;
2496 
2497         assert(filename);
2498         assert(section);
2499         assert(lvalue);
2500         assert(rvalue);
2501         assert(data);
2502 
2503         r = route_new_static(network, filename, section_line, &n);
2504         if (r == -ENOMEM)
2505                 return log_oom();
2506         if (r < 0) {
2507                 log_syntax(unit, LOG_WARNING, filename, line, r,
2508                            "Failed to allocate route, ignoring assignment: %m");
2509                 return 0;
2510         }
2511 
2512         if (isempty(rvalue)) {
2513                 n->advmss = 0;
2514                 TAKE_PTR(n);
2515                 return 0;
2516         }
2517 
2518         r = parse_size(rvalue, 1024, &u);
2519         if (r < 0) {
2520                 log_syntax(unit, LOG_WARNING, filename, line, r,
2521                            "Could not parse TCPAdvertisedMaximumSegmentSize= \"%s\", ignoring assignment: %m", rvalue);
2522                 return 0;
2523         }
2524 
2525         if (u == 0 || u > UINT32_MAX) {
2526                 log_syntax(unit, LOG_WARNING, filename, line, 0,
2527                            "Invalid TCPAdvertisedMaximumSegmentSize= \"%s\", ignoring assignment: %m", rvalue);
2528                 return 0;
2529         }
2530 
2531         n->advmss = u;
2532 
2533         TAKE_PTR(n);
2534         return 0;
2535 }
2536 
config_parse_tcp_window(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)2537 int config_parse_tcp_window(
2538                 const char *unit,
2539                 const char *filename,
2540                 unsigned line,
2541                 const char *section,
2542                 unsigned section_line,
2543                 const char *lvalue,
2544                 int ltype,
2545                 const char *rvalue,
2546                 void *data,
2547                 void *userdata) {
2548 
2549         _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2550         Network *network = userdata;
2551         uint32_t k;
2552         int r;
2553 
2554         assert(filename);
2555         assert(section);
2556         assert(lvalue);
2557         assert(rvalue);
2558         assert(data);
2559 
2560         r = route_new_static(network, filename, section_line, &n);
2561         if (r == -ENOMEM)
2562                 return log_oom();
2563         if (r < 0) {
2564                 log_syntax(unit, LOG_WARNING, filename, line, r,
2565                            "Failed to allocate route, ignoring assignment: %m");
2566                 return 0;
2567         }
2568 
2569         r = safe_atou32(rvalue, &k);
2570         if (r < 0) {
2571                 log_syntax(unit, LOG_WARNING, filename, line, r,
2572                            "Could not parse TCP %s \"%s\", ignoring assignment: %m", lvalue, rvalue);
2573                 return 0;
2574         }
2575         if (k >= 1024) {
2576                 log_syntax(unit, LOG_WARNING, filename, line, 0,
2577                            "Specified TCP %s \"%s\" is too large, ignoring assignment: %m", lvalue, rvalue);
2578                 return 0;
2579         }
2580         if (k == 0) {
2581                 log_syntax(unit, LOG_WARNING, filename, line, 0,
2582                            "Invalid TCP %s \"%s\", ignoring assignment: %m", lvalue, rvalue);
2583                 return 0;
2584         }
2585 
2586         if (streq(lvalue, "InitialCongestionWindow"))
2587                 n->initcwnd = k;
2588         else if (streq(lvalue, "InitialAdvertisedReceiveWindow"))
2589                 n->initrwnd = k;
2590         else
2591                 assert_not_reached();
2592 
2593         TAKE_PTR(n);
2594         return 0;
2595 }
2596 
config_parse_route_mtu(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)2597 int config_parse_route_mtu(
2598                 const char *unit,
2599                 const char *filename,
2600                 unsigned line,
2601                 const char *section,
2602                 unsigned section_line,
2603                 const char *lvalue,
2604                 int ltype,
2605                 const char *rvalue,
2606                 void *data,
2607                 void *userdata) {
2608 
2609         Network *network = userdata;
2610         _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2611         int r;
2612 
2613         assert(filename);
2614         assert(section);
2615         assert(lvalue);
2616         assert(rvalue);
2617         assert(data);
2618 
2619         r = route_new_static(network, filename, section_line, &n);
2620         if (r == -ENOMEM)
2621                 return log_oom();
2622         if (r < 0) {
2623                 log_syntax(unit, LOG_WARNING, filename, line, r,
2624                            "Failed to allocate route, ignoring assignment: %m");
2625                 return 0;
2626         }
2627 
2628         r = config_parse_mtu(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &n->mtu, userdata);
2629         if (r < 0)
2630                 return r;
2631 
2632         TAKE_PTR(n);
2633         return 0;
2634 }
2635 
config_parse_multipath_route(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)2636 int config_parse_multipath_route(
2637                 const char *unit,
2638                 const char *filename,
2639                 unsigned line,
2640                 const char *section,
2641                 unsigned section_line,
2642                 const char *lvalue,
2643                 int ltype,
2644                 const char *rvalue,
2645                 void *data,
2646                 void *userdata) {
2647 
2648         _cleanup_(multipath_route_freep) MultipathRoute *m = NULL;
2649         _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2650         _cleanup_free_ char *word = NULL;
2651         Network *network = userdata;
2652         union in_addr_union a;
2653         int family, r;
2654         const char *p;
2655         char *dev;
2656 
2657         assert(filename);
2658         assert(section);
2659         assert(lvalue);
2660         assert(rvalue);
2661         assert(data);
2662 
2663         r = route_new_static(network, filename, section_line, &n);
2664         if (r == -ENOMEM)
2665                 return log_oom();
2666         if (r < 0) {
2667                 log_syntax(unit, LOG_WARNING, filename, line, r,
2668                            "Failed to allocate route, ignoring assignment: %m");
2669                 return 0;
2670         }
2671 
2672         if (isempty(rvalue)) {
2673                 n->multipath_routes = ordered_set_free_with_destructor(n->multipath_routes, multipath_route_free);
2674                 return 0;
2675         }
2676 
2677         m = new0(MultipathRoute, 1);
2678         if (!m)
2679                 return log_oom();
2680 
2681         p = rvalue;
2682         r = extract_first_word(&p, &word, NULL, 0);
2683         if (r == -ENOMEM)
2684                 return log_oom();
2685         if (r <= 0) {
2686                 log_syntax(unit, LOG_WARNING, filename, line, r,
2687                            "Invalid multipath route option, ignoring assignment: %s", rvalue);
2688                 return 0;
2689         }
2690 
2691         dev = strchr(word, '@');
2692         if (dev) {
2693                 *dev++ = '\0';
2694 
2695                 r = parse_ifindex(dev);
2696                 if (r > 0)
2697                         m->ifindex = r;
2698                 else {
2699                         if (!ifname_valid_full(dev, IFNAME_VALID_ALTERNATIVE)) {
2700                                 log_syntax(unit, LOG_WARNING, filename, line, 0,
2701                                            "Invalid interface name '%s' in %s=, ignoring: %s", dev, lvalue, rvalue);
2702                                 return 0;
2703                         }
2704 
2705                         m->ifname = strdup(dev);
2706                         if (!m->ifname)
2707                                 return log_oom();
2708                 }
2709         }
2710 
2711         r = in_addr_from_string_auto(word, &family, &a);
2712         if (r < 0) {
2713                 log_syntax(unit, LOG_WARNING, filename, line, r,
2714                            "Invalid multipath route gateway '%s', ignoring assignment: %m", rvalue);
2715                 return 0;
2716         }
2717         m->gateway.address = a;
2718         m->gateway.family = family;
2719 
2720         if (!isempty(p)) {
2721                 r = safe_atou32(p, &m->weight);
2722                 if (r < 0) {
2723                         log_syntax(unit, LOG_WARNING, filename, line, r,
2724                                    "Invalid multipath route weight, ignoring assignment: %s", p);
2725                         return 0;
2726                 }
2727                 /* ip command takes weight in the range 1…255, while kernel takes the value in the
2728                  * range 0…254. MultiPathRoute= setting also takes weight in the same range which ip
2729                  * command uses, then networkd decreases by one and stores it to match the range which
2730                  * kernel uses. */
2731                 if (m->weight == 0 || m->weight > 256) {
2732                         log_syntax(unit, LOG_WARNING, filename, line, 0,
2733                                    "Invalid multipath route weight, ignoring assignment: %s", p);
2734                         return 0;
2735                 }
2736                 m->weight--;
2737         }
2738 
2739         r = ordered_set_ensure_put(&n->multipath_routes, NULL, m);
2740         if (r == -ENOMEM)
2741                 return log_oom();
2742         if (r < 0) {
2743                 log_syntax(unit, LOG_WARNING, filename, line, r,
2744                            "Failed to store multipath route, ignoring assignment: %m");
2745                 return 0;
2746         }
2747 
2748         TAKE_PTR(m);
2749         TAKE_PTR(n);
2750         return 0;
2751 }
2752 
route_section_verify(Route * route,Network * network)2753 static int route_section_verify(Route *route, Network *network) {
2754         if (section_is_invalid(route->section))
2755                 return -EINVAL;
2756 
2757         /* Currently, we do not support static route with finite lifetime. */
2758         assert(route->lifetime_usec == USEC_INFINITY);
2759 
2760         if (route->gateway_from_dhcp_or_ra) {
2761                 if (route->gw_family == AF_UNSPEC) {
2762                         /* When deprecated Gateway=_dhcp is set, then assume gateway family based on other settings. */
2763                         switch (route->family) {
2764                         case AF_UNSPEC:
2765                                 log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
2766                                             "Please use \"_dhcp4\" or \"_ipv6ra\" instead. Assuming \"_dhcp4\".",
2767                                             route->section->filename, route->section->line);
2768                                 route->family = AF_INET;
2769                                 break;
2770                         case AF_INET:
2771                         case AF_INET6:
2772                                 log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
2773                                             "Assuming \"%s\" based on Destination=, Source=, or PreferredSource= setting.",
2774                                             route->section->filename, route->section->line, route->family == AF_INET ? "_dhcp4" : "_ipv6ra");
2775                                 break;
2776                         default:
2777                                 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
2778                                                          "%s: Invalid route family. Ignoring [Route] section from line %u.",
2779                                                          route->section->filename, route->section->line);
2780                         }
2781                         route->gw_family = route->family;
2782                 }
2783 
2784                 if (route->gw_family == AF_INET && !FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV4))
2785                         return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
2786                                                  "%s: Gateway=\"_dhcp4\" is specified but DHCPv4 client is disabled. "
2787                                                  "Ignoring [Route] section from line %u.",
2788                                                  route->section->filename, route->section->line);
2789 
2790                 if (route->gw_family == AF_INET6 && !network->ipv6_accept_ra)
2791                         return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
2792                                                  "%s: Gateway=\"_ipv6ra\" is specified but IPv6AcceptRA= is disabled. "
2793                                                  "Ignoring [Route] section from line %u.",
2794                                                  route->section->filename, route->section->line);
2795         }
2796 
2797         /* When only Gateway= is specified, assume the route family based on the Gateway address. */
2798         if (route->family == AF_UNSPEC)
2799                 route->family = route->gw_family;
2800 
2801         if (route->family == AF_UNSPEC) {
2802                 assert(route->section);
2803 
2804                 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
2805                                          "%s: Route section without Gateway=, Destination=, Source=, "
2806                                          "or PreferredSource= field configured. "
2807                                          "Ignoring [Route] section from line %u.",
2808                                          route->section->filename, route->section->line);
2809         }
2810 
2811         if (route->family == AF_INET6 && route->gw_family == AF_INET)
2812                 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
2813                                          "%s: IPv4 gateway is configured for IPv6 route. "
2814                                          "Ignoring [Route] section from line %u.",
2815                                          route->section->filename, route->section->line);
2816 
2817         if (!route->table_set && network->vrf) {
2818                 route->table = VRF(network->vrf)->table;
2819                 route->table_set = true;
2820         }
2821 
2822         if (!route->table_set && IN_SET(route->type, RTN_LOCAL, RTN_BROADCAST, RTN_ANYCAST, RTN_NAT))
2823                 route->table = RT_TABLE_LOCAL;
2824 
2825         if (!route->scope_set && route->family != AF_INET6) {
2826                 if (IN_SET(route->type, RTN_LOCAL, RTN_NAT))
2827                         route->scope = RT_SCOPE_HOST;
2828                 else if (IN_SET(route->type, RTN_BROADCAST, RTN_ANYCAST, RTN_MULTICAST))
2829                         route->scope = RT_SCOPE_LINK;
2830                 else if (IN_SET(route->type, RTN_UNICAST, RTN_UNSPEC) &&
2831                          !route->gateway_from_dhcp_or_ra &&
2832                          !in_addr_is_set(route->gw_family, &route->gw) &&
2833                          ordered_set_isempty(route->multipath_routes) &&
2834                          route->nexthop_id == 0)
2835                         route->scope = RT_SCOPE_LINK;
2836         }
2837 
2838         if (route->scope != RT_SCOPE_UNIVERSE && route->family == AF_INET6) {
2839                 log_warning("%s: Scope= is specified for IPv6 route. It will be ignored.", route->section->filename);
2840                 route->scope = RT_SCOPE_UNIVERSE;
2841         }
2842 
2843         if (route->family == AF_INET6 && route->priority == 0)
2844                 route->priority = IP6_RT_PRIO_USER;
2845 
2846         if (route->gateway_onlink < 0 && in_addr_is_set(route->gw_family, &route->gw) &&
2847             ordered_hashmap_isempty(network->addresses_by_section)) {
2848                 /* If no address is configured, in most cases the gateway cannot be reachable.
2849                  * TODO: we may need to improve the condition above. */
2850                 log_warning("%s: Gateway= without static address configured. "
2851                             "Enabling GatewayOnLink= option.",
2852                             network->filename);
2853                 route->gateway_onlink = true;
2854         }
2855 
2856         if (route->gateway_onlink >= 0)
2857                 SET_FLAG(route->flags, RTNH_F_ONLINK, route->gateway_onlink);
2858 
2859         if (route->family == AF_INET6) {
2860                 MultipathRoute *m;
2861 
2862                 ORDERED_SET_FOREACH(m, route->multipath_routes)
2863                         if (m->gateway.family == AF_INET)
2864                                 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
2865                                                          "%s: IPv4 multipath route is specified for IPv6 route. "
2866                                                          "Ignoring [Route] section from line %u.",
2867                                                          route->section->filename, route->section->line);
2868         }
2869 
2870         if ((route->gateway_from_dhcp_or_ra ||
2871              in_addr_is_set(route->gw_family, &route->gw)) &&
2872             !ordered_set_isempty(route->multipath_routes))
2873                 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
2874                                          "%s: Gateway= cannot be specified with MultiPathRoute=. "
2875                                          "Ignoring [Route] section from line %u.",
2876                                          route->section->filename, route->section->line);
2877 
2878         if (route->nexthop_id > 0 &&
2879             (route->gateway_from_dhcp_or_ra ||
2880              in_addr_is_set(route->gw_family, &route->gw) ||
2881              !ordered_set_isempty(route->multipath_routes)))
2882                 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
2883                                          "%s: NextHopId= cannot be specified with Gateway= or MultiPathRoute=. "
2884                                          "Ignoring [Route] section from line %u.",
2885                                          route->section->filename, route->section->line);
2886 
2887         return 0;
2888 }
2889 
network_drop_invalid_routes(Network * network)2890 void network_drop_invalid_routes(Network *network) {
2891         Route *route;
2892 
2893         assert(network);
2894 
2895         HASHMAP_FOREACH(route, network->routes_by_section)
2896                 if (route_section_verify(route, network) < 0)
2897                         route_free(route);
2898 }
2899