1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright © 2014 Intel Corporation. All rights reserved.
6 #include <netinet/icmp6.h>
11 #include "missing_network.h"
12 #include "networkd-dhcp6.h"
13 #include "networkd-manager.h"
14 #include "networkd-ndisc.h"
15 #include "networkd-route.h"
16 #include "string-util.h"
19 #define NDISC_DNSSL_MAX 64U
20 #define NDISC_RDNSS_MAX 64U
21 #define NDISC_PREFIX_LFT_MIN 7200U
23 #define DAD_CONFLICTS_IDGEN_RETRIES_RFC7217 3
25 /* https://tools.ietf.org/html/rfc5453 */
26 /* https://www.iana.org/assignments/ipv6-interface-ids/ipv6-interface-ids.xml */
28 #define SUBNET_ROUTER_ANYCAST_ADDRESS_RFC4291 ((struct in6_addr) { .s6_addr = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } })
29 #define SUBNET_ROUTER_ANYCAST_PREFIXLEN 8
30 #define RESERVED_IPV6_INTERFACE_IDENTIFIERS_ADDRESS_RFC4291 ((struct in6_addr) { .s6_addr = { 0x02, 0x00, 0x5E, 0xFF, 0xFE } })
31 #define RESERVED_IPV6_INTERFACE_IDENTIFIERS_PREFIXLEN 5
32 #define RESERVED_SUBNET_ANYCAST_ADDRESSES_RFC4291 ((struct in6_addr) { .s6_addr = { 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } })
33 #define RESERVED_SUBNET_ANYCAST_PREFIXLEN 7
35 #define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e)
37 static bool stableprivate_address_is_valid(const struct in6_addr
*addr
) {
40 /* According to rfc4291, generated address should not be in the following ranges. */
42 if (memcmp(addr
, &SUBNET_ROUTER_ANYCAST_ADDRESS_RFC4291
, SUBNET_ROUTER_ANYCAST_PREFIXLEN
) == 0)
45 if (memcmp(addr
, &RESERVED_IPV6_INTERFACE_IDENTIFIERS_ADDRESS_RFC4291
, RESERVED_IPV6_INTERFACE_IDENTIFIERS_PREFIXLEN
) == 0)
48 if (memcmp(addr
, &RESERVED_SUBNET_ANYCAST_ADDRESSES_RFC4291
, RESERVED_SUBNET_ANYCAST_PREFIXLEN
) == 0)
54 static int make_stableprivate_address(Link
*link
, const struct in6_addr
*prefix
, uint8_t prefix_len
, uint8_t dad_counter
, struct in6_addr
*addr
) {
55 sd_id128_t secret_key
;
61 /* According to rfc7217 section 5.1
62 * RID = F(Prefix, Net_Iface, Network_ID, DAD_Counter, secret_key) */
64 r
= sd_id128_get_machine_app_specific(NDISC_APP_ID
, &secret_key
);
66 return log_error_errno(r
, "Failed to generate key: %m");
68 siphash24_init(&state
, secret_key
.bytes
);
70 l
= MAX(DIV_ROUND_UP(prefix_len
, 8), 8);
71 siphash24_compress(prefix
, l
, &state
);
72 siphash24_compress(link
->ifname
, strlen(link
->ifname
), &state
);
73 siphash24_compress(&link
->mac
, sizeof(struct ether_addr
), &state
);
74 siphash24_compress(&dad_counter
, sizeof(uint8_t), &state
);
76 rid
= htole64(siphash24_finalize(&state
));
78 memcpy(addr
->s6_addr
, prefix
->s6_addr
, l
);
79 memcpy((uint8_t *) &addr
->s6_addr
+ l
, &rid
, 16 - l
);
84 static int ndisc_netlink_route_message_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
88 assert(link
->ndisc_messages
> 0);
90 link
->ndisc_messages
--;
92 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
95 r
= sd_netlink_message_get_errno(m
);
96 if (r
< 0 && r
!= -EEXIST
) {
97 log_link_message_error_errno(link
, m
, r
, "Could not set NDisc route or address");
98 link_enter_failed(link
);
102 if (link
->ndisc_messages
== 0) {
103 link
->ndisc_configured
= true;
104 r
= link_request_set_routes(link
);
106 link_enter_failed(link
);
109 link_check_ready(link
);
115 static int ndisc_netlink_address_message_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
119 assert(link
->ndisc_messages
> 0);
121 link
->ndisc_messages
--;
123 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
126 r
= sd_netlink_message_get_errno(m
);
127 if (r
< 0 && r
!= -EEXIST
) {
128 log_link_message_error_errno(link
, m
, r
, "Could not set NDisc route or address");
129 link_enter_failed(link
);
132 (void) manager_rtnl_process_address(rtnl
, m
, link
->manager
);
134 if (link
->ndisc_messages
== 0) {
135 link
->ndisc_configured
= true;
136 r
= link_request_set_routes(link
);
138 link_enter_failed(link
);
141 link_check_ready(link
);
147 static int ndisc_router_process_default(Link
*link
, sd_ndisc_router
*rt
) {
148 _cleanup_(route_freep
) Route
*route
= NULL
;
149 union in_addr_union gateway
;
161 r
= sd_ndisc_router_get_lifetime(rt
, &lifetime
);
163 return log_link_warning_errno(link
, r
, "Failed to get gateway address from RA: %m");
165 if (lifetime
== 0) /* not a default router */
168 r
= sd_ndisc_router_get_address(rt
, &gateway
.in6
);
170 return log_link_warning_errno(link
, r
, "Failed to get gateway address from RA: %m");
172 SET_FOREACH(address
, link
->addresses
, i
) {
173 if (address
->family
!= AF_INET6
)
175 if (in_addr_equal(AF_INET6
, &gateway
, &address
->in_addr
)) {
176 _cleanup_free_
char *buffer
= NULL
;
178 (void) in_addr_to_string(AF_INET6
, &address
->in_addr
, &buffer
);
179 log_link_debug(link
, "No NDisc route added, gateway %s matches local address",
185 SET_FOREACH(address
, link
->addresses_foreign
, i
) {
186 if (address
->family
!= AF_INET6
)
188 if (in_addr_equal(AF_INET6
, &gateway
, &address
->in_addr
)) {
189 _cleanup_free_
char *buffer
= NULL
;
191 (void) in_addr_to_string(AF_INET6
, &address
->in_addr
, &buffer
);
192 log_link_debug(link
, "No NDisc route added, gateway %s matches local address",
198 r
= sd_ndisc_router_get_preference(rt
, &preference
);
200 return log_link_warning_errno(link
, r
, "Failed to get default router preference from RA: %m");
202 r
= sd_ndisc_router_get_timestamp(rt
, clock_boottime_or_monotonic(), &time_now
);
204 return log_link_warning_errno(link
, r
, "Failed to get RA timestamp: %m");
206 r
= sd_ndisc_router_get_mtu(rt
, &mtu
);
210 return log_link_warning_errno(link
, r
, "Failed to get default router MTU from RA: %m");
212 r
= route_new(&route
);
214 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
216 route
->family
= AF_INET6
;
217 route
->table
= link_get_ipv6_accept_ra_route_table(link
);
218 route
->priority
= link
->network
->dhcp_route_metric
;
219 route
->protocol
= RTPROT_RA
;
220 route
->pref
= preference
;
222 route
->lifetime
= time_now
+ lifetime
* USEC_PER_SEC
;
225 r
= route_configure(route
, link
, ndisc_netlink_route_message_handler
);
227 log_link_warning_errno(link
, r
, "Could not set default route: %m");
228 link_enter_failed(link
);
232 link
->ndisc_messages
++;
235 LIST_FOREACH(routes
, route_gw
, link
->network
->static_routes
) {
236 if (!route_gw
->gateway_from_dhcp
)
239 if (route_gw
->family
!= AF_INET6
)
242 route_gw
->gw
= gateway
;
244 r
= route_configure(route_gw
, link
, ndisc_netlink_route_message_handler
);
246 log_link_error_errno(link
, r
, "Could not set gateway: %m");
247 link_enter_failed(link
);
251 link
->ndisc_messages
++;
257 static int ndisc_router_generate_addresses(Link
*link
, unsigned prefixlen
, uint32_t lifetime_preferred
, Address
*address
, Set
**ret
) {
258 _cleanup_set_free_free_ Set
*addresses
= NULL
;
259 struct in6_addr addr
;
268 addresses
= set_new(&address_hash_ops
);
272 addr
= address
->in_addr
.in6
;
273 ORDERED_HASHMAP_FOREACH(j
, link
->network
->ipv6_tokens
, i
) {
274 bool have_address
= false;
275 _cleanup_(address_freep
) Address
*new_address
= NULL
;
277 r
= address_new(&new_address
);
281 *new_address
= *address
;
283 if (j
->address_generation_type
== IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE
284 && memcmp(&j
->prefix
, &addr
, FAMILY_ADDRESS_SIZE(address
->family
)) == 0) {
285 /* While this loop uses dad_counter and a retry limit as specified in RFC 7217, the loop
286 does not actually attempt Duplicate Address Detection; the counter will be incremented
287 only when the address generation algorithm produces an invalid address, and the loop
288 may exit with an address which ends up being unusable due to duplication on the link.
290 for (; j
->dad_counter
< DAD_CONFLICTS_IDGEN_RETRIES_RFC7217
; j
->dad_counter
++) {
291 r
= make_stableprivate_address(link
, &j
->prefix
, prefixlen
, j
->dad_counter
, &new_address
->in_addr
.in6
);
295 if (stableprivate_address_is_valid(&new_address
->in_addr
.in6
)) {
300 } else if (j
->address_generation_type
== IPV6_TOKEN_ADDRESS_GENERATION_STATIC
) {
301 memcpy(((uint8_t *)&new_address
->in_addr
.in6
) + 8, ((uint8_t *) &j
->prefix
) + 8, 8);
306 new_address
->prefixlen
= prefixlen
;
307 new_address
->flags
= IFA_F_NOPREFIXROUTE
|IFA_F_MANAGETEMPADDR
;
308 new_address
->cinfo
.ifa_prefered
= lifetime_preferred
;
310 r
= set_put(addresses
, new_address
);
312 return log_link_warning_errno(link
, r
, "Failed to store address: %m");
313 TAKE_PTR(new_address
);
317 /* fall back to EUI-64 if no tokens provided addresses */
318 if (set_isempty(addresses
)) {
319 _cleanup_(address_freep
) Address
*new_address
= NULL
;
321 r
= address_new(&new_address
);
325 *new_address
= *address
;
327 r
= generate_ipv6_eui_64_address(link
, &new_address
->in_addr
.in6
);
329 return log_link_error_errno(link
, r
, "Failed to generate EUI64 address: %m");
331 new_address
->prefixlen
= prefixlen
;
332 new_address
->flags
= IFA_F_NOPREFIXROUTE
|IFA_F_MANAGETEMPADDR
;
333 new_address
->cinfo
.ifa_prefered
= lifetime_preferred
;
335 r
= set_put(addresses
, new_address
);
337 return log_link_warning_errno(link
, r
, "Failed to store address: %m");
338 TAKE_PTR(new_address
);
341 *ret
= TAKE_PTR(addresses
);
346 static int ndisc_router_process_autonomous_prefix(Link
*link
, sd_ndisc_router
*rt
) {
347 uint32_t lifetime_valid
, lifetime_preferred
, lifetime_remaining
;
348 _cleanup_set_free_free_ Set
*addresses
= NULL
;
349 _cleanup_(address_freep
) Address
*address
= NULL
;
352 Address
*existing_address
, *a
;
359 r
= sd_ndisc_router_get_timestamp(rt
, clock_boottime_or_monotonic(), &time_now
);
361 return log_link_warning_errno(link
, r
, "Failed to get RA timestamp: %m");
363 r
= sd_ndisc_router_prefix_get_prefixlen(rt
, &prefixlen
);
365 return log_link_error_errno(link
, r
, "Failed to get prefix length: %m");
367 r
= sd_ndisc_router_prefix_get_valid_lifetime(rt
, &lifetime_valid
);
369 return log_link_error_errno(link
, r
, "Failed to get prefix valid lifetime: %m");
371 r
= sd_ndisc_router_prefix_get_preferred_lifetime(rt
, &lifetime_preferred
);
373 return log_link_error_errno(link
, r
, "Failed to get prefix preferred lifetime: %m");
375 /* The preferred lifetime is never greater than the valid lifetime */
376 if (lifetime_preferred
> lifetime_valid
)
379 r
= address_new(&address
);
381 return log_link_error_errno(link
, r
, "Could not allocate address: %m");
383 address
->family
= AF_INET6
;
384 r
= sd_ndisc_router_prefix_get_address(rt
, &address
->in_addr
.in6
);
386 return log_link_error_errno(link
, r
, "Failed to get prefix address: %m");
388 r
= ndisc_router_generate_addresses(link
, prefixlen
, lifetime_preferred
, address
, &addresses
);
390 return log_link_error_errno(link
, r
, "Failed to generate SLAAC addresses: %m");
392 SET_FOREACH(a
, addresses
, i
) {
393 /* see RFC4862 section 5.5.3.e */
394 r
= address_get(link
, a
->family
, &a
->in_addr
, a
->prefixlen
, &existing_address
);
396 lifetime_remaining
= existing_address
->cinfo
.tstamp
/ 100 + existing_address
->cinfo
.ifa_valid
- time_now
/ USEC_PER_SEC
;
397 if (lifetime_valid
> NDISC_PREFIX_LFT_MIN
|| lifetime_valid
> lifetime_remaining
)
398 a
->cinfo
.ifa_valid
= lifetime_valid
;
399 else if (lifetime_remaining
<= NDISC_PREFIX_LFT_MIN
)
400 a
->cinfo
.ifa_valid
= lifetime_remaining
;
402 a
->cinfo
.ifa_valid
= NDISC_PREFIX_LFT_MIN
;
403 } else if (lifetime_valid
> 0)
404 a
->cinfo
.ifa_valid
= lifetime_valid
;
406 return 0; /* see RFC4862 section 5.5.3.d */
408 if (a
->cinfo
.ifa_valid
== 0)
411 r
= address_configure(a
, link
, ndisc_netlink_address_message_handler
, true);
413 log_link_warning_errno(link
, r
, "Could not set SLAAC address: %m");
414 link_enter_failed(link
);
419 link
->ndisc_messages
++;
425 static int ndisc_router_process_onlink_prefix(Link
*link
, sd_ndisc_router
*rt
) {
426 _cleanup_(route_freep
) Route
*route
= NULL
;
435 r
= sd_ndisc_router_get_timestamp(rt
, clock_boottime_or_monotonic(), &time_now
);
437 return log_link_warning_errno(link
, r
, "Failed to get RA timestamp: %m");
439 r
= sd_ndisc_router_prefix_get_prefixlen(rt
, &prefixlen
);
441 return log_link_error_errno(link
, r
, "Failed to get prefix length: %m");
443 r
= sd_ndisc_router_prefix_get_valid_lifetime(rt
, &lifetime
);
445 return log_link_error_errno(link
, r
, "Failed to get prefix lifetime: %m");
447 r
= route_new(&route
);
449 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
451 route
->family
= AF_INET6
;
452 route
->table
= link_get_ipv6_accept_ra_route_table(link
);
453 route
->priority
= link
->network
->dhcp_route_metric
;
454 route
->protocol
= RTPROT_RA
;
455 route
->flags
= RTM_F_PREFIX
;
456 route
->dst_prefixlen
= prefixlen
;
457 route
->lifetime
= time_now
+ lifetime
* USEC_PER_SEC
;
459 r
= sd_ndisc_router_prefix_get_address(rt
, &route
->dst
.in6
);
461 return log_link_error_errno(link
, r
, "Failed to get prefix address: %m");
463 r
= route_configure(route
, link
, ndisc_netlink_route_message_handler
);
465 log_link_warning_errno(link
, r
, "Could not set prefix route: %m");
466 link_enter_failed(link
);
470 link
->ndisc_messages
++;
475 static int ndisc_router_process_route(Link
*link
, sd_ndisc_router
*rt
) {
476 _cleanup_(route_freep
) Route
*route
= NULL
;
477 struct in6_addr gateway
;
479 unsigned preference
, prefixlen
;
485 r
= sd_ndisc_router_route_get_lifetime(rt
, &lifetime
);
487 return log_link_warning_errno(link
, r
, "Failed to get gateway address from RA: %m");
492 r
= sd_ndisc_router_get_address(rt
, &gateway
);
494 return log_link_warning_errno(link
, r
, "Failed to get gateway address from RA: %m");
496 r
= sd_ndisc_router_route_get_prefixlen(rt
, &prefixlen
);
498 return log_link_warning_errno(link
, r
, "Failed to get route prefix length: %m");
500 r
= sd_ndisc_router_route_get_preference(rt
, &preference
);
502 return log_link_warning_errno(link
, r
, "Failed to get default router preference from RA: %m");
504 r
= sd_ndisc_router_get_timestamp(rt
, clock_boottime_or_monotonic(), &time_now
);
506 return log_link_warning_errno(link
, r
, "Failed to get RA timestamp: %m");
508 r
= route_new(&route
);
510 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
512 route
->family
= AF_INET6
;
513 route
->table
= link_get_ipv6_accept_ra_route_table(link
);
514 route
->protocol
= RTPROT_RA
;
515 route
->pref
= preference
;
516 route
->gw
.in6
= gateway
;
517 route
->dst_prefixlen
= prefixlen
;
518 route
->lifetime
= time_now
+ lifetime
* USEC_PER_SEC
;
520 r
= sd_ndisc_router_route_get_address(rt
, &route
->dst
.in6
);
522 return log_link_error_errno(link
, r
, "Failed to get route address: %m");
524 r
= route_configure(route
, link
, ndisc_netlink_route_message_handler
);
526 log_link_warning_errno(link
, r
, "Could not set additional route: %m");
527 link_enter_failed(link
);
531 link
->ndisc_messages
++;
536 static void ndisc_rdnss_hash_func(const NDiscRDNSS
*x
, struct siphash
*state
) {
537 siphash24_compress(&x
->address
, sizeof(x
->address
), state
);
540 static int ndisc_rdnss_compare_func(const NDiscRDNSS
*a
, const NDiscRDNSS
*b
) {
541 return memcmp(&a
->address
, &b
->address
, sizeof(a
->address
));
544 DEFINE_PRIVATE_HASH_OPS(ndisc_rdnss_hash_ops
, NDiscRDNSS
, ndisc_rdnss_hash_func
, ndisc_rdnss_compare_func
);
546 static int ndisc_router_process_rdnss(Link
*link
, sd_ndisc_router
*rt
) {
548 const struct in6_addr
*a
;
555 r
= sd_ndisc_router_get_timestamp(rt
, clock_boottime_or_monotonic(), &time_now
);
557 return log_link_warning_errno(link
, r
, "Failed to get RA timestamp: %m");
559 r
= sd_ndisc_router_rdnss_get_lifetime(rt
, &lifetime
);
561 return log_link_warning_errno(link
, r
, "Failed to get RDNSS lifetime: %m");
563 n
= sd_ndisc_router_rdnss_get_addresses(rt
, &a
);
565 return log_link_warning_errno(link
, n
, "Failed to get RDNSS addresses: %m");
567 for (i
= 0; i
< n
; i
++) {
568 _cleanup_free_ NDiscRDNSS
*x
= NULL
;
574 (void) set_remove(link
->ndisc_rdnss
, &d
);
579 y
= set_get(link
->ndisc_rdnss
, &d
);
581 y
->valid_until
= time_now
+ lifetime
* USEC_PER_SEC
;
587 if (set_size(link
->ndisc_rdnss
) >= NDISC_RDNSS_MAX
) {
588 log_link_warning(link
, "Too many RDNSS records per link, ignoring.");
592 r
= set_ensure_allocated(&link
->ndisc_rdnss
, &ndisc_rdnss_hash_ops
);
596 x
= new(NDiscRDNSS
, 1);
602 .valid_until
= time_now
+ lifetime
* USEC_PER_SEC
,
605 r
= set_put(link
->ndisc_rdnss
, x
);
618 static void ndisc_dnssl_hash_func(const NDiscDNSSL
*x
, struct siphash
*state
) {
619 siphash24_compress(NDISC_DNSSL_DOMAIN(x
), strlen(NDISC_DNSSL_DOMAIN(x
)), state
);
622 static int ndisc_dnssl_compare_func(const NDiscDNSSL
*a
, const NDiscDNSSL
*b
) {
623 return strcmp(NDISC_DNSSL_DOMAIN(a
), NDISC_DNSSL_DOMAIN(b
));
626 DEFINE_PRIVATE_HASH_OPS(ndisc_dnssl_hash_ops
, NDiscDNSSL
, ndisc_dnssl_hash_func
, ndisc_dnssl_compare_func
);
628 static void ndisc_router_process_dnssl(Link
*link
, sd_ndisc_router
*rt
) {
629 _cleanup_strv_free_
char **l
= NULL
;
638 r
= sd_ndisc_router_get_timestamp(rt
, clock_boottime_or_monotonic(), &time_now
);
640 log_link_warning_errno(link
, r
, "Failed to get RA timestamp: %m");
644 r
= sd_ndisc_router_dnssl_get_lifetime(rt
, &lifetime
);
646 log_link_warning_errno(link
, r
, "Failed to get RDNSS lifetime: %m");
650 r
= sd_ndisc_router_dnssl_get_domains(rt
, &l
);
652 log_link_warning_errno(link
, r
, "Failed to get RDNSS addresses: %m");
657 _cleanup_free_ NDiscDNSSL
*s
;
660 s
= malloc0(ALIGN(sizeof(NDiscDNSSL
)) + strlen(*i
) + 1);
666 strcpy(NDISC_DNSSL_DOMAIN(s
), *i
);
669 (void) set_remove(link
->ndisc_dnssl
, s
);
674 x
= set_get(link
->ndisc_dnssl
, s
);
676 x
->valid_until
= time_now
+ lifetime
* USEC_PER_SEC
;
682 if (set_size(link
->ndisc_dnssl
) >= NDISC_DNSSL_MAX
) {
683 log_link_warning(link
, "Too many DNSSL records per link, ignoring.");
687 r
= set_ensure_allocated(&link
->ndisc_dnssl
, &ndisc_dnssl_hash_ops
);
693 s
->valid_until
= time_now
+ lifetime
* USEC_PER_SEC
;
695 r
= set_put(link
->ndisc_dnssl
, s
);
707 static int ndisc_router_process_options(Link
*link
, sd_ndisc_router
*rt
) {
711 assert(link
->network
);
714 r
= sd_ndisc_router_option_rewind(rt
);
719 return log_link_warning_errno(link
, r
, "Failed to iterate through options: %m");
720 if (r
== 0) /* EOF */
723 r
= sd_ndisc_router_option_get_type(rt
, &type
);
725 return log_link_warning_errno(link
, r
, "Failed to get RA option type: %m");
729 case SD_NDISC_OPTION_PREFIX_INFORMATION
: {
730 union in_addr_union a
;
733 r
= sd_ndisc_router_prefix_get_address(rt
, &a
.in6
);
735 return log_link_error_errno(link
, r
, "Failed to get prefix address: %m");
737 if (set_contains(link
->network
->ndisc_black_listed_prefix
, &a
.in6
)) {
739 _cleanup_free_
char *b
= NULL
;
741 (void) in_addr_to_string(AF_INET6
, &a
, &b
);
742 log_link_debug(link
, "Prefix '%s' is black listed, ignoring", strna(b
));
748 r
= sd_ndisc_router_prefix_get_flags(rt
, &flags
);
750 return log_link_warning_errno(link
, r
, "Failed to get RA prefix flags: %m");
752 if (link
->network
->ipv6_accept_ra_use_onlink_prefix
&&
753 FLAGS_SET(flags
, ND_OPT_PI_FLAG_ONLINK
))
754 (void) ndisc_router_process_onlink_prefix(link
, rt
);
756 if (link
->network
->ipv6_accept_ra_use_autonomous_prefix
&&
757 FLAGS_SET(flags
, ND_OPT_PI_FLAG_AUTO
))
758 (void) ndisc_router_process_autonomous_prefix(link
, rt
);
763 case SD_NDISC_OPTION_ROUTE_INFORMATION
:
764 (void) ndisc_router_process_route(link
, rt
);
767 case SD_NDISC_OPTION_RDNSS
:
768 if (link
->network
->ipv6_accept_ra_use_dns
)
769 (void) ndisc_router_process_rdnss(link
, rt
);
772 case SD_NDISC_OPTION_DNSSL
:
773 if (link
->network
->ipv6_accept_ra_use_dns
)
774 (void) ndisc_router_process_dnssl(link
, rt
);
778 r
= sd_ndisc_router_option_next(rt
);
784 static int ndisc_router_handler(Link
*link
, sd_ndisc_router
*rt
) {
789 assert(link
->network
);
790 assert(link
->manager
);
793 r
= sd_ndisc_router_get_flags(rt
, &flags
);
795 return log_link_warning_errno(link
, r
, "Failed to get RA flags: %m");
797 if (flags
& (ND_RA_FLAG_MANAGED
| ND_RA_FLAG_OTHER
) &&
798 link
->network
->ipv6_accept_ra_start_dhcp6_client
) {
799 /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags */
800 r
= dhcp6_request_address(link
, !(flags
& ND_RA_FLAG_MANAGED
));
801 if (r
< 0 && r
!= -EBUSY
)
802 log_link_warning_errno(link
, r
, "Could not acquire DHCPv6 lease on NDisc request: %m");
804 log_link_debug(link
, "Acquiring DHCPv6 lease on NDisc request");
809 (void) ndisc_router_process_default(link
, rt
);
810 (void) ndisc_router_process_options(link
, rt
);
815 static void ndisc_handler(sd_ndisc
*nd
, sd_ndisc_event event
, sd_ndisc_router
*rt
, void *userdata
) {
816 Link
*link
= userdata
;
820 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
825 case SD_NDISC_EVENT_ROUTER
:
826 (void) ndisc_router_handler(link
, rt
);
829 case SD_NDISC_EVENT_TIMEOUT
:
830 link
->ndisc_configured
= true;
831 link_check_ready(link
);
835 log_link_warning(link
, "IPv6 Neighbor Discovery unknown event: %d", event
);
839 int ndisc_configure(Link
*link
) {
844 r
= sd_ndisc_new(&link
->ndisc
);
848 r
= sd_ndisc_attach_event(link
->ndisc
, NULL
, 0);
852 r
= sd_ndisc_set_mac(link
->ndisc
, &link
->mac
);
856 r
= sd_ndisc_set_ifindex(link
->ndisc
, link
->ifindex
);
860 r
= sd_ndisc_set_callback(link
->ndisc
, ndisc_handler
, link
);
867 void ndisc_vacuum(Link
*link
) {
875 /* Removes all RDNSS and DNSSL entries whose validity time has passed */
877 time_now
= now(clock_boottime_or_monotonic());
879 SET_FOREACH(r
, link
->ndisc_rdnss
, i
)
880 if (r
->valid_until
< time_now
) {
881 free(set_remove(link
->ndisc_rdnss
, r
));
885 SET_FOREACH(d
, link
->ndisc_dnssl
, i
)
886 if (d
->valid_until
< time_now
) {
887 free(set_remove(link
->ndisc_dnssl
, d
));
892 void ndisc_flush(Link
*link
) {
895 /* Removes all RDNSS and DNSSL entries, without exception */
897 link
->ndisc_rdnss
= set_free_free(link
->ndisc_rdnss
);
898 link
->ndisc_dnssl
= set_free_free(link
->ndisc_dnssl
);
901 int ipv6token_new(IPv6Token
**ret
) {
904 p
= new(IPv6Token
, 1);
909 .address_generation_type
= IPV6_TOKEN_ADDRESS_GENERATION_NONE
,
917 DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
921 trivial_compare_func
,
925 int config_parse_ndisc_black_listed_prefix(
927 const char *filename
,
930 unsigned section_line
,
937 Network
*network
= data
;
946 if (isempty(rvalue
)) {
947 network
->ndisc_black_listed_prefix
= set_free_free(network
->ndisc_black_listed_prefix
);
952 _cleanup_free_
char *n
= NULL
;
953 _cleanup_free_
struct in6_addr
*a
= NULL
;
954 union in_addr_union ip
;
956 r
= extract_first_word(&p
, &n
, NULL
, 0);
958 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
959 "Failed to parse NDISC black listed prefix, ignoring assignment: %s",
966 r
= in_addr_from_string(AF_INET6
, n
, &ip
);
968 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
969 "NDISC black listed prefix is invalid, ignoring assignment: %s", n
);
973 if (set_contains(network
->ndisc_black_listed_prefix
, &ip
.in6
))
976 r
= set_ensure_allocated(&network
->ndisc_black_listed_prefix
, &in6_addr_hash_ops
);
980 a
= newdup(struct in6_addr
, &ip
.in6
, 1);
984 r
= set_put(network
->ndisc_black_listed_prefix
, a
);
986 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
987 "Failed to store NDISC black listed prefix '%s', ignoring assignment: %m", n
);
997 int config_parse_address_generation_type(
999 const char *filename
,
1001 const char *section
,
1002 unsigned section_line
,
1009 _cleanup_free_ IPv6Token
*token
= NULL
;
1010 union in_addr_union buffer
;
1011 Network
*network
= data
;
1020 if (isempty(rvalue
)) {
1021 network
->ipv6_tokens
= ordered_hashmap_free(network
->ipv6_tokens
);
1025 r
= ipv6token_new(&token
);
1029 if ((p
= startswith(rvalue
, "static:")))
1030 token
->address_generation_type
= IPV6_TOKEN_ADDRESS_GENERATION_STATIC
;
1031 else if ((p
= startswith(rvalue
, "prefixstable:")))
1032 token
->address_generation_type
= IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE
;
1034 token
->address_generation_type
= IPV6_TOKEN_ADDRESS_GENERATION_STATIC
;
1038 r
= in_addr_from_string(AF_INET6
, p
, &buffer
);
1040 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1041 "Failed to parse IPv6 %s, ignoring: %s", lvalue
, rvalue
);
1045 if (in_addr_is_null(AF_INET6
, &buffer
)) {
1046 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
1047 "IPv6 %s cannot be the ANY address, ignoring: %s", lvalue
, rvalue
);
1051 token
->prefix
= buffer
.in6
;
1053 r
= ordered_hashmap_ensure_allocated(&network
->ipv6_tokens
, &ipv6_token_hash_ops
);
1057 r
= ordered_hashmap_put(network
->ipv6_tokens
, &token
->prefix
, token
);
1059 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
1060 "Failed to store IPv6 token '%s'", rvalue
);