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-ndisc.h"
13 #include "networkd-route.h"
16 #define NDISC_DNSSL_MAX 64U
17 #define NDISC_RDNSS_MAX 64U
18 #define NDISC_PREFIX_LFT_MIN 7200U
20 static int ndisc_netlink_message_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
24 assert(link
->ndisc_messages
> 0);
26 link
->ndisc_messages
--;
28 r
= sd_netlink_message_get_errno(m
);
29 if (r
< 0 && r
!= -EEXIST
)
30 log_link_error_errno(link
, r
, "Could not set NDisc route or address: %m");
32 if (link
->ndisc_messages
== 0) {
33 link
->ndisc_configured
= true;
34 link_check_ready(link
);
40 static int ndisc_router_process_default(Link
*link
, sd_ndisc_router
*rt
) {
41 _cleanup_(route_freep
) Route
*route
= NULL
;
42 union in_addr_union gateway
;
54 r
= sd_ndisc_router_get_lifetime(rt
, &lifetime
);
56 return log_link_warning_errno(link
, r
, "Failed to get gateway address from RA: %m");
58 if (lifetime
== 0) /* not a default router */
61 r
= sd_ndisc_router_get_address(rt
, &gateway
.in6
);
63 return log_link_warning_errno(link
, r
, "Failed to get gateway address from RA: %m");
65 SET_FOREACH(address
, link
->addresses
, i
) {
66 if (address
->family
!= AF_INET6
)
68 if (in_addr_equal(AF_INET6
, &gateway
, &address
->in_addr
)) {
69 _cleanup_free_
char *buffer
= NULL
;
71 (void) in_addr_to_string(AF_INET6
, &address
->in_addr
, &buffer
);
72 log_link_debug(link
, "No NDisc route added, gateway %s matches local address",
78 SET_FOREACH(address
, link
->addresses_foreign
, i
) {
79 if (address
->family
!= AF_INET6
)
81 if (in_addr_equal(AF_INET6
, &gateway
, &address
->in_addr
)) {
82 _cleanup_free_
char *buffer
= NULL
;
84 (void) in_addr_to_string(AF_INET6
, &address
->in_addr
, &buffer
);
85 log_link_debug(link
, "No NDisc route added, gateway %s matches local address",
91 r
= sd_ndisc_router_get_preference(rt
, &preference
);
93 return log_link_warning_errno(link
, r
, "Failed to get default router preference from RA: %m");
95 r
= sd_ndisc_router_get_timestamp(rt
, clock_boottime_or_monotonic(), &time_now
);
97 return log_link_warning_errno(link
, r
, "Failed to get RA timestamp: %m");
99 r
= sd_ndisc_router_get_mtu(rt
, &mtu
);
103 return log_link_warning_errno(link
, r
, "Failed to get default router MTU from RA: %m");
105 r
= route_new(&route
);
107 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
109 route
->family
= AF_INET6
;
110 route
->table
= link_get_ipv6_accept_ra_route_table(link
);
111 route
->priority
= link
->network
->dhcp_route_metric
;
112 route
->protocol
= RTPROT_RA
;
113 route
->pref
= preference
;
115 route
->lifetime
= time_now
+ lifetime
* USEC_PER_SEC
;
118 r
= route_configure(route
, link
, ndisc_netlink_message_handler
);
120 log_link_warning_errno(link
, r
, "Could not set default route: %m");
121 link_enter_failed(link
);
125 link
->ndisc_messages
++;
130 static int ndisc_router_process_autonomous_prefix(Link
*link
, sd_ndisc_router
*rt
) {
131 _cleanup_(address_freep
) Address
*address
= NULL
;
132 Address
*existing_address
;
133 uint32_t lifetime_valid
, lifetime_preferred
, lifetime_remaining
;
141 r
= sd_ndisc_router_get_timestamp(rt
, clock_boottime_or_monotonic(), &time_now
);
143 return log_link_warning_errno(link
, r
, "Failed to get RA timestamp: %m");
145 r
= sd_ndisc_router_prefix_get_prefixlen(rt
, &prefixlen
);
147 return log_link_error_errno(link
, r
, "Failed to get prefix length: %m");
149 r
= sd_ndisc_router_prefix_get_valid_lifetime(rt
, &lifetime_valid
);
151 return log_link_error_errno(link
, r
, "Failed to get prefix valid lifetime: %m");
153 r
= sd_ndisc_router_prefix_get_preferred_lifetime(rt
, &lifetime_preferred
);
155 return log_link_error_errno(link
, r
, "Failed to get prefix preferred lifetime: %m");
157 /* The preferred lifetime is never greater than the valid lifetime */
158 if (lifetime_preferred
> lifetime_valid
)
161 r
= address_new(&address
);
163 return log_link_error_errno(link
, r
, "Could not allocate address: %m");
165 address
->family
= AF_INET6
;
166 r
= sd_ndisc_router_prefix_get_address(rt
, &address
->in_addr
.in6
);
168 return log_link_error_errno(link
, r
, "Failed to get prefix address: %m");
170 if (in_addr_is_null(AF_INET6
, (const union in_addr_union
*) &link
->network
->ipv6_token
) == 0)
171 memcpy(((char *)&address
->in_addr
.in6
) + 8, ((char *)&link
->network
->ipv6_token
) + 8, 8);
173 /* see RFC4291 section 2.5.1 */
174 address
->in_addr
.in6
.s6_addr
[8] = link
->mac
.ether_addr_octet
[0];
175 address
->in_addr
.in6
.s6_addr
[8] ^= 1 << 1;
176 address
->in_addr
.in6
.s6_addr
[9] = link
->mac
.ether_addr_octet
[1];
177 address
->in_addr
.in6
.s6_addr
[10] = link
->mac
.ether_addr_octet
[2];
178 address
->in_addr
.in6
.s6_addr
[11] = 0xff;
179 address
->in_addr
.in6
.s6_addr
[12] = 0xfe;
180 address
->in_addr
.in6
.s6_addr
[13] = link
->mac
.ether_addr_octet
[3];
181 address
->in_addr
.in6
.s6_addr
[14] = link
->mac
.ether_addr_octet
[4];
182 address
->in_addr
.in6
.s6_addr
[15] = link
->mac
.ether_addr_octet
[5];
184 address
->prefixlen
= prefixlen
;
185 address
->flags
= IFA_F_NOPREFIXROUTE
|IFA_F_MANAGETEMPADDR
;
186 address
->cinfo
.ifa_prefered
= lifetime_preferred
;
188 /* see RFC4862 section 5.5.3.e */
189 r
= address_get(link
, address
->family
, &address
->in_addr
, address
->prefixlen
, &existing_address
);
191 lifetime_remaining
= existing_address
->cinfo
.tstamp
/ 100 + existing_address
->cinfo
.ifa_valid
- time_now
/ USEC_PER_SEC
;
192 if (lifetime_valid
> NDISC_PREFIX_LFT_MIN
|| lifetime_valid
> lifetime_remaining
)
193 address
->cinfo
.ifa_valid
= lifetime_valid
;
194 else if (lifetime_remaining
<= NDISC_PREFIX_LFT_MIN
)
195 address
->cinfo
.ifa_valid
= lifetime_remaining
;
197 address
->cinfo
.ifa_valid
= NDISC_PREFIX_LFT_MIN
;
198 } else if (lifetime_valid
> 0)
199 address
->cinfo
.ifa_valid
= lifetime_valid
;
201 return 0; /* see RFC4862 section 5.5.3.d */
203 if (address
->cinfo
.ifa_valid
== 0)
206 r
= address_configure(address
, link
, ndisc_netlink_message_handler
, true);
208 log_link_warning_errno(link
, r
, "Could not set SLAAC address: %m");
209 link_enter_failed(link
);
213 link
->ndisc_messages
++;
218 static int ndisc_router_process_onlink_prefix(Link
*link
, sd_ndisc_router
*rt
) {
219 _cleanup_(route_freep
) Route
*route
= NULL
;
228 r
= sd_ndisc_router_get_timestamp(rt
, clock_boottime_or_monotonic(), &time_now
);
230 return log_link_warning_errno(link
, r
, "Failed to get RA timestamp: %m");
232 r
= sd_ndisc_router_prefix_get_prefixlen(rt
, &prefixlen
);
234 return log_link_error_errno(link
, r
, "Failed to get prefix length: %m");
236 r
= sd_ndisc_router_prefix_get_valid_lifetime(rt
, &lifetime
);
238 return log_link_error_errno(link
, r
, "Failed to get prefix lifetime: %m");
240 r
= route_new(&route
);
242 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
244 route
->family
= AF_INET6
;
245 route
->table
= link_get_ipv6_accept_ra_route_table(link
);
246 route
->priority
= link
->network
->dhcp_route_metric
;
247 route
->protocol
= RTPROT_RA
;
248 route
->flags
= RTM_F_PREFIX
;
249 route
->dst_prefixlen
= prefixlen
;
250 route
->lifetime
= time_now
+ lifetime
* USEC_PER_SEC
;
252 r
= sd_ndisc_router_prefix_get_address(rt
, &route
->dst
.in6
);
254 return log_link_error_errno(link
, r
, "Failed to get prefix address: %m");
256 r
= route_configure(route
, link
, ndisc_netlink_message_handler
);
258 log_link_warning_errno(link
, r
, "Could not set prefix route: %m");
259 link_enter_failed(link
);
263 link
->ndisc_messages
++;
268 static int ndisc_router_process_route(Link
*link
, sd_ndisc_router
*rt
) {
269 _cleanup_(route_freep
) Route
*route
= NULL
;
270 struct in6_addr gateway
;
272 unsigned preference
, prefixlen
;
278 r
= sd_ndisc_router_route_get_lifetime(rt
, &lifetime
);
280 return log_link_warning_errno(link
, r
, "Failed to get gateway address from RA: %m");
285 r
= sd_ndisc_router_get_address(rt
, &gateway
);
287 return log_link_warning_errno(link
, r
, "Failed to get gateway address from RA: %m");
289 r
= sd_ndisc_router_route_get_prefixlen(rt
, &prefixlen
);
291 return log_link_warning_errno(link
, r
, "Failed to get route prefix length: %m");
293 r
= sd_ndisc_router_route_get_preference(rt
, &preference
);
295 return log_link_warning_errno(link
, r
, "Failed to get default router preference from RA: %m");
297 r
= sd_ndisc_router_get_timestamp(rt
, clock_boottime_or_monotonic(), &time_now
);
299 return log_link_warning_errno(link
, r
, "Failed to get RA timestamp: %m");
301 r
= route_new(&route
);
303 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
305 route
->family
= AF_INET6
;
306 route
->table
= link_get_ipv6_accept_ra_route_table(link
);
307 route
->protocol
= RTPROT_RA
;
308 route
->pref
= preference
;
309 route
->gw
.in6
= gateway
;
310 route
->dst_prefixlen
= prefixlen
;
311 route
->lifetime
= time_now
+ lifetime
* USEC_PER_SEC
;
313 r
= sd_ndisc_router_route_get_address(rt
, &route
->dst
.in6
);
315 return log_link_error_errno(link
, r
, "Failed to get route address: %m");
317 r
= route_configure(route
, link
, ndisc_netlink_message_handler
);
319 log_link_warning_errno(link
, r
, "Could not set additional route: %m");
320 link_enter_failed(link
);
324 link
->ndisc_messages
++;
329 static void ndisc_rdnss_hash_func(const NDiscRDNSS
*x
, struct siphash
*state
) {
330 siphash24_compress(&x
->address
, sizeof(x
->address
), state
);
333 static int ndisc_rdnss_compare_func(const NDiscRDNSS
*a
, const NDiscRDNSS
*b
) {
334 return memcmp(&a
->address
, &b
->address
, sizeof(a
->address
));
337 DEFINE_PRIVATE_HASH_OPS(ndisc_rdnss_hash_ops
, NDiscRDNSS
, ndisc_rdnss_hash_func
, ndisc_rdnss_compare_func
);
339 static int ndisc_router_process_rdnss(Link
*link
, sd_ndisc_router
*rt
) {
341 const struct in6_addr
*a
;
348 r
= sd_ndisc_router_get_timestamp(rt
, clock_boottime_or_monotonic(), &time_now
);
350 return log_link_warning_errno(link
, r
, "Failed to get RA timestamp: %m");
352 r
= sd_ndisc_router_rdnss_get_lifetime(rt
, &lifetime
);
354 return log_link_warning_errno(link
, r
, "Failed to get RDNSS lifetime: %m");
356 n
= sd_ndisc_router_rdnss_get_addresses(rt
, &a
);
358 return log_link_warning_errno(link
, n
, "Failed to get RDNSS addresses: %m");
360 for (i
= 0; i
< n
; i
++) {
361 _cleanup_free_ NDiscRDNSS
*x
= NULL
;
367 (void) set_remove(link
->ndisc_rdnss
, &d
);
372 y
= set_get(link
->ndisc_rdnss
, &d
);
374 y
->valid_until
= time_now
+ lifetime
* USEC_PER_SEC
;
380 if (set_size(link
->ndisc_rdnss
) >= NDISC_RDNSS_MAX
) {
381 log_link_warning(link
, "Too many RDNSS records per link, ignoring.");
385 r
= set_ensure_allocated(&link
->ndisc_rdnss
, &ndisc_rdnss_hash_ops
);
389 x
= new(NDiscRDNSS
, 1);
395 .valid_until
= time_now
+ lifetime
* USEC_PER_SEC
,
398 r
= set_put(link
->ndisc_rdnss
, x
);
411 static void ndisc_dnssl_hash_func(const NDiscDNSSL
*x
, struct siphash
*state
) {
412 siphash24_compress(NDISC_DNSSL_DOMAIN(x
), strlen(NDISC_DNSSL_DOMAIN(x
)), state
);
415 static int ndisc_dnssl_compare_func(const NDiscDNSSL
*a
, const NDiscDNSSL
*b
) {
416 return strcmp(NDISC_DNSSL_DOMAIN(a
), NDISC_DNSSL_DOMAIN(b
));
419 DEFINE_PRIVATE_HASH_OPS(ndisc_dnssl_hash_ops
, NDiscDNSSL
, ndisc_dnssl_hash_func
, ndisc_dnssl_compare_func
);
421 static void ndisc_router_process_dnssl(Link
*link
, sd_ndisc_router
*rt
) {
422 _cleanup_strv_free_
char **l
= NULL
;
431 r
= sd_ndisc_router_get_timestamp(rt
, clock_boottime_or_monotonic(), &time_now
);
433 log_link_warning_errno(link
, r
, "Failed to get RA timestamp: %m");
437 r
= sd_ndisc_router_dnssl_get_lifetime(rt
, &lifetime
);
439 log_link_warning_errno(link
, r
, "Failed to get RDNSS lifetime: %m");
443 r
= sd_ndisc_router_dnssl_get_domains(rt
, &l
);
445 log_link_warning_errno(link
, r
, "Failed to get RDNSS addresses: %m");
450 _cleanup_free_ NDiscDNSSL
*s
;
453 s
= malloc0(ALIGN(sizeof(NDiscDNSSL
)) + strlen(*i
) + 1);
459 strcpy(NDISC_DNSSL_DOMAIN(s
), *i
);
462 (void) set_remove(link
->ndisc_dnssl
, s
);
467 x
= set_get(link
->ndisc_dnssl
, s
);
469 x
->valid_until
= time_now
+ lifetime
* USEC_PER_SEC
;
475 if (set_size(link
->ndisc_dnssl
) >= NDISC_DNSSL_MAX
) {
476 log_link_warning(link
, "Too many DNSSL records per link, ignoring.");
480 r
= set_ensure_allocated(&link
->ndisc_dnssl
, &ndisc_dnssl_hash_ops
);
486 s
->valid_until
= time_now
+ lifetime
* USEC_PER_SEC
;
488 r
= set_put(link
->ndisc_dnssl
, s
);
500 static int ndisc_router_process_options(Link
*link
, sd_ndisc_router
*rt
) {
506 r
= sd_ndisc_router_option_rewind(rt
);
511 return log_link_warning_errno(link
, r
, "Failed to iterate through options: %m");
512 if (r
== 0) /* EOF */
515 r
= sd_ndisc_router_option_get_type(rt
, &type
);
517 return log_link_warning_errno(link
, r
, "Failed to get RA option type: %m");
521 case SD_NDISC_OPTION_PREFIX_INFORMATION
: {
524 r
= sd_ndisc_router_prefix_get_flags(rt
, &flags
);
526 return log_link_warning_errno(link
, r
, "Failed to get RA prefix flags: %m");
528 if (link
->network
->ipv6_accept_ra_use_onlink_prefix
&&
529 FLAGS_SET(flags
, ND_OPT_PI_FLAG_ONLINK
))
530 (void) ndisc_router_process_onlink_prefix(link
, rt
);
532 if (link
->network
->ipv6_accept_ra_use_autonomous_prefix
&&
533 FLAGS_SET(flags
, ND_OPT_PI_FLAG_AUTO
))
534 (void) ndisc_router_process_autonomous_prefix(link
, rt
);
539 case SD_NDISC_OPTION_ROUTE_INFORMATION
:
540 (void) ndisc_router_process_route(link
, rt
);
543 case SD_NDISC_OPTION_RDNSS
:
544 if (link
->network
->ipv6_accept_ra_use_dns
)
545 (void) ndisc_router_process_rdnss(link
, rt
);
548 case SD_NDISC_OPTION_DNSSL
:
549 if (link
->network
->ipv6_accept_ra_use_dns
)
550 (void) ndisc_router_process_dnssl(link
, rt
);
554 r
= sd_ndisc_router_option_next(rt
);
560 static int ndisc_prefix_is_black_listed(Link
*link
, sd_ndisc_router
*rt
) {
564 assert(link
->network
);
567 for (r
= sd_ndisc_router_option_rewind(rt
); ; r
= sd_ndisc_router_option_next(rt
)) {
568 union in_addr_union a
;
572 return log_link_warning_errno(link
, r
, "Failed to iterate through options: %m");
573 if (r
== 0) /* EOF */
576 r
= sd_ndisc_router_option_get_type(rt
, &type
);
578 return log_link_warning_errno(link
, r
, "Failed to get RA option type: %m");
580 if (type
!= SD_NDISC_OPTION_PREFIX_INFORMATION
)
583 r
= sd_ndisc_router_prefix_get_address(rt
, &a
.in6
);
585 return log_link_error_errno(link
, r
, "Failed to get prefix address: %m");
587 if (set_contains(link
->network
->ndisc_black_listed_prefix
, &a
.in6
)) {
589 _cleanup_free_
char *b
= NULL
;
591 (void) in_addr_to_string(AF_INET6
, &a
, &b
);
592 log_link_debug(link
, "Prefix '%s' is black listed, ignoring", strna(b
));
600 static int ndisc_router_handler(Link
*link
, sd_ndisc_router
*rt
) {
605 assert(link
->network
);
606 assert(link
->manager
);
609 r
= sd_ndisc_router_get_flags(rt
, &flags
);
611 return log_link_warning_errno(link
, r
, "Failed to get RA flags: %m");
613 if (flags
& (ND_RA_FLAG_MANAGED
| ND_RA_FLAG_OTHER
)) {
614 /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags */
615 r
= dhcp6_request_address(link
, !(flags
& ND_RA_FLAG_MANAGED
));
616 if (r
< 0 && r
!= -EBUSY
)
617 log_link_warning_errno(link
, r
, "Could not acquire DHCPv6 lease on NDisc request: %m");
619 log_link_debug(link
, "Acquiring DHCPv6 lease on NDisc request");
624 if (ndisc_prefix_is_black_listed(link
, rt
) == 0) {
625 (void) ndisc_router_process_default(link
, rt
);
626 (void) ndisc_router_process_options(link
, rt
);
632 static void ndisc_handler(sd_ndisc
*nd
, sd_ndisc_event event
, sd_ndisc_router
*rt
, void *userdata
) {
633 Link
*link
= userdata
;
637 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
642 case SD_NDISC_EVENT_ROUTER
:
643 (void) ndisc_router_handler(link
, rt
);
646 case SD_NDISC_EVENT_TIMEOUT
:
647 link
->ndisc_configured
= true;
648 link_check_ready(link
);
652 log_link_warning(link
, "IPv6 Neighbor Discovery unknown event: %d", event
);
656 int ndisc_configure(Link
*link
) {
661 r
= sd_ndisc_new(&link
->ndisc
);
665 r
= sd_ndisc_attach_event(link
->ndisc
, NULL
, 0);
669 r
= sd_ndisc_set_mac(link
->ndisc
, &link
->mac
);
673 r
= sd_ndisc_set_ifindex(link
->ndisc
, link
->ifindex
);
677 r
= sd_ndisc_set_callback(link
->ndisc
, ndisc_handler
, link
);
684 void ndisc_vacuum(Link
*link
) {
692 /* Removes all RDNSS and DNSSL entries whose validity time has passed */
694 time_now
= now(clock_boottime_or_monotonic());
696 SET_FOREACH(r
, link
->ndisc_rdnss
, i
)
697 if (r
->valid_until
< time_now
) {
698 free(set_remove(link
->ndisc_rdnss
, r
));
702 SET_FOREACH(d
, link
->ndisc_dnssl
, i
)
703 if (d
->valid_until
< time_now
) {
704 free(set_remove(link
->ndisc_dnssl
, d
));
709 void ndisc_flush(Link
*link
) {
712 /* Removes all RDNSS and DNSSL entries, without exception */
714 link
->ndisc_rdnss
= set_free_free(link
->ndisc_rdnss
);
715 link
->ndisc_dnssl
= set_free_free(link
->ndisc_dnssl
);
718 int config_parse_ndisc_black_listed_prefix(
720 const char *filename
,
723 unsigned section_line
,
730 Network
*network
= data
;
739 if (isempty(rvalue
)) {
740 network
->ndisc_black_listed_prefix
= set_free_free(network
->ndisc_black_listed_prefix
);
745 _cleanup_free_
char *n
= NULL
;
746 _cleanup_free_
struct in6_addr
*a
= NULL
;
747 union in_addr_union ip
;
749 r
= extract_first_word(&p
, &n
, NULL
, 0);
751 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
752 "Failed to parse NDISC black listed prefix, ignoring assignment: %s",
759 r
= in_addr_from_string(AF_INET6
, n
, &ip
);
761 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
762 "NDISC black listed prefix is invalid, ignoring assignment: %s", n
);
766 r
= set_ensure_allocated(&network
->ndisc_black_listed_prefix
, &in6_addr_hash_ops
);
770 a
= newdup(struct in6_addr
, &ip
.in6
, 1);
774 r
= set_put(network
->ndisc_black_listed_prefix
, a
);
777 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
778 "NDISC black listed prefixs is duplicated, ignoring assignment: %s", n
);
780 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
781 "Failed to store NDISC black listed prefix '%s', ignoring assignment: %m", n
);