]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/ndisc-router.c
IPv6 RA: Support the Retrans Timer field (IPv6 Conformance Test: v6LC.2.1.5)
[thirdparty/systemd.git] / src / libsystemd-network / ndisc-router.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /***
3 Copyright © 2014 Intel Corporation. All rights reserved.
4 ***/
5
6 #include <netinet/icmp6.h>
7
8 #include "sd-ndisc.h"
9
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-protocol.h"
17 #include "ndisc-router.h"
18 #include "strv.h"
19
20 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_ndisc_router, sd_ndisc_router, mfree);
21
22 sd_ndisc_router *ndisc_router_new(size_t raw_size) {
23 sd_ndisc_router *rt;
24
25 if (raw_size > SIZE_MAX - ALIGN(sizeof(sd_ndisc_router)))
26 return NULL;
27
28 rt = malloc0(ALIGN(sizeof(sd_ndisc_router)) + raw_size);
29 if (!rt)
30 return NULL;
31
32 rt->raw_size = raw_size;
33 rt->n_ref = 1;
34
35 return rt;
36 }
37
38 int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret) {
39 assert_return(rt, -EINVAL);
40 assert_return(ret, -EINVAL);
41
42 if (in6_addr_is_null(&rt->address))
43 return -ENODATA;
44
45 *ret = rt->address;
46 return 0;
47 }
48
49 int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret) {
50 assert_return(rt, -EINVAL);
51 assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP);
52 assert_return(clock_supported(clock), -EOPNOTSUPP);
53 assert_return(ret, -EINVAL);
54
55 if (!triple_timestamp_is_set(&rt->timestamp))
56 return -ENODATA;
57
58 *ret = triple_timestamp_by_clock(&rt->timestamp, clock);
59 return 0;
60 }
61
62 #define DEFINE_GET_TIMESTAMP(name) \
63 int sd_ndisc_router_##name##_timestamp( \
64 sd_ndisc_router *rt, \
65 clockid_t clock, \
66 uint64_t *ret) { \
67 \
68 usec_t s, t; \
69 int r; \
70 \
71 assert_return(rt, -EINVAL); \
72 assert_return(ret, -EINVAL); \
73 \
74 r = sd_ndisc_router_##name(rt, &s); \
75 if (r < 0) \
76 return r; \
77 \
78 r = sd_ndisc_router_get_timestamp(rt, clock, &t); \
79 if (r < 0) \
80 return r; \
81 \
82 *ret = time_span_to_stamp(s, t); \
83 return 0; \
84 }
85
86 DEFINE_GET_TIMESTAMP(get_lifetime);
87 DEFINE_GET_TIMESTAMP(prefix_get_valid_lifetime);
88 DEFINE_GET_TIMESTAMP(prefix_get_preferred_lifetime);
89 DEFINE_GET_TIMESTAMP(route_get_lifetime);
90 DEFINE_GET_TIMESTAMP(rdnss_get_lifetime);
91 DEFINE_GET_TIMESTAMP(dnssl_get_lifetime);
92 DEFINE_GET_TIMESTAMP(prefix64_get_lifetime);
93
94 int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size) {
95 assert_return(rt, -EINVAL);
96 assert_return(ret, -EINVAL);
97 assert_return(ret_size, -EINVAL);
98
99 *ret = NDISC_ROUTER_RAW(rt);
100 *ret_size = rt->raw_size;
101
102 return 0;
103 }
104
105 static bool pref64_option_verify(const struct nd_opt_prefix64_info *p, size_t length) {
106 uint16_t lifetime_and_plc;
107
108 assert(p);
109
110 if (length != sizeof(struct nd_opt_prefix64_info))
111 return false;
112
113 lifetime_and_plc = be16toh(p->lifetime_and_plc);
114 if (pref64_plc_to_prefix_length(lifetime_and_plc, NULL) < 0)
115 return false;
116
117 return true;
118 }
119
120 int ndisc_router_parse(sd_ndisc *nd, sd_ndisc_router *rt) {
121 struct nd_router_advert *a;
122 const uint8_t *p;
123 bool has_mtu = false, has_flag_extension = false;
124 size_t left;
125
126 assert(rt);
127
128 if (rt->raw_size < sizeof(struct nd_router_advert))
129 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
130 "Too small to be a router advertisement, ignoring.");
131
132 /* Router advertisement packets are neatly aligned to 64-bit boundaries, hence we can access them directly */
133 a = NDISC_ROUTER_RAW(rt);
134
135 if (a->nd_ra_type != ND_ROUTER_ADVERT)
136 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
137 "Received ND packet that is not a router advertisement, ignoring.");
138
139 if (a->nd_ra_code != 0)
140 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
141 "Received ND packet with wrong RA code, ignoring.");
142
143 rt->hop_limit = a->nd_ra_curhoplimit;
144 rt->flags = a->nd_ra_flags_reserved; /* the first 8 bits */
145 rt->lifetime_usec = be16_sec_to_usec(a->nd_ra_router_lifetime, /* max_as_infinity = */ false);
146 rt->icmp6_ratelimit_usec = be32_msec_to_usec(a->nd_ra_retransmit, /* max_as_infinity = */ false);
147 rt->retransmission_time_usec = be32_msec_to_usec(a->nd_ra_retransmit, /* max_as_infinity = */ false);
148
149 rt->preference = (rt->flags >> 3) & 3;
150 if (!IN_SET(rt->preference, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_HIGH))
151 rt->preference = SD_NDISC_PREFERENCE_MEDIUM;
152
153 p = (const uint8_t*) NDISC_ROUTER_RAW(rt) + sizeof(struct nd_router_advert);
154 left = rt->raw_size - sizeof(struct nd_router_advert);
155
156 for (;;) {
157 uint8_t type;
158 size_t length;
159
160 if (left == 0)
161 break;
162
163 if (left < 2)
164 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
165 "Option lacks header, ignoring datagram.");
166
167 type = p[0];
168 length = p[1] * 8;
169
170 if (length == 0)
171 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
172 "Zero-length option, ignoring datagram.");
173 if (left < length)
174 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
175 "Option truncated, ignoring datagram.");
176
177 switch (type) {
178
179 case SD_NDISC_OPTION_PREFIX_INFORMATION:
180
181 if (length != 4*8)
182 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
183 "Prefix option of invalid size, ignoring datagram.");
184
185 if (p[2] > 128)
186 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
187 "Bad prefix length, ignoring datagram.");
188
189 break;
190
191 case SD_NDISC_OPTION_MTU: {
192 uint32_t m;
193
194 if (has_mtu) {
195 log_ndisc(nd, "MTU option specified twice, ignoring.");
196 break;
197 }
198
199 if (length != 8)
200 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
201 "MTU option of invalid size, ignoring datagram.");
202
203 m = be32toh(*(uint32_t*) (p + 4));
204 if (m >= IPV6_MIN_MTU) /* ignore invalidly small MTUs */
205 rt->mtu = m;
206
207 has_mtu = true;
208 break;
209 }
210
211 case SD_NDISC_OPTION_ROUTE_INFORMATION:
212 if (length < 1*8 || length > 3*8)
213 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
214 "Route information option of invalid size, ignoring datagram.");
215
216 if (p[2] > 128)
217 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
218 "Bad route prefix length, ignoring datagram.");
219
220 break;
221
222 case SD_NDISC_OPTION_RDNSS:
223 if (length < 3*8 || (length % (2*8)) != 1*8)
224 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG), "RDNSS option has invalid size.");
225
226 break;
227
228 case SD_NDISC_OPTION_FLAGS_EXTENSION:
229
230 if (has_flag_extension) {
231 log_ndisc(nd, "Flags extension option specified twice, ignoring.");
232 break;
233 }
234
235 if (length < 1*8)
236 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
237 "Flags extension option has invalid size.");
238
239 /* Add in the additional flags bits */
240 rt->flags |=
241 ((uint64_t) p[2] << 8) |
242 ((uint64_t) p[3] << 16) |
243 ((uint64_t) p[4] << 24) |
244 ((uint64_t) p[5] << 32) |
245 ((uint64_t) p[6] << 40) |
246 ((uint64_t) p[7] << 48);
247
248 has_flag_extension = true;
249 break;
250
251 case SD_NDISC_OPTION_DNSSL:
252 if (length < 2*8)
253 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
254 "DNSSL option has invalid size.");
255
256 break;
257 case SD_NDISC_OPTION_PREF64: {
258 if (!pref64_option_verify((struct nd_opt_prefix64_info *) p, length))
259 log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
260 "PREF64 prefix has invalid prefix length.");
261 break;
262 }}
263
264 p += length, left -= length;
265 }
266
267 rt->rindex = sizeof(struct nd_router_advert);
268 return 0;
269 }
270
271 int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret) {
272 assert_return(rt, -EINVAL);
273 assert_return(ret, -EINVAL);
274
275 *ret = rt->hop_limit;
276 return 0;
277 }
278
279 int sd_ndisc_router_get_retransmission_time(sd_ndisc_router *rt, uint64_t *ret) {
280 assert_return(rt, -EINVAL);
281 assert_return(ret, -EINVAL);
282
283 *ret = rt->retransmission_time_usec;
284 return 0;
285 }
286
287 int sd_ndisc_router_get_icmp6_ratelimit(sd_ndisc_router *rt, uint64_t *ret) {
288 assert_return(rt, -EINVAL);
289 assert_return(ret, -EINVAL);
290
291 *ret = rt->icmp6_ratelimit_usec;
292 return 0;
293 }
294
295 int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret) {
296 assert_return(rt, -EINVAL);
297 assert_return(ret, -EINVAL);
298
299 *ret = rt->flags;
300 return 0;
301 }
302
303 int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint64_t *ret) {
304 assert_return(rt, -EINVAL);
305 assert_return(ret, -EINVAL);
306
307 *ret = rt->lifetime_usec;
308 return 0;
309 }
310
311 int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret) {
312 assert_return(rt, -EINVAL);
313 assert_return(ret, -EINVAL);
314
315 *ret = rt->preference;
316 return 0;
317 }
318
319 int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret) {
320 assert_return(rt, -EINVAL);
321 assert_return(ret, -EINVAL);
322
323 if (rt->mtu <= 0)
324 return -ENODATA;
325
326 *ret = rt->mtu;
327 return 0;
328 }
329
330 int sd_ndisc_router_option_rewind(sd_ndisc_router *rt) {
331 assert_return(rt, -EINVAL);
332
333 assert(rt->raw_size >= sizeof(struct nd_router_advert));
334 rt->rindex = sizeof(struct nd_router_advert);
335
336 return rt->rindex < rt->raw_size;
337 }
338
339 int sd_ndisc_router_option_next(sd_ndisc_router *rt) {
340 size_t length;
341
342 assert_return(rt, -EINVAL);
343
344 if (rt->rindex == rt->raw_size) /* EOF */
345 return -ESPIPE;
346
347 if (rt->rindex + 2 > rt->raw_size) /* Truncated message */
348 return -EBADMSG;
349
350 length = NDISC_ROUTER_OPTION_LENGTH(rt);
351 if (rt->rindex + length > rt->raw_size)
352 return -EBADMSG;
353
354 rt->rindex += length;
355 return rt->rindex < rt->raw_size;
356 }
357
358 int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret) {
359 assert_return(rt, -EINVAL);
360 assert_return(ret, -EINVAL);
361
362 if (rt->rindex == rt->raw_size) /* EOF */
363 return -ESPIPE;
364
365 if (rt->rindex + 2 > rt->raw_size) /* Truncated message */
366 return -EBADMSG;
367
368 *ret = NDISC_ROUTER_OPTION_TYPE(rt);
369 return 0;
370 }
371
372 int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type) {
373 uint8_t k;
374 int r;
375
376 assert_return(rt, -EINVAL);
377
378 r = sd_ndisc_router_option_get_type(rt, &k);
379 if (r < 0)
380 return r;
381
382 return type == k;
383 }
384
385 int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size) {
386 size_t length;
387
388 assert_return(rt, -EINVAL);
389 assert_return(ret, -EINVAL);
390 assert_return(ret_size, -EINVAL);
391
392 /* Note that this returns the full option, including the option header */
393
394 if (rt->rindex + 2 > rt->raw_size)
395 return -EBADMSG;
396
397 length = NDISC_ROUTER_OPTION_LENGTH(rt);
398 if (rt->rindex + length > rt->raw_size)
399 return -EBADMSG;
400
401 *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
402 *ret_size = length;
403
404 return 0;
405 }
406
407 static int get_prefix_info(sd_ndisc_router *rt, struct nd_opt_prefix_info **ret) {
408 struct nd_opt_prefix_info *ri;
409 size_t length;
410 int r;
411
412 assert(rt);
413 assert(ret);
414
415 r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_PREFIX_INFORMATION);
416 if (r < 0)
417 return r;
418 if (r == 0)
419 return -EMEDIUMTYPE;
420
421 length = NDISC_ROUTER_OPTION_LENGTH(rt);
422 if (length != sizeof(struct nd_opt_prefix_info))
423 return -EBADMSG;
424
425 ri = (struct nd_opt_prefix_info*) ((uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex);
426 if (ri->nd_opt_pi_prefix_len > 128)
427 return -EBADMSG;
428
429 *ret = ri;
430 return 0;
431 }
432
433 int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint64_t *ret) {
434 struct nd_opt_prefix_info *ri;
435 int r;
436
437 assert_return(rt, -EINVAL);
438 assert_return(ret, -EINVAL);
439
440 r = get_prefix_info(rt, &ri);
441 if (r < 0)
442 return r;
443
444 *ret = be32_sec_to_usec(ri->nd_opt_pi_valid_time, /* max_as_infinity = */ true);
445 return 0;
446 }
447
448 int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint64_t *ret) {
449 struct nd_opt_prefix_info *pi;
450 int r;
451
452 assert_return(rt, -EINVAL);
453 assert_return(ret, -EINVAL);
454
455 r = get_prefix_info(rt, &pi);
456 if (r < 0)
457 return r;
458
459 *ret = be32_sec_to_usec(pi->nd_opt_pi_preferred_time, /* max_as_infinity = */ true);
460 return 0;
461 }
462
463 int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret) {
464 struct nd_opt_prefix_info *pi;
465 uint8_t flags;
466 int r;
467
468 assert_return(rt, -EINVAL);
469 assert_return(ret, -EINVAL);
470
471 r = get_prefix_info(rt, &pi);
472 if (r < 0)
473 return r;
474
475 flags = pi->nd_opt_pi_flags_reserved;
476
477 if ((flags & ND_OPT_PI_FLAG_AUTO) && (pi->nd_opt_pi_prefix_len != 64)) {
478 log_ndisc(NULL, "Invalid prefix length, ignoring prefix for stateless autoconfiguration.");
479 flags &= ~ND_OPT_PI_FLAG_AUTO;
480 }
481
482 *ret = flags;
483 return 0;
484 }
485
486 int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret) {
487 struct nd_opt_prefix_info *pi;
488 int r;
489
490 assert_return(rt, -EINVAL);
491 assert_return(ret, -EINVAL);
492
493 r = get_prefix_info(rt, &pi);
494 if (r < 0)
495 return r;
496
497 *ret = pi->nd_opt_pi_prefix;
498 return 0;
499 }
500
501 int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *ret) {
502 struct nd_opt_prefix_info *pi;
503 int r;
504
505 assert_return(rt, -EINVAL);
506 assert_return(ret, -EINVAL);
507
508 r = get_prefix_info(rt, &pi);
509 if (r < 0)
510 return r;
511
512 if (pi->nd_opt_pi_prefix_len > 128)
513 return -EBADMSG;
514
515 *ret = pi->nd_opt_pi_prefix_len;
516 return 0;
517 }
518
519 static int get_route_info(sd_ndisc_router *rt, uint8_t **ret) {
520 uint8_t *ri;
521 size_t length;
522 int r;
523
524 assert(rt);
525 assert(ret);
526
527 r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_ROUTE_INFORMATION);
528 if (r < 0)
529 return r;
530 if (r == 0)
531 return -EMEDIUMTYPE;
532
533 length = NDISC_ROUTER_OPTION_LENGTH(rt);
534 if (length < 1*8 || length > 3*8)
535 return -EBADMSG;
536
537 ri = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
538
539 if (ri[2] > 128)
540 return -EBADMSG;
541
542 *ret = ri;
543 return 0;
544 }
545
546 int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint64_t *ret) {
547 uint8_t *ri;
548 int r;
549
550 assert_return(rt, -EINVAL);
551 assert_return(ret, -EINVAL);
552
553 r = get_route_info(rt, &ri);
554 if (r < 0)
555 return r;
556
557 *ret = unaligned_be32_sec_to_usec(ri + 4, /* max_as_infinity = */ true);
558 return 0;
559 }
560
561 int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret) {
562 uint8_t *ri;
563 int r;
564
565 assert_return(rt, -EINVAL);
566 assert_return(ret, -EINVAL);
567
568 r = get_route_info(rt, &ri);
569 if (r < 0)
570 return r;
571
572 zero(*ret);
573 memcpy(ret, ri + 8, NDISC_ROUTER_OPTION_LENGTH(rt) - 8);
574
575 return 0;
576 }
577
578 int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *ret) {
579 uint8_t *ri;
580 int r;
581
582 assert_return(rt, -EINVAL);
583 assert_return(ret, -EINVAL);
584
585 r = get_route_info(rt, &ri);
586 if (r < 0)
587 return r;
588
589 *ret = ri[2];
590 return 0;
591 }
592
593 int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret) {
594 uint8_t *ri;
595 int r;
596
597 assert_return(rt, -EINVAL);
598 assert_return(ret, -EINVAL);
599
600 r = get_route_info(rt, &ri);
601 if (r < 0)
602 return r;
603
604 if (!IN_SET((ri[3] >> 3) & 3, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_MEDIUM, SD_NDISC_PREFERENCE_HIGH))
605 return -EOPNOTSUPP;
606
607 *ret = (ri[3] >> 3) & 3;
608 return 0;
609 }
610
611 static int get_rdnss_info(sd_ndisc_router *rt, uint8_t **ret) {
612 size_t length;
613 int r;
614
615 assert(rt);
616 assert(ret);
617
618 r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_RDNSS);
619 if (r < 0)
620 return r;
621 if (r == 0)
622 return -EMEDIUMTYPE;
623
624 length = NDISC_ROUTER_OPTION_LENGTH(rt);
625 if (length < 3*8 || (length % (2*8)) != 1*8)
626 return -EBADMSG;
627
628 *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
629 return 0;
630 }
631
632 int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret) {
633 uint8_t *ri;
634 int r;
635
636 assert_return(rt, -EINVAL);
637 assert_return(ret, -EINVAL);
638
639 r = get_rdnss_info(rt, &ri);
640 if (r < 0)
641 return r;
642
643 *ret = (const struct in6_addr*) (ri + 8);
644 return (NDISC_ROUTER_OPTION_LENGTH(rt) - 8) / 16;
645 }
646
647 int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint64_t *ret) {
648 uint8_t *ri;
649 int r;
650
651 assert_return(rt, -EINVAL);
652 assert_return(ret, -EINVAL);
653
654 r = get_rdnss_info(rt, &ri);
655 if (r < 0)
656 return r;
657
658 *ret = unaligned_be32_sec_to_usec(ri + 4, /* max_as_infinity = */ true);
659 return 0;
660 }
661
662 static int get_dnssl_info(sd_ndisc_router *rt, uint8_t **ret) {
663 size_t length;
664 int r;
665
666 assert(rt);
667 assert(ret);
668
669 r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_DNSSL);
670 if (r < 0)
671 return r;
672 if (r == 0)
673 return -EMEDIUMTYPE;
674
675 length = NDISC_ROUTER_OPTION_LENGTH(rt);
676 if (length < 2*8)
677 return -EBADMSG;
678
679 *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
680 return 0;
681 }
682
683 int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret) {
684 _cleanup_strv_free_ char **l = NULL;
685 _cleanup_free_ char *e = NULL;
686 size_t n = 0, left;
687 uint8_t *ri, *p;
688 bool first = true;
689 int r;
690 unsigned k = 0;
691
692 assert_return(rt, -EINVAL);
693 assert_return(ret, -EINVAL);
694
695 r = get_dnssl_info(rt, &ri);
696 if (r < 0)
697 return r;
698
699 p = ri + 8;
700 left = NDISC_ROUTER_OPTION_LENGTH(rt) - 8;
701
702 for (;;) {
703 if (left == 0) {
704
705 if (n > 0) /* Not properly NUL terminated */
706 return -EBADMSG;
707
708 break;
709 }
710
711 if (*p == 0) {
712 /* Found NUL termination */
713
714 if (n > 0) {
715 _cleanup_free_ char *normalized = NULL;
716
717 e[n] = 0;
718 r = dns_name_normalize(e, 0, &normalized);
719 if (r < 0)
720 return r;
721
722 /* Ignore the root domain name or "localhost" and friends */
723 if (!is_localhost(normalized) &&
724 !dns_name_is_root(normalized)) {
725
726 if (strv_push(&l, normalized) < 0)
727 return -ENOMEM;
728
729 normalized = NULL;
730 k++;
731 }
732 }
733
734 n = 0;
735 first = true;
736 p++, left--;
737 continue;
738 }
739
740 /* Check for compression (which is not allowed) */
741 if (*p > 63)
742 return -EBADMSG;
743
744 if (1U + *p + 1U > left)
745 return -EBADMSG;
746
747 if (!GREEDY_REALLOC(e, n + !first + DNS_LABEL_ESCAPED_MAX + 1U))
748 return -ENOMEM;
749
750 if (first)
751 first = false;
752 else
753 e[n++] = '.';
754
755 r = dns_label_escape((char*) p+1, *p, e + n, DNS_LABEL_ESCAPED_MAX);
756 if (r < 0)
757 return r;
758
759 n += r;
760
761 left -= 1 + *p;
762 p += 1 + *p;
763 }
764
765 if (strv_isempty(l)) {
766 *ret = NULL;
767 return 0;
768 }
769
770 *ret = TAKE_PTR(l);
771
772 return k;
773 }
774
775 int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint64_t *ret) {
776 uint8_t *ri;
777 int r;
778
779 assert_return(rt, -EINVAL);
780 assert_return(ret, -EINVAL);
781
782 r = get_dnssl_info(rt, &ri);
783 if (r < 0)
784 return r;
785
786 *ret = unaligned_be32_sec_to_usec(ri + 4, /* max_as_infinity = */ true);
787 return 0;
788 }
789
790 int sd_ndisc_router_captive_portal_get_uri(sd_ndisc_router *rt, const char **ret, size_t *ret_size) {
791 int r;
792 const char *nd_opt_captive_portal;
793 size_t length;
794
795 assert_return(rt, -EINVAL);
796 assert_return(ret, -EINVAL);
797 assert_return(ret_size, -EINVAL);
798
799 r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_CAPTIVE_PORTAL);
800 if (r < 0)
801 return r;
802 if (r == 0)
803 return -EMEDIUMTYPE;
804
805 r = sd_ndisc_router_option_get_raw(rt, (void *)&nd_opt_captive_portal, &length);
806 if (r < 0)
807 return r;
808
809 /* The length field has units of 8 octets */
810 assert(length % 8 == 0);
811 if (length == 0)
812 return -EBADMSG;
813
814 /* Check that the message is not truncated by an embedded NUL.
815 * NUL padding to a multiple of 8 is expected. */
816 size_t size = strnlen(nd_opt_captive_portal + 2, length - 2);
817 if (DIV_ROUND_UP(size + 2, 8) != length / 8)
818 return -EBADMSG;
819
820 /* Let's not return an empty buffer */
821 if (size == 0) {
822 *ret = NULL;
823 *ret_size = 0;
824 return 0;
825 }
826
827 *ret = nd_opt_captive_portal + 2;
828 *ret_size = size;
829
830 return 0;
831 }
832
833 static int get_pref64_prefix_info(sd_ndisc_router *rt, struct nd_opt_prefix64_info **ret) {
834 struct nd_opt_prefix64_info *ri;
835 size_t length;
836 int r;
837
838 assert(rt);
839 assert(ret);
840
841 r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_PREF64);
842 if (r < 0)
843 return r;
844 if (r == 0)
845 return -EMEDIUMTYPE;
846
847 length = NDISC_ROUTER_OPTION_LENGTH(rt);
848 if (length != sizeof(struct nd_opt_prefix64_info))
849 return -EBADMSG;
850
851 ri = (struct nd_opt_prefix64_info *) ((uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex);
852 if (!pref64_option_verify(ri, length))
853 return -EBADMSG;
854
855 *ret = ri;
856 return 0;
857 }
858
859 int sd_ndisc_router_prefix64_get_prefix(sd_ndisc_router *rt, struct in6_addr *ret) {
860 struct nd_opt_prefix64_info *pi;
861 struct in6_addr a = {};
862 unsigned prefixlen;
863 int r;
864
865 assert_return(rt, -EINVAL);
866 assert_return(ret, -EINVAL);
867
868 r = get_pref64_prefix_info(rt, &pi);
869 if (r < 0)
870 return r;
871
872 r = sd_ndisc_router_prefix64_get_prefixlen(rt, &prefixlen);
873 if (r < 0)
874 return r;
875
876 memcpy(&a, pi->prefix, sizeof(pi->prefix));
877 in6_addr_mask(&a, prefixlen);
878 /* extra safety check for refusing malformed prefix. */
879 if (memcmp(&a, pi->prefix, sizeof(pi->prefix)) != 0)
880 return -EBADMSG;
881
882 *ret = a;
883 return 0;
884 }
885
886 int sd_ndisc_router_prefix64_get_prefixlen(sd_ndisc_router *rt, unsigned *ret) {
887 struct nd_opt_prefix64_info *pi;
888 uint16_t lifetime_prefix_len;
889 uint8_t prefix_len;
890 int r;
891
892 assert_return(rt, -EINVAL);
893 assert_return(ret, -EINVAL);
894
895 r = get_pref64_prefix_info(rt, &pi);
896 if (r < 0)
897 return r;
898
899 lifetime_prefix_len = be16toh(pi->lifetime_and_plc);
900 pref64_plc_to_prefix_length(lifetime_prefix_len, &prefix_len);
901
902 *ret = prefix_len;
903 return 0;
904 }
905
906 int sd_ndisc_router_prefix64_get_lifetime(sd_ndisc_router *rt, uint64_t *ret) {
907 struct nd_opt_prefix64_info *pi;
908 uint16_t lifetime_prefix_len;
909 int r;
910
911 assert_return(rt, -EINVAL);
912 assert_return(ret, -EINVAL);
913
914 r = get_pref64_prefix_info(rt, &pi);
915 if (r < 0)
916 return r;
917
918 lifetime_prefix_len = be16toh(pi->lifetime_and_plc);
919
920 *ret = (lifetime_prefix_len & PREF64_SCALED_LIFETIME_MASK) * USEC_PER_SEC;
921 return 0;
922 }