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 "string-table.h"
24 #include "string-util.h"
26 #include "sysctl-util.h"
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
37 bool link_ipv6_accept_ra_enabled(Link
*link
) {
40 if (!socket_ipv6_is_supported())
43 if (link
->flags
& IFF_LOOPBACK
)
46 if (link
->iftype
== ARPHRD_CAN
)
52 if (!link_may_have_ipv6ll(link
, /* check_multicast = */ true))
55 assert(link
->network
->ipv6_accept_ra
>= 0);
56 return link
->network
->ipv6_accept_ra
;
59 void network_adjust_ipv6_accept_ra(Network
*network
) {
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;
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
);
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
);
83 static int ndisc_check_ready(Link
*link
);
85 static int ndisc_address_ready_callback(Address
*address
) {
89 assert(address
->link
);
91 SET_FOREACH(a
, address
->link
->addresses
)
92 if (a
->source
== NETWORK_CONFIG_SOURCE_NDISC
)
95 return ndisc_check_ready(address
->link
);
98 static int ndisc_check_ready(Link
*link
) {
99 bool found
= false, ready
= false;
104 if (link
->ndisc_messages
> 0) {
105 log_link_debug(link
, "%s(): SLAAC addresses and routes are not set.", __func__
);
109 SET_FOREACH(address
, link
->addresses
) {
110 if (address
->source
!= NETWORK_CONFIG_SOURCE_NDISC
)
115 if (address_is_ready(address
)) {
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
;
126 log_link_debug(link
, "%s(): no SLAAC address is ready.", __func__
);
130 link
->ndisc_configured
= true;
131 log_link_debug(link
, "SLAAC addresses and routes set.");
133 link_check_ready(link
);
137 static int ndisc_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Route
*route
) {
142 r
= route_configure_handler_internal(rtnl
, m
, link
, route
, "Could not set NDisc route");
146 r
= ndisc_check_ready(link
);
148 link_enter_failed(link
);
153 static void ndisc_set_route_priority(Link
*link
, Route
*route
) {
157 if (route
->priority_set
)
158 return; /* explicitly configured. */
160 switch (route
->pref
) {
161 case SD_NDISC_PREFERENCE_LOW
:
162 route
->priority
= link
->network
->ipv6_accept_ra_route_metric_low
;
164 case SD_NDISC_PREFERENCE_MEDIUM
:
165 route
->priority
= link
->network
->ipv6_accept_ra_route_metric_medium
;
167 case SD_NDISC_PREFERENCE_HIGH
:
168 route
->priority
= link
->network
->ipv6_accept_ra_route_metric_high
;
171 assert_not_reached();
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;
184 assert(link
->manager
);
185 assert(link
->network
);
188 r
= sd_ndisc_router_get_address(rt
, &router
);
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");
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");
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
);
213 r
= route_metric_set(&route
->metric
, RTAX_HOPLIMIT
, hop_limit
);
216 r
= route_metric_set(&route
->metric
, RTAX_QUICKACK
, link
->network
->ipv6_accept_ra_quickack
);
220 r
= route_adjust_nexthops(route
, link
);
224 uint8_t pref
, pref_original
= route
->pref
;
225 FOREACH_ARGUMENT(pref
, SD_NDISC_PREFERENCE_LOW
, SD_NDISC_PREFERENCE_MEDIUM
, SD_NDISC_PREFERENCE_HIGH
) {
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
)
235 ndisc_set_route_priority(link
, route
);
237 /* Note, here do not call route_remove_and_cancel() with 'route' directly, otherwise
238 * existing route(s) may be removed needlessly. */
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
);
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
);
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
);
265 is_new
= route_get(link
->manager
, route
, NULL
) < 0;
267 r
= link_request_route(link
, route
, &link
->ndisc_messages
, ndisc_route_handler
);
271 link
->ndisc_configured
= false;
276 static int ndisc_remove_route(Route
*route
, Link
*link
) {
281 assert(link
->manager
);
283 ndisc_set_route_priority(link
, route
);
285 if (!route
->table_set
)
286 route
->table
= link_get_ipv6_accept_ra_route_table(link
);
288 r
= route_adjust_nexthops(route
, link
);
292 if (route
->pref_set
) {
293 ndisc_set_route_priority(link
, route
);
294 return route_remove_and_cancel(route
, link
->manager
);
298 FOREACH_ARGUMENT(pref
, SD_NDISC_PREFERENCE_LOW
, SD_NDISC_PREFERENCE_MEDIUM
, SD_NDISC_PREFERENCE_HIGH
) {
300 ndisc_set_route_priority(link
, route
);
301 r
= route_remove_and_cancel(route
, link
->manager
);
309 static int ndisc_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Address
*address
) {
314 r
= address_configure_handler_internal(rtnl
, m
, link
, "Could not set NDisc address");
318 r
= ndisc_check_ready(link
);
320 link_enter_failed(link
);
325 static int ndisc_request_address(Address
*address
, Link
*link
, sd_ndisc_router
*rt
) {
326 struct in6_addr router
;
334 r
= sd_ndisc_router_get_address(rt
, &router
);
338 address
->source
= NETWORK_CONFIG_SOURCE_NDISC
;
339 address
->provider
.in6
= router
;
341 r
= free_and_strdup_warn(&address
->netlabel
, link
->network
->ndisc_netlabel
);
346 if (address_get_harder(link
, address
, &existing
) < 0)
348 else if (address_can_update(existing
, address
))
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
);
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
));
366 r
= link_request_address(link
, address
, &link
->ndisc_messages
,
367 ndisc_address_handler
, NULL
);
371 link
->ndisc_configured
= false;
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
;
382 assert(link
->network
);
385 r
= sd_ndisc_router_get_address(rt
, &gateway
);
387 return log_link_warning_errno(link
, r
, "Failed to get router address from RA: %m");
389 r
= route_new(&route
);
393 route
->family
= AF_INET6
;
394 route
->nexthop
.family
= AF_INET6
;
395 route
->nexthop
.gw
.in6
= gateway
;
397 r
= ndisc_remove_route(route
, link
);
399 return log_link_warning_errno(link
, r
, "Failed to remove the default gateway configured by RA: %m");
402 HASHMAP_FOREACH(route_gw
, link
->network
->routes_by_section
) {
403 _cleanup_(route_unrefp
) Route
*tmp
= NULL
;
405 if (!route_gw
->gateway_from_dhcp_or_ra
)
408 if (route_gw
->nexthop
.family
!= AF_INET6
)
411 r
= route_dup(route_gw
, NULL
, &tmp
);
415 tmp
->nexthop
.gw
.in6
= gateway
;
417 r
= ndisc_remove_route(tmp
, link
);
419 return log_link_warning_errno(link
, r
, "Could not remove semi-static gateway: %m");
425 static int ndisc_router_process_default(Link
*link
, sd_ndisc_router
*rt
) {
426 usec_t lifetime_usec
;
427 struct in6_addr gateway
;
432 assert(link
->network
);
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
);
440 return ndisc_router_drop_default(link
, rt
);
442 if (!link
->network
->ipv6_accept_ra_use_gateway
&&
443 hashmap_isempty(link
->network
->routes_by_section
))
446 r
= sd_ndisc_router_get_lifetime_timestamp(rt
, CLOCK_BOOTTIME
, &lifetime_usec
);
448 return log_link_warning_errno(link
, r
, "Failed to get gateway lifetime from RA: %m");
450 r
= sd_ndisc_router_get_address(rt
, &gateway
);
452 return log_link_warning_errno(link
, r
, "Failed to get gateway address from RA: %m");
454 if (link_get_ipv6_address(link
, &gateway
, 0, NULL
) >= 0) {
456 log_link_debug(link
, "No NDisc route added, gateway %s matches local address",
457 IN6_ADDR_TO_STRING(&gateway
));
461 r
= sd_ndisc_router_get_preference(rt
, &preference
);
463 return log_link_warning_errno(link
, r
, "Failed to get router preference from RA: %m");
465 if (link
->network
->ipv6_accept_ra_use_gateway
) {
466 _cleanup_(route_unrefp
) Route
*route
= NULL
;
468 r
= route_new(&route
);
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
;
478 r
= ndisc_request_route(route
, link
, rt
);
480 return log_link_warning_errno(link
, r
, "Could not request default route: %m");
484 HASHMAP_FOREACH(route_gw
, link
->network
->routes_by_section
) {
485 _cleanup_(route_unrefp
) Route
*route
= NULL
;
487 if (!route_gw
->gateway_from_dhcp_or_ra
)
490 if (route_gw
->nexthop
.family
!= AF_INET6
)
493 r
= route_dup(route_gw
, NULL
, &route
);
497 route
->nexthop
.gw
.in6
= gateway
;
498 if (!route
->pref_set
)
499 route
->pref
= preference
;
500 route
->lifetime_usec
= lifetime_usec
;
502 r
= ndisc_request_route(route
, link
, rt
);
504 return log_link_warning_errno(link
, r
, "Could not request gateway: %m");
510 static int ndisc_router_process_icmp6_ratelimit(Link
*link
, sd_ndisc_router
*rt
) {
511 usec_t icmp6_ratelimit
, msec
;
515 assert(link
->network
);
518 if (!link
->network
->ipv6_accept_ra_use_icmp6_ratelimit
)
521 /* Ignore the icmp6 ratelimit field of the RA header if the lifetime is zero. */
522 r
= sd_ndisc_router_get_lifetime(rt
, NULL
);
526 r
= sd_ndisc_router_get_icmp6_ratelimit(rt
, &icmp6_ratelimit
);
528 return log_link_warning_errno(link
, r
, "Failed to get ICMP6 ratelimit from RA: %m");
530 /* We do not allow 0 here. */
531 if (!timestamp_is_set(icmp6_ratelimit
))
534 msec
= DIV_ROUND_UP(icmp6_ratelimit
, USEC_PER_MSEC
);
535 if (msec
<= 0 || msec
> INT_MAX
)
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
);
542 log_link_warning_errno(link
, r
, "Failed to apply ICMP6 ratelimit, ignoring: %m");
547 static int ndisc_router_process_reachable_time(Link
*link
, sd_ndisc_router
*rt
) {
548 usec_t reachable_time
, msec
;
552 assert(link
->network
);
555 if (!link
->network
->ipv6_accept_ra_use_reachable_time
)
558 /* Ignore the reachable time field of the RA header if the lifetime is zero. */
559 r
= sd_ndisc_router_get_lifetime(rt
, NULL
);
563 r
= sd_ndisc_router_get_reachable_time(rt
, &reachable_time
);
565 return log_link_warning_errno(link
, r
, "Failed to get reachable time from RA: %m");
567 /* 0 is the unspecified value and must not be set (see RFC4861, 6.3.4) */
568 if (!timestamp_is_set(reachable_time
))
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
);
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
);
580 log_link_warning_errno(link
, r
, "Failed to apply neighbor reachable time (%"PRIu64
"), ignoring: %m", msec
);
585 static int ndisc_router_process_retransmission_time(Link
*link
, sd_ndisc_router
*rt
) {
586 usec_t retrans_time
, msec
;
590 assert(link
->network
);
593 if (!link
->network
->ipv6_accept_ra_use_retransmission_time
)
596 /* Ignore the retransmission time field of the RA header if the lifetime is zero. */
597 r
= sd_ndisc_router_get_lifetime(rt
, NULL
);
601 r
= sd_ndisc_router_get_retransmission_time(rt
, &retrans_time
);
603 return log_link_warning_errno(link
, r
, "Failed to get retransmission time from RA: %m");
605 /* 0 is the unspecified value and must not be set (see RFC4861, 6.3.4) */
606 if (!timestamp_is_set(retrans_time
))
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
);
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
);
618 log_link_warning_errno(link
, r
, "Failed to apply neighbor retransmission time (%"PRIu64
"), ignoring: %m", msec
);
623 static int ndisc_router_process_hop_limit(Link
*link
, sd_ndisc_router
*rt
) {
628 assert(link
->network
);
631 if (!link
->network
->ipv6_accept_ra_use_hop_limit
)
634 /* Ignore the hop limit field of the RA header if the lifetime is zero. */
635 r
= sd_ndisc_router_get_lifetime(rt
, NULL
);
639 r
= sd_ndisc_router_get_hop_limit(rt
, &hop_limit
);
641 return log_link_warning_errno(link
, r
, "Failed to get hop limit from RA: %m");
643 /* 0 is the unspecified value and must not be set (see RFC4861, 6.3.4):
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.
651 * If the received Cur Hop Limit value is non-zero, the host SHOULD set
652 * its CurHopLimit variable to the received value.*/
656 r
= sysctl_write_ip_property_uint32(AF_INET6
, link
->ifname
, "hop_limit", (uint32_t) hop_limit
);
658 log_link_warning_errno(link
, r
, "Failed to apply hop_limit (%u), ignoring: %m", hop_limit
);
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
;
671 assert(link
->network
);
674 if (!link
->network
->ipv6_accept_ra_use_autonomous_prefix
)
677 r
= sd_ndisc_router_prefix_get_address(rt
, &prefix
);
679 return log_link_warning_errno(link
, r
, "Failed to get prefix address: %m");
681 r
= sd_ndisc_router_prefix_get_prefixlen(rt
, &prefixlen
);
683 return log_link_warning_errno(link
, r
, "Failed to get prefix length: %m");
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
));
692 r
= sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt
, CLOCK_BOOTTIME
, &lifetime_valid_usec
);
694 return log_link_warning_errno(link
, r
, "Failed to get prefix valid lifetime: %m");
696 r
= sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(rt
, CLOCK_BOOTTIME
, &lifetime_preferred_usec
);
698 return log_link_warning_errno(link
, r
, "Failed to get prefix preferred lifetime: %m");
700 /* The preferred lifetime is never greater than the valid lifetime */
701 if (lifetime_preferred_usec
> lifetime_valid_usec
)
704 r
= ndisc_generate_addresses(link
, &prefix
, prefixlen
, &addresses
);
706 return log_link_warning_errno(link
, r
, "Failed to generate SLAAC addresses: %m");
708 SET_FOREACH(a
, addresses
) {
709 _cleanup_(address_unrefp
) Address
*address
= NULL
;
711 r
= address_new(&address
);
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
;
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
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
);
732 return log_link_warning_errno(link
, r
, "Could not remove SLAAC address: %m");
734 r
= ndisc_request_address(address
, link
, rt
);
736 return log_link_warning_errno(link
, r
, "Could not request SLAAC address: %m");
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
;
751 assert(link
->network
);
754 if (!link
->network
->ipv6_accept_ra_use_onlink_prefix
)
757 r
= sd_ndisc_router_prefix_get_valid_lifetime_timestamp(rt
, CLOCK_BOOTTIME
, &lifetime_usec
);
759 return log_link_warning_errno(link
, r
, "Failed to get prefix lifetime: %m");
761 r
= sd_ndisc_router_prefix_get_address(rt
, &prefix
);
763 return log_link_warning_errno(link
, r
, "Failed to get prefix address: %m");
765 r
= sd_ndisc_router_prefix_get_prefixlen(rt
, &prefixlen
);
767 return log_link_warning_errno(link
, r
, "Failed to get prefix length: %m");
769 /* Prefix Information option does not have preference, hence we use the 'main' preference here */
770 r
= sd_ndisc_router_get_preference(rt
, &preference
);
772 return log_link_warning_errno(link
, r
, "Failed to get router preference from RA: %m");
774 r
= route_new(&route
);
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
;
784 r
= ndisc_request_route(route
, link
, rt
);
786 return log_link_warning_errno(link
, r
, "Could not request prefix route: %m");
791 static int ndisc_router_drop_onlink_prefix(Link
*link
, sd_ndisc_router
*rt
) {
792 _cleanup_(route_unrefp
) Route
*route
= NULL
;
794 struct in6_addr prefix
;
795 usec_t lifetime_usec
;
799 assert(link
->network
);
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. */
808 if (!link
->network
->ipv6_accept_ra_use_onlink_prefix
)
811 r
= sd_ndisc_router_prefix_get_valid_lifetime(rt
, &lifetime_usec
);
813 return log_link_warning_errno(link
, r
, "Failed to get prefix lifetime: %m");
815 if (lifetime_usec
!= 0)
818 r
= sd_ndisc_router_prefix_get_address(rt
, &prefix
);
820 return log_link_warning_errno(link
, r
, "Failed to get prefix address: %m");
822 r
= sd_ndisc_router_prefix_get_prefixlen(rt
, &prefixlen
);
824 return log_link_warning_errno(link
, r
, "Failed to get prefix length: %m");
826 r
= route_new(&route
);
830 route
->family
= AF_INET6
;
831 route
->dst
.in6
= prefix
;
832 route
->dst_prefixlen
= prefixlen
;
834 r
= ndisc_remove_route(route
, link
);
836 return log_link_warning_errno(link
, r
, "Could not remove prefix route: %m");
841 static int ndisc_router_process_prefix(Link
*link
, sd_ndisc_router
*rt
) {
848 assert(link
->network
);
851 r
= sd_ndisc_router_prefix_get_address(rt
, &a
);
853 return log_link_warning_errno(link
, r
, "Failed to get prefix address: %m");
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.");
863 r
= sd_ndisc_router_prefix_get_prefixlen(rt
, &prefixlen
);
865 return log_link_warning_errno(link
, r
, "Failed to get prefix length: %m");
867 if (in6_prefix_is_filtered(&a
, prefixlen
, link
->network
->ndisc_allow_listed_prefix
, link
->network
->ndisc_deny_listed_prefix
)) {
869 log_link_debug(link
, "Prefix '%s' is %s, ignoring",
870 !set_isempty(link
->network
->ndisc_allow_listed_prefix
) ? "not in allow list"
872 IN6_ADDR_PREFIX_TO_STRING(&a
, prefixlen
));
876 r
= sd_ndisc_router_prefix_get_flags(rt
, &flags
);
878 return log_link_warning_errno(link
, r
, "Failed to get RA prefix flags: %m");
880 if (FLAGS_SET(flags
, ND_OPT_PI_FLAG_ONLINK
))
881 r
= ndisc_router_process_onlink_prefix(link
, rt
);
883 r
= ndisc_router_drop_onlink_prefix(link
, rt
);
887 if (FLAGS_SET(flags
, ND_OPT_PI_FLAG_AUTO
)) {
888 r
= ndisc_router_process_autonomous_prefix(link
, rt
);
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
;
905 if (!link
->network
->ipv6_accept_ra_use_route_prefix
)
908 r
= sd_ndisc_router_route_get_lifetime_timestamp(rt
, CLOCK_BOOTTIME
, &lifetime_usec
);
910 return log_link_warning_errno(link
, r
, "Failed to get route lifetime from RA: %m");
912 r
= sd_ndisc_router_route_get_address(rt
, &dst
);
914 return log_link_warning_errno(link
, r
, "Failed to get route destination address: %m");
916 r
= sd_ndisc_router_route_get_prefixlen(rt
, &prefixlen
);
918 return log_link_warning_errno(link
, r
, "Failed to get route prefix length: %m");
920 if (in6_addr_is_null(&dst
) && prefixlen
== 0) {
921 log_link_debug(link
, "Route prefix is ::/0, ignoring");
925 if (in6_prefix_is_filtered(&dst
, prefixlen
,
926 link
->network
->ndisc_allow_listed_route_prefix
,
927 link
->network
->ndisc_deny_listed_route_prefix
)) {
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"
933 IN6_ADDR_PREFIX_TO_STRING(&dst
, prefixlen
));
937 r
= sd_ndisc_router_get_address(rt
, &gateway
);
939 return log_link_warning_errno(link
, r
, "Failed to get gateway address from RA: %m");
941 if (link_get_ipv6_address(link
, &gateway
, 0, NULL
) >= 0) {
943 log_link_debug(link
, "Advertised route gateway %s is local to the link, ignoring route",
944 IN6_ADDR_TO_STRING(&gateway
));
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");
954 return log_link_warning_errno(link
, r
, "Failed to get router preference from RA: %m");
956 r
= route_new(&route
);
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
;
968 r
= ndisc_request_route(route
, link
, rt
);
970 return log_link_warning_errno(link
, r
, "Could not request additional route: %m");
975 static void ndisc_rdnss_hash_func(const NDiscRDNSS
*x
, struct siphash
*state
) {
976 siphash24_compress_typesafe(x
->address
, state
);
979 static int ndisc_rdnss_compare_func(const NDiscRDNSS
*a
, const NDiscRDNSS
*b
) {
980 return memcmp(&a
->address
, &b
->address
, sizeof(a
->address
));
983 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
984 ndisc_rdnss_hash_ops
,
986 ndisc_rdnss_hash_func
,
987 ndisc_rdnss_compare_func
,
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;
998 assert(link
->network
);
1001 if (!link
->network
->ipv6_accept_ra_use_dns
)
1004 r
= sd_ndisc_router_get_address(rt
, &router
);
1006 return log_link_warning_errno(link
, r
, "Failed to get router address from RA: %m");
1008 r
= sd_ndisc_router_rdnss_get_lifetime_timestamp(rt
, CLOCK_BOOTTIME
, &lifetime_usec
);
1010 return log_link_warning_errno(link
, r
, "Failed to get RDNSS lifetime: %m");
1012 n
= sd_ndisc_router_rdnss_get_addresses(rt
, &a
);
1014 return log_link_warning_errno(link
, n
, "Failed to get RDNSS addresses: %m");
1016 for (int j
= 0; j
< n
; j
++) {
1017 _cleanup_free_ NDiscRDNSS
*x
= NULL
;
1018 NDiscRDNSS
*rdnss
, d
= {
1022 if (lifetime_usec
== 0) {
1023 /* The entry is outdated. */
1024 free(set_remove(link
->ndisc_rdnss
, &d
));
1029 rdnss
= set_get(link
->ndisc_rdnss
, &d
);
1031 rdnss
->router
= router
;
1032 rdnss
->lifetime_usec
= lifetime_usec
;
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;
1043 x
= new(NDiscRDNSS
, 1);
1050 .lifetime_usec
= lifetime_usec
,
1053 r
= set_ensure_consume(&link
->ndisc_rdnss
, &ndisc_rdnss_hash_ops
, TAKE_PTR(x
));
1067 static void ndisc_dnssl_hash_func(const NDiscDNSSL
*x
, struct siphash
*state
) {
1068 siphash24_compress_string(NDISC_DNSSL_DOMAIN(x
), state
);
1071 static int ndisc_dnssl_compare_func(const NDiscDNSSL
*a
, const NDiscDNSSL
*b
) {
1072 return strcmp(NDISC_DNSSL_DOMAIN(a
), NDISC_DNSSL_DOMAIN(b
));
1075 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
1076 ndisc_dnssl_hash_ops
,
1078 ndisc_dnssl_hash_func
,
1079 ndisc_dnssl_compare_func
,
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;
1090 assert(link
->network
);
1093 if (link
->network
->ipv6_accept_ra_use_domains
== DHCP_USE_DOMAINS_NO
)
1096 r
= sd_ndisc_router_get_address(rt
, &router
);
1098 return log_link_warning_errno(link
, r
, "Failed to get router address from RA: %m");
1100 r
= sd_ndisc_router_dnssl_get_lifetime_timestamp(rt
, CLOCK_BOOTTIME
, &lifetime_usec
);
1102 return log_link_warning_errno(link
, r
, "Failed to get DNSSL lifetime: %m");
1104 r
= sd_ndisc_router_dnssl_get_domains(rt
, &l
);
1106 return log_link_warning_errno(link
, r
, "Failed to get DNSSL addresses: %m");
1108 STRV_FOREACH(j
, l
) {
1109 _cleanup_free_ NDiscDNSSL
*s
= NULL
;
1112 s
= malloc0(ALIGN(sizeof(NDiscDNSSL
)) + strlen(*j
) + 1);
1116 strcpy(NDISC_DNSSL_DOMAIN(s
), *j
);
1118 if (lifetime_usec
== 0) {
1119 /* The entry is outdated. */
1120 free(set_remove(link
->ndisc_dnssl
, s
));
1125 dnssl
= set_get(link
->ndisc_dnssl
, s
);
1127 dnssl
->router
= router
;
1128 dnssl
->lifetime_usec
= lifetime_usec
;
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;
1140 s
->lifetime_usec
= lifetime_usec
;
1142 r
= set_ensure_consume(&link
->ndisc_dnssl
, &ndisc_dnssl_hash_ops
, TAKE_PTR(s
));
1156 static NDiscCaptivePortal
* ndisc_captive_portal_free(NDiscCaptivePortal
*x
) {
1160 free(x
->captive_portal
);
1164 DEFINE_TRIVIAL_CLEANUP_FUNC(NDiscCaptivePortal
*, ndisc_captive_portal_free
);
1166 static void ndisc_captive_portal_hash_func(const NDiscCaptivePortal
*x
, struct siphash
*state
) {
1168 siphash24_compress_string(x
->captive_portal
, state
);
1171 static int ndisc_captive_portal_compare_func(const NDiscCaptivePortal
*a
, const NDiscCaptivePortal
*b
) {
1174 return strcmp_ptr(a
->captive_portal
, b
->captive_portal
);
1177 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
1178 ndisc_captive_portal_hash_ops
,
1180 ndisc_captive_portal_hash_func
,
1181 ndisc_captive_portal_compare_func
,
1182 ndisc_captive_portal_free
);
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
;
1195 assert(link
->network
);
1198 if (!link
->network
->ipv6_accept_ra_use_captive_portal
)
1201 r
= sd_ndisc_router_get_address(rt
, &router
);
1203 return log_link_warning_errno(link
, r
, "Failed to get router address from RA: %m");
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
);
1210 return log_link_warning_errno(link
, r
, "Failed to get lifetime of RA message: %m");
1212 r
= sd_ndisc_router_captive_portal_get_uri(rt
, &uri
, &len
);
1214 return log_link_warning_errno(link
, r
, "Failed to get captive portal from RA: %m");
1217 return log_link_warning_errno(link
, SYNTHETIC_ERRNO(EBADMSG
), "Received empty captive portal, ignoring.");
1219 r
= make_cstring(uri
, len
, MAKE_CSTRING_REFUSE_TRAILING_NUL
, &captive_portal
);
1221 return log_link_warning_errno(link
, r
, "Failed to convert captive portal URI: %m");
1223 if (!in_charset(captive_portal
, URI_VALID
))
1224 return log_link_warning_errno(link
, SYNTHETIC_ERRNO(EBADMSG
), "Received invalid captive portal, ignoring.");
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
,
1235 exist
= set_get(link
->ndisc_captive_portals
,
1236 &(NDiscCaptivePortal
) {
1237 .captive_portal
= captive_portal
,
1240 /* update existing entry */
1241 exist
->router
= router
;
1242 exist
->lifetime_usec
= lifetime_usec
;
1246 if (set_size(link
->ndisc_captive_portals
) >= NDISC_CAPTIVE_PORTAL_MAX
) {
1247 NDiscCaptivePortal
*c
, *target
= NULL
;
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
)
1255 assert(set_remove(link
->ndisc_captive_portals
, target
) == target
);
1256 ndisc_captive_portal_free(target
);
1259 new_entry
= new(NDiscCaptivePortal
, 1);
1263 *new_entry
= (NDiscCaptivePortal
) {
1265 .lifetime_usec
= lifetime_usec
,
1266 .captive_portal
= TAKE_PTR(captive_portal
),
1269 r
= set_ensure_put(&link
->ndisc_captive_portals
, &ndisc_captive_portal_hash_ops
, new_entry
);
1273 TAKE_PTR(new_entry
);
1279 static void ndisc_pref64_hash_func(const NDiscPREF64
*x
, struct siphash
*state
) {
1282 siphash24_compress_typesafe(x
->prefix_len
, state
);
1283 siphash24_compress_typesafe(x
->prefix
, state
);
1286 static int ndisc_pref64_compare_func(const NDiscPREF64
*a
, const NDiscPREF64
*b
) {
1292 r
= CMP(a
->prefix_len
, b
->prefix_len
);
1296 return memcmp(&a
->prefix
, &b
->prefix
, sizeof(a
->prefix
));
1299 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
1300 ndisc_pref64_hash_ops
,
1302 ndisc_pref64_hash_func
,
1303 ndisc_pref64_compare_func
,
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
;
1315 assert(link
->network
);
1318 if (!link
->network
->ipv6_accept_ra_use_pref64
)
1321 r
= sd_ndisc_router_get_address(rt
, &router
);
1323 return log_link_warning_errno(link
, r
, "Failed to get router address from RA: %m");
1325 r
= sd_ndisc_router_prefix64_get_prefix(rt
, &a
);
1327 return log_link_warning_errno(link
, r
, "Failed to get pref64 prefix: %m");
1329 r
= sd_ndisc_router_prefix64_get_prefixlen(rt
, &prefix_len
);
1331 return log_link_warning_errno(link
, r
, "Failed to get pref64 prefix length: %m");
1333 r
= sd_ndisc_router_prefix64_get_lifetime_timestamp(rt
, CLOCK_BOOTTIME
, &lifetime_usec
);
1335 return log_link_warning_errno(link
, r
, "Failed to get pref64 prefix lifetime: %m");
1337 if (lifetime_usec
== 0) {
1338 free(set_remove(link
->ndisc_pref64
,
1341 .prefix_len
= prefix_len
1346 exist
= set_get(link
->ndisc_pref64
,
1349 .prefix_len
= prefix_len
1352 /* update existing entry */
1353 exist
->router
= router
;
1354 exist
->lifetime_usec
= lifetime_usec
;
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
);
1363 new_entry
= new(NDiscPREF64
, 1);
1367 *new_entry
= (NDiscPREF64
) {
1369 .lifetime_usec
= lifetime_usec
,
1371 .prefix_len
= prefix_len
,
1374 r
= set_ensure_put(&link
->ndisc_pref64
, &ndisc_pref64_hash_ops
, new_entry
);
1379 TAKE_PTR(new_entry
);
1384 static int ndisc_router_process_options(Link
*link
, sd_ndisc_router
*rt
) {
1385 size_t n_captive_portal
= 0;
1389 assert(link
->network
);
1392 for (r
= sd_ndisc_router_option_rewind(rt
); ; r
= sd_ndisc_router_option_next(rt
)) {
1396 return log_link_warning_errno(link
, r
, "Failed to iterate through options: %m");
1397 if (r
== 0) /* EOF */
1400 r
= sd_ndisc_router_option_get_type(rt
, &type
);
1402 return log_link_warning_errno(link
, r
, "Failed to get RA option type: %m");
1405 case SD_NDISC_OPTION_PREFIX_INFORMATION
:
1406 r
= ndisc_router_process_prefix(link
, rt
);
1409 case SD_NDISC_OPTION_ROUTE_INFORMATION
:
1410 r
= ndisc_router_process_route(link
, rt
);
1413 case SD_NDISC_OPTION_RDNSS
:
1414 r
= ndisc_router_process_rdnss(link
, rt
);
1417 case SD_NDISC_OPTION_DNSSL
:
1418 r
= ndisc_router_process_dnssl(link
, rt
);
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.");
1428 r
= ndisc_router_process_captive_portal(link
, rt
);
1432 case SD_NDISC_OPTION_PREF64
:
1433 r
= ndisc_router_process_pref64(link
, rt
);
1436 if (r
< 0 && r
!= -EBADMSG
)
1441 static int ndisc_drop_outdated(Link
*link
, usec_t timestamp_usec
) {
1442 bool updated
= false;
1445 NDiscCaptivePortal
*cp
;
1452 assert(link
->manager
);
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. */
1460 SET_FOREACH(route
, link
->manager
->routes
) {
1461 if (route
->source
!= NETWORK_CONFIG_SOURCE_NDISC
)
1464 if (route
->nexthop
.ifindex
!= link
->ifindex
)
1467 if (route
->lifetime_usec
>= timestamp_usec
)
1468 continue; /* the route is still valid */
1470 r
= route_remove_and_cancel(route
, link
->manager
);
1472 RET_GATHER(ret
, log_link_warning_errno(link
, r
, "Failed to remove outdated SLAAC route, ignoring: %m"));
1475 SET_FOREACH(address
, link
->addresses
) {
1476 if (address
->source
!= NETWORK_CONFIG_SOURCE_NDISC
)
1479 if (address
->lifetime_valid_usec
>= timestamp_usec
)
1480 continue; /* the address is still valid */
1482 r
= address_remove_and_cancel(address
, link
);
1484 RET_GATHER(ret
, log_link_warning_errno(link
, r
, "Failed to remove outdated SLAAC address, ignoring: %m"));
1487 SET_FOREACH(rdnss
, link
->ndisc_rdnss
) {
1488 if (rdnss
->lifetime_usec
>= timestamp_usec
)
1489 continue; /* the DNS server is still valid */
1491 free(set_remove(link
->ndisc_rdnss
, rdnss
));
1495 SET_FOREACH(dnssl
, link
->ndisc_dnssl
) {
1496 if (dnssl
->lifetime_usec
>= timestamp_usec
)
1497 continue; /* the DNS domain is still valid */
1499 free(set_remove(link
->ndisc_dnssl
, dnssl
));
1503 SET_FOREACH(cp
, link
->ndisc_captive_portals
) {
1504 if (cp
->lifetime_usec
>= timestamp_usec
)
1505 continue; /* the captive portal is still valid */
1507 ndisc_captive_portal_free(set_remove(link
->ndisc_captive_portals
, cp
));
1511 SET_FOREACH(p64
, link
->ndisc_pref64
) {
1512 if (p64
->lifetime_usec
>= timestamp_usec
)
1513 continue; /* the pref64 prefix is still valid */
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. */
1526 static int ndisc_setup_expire(Link
*link
);
1528 static int ndisc_expire_handler(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
1529 Link
*link
= ASSERT_PTR(userdata
);
1532 assert(link
->manager
);
1534 assert_se(sd_event_now(link
->manager
->event
, CLOCK_BOOTTIME
, &now_usec
) >= 0);
1536 (void) ndisc_drop_outdated(link
, now_usec
);
1537 (void) ndisc_setup_expire(link
);
1541 static int ndisc_setup_expire(Link
*link
) {
1542 usec_t lifetime_usec
= USEC_INFINITY
;
1543 NDiscCaptivePortal
*cp
;
1552 assert(link
->manager
);
1554 SET_FOREACH(route
, link
->manager
->routes
) {
1555 if (route
->source
!= NETWORK_CONFIG_SOURCE_NDISC
)
1558 if (route
->nexthop
.ifindex
!= link
->ifindex
)
1561 if (!route_exists(route
))
1564 lifetime_usec
= MIN(lifetime_usec
, route
->lifetime_usec
);
1567 SET_FOREACH(address
, link
->addresses
) {
1568 if (address
->source
!= NETWORK_CONFIG_SOURCE_NDISC
)
1571 if (!address_exists(address
))
1574 lifetime_usec
= MIN(lifetime_usec
, address
->lifetime_valid_usec
);
1577 SET_FOREACH(rdnss
, link
->ndisc_rdnss
)
1578 lifetime_usec
= MIN(lifetime_usec
, rdnss
->lifetime_usec
);
1580 SET_FOREACH(dnssl
, link
->ndisc_dnssl
)
1581 lifetime_usec
= MIN(lifetime_usec
, dnssl
->lifetime_usec
);
1583 SET_FOREACH(cp
, link
->ndisc_captive_portals
)
1584 lifetime_usec
= MIN(lifetime_usec
, cp
->lifetime_usec
);
1586 SET_FOREACH(p64
, link
->ndisc_pref64
)
1587 lifetime_usec
= MIN(lifetime_usec
, p64
->lifetime_usec
);
1589 if (lifetime_usec
== USEC_INFINITY
)
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);
1595 return log_link_warning_errno(link
, r
, "Failed to update expiration timer for ndisc: %m");
1600 static int ndisc_start_dhcp6_client(Link
*link
, sd_ndisc_router
*rt
) {
1604 assert(link
->network
);
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
);
1612 switch (link
->network
->ipv6_accept_ra_start_dhcp6_client
) {
1613 case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO
:
1616 case IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES
: {
1619 r
= sd_ndisc_router_get_flags(rt
, &flags
);
1621 return log_link_warning_errno(link
, r
, "Failed to get RA flags: %m");
1623 if ((flags
& (ND_RA_FLAG_MANAGED
| ND_RA_FLAG_OTHER
)) == 0)
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
));
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);
1639 assert_not_reached();
1643 return log_link_warning_errno(link
, r
, "Could not acquire DHCPv6 lease on NDisc request: %m");
1645 log_link_debug(link
, "Acquiring DHCPv6 lease on NDisc request");
1649 static int ndisc_router_handler(Link
*link
, sd_ndisc_router
*rt
) {
1650 struct in6_addr router
;
1651 usec_t timestamp_usec
;
1655 assert(link
->network
);
1656 assert(link
->manager
);
1659 r
= sd_ndisc_router_get_address(rt
, &router
);
1660 if (r
== -ENODATA
) {
1661 log_link_debug(link
, "Received RA without router address, ignoring.");
1665 return log_link_warning_errno(link
, r
, "Failed to get router address from RA: %m");
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
));
1672 log_link_debug(link
, "Router %s is in deny list, ignoring.", IN6_ADDR_TO_STRING(&router
));
1677 r
= sd_ndisc_router_get_timestamp(rt
, CLOCK_BOOTTIME
, ×tamp_usec
);
1678 if (r
== -ENODATA
) {
1679 log_link_debug(link
, "Received RA without timestamp, ignoring.");
1685 r
= ndisc_drop_outdated(link
, timestamp_usec
);
1689 r
= ndisc_start_dhcp6_client(link
, rt
);
1693 r
= ndisc_router_process_default(link
, rt
);
1697 r
= ndisc_router_process_icmp6_ratelimit(link
, rt
);
1701 r
= ndisc_router_process_reachable_time(link
, rt
);
1705 r
= ndisc_router_process_retransmission_time(link
, rt
);
1709 r
= ndisc_router_process_hop_limit(link
, rt
);
1713 r
= ndisc_router_process_options(link
, rt
);
1717 r
= ndisc_setup_expire(link
);
1721 if (link
->ndisc_messages
== 0)
1722 link
->ndisc_configured
= true;
1724 log_link_debug(link
, "Setting SLAAC addresses and router.");
1726 if (!link
->ndisc_configured
)
1727 link_set_state(link
, LINK_STATE_CONFIGURING
);
1729 link_check_ready(link
);
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
);
1737 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
1742 case SD_NDISC_EVENT_ROUTER
:
1743 r
= ndisc_router_handler(link
, rt
);
1744 if (r
< 0 && r
!= -EBADMSG
) {
1745 link_enter_failed(link
);
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
);
1758 assert_not_reached();
1762 static int ndisc_configure(Link
*link
) {
1767 if (!link_ipv6_accept_ra_enabled(link
))
1771 return -EBUSY
; /* Already configured. */
1773 r
= sd_ndisc_new(&link
->ndisc
);
1777 r
= sd_ndisc_attach_event(link
->ndisc
, link
->manager
->event
, 0);
1781 if (link
->hw_addr
.length
== ETH_ALEN
) {
1782 r
= sd_ndisc_set_mac(link
->ndisc
, &link
->hw_addr
.ether
);
1787 r
= sd_ndisc_set_ifindex(link
->ndisc
, link
->ifindex
);
1791 r
= sd_ndisc_set_callback(link
->ndisc
, ndisc_handler
, link
);
1798 int ndisc_start(Link
*link
) {
1803 if (!link
->ndisc
|| !link
->dhcp6_client
)
1806 if (!link_has_carrier(link
))
1809 if (in6_addr_is_null(&link
->ipv6ll_address
))
1812 log_link_debug(link
, "Discovering IPv6 routers");
1814 r
= sd_ndisc_start(link
->ndisc
);
1821 static int ndisc_process_request(Request
*req
, Link
*link
, void *userdata
) {
1826 if (!link_is_ready_to_configure(link
, /* allow_unmanaged = */ false))
1829 r
= ndisc_configure(link
);
1831 return log_link_warning_errno(link
, r
, "Failed to configure IPv6 Router Discovery: %m");
1833 r
= ndisc_start(link
);
1835 return log_link_warning_errno(link
, r
, "Failed to start IPv6 Router Discovery: %m");
1837 log_link_debug(link
, "IPv6 Router Discovery is configured%s.",
1838 r
> 0 ? " and started" : "");
1842 int link_request_ndisc(Link
*link
) {
1847 if (!link_ipv6_accept_ra_enabled(link
))
1853 r
= link_queue_request(link
, REQUEST_TYPE_NDISC
, ndisc_process_request
, NULL
);
1855 return log_link_warning_errno(link
, r
, "Failed to request configuring of the IPv6 Router Discovery: %m");
1857 log_link_debug(link
, "Requested configuring of the IPv6 Router Discovery.");
1861 int ndisc_stop(Link
*link
) {
1864 link
->ndisc_expire
= sd_event_source_disable_unref(link
->ndisc_expire
);
1866 return sd_ndisc_stop(link
->ndisc
);
1870 void ndisc_flush(Link
*link
) {
1873 /* Remove all addresses, routes, RDNSS, DNSSL, and Captive Portal entries, without exception. */
1874 (void) ndisc_drop_outdated(link
, /* timestamp_usec = */ USEC_INFINITY
);
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
);
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",
1888 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(ipv6_accept_ra_start_dhcp6_client
, IPv6AcceptRAStartDHCP6Client
, IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES
);
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");