1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright (C) 2014 Intel Corporation. All rights reserved.
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <netinet/icmp6.h>
25 #include "alloc-util.h"
26 #include "dns-domain.h"
27 #include "hostname-util.h"
29 #include "ndisc-internal.h"
30 #include "ndisc-router.h"
33 _public_ sd_ndisc_router
* sd_ndisc_router_ref(sd_ndisc_router
*rt
) {
37 assert(rt
->n_ref
> 0);
43 _public_ sd_ndisc_router
* sd_ndisc_router_unref(sd_ndisc_router
*rt
) {
47 assert(rt
->n_ref
> 0);
56 sd_ndisc_router
*ndisc_router_new(size_t raw_size
) {
59 rt
= malloc0(ALIGN(sizeof(sd_ndisc_router
)) + raw_size
);
63 rt
->raw_size
= raw_size
;
69 _public_
int sd_ndisc_router_from_raw(sd_ndisc_router
**ret
, const void *raw
, size_t raw_size
) {
70 _cleanup_(sd_ndisc_router_unrefp
) sd_ndisc_router
*rt
= NULL
;
73 assert_return(ret
, -EINVAL
);
74 assert_return(raw
|| raw_size
<= 0, -EINVAL
);
76 rt
= ndisc_router_new(raw_size
);
80 memcpy(NDISC_ROUTER_RAW(rt
), raw
, raw_size
);
81 r
= ndisc_router_parse(rt
);
91 _public_
int sd_ndisc_router_get_address(sd_ndisc_router
*rt
, struct in6_addr
*ret_addr
) {
92 assert_return(rt
, -EINVAL
);
93 assert_return(ret_addr
, -EINVAL
);
95 if (IN6_IS_ADDR_UNSPECIFIED(&rt
->address
))
98 *ret_addr
= rt
->address
;
102 _public_
int sd_ndisc_router_get_timestamp(sd_ndisc_router
*rt
, clockid_t clock
, uint64_t *ret
) {
103 assert_return(rt
, -EINVAL
);
104 assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock
), -EOPNOTSUPP
);
105 assert_return(clock_supported(clock
), -EOPNOTSUPP
);
106 assert_return(ret
, -EINVAL
);
108 if (!triple_timestamp_is_set(&rt
->timestamp
))
111 *ret
= triple_timestamp_by_clock(&rt
->timestamp
, clock
);
115 _public_
int sd_ndisc_router_get_raw(sd_ndisc_router
*rt
, const void **ret
, size_t *size
) {
116 assert_return(rt
, -EINVAL
);
117 assert_return(ret
, -EINVAL
);
118 assert_return(size
, -EINVAL
);
120 *ret
= NDISC_ROUTER_RAW(rt
);
121 *size
= rt
->raw_size
;
126 int ndisc_router_parse(sd_ndisc_router
*rt
) {
127 struct nd_router_advert
*a
;
129 bool has_mtu
= false, has_flag_extension
= false;
134 if (rt
->raw_size
< sizeof(struct nd_router_advert
)) {
135 log_ndisc("Too small to be a router advertisement, ignoring.");
139 /* Router advertisement packets are neatly aligned to 64bit boundaries, hence we can access them directly */
140 a
= NDISC_ROUTER_RAW(rt
);
142 if (a
->nd_ra_type
!= ND_ROUTER_ADVERT
) {
143 log_ndisc("Received ND packet that is not a router advertisement, ignoring.");
147 if (a
->nd_ra_code
!= 0) {
148 log_ndisc("Received ND packet with wrong RA code, ignoring.");
152 rt
->hop_limit
= a
->nd_ra_curhoplimit
;
153 rt
->flags
= a
->nd_ra_flags_reserved
; /* the first 8bit */
154 rt
->lifetime
= be16toh(a
->nd_ra_router_lifetime
);
156 rt
->preference
= (rt
->flags
>> 3) & 3;
157 if (!IN_SET(rt
->preference
, SD_NDISC_PREFERENCE_LOW
, SD_NDISC_PREFERENCE_HIGH
))
158 rt
->preference
= SD_NDISC_PREFERENCE_MEDIUM
;
160 p
= (const uint8_t*) NDISC_ROUTER_RAW(rt
) + sizeof(struct nd_router_advert
);
161 left
= rt
->raw_size
- sizeof(struct nd_router_advert
);
171 log_ndisc("Option lacks header, ignoring datagram.");
179 log_ndisc("Zero-length option, ignoring datagram.");
183 log_ndisc("Option truncated, ignoring datagram.");
189 case SD_NDISC_OPTION_PREFIX_INFORMATION
:
192 log_ndisc("Prefix option of invalid size, ignoring datagram.");
197 log_ndisc("Bad prefix length, ignoring datagram.");
203 case SD_NDISC_OPTION_MTU
: {
207 log_ndisc("MTU option specified twice, ignoring.");
212 log_ndisc("MTU option of invalid size, ignoring datagram.");
216 m
= be32toh(*(uint32_t*) (p
+ 4));
217 if (m
>= IPV6_MIN_MTU
) /* ignore invalidly small MTUs */
224 case SD_NDISC_OPTION_ROUTE_INFORMATION
:
225 if (length
< 1*8 || length
> 3*8) {
226 log_ndisc("Route information option of invalid size, ignoring datagram.");
231 log_ndisc("Bad route prefix length, ignoring datagram.");
237 case SD_NDISC_OPTION_RDNSS
:
238 if (length
< 3*8 || (length
% (2*8)) != 1*8) {
239 log_ndisc("RDNSS option has invalid size.");
245 case SD_NDISC_OPTION_FLAGS_EXTENSION
:
247 if (has_flag_extension
) {
248 log_ndisc("Flags extension option specified twice, ignoring.");
253 log_ndisc("Flags extension option has invalid size.");
257 /* Add in the additional flags bits */
259 ((uint64_t) p
[2] << 8) |
260 ((uint64_t) p
[3] << 16) |
261 ((uint64_t) p
[4] << 24) |
262 ((uint64_t) p
[5] << 32) |
263 ((uint64_t) p
[6] << 40) |
264 ((uint64_t) p
[7] << 48);
266 has_flag_extension
= true;
269 case SD_NDISC_OPTION_DNSSL
:
271 log_ndisc("DNSSL option has invalid size.");
278 p
+= length
, left
-= length
;
281 rt
->rindex
= sizeof(struct nd_router_advert
);
285 _public_
int sd_ndisc_router_get_hop_limit(sd_ndisc_router
*rt
, uint8_t *ret
) {
286 assert_return(rt
, -EINVAL
);
287 assert_return(ret
, -EINVAL
);
289 *ret
= rt
->hop_limit
;
293 _public_
int sd_ndisc_router_get_flags(sd_ndisc_router
*rt
, uint64_t *ret_flags
) {
294 assert_return(rt
, -EINVAL
);
295 assert_return(ret_flags
, -EINVAL
);
297 *ret_flags
= rt
->flags
;
301 _public_
int sd_ndisc_router_get_lifetime(sd_ndisc_router
*rt
, uint16_t *ret_lifetime
) {
302 assert_return(rt
, -EINVAL
);
303 assert_return(ret_lifetime
, -EINVAL
);
305 *ret_lifetime
= rt
->lifetime
;
309 _public_
int sd_ndisc_router_get_preference(sd_ndisc_router
*rt
, unsigned *ret
) {
310 assert_return(rt
, -EINVAL
);
311 assert_return(ret
, -EINVAL
);
313 *ret
= rt
->preference
;
317 _public_
int sd_ndisc_router_get_mtu(sd_ndisc_router
*rt
, uint32_t *ret
) {
318 assert_return(rt
, -EINVAL
);
319 assert_return(ret
, -EINVAL
);
328 _public_
int sd_ndisc_router_option_rewind(sd_ndisc_router
*rt
) {
329 assert_return(rt
, -EINVAL
);
331 assert(rt
->raw_size
>= sizeof(struct nd_router_advert
));
332 rt
->rindex
= sizeof(struct nd_router_advert
);
334 return rt
->rindex
< rt
->raw_size
;
337 _public_
int sd_ndisc_router_option_next(sd_ndisc_router
*rt
) {
340 assert_return(rt
, -EINVAL
);
342 if (rt
->rindex
== rt
->raw_size
) /* EOF */
345 if (rt
->rindex
+ 2 > rt
->raw_size
) /* Truncated message */
348 length
= NDISC_ROUTER_OPTION_LENGTH(rt
);
349 if (rt
->rindex
+ length
> rt
->raw_size
)
352 rt
->rindex
+= length
;
353 return rt
->rindex
< rt
->raw_size
;
356 _public_
int sd_ndisc_router_option_get_type(sd_ndisc_router
*rt
, uint8_t *ret
) {
357 assert_return(rt
, -EINVAL
);
358 assert_return(ret
, -EINVAL
);
360 if (rt
->rindex
== rt
->raw_size
) /* EOF */
363 if (rt
->rindex
+ 2 > rt
->raw_size
) /* Truncated message */
366 *ret
= NDISC_ROUTER_OPTION_TYPE(rt
);
370 _public_
int sd_ndisc_router_option_is_type(sd_ndisc_router
*rt
, uint8_t type
) {
374 assert_return(rt
, -EINVAL
);
376 r
= sd_ndisc_router_option_get_type(rt
, &k
);
383 _public_
int sd_ndisc_router_option_get_raw(sd_ndisc_router
*rt
, const void **ret
, size_t *size
) {
386 assert_return(rt
, -EINVAL
);
387 assert_return(ret
, -EINVAL
);
388 assert_return(size
, -EINVAL
);
390 /* Note that this returns the full option, including the option header */
392 if (rt
->rindex
+ 2 > rt
->raw_size
)
395 length
= NDISC_ROUTER_OPTION_LENGTH(rt
);
396 if (rt
->rindex
+ length
> rt
->raw_size
)
399 *ret
= (uint8_t*) NDISC_ROUTER_RAW(rt
) + rt
->rindex
;
405 static int get_prefix_info(sd_ndisc_router
*rt
, struct nd_opt_prefix_info
**ret
) {
406 struct nd_opt_prefix_info
*ri
;
413 r
= sd_ndisc_router_option_is_type(rt
, SD_NDISC_OPTION_PREFIX_INFORMATION
);
419 length
= NDISC_ROUTER_OPTION_LENGTH(rt
);
420 if (length
!= sizeof(struct nd_opt_prefix_info
))
423 ri
= (struct nd_opt_prefix_info
*) ((uint8_t*) NDISC_ROUTER_RAW(rt
) + rt
->rindex
);
424 if (ri
->nd_opt_pi_prefix_len
> 128)
431 _public_
int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router
*rt
, uint32_t *ret
) {
432 struct nd_opt_prefix_info
*ri
;
435 assert_return(rt
, -EINVAL
);
436 assert_return(ret
, -EINVAL
);
438 r
= get_prefix_info(rt
, &ri
);
442 *ret
= be32toh(ri
->nd_opt_pi_valid_time
);
446 _public_
int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router
*rt
, uint32_t *ret
) {
447 struct nd_opt_prefix_info
*pi
;
450 assert_return(rt
, -EINVAL
);
451 assert_return(ret
, -EINVAL
);
453 r
= get_prefix_info(rt
, &pi
);
457 *ret
= be32toh(pi
->nd_opt_pi_preferred_time
);
461 _public_
int sd_ndisc_router_prefix_get_flags(sd_ndisc_router
*rt
, uint8_t *ret
) {
462 struct nd_opt_prefix_info
*pi
;
466 assert_return(rt
, -EINVAL
);
467 assert_return(ret
, -EINVAL
);
469 r
= get_prefix_info(rt
, &pi
);
473 flags
= pi
->nd_opt_pi_flags_reserved
;
475 if ((flags
& ND_OPT_PI_FLAG_AUTO
) && (pi
->nd_opt_pi_prefix_len
!= 64)) {
476 log_ndisc("Invalid prefix length, ignoring prefix for stateless autoconfiguration.");
477 flags
&= ~ND_OPT_PI_FLAG_AUTO
;
484 _public_
int sd_ndisc_router_prefix_get_address(sd_ndisc_router
*rt
, struct in6_addr
*ret_addr
) {
485 struct nd_opt_prefix_info
*pi
;
488 assert_return(rt
, -EINVAL
);
489 assert_return(ret_addr
, -EINVAL
);
491 r
= get_prefix_info(rt
, &pi
);
495 *ret_addr
= pi
->nd_opt_pi_prefix
;
499 _public_
int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router
*rt
, unsigned *ret
) {
500 struct nd_opt_prefix_info
*pi
;
503 assert_return(rt
, -EINVAL
);
504 assert_return(ret
, -EINVAL
);
506 r
= get_prefix_info(rt
, &pi
);
510 if (pi
->nd_opt_pi_prefix_len
> 128)
513 *ret
= pi
->nd_opt_pi_prefix_len
;
517 static int get_route_info(sd_ndisc_router
*rt
, uint8_t **ret
) {
525 r
= sd_ndisc_router_option_is_type(rt
, SD_NDISC_OPTION_ROUTE_INFORMATION
);
531 length
= NDISC_ROUTER_OPTION_LENGTH(rt
);
532 if (length
< 1*8 || length
> 3*8)
535 ri
= (uint8_t*) NDISC_ROUTER_RAW(rt
) + rt
->rindex
;
544 _public_
int sd_ndisc_router_route_get_lifetime(sd_ndisc_router
*rt
, uint32_t *ret
) {
548 assert_return(rt
, -EINVAL
);
549 assert_return(ret
, -EINVAL
);
551 r
= get_route_info(rt
, &ri
);
555 *ret
= be32toh(*(uint32_t*) (ri
+ 4));
559 _public_
int sd_ndisc_router_route_get_address(sd_ndisc_router
*rt
, struct in6_addr
*ret_addr
) {
563 assert_return(rt
, -EINVAL
);
564 assert_return(ret_addr
, -EINVAL
);
566 r
= get_route_info(rt
, &ri
);
571 memcpy(ret_addr
, ri
+ 8, NDISC_ROUTER_OPTION_LENGTH(rt
) - 8);
576 _public_
int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router
*rt
, unsigned *ret
) {
580 assert_return(rt
, -EINVAL
);
581 assert_return(ret
, -EINVAL
);
583 r
= get_route_info(rt
, &ri
);
591 _public_
int sd_ndisc_router_route_get_preference(sd_ndisc_router
*rt
, unsigned *ret
) {
595 assert_return(rt
, -EINVAL
);
596 assert_return(ret
, -EINVAL
);
598 r
= get_route_info(rt
, &ri
);
602 *ret
= (ri
[3] >> 3) & 3;
603 if (!IN_SET(*ret
, SD_NDISC_PREFERENCE_LOW
, SD_NDISC_PREFERENCE_HIGH
))
604 *ret
= SD_NDISC_PREFERENCE_MEDIUM
;
609 static int get_rdnss_info(sd_ndisc_router
*rt
, uint8_t **ret
) {
616 r
= sd_ndisc_router_option_is_type(rt
, SD_NDISC_OPTION_RDNSS
);
622 length
= NDISC_ROUTER_OPTION_LENGTH(rt
);
623 if (length
< 3*8 || (length
% (2*8)) != 1*8)
626 *ret
= (uint8_t*) NDISC_ROUTER_RAW(rt
) + rt
->rindex
;
630 _public_
int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router
*rt
, const struct in6_addr
**ret
) {
634 assert_return(rt
, -EINVAL
);
635 assert_return(ret
, -EINVAL
);
637 r
= get_rdnss_info(rt
, &ri
);
641 *ret
= (const struct in6_addr
*) (ri
+ 8);
642 return (NDISC_ROUTER_OPTION_LENGTH(rt
) - 8) / 16;
645 _public_
int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router
*rt
, uint32_t *ret
) {
649 assert_return(rt
, -EINVAL
);
650 assert_return(ret
, -EINVAL
);
652 r
= get_rdnss_info(rt
, &ri
);
656 *ret
= be32toh(*(uint32_t*) (ri
+ 4));
660 static int get_dnssl_info(sd_ndisc_router
*rt
, uint8_t **ret
) {
667 r
= sd_ndisc_router_option_is_type(rt
, SD_NDISC_OPTION_DNSSL
);
673 length
= NDISC_ROUTER_OPTION_LENGTH(rt
);
677 *ret
= (uint8_t*) NDISC_ROUTER_RAW(rt
) + rt
->rindex
;
681 _public_
int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router
*rt
, char ***ret
) {
682 _cleanup_strv_free_
char **l
= NULL
;
683 _cleanup_free_
char *e
= NULL
;
684 size_t allocated
= 0, n
= 0, left
;
690 assert_return(rt
, -EINVAL
);
691 assert_return(ret
, -EINVAL
);
693 r
= get_dnssl_info(rt
, &ri
);
698 left
= NDISC_ROUTER_OPTION_LENGTH(rt
) - 8;
703 if (n
> 0) /* Not properly NUL terminated */
710 /* Found NUL termination */
713 _cleanup_free_
char *normalized
= NULL
;
716 r
= dns_name_normalize(e
, &normalized
);
720 /* Ignore the root domain name or "localhost" and friends */
721 if (!is_localhost(normalized
) &&
722 !dns_name_is_root(normalized
)) {
724 if (strv_push(&l
, normalized
) < 0)
738 /* Check for compression (which is not allowed) */
742 if (1U + *p
+ 1U > left
)
745 if (!GREEDY_REALLOC(e
, allocated
, n
+ !first
+ DNS_LABEL_ESCAPED_MAX
+ 1U))
753 r
= dns_label_escape((char*) p
+1, *p
, e
+ n
, DNS_LABEL_ESCAPED_MAX
);
763 if (strv_isempty(l
)) {
774 _public_
int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router
*rt
, uint32_t *ret_sec
) {
778 assert_return(rt
, -EINVAL
);
779 assert_return(ret_sec
, -EINVAL
);
781 r
= get_dnssl_info(rt
, &ri
);
785 *ret_sec
= be32toh(*(uint32_t*) (ri
+ 4));