]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-ndisc.c
man/systemd-sysext.xml: document mutable extensions
[thirdparty/systemd.git] / src / network / networkd-ndisc.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /***
3 Copyright © 2014 Intel Corporation. All rights reserved.
4 ***/
5
6 #include <arpa/inet.h>
7 #include <netinet/icmp6.h>
8 #include <linux/if.h>
9 #include <linux/if_arp.h>
10
11 #include "sd-ndisc.h"
12
13 #include "event-util.h"
14 #include "missing_network.h"
15 #include "networkd-address-generation.h"
16 #include "networkd-address.h"
17 #include "networkd-dhcp6.h"
18 #include "networkd-manager.h"
19 #include "networkd-ndisc.h"
20 #include "networkd-queue.h"
21 #include "networkd-route.h"
22 #include "networkd-state-file.h"
23 #include "string-table.h"
24 #include "string-util.h"
25 #include "strv.h"
26 #include "sysctl-util.h"
27
28 #define NDISC_DNSSL_MAX 64U
29 #define NDISC_RDNSS_MAX 64U
30 /* Not defined in the RFC, but let's set an upper limit to make not consume much memory.
31 * This should be safe as typically there should be at most 1 portal per network. */
32 #define NDISC_CAPTIVE_PORTAL_MAX 64U
33 /* Neither defined in the RFC. Just for safety. Otherwise, malformed messages can make clients trigger OOM.
34 * Not sure if the threshold is high enough. Let's adjust later if not. */
35 #define NDISC_PREF64_MAX 64U
36
37 bool link_ipv6_accept_ra_enabled(Link *link) {
38 assert(link);
39
40 if (!socket_ipv6_is_supported())
41 return false;
42
43 if (link->flags & IFF_LOOPBACK)
44 return false;
45
46 if (link->iftype == ARPHRD_CAN)
47 return false;
48
49 if (!link->network)
50 return false;
51
52 if (!link_may_have_ipv6ll(link, /* check_multicast = */ true))
53 return false;
54
55 assert(link->network->ipv6_accept_ra >= 0);
56 return link->network->ipv6_accept_ra;
57 }
58
59 void network_adjust_ipv6_accept_ra(Network *network) {
60 assert(network);
61
62 if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) {
63 if (network->ipv6_accept_ra > 0)
64 log_warning("%s: IPv6AcceptRA= is enabled but IPv6 link-local addressing is disabled or not supported. "
65 "Disabling IPv6AcceptRA=.", network->filename);
66 network->ipv6_accept_ra = false;
67 }
68
69 if (network->ipv6_accept_ra < 0)
70 /* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */
71 network->ipv6_accept_ra = !FLAGS_SET(network->ip_forward, ADDRESS_FAMILY_IPV6);
72
73 /* When RouterAllowList=, PrefixAllowList= or RouteAllowList= are specified, then
74 * RouterDenyList=, PrefixDenyList= or RouteDenyList= are ignored, respectively. */
75 if (!set_isempty(network->ndisc_allow_listed_router))
76 network->ndisc_deny_listed_router = set_free_free(network->ndisc_deny_listed_router);
77 if (!set_isempty(network->ndisc_allow_listed_prefix))
78 network->ndisc_deny_listed_prefix = set_free_free(network->ndisc_deny_listed_prefix);
79 if (!set_isempty(network->ndisc_allow_listed_route_prefix))
80 network->ndisc_deny_listed_route_prefix = set_free_free(network->ndisc_deny_listed_route_prefix);
81 }
82
83 static int ndisc_check_ready(Link *link);
84
85 static int ndisc_address_ready_callback(Address *address) {
86 Address *a;
87
88 assert(address);
89 assert(address->link);
90
91 SET_FOREACH(a, address->link->addresses)
92 if (a->source == NETWORK_CONFIG_SOURCE_NDISC)
93 a->callback = NULL;
94
95 return ndisc_check_ready(address->link);
96 }
97
98 static int ndisc_check_ready(Link *link) {
99 bool found = false, ready = false;
100 Address *address;
101
102 assert(link);
103
104 if (link->ndisc_messages > 0) {
105 log_link_debug(link, "%s(): SLAAC addresses and routes are not set.", __func__);
106 return 0;
107 }
108
109 SET_FOREACH(address, link->addresses) {
110 if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
111 continue;
112
113 found = true;
114
115 if (address_is_ready(address)) {
116 ready = true;
117 break;
118 }
119 }
120
121 if (found && !ready) {
122 SET_FOREACH(address, link->addresses)
123 if (address->source == NETWORK_CONFIG_SOURCE_NDISC)
124 address->callback = ndisc_address_ready_callback;
125
126 log_link_debug(link, "%s(): no SLAAC address is ready.", __func__);
127 return 0;
128 }
129
130 link->ndisc_configured = true;
131 log_link_debug(link, "SLAAC addresses and routes set.");
132
133 link_check_ready(link);
134 return 0;
135 }
136
137 static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
138 int r;
139
140 assert(link);
141
142 r = route_configure_handler_internal(rtnl, m, link, route, "Could not set NDisc route");
143 if (r <= 0)
144 return r;
145
146 r = ndisc_check_ready(link);
147 if (r < 0)
148 link_enter_failed(link);
149
150 return 1;
151 }
152
153 static void ndisc_set_route_priority(Link *link, Route *route) {
154 assert(link);
155 assert(route);
156
157 if (route->priority_set)
158 return; /* explicitly configured. */
159
160 switch (route->pref) {
161 case SD_NDISC_PREFERENCE_LOW:
162 route->priority = link->network->ipv6_accept_ra_route_metric_low;
163 break;
164 case SD_NDISC_PREFERENCE_MEDIUM:
165 route->priority = link->network->ipv6_accept_ra_route_metric_medium;
166 break;
167 case SD_NDISC_PREFERENCE_HIGH:
168 route->priority = link->network->ipv6_accept_ra_route_metric_high;
169 break;
170 default:
171 assert_not_reached();
172 }
173 }
174
175 static int ndisc_request_route(Route *route, Link *link, sd_ndisc_router *rt) {
176 struct in6_addr router;
177 uint8_t hop_limit = 0;
178 uint32_t mtu = 0;
179 bool is_new;
180 int r;
181
182 assert(route);
183 assert(link);
184 assert(link->manager);
185 assert(link->network);
186 assert(rt);
187
188 r = sd_ndisc_router_get_address(rt, &router);
189 if (r < 0)
190 return r;
191
192 if (link->network->ipv6_accept_ra_use_mtu) {
193 r = sd_ndisc_router_get_mtu(rt, &mtu);
194 if (r < 0 && r != -ENODATA)
195 return log_link_warning_errno(link, r, "Failed to get MTU from RA: %m");
196 }
197
198 if (link->network->ipv6_accept_ra_use_hop_limit) {
199 r = sd_ndisc_router_get_hop_limit(rt, &hop_limit);
200 if (r < 0 && r != -ENODATA)
201 return log_link_warning_errno(link, r, "Failed to get hop limit from RA: %m");
202 }
203
204 route->source = NETWORK_CONFIG_SOURCE_NDISC;
205 route->provider.in6 = router;
206 if (!route->table_set)
207 route->table = link_get_ipv6_accept_ra_route_table(link);
208 if (!route->protocol_set)
209 route->protocol = RTPROT_RA;
210 r = route_metric_set(&route->metric, RTAX_MTU, mtu);
211 if (r < 0)
212 return r;
213 r = route_metric_set(&route->metric, RTAX_HOPLIMIT, hop_limit);
214 if (r < 0)
215 return r;
216 r = route_metric_set(&route->metric, RTAX_QUICKACK, link->network->ipv6_accept_ra_quickack);
217 if (r < 0)
218 return r;
219
220 r = route_adjust_nexthops(route, link);
221 if (r < 0)
222 return r;
223
224 uint8_t pref, pref_original = route->pref;
225 FOREACH_ARGUMENT(pref, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_MEDIUM, SD_NDISC_PREFERENCE_HIGH) {
226 Route *existing;
227 Request *req;
228
229 /* If the preference is specified by the user config (that is, for semi-static routes),
230 * rather than RA, then only search conflicting routes that have the same preference. */
231 if (route->pref_set && pref != pref_original)
232 continue;
233
234 route->pref = pref;
235 ndisc_set_route_priority(link, route);
236
237 /* Note, here do not call route_remove_and_cancel() with 'route' directly, otherwise
238 * existing route(s) may be removed needlessly. */
239
240 if (route_get(link->manager, route, &existing) >= 0) {
241 /* Found an existing route that may conflict with this route. */
242 if (!route_can_update(existing, route)) {
243 log_link_debug(link, "Found an existing route that conflicts with new route based on a received RA, removing.");
244 r = route_remove_and_cancel(existing, link->manager);
245 if (r < 0)
246 return r;
247 }
248 }
249
250 if (route_get_request(link->manager, route, &req) >= 0) {
251 existing = ASSERT_PTR(req->userdata);
252 if (!route_can_update(existing, route)) {
253 log_link_debug(link, "Found a pending route request that conflicts with new request based on a received RA, cancelling.");
254 r = route_remove_and_cancel(existing, link->manager);
255 if (r < 0)
256 return r;
257 }
258 }
259 }
260
261 /* The preference (and priority) may be changed in the above loop. Restore it. */
262 route->pref = pref_original;
263 ndisc_set_route_priority(link, route);
264
265 is_new = route_get(link->manager, route, NULL) < 0;
266
267 r = link_request_route(link, route, &link->ndisc_messages, ndisc_route_handler);
268 if (r < 0)
269 return r;
270 if (r > 0 && is_new)
271 link->ndisc_configured = false;
272
273 return 0;
274 }
275
276 static int ndisc_remove_route(Route *route, Link *link) {
277 int r;
278
279 assert(route);
280 assert(link);
281 assert(link->manager);
282
283 ndisc_set_route_priority(link, route);
284
285 if (!route->table_set)
286 route->table = link_get_ipv6_accept_ra_route_table(link);
287
288 r = route_adjust_nexthops(route, link);
289 if (r < 0)
290 return r;
291
292 if (route->pref_set) {
293 ndisc_set_route_priority(link, route);
294 return route_remove_and_cancel(route, link->manager);
295 }
296
297 uint8_t pref;
298 FOREACH_ARGUMENT(pref, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_MEDIUM, SD_NDISC_PREFERENCE_HIGH) {
299 route->pref = pref;
300 ndisc_set_route_priority(link, route);
301 r = route_remove_and_cancel(route, link->manager);
302 if (r < 0)
303 return r;
304 }
305
306 return 0;
307 }
308
309 static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
310 int r;
311
312 assert(link);
313
314 r = address_configure_handler_internal(rtnl, m, link, "Could not set NDisc address");
315 if (r <= 0)
316 return r;
317
318 r = ndisc_check_ready(link);
319 if (r < 0)
320 link_enter_failed(link);
321
322 return 1;
323 }
324
325 static int ndisc_request_address(Address *address, Link *link, sd_ndisc_router *rt) {
326 struct in6_addr router;
327 bool is_new;
328 int r;
329
330 assert(address);
331 assert(link);
332 assert(rt);
333
334 r = sd_ndisc_router_get_address(rt, &router);
335 if (r < 0)
336 return r;
337
338 address->source = NETWORK_CONFIG_SOURCE_NDISC;
339 address->provider.in6 = router;
340
341 r = free_and_strdup_warn(&address->netlabel, link->network->ndisc_netlabel);
342 if (r < 0)
343 return r;
344
345 Address *existing;
346 if (address_get_harder(link, address, &existing) < 0)
347 is_new = true;
348 else if (address_can_update(existing, address))
349 is_new = false;
350 else if (existing->source == NETWORK_CONFIG_SOURCE_DHCP6) {
351 /* SLAAC address is preferred over DHCPv6 address. */
352 log_link_debug(link, "Conflicting DHCPv6 address %s exists, removing.",
353 IN_ADDR_PREFIX_TO_STRING(existing->family, &existing->in_addr, existing->prefixlen));
354 r = address_remove(existing, link);
355 if (r < 0)
356 return r;
357
358 is_new = true;
359 } else {
360 /* Conflicting static address is configured?? */
361 log_link_debug(link, "Conflicting address %s exists, ignoring request.",
362 IN_ADDR_PREFIX_TO_STRING(existing->family, &existing->in_addr, existing->prefixlen));
363 return 0;
364 }
365
366 r = link_request_address(link, address, &link->ndisc_messages,
367 ndisc_address_handler, NULL);
368 if (r < 0)
369 return r;
370 if (r > 0 && is_new)
371 link->ndisc_configured = false;
372
373 return 0;
374 }
375
376 static int ndisc_router_drop_default(Link *link, sd_ndisc_router *rt) {
377 _cleanup_(route_unrefp) Route *route = NULL;
378 struct in6_addr gateway;
379 int r;
380
381 assert(link);
382 assert(link->network);
383 assert(rt);
384
385 r = sd_ndisc_router_get_address(rt, &gateway);
386 if (r < 0)
387 return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
388
389 r = route_new(&route);
390 if (r < 0)
391 return log_oom();
392
393 route->family = AF_INET6;
394 route->nexthop.family = AF_INET6;
395 route->nexthop.gw.in6 = gateway;
396
397 r = ndisc_remove_route(route, link);
398 if (r < 0)
399 return log_link_warning_errno(link, r, "Failed to remove the default gateway configured by RA: %m");
400
401 Route *route_gw;
402 HASHMAP_FOREACH(route_gw, link->network->routes_by_section) {
403 _cleanup_(route_unrefp) Route *tmp = NULL;
404
405 if (!route_gw->gateway_from_dhcp_or_ra)
406 continue;
407
408 if (route_gw->nexthop.family != AF_INET6)
409 continue;
410
411 r = route_dup(route_gw, NULL, &tmp);
412 if (r < 0)
413 return r;
414
415 tmp->nexthop.gw.in6 = gateway;
416
417 r = ndisc_remove_route(tmp, link);
418 if (r < 0)
419 return log_link_warning_errno(link, r, "Could not remove semi-static gateway: %m");
420 }
421
422 return 0;
423 }
424
425 static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
426 usec_t lifetime_usec;
427 struct in6_addr gateway;
428 unsigned preference;
429 int r;
430
431 assert(link);
432 assert(link->network);
433 assert(rt);
434
435 /* If the router lifetime is zero, the router should not be used as the default gateway. */
436 r = sd_ndisc_router_get_lifetime(rt, NULL);
437 if (r < 0)
438 return r;
439 if (r == 0)
440 return ndisc_router_drop_default(link, rt);
441
442 if (!link->network->ipv6_accept_ra_use_gateway &&
443 hashmap_isempty(link->network->routes_by_section))
444 return 0;
445
446 r = sd_ndisc_router_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
447 if (r < 0)
448 return log_link_warning_errno(link, r, "Failed to get gateway lifetime from RA: %m");
449
450 r = sd_ndisc_router_get_address(rt, &gateway);
451 if (r < 0)
452 return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
453
454 if (link_get_ipv6_address(link, &gateway, 0, NULL) >= 0) {
455 if (DEBUG_LOGGING)
456 log_link_debug(link, "No NDisc route added, gateway %s matches local address",
457 IN6_ADDR_TO_STRING(&gateway));
458 return 0;
459 }
460
461 r = sd_ndisc_router_get_preference(rt, &preference);
462 if (r < 0)
463 return log_link_warning_errno(link, r, "Failed to get router preference from RA: %m");
464
465 if (link->network->ipv6_accept_ra_use_gateway) {
466 _cleanup_(route_unrefp) Route *route = NULL;
467
468 r = route_new(&route);
469 if (r < 0)
470 return log_oom();
471
472 route->family = AF_INET6;
473 route->pref = preference;
474 route->nexthop.family = AF_INET6;
475 route->nexthop.gw.in6 = gateway;
476 route->lifetime_usec = lifetime_usec;
477
478 r = ndisc_request_route(route, link, rt);
479 if (r < 0)
480 return log_link_warning_errno(link, r, "Could not request default route: %m");
481 }
482
483 Route *route_gw;
484 HASHMAP_FOREACH(route_gw, link->network->routes_by_section) {
485 _cleanup_(route_unrefp) Route *route = NULL;
486
487 if (!route_gw->gateway_from_dhcp_or_ra)
488 continue;
489
490 if (route_gw->nexthop.family != AF_INET6)
491 continue;
492
493 r = route_dup(route_gw, NULL, &route);
494 if (r < 0)
495 return r;
496
497 route->nexthop.gw.in6 = gateway;
498 if (!route->pref_set)
499 route->pref = preference;
500 route->lifetime_usec = lifetime_usec;
501
502 r = ndisc_request_route(route, link, rt);
503 if (r < 0)
504 return log_link_warning_errno(link, r, "Could not request gateway: %m");
505 }
506
507 return 0;
508 }
509
510 static int ndisc_router_process_icmp6_ratelimit(Link *link, sd_ndisc_router *rt) {
511 usec_t icmp6_ratelimit, msec;
512 int r;
513
514 assert(link);
515 assert(link->network);
516 assert(rt);
517
518 if (!link->network->ipv6_accept_ra_use_icmp6_ratelimit)
519 return 0;
520
521 /* Ignore the icmp6 ratelimit field of the RA header if the lifetime is zero. */
522 r = sd_ndisc_router_get_lifetime(rt, NULL);
523 if (r <= 0)
524 return r;
525
526 r = sd_ndisc_router_get_icmp6_ratelimit(rt, &icmp6_ratelimit);
527 if (r < 0)
528 return log_link_warning_errno(link, r, "Failed to get ICMP6 ratelimit from RA: %m");
529
530 /* We do not allow 0 here. */
531 if (!timestamp_is_set(icmp6_ratelimit))
532 return 0;
533
534 msec = DIV_ROUND_UP(icmp6_ratelimit, USEC_PER_MSEC);
535 if (msec <= 0 || msec > INT_MAX)
536 return 0;
537
538 /* Limit the maximal rates for sending ICMPv6 packets. 0 to disable any limiting, otherwise the
539 * minimal space between responses in milliseconds. Default: 1000. */
540 r = sysctl_write_ip_property_int(AF_INET6, NULL, "icmp/ratelimit", (int) msec);
541 if (r < 0)
542 log_link_warning_errno(link, r, "Failed to apply ICMP6 ratelimit, ignoring: %m");
543
544 return 0;
545 }
546
547 static int ndisc_router_process_reachable_time(Link *link, sd_ndisc_router *rt) {
548 usec_t reachable_time, msec;
549 int r;
550
551 assert(link);
552 assert(link->network);
553 assert(rt);
554
555 if (!link->network->ipv6_accept_ra_use_reachable_time)
556 return 0;
557
558 /* Ignore the reachable time field of the RA header if the lifetime is zero. */
559 r = sd_ndisc_router_get_lifetime(rt, NULL);
560 if (r <= 0)
561 return r;
562
563 r = sd_ndisc_router_get_reachable_time(rt, &reachable_time);
564 if (r < 0)
565 return log_link_warning_errno(link, r, "Failed to get reachable time from RA: %m");
566
567 /* 0 is the unspecified value and must not be set (see RFC4861, 6.3.4) */
568 if (!timestamp_is_set(reachable_time))
569 return 0;
570
571 msec = DIV_ROUND_UP(reachable_time, USEC_PER_MSEC);
572 if (msec <= 0 || msec > UINT32_MAX) {
573 log_link_debug(link, "Failed to get reachable time from RA - out of range (%"PRIu64"), ignoring", msec);
574 return 0;
575 }
576
577 /* Set the reachable time for Neighbor Solicitations. */
578 r = sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "base_reachable_time_ms", (uint32_t) msec);
579 if (r < 0)
580 log_link_warning_errno(link, r, "Failed to apply neighbor reachable time (%"PRIu64"), ignoring: %m", msec);
581
582 return 0;
583 }
584
585 static int ndisc_router_process_retransmission_time(Link *link, sd_ndisc_router *rt) {
586 usec_t retrans_time, msec;
587 int r;
588
589 assert(link);
590 assert(link->network);
591 assert(rt);
592
593 if (!link->network->ipv6_accept_ra_use_retransmission_time)
594 return 0;
595
596 /* Ignore the retransmission time field of the RA header if the lifetime is zero. */
597 r = sd_ndisc_router_get_lifetime(rt, NULL);
598 if (r <= 0)
599 return r;
600
601 r = sd_ndisc_router_get_retransmission_time(rt, &retrans_time);
602 if (r < 0)
603 return log_link_warning_errno(link, r, "Failed to get retransmission time from RA: %m");
604
605 /* 0 is the unspecified value and must not be set (see RFC4861, 6.3.4) */
606 if (!timestamp_is_set(retrans_time))
607 return 0;
608
609 msec = DIV_ROUND_UP(retrans_time, USEC_PER_MSEC);
610 if (msec <= 0 || msec > UINT32_MAX) {
611 log_link_debug(link, "Failed to get retransmission time from RA - out of range (%"PRIu64"), ignoring", msec);
612 return 0;
613 }
614
615 /* Set the retransmission time for Neighbor Solicitations. */
616 r = sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "retrans_time_ms", (uint32_t) msec);
617 if (r < 0)
618 log_link_warning_errno(link, r, "Failed to apply neighbor retransmission time (%"PRIu64"), ignoring: %m", msec);
619
620 return 0;
621 }
622
623 static int ndisc_router_process_hop_limit(Link *link, sd_ndisc_router *rt) {
624 uint8_t hop_limit;
625 int r;
626
627 assert(link);
628 assert(link->network);
629 assert(rt);
630
631 if (!link->network->ipv6_accept_ra_use_hop_limit)
632 return 0;
633
634 /* Ignore the hop limit field of the RA header if the lifetime is zero. */
635 r = sd_ndisc_router_get_lifetime(rt, NULL);
636 if (r <= 0)
637 return r;
638
639 r = sd_ndisc_router_get_hop_limit(rt, &hop_limit);
640 if (r < 0)
641 return log_link_warning_errno(link, r, "Failed to get hop limit from RA: %m");
642
643 /* 0 is the unspecified value and must not be set (see RFC4861, 6.3.4):
644 *
645 * A Router Advertisement field (e.g., Cur Hop Limit, Reachable Time, and Retrans Timer) may contain
646 * a value denoting that it is unspecified. In such cases, the parameter should be ignored and the
647 * host should continue using whatever value it is already using. In particular, a host MUST NOT
648 * interpret the unspecified value as meaning change back to the default value that was in use before
649 * the first Router Advertisement was received.
650 *
651 * If the received Cur Hop Limit value is non-zero, the host SHOULD set
652 * its CurHopLimit variable to the received value.*/
653 if (hop_limit <= 0)
654 return 0;
655
656 r = sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "hop_limit", (uint32_t) hop_limit);
657 if (r < 0)
658 log_link_warning_errno(link, r, "Failed to apply hop_limit (%u), ignoring: %m", hop_limit);
659
660 return 0;
661 }
662
663 static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
664 usec_t lifetime_valid_usec, lifetime_preferred_usec;
665 _cleanup_set_free_ Set *addresses = NULL;
666 struct in6_addr prefix, *a;
667 unsigned prefixlen;
668 int r;
669
670 assert(link);
671 assert(link->network);
672 assert(rt);
673
674 if (!link->network->ipv6_accept_ra_use_autonomous_prefix)
675 return 0;
676
677 r = sd_ndisc_router_prefix_get_address(rt, &prefix);
678 if (r < 0)
679 return log_link_warning_errno(link, r, "Failed to get prefix address: %m");
680
681 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
682 if (r < 0)
683 return log_link_warning_errno(link, r, "Failed to get prefix length: %m");
684
685 /* ndisc_generate_addresses() below requires the prefix length <= 64. */
686 if (prefixlen > 64) {
687 log_link_debug(link, "Prefix is longer than 64, ignoring autonomous prefix %s.",
688 IN6_ADDR_PREFIX_TO_STRING(&prefix, prefixlen));
689 return 0;
690 }
691
692 r = sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_valid_usec);
693 if (r < 0)
694 return log_link_warning_errno(link, r, "Failed to get prefix valid lifetime: %m");
695
696 r = sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_preferred_usec);
697 if (r < 0)
698 return log_link_warning_errno(link, r, "Failed to get prefix preferred lifetime: %m");
699
700 /* The preferred lifetime is never greater than the valid lifetime */
701 if (lifetime_preferred_usec > lifetime_valid_usec)
702 return 0;
703
704 r = ndisc_generate_addresses(link, &prefix, prefixlen, &addresses);
705 if (r < 0)
706 return log_link_warning_errno(link, r, "Failed to generate SLAAC addresses: %m");
707
708 SET_FOREACH(a, addresses) {
709 _cleanup_(address_unrefp) Address *address = NULL;
710
711 r = address_new(&address);
712 if (r < 0)
713 return log_oom();
714
715 address->family = AF_INET6;
716 address->in_addr.in6 = *a;
717 address->prefixlen = prefixlen;
718 address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
719 address->lifetime_valid_usec = lifetime_valid_usec;
720 address->lifetime_preferred_usec = lifetime_preferred_usec;
721
722 /* draft-ietf-6man-slaac-renum-07 section 4.2
723 * https://datatracker.ietf.org/doc/html/draft-ietf-6man-slaac-renum-07#section-4.2
724 *
725 * If the advertised prefix is equal to the prefix of an address configured by stateless
726 * autoconfiguration in the list, the valid lifetime and the preferred lifetime of the
727 * address should be updated by processing the Valid Lifetime and the Preferred Lifetime
728 * (respectively) in the received advertisement. */
729 if (lifetime_valid_usec == 0) {
730 r = address_remove_and_cancel(address, link);
731 if (r < 0)
732 return log_link_warning_errno(link, r, "Could not remove SLAAC address: %m");
733 } else {
734 r = ndisc_request_address(address, link, rt);
735 if (r < 0)
736 return log_link_warning_errno(link, r, "Could not request SLAAC address: %m");
737 }
738 }
739
740 return 0;
741 }
742
743 static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
744 _cleanup_(route_unrefp) Route *route = NULL;
745 unsigned prefixlen, preference;
746 usec_t lifetime_usec;
747 struct in6_addr prefix;
748 int r;
749
750 assert(link);
751 assert(link->network);
752 assert(rt);
753
754 if (!link->network->ipv6_accept_ra_use_onlink_prefix)
755 return 0;
756
757 r = sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
758 if (r < 0)
759 return log_link_warning_errno(link, r, "Failed to get prefix lifetime: %m");
760
761 r = sd_ndisc_router_prefix_get_address(rt, &prefix);
762 if (r < 0)
763 return log_link_warning_errno(link, r, "Failed to get prefix address: %m");
764
765 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
766 if (r < 0)
767 return log_link_warning_errno(link, r, "Failed to get prefix length: %m");
768
769 /* Prefix Information option does not have preference, hence we use the 'main' preference here */
770 r = sd_ndisc_router_get_preference(rt, &preference);
771 if (r < 0)
772 return log_link_warning_errno(link, r, "Failed to get router preference from RA: %m");
773
774 r = route_new(&route);
775 if (r < 0)
776 return log_oom();
777
778 route->family = AF_INET6;
779 route->dst.in6 = prefix;
780 route->dst_prefixlen = prefixlen;
781 route->pref = preference;
782 route->lifetime_usec = lifetime_usec;
783
784 r = ndisc_request_route(route, link, rt);
785 if (r < 0)
786 return log_link_warning_errno(link, r, "Could not request prefix route: %m");
787
788 return 0;
789 }
790
791 static int ndisc_router_drop_onlink_prefix(Link *link, sd_ndisc_router *rt) {
792 _cleanup_(route_unrefp) Route *route = NULL;
793 unsigned prefixlen;
794 struct in6_addr prefix;
795 usec_t lifetime_usec;
796 int r;
797
798 assert(link);
799 assert(link->network);
800 assert(rt);
801
802 /* RFC 4861 section 6.3.4.
803 * Note, however, that a Prefix Information option with the on-link flag set to zero conveys no
804 * information concerning on-link determination and MUST NOT be interpreted to mean that addresses
805 * covered by the prefix are off-link. The only way to cancel a previous on-link indication is to
806 * advertise that prefix with the L-bit set and the Lifetime set to zero. */
807
808 if (!link->network->ipv6_accept_ra_use_onlink_prefix)
809 return 0;
810
811 r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_usec);
812 if (r < 0)
813 return log_link_warning_errno(link, r, "Failed to get prefix lifetime: %m");
814
815 if (lifetime_usec != 0)
816 return 0;
817
818 r = sd_ndisc_router_prefix_get_address(rt, &prefix);
819 if (r < 0)
820 return log_link_warning_errno(link, r, "Failed to get prefix address: %m");
821
822 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
823 if (r < 0)
824 return log_link_warning_errno(link, r, "Failed to get prefix length: %m");
825
826 r = route_new(&route);
827 if (r < 0)
828 return log_oom();
829
830 route->family = AF_INET6;
831 route->dst.in6 = prefix;
832 route->dst_prefixlen = prefixlen;
833
834 r = ndisc_remove_route(route, link);
835 if (r < 0)
836 return log_link_warning_errno(link, r, "Could not remove prefix route: %m");
837
838 return 0;
839 }
840
841 static int ndisc_router_process_prefix(Link *link, sd_ndisc_router *rt) {
842 unsigned prefixlen;
843 struct in6_addr a;
844 uint8_t flags;
845 int r;
846
847 assert(link);
848 assert(link->network);
849 assert(rt);
850
851 r = sd_ndisc_router_prefix_get_address(rt, &a);
852 if (r < 0)
853 return log_link_warning_errno(link, r, "Failed to get prefix address: %m");
854
855 /* RFC 4861 Section 4.6.2:
856 * A router SHOULD NOT send a prefix option for the link-local prefix and a host SHOULD ignore such
857 * a prefix option. */
858 if (in6_addr_is_link_local(&a)) {
859 log_link_debug(link, "Received link-local prefix, ignoring prefix.");
860 return 0;
861 }
862
863 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
864 if (r < 0)
865 return log_link_warning_errno(link, r, "Failed to get prefix length: %m");
866
867 if (in6_prefix_is_filtered(&a, prefixlen, link->network->ndisc_allow_listed_prefix, link->network->ndisc_deny_listed_prefix)) {
868 if (DEBUG_LOGGING)
869 log_link_debug(link, "Prefix '%s' is %s, ignoring",
870 !set_isempty(link->network->ndisc_allow_listed_prefix) ? "not in allow list"
871 : "in deny list",
872 IN6_ADDR_PREFIX_TO_STRING(&a, prefixlen));
873 return 0;
874 }
875
876 r = sd_ndisc_router_prefix_get_flags(rt, &flags);
877 if (r < 0)
878 return log_link_warning_errno(link, r, "Failed to get RA prefix flags: %m");
879
880 if (FLAGS_SET(flags, ND_OPT_PI_FLAG_ONLINK))
881 r = ndisc_router_process_onlink_prefix(link, rt);
882 else
883 r = ndisc_router_drop_onlink_prefix(link, rt);
884 if (r < 0)
885 return r;
886
887 if (FLAGS_SET(flags, ND_OPT_PI_FLAG_AUTO)) {
888 r = ndisc_router_process_autonomous_prefix(link, rt);
889 if (r < 0)
890 return r;
891 }
892
893 return 0;
894 }
895
896 static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
897 _cleanup_(route_unrefp) Route *route = NULL;
898 unsigned preference, prefixlen;
899 struct in6_addr gateway, dst;
900 usec_t lifetime_usec;
901 int r;
902
903 assert(link);
904
905 if (!link->network->ipv6_accept_ra_use_route_prefix)
906 return 0;
907
908 r = sd_ndisc_router_route_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
909 if (r < 0)
910 return log_link_warning_errno(link, r, "Failed to get route lifetime from RA: %m");
911
912 r = sd_ndisc_router_route_get_address(rt, &dst);
913 if (r < 0)
914 return log_link_warning_errno(link, r, "Failed to get route destination address: %m");
915
916 r = sd_ndisc_router_route_get_prefixlen(rt, &prefixlen);
917 if (r < 0)
918 return log_link_warning_errno(link, r, "Failed to get route prefix length: %m");
919
920 if (in6_addr_is_null(&dst) && prefixlen == 0) {
921 log_link_debug(link, "Route prefix is ::/0, ignoring");
922 return 0;
923 }
924
925 if (in6_prefix_is_filtered(&dst, prefixlen,
926 link->network->ndisc_allow_listed_route_prefix,
927 link->network->ndisc_deny_listed_route_prefix)) {
928
929 if (DEBUG_LOGGING)
930 log_link_debug(link, "Route prefix %s is %s, ignoring",
931 !set_isempty(link->network->ndisc_allow_listed_route_prefix) ? "not in allow list"
932 : "in deny list",
933 IN6_ADDR_PREFIX_TO_STRING(&dst, prefixlen));
934 return 0;
935 }
936
937 r = sd_ndisc_router_get_address(rt, &gateway);
938 if (r < 0)
939 return log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
940
941 if (link_get_ipv6_address(link, &gateway, 0, NULL) >= 0) {
942 if (DEBUG_LOGGING)
943 log_link_debug(link, "Advertised route gateway %s is local to the link, ignoring route",
944 IN6_ADDR_TO_STRING(&gateway));
945 return 0;
946 }
947
948 r = sd_ndisc_router_route_get_preference(rt, &preference);
949 if (r == -EOPNOTSUPP) {
950 log_link_debug_errno(link, r, "Received route prefix with unsupported preference, ignoring: %m");
951 return 0;
952 }
953 if (r < 0)
954 return log_link_warning_errno(link, r, "Failed to get router preference from RA: %m");
955
956 r = route_new(&route);
957 if (r < 0)
958 return log_oom();
959
960 route->family = AF_INET6;
961 route->pref = preference;
962 route->nexthop.gw.in6 = gateway;
963 route->nexthop.family = AF_INET6;
964 route->dst.in6 = dst;
965 route->dst_prefixlen = prefixlen;
966 route->lifetime_usec = lifetime_usec;
967
968 r = ndisc_request_route(route, link, rt);
969 if (r < 0)
970 return log_link_warning_errno(link, r, "Could not request additional route: %m");
971
972 return 0;
973 }
974
975 static void ndisc_rdnss_hash_func(const NDiscRDNSS *x, struct siphash *state) {
976 siphash24_compress_typesafe(x->address, state);
977 }
978
979 static int ndisc_rdnss_compare_func(const NDiscRDNSS *a, const NDiscRDNSS *b) {
980 return memcmp(&a->address, &b->address, sizeof(a->address));
981 }
982
983 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
984 ndisc_rdnss_hash_ops,
985 NDiscRDNSS,
986 ndisc_rdnss_hash_func,
987 ndisc_rdnss_compare_func,
988 free);
989
990 static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
991 usec_t lifetime_usec;
992 const struct in6_addr *a;
993 struct in6_addr router;
994 bool updated = false, logged_about_too_many = false;
995 int n, r;
996
997 assert(link);
998 assert(link->network);
999 assert(rt);
1000
1001 if (!link->network->ipv6_accept_ra_use_dns)
1002 return 0;
1003
1004 r = sd_ndisc_router_get_address(rt, &router);
1005 if (r < 0)
1006 return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
1007
1008 r = sd_ndisc_router_rdnss_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
1009 if (r < 0)
1010 return log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m");
1011
1012 n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
1013 if (n < 0)
1014 return log_link_warning_errno(link, n, "Failed to get RDNSS addresses: %m");
1015
1016 for (int j = 0; j < n; j++) {
1017 _cleanup_free_ NDiscRDNSS *x = NULL;
1018 NDiscRDNSS *rdnss, d = {
1019 .address = a[j],
1020 };
1021
1022 if (lifetime_usec == 0) {
1023 /* The entry is outdated. */
1024 free(set_remove(link->ndisc_rdnss, &d));
1025 updated = true;
1026 continue;
1027 }
1028
1029 rdnss = set_get(link->ndisc_rdnss, &d);
1030 if (rdnss) {
1031 rdnss->router = router;
1032 rdnss->lifetime_usec = lifetime_usec;
1033 continue;
1034 }
1035
1036 if (set_size(link->ndisc_rdnss) >= NDISC_RDNSS_MAX) {
1037 if (!logged_about_too_many)
1038 log_link_warning(link, "Too many RDNSS records per link. Only first %u records will be used.", NDISC_RDNSS_MAX);
1039 logged_about_too_many = true;
1040 continue;
1041 }
1042
1043 x = new(NDiscRDNSS, 1);
1044 if (!x)
1045 return log_oom();
1046
1047 *x = (NDiscRDNSS) {
1048 .address = a[j],
1049 .router = router,
1050 .lifetime_usec = lifetime_usec,
1051 };
1052
1053 r = set_ensure_consume(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops, TAKE_PTR(x));
1054 if (r < 0)
1055 return log_oom();
1056 assert(r > 0);
1057
1058 updated = true;
1059 }
1060
1061 if (updated)
1062 link_dirty(link);
1063
1064 return 0;
1065 }
1066
1067 static void ndisc_dnssl_hash_func(const NDiscDNSSL *x, struct siphash *state) {
1068 siphash24_compress_string(NDISC_DNSSL_DOMAIN(x), state);
1069 }
1070
1071 static int ndisc_dnssl_compare_func(const NDiscDNSSL *a, const NDiscDNSSL *b) {
1072 return strcmp(NDISC_DNSSL_DOMAIN(a), NDISC_DNSSL_DOMAIN(b));
1073 }
1074
1075 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
1076 ndisc_dnssl_hash_ops,
1077 NDiscDNSSL,
1078 ndisc_dnssl_hash_func,
1079 ndisc_dnssl_compare_func,
1080 free);
1081
1082 static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
1083 _cleanup_strv_free_ char **l = NULL;
1084 usec_t lifetime_usec;
1085 struct in6_addr router;
1086 bool updated = false, logged_about_too_many = false;
1087 int r;
1088
1089 assert(link);
1090 assert(link->network);
1091 assert(rt);
1092
1093 if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_NO)
1094 return 0;
1095
1096 r = sd_ndisc_router_get_address(rt, &router);
1097 if (r < 0)
1098 return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
1099
1100 r = sd_ndisc_router_dnssl_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
1101 if (r < 0)
1102 return log_link_warning_errno(link, r, "Failed to get DNSSL lifetime: %m");
1103
1104 r = sd_ndisc_router_dnssl_get_domains(rt, &l);
1105 if (r < 0)
1106 return log_link_warning_errno(link, r, "Failed to get DNSSL addresses: %m");
1107
1108 STRV_FOREACH(j, l) {
1109 _cleanup_free_ NDiscDNSSL *s = NULL;
1110 NDiscDNSSL *dnssl;
1111
1112 s = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*j) + 1);
1113 if (!s)
1114 return log_oom();
1115
1116 strcpy(NDISC_DNSSL_DOMAIN(s), *j);
1117
1118 if (lifetime_usec == 0) {
1119 /* The entry is outdated. */
1120 free(set_remove(link->ndisc_dnssl, s));
1121 updated = true;
1122 continue;
1123 }
1124
1125 dnssl = set_get(link->ndisc_dnssl, s);
1126 if (dnssl) {
1127 dnssl->router = router;
1128 dnssl->lifetime_usec = lifetime_usec;
1129 continue;
1130 }
1131
1132 if (set_size(link->ndisc_dnssl) >= NDISC_DNSSL_MAX) {
1133 if (!logged_about_too_many)
1134 log_link_warning(link, "Too many DNSSL records per link. Only first %u records will be used.", NDISC_DNSSL_MAX);
1135 logged_about_too_many = true;
1136 continue;
1137 }
1138
1139 s->router = router;
1140 s->lifetime_usec = lifetime_usec;
1141
1142 r = set_ensure_consume(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops, TAKE_PTR(s));
1143 if (r < 0)
1144 return log_oom();
1145 assert(r > 0);
1146
1147 updated = true;
1148 }
1149
1150 if (updated)
1151 link_dirty(link);
1152
1153 return 0;
1154 }
1155
1156 static NDiscCaptivePortal* ndisc_captive_portal_free(NDiscCaptivePortal *x) {
1157 if (!x)
1158 return NULL;
1159
1160 free(x->captive_portal);
1161 return mfree(x);
1162 }
1163
1164 DEFINE_TRIVIAL_CLEANUP_FUNC(NDiscCaptivePortal*, ndisc_captive_portal_free);
1165
1166 static void ndisc_captive_portal_hash_func(const NDiscCaptivePortal *x, struct siphash *state) {
1167 assert(x);
1168 siphash24_compress_string(x->captive_portal, state);
1169 }
1170
1171 static int ndisc_captive_portal_compare_func(const NDiscCaptivePortal *a, const NDiscCaptivePortal *b) {
1172 assert(a);
1173 assert(b);
1174 return strcmp_ptr(a->captive_portal, b->captive_portal);
1175 }
1176
1177 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
1178 ndisc_captive_portal_hash_ops,
1179 NDiscCaptivePortal,
1180 ndisc_captive_portal_hash_func,
1181 ndisc_captive_portal_compare_func,
1182 ndisc_captive_portal_free);
1183
1184 static int ndisc_router_process_captive_portal(Link *link, sd_ndisc_router *rt) {
1185 _cleanup_(ndisc_captive_portal_freep) NDiscCaptivePortal *new_entry = NULL;
1186 _cleanup_free_ char *captive_portal = NULL;
1187 usec_t lifetime_usec;
1188 NDiscCaptivePortal *exist;
1189 struct in6_addr router;
1190 const char *uri;
1191 size_t len;
1192 int r;
1193
1194 assert(link);
1195 assert(link->network);
1196 assert(rt);
1197
1198 if (!link->network->ipv6_accept_ra_use_captive_portal)
1199 return 0;
1200
1201 r = sd_ndisc_router_get_address(rt, &router);
1202 if (r < 0)
1203 return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
1204
1205 /* RFC 4861 section 4.2. states that the lifetime in the message header should be used only for the
1206 * default gateway, but the captive portal option does not have a lifetime field, hence, we use the
1207 * main lifetime for the portal. */
1208 r = sd_ndisc_router_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
1209 if (r < 0)
1210 return log_link_warning_errno(link, r, "Failed to get lifetime of RA message: %m");
1211
1212 r = sd_ndisc_router_captive_portal_get_uri(rt, &uri, &len);
1213 if (r < 0)
1214 return log_link_warning_errno(link, r, "Failed to get captive portal from RA: %m");
1215
1216 if (len == 0)
1217 return log_link_warning_errno(link, SYNTHETIC_ERRNO(EBADMSG), "Received empty captive portal, ignoring.");
1218
1219 r = make_cstring(uri, len, MAKE_CSTRING_REFUSE_TRAILING_NUL, &captive_portal);
1220 if (r < 0)
1221 return log_link_warning_errno(link, r, "Failed to convert captive portal URI: %m");
1222
1223 if (!in_charset(captive_portal, URI_VALID))
1224 return log_link_warning_errno(link, SYNTHETIC_ERRNO(EBADMSG), "Received invalid captive portal, ignoring.");
1225
1226 if (lifetime_usec == 0) {
1227 /* Drop the portal with zero lifetime. */
1228 ndisc_captive_portal_free(set_remove(link->ndisc_captive_portals,
1229 &(NDiscCaptivePortal) {
1230 .captive_portal = captive_portal,
1231 }));
1232 return 0;
1233 }
1234
1235 exist = set_get(link->ndisc_captive_portals,
1236 &(NDiscCaptivePortal) {
1237 .captive_portal = captive_portal,
1238 });
1239 if (exist) {
1240 /* update existing entry */
1241 exist->router = router;
1242 exist->lifetime_usec = lifetime_usec;
1243 return 1;
1244 }
1245
1246 if (set_size(link->ndisc_captive_portals) >= NDISC_CAPTIVE_PORTAL_MAX) {
1247 NDiscCaptivePortal *c, *target = NULL;
1248
1249 /* Find the portal who has the minimal lifetime and drop it to store new one. */
1250 SET_FOREACH(c, link->ndisc_captive_portals)
1251 if (!target || c->lifetime_usec < target->lifetime_usec)
1252 target = c;
1253
1254 assert(target);
1255 assert(set_remove(link->ndisc_captive_portals, target) == target);
1256 ndisc_captive_portal_free(target);
1257 }
1258
1259 new_entry = new(NDiscCaptivePortal, 1);
1260 if (!new_entry)
1261 return log_oom();
1262
1263 *new_entry = (NDiscCaptivePortal) {
1264 .router = router,
1265 .lifetime_usec = lifetime_usec,
1266 .captive_portal = TAKE_PTR(captive_portal),
1267 };
1268
1269 r = set_ensure_put(&link->ndisc_captive_portals, &ndisc_captive_portal_hash_ops, new_entry);
1270 if (r < 0)
1271 return log_oom();
1272 assert(r > 0);
1273 TAKE_PTR(new_entry);
1274
1275 link_dirty(link);
1276 return 1;
1277 }
1278
1279 static void ndisc_pref64_hash_func(const NDiscPREF64 *x, struct siphash *state) {
1280 assert(x);
1281
1282 siphash24_compress_typesafe(x->prefix_len, state);
1283 siphash24_compress_typesafe(x->prefix, state);
1284 }
1285
1286 static int ndisc_pref64_compare_func(const NDiscPREF64 *a, const NDiscPREF64 *b) {
1287 int r;
1288
1289 assert(a);
1290 assert(b);
1291
1292 r = CMP(a->prefix_len, b->prefix_len);
1293 if (r != 0)
1294 return r;
1295
1296 return memcmp(&a->prefix, &b->prefix, sizeof(a->prefix));
1297 }
1298
1299 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
1300 ndisc_pref64_hash_ops,
1301 NDiscPREF64,
1302 ndisc_pref64_hash_func,
1303 ndisc_pref64_compare_func,
1304 mfree);
1305
1306 static int ndisc_router_process_pref64(Link *link, sd_ndisc_router *rt) {
1307 _cleanup_free_ NDiscPREF64 *new_entry = NULL;
1308 usec_t lifetime_usec;
1309 struct in6_addr a, router;
1310 unsigned prefix_len;
1311 NDiscPREF64 *exist;
1312 int r;
1313
1314 assert(link);
1315 assert(link->network);
1316 assert(rt);
1317
1318 if (!link->network->ipv6_accept_ra_use_pref64)
1319 return 0;
1320
1321 r = sd_ndisc_router_get_address(rt, &router);
1322 if (r < 0)
1323 return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
1324
1325 r = sd_ndisc_router_prefix64_get_prefix(rt, &a);
1326 if (r < 0)
1327 return log_link_warning_errno(link, r, "Failed to get pref64 prefix: %m");
1328
1329 r = sd_ndisc_router_prefix64_get_prefixlen(rt, &prefix_len);
1330 if (r < 0)
1331 return log_link_warning_errno(link, r, "Failed to get pref64 prefix length: %m");
1332
1333 r = sd_ndisc_router_prefix64_get_lifetime_timestamp(rt, CLOCK_BOOTTIME, &lifetime_usec);
1334 if (r < 0)
1335 return log_link_warning_errno(link, r, "Failed to get pref64 prefix lifetime: %m");
1336
1337 if (lifetime_usec == 0) {
1338 free(set_remove(link->ndisc_pref64,
1339 &(NDiscPREF64) {
1340 .prefix = a,
1341 .prefix_len = prefix_len
1342 }));
1343 return 0;
1344 }
1345
1346 exist = set_get(link->ndisc_pref64,
1347 &(NDiscPREF64) {
1348 .prefix = a,
1349 .prefix_len = prefix_len
1350 });
1351 if (exist) {
1352 /* update existing entry */
1353 exist->router = router;
1354 exist->lifetime_usec = lifetime_usec;
1355 return 0;
1356 }
1357
1358 if (set_size(link->ndisc_pref64) >= NDISC_PREF64_MAX) {
1359 log_link_debug(link, "Too many PREF64 records received. Only first %u records will be used.", NDISC_PREF64_MAX);
1360 return 0;
1361 }
1362
1363 new_entry = new(NDiscPREF64, 1);
1364 if (!new_entry)
1365 return log_oom();
1366
1367 *new_entry = (NDiscPREF64) {
1368 .router = router,
1369 .lifetime_usec = lifetime_usec,
1370 .prefix = a,
1371 .prefix_len = prefix_len,
1372 };
1373
1374 r = set_ensure_put(&link->ndisc_pref64, &ndisc_pref64_hash_ops, new_entry);
1375 if (r < 0)
1376 return log_oom();
1377
1378 assert(r > 0);
1379 TAKE_PTR(new_entry);
1380
1381 return 0;
1382 }
1383
1384 static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
1385 size_t n_captive_portal = 0;
1386 int r;
1387
1388 assert(link);
1389 assert(link->network);
1390 assert(rt);
1391
1392 for (r = sd_ndisc_router_option_rewind(rt); ; r = sd_ndisc_router_option_next(rt)) {
1393 uint8_t type;
1394
1395 if (r < 0)
1396 return log_link_warning_errno(link, r, "Failed to iterate through options: %m");
1397 if (r == 0) /* EOF */
1398 return 0;
1399
1400 r = sd_ndisc_router_option_get_type(rt, &type);
1401 if (r < 0)
1402 return log_link_warning_errno(link, r, "Failed to get RA option type: %m");
1403
1404 switch (type) {
1405 case SD_NDISC_OPTION_PREFIX_INFORMATION:
1406 r = ndisc_router_process_prefix(link, rt);
1407 break;
1408
1409 case SD_NDISC_OPTION_ROUTE_INFORMATION:
1410 r = ndisc_router_process_route(link, rt);
1411 break;
1412
1413 case SD_NDISC_OPTION_RDNSS:
1414 r = ndisc_router_process_rdnss(link, rt);
1415 break;
1416
1417 case SD_NDISC_OPTION_DNSSL:
1418 r = ndisc_router_process_dnssl(link, rt);
1419 break;
1420 case SD_NDISC_OPTION_CAPTIVE_PORTAL:
1421 if (n_captive_portal > 0) {
1422 if (n_captive_portal == 1)
1423 log_link_notice(link, "Received RA with multiple captive portals, only using the first one.");
1424
1425 n_captive_portal++;
1426 continue;
1427 }
1428 r = ndisc_router_process_captive_portal(link, rt);
1429 if (r > 0)
1430 n_captive_portal++;
1431 break;
1432 case SD_NDISC_OPTION_PREF64:
1433 r = ndisc_router_process_pref64(link, rt);
1434 break;
1435 }
1436 if (r < 0 && r != -EBADMSG)
1437 return r;
1438 }
1439 }
1440
1441 static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec) {
1442 bool updated = false;
1443 NDiscDNSSL *dnssl;
1444 NDiscRDNSS *rdnss;
1445 NDiscCaptivePortal *cp;
1446 NDiscPREF64 *p64;
1447 Address *address;
1448 Route *route;
1449 int r, ret = 0;
1450
1451 assert(link);
1452 assert(link->manager);
1453
1454 /* If an address or friends is already assigned, but not valid anymore, then refuse to update it,
1455 * and let's immediately remove it.
1456 * See RFC4862, section 5.5.3.e. But the following logic is deviated from RFC4862 by honoring all
1457 * valid lifetimes to improve the reaction of SLAAC to renumbering events.
1458 * See draft-ietf-6man-slaac-renum-02, section 4.2. */
1459
1460 SET_FOREACH(route, link->manager->routes) {
1461 if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
1462 continue;
1463
1464 if (route->nexthop.ifindex != link->ifindex)
1465 continue;
1466
1467 if (route->lifetime_usec >= timestamp_usec)
1468 continue; /* the route is still valid */
1469
1470 r = route_remove_and_cancel(route, link->manager);
1471 if (r < 0)
1472 RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to remove outdated SLAAC route, ignoring: %m"));
1473 }
1474
1475 SET_FOREACH(address, link->addresses) {
1476 if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
1477 continue;
1478
1479 if (address->lifetime_valid_usec >= timestamp_usec)
1480 continue; /* the address is still valid */
1481
1482 r = address_remove_and_cancel(address, link);
1483 if (r < 0)
1484 RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to remove outdated SLAAC address, ignoring: %m"));
1485 }
1486
1487 SET_FOREACH(rdnss, link->ndisc_rdnss) {
1488 if (rdnss->lifetime_usec >= timestamp_usec)
1489 continue; /* the DNS server is still valid */
1490
1491 free(set_remove(link->ndisc_rdnss, rdnss));
1492 updated = true;
1493 }
1494
1495 SET_FOREACH(dnssl, link->ndisc_dnssl) {
1496 if (dnssl->lifetime_usec >= timestamp_usec)
1497 continue; /* the DNS domain is still valid */
1498
1499 free(set_remove(link->ndisc_dnssl, dnssl));
1500 updated = true;
1501 }
1502
1503 SET_FOREACH(cp, link->ndisc_captive_portals) {
1504 if (cp->lifetime_usec >= timestamp_usec)
1505 continue; /* the captive portal is still valid */
1506
1507 ndisc_captive_portal_free(set_remove(link->ndisc_captive_portals, cp));
1508 updated = true;
1509 }
1510
1511 SET_FOREACH(p64, link->ndisc_pref64) {
1512 if (p64->lifetime_usec >= timestamp_usec)
1513 continue; /* the pref64 prefix is still valid */
1514
1515 free(set_remove(link->ndisc_pref64, p64));
1516 /* The pref64 prefix is not exported through the state file, hence it is not necessary to set
1517 * the 'updated' flag. */
1518 }
1519
1520 if (updated)
1521 link_dirty(link);
1522
1523 return ret;
1524 }
1525
1526 static int ndisc_setup_expire(Link *link);
1527
1528 static int ndisc_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
1529 Link *link = ASSERT_PTR(userdata);
1530 usec_t now_usec;
1531
1532 assert(link->manager);
1533
1534 assert_se(sd_event_now(link->manager->event, CLOCK_BOOTTIME, &now_usec) >= 0);
1535
1536 (void) ndisc_drop_outdated(link, now_usec);
1537 (void) ndisc_setup_expire(link);
1538 return 0;
1539 }
1540
1541 static int ndisc_setup_expire(Link *link) {
1542 usec_t lifetime_usec = USEC_INFINITY;
1543 NDiscCaptivePortal *cp;
1544 NDiscDNSSL *dnssl;
1545 NDiscRDNSS *rdnss;
1546 NDiscPREF64 *p64;
1547 Address *address;
1548 Route *route;
1549 int r;
1550
1551 assert(link);
1552 assert(link->manager);
1553
1554 SET_FOREACH(route, link->manager->routes) {
1555 if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
1556 continue;
1557
1558 if (route->nexthop.ifindex != link->ifindex)
1559 continue;
1560
1561 if (!route_exists(route))
1562 continue;
1563
1564 lifetime_usec = MIN(lifetime_usec, route->lifetime_usec);
1565 }
1566
1567 SET_FOREACH(address, link->addresses) {
1568 if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
1569 continue;
1570
1571 if (!address_exists(address))
1572 continue;
1573
1574 lifetime_usec = MIN(lifetime_usec, address->lifetime_valid_usec);
1575 }
1576
1577 SET_FOREACH(rdnss, link->ndisc_rdnss)
1578 lifetime_usec = MIN(lifetime_usec, rdnss->lifetime_usec);
1579
1580 SET_FOREACH(dnssl, link->ndisc_dnssl)
1581 lifetime_usec = MIN(lifetime_usec, dnssl->lifetime_usec);
1582
1583 SET_FOREACH(cp, link->ndisc_captive_portals)
1584 lifetime_usec = MIN(lifetime_usec, cp->lifetime_usec);
1585
1586 SET_FOREACH(p64, link->ndisc_pref64)
1587 lifetime_usec = MIN(lifetime_usec, p64->lifetime_usec);
1588
1589 if (lifetime_usec == USEC_INFINITY)
1590 return 0;
1591
1592 r = event_reset_time(link->manager->event, &link->ndisc_expire, CLOCK_BOOTTIME,
1593 lifetime_usec, 0, ndisc_expire_handler, link, 0, "ndisc-expiration", true);
1594 if (r < 0)
1595 return log_link_warning_errno(link, r, "Failed to update expiration timer for ndisc: %m");
1596
1597 return 0;
1598 }
1599
1600 static int ndisc_start_dhcp6_client(Link *link, sd_ndisc_router *rt) {
1601 int r;
1602
1603 assert(link);
1604 assert(link->network);
1605
1606 /* Do not start DHCPv6 client if the router lifetime is zero, as the message sent as a signal of
1607 * that the router is e.g. shutting down, revoked, etc,. */
1608 r = sd_ndisc_router_get_lifetime(rt, NULL);
1609 if (r <= 0)
1610 return r;
1611
1612 switch (link->network->ipv6_accept_ra_start_dhcp6_client) {
1613 case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO:
1614 return 0;
1615
1616 case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES: {
1617 uint64_t flags;
1618
1619 r = sd_ndisc_router_get_flags(rt, &flags);
1620 if (r < 0)
1621 return log_link_warning_errno(link, r, "Failed to get RA flags: %m");
1622
1623 if ((flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) == 0)
1624 return 0;
1625
1626 /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags.
1627 * Note, if both "managed" and "other configuration" bits are set, then ignore
1628 * "other configuration" bit. See RFC 4861. */
1629 r = dhcp6_start_on_ra(link, !(flags & ND_RA_FLAG_MANAGED));
1630 break;
1631 }
1632 case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS:
1633 /* When IPv6AcceptRA.DHCPv6Client=always, start dhcp6 client in solicit mode
1634 * even if the router flags have neither M nor O flags. */
1635 r = dhcp6_start_on_ra(link, /* information_request = */ false);
1636 break;
1637
1638 default:
1639 assert_not_reached();
1640 }
1641
1642 if (r < 0)
1643 return log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m");
1644
1645 log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request");
1646 return 0;
1647 }
1648
1649 static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
1650 struct in6_addr router;
1651 usec_t timestamp_usec;
1652 int r;
1653
1654 assert(link);
1655 assert(link->network);
1656 assert(link->manager);
1657 assert(rt);
1658
1659 r = sd_ndisc_router_get_address(rt, &router);
1660 if (r == -ENODATA) {
1661 log_link_debug(link, "Received RA without router address, ignoring.");
1662 return 0;
1663 }
1664 if (r < 0)
1665 return log_link_warning_errno(link, r, "Failed to get router address from RA: %m");
1666
1667 if (in6_prefix_is_filtered(&router, 128, link->network->ndisc_allow_listed_router, link->network->ndisc_deny_listed_router)) {
1668 if (DEBUG_LOGGING) {
1669 if (!set_isempty(link->network->ndisc_allow_listed_router))
1670 log_link_debug(link, "Router %s is not in allow list, ignoring.", IN6_ADDR_TO_STRING(&router));
1671 else
1672 log_link_debug(link, "Router %s is in deny list, ignoring.", IN6_ADDR_TO_STRING(&router));
1673 }
1674 return 0;
1675 }
1676
1677 r = sd_ndisc_router_get_timestamp(rt, CLOCK_BOOTTIME, &timestamp_usec);
1678 if (r == -ENODATA) {
1679 log_link_debug(link, "Received RA without timestamp, ignoring.");
1680 return 0;
1681 }
1682 if (r < 0)
1683 return r;
1684
1685 r = ndisc_drop_outdated(link, timestamp_usec);
1686 if (r < 0)
1687 return r;
1688
1689 r = ndisc_start_dhcp6_client(link, rt);
1690 if (r < 0)
1691 return r;
1692
1693 r = ndisc_router_process_default(link, rt);
1694 if (r < 0)
1695 return r;
1696
1697 r = ndisc_router_process_icmp6_ratelimit(link, rt);
1698 if (r < 0)
1699 return r;
1700
1701 r = ndisc_router_process_reachable_time(link, rt);
1702 if (r < 0)
1703 return r;
1704
1705 r = ndisc_router_process_retransmission_time(link, rt);
1706 if (r < 0)
1707 return r;
1708
1709 r = ndisc_router_process_hop_limit(link, rt);
1710 if (r < 0)
1711 return r;
1712
1713 r = ndisc_router_process_options(link, rt);
1714 if (r < 0)
1715 return r;
1716
1717 r = ndisc_setup_expire(link);
1718 if (r < 0)
1719 return r;
1720
1721 if (link->ndisc_messages == 0)
1722 link->ndisc_configured = true;
1723 else
1724 log_link_debug(link, "Setting SLAAC addresses and router.");
1725
1726 if (!link->ndisc_configured)
1727 link_set_state(link, LINK_STATE_CONFIGURING);
1728
1729 link_check_ready(link);
1730 return 0;
1731 }
1732
1733 static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata) {
1734 Link *link = ASSERT_PTR(userdata);
1735 int r;
1736
1737 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
1738 return;
1739
1740 switch (event) {
1741
1742 case SD_NDISC_EVENT_ROUTER:
1743 r = ndisc_router_handler(link, rt);
1744 if (r < 0 && r != -EBADMSG) {
1745 link_enter_failed(link);
1746 return;
1747 }
1748 break;
1749
1750 case SD_NDISC_EVENT_TIMEOUT:
1751 log_link_debug(link, "NDisc handler get timeout event");
1752 if (link->ndisc_messages == 0) {
1753 link->ndisc_configured = true;
1754 link_check_ready(link);
1755 }
1756 break;
1757 default:
1758 assert_not_reached();
1759 }
1760 }
1761
1762 static int ndisc_configure(Link *link) {
1763 int r;
1764
1765 assert(link);
1766
1767 if (!link_ipv6_accept_ra_enabled(link))
1768 return 0;
1769
1770 if (link->ndisc)
1771 return -EBUSY; /* Already configured. */
1772
1773 r = sd_ndisc_new(&link->ndisc);
1774 if (r < 0)
1775 return r;
1776
1777 r = sd_ndisc_attach_event(link->ndisc, link->manager->event, 0);
1778 if (r < 0)
1779 return r;
1780
1781 if (link->hw_addr.length == ETH_ALEN) {
1782 r = sd_ndisc_set_mac(link->ndisc, &link->hw_addr.ether);
1783 if (r < 0)
1784 return r;
1785 }
1786
1787 r = sd_ndisc_set_ifindex(link->ndisc, link->ifindex);
1788 if (r < 0)
1789 return r;
1790
1791 r = sd_ndisc_set_callback(link->ndisc, ndisc_handler, link);
1792 if (r < 0)
1793 return r;
1794
1795 return 0;
1796 }
1797
1798 int ndisc_start(Link *link) {
1799 int r;
1800
1801 assert(link);
1802
1803 if (!link->ndisc || !link->dhcp6_client)
1804 return 0;
1805
1806 if (!link_has_carrier(link))
1807 return 0;
1808
1809 if (in6_addr_is_null(&link->ipv6ll_address))
1810 return 0;
1811
1812 log_link_debug(link, "Discovering IPv6 routers");
1813
1814 r = sd_ndisc_start(link->ndisc);
1815 if (r < 0)
1816 return r;
1817
1818 return 1;
1819 }
1820
1821 static int ndisc_process_request(Request *req, Link *link, void *userdata) {
1822 int r;
1823
1824 assert(link);
1825
1826 if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ false))
1827 return 0;
1828
1829 r = ndisc_configure(link);
1830 if (r < 0)
1831 return log_link_warning_errno(link, r, "Failed to configure IPv6 Router Discovery: %m");
1832
1833 r = ndisc_start(link);
1834 if (r < 0)
1835 return log_link_warning_errno(link, r, "Failed to start IPv6 Router Discovery: %m");
1836
1837 log_link_debug(link, "IPv6 Router Discovery is configured%s.",
1838 r > 0 ? " and started" : "");
1839 return 1;
1840 }
1841
1842 int link_request_ndisc(Link *link) {
1843 int r;
1844
1845 assert(link);
1846
1847 if (!link_ipv6_accept_ra_enabled(link))
1848 return 0;
1849
1850 if (link->ndisc)
1851 return 0;
1852
1853 r = link_queue_request(link, REQUEST_TYPE_NDISC, ndisc_process_request, NULL);
1854 if (r < 0)
1855 return log_link_warning_errno(link, r, "Failed to request configuring of the IPv6 Router Discovery: %m");
1856
1857 log_link_debug(link, "Requested configuring of the IPv6 Router Discovery.");
1858 return 0;
1859 }
1860
1861 int ndisc_stop(Link *link) {
1862 assert(link);
1863
1864 link->ndisc_expire = sd_event_source_disable_unref(link->ndisc_expire);
1865
1866 return sd_ndisc_stop(link->ndisc);
1867 }
1868
1869
1870 void ndisc_flush(Link *link) {
1871 assert(link);
1872
1873 /* Remove all addresses, routes, RDNSS, DNSSL, and Captive Portal entries, without exception. */
1874 (void) ndisc_drop_outdated(link, /* timestamp_usec = */ USEC_INFINITY);
1875
1876 link->ndisc_rdnss = set_free(link->ndisc_rdnss);
1877 link->ndisc_dnssl = set_free(link->ndisc_dnssl);
1878 link->ndisc_captive_portals = set_free(link->ndisc_captive_portals);
1879 link->ndisc_pref64 = set_free(link->ndisc_pref64);
1880 }
1881
1882 static const char* const ipv6_accept_ra_start_dhcp6_client_table[_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_MAX] = {
1883 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO] = "no",
1884 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS] = "always",
1885 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES] = "yes",
1886 };
1887
1888 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client, IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES);
1889
1890 DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_use_domains, dhcp_use_domains, DHCPUseDomains,
1891 "Failed to parse UseDomains= setting");
1892 DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_start_dhcp6_client, ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client,
1893 "Failed to parse DHCPv6Client= setting");