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(NULL
, 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_addr_is_null(&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
*nd
, 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 return log_ndisc_errno(nd
, SYNTHETIC_ERRNO(EBADMSG
),
100 "Too small to be a router advertisement, ignoring.");
102 /* Router advertisement packets are neatly aligned to 64bit boundaries, hence we can access them directly */
103 a
= NDISC_ROUTER_RAW(rt
);
105 if (a
->nd_ra_type
!= ND_ROUTER_ADVERT
)
106 return log_ndisc_errno(nd
, SYNTHETIC_ERRNO(EBADMSG
),
107 "Received ND packet that is not a router advertisement, ignoring.");
109 if (a
->nd_ra_code
!= 0)
110 return log_ndisc_errno(nd
, SYNTHETIC_ERRNO(EBADMSG
),
111 "Received ND packet with wrong RA code, ignoring.");
113 rt
->hop_limit
= a
->nd_ra_curhoplimit
;
114 rt
->flags
= a
->nd_ra_flags_reserved
; /* the first 8bit */
115 rt
->lifetime
= be16toh(a
->nd_ra_router_lifetime
);
117 rt
->preference
= (rt
->flags
>> 3) & 3;
118 if (!IN_SET(rt
->preference
, SD_NDISC_PREFERENCE_LOW
, SD_NDISC_PREFERENCE_HIGH
))
119 rt
->preference
= SD_NDISC_PREFERENCE_MEDIUM
;
121 p
= (const uint8_t*) NDISC_ROUTER_RAW(rt
) + sizeof(struct nd_router_advert
);
122 left
= rt
->raw_size
- sizeof(struct nd_router_advert
);
132 return log_ndisc_errno(nd
, SYNTHETIC_ERRNO(EBADMSG
),
133 "Option lacks header, ignoring datagram.");
139 return log_ndisc_errno(nd
, SYNTHETIC_ERRNO(EBADMSG
),
140 "Zero-length option, ignoring datagram.");
142 return log_ndisc_errno(nd
, SYNTHETIC_ERRNO(EBADMSG
),
143 "Option truncated, ignoring datagram.");
147 case SD_NDISC_OPTION_PREFIX_INFORMATION
:
150 return log_ndisc_errno(nd
, SYNTHETIC_ERRNO(EBADMSG
),
151 "Prefix option of invalid size, ignoring datagram.");
154 return log_ndisc_errno(nd
, SYNTHETIC_ERRNO(EBADMSG
),
155 "Bad prefix length, ignoring datagram.");
159 case SD_NDISC_OPTION_MTU
: {
163 log_ndisc(nd
, "MTU option specified twice, ignoring.");
168 return log_ndisc_errno(nd
, SYNTHETIC_ERRNO(EBADMSG
),
169 "MTU option of invalid size, ignoring datagram.");
171 m
= be32toh(*(uint32_t*) (p
+ 4));
172 if (m
>= IPV6_MIN_MTU
) /* ignore invalidly small MTUs */
179 case SD_NDISC_OPTION_ROUTE_INFORMATION
:
180 if (length
< 1*8 || length
> 3*8)
181 return log_ndisc_errno(nd
, SYNTHETIC_ERRNO(EBADMSG
),
182 "Route information option of invalid size, ignoring datagram.");
185 return log_ndisc_errno(nd
, SYNTHETIC_ERRNO(EBADMSG
),
186 "Bad route prefix length, ignoring datagram.");
190 case SD_NDISC_OPTION_RDNSS
:
191 if (length
< 3*8 || (length
% (2*8)) != 1*8)
192 return log_ndisc_errno(nd
, SYNTHETIC_ERRNO(EBADMSG
), "RDNSS option has invalid size.");
196 case SD_NDISC_OPTION_FLAGS_EXTENSION
:
198 if (has_flag_extension
) {
199 log_ndisc(nd
, "Flags extension option specified twice, ignoring.");
204 return log_ndisc_errno(nd
, SYNTHETIC_ERRNO(EBADMSG
),
205 "Flags extension option has invalid size.");
207 /* Add in the additional flags bits */
209 ((uint64_t) p
[2] << 8) |
210 ((uint64_t) p
[3] << 16) |
211 ((uint64_t) p
[4] << 24) |
212 ((uint64_t) p
[5] << 32) |
213 ((uint64_t) p
[6] << 40) |
214 ((uint64_t) p
[7] << 48);
216 has_flag_extension
= true;
219 case SD_NDISC_OPTION_DNSSL
:
221 return log_ndisc_errno(nd
, SYNTHETIC_ERRNO(EBADMSG
),
222 "DNSSL option has invalid size.");
227 p
+= length
, left
-= length
;
230 rt
->rindex
= sizeof(struct nd_router_advert
);
234 _public_
int sd_ndisc_router_get_hop_limit(sd_ndisc_router
*rt
, uint8_t *ret
) {
235 assert_return(rt
, -EINVAL
);
236 assert_return(ret
, -EINVAL
);
238 *ret
= rt
->hop_limit
;
242 _public_
int sd_ndisc_router_get_flags(sd_ndisc_router
*rt
, uint64_t *ret_flags
) {
243 assert_return(rt
, -EINVAL
);
244 assert_return(ret_flags
, -EINVAL
);
246 *ret_flags
= rt
->flags
;
250 _public_
int sd_ndisc_router_get_lifetime(sd_ndisc_router
*rt
, uint16_t *ret_lifetime
) {
251 assert_return(rt
, -EINVAL
);
252 assert_return(ret_lifetime
, -EINVAL
);
254 *ret_lifetime
= rt
->lifetime
;
258 _public_
int sd_ndisc_router_get_preference(sd_ndisc_router
*rt
, unsigned *ret
) {
259 assert_return(rt
, -EINVAL
);
260 assert_return(ret
, -EINVAL
);
262 *ret
= rt
->preference
;
266 _public_
int sd_ndisc_router_get_mtu(sd_ndisc_router
*rt
, uint32_t *ret
) {
267 assert_return(rt
, -EINVAL
);
268 assert_return(ret
, -EINVAL
);
277 _public_
int sd_ndisc_router_option_rewind(sd_ndisc_router
*rt
) {
278 assert_return(rt
, -EINVAL
);
280 assert(rt
->raw_size
>= sizeof(struct nd_router_advert
));
281 rt
->rindex
= sizeof(struct nd_router_advert
);
283 return rt
->rindex
< rt
->raw_size
;
286 _public_
int sd_ndisc_router_option_next(sd_ndisc_router
*rt
) {
289 assert_return(rt
, -EINVAL
);
291 if (rt
->rindex
== rt
->raw_size
) /* EOF */
294 if (rt
->rindex
+ 2 > rt
->raw_size
) /* Truncated message */
297 length
= NDISC_ROUTER_OPTION_LENGTH(rt
);
298 if (rt
->rindex
+ length
> rt
->raw_size
)
301 rt
->rindex
+= length
;
302 return rt
->rindex
< rt
->raw_size
;
305 _public_
int sd_ndisc_router_option_get_type(sd_ndisc_router
*rt
, uint8_t *ret
) {
306 assert_return(rt
, -EINVAL
);
307 assert_return(ret
, -EINVAL
);
309 if (rt
->rindex
== rt
->raw_size
) /* EOF */
312 if (rt
->rindex
+ 2 > rt
->raw_size
) /* Truncated message */
315 *ret
= NDISC_ROUTER_OPTION_TYPE(rt
);
319 _public_
int sd_ndisc_router_option_is_type(sd_ndisc_router
*rt
, uint8_t type
) {
323 assert_return(rt
, -EINVAL
);
325 r
= sd_ndisc_router_option_get_type(rt
, &k
);
332 _public_
int sd_ndisc_router_option_get_raw(sd_ndisc_router
*rt
, const void **ret
, size_t *size
) {
335 assert_return(rt
, -EINVAL
);
336 assert_return(ret
, -EINVAL
);
337 assert_return(size
, -EINVAL
);
339 /* Note that this returns the full option, including the option header */
341 if (rt
->rindex
+ 2 > rt
->raw_size
)
344 length
= NDISC_ROUTER_OPTION_LENGTH(rt
);
345 if (rt
->rindex
+ length
> rt
->raw_size
)
348 *ret
= (uint8_t*) NDISC_ROUTER_RAW(rt
) + rt
->rindex
;
354 static int get_prefix_info(sd_ndisc_router
*rt
, struct nd_opt_prefix_info
**ret
) {
355 struct nd_opt_prefix_info
*ri
;
362 r
= sd_ndisc_router_option_is_type(rt
, SD_NDISC_OPTION_PREFIX_INFORMATION
);
368 length
= NDISC_ROUTER_OPTION_LENGTH(rt
);
369 if (length
!= sizeof(struct nd_opt_prefix_info
))
372 ri
= (struct nd_opt_prefix_info
*) ((uint8_t*) NDISC_ROUTER_RAW(rt
) + rt
->rindex
);
373 if (ri
->nd_opt_pi_prefix_len
> 128)
380 _public_
int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router
*rt
, uint32_t *ret
) {
381 struct nd_opt_prefix_info
*ri
;
384 assert_return(rt
, -EINVAL
);
385 assert_return(ret
, -EINVAL
);
387 r
= get_prefix_info(rt
, &ri
);
391 *ret
= be32toh(ri
->nd_opt_pi_valid_time
);
395 _public_
int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router
*rt
, uint32_t *ret
) {
396 struct nd_opt_prefix_info
*pi
;
399 assert_return(rt
, -EINVAL
);
400 assert_return(ret
, -EINVAL
);
402 r
= get_prefix_info(rt
, &pi
);
406 *ret
= be32toh(pi
->nd_opt_pi_preferred_time
);
410 _public_
int sd_ndisc_router_prefix_get_flags(sd_ndisc_router
*rt
, uint8_t *ret
) {
411 struct nd_opt_prefix_info
*pi
;
415 assert_return(rt
, -EINVAL
);
416 assert_return(ret
, -EINVAL
);
418 r
= get_prefix_info(rt
, &pi
);
422 flags
= pi
->nd_opt_pi_flags_reserved
;
424 if ((flags
& ND_OPT_PI_FLAG_AUTO
) && (pi
->nd_opt_pi_prefix_len
!= 64)) {
425 log_ndisc(NULL
, "Invalid prefix length, ignoring prefix for stateless autoconfiguration.");
426 flags
&= ~ND_OPT_PI_FLAG_AUTO
;
433 _public_
int sd_ndisc_router_prefix_get_address(sd_ndisc_router
*rt
, struct in6_addr
*ret_addr
) {
434 struct nd_opt_prefix_info
*pi
;
437 assert_return(rt
, -EINVAL
);
438 assert_return(ret_addr
, -EINVAL
);
440 r
= get_prefix_info(rt
, &pi
);
444 *ret_addr
= pi
->nd_opt_pi_prefix
;
448 _public_
int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router
*rt
, unsigned *ret
) {
449 struct nd_opt_prefix_info
*pi
;
452 assert_return(rt
, -EINVAL
);
453 assert_return(ret
, -EINVAL
);
455 r
= get_prefix_info(rt
, &pi
);
459 if (pi
->nd_opt_pi_prefix_len
> 128)
462 *ret
= pi
->nd_opt_pi_prefix_len
;
466 static int get_route_info(sd_ndisc_router
*rt
, uint8_t **ret
) {
474 r
= sd_ndisc_router_option_is_type(rt
, SD_NDISC_OPTION_ROUTE_INFORMATION
);
480 length
= NDISC_ROUTER_OPTION_LENGTH(rt
);
481 if (length
< 1*8 || length
> 3*8)
484 ri
= (uint8_t*) NDISC_ROUTER_RAW(rt
) + rt
->rindex
;
493 _public_
int sd_ndisc_router_route_get_lifetime(sd_ndisc_router
*rt
, uint32_t *ret
) {
497 assert_return(rt
, -EINVAL
);
498 assert_return(ret
, -EINVAL
);
500 r
= get_route_info(rt
, &ri
);
504 *ret
= be32toh(*(uint32_t*) (ri
+ 4));
508 _public_
int sd_ndisc_router_route_get_address(sd_ndisc_router
*rt
, struct in6_addr
*ret_addr
) {
512 assert_return(rt
, -EINVAL
);
513 assert_return(ret_addr
, -EINVAL
);
515 r
= get_route_info(rt
, &ri
);
520 memcpy(ret_addr
, ri
+ 8, NDISC_ROUTER_OPTION_LENGTH(rt
) - 8);
525 _public_
int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router
*rt
, unsigned *ret
) {
529 assert_return(rt
, -EINVAL
);
530 assert_return(ret
, -EINVAL
);
532 r
= get_route_info(rt
, &ri
);
540 _public_
int sd_ndisc_router_route_get_preference(sd_ndisc_router
*rt
, unsigned *ret
) {
544 assert_return(rt
, -EINVAL
);
545 assert_return(ret
, -EINVAL
);
547 r
= get_route_info(rt
, &ri
);
551 *ret
= (ri
[3] >> 3) & 3;
552 if (!IN_SET(*ret
, SD_NDISC_PREFERENCE_LOW
, SD_NDISC_PREFERENCE_HIGH
))
553 *ret
= SD_NDISC_PREFERENCE_MEDIUM
;
558 static int get_rdnss_info(sd_ndisc_router
*rt
, uint8_t **ret
) {
565 r
= sd_ndisc_router_option_is_type(rt
, SD_NDISC_OPTION_RDNSS
);
571 length
= NDISC_ROUTER_OPTION_LENGTH(rt
);
572 if (length
< 3*8 || (length
% (2*8)) != 1*8)
575 *ret
= (uint8_t*) NDISC_ROUTER_RAW(rt
) + rt
->rindex
;
579 _public_
int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router
*rt
, const struct in6_addr
**ret
) {
583 assert_return(rt
, -EINVAL
);
584 assert_return(ret
, -EINVAL
);
586 r
= get_rdnss_info(rt
, &ri
);
590 *ret
= (const struct in6_addr
*) (ri
+ 8);
591 return (NDISC_ROUTER_OPTION_LENGTH(rt
) - 8) / 16;
594 _public_
int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router
*rt
, uint32_t *ret
) {
598 assert_return(rt
, -EINVAL
);
599 assert_return(ret
, -EINVAL
);
601 r
= get_rdnss_info(rt
, &ri
);
605 *ret
= be32toh(*(uint32_t*) (ri
+ 4));
609 static int get_dnssl_info(sd_ndisc_router
*rt
, uint8_t **ret
) {
616 r
= sd_ndisc_router_option_is_type(rt
, SD_NDISC_OPTION_DNSSL
);
622 length
= NDISC_ROUTER_OPTION_LENGTH(rt
);
626 *ret
= (uint8_t*) NDISC_ROUTER_RAW(rt
) + rt
->rindex
;
630 _public_
int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router
*rt
, char ***ret
) {
631 _cleanup_strv_free_
char **l
= NULL
;
632 _cleanup_free_
char *e
= NULL
;
633 size_t allocated
= 0, n
= 0, left
;
639 assert_return(rt
, -EINVAL
);
640 assert_return(ret
, -EINVAL
);
642 r
= get_dnssl_info(rt
, &ri
);
647 left
= NDISC_ROUTER_OPTION_LENGTH(rt
) - 8;
652 if (n
> 0) /* Not properly NUL terminated */
659 /* Found NUL termination */
662 _cleanup_free_
char *normalized
= NULL
;
665 r
= dns_name_normalize(e
, 0, &normalized
);
669 /* Ignore the root domain name or "localhost" and friends */
670 if (!is_localhost(normalized
) &&
671 !dns_name_is_root(normalized
)) {
673 if (strv_push(&l
, normalized
) < 0)
687 /* Check for compression (which is not allowed) */
691 if (1U + *p
+ 1U > left
)
694 if (!GREEDY_REALLOC(e
, allocated
, n
+ !first
+ DNS_LABEL_ESCAPED_MAX
+ 1U))
702 r
= dns_label_escape((char*) p
+1, *p
, e
+ n
, DNS_LABEL_ESCAPED_MAX
);
712 if (strv_isempty(l
)) {
722 _public_
int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router
*rt
, uint32_t *ret_sec
) {
726 assert_return(rt
, -EINVAL
);
727 assert_return(ret_sec
, -EINVAL
);
729 r
= get_dnssl_info(rt
, &ri
);
733 *ret_sec
= be32toh(*(uint32_t*) (ri
+ 4));