1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2014 Intel Corporation. All rights reserved.
7 #include <netinet/icmp6.h>
9 #include <linux/if_arp.h>
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 "networkd-sysctl.h"
24 #include "string-table.h"
25 #include "string-util.h"
27 #include "sysctl-util.h"
29 #define NDISC_DNSSL_MAX 64U
30 #define NDISC_RDNSS_MAX 64U
31 /* Not defined in the RFC, but let's set an upper limit to make not consume much memory.
32 * This should be safe as typically there should be at most 1 portal per network. */
33 #define NDISC_CAPTIVE_PORTAL_MAX 64U
34 /* Neither defined in the RFC. Just for safety. Otherwise, malformed messages can make clients trigger OOM.
35 * Not sure if the threshold is high enough. Let's adjust later if not. */
36 #define NDISC_PREF64_MAX 64U
38 bool link_ipv6_accept_ra_enabled(Link
*link
) {
41 if (!socket_ipv6_is_supported())
44 if (link
->flags
& IFF_LOOPBACK
)
47 if (link
->iftype
== ARPHRD_CAN
)
53 if (!link_may_have_ipv6ll(link
, /* check_multicast = */ true))
56 if (link
->network
->ipv6_accept_ra
>= 0)
57 return link
->network
->ipv6_accept_ra
;
59 /* Accept RAs if IPv6 forwarding is disabled, and ignore RAs if IPv6 forwarding is enabled. */
60 int t
= link_get_ip_forwarding(link
, AF_INET6
);
64 /* Otherwise, defaults to true. */
68 void network_adjust_ipv6_accept_ra(Network
*network
) {
71 if (!FLAGS_SET(network
->link_local
, ADDRESS_FAMILY_IPV6
)) {
72 if (network
->ipv6_accept_ra
> 0)
73 log_warning("%s: IPv6AcceptRA= is enabled but IPv6 link-local addressing is disabled or not supported. "
74 "Disabling IPv6AcceptRA=.", network
->filename
);
75 network
->ipv6_accept_ra
= false;
78 /* When RouterAllowList=, PrefixAllowList= or RouteAllowList= are specified, then
79 * RouterDenyList=, PrefixDenyList= or RouteDenyList= are ignored, respectively. */
80 if (!set_isempty(network
->ndisc_allow_listed_router
))
81 network
->ndisc_deny_listed_router
= set_free_free(network
->ndisc_deny_listed_router
);
82 if (!set_isempty(network
->ndisc_allow_listed_prefix
))
83 network
->ndisc_deny_listed_prefix
= set_free_free(network
->ndisc_deny_listed_prefix
);
84 if (!set_isempty(network
->ndisc_allow_listed_route_prefix
))
85 network
->ndisc_deny_listed_route_prefix
= set_free_free(network
->ndisc_deny_listed_route_prefix
);
88 static int ndisc_check_ready(Link
*link
);
90 static int ndisc_address_ready_callback(Address
*address
) {
94 assert(address
->link
);
96 SET_FOREACH(a
, address
->link
->addresses
)
97 if (a
->source
== NETWORK_CONFIG_SOURCE_NDISC
)
100 return ndisc_check_ready(address
->link
);
103 static int ndisc_check_ready(Link
*link
) {
104 bool found
= false, ready
= false;
109 if (link
->ndisc_messages
> 0) {
110 log_link_debug(link
, "%s(): SLAAC addresses and routes are not set.", __func__
);
114 SET_FOREACH(address
, link
->addresses
) {
115 if (address
->source
!= NETWORK_CONFIG_SOURCE_NDISC
)
120 if (address_is_ready(address
)) {
126 if (found
&& !ready
) {
127 SET_FOREACH(address
, link
->addresses
)
128 if (address
->source
== NETWORK_CONFIG_SOURCE_NDISC
)
129 address
->callback
= ndisc_address_ready_callback
;
131 log_link_debug(link
, "%s(): no SLAAC address is ready.", __func__
);
135 link
->ndisc_configured
= true;
136 log_link_debug(link
, "SLAAC addresses and routes set.");
138 link_check_ready(link
);
142 static int ndisc_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Route
*route
) {
147 r
= route_configure_handler_internal(rtnl
, m
, link
, route
, "Could not set NDisc route");
151 r
= ndisc_check_ready(link
);
153 link_enter_failed(link
);
158 static void ndisc_set_route_priority(Link
*link
, Route
*route
) {
162 if (route
->priority_set
)
163 return; /* explicitly configured. */
165 switch (route
->pref
) {
166 case SD_NDISC_PREFERENCE_LOW
:
167 route
->priority
= link
->network
->ipv6_accept_ra_route_metric_low
;
169 case SD_NDISC_PREFERENCE_MEDIUM
:
170 route
->priority
= link
->network
->ipv6_accept_ra_route_metric_medium
;
172 case SD_NDISC_PREFERENCE_HIGH
:
173 route
->priority
= link
->network
->ipv6_accept_ra_route_metric_high
;
176 assert_not_reached();
180 static int ndisc_request_route(Route
*route
, Link
*link
, sd_ndisc_router
*rt
) {
181 struct in6_addr router
;
182 uint8_t hop_limit
= 0;
189 assert(link
->manager
);
190 assert(link
->network
);
193 r
= sd_ndisc_router_get_address(rt
, &router
);
197 if (link
->network
->ipv6_accept_ra_use_mtu
) {
198 r
= sd_ndisc_router_get_mtu(rt
, &mtu
);
199 if (r
< 0 && r
!= -ENODATA
)
200 return log_link_warning_errno(link
, r
, "Failed to get MTU from RA: %m");
203 if (link
->network
->ipv6_accept_ra_use_hop_limit
) {
204 r
= sd_ndisc_router_get_hop_limit(rt
, &hop_limit
);
205 if (r
< 0 && r
!= -ENODATA
)
206 return log_link_warning_errno(link
, r
, "Failed to get hop limit from RA: %m");
209 route
->source
= NETWORK_CONFIG_SOURCE_NDISC
;
210 route
->provider
.in6
= router
;
211 if (!route
->table_set
)
212 route
->table
= link_get_ipv6_accept_ra_route_table(link
);
213 if (!route
->protocol_set
)
214 route
->protocol
= RTPROT_RA
;
215 r
= route_metric_set(&route
->metric
, RTAX_MTU
, mtu
);
218 r
= route_metric_set(&route
->metric
, RTAX_HOPLIMIT
, hop_limit
);
221 r
= route_metric_set(&route
->metric
, RTAX_QUICKACK
, link
->network
->ipv6_accept_ra_quickack
);
225 r
= route_adjust_nexthops(route
, link
);
229 uint8_t pref
, pref_original
= route
->pref
;
230 FOREACH_ARGUMENT(pref
, SD_NDISC_PREFERENCE_LOW
, SD_NDISC_PREFERENCE_MEDIUM
, SD_NDISC_PREFERENCE_HIGH
) {
234 /* If the preference is specified by the user config (that is, for semi-static routes),
235 * rather than RA, then only search conflicting routes that have the same preference. */
236 if (route
->pref_set
&& pref
!= pref_original
)
240 ndisc_set_route_priority(link
, route
);
242 /* Note, here do not call route_remove_and_cancel() with 'route' directly, otherwise
243 * existing route(s) may be removed needlessly. */
245 if (route_get(link
->manager
, route
, &existing
) >= 0) {
246 /* Found an existing route that may conflict with this route. */
247 if (!route_can_update(existing
, route
)) {
248 log_link_debug(link
, "Found an existing route that conflicts with new route based on a received RA, removing.");
249 r
= route_remove_and_cancel(existing
, link
->manager
);
255 if (route_get_request(link
->manager
, route
, &req
) >= 0) {
256 existing
= ASSERT_PTR(req
->userdata
);
257 if (!route_can_update(existing
, route
)) {
258 log_link_debug(link
, "Found a pending route request that conflicts with new request based on a received RA, cancelling.");
259 r
= route_remove_and_cancel(existing
, link
->manager
);
266 /* The preference (and priority) may be changed in the above loop. Restore it. */
267 route
->pref
= pref_original
;
268 ndisc_set_route_priority(link
, route
);
270 is_new
= route_get(link
->manager
, route
, NULL
) < 0;
272 r
= link_request_route(link
, route
, &link
->ndisc_messages
, ndisc_route_handler
);
276 link
->ndisc_configured
= false;
281 static int ndisc_remove_route(Route
*route
, Link
*link
) {
286 assert(link
->manager
);
288 ndisc_set_route_priority(link
, route
);
290 if (!route
->table_set
)
291 route
->table
= link_get_ipv6_accept_ra_route_table(link
);
293 r
= route_adjust_nexthops(route
, link
);
297 if (route
->pref_set
) {
298 ndisc_set_route_priority(link
, route
);
299 return route_remove_and_cancel(route
, link
->manager
);
303 FOREACH_ARGUMENT(pref
, SD_NDISC_PREFERENCE_LOW
, SD_NDISC_PREFERENCE_MEDIUM
, SD_NDISC_PREFERENCE_HIGH
) {
305 ndisc_set_route_priority(link
, route
);
306 r
= route_remove_and_cancel(route
, link
->manager
);
314 static int ndisc_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Address
*address
) {
319 r
= address_configure_handler_internal(rtnl
, m
, link
, "Could not set NDisc address");
323 r
= ndisc_check_ready(link
);
325 link_enter_failed(link
);
330 static int ndisc_request_address(Address
*address
, Link
*link
, sd_ndisc_router
*rt
) {
331 struct in6_addr router
;
339 r
= sd_ndisc_router_get_address(rt
, &router
);
343 address
->source
= NETWORK_CONFIG_SOURCE_NDISC
;
344 address
->provider
.in6
= router
;
346 r
= free_and_strdup_warn(&address
->netlabel
, link
->network
->ndisc_netlabel
);
351 if (address_get_harder(link
, address
, &existing
) < 0)
353 else if (address_can_update(existing
, address
))
355 else if (existing
->source
== NETWORK_CONFIG_SOURCE_DHCP6
) {
356 /* SLAAC address is preferred over DHCPv6 address. */
357 log_link_debug(link
, "Conflicting DHCPv6 address %s exists, removing.",
358 IN_ADDR_PREFIX_TO_STRING(existing
->family
, &existing
->in_addr
, existing
->prefixlen
));
359 r
= address_remove(existing
, link
);
365 /* Conflicting static address is configured?? */
366 log_link_debug(link
, "Conflicting address %s exists, ignoring request.",
367 IN_ADDR_PREFIX_TO_STRING(existing
->family
, &existing
->in_addr
, existing
->prefixlen
));
371 r
= link_request_address(link
, address
, &link
->ndisc_messages
,
372 ndisc_address_handler
, NULL
);
376 link
->ndisc_configured
= false;
381 static int ndisc_router_drop_default(Link
*link
, sd_ndisc_router
*rt
) {
382 _cleanup_(route_unrefp
) Route
*route
= NULL
;
383 struct in6_addr gateway
;
387 assert(link
->network
);
390 r
= sd_ndisc_router_get_address(rt
, &gateway
);
392 return log_link_warning_errno(link
, r
, "Failed to get router address from RA: %m");
394 r
= route_new(&route
);
398 route
->family
= AF_INET6
;
399 route
->nexthop
.family
= AF_INET6
;
400 route
->nexthop
.gw
.in6
= gateway
;
402 r
= ndisc_remove_route(route
, link
);
404 return log_link_warning_errno(link
, r
, "Failed to remove the default gateway configured by RA: %m");
407 HASHMAP_FOREACH(route_gw
, link
->network
->routes_by_section
) {
408 _cleanup_(route_unrefp
) Route
*tmp
= NULL
;
410 if (!route_gw
->gateway_from_dhcp_or_ra
)
413 if (route_gw
->nexthop
.family
!= AF_INET6
)
416 r
= route_dup(route_gw
, NULL
, &tmp
);
420 tmp
->nexthop
.gw
.in6
= gateway
;
422 r
= ndisc_remove_route(tmp
, link
);
424 return log_link_warning_errno(link
, r
, "Could not remove semi-static gateway: %m");
430 static int ndisc_router_process_default(Link
*link
, sd_ndisc_router
*rt
) {
431 usec_t lifetime_usec
;
432 struct in6_addr gateway
;
437 assert(link
->network
);
440 /* If the router lifetime is zero, the router should not be used as the default gateway. */
441 r
= sd_ndisc_router_get_lifetime(rt
, NULL
);
445 return ndisc_router_drop_default(link
, rt
);
447 if (!link
->network
->ipv6_accept_ra_use_gateway
&&
448 hashmap_isempty(link
->network
->routes_by_section
))
451 r
= sd_ndisc_router_get_lifetime_timestamp(rt
, CLOCK_BOOTTIME
, &lifetime_usec
);
453 return log_link_warning_errno(link
, r
, "Failed to get gateway lifetime from RA: %m");
455 r
= sd_ndisc_router_get_address(rt
, &gateway
);
457 return log_link_warning_errno(link
, r
, "Failed to get gateway address from RA: %m");
459 if (link_get_ipv6_address(link
, &gateway
, 0, NULL
) >= 0) {
461 log_link_debug(link
, "No NDisc route added, gateway %s matches local address",
462 IN6_ADDR_TO_STRING(&gateway
));
466 r
= sd_ndisc_router_get_preference(rt
, &preference
);
468 return log_link_warning_errno(link
, r
, "Failed to get router preference from RA: %m");
470 if (link
->network
->ipv6_accept_ra_use_gateway
) {
471 _cleanup_(route_unrefp
) Route
*route
= NULL
;
473 r
= route_new(&route
);
477 route
->family
= AF_INET6
;
478 route
->pref
= preference
;
479 route
->nexthop
.family
= AF_INET6
;
480 route
->nexthop
.gw
.in6
= gateway
;
481 route
->lifetime_usec
= lifetime_usec
;
483 r
= ndisc_request_route(route
, link
, rt
);
485 return log_link_warning_errno(link
, r
, "Could not request default route: %m");
489 HASHMAP_FOREACH(route_gw
, link
->network
->routes_by_section
) {
490 _cleanup_(route_unrefp
) Route
*route
= NULL
;
492 if (!route_gw
->gateway_from_dhcp_or_ra
)
495 if (route_gw
->nexthop
.family
!= AF_INET6
)
498 r
= route_dup(route_gw
, NULL
, &route
);
502 route
->nexthop
.gw
.in6
= gateway
;
503 if (!route
->pref_set
)
504 route
->pref
= preference
;
505 route
->lifetime_usec
= lifetime_usec
;
507 r
= ndisc_request_route(route
, link
, rt
);
509 return log_link_warning_errno(link
, r
, "Could not request gateway: %m");
515 static int ndisc_router_process_icmp6_ratelimit(Link
*link
, sd_ndisc_router
*rt
) {
516 usec_t icmp6_ratelimit
, msec
;
520 assert(link
->network
);
523 if (!link
->network
->ipv6_accept_ra_use_icmp6_ratelimit
)
526 /* Ignore the icmp6 ratelimit field of the RA header if the lifetime is zero. */
527 r
= sd_ndisc_router_get_lifetime(rt
, NULL
);
531 r
= sd_ndisc_router_get_icmp6_ratelimit(rt
, &icmp6_ratelimit
);
533 return log_link_warning_errno(link
, r
, "Failed to get ICMP6 ratelimit from RA: %m");
535 /* We do not allow 0 here. */
536 if (!timestamp_is_set(icmp6_ratelimit
))
539 msec
= DIV_ROUND_UP(icmp6_ratelimit
, USEC_PER_MSEC
);
540 if (msec
<= 0 || msec
> INT_MAX
)
543 /* Limit the maximal rates for sending ICMPv6 packets. 0 to disable any limiting, otherwise the
544 * minimal space between responses in milliseconds. Default: 1000. */
545 r
= sysctl_write_ip_property_int(AF_INET6
, NULL
, "icmp/ratelimit", (int) msec
);
547 log_link_warning_errno(link
, r
, "Failed to apply ICMP6 ratelimit, ignoring: %m");
552 static int ndisc_router_process_reachable_time(Link
*link
, sd_ndisc_router
*rt
) {
553 usec_t reachable_time
, msec
;
557 assert(link
->network
);
560 if (!link
->network
->ipv6_accept_ra_use_reachable_time
)
563 /* Ignore the reachable time field of the RA header if the lifetime is zero. */
564 r
= sd_ndisc_router_get_lifetime(rt
, NULL
);
568 r
= sd_ndisc_router_get_reachable_time(rt
, &reachable_time
);
570 return log_link_warning_errno(link
, r
, "Failed to get reachable time from RA: %m");
572 /* 0 is the unspecified value and must not be set (see RFC4861, 6.3.4) */
573 if (!timestamp_is_set(reachable_time
))
576 msec
= DIV_ROUND_UP(reachable_time
, USEC_PER_MSEC
);
577 if (msec
<= 0 || msec
> UINT32_MAX
) {
578 log_link_debug(link
, "Failed to get reachable time from RA - out of range (%"PRIu64
"), ignoring", msec
);
582 /* Set the reachable time for Neighbor Solicitations. */
583 r
= sysctl_write_ip_neighbor_property_uint32(AF_INET6
, link
->ifname
, "base_reachable_time_ms", (uint32_t) msec
);
585 log_link_warning_errno(link
, r
, "Failed to apply neighbor reachable time (%"PRIu64
"), ignoring: %m", msec
);
590 static int ndisc_router_process_retransmission_time(Link
*link
, sd_ndisc_router
*rt
) {
591 usec_t retrans_time
, msec
;
595 assert(link
->network
);
598 if (!link
->network
->ipv6_accept_ra_use_retransmission_time
)
601 /* Ignore the retransmission time field of the RA header if the lifetime is zero. */
602 r
= sd_ndisc_router_get_lifetime(rt
, NULL
);
606 r
= sd_ndisc_router_get_retransmission_time(rt
, &retrans_time
);
608 return log_link_warning_errno(link
, r
, "Failed to get retransmission time from RA: %m");
610 /* 0 is the unspecified value and must not be set (see RFC4861, 6.3.4) */
611 if (!timestamp_is_set(retrans_time
))
614 msec
= DIV_ROUND_UP(retrans_time
, USEC_PER_MSEC
);
615 if (msec
<= 0 || msec
> UINT32_MAX
) {
616 log_link_debug(link
, "Failed to get retransmission time from RA - out of range (%"PRIu64
"), ignoring", msec
);
620 /* Set the retransmission time for Neighbor Solicitations. */
621 r
= sysctl_write_ip_neighbor_property_uint32(AF_INET6
, link
->ifname
, "retrans_time_ms", (uint32_t) msec
);
623 log_link_warning_errno(link
, r
, "Failed to apply neighbor retransmission time (%"PRIu64
"), ignoring: %m", msec
);
628 static int ndisc_router_process_hop_limit(Link
*link
, sd_ndisc_router
*rt
) {
633 assert(link
->network
);
636 if (!link
->network
->ipv6_accept_ra_use_hop_limit
)
639 /* Ignore the hop limit field of the RA header if the lifetime is zero. */
640 r
= sd_ndisc_router_get_lifetime(rt
, NULL
);
644 r
= sd_ndisc_router_get_hop_limit(rt
, &hop_limit
);
646 return log_link_warning_errno(link
, r
, "Failed to get hop limit from RA: %m");
648 /* 0 is the unspecified value and must not be set (see RFC4861, 6.3.4):
650 * A Router Advertisement field (e.g., Cur Hop Limit, Reachable Time, and Retrans Timer) may contain
651 * a value denoting that it is unspecified. In such cases, the parameter should be ignored and the
652 * host should continue using whatever value it is already using. In particular, a host MUST NOT
653 * interpret the unspecified value as meaning change back to the default value that was in use before
654 * the first Router Advertisement was received.
656 * If the received Cur Hop Limit value is non-zero, the host SHOULD set
657 * its CurHopLimit variable to the received value.*/
661 r
= sysctl_write_ip_property_uint32(AF_INET6
, link
->ifname
, "hop_limit", (uint32_t) hop_limit
);
663 log_link_warning_errno(link
, r
, "Failed to apply hop_limit (%u), ignoring: %m", hop_limit
);
668 static int ndisc_router_process_autonomous_prefix(Link
*link
, sd_ndisc_router
*rt
) {
669 usec_t lifetime_valid_usec
, lifetime_preferred_usec
;
670 _cleanup_set_free_ Set
*addresses
= NULL
;
671 struct in6_addr prefix
, *a
;
676 assert(link
->network
);
679 if (!link
->network
->ipv6_accept_ra_use_autonomous_prefix
)
682 r
= sd_ndisc_router_prefix_get_address(rt
, &prefix
);
684 return log_link_warning_errno(link
, r
, "Failed to get prefix address: %m");
686 r
= sd_ndisc_router_prefix_get_prefixlen(rt
, &prefixlen
);
688 return log_link_warning_errno(link
, r
, "Failed to get prefix length: %m");
690 /* ndisc_generate_addresses() below requires the prefix length <= 64. */
691 if (prefixlen
> 64) {
692 log_link_debug(link
, "Prefix is longer than 64, ignoring autonomous prefix %s.",
693 IN6_ADDR_PREFIX_TO_STRING(&prefix
, prefixlen
));
697 r
= sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt
, CLOCK_BOOTTIME
, &lifetime_valid_usec
);
699 return log_link_warning_errno(link
, r
, "Failed to get prefix valid lifetime: %m");
701 r
= sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(rt
, CLOCK_BOOTTIME
, &lifetime_preferred_usec
);
703 return log_link_warning_errno(link
, r
, "Failed to get prefix preferred lifetime: %m");
705 /* The preferred lifetime is never greater than the valid lifetime */
706 if (lifetime_preferred_usec
> lifetime_valid_usec
)
709 r
= ndisc_generate_addresses(link
, &prefix
, prefixlen
, &addresses
);
711 return log_link_warning_errno(link
, r
, "Failed to generate SLAAC addresses: %m");
713 SET_FOREACH(a
, addresses
) {
714 _cleanup_(address_unrefp
) Address
*address
= NULL
;
716 r
= address_new(&address
);
720 address
->family
= AF_INET6
;
721 address
->in_addr
.in6
= *a
;
722 address
->prefixlen
= prefixlen
;
723 address
->flags
= IFA_F_NOPREFIXROUTE
|IFA_F_MANAGETEMPADDR
;
724 address
->lifetime_valid_usec
= lifetime_valid_usec
;
725 address
->lifetime_preferred_usec
= lifetime_preferred_usec
;
727 /* draft-ietf-6man-slaac-renum-07 section 4.2
728 * https://datatracker.ietf.org/doc/html/draft-ietf-6man-slaac-renum-07#section-4.2
730 * If the advertised prefix is equal to the prefix of an address configured by stateless
731 * autoconfiguration in the list, the valid lifetime and the preferred lifetime of the
732 * address should be updated by processing the Valid Lifetime and the Preferred Lifetime
733 * (respectively) in the received advertisement. */
734 if (lifetime_valid_usec
== 0) {
735 r
= address_remove_and_cancel(address
, link
);
737 return log_link_warning_errno(link
, r
, "Could not remove SLAAC address: %m");
739 r
= ndisc_request_address(address
, link
, rt
);
741 return log_link_warning_errno(link
, r
, "Could not request SLAAC address: %m");
748 static int ndisc_router_process_onlink_prefix(Link
*link
, sd_ndisc_router
*rt
) {
749 _cleanup_(route_unrefp
) Route
*route
= NULL
;
750 unsigned prefixlen
, preference
;
751 usec_t lifetime_usec
;
752 struct in6_addr prefix
;
756 assert(link
->network
);
759 if (!link
->network
->ipv6_accept_ra_use_onlink_prefix
)
762 r
= sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt
, CLOCK_BOOTTIME
, &lifetime_usec
);
764 return log_link_warning_errno(link
, r
, "Failed to get prefix lifetime: %m");
766 r
= sd_ndisc_router_prefix_get_address(rt
, &prefix
);
768 return log_link_warning_errno(link
, r
, "Failed to get prefix address: %m");
770 r
= sd_ndisc_router_prefix_get_prefixlen(rt
, &prefixlen
);
772 return log_link_warning_errno(link
, r
, "Failed to get prefix length: %m");
774 /* Prefix Information option does not have preference, hence we use the 'main' preference here */
775 r
= sd_ndisc_router_get_preference(rt
, &preference
);
777 return log_link_warning_errno(link
, r
, "Failed to get router preference from RA: %m");
779 r
= route_new(&route
);
783 route
->family
= AF_INET6
;
784 route
->dst
.in6
= prefix
;
785 route
->dst_prefixlen
= prefixlen
;
786 route
->pref
= preference
;
787 route
->lifetime_usec
= lifetime_usec
;
789 r
= ndisc_request_route(route
, link
, rt
);
791 return log_link_warning_errno(link
, r
, "Could not request prefix route: %m");
796 static int ndisc_router_drop_onlink_prefix(Link
*link
, sd_ndisc_router
*rt
) {
797 _cleanup_(route_unrefp
) Route
*route
= NULL
;
799 struct in6_addr prefix
;
800 usec_t lifetime_usec
;
804 assert(link
->network
);
807 /* RFC 4861 section 6.3.4.
808 * Note, however, that a Prefix Information option with the on-link flag set to zero conveys no
809 * information concerning on-link determination and MUST NOT be interpreted to mean that addresses
810 * covered by the prefix are off-link. The only way to cancel a previous on-link indication is to
811 * advertise that prefix with the L-bit set and the Lifetime set to zero. */
813 if (!link
->network
->ipv6_accept_ra_use_onlink_prefix
)
816 r
= sd_ndisc_router_prefix_get_valid_lifetime(rt
, &lifetime_usec
);
818 return log_link_warning_errno(link
, r
, "Failed to get prefix lifetime: %m");
820 if (lifetime_usec
!= 0)
823 r
= sd_ndisc_router_prefix_get_address(rt
, &prefix
);
825 return log_link_warning_errno(link
, r
, "Failed to get prefix address: %m");
827 r
= sd_ndisc_router_prefix_get_prefixlen(rt
, &prefixlen
);
829 return log_link_warning_errno(link
, r
, "Failed to get prefix length: %m");
831 r
= route_new(&route
);
835 route
->family
= AF_INET6
;
836 route
->dst
.in6
= prefix
;
837 route
->dst_prefixlen
= prefixlen
;
839 r
= ndisc_remove_route(route
, link
);
841 return log_link_warning_errno(link
, r
, "Could not remove prefix route: %m");
846 static int ndisc_router_process_prefix(Link
*link
, sd_ndisc_router
*rt
) {
853 assert(link
->network
);
856 r
= sd_ndisc_router_prefix_get_address(rt
, &a
);
858 return log_link_warning_errno(link
, r
, "Failed to get prefix address: %m");
860 /* RFC 4861 Section 4.6.2:
861 * A router SHOULD NOT send a prefix option for the link-local prefix and a host SHOULD ignore such
862 * a prefix option. */
863 if (in6_addr_is_link_local(&a
)) {
864 log_link_debug(link
, "Received link-local prefix, ignoring prefix.");
868 r
= sd_ndisc_router_prefix_get_prefixlen(rt
, &prefixlen
);
870 return log_link_warning_errno(link
, r
, "Failed to get prefix length: %m");
872 if (in6_prefix_is_filtered(&a
, prefixlen
, link
->network
->ndisc_allow_listed_prefix
, link
->network
->ndisc_deny_listed_prefix
)) {
874 log_link_debug(link
, "Prefix '%s' is %s, ignoring",
875 !set_isempty(link
->network
->ndisc_allow_listed_prefix
) ? "not in allow list"
877 IN6_ADDR_PREFIX_TO_STRING(&a
, prefixlen
));
881 r
= sd_ndisc_router_prefix_get_flags(rt
, &flags
);
883 return log_link_warning_errno(link
, r
, "Failed to get RA prefix flags: %m");
885 if (FLAGS_SET(flags
, ND_OPT_PI_FLAG_ONLINK
))
886 r
= ndisc_router_process_onlink_prefix(link
, rt
);
888 r
= ndisc_router_drop_onlink_prefix(link
, rt
);
892 if (FLAGS_SET(flags
, ND_OPT_PI_FLAG_AUTO
)) {
893 r
= ndisc_router_process_autonomous_prefix(link
, rt
);
901 static int ndisc_router_process_route(Link
*link
, sd_ndisc_router
*rt
) {
902 _cleanup_(route_unrefp
) Route
*route
= NULL
;
903 unsigned preference
, prefixlen
;
904 struct in6_addr gateway
, dst
;
905 usec_t lifetime_usec
;
910 if (!link
->network
->ipv6_accept_ra_use_route_prefix
)
913 r
= sd_ndisc_router_route_get_lifetime_timestamp(rt
, CLOCK_BOOTTIME
, &lifetime_usec
);
915 return log_link_warning_errno(link
, r
, "Failed to get route lifetime from RA: %m");
917 r
= sd_ndisc_router_route_get_address(rt
, &dst
);
919 return log_link_warning_errno(link
, r
, "Failed to get route destination address: %m");
921 r
= sd_ndisc_router_route_get_prefixlen(rt
, &prefixlen
);
923 return log_link_warning_errno(link
, r
, "Failed to get route prefix length: %m");
925 if (in6_addr_is_null(&dst
) && prefixlen
== 0) {
926 log_link_debug(link
, "Route prefix is ::/0, ignoring");
930 if (in6_prefix_is_filtered(&dst
, prefixlen
,
931 link
->network
->ndisc_allow_listed_route_prefix
,
932 link
->network
->ndisc_deny_listed_route_prefix
)) {
935 log_link_debug(link
, "Route prefix %s is %s, ignoring",
936 !set_isempty(link
->network
->ndisc_allow_listed_route_prefix
) ? "not in allow list"
938 IN6_ADDR_PREFIX_TO_STRING(&dst
, prefixlen
));
942 r
= sd_ndisc_router_get_address(rt
, &gateway
);
944 return log_link_warning_errno(link
, r
, "Failed to get gateway address from RA: %m");
946 if (link_get_ipv6_address(link
, &gateway
, 0, NULL
) >= 0) {
948 log_link_debug(link
, "Advertised route gateway %s is local to the link, ignoring route",
949 IN6_ADDR_TO_STRING(&gateway
));
953 r
= sd_ndisc_router_route_get_preference(rt
, &preference
);
954 if (r
== -EOPNOTSUPP
) {
955 log_link_debug_errno(link
, r
, "Received route prefix with unsupported preference, ignoring: %m");
959 return log_link_warning_errno(link
, r
, "Failed to get router preference from RA: %m");
961 r
= route_new(&route
);
965 route
->family
= AF_INET6
;
966 route
->pref
= preference
;
967 route
->nexthop
.gw
.in6
= gateway
;
968 route
->nexthop
.family
= AF_INET6
;
969 route
->dst
.in6
= dst
;
970 route
->dst_prefixlen
= prefixlen
;
971 route
->lifetime_usec
= lifetime_usec
;
973 r
= ndisc_request_route(route
, link
, rt
);
975 return log_link_warning_errno(link
, r
, "Could not request additional route: %m");
980 static void ndisc_rdnss_hash_func(const NDiscRDNSS
*x
, struct siphash
*state
) {
981 siphash24_compress_typesafe(x
->address
, state
);
984 static int ndisc_rdnss_compare_func(const NDiscRDNSS
*a
, const NDiscRDNSS
*b
) {
985 return memcmp(&a
->address
, &b
->address
, sizeof(a
->address
));
988 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
989 ndisc_rdnss_hash_ops
,
991 ndisc_rdnss_hash_func
,
992 ndisc_rdnss_compare_func
,
995 static int ndisc_router_process_rdnss(Link
*link
, sd_ndisc_router
*rt
) {
996 usec_t lifetime_usec
;
997 const struct in6_addr
*a
;
998 struct in6_addr router
;
999 bool updated
= false, logged_about_too_many
= false;
1003 assert(link
->network
);
1006 if (!link
->network
->ipv6_accept_ra_use_dns
)
1009 r
= sd_ndisc_router_get_address(rt
, &router
);
1011 return log_link_warning_errno(link
, r
, "Failed to get router address from RA: %m");
1013 r
= sd_ndisc_router_rdnss_get_lifetime_timestamp(rt
, CLOCK_BOOTTIME
, &lifetime_usec
);
1015 return log_link_warning_errno(link
, r
, "Failed to get RDNSS lifetime: %m");
1017 n
= sd_ndisc_router_rdnss_get_addresses(rt
, &a
);
1019 return log_link_warning_errno(link
, n
, "Failed to get RDNSS addresses: %m");
1021 for (int j
= 0; j
< n
; j
++) {
1022 _cleanup_free_ NDiscRDNSS
*x
= NULL
;
1023 NDiscRDNSS
*rdnss
, d
= {
1027 if (lifetime_usec
== 0) {
1028 /* The entry is outdated. */
1029 free(set_remove(link
->ndisc_rdnss
, &d
));
1034 rdnss
= set_get(link
->ndisc_rdnss
, &d
);
1036 rdnss
->router
= router
;
1037 rdnss
->lifetime_usec
= lifetime_usec
;
1041 if (set_size(link
->ndisc_rdnss
) >= NDISC_RDNSS_MAX
) {
1042 if (!logged_about_too_many
)
1043 log_link_warning(link
, "Too many RDNSS records per link. Only first %u records will be used.", NDISC_RDNSS_MAX
);
1044 logged_about_too_many
= true;
1048 x
= new(NDiscRDNSS
, 1);
1055 .lifetime_usec
= lifetime_usec
,
1058 r
= set_ensure_consume(&link
->ndisc_rdnss
, &ndisc_rdnss_hash_ops
, TAKE_PTR(x
));
1072 static void ndisc_dnssl_hash_func(const NDiscDNSSL
*x
, struct siphash
*state
) {
1073 siphash24_compress_string(NDISC_DNSSL_DOMAIN(x
), state
);
1076 static int ndisc_dnssl_compare_func(const NDiscDNSSL
*a
, const NDiscDNSSL
*b
) {
1077 return strcmp(NDISC_DNSSL_DOMAIN(a
), NDISC_DNSSL_DOMAIN(b
));
1080 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
1081 ndisc_dnssl_hash_ops
,
1083 ndisc_dnssl_hash_func
,
1084 ndisc_dnssl_compare_func
,
1087 static int ndisc_router_process_dnssl(Link
*link
, sd_ndisc_router
*rt
) {
1088 _cleanup_strv_free_
char **l
= NULL
;
1089 usec_t lifetime_usec
;
1090 struct in6_addr router
;
1091 bool updated
= false, logged_about_too_many
= false;
1095 assert(link
->network
);
1098 if (link
->network
->ipv6_accept_ra_use_domains
== DHCP_USE_DOMAINS_NO
)
1101 r
= sd_ndisc_router_get_address(rt
, &router
);
1103 return log_link_warning_errno(link
, r
, "Failed to get router address from RA: %m");
1105 r
= sd_ndisc_router_dnssl_get_lifetime_timestamp(rt
, CLOCK_BOOTTIME
, &lifetime_usec
);
1107 return log_link_warning_errno(link
, r
, "Failed to get DNSSL lifetime: %m");
1109 r
= sd_ndisc_router_dnssl_get_domains(rt
, &l
);
1111 return log_link_warning_errno(link
, r
, "Failed to get DNSSL addresses: %m");
1113 STRV_FOREACH(j
, l
) {
1114 _cleanup_free_ NDiscDNSSL
*s
= NULL
;
1117 s
= malloc0(ALIGN(sizeof(NDiscDNSSL
)) + strlen(*j
) + 1);
1121 strcpy(NDISC_DNSSL_DOMAIN(s
), *j
);
1123 if (lifetime_usec
== 0) {
1124 /* The entry is outdated. */
1125 free(set_remove(link
->ndisc_dnssl
, s
));
1130 dnssl
= set_get(link
->ndisc_dnssl
, s
);
1132 dnssl
->router
= router
;
1133 dnssl
->lifetime_usec
= lifetime_usec
;
1137 if (set_size(link
->ndisc_dnssl
) >= NDISC_DNSSL_MAX
) {
1138 if (!logged_about_too_many
)
1139 log_link_warning(link
, "Too many DNSSL records per link. Only first %u records will be used.", NDISC_DNSSL_MAX
);
1140 logged_about_too_many
= true;
1145 s
->lifetime_usec
= lifetime_usec
;
1147 r
= set_ensure_consume(&link
->ndisc_dnssl
, &ndisc_dnssl_hash_ops
, TAKE_PTR(s
));
1161 static NDiscCaptivePortal
* ndisc_captive_portal_free(NDiscCaptivePortal
*x
) {
1165 free(x
->captive_portal
);
1169 DEFINE_TRIVIAL_CLEANUP_FUNC(NDiscCaptivePortal
*, ndisc_captive_portal_free
);
1171 static void ndisc_captive_portal_hash_func(const NDiscCaptivePortal
*x
, struct siphash
*state
) {
1173 siphash24_compress_string(x
->captive_portal
, state
);
1176 static int ndisc_captive_portal_compare_func(const NDiscCaptivePortal
*a
, const NDiscCaptivePortal
*b
) {
1179 return strcmp_ptr(a
->captive_portal
, b
->captive_portal
);
1182 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
1183 ndisc_captive_portal_hash_ops
,
1185 ndisc_captive_portal_hash_func
,
1186 ndisc_captive_portal_compare_func
,
1187 ndisc_captive_portal_free
);
1189 static int ndisc_router_process_captive_portal(Link
*link
, sd_ndisc_router
*rt
) {
1190 _cleanup_(ndisc_captive_portal_freep
) NDiscCaptivePortal
*new_entry
= NULL
;
1191 _cleanup_free_
char *captive_portal
= NULL
;
1192 usec_t lifetime_usec
;
1193 NDiscCaptivePortal
*exist
;
1194 struct in6_addr router
;
1200 assert(link
->network
);
1203 if (!link
->network
->ipv6_accept_ra_use_captive_portal
)
1206 r
= sd_ndisc_router_get_address(rt
, &router
);
1208 return log_link_warning_errno(link
, r
, "Failed to get router address from RA: %m");
1210 /* RFC 4861 section 4.2. states that the lifetime in the message header should be used only for the
1211 * default gateway, but the captive portal option does not have a lifetime field, hence, we use the
1212 * main lifetime for the portal. */
1213 r
= sd_ndisc_router_get_lifetime_timestamp(rt
, CLOCK_BOOTTIME
, &lifetime_usec
);
1215 return log_link_warning_errno(link
, r
, "Failed to get lifetime of RA message: %m");
1217 r
= sd_ndisc_router_captive_portal_get_uri(rt
, &uri
, &len
);
1219 return log_link_warning_errno(link
, r
, "Failed to get captive portal from RA: %m");
1222 return log_link_warning_errno(link
, SYNTHETIC_ERRNO(EBADMSG
), "Received empty captive portal, ignoring.");
1224 r
= make_cstring(uri
, len
, MAKE_CSTRING_REFUSE_TRAILING_NUL
, &captive_portal
);
1226 return log_link_warning_errno(link
, r
, "Failed to convert captive portal URI: %m");
1228 if (!in_charset(captive_portal
, URI_VALID
))
1229 return log_link_warning_errno(link
, SYNTHETIC_ERRNO(EBADMSG
), "Received invalid captive portal, ignoring.");
1231 if (lifetime_usec
== 0) {
1232 /* Drop the portal with zero lifetime. */
1233 ndisc_captive_portal_free(set_remove(link
->ndisc_captive_portals
,
1234 &(NDiscCaptivePortal
) {
1235 .captive_portal
= captive_portal
,
1240 exist
= set_get(link
->ndisc_captive_portals
,
1241 &(NDiscCaptivePortal
) {
1242 .captive_portal
= captive_portal
,
1245 /* update existing entry */
1246 exist
->router
= router
;
1247 exist
->lifetime_usec
= lifetime_usec
;
1251 if (set_size(link
->ndisc_captive_portals
) >= NDISC_CAPTIVE_PORTAL_MAX
) {
1252 NDiscCaptivePortal
*c
, *target
= NULL
;
1254 /* Find the portal who has the minimal lifetime and drop it to store new one. */
1255 SET_FOREACH(c
, link
->ndisc_captive_portals
)
1256 if (!target
|| c
->lifetime_usec
< target
->lifetime_usec
)
1260 assert(set_remove(link
->ndisc_captive_portals
, target
) == target
);
1261 ndisc_captive_portal_free(target
);
1264 new_entry
= new(NDiscCaptivePortal
, 1);
1268 *new_entry
= (NDiscCaptivePortal
) {
1270 .lifetime_usec
= lifetime_usec
,
1271 .captive_portal
= TAKE_PTR(captive_portal
),
1274 r
= set_ensure_put(&link
->ndisc_captive_portals
, &ndisc_captive_portal_hash_ops
, new_entry
);
1278 TAKE_PTR(new_entry
);
1284 static void ndisc_pref64_hash_func(const NDiscPREF64
*x
, struct siphash
*state
) {
1287 siphash24_compress_typesafe(x
->prefix_len
, state
);
1288 siphash24_compress_typesafe(x
->prefix
, state
);
1291 static int ndisc_pref64_compare_func(const NDiscPREF64
*a
, const NDiscPREF64
*b
) {
1297 r
= CMP(a
->prefix_len
, b
->prefix_len
);
1301 return memcmp(&a
->prefix
, &b
->prefix
, sizeof(a
->prefix
));
1304 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
1305 ndisc_pref64_hash_ops
,
1307 ndisc_pref64_hash_func
,
1308 ndisc_pref64_compare_func
,
1311 static int ndisc_router_process_pref64(Link
*link
, sd_ndisc_router
*rt
) {
1312 _cleanup_free_ NDiscPREF64
*new_entry
= NULL
;
1313 usec_t lifetime_usec
;
1314 struct in6_addr a
, router
;
1315 unsigned prefix_len
;
1320 assert(link
->network
);
1323 if (!link
->network
->ipv6_accept_ra_use_pref64
)
1326 r
= sd_ndisc_router_get_address(rt
, &router
);
1328 return log_link_warning_errno(link
, r
, "Failed to get router address from RA: %m");
1330 r
= sd_ndisc_router_prefix64_get_prefix(rt
, &a
);
1332 return log_link_warning_errno(link
, r
, "Failed to get pref64 prefix: %m");
1334 r
= sd_ndisc_router_prefix64_get_prefixlen(rt
, &prefix_len
);
1336 return log_link_warning_errno(link
, r
, "Failed to get pref64 prefix length: %m");
1338 r
= sd_ndisc_router_prefix64_get_lifetime_timestamp(rt
, CLOCK_BOOTTIME
, &lifetime_usec
);
1340 return log_link_warning_errno(link
, r
, "Failed to get pref64 prefix lifetime: %m");
1342 if (lifetime_usec
== 0) {
1343 free(set_remove(link
->ndisc_pref64
,
1346 .prefix_len
= prefix_len
1351 exist
= set_get(link
->ndisc_pref64
,
1354 .prefix_len
= prefix_len
1357 /* update existing entry */
1358 exist
->router
= router
;
1359 exist
->lifetime_usec
= lifetime_usec
;
1363 if (set_size(link
->ndisc_pref64
) >= NDISC_PREF64_MAX
) {
1364 log_link_debug(link
, "Too many PREF64 records received. Only first %u records will be used.", NDISC_PREF64_MAX
);
1368 new_entry
= new(NDiscPREF64
, 1);
1372 *new_entry
= (NDiscPREF64
) {
1374 .lifetime_usec
= lifetime_usec
,
1376 .prefix_len
= prefix_len
,
1379 r
= set_ensure_put(&link
->ndisc_pref64
, &ndisc_pref64_hash_ops
, new_entry
);
1384 TAKE_PTR(new_entry
);
1389 static int ndisc_router_process_options(Link
*link
, sd_ndisc_router
*rt
) {
1390 size_t n_captive_portal
= 0;
1394 assert(link
->network
);
1397 for (r
= sd_ndisc_router_option_rewind(rt
); ; r
= sd_ndisc_router_option_next(rt
)) {
1401 return log_link_warning_errno(link
, r
, "Failed to iterate through options: %m");
1402 if (r
== 0) /* EOF */
1405 r
= sd_ndisc_router_option_get_type(rt
, &type
);
1407 return log_link_warning_errno(link
, r
, "Failed to get RA option type: %m");
1410 case SD_NDISC_OPTION_PREFIX_INFORMATION
:
1411 r
= ndisc_router_process_prefix(link
, rt
);
1414 case SD_NDISC_OPTION_ROUTE_INFORMATION
:
1415 r
= ndisc_router_process_route(link
, rt
);
1418 case SD_NDISC_OPTION_RDNSS
:
1419 r
= ndisc_router_process_rdnss(link
, rt
);
1422 case SD_NDISC_OPTION_DNSSL
:
1423 r
= ndisc_router_process_dnssl(link
, rt
);
1425 case SD_NDISC_OPTION_CAPTIVE_PORTAL
:
1426 if (n_captive_portal
> 0) {
1427 if (n_captive_portal
== 1)
1428 log_link_notice(link
, "Received RA with multiple captive portals, only using the first one.");
1433 r
= ndisc_router_process_captive_portal(link
, rt
);
1437 case SD_NDISC_OPTION_PREF64
:
1438 r
= ndisc_router_process_pref64(link
, rt
);
1441 if (r
< 0 && r
!= -EBADMSG
)
1446 static int ndisc_drop_outdated(Link
*link
, usec_t timestamp_usec
) {
1447 bool updated
= false;
1450 NDiscCaptivePortal
*cp
;
1457 assert(link
->manager
);
1459 /* If an address or friends is already assigned, but not valid anymore, then refuse to update it,
1460 * and let's immediately remove it.
1461 * See RFC4862, section 5.5.3.e. But the following logic is deviated from RFC4862 by honoring all
1462 * valid lifetimes to improve the reaction of SLAAC to renumbering events.
1463 * See draft-ietf-6man-slaac-renum-02, section 4.2. */
1465 SET_FOREACH(route
, link
->manager
->routes
) {
1466 if (route
->source
!= NETWORK_CONFIG_SOURCE_NDISC
)
1469 if (route
->nexthop
.ifindex
!= link
->ifindex
)
1472 if (route
->lifetime_usec
>= timestamp_usec
)
1473 continue; /* the route is still valid */
1475 r
= route_remove_and_cancel(route
, link
->manager
);
1477 RET_GATHER(ret
, log_link_warning_errno(link
, r
, "Failed to remove outdated SLAAC route, ignoring: %m"));
1480 SET_FOREACH(address
, link
->addresses
) {
1481 if (address
->source
!= NETWORK_CONFIG_SOURCE_NDISC
)
1484 if (address
->lifetime_valid_usec
>= timestamp_usec
)
1485 continue; /* the address is still valid */
1487 r
= address_remove_and_cancel(address
, link
);
1489 RET_GATHER(ret
, log_link_warning_errno(link
, r
, "Failed to remove outdated SLAAC address, ignoring: %m"));
1492 SET_FOREACH(rdnss
, link
->ndisc_rdnss
) {
1493 if (rdnss
->lifetime_usec
>= timestamp_usec
)
1494 continue; /* the DNS server is still valid */
1496 free(set_remove(link
->ndisc_rdnss
, rdnss
));
1500 SET_FOREACH(dnssl
, link
->ndisc_dnssl
) {
1501 if (dnssl
->lifetime_usec
>= timestamp_usec
)
1502 continue; /* the DNS domain is still valid */
1504 free(set_remove(link
->ndisc_dnssl
, dnssl
));
1508 SET_FOREACH(cp
, link
->ndisc_captive_portals
) {
1509 if (cp
->lifetime_usec
>= timestamp_usec
)
1510 continue; /* the captive portal is still valid */
1512 ndisc_captive_portal_free(set_remove(link
->ndisc_captive_portals
, cp
));
1516 SET_FOREACH(p64
, link
->ndisc_pref64
) {
1517 if (p64
->lifetime_usec
>= timestamp_usec
)
1518 continue; /* the pref64 prefix is still valid */
1520 free(set_remove(link
->ndisc_pref64
, p64
));
1521 /* The pref64 prefix is not exported through the state file, hence it is not necessary to set
1522 * the 'updated' flag. */
1531 static int ndisc_setup_expire(Link
*link
);
1533 static int ndisc_expire_handler(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
1534 Link
*link
= ASSERT_PTR(userdata
);
1537 assert(link
->manager
);
1539 assert_se(sd_event_now(link
->manager
->event
, CLOCK_BOOTTIME
, &now_usec
) >= 0);
1541 (void) ndisc_drop_outdated(link
, now_usec
);
1542 (void) ndisc_setup_expire(link
);
1546 static int ndisc_setup_expire(Link
*link
) {
1547 usec_t lifetime_usec
= USEC_INFINITY
;
1548 NDiscCaptivePortal
*cp
;
1557 assert(link
->manager
);
1559 SET_FOREACH(route
, link
->manager
->routes
) {
1560 if (route
->source
!= NETWORK_CONFIG_SOURCE_NDISC
)
1563 if (route
->nexthop
.ifindex
!= link
->ifindex
)
1566 if (!route_exists(route
))
1569 lifetime_usec
= MIN(lifetime_usec
, route
->lifetime_usec
);
1572 SET_FOREACH(address
, link
->addresses
) {
1573 if (address
->source
!= NETWORK_CONFIG_SOURCE_NDISC
)
1576 if (!address_exists(address
))
1579 lifetime_usec
= MIN(lifetime_usec
, address
->lifetime_valid_usec
);
1582 SET_FOREACH(rdnss
, link
->ndisc_rdnss
)
1583 lifetime_usec
= MIN(lifetime_usec
, rdnss
->lifetime_usec
);
1585 SET_FOREACH(dnssl
, link
->ndisc_dnssl
)
1586 lifetime_usec
= MIN(lifetime_usec
, dnssl
->lifetime_usec
);
1588 SET_FOREACH(cp
, link
->ndisc_captive_portals
)
1589 lifetime_usec
= MIN(lifetime_usec
, cp
->lifetime_usec
);
1591 SET_FOREACH(p64
, link
->ndisc_pref64
)
1592 lifetime_usec
= MIN(lifetime_usec
, p64
->lifetime_usec
);
1594 if (lifetime_usec
== USEC_INFINITY
)
1597 r
= event_reset_time(link
->manager
->event
, &link
->ndisc_expire
, CLOCK_BOOTTIME
,
1598 lifetime_usec
, 0, ndisc_expire_handler
, link
, 0, "ndisc-expiration", true);
1600 return log_link_warning_errno(link
, r
, "Failed to update expiration timer for ndisc: %m");
1605 static int ndisc_start_dhcp6_client(Link
*link
, sd_ndisc_router
*rt
) {
1609 assert(link
->network
);
1611 /* Do not start DHCPv6 client if the router lifetime is zero, as the message sent as a signal of
1612 * that the router is e.g. shutting down, revoked, etc,. */
1613 r
= sd_ndisc_router_get_lifetime(rt
, NULL
);
1617 switch (link
->network
->ipv6_accept_ra_start_dhcp6_client
) {
1618 case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO
:
1621 case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES
: {
1624 r
= sd_ndisc_router_get_flags(rt
, &flags
);
1626 return log_link_warning_errno(link
, r
, "Failed to get RA flags: %m");
1628 if ((flags
& (ND_RA_FLAG_MANAGED
| ND_RA_FLAG_OTHER
)) == 0)
1631 /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags.
1632 * Note, if both "managed" and "other configuration" bits are set, then ignore
1633 * "other configuration" bit. See RFC 4861. */
1634 r
= dhcp6_start_on_ra(link
, !(flags
& ND_RA_FLAG_MANAGED
));
1637 case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS
:
1638 /* When IPv6AcceptRA.DHCPv6Client=always, start dhcp6 client in solicit mode
1639 * even if the router flags have neither M nor O flags. */
1640 r
= dhcp6_start_on_ra(link
, /* information_request = */ false);
1644 assert_not_reached();
1648 return log_link_warning_errno(link
, r
, "Could not acquire DHCPv6 lease on NDisc request: %m");
1650 log_link_debug(link
, "Acquiring DHCPv6 lease on NDisc request");
1654 static int ndisc_router_handler(Link
*link
, sd_ndisc_router
*rt
) {
1655 struct in6_addr router
;
1656 usec_t timestamp_usec
;
1660 assert(link
->network
);
1661 assert(link
->manager
);
1664 r
= sd_ndisc_router_get_address(rt
, &router
);
1665 if (r
== -ENODATA
) {
1666 log_link_debug(link
, "Received RA without router address, ignoring.");
1670 return log_link_warning_errno(link
, r
, "Failed to get router address from RA: %m");
1672 if (in6_prefix_is_filtered(&router
, 128, link
->network
->ndisc_allow_listed_router
, link
->network
->ndisc_deny_listed_router
)) {
1673 if (DEBUG_LOGGING
) {
1674 if (!set_isempty(link
->network
->ndisc_allow_listed_router
))
1675 log_link_debug(link
, "Router %s is not in allow list, ignoring.", IN6_ADDR_TO_STRING(&router
));
1677 log_link_debug(link
, "Router %s is in deny list, ignoring.", IN6_ADDR_TO_STRING(&router
));
1682 r
= sd_ndisc_router_get_timestamp(rt
, CLOCK_BOOTTIME
, ×tamp_usec
);
1683 if (r
== -ENODATA
) {
1684 log_link_debug(link
, "Received RA without timestamp, ignoring.");
1690 r
= ndisc_drop_outdated(link
, timestamp_usec
);
1694 r
= ndisc_start_dhcp6_client(link
, rt
);
1698 r
= ndisc_router_process_default(link
, rt
);
1702 r
= ndisc_router_process_icmp6_ratelimit(link
, rt
);
1706 r
= ndisc_router_process_reachable_time(link
, rt
);
1710 r
= ndisc_router_process_retransmission_time(link
, rt
);
1714 r
= ndisc_router_process_hop_limit(link
, rt
);
1718 r
= ndisc_router_process_options(link
, rt
);
1722 r
= ndisc_setup_expire(link
);
1726 if (link
->ndisc_messages
== 0)
1727 link
->ndisc_configured
= true;
1729 log_link_debug(link
, "Setting SLAAC addresses and router.");
1731 if (!link
->ndisc_configured
)
1732 link_set_state(link
, LINK_STATE_CONFIGURING
);
1734 link_check_ready(link
);
1738 static void ndisc_handler(sd_ndisc
*nd
, sd_ndisc_event_t event
, sd_ndisc_router
*rt
, void *userdata
) {
1739 Link
*link
= ASSERT_PTR(userdata
);
1742 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
1747 case SD_NDISC_EVENT_ROUTER
:
1748 r
= ndisc_router_handler(link
, rt
);
1749 if (r
< 0 && r
!= -EBADMSG
) {
1750 link_enter_failed(link
);
1755 case SD_NDISC_EVENT_TIMEOUT
:
1756 log_link_debug(link
, "NDisc handler get timeout event");
1757 if (link
->ndisc_messages
== 0) {
1758 link
->ndisc_configured
= true;
1759 link_check_ready(link
);
1763 assert_not_reached();
1767 static int ndisc_configure(Link
*link
) {
1772 if (!link_ipv6_accept_ra_enabled(link
))
1776 return -EBUSY
; /* Already configured. */
1778 r
= sd_ndisc_new(&link
->ndisc
);
1782 r
= sd_ndisc_attach_event(link
->ndisc
, link
->manager
->event
, 0);
1786 if (link
->hw_addr
.length
== ETH_ALEN
) {
1787 r
= sd_ndisc_set_mac(link
->ndisc
, &link
->hw_addr
.ether
);
1792 r
= sd_ndisc_set_ifindex(link
->ndisc
, link
->ifindex
);
1796 r
= sd_ndisc_set_callback(link
->ndisc
, ndisc_handler
, link
);
1803 int ndisc_start(Link
*link
) {
1808 if (!link
->ndisc
|| !link
->dhcp6_client
)
1811 if (!link_has_carrier(link
))
1814 if (in6_addr_is_null(&link
->ipv6ll_address
))
1817 log_link_debug(link
, "Discovering IPv6 routers");
1819 r
= sd_ndisc_start(link
->ndisc
);
1826 static int ndisc_process_request(Request
*req
, Link
*link
, void *userdata
) {
1831 if (!link_is_ready_to_configure(link
, /* allow_unmanaged = */ false))
1834 r
= ndisc_configure(link
);
1836 return log_link_warning_errno(link
, r
, "Failed to configure IPv6 Router Discovery: %m");
1838 r
= ndisc_start(link
);
1840 return log_link_warning_errno(link
, r
, "Failed to start IPv6 Router Discovery: %m");
1842 log_link_debug(link
, "IPv6 Router Discovery is configured%s.",
1843 r
> 0 ? " and started" : "");
1847 int link_request_ndisc(Link
*link
) {
1852 if (!link_ipv6_accept_ra_enabled(link
))
1858 r
= link_queue_request(link
, REQUEST_TYPE_NDISC
, ndisc_process_request
, NULL
);
1860 return log_link_warning_errno(link
, r
, "Failed to request configuring of the IPv6 Router Discovery: %m");
1862 log_link_debug(link
, "Requested configuring of the IPv6 Router Discovery.");
1866 int ndisc_stop(Link
*link
) {
1869 link
->ndisc_expire
= sd_event_source_disable_unref(link
->ndisc_expire
);
1871 return sd_ndisc_stop(link
->ndisc
);
1875 void ndisc_flush(Link
*link
) {
1878 /* Remove all addresses, routes, RDNSS, DNSSL, and Captive Portal entries, without exception. */
1879 (void) ndisc_drop_outdated(link
, /* timestamp_usec = */ USEC_INFINITY
);
1881 link
->ndisc_rdnss
= set_free(link
->ndisc_rdnss
);
1882 link
->ndisc_dnssl
= set_free(link
->ndisc_dnssl
);
1883 link
->ndisc_captive_portals
= set_free(link
->ndisc_captive_portals
);
1884 link
->ndisc_pref64
= set_free(link
->ndisc_pref64
);
1887 static const char* const ipv6_accept_ra_start_dhcp6_client_table
[_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_MAX
] = {
1888 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO
] = "no",
1889 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS
] = "always",
1890 [IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES
] = "yes",
1893 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(ipv6_accept_ra_start_dhcp6_client
, IPv6AcceptRAStartDHCP6Client
, IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES
);
1895 DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_use_domains
, dhcp_use_domains
, DHCPUseDomains
,
1896 "Failed to parse UseDomains= setting");
1897 DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_start_dhcp6_client
, ipv6_accept_ra_start_dhcp6_client
, IPv6AcceptRAStartDHCP6Client
,
1898 "Failed to parse DHCPv6Client= setting");