1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2014 Intel Corporation. All rights reserved.
6 #include <netinet/icmp6.h>
10 #include "alloc-util.h"
11 #include "dns-domain.h"
12 #include "hostname-util.h"
13 #include "memory-util.h"
14 #include "missing_network.h"
15 #include "ndisc-internal.h"
16 #include "ndisc-router.h"
19 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_ndisc_router
, sd_ndisc_router
, mfree
);
21 sd_ndisc_router
*ndisc_router_new(size_t raw_size
) {
24 rt
= malloc0(ALIGN(sizeof(sd_ndisc_router
)) + raw_size
);
28 rt
->raw_size
= raw_size
;
34 _public_
int sd_ndisc_router_from_raw(sd_ndisc_router
**ret
, const void *raw
, size_t raw_size
) {
35 _cleanup_(sd_ndisc_router_unrefp
) sd_ndisc_router
*rt
= NULL
;
38 assert_return(ret
, -EINVAL
);
39 assert_return(raw
|| raw_size
<= 0, -EINVAL
);
41 rt
= ndisc_router_new(raw_size
);
45 memcpy(NDISC_ROUTER_RAW(rt
), raw
, raw_size
);
46 r
= ndisc_router_parse(rt
);
55 _public_
int sd_ndisc_router_get_address(sd_ndisc_router
*rt
, struct in6_addr
*ret_addr
) {
56 assert_return(rt
, -EINVAL
);
57 assert_return(ret_addr
, -EINVAL
);
59 if (IN6_IS_ADDR_UNSPECIFIED(&rt
->address
))
62 *ret_addr
= rt
->address
;
66 _public_
int sd_ndisc_router_get_timestamp(sd_ndisc_router
*rt
, clockid_t clock
, uint64_t *ret
) {
67 assert_return(rt
, -EINVAL
);
68 assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock
), -EOPNOTSUPP
);
69 assert_return(clock_supported(clock
), -EOPNOTSUPP
);
70 assert_return(ret
, -EINVAL
);
72 if (!triple_timestamp_is_set(&rt
->timestamp
))
75 *ret
= triple_timestamp_by_clock(&rt
->timestamp
, clock
);
79 _public_
int sd_ndisc_router_get_raw(sd_ndisc_router
*rt
, const void **ret
, size_t *size
) {
80 assert_return(rt
, -EINVAL
);
81 assert_return(ret
, -EINVAL
);
82 assert_return(size
, -EINVAL
);
84 *ret
= NDISC_ROUTER_RAW(rt
);
90 int ndisc_router_parse(sd_ndisc_router
*rt
) {
91 struct nd_router_advert
*a
;
93 bool has_mtu
= false, has_flag_extension
= false;
98 if (rt
->raw_size
< sizeof(struct nd_router_advert
)) {
99 log_ndisc("Too small to be a router advertisement, ignoring.");
103 /* Router advertisement packets are neatly aligned to 64bit boundaries, hence we can access them directly */
104 a
= NDISC_ROUTER_RAW(rt
);
106 if (a
->nd_ra_type
!= ND_ROUTER_ADVERT
) {
107 log_ndisc("Received ND packet that is not a router advertisement, ignoring.");
111 if (a
->nd_ra_code
!= 0) {
112 log_ndisc("Received ND packet with wrong RA code, ignoring.");
116 rt
->hop_limit
= a
->nd_ra_curhoplimit
;
117 rt
->flags
= a
->nd_ra_flags_reserved
; /* the first 8bit */
118 rt
->lifetime
= be16toh(a
->nd_ra_router_lifetime
);
120 rt
->preference
= (rt
->flags
>> 3) & 3;
121 if (!IN_SET(rt
->preference
, SD_NDISC_PREFERENCE_LOW
, SD_NDISC_PREFERENCE_HIGH
))
122 rt
->preference
= SD_NDISC_PREFERENCE_MEDIUM
;
124 p
= (const uint8_t*) NDISC_ROUTER_RAW(rt
) + sizeof(struct nd_router_advert
);
125 left
= rt
->raw_size
- sizeof(struct nd_router_advert
);
135 log_ndisc("Option lacks header, ignoring datagram.");
143 log_ndisc("Zero-length option, ignoring datagram.");
147 log_ndisc("Option truncated, ignoring datagram.");
153 case SD_NDISC_OPTION_PREFIX_INFORMATION
:
156 log_ndisc("Prefix option of invalid size, ignoring datagram.");
161 log_ndisc("Bad prefix length, ignoring datagram.");
167 case SD_NDISC_OPTION_MTU
: {
171 log_ndisc("MTU option specified twice, ignoring.");
176 log_ndisc("MTU option of invalid size, ignoring datagram.");
180 m
= be32toh(*(uint32_t*) (p
+ 4));
181 if (m
>= IPV6_MIN_MTU
) /* ignore invalidly small MTUs */
188 case SD_NDISC_OPTION_ROUTE_INFORMATION
:
189 if (length
< 1*8 || length
> 3*8) {
190 log_ndisc("Route information option of invalid size, ignoring datagram.");
195 log_ndisc("Bad route prefix length, ignoring datagram.");
201 case SD_NDISC_OPTION_RDNSS
:
202 if (length
< 3*8 || (length
% (2*8)) != 1*8) {
203 log_ndisc("RDNSS option has invalid size.");
209 case SD_NDISC_OPTION_FLAGS_EXTENSION
:
211 if (has_flag_extension
) {
212 log_ndisc("Flags extension option specified twice, ignoring.");
217 log_ndisc("Flags extension option has invalid size.");
221 /* Add in the additional flags bits */
223 ((uint64_t) p
[2] << 8) |
224 ((uint64_t) p
[3] << 16) |
225 ((uint64_t) p
[4] << 24) |
226 ((uint64_t) p
[5] << 32) |
227 ((uint64_t) p
[6] << 40) |
228 ((uint64_t) p
[7] << 48);
230 has_flag_extension
= true;
233 case SD_NDISC_OPTION_DNSSL
:
235 log_ndisc("DNSSL option has invalid size.");
242 p
+= length
, left
-= length
;
245 rt
->rindex
= sizeof(struct nd_router_advert
);
249 _public_
int sd_ndisc_router_get_hop_limit(sd_ndisc_router
*rt
, uint8_t *ret
) {
250 assert_return(rt
, -EINVAL
);
251 assert_return(ret
, -EINVAL
);
253 *ret
= rt
->hop_limit
;
257 _public_
int sd_ndisc_router_get_flags(sd_ndisc_router
*rt
, uint64_t *ret_flags
) {
258 assert_return(rt
, -EINVAL
);
259 assert_return(ret_flags
, -EINVAL
);
261 *ret_flags
= rt
->flags
;
265 _public_
int sd_ndisc_router_get_lifetime(sd_ndisc_router
*rt
, uint16_t *ret_lifetime
) {
266 assert_return(rt
, -EINVAL
);
267 assert_return(ret_lifetime
, -EINVAL
);
269 *ret_lifetime
= rt
->lifetime
;
273 _public_
int sd_ndisc_router_get_preference(sd_ndisc_router
*rt
, unsigned *ret
) {
274 assert_return(rt
, -EINVAL
);
275 assert_return(ret
, -EINVAL
);
277 *ret
= rt
->preference
;
281 _public_
int sd_ndisc_router_get_mtu(sd_ndisc_router
*rt
, uint32_t *ret
) {
282 assert_return(rt
, -EINVAL
);
283 assert_return(ret
, -EINVAL
);
292 _public_
int sd_ndisc_router_option_rewind(sd_ndisc_router
*rt
) {
293 assert_return(rt
, -EINVAL
);
295 assert(rt
->raw_size
>= sizeof(struct nd_router_advert
));
296 rt
->rindex
= sizeof(struct nd_router_advert
);
298 return rt
->rindex
< rt
->raw_size
;
301 _public_
int sd_ndisc_router_option_next(sd_ndisc_router
*rt
) {
304 assert_return(rt
, -EINVAL
);
306 if (rt
->rindex
== rt
->raw_size
) /* EOF */
309 if (rt
->rindex
+ 2 > rt
->raw_size
) /* Truncated message */
312 length
= NDISC_ROUTER_OPTION_LENGTH(rt
);
313 if (rt
->rindex
+ length
> rt
->raw_size
)
316 rt
->rindex
+= length
;
317 return rt
->rindex
< rt
->raw_size
;
320 _public_
int sd_ndisc_router_option_get_type(sd_ndisc_router
*rt
, uint8_t *ret
) {
321 assert_return(rt
, -EINVAL
);
322 assert_return(ret
, -EINVAL
);
324 if (rt
->rindex
== rt
->raw_size
) /* EOF */
327 if (rt
->rindex
+ 2 > rt
->raw_size
) /* Truncated message */
330 *ret
= NDISC_ROUTER_OPTION_TYPE(rt
);
334 _public_
int sd_ndisc_router_option_is_type(sd_ndisc_router
*rt
, uint8_t type
) {
338 assert_return(rt
, -EINVAL
);
340 r
= sd_ndisc_router_option_get_type(rt
, &k
);
347 _public_
int sd_ndisc_router_option_get_raw(sd_ndisc_router
*rt
, const void **ret
, size_t *size
) {
350 assert_return(rt
, -EINVAL
);
351 assert_return(ret
, -EINVAL
);
352 assert_return(size
, -EINVAL
);
354 /* Note that this returns the full option, including the option header */
356 if (rt
->rindex
+ 2 > rt
->raw_size
)
359 length
= NDISC_ROUTER_OPTION_LENGTH(rt
);
360 if (rt
->rindex
+ length
> rt
->raw_size
)
363 *ret
= (uint8_t*) NDISC_ROUTER_RAW(rt
) + rt
->rindex
;
369 static int get_prefix_info(sd_ndisc_router
*rt
, struct nd_opt_prefix_info
**ret
) {
370 struct nd_opt_prefix_info
*ri
;
377 r
= sd_ndisc_router_option_is_type(rt
, SD_NDISC_OPTION_PREFIX_INFORMATION
);
383 length
= NDISC_ROUTER_OPTION_LENGTH(rt
);
384 if (length
!= sizeof(struct nd_opt_prefix_info
))
387 ri
= (struct nd_opt_prefix_info
*) ((uint8_t*) NDISC_ROUTER_RAW(rt
) + rt
->rindex
);
388 if (ri
->nd_opt_pi_prefix_len
> 128)
395 _public_
int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router
*rt
, uint32_t *ret
) {
396 struct nd_opt_prefix_info
*ri
;
399 assert_return(rt
, -EINVAL
);
400 assert_return(ret
, -EINVAL
);
402 r
= get_prefix_info(rt
, &ri
);
406 *ret
= be32toh(ri
->nd_opt_pi_valid_time
);
410 _public_
int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router
*rt
, uint32_t *ret
) {
411 struct nd_opt_prefix_info
*pi
;
414 assert_return(rt
, -EINVAL
);
415 assert_return(ret
, -EINVAL
);
417 r
= get_prefix_info(rt
, &pi
);
421 *ret
= be32toh(pi
->nd_opt_pi_preferred_time
);
425 _public_
int sd_ndisc_router_prefix_get_flags(sd_ndisc_router
*rt
, uint8_t *ret
) {
426 struct nd_opt_prefix_info
*pi
;
430 assert_return(rt
, -EINVAL
);
431 assert_return(ret
, -EINVAL
);
433 r
= get_prefix_info(rt
, &pi
);
437 flags
= pi
->nd_opt_pi_flags_reserved
;
439 if ((flags
& ND_OPT_PI_FLAG_AUTO
) && (pi
->nd_opt_pi_prefix_len
!= 64)) {
440 log_ndisc("Invalid prefix length, ignoring prefix for stateless autoconfiguration.");
441 flags
&= ~ND_OPT_PI_FLAG_AUTO
;
448 _public_
int sd_ndisc_router_prefix_get_address(sd_ndisc_router
*rt
, struct in6_addr
*ret_addr
) {
449 struct nd_opt_prefix_info
*pi
;
452 assert_return(rt
, -EINVAL
);
453 assert_return(ret_addr
, -EINVAL
);
455 r
= get_prefix_info(rt
, &pi
);
459 *ret_addr
= pi
->nd_opt_pi_prefix
;
463 _public_
int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router
*rt
, unsigned *ret
) {
464 struct nd_opt_prefix_info
*pi
;
467 assert_return(rt
, -EINVAL
);
468 assert_return(ret
, -EINVAL
);
470 r
= get_prefix_info(rt
, &pi
);
474 if (pi
->nd_opt_pi_prefix_len
> 128)
477 *ret
= pi
->nd_opt_pi_prefix_len
;
481 static int get_route_info(sd_ndisc_router
*rt
, uint8_t **ret
) {
489 r
= sd_ndisc_router_option_is_type(rt
, SD_NDISC_OPTION_ROUTE_INFORMATION
);
495 length
= NDISC_ROUTER_OPTION_LENGTH(rt
);
496 if (length
< 1*8 || length
> 3*8)
499 ri
= (uint8_t*) NDISC_ROUTER_RAW(rt
) + rt
->rindex
;
508 _public_
int sd_ndisc_router_route_get_lifetime(sd_ndisc_router
*rt
, uint32_t *ret
) {
512 assert_return(rt
, -EINVAL
);
513 assert_return(ret
, -EINVAL
);
515 r
= get_route_info(rt
, &ri
);
519 *ret
= be32toh(*(uint32_t*) (ri
+ 4));
523 _public_
int sd_ndisc_router_route_get_address(sd_ndisc_router
*rt
, struct in6_addr
*ret_addr
) {
527 assert_return(rt
, -EINVAL
);
528 assert_return(ret_addr
, -EINVAL
);
530 r
= get_route_info(rt
, &ri
);
535 memcpy(ret_addr
, ri
+ 8, NDISC_ROUTER_OPTION_LENGTH(rt
) - 8);
540 _public_
int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router
*rt
, unsigned *ret
) {
544 assert_return(rt
, -EINVAL
);
545 assert_return(ret
, -EINVAL
);
547 r
= get_route_info(rt
, &ri
);
555 _public_
int sd_ndisc_router_route_get_preference(sd_ndisc_router
*rt
, unsigned *ret
) {
559 assert_return(rt
, -EINVAL
);
560 assert_return(ret
, -EINVAL
);
562 r
= get_route_info(rt
, &ri
);
566 *ret
= (ri
[3] >> 3) & 3;
567 if (!IN_SET(*ret
, SD_NDISC_PREFERENCE_LOW
, SD_NDISC_PREFERENCE_HIGH
))
568 *ret
= SD_NDISC_PREFERENCE_MEDIUM
;
573 static int get_rdnss_info(sd_ndisc_router
*rt
, uint8_t **ret
) {
580 r
= sd_ndisc_router_option_is_type(rt
, SD_NDISC_OPTION_RDNSS
);
586 length
= NDISC_ROUTER_OPTION_LENGTH(rt
);
587 if (length
< 3*8 || (length
% (2*8)) != 1*8)
590 *ret
= (uint8_t*) NDISC_ROUTER_RAW(rt
) + rt
->rindex
;
594 _public_
int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router
*rt
, const struct in6_addr
**ret
) {
598 assert_return(rt
, -EINVAL
);
599 assert_return(ret
, -EINVAL
);
601 r
= get_rdnss_info(rt
, &ri
);
605 *ret
= (const struct in6_addr
*) (ri
+ 8);
606 return (NDISC_ROUTER_OPTION_LENGTH(rt
) - 8) / 16;
609 _public_
int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router
*rt
, uint32_t *ret
) {
613 assert_return(rt
, -EINVAL
);
614 assert_return(ret
, -EINVAL
);
616 r
= get_rdnss_info(rt
, &ri
);
620 *ret
= be32toh(*(uint32_t*) (ri
+ 4));
624 static int get_dnssl_info(sd_ndisc_router
*rt
, uint8_t **ret
) {
631 r
= sd_ndisc_router_option_is_type(rt
, SD_NDISC_OPTION_DNSSL
);
637 length
= NDISC_ROUTER_OPTION_LENGTH(rt
);
641 *ret
= (uint8_t*) NDISC_ROUTER_RAW(rt
) + rt
->rindex
;
645 _public_
int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router
*rt
, char ***ret
) {
646 _cleanup_strv_free_
char **l
= NULL
;
647 _cleanup_free_
char *e
= NULL
;
648 size_t allocated
= 0, n
= 0, left
;
654 assert_return(rt
, -EINVAL
);
655 assert_return(ret
, -EINVAL
);
657 r
= get_dnssl_info(rt
, &ri
);
662 left
= NDISC_ROUTER_OPTION_LENGTH(rt
) - 8;
667 if (n
> 0) /* Not properly NUL terminated */
674 /* Found NUL termination */
677 _cleanup_free_
char *normalized
= NULL
;
680 r
= dns_name_normalize(e
, 0, &normalized
);
684 /* Ignore the root domain name or "localhost" and friends */
685 if (!is_localhost(normalized
) &&
686 !dns_name_is_root(normalized
)) {
688 if (strv_push(&l
, normalized
) < 0)
702 /* Check for compression (which is not allowed) */
706 if (1U + *p
+ 1U > left
)
709 if (!GREEDY_REALLOC(e
, allocated
, n
+ !first
+ DNS_LABEL_ESCAPED_MAX
+ 1U))
717 r
= dns_label_escape((char*) p
+1, *p
, e
+ n
, DNS_LABEL_ESCAPED_MAX
);
727 if (strv_isempty(l
)) {
737 _public_
int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router
*rt
, uint32_t *ret_sec
) {
741 assert_return(rt
, -EINVAL
);
742 assert_return(ret_sec
, -EINVAL
);
744 r
= get_dnssl_info(rt
, &ri
);
748 *ret_sec
= be32toh(*(uint32_t*) (ri
+ 4));