]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/ndisc-router.c
3cb71dbdac9a3c07d0d5a900aba7e04acdf56e47
[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-router.h"
17 #include "strv.h"
18
19 DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_ndisc_router, sd_ndisc_router, mfree);
20
21 sd_ndisc_router *ndisc_router_new(size_t raw_size) {
22 sd_ndisc_router *rt;
23
24 rt = malloc0(ALIGN(sizeof(sd_ndisc_router)) + raw_size);
25 if (!rt)
26 return NULL;
27
28 rt->raw_size = raw_size;
29 rt->n_ref = 1;
30
31 return rt;
32 }
33
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;
36 int r;
37
38 assert_return(ret, -EINVAL);
39 assert_return(raw || raw_size <= 0, -EINVAL);
40
41 rt = ndisc_router_new(raw_size);
42 if (!rt)
43 return -ENOMEM;
44
45 memcpy(NDISC_ROUTER_RAW(rt), raw, raw_size);
46 r = ndisc_router_parse(rt);
47 if (r < 0)
48 return r;
49
50 *ret = TAKE_PTR(rt);
51
52 return r;
53 }
54
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);
58
59 if (IN6_IS_ADDR_UNSPECIFIED(&rt->address))
60 return -ENODATA;
61
62 *ret_addr = rt->address;
63 return 0;
64 }
65
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);
71
72 if (!triple_timestamp_is_set(&rt->timestamp))
73 return -ENODATA;
74
75 *ret = triple_timestamp_by_clock(&rt->timestamp, clock);
76 return 0;
77 }
78
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);
83
84 *ret = NDISC_ROUTER_RAW(rt);
85 *size = rt->raw_size;
86
87 return 0;
88 }
89
90 int ndisc_router_parse(sd_ndisc_router *rt) {
91 struct nd_router_advert *a;
92 const uint8_t *p;
93 bool has_mtu = false, has_flag_extension = false;
94 size_t left;
95
96 assert(rt);
97
98 if (rt->raw_size < sizeof(struct nd_router_advert)) {
99 log_ndisc("Too small to be a router advertisement, ignoring.");
100 return -EBADMSG;
101 }
102
103 /* Router advertisement packets are neatly aligned to 64bit boundaries, hence we can access them directly */
104 a = NDISC_ROUTER_RAW(rt);
105
106 if (a->nd_ra_type != ND_ROUTER_ADVERT) {
107 log_ndisc("Received ND packet that is not a router advertisement, ignoring.");
108 return -EBADMSG;
109 }
110
111 if (a->nd_ra_code != 0) {
112 log_ndisc("Received ND packet with wrong RA code, ignoring.");
113 return -EBADMSG;
114 }
115
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);
119
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;
123
124 p = (const uint8_t*) NDISC_ROUTER_RAW(rt) + sizeof(struct nd_router_advert);
125 left = rt->raw_size - sizeof(struct nd_router_advert);
126
127 for (;;) {
128 uint8_t type;
129 size_t length;
130
131 if (left == 0)
132 break;
133
134 if (left < 2) {
135 log_ndisc("Option lacks header, ignoring datagram.");
136 return -EBADMSG;
137 }
138
139 type = p[0];
140 length = p[1] * 8;
141
142 if (length == 0) {
143 log_ndisc("Zero-length option, ignoring datagram.");
144 return -EBADMSG;
145 }
146 if (left < length) {
147 log_ndisc("Option truncated, ignoring datagram.");
148 return -EBADMSG;
149 }
150
151 switch (type) {
152
153 case SD_NDISC_OPTION_PREFIX_INFORMATION:
154
155 if (length != 4*8) {
156 log_ndisc("Prefix option of invalid size, ignoring datagram.");
157 return -EBADMSG;
158 }
159
160 if (p[2] > 128) {
161 log_ndisc("Bad prefix length, ignoring datagram.");
162 return -EBADMSG;
163 }
164
165 break;
166
167 case SD_NDISC_OPTION_MTU: {
168 uint32_t m;
169
170 if (has_mtu) {
171 log_ndisc("MTU option specified twice, ignoring.");
172 break;
173 }
174
175 if (length != 8) {
176 log_ndisc("MTU option of invalid size, ignoring datagram.");
177 return -EBADMSG;
178 }
179
180 m = be32toh(*(uint32_t*) (p + 4));
181 if (m >= IPV6_MIN_MTU) /* ignore invalidly small MTUs */
182 rt->mtu = m;
183
184 has_mtu = true;
185 break;
186 }
187
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.");
191 return -EBADMSG;
192 }
193
194 if (p[2] > 128) {
195 log_ndisc("Bad route prefix length, ignoring datagram.");
196 return -EBADMSG;
197 }
198
199 break;
200
201 case SD_NDISC_OPTION_RDNSS:
202 if (length < 3*8 || (length % (2*8)) != 1*8) {
203 log_ndisc("RDNSS option has invalid size.");
204 return -EBADMSG;
205 }
206
207 break;
208
209 case SD_NDISC_OPTION_FLAGS_EXTENSION:
210
211 if (has_flag_extension) {
212 log_ndisc("Flags extension option specified twice, ignoring.");
213 break;
214 }
215
216 if (length < 1*8) {
217 log_ndisc("Flags extension option has invalid size.");
218 return -EBADMSG;
219 }
220
221 /* Add in the additional flags bits */
222 rt->flags |=
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);
229
230 has_flag_extension = true;
231 break;
232
233 case SD_NDISC_OPTION_DNSSL:
234 if (length < 2*8) {
235 log_ndisc("DNSSL option has invalid size.");
236 return -EBADMSG;
237 }
238
239 break;
240 }
241
242 p += length, left -= length;
243 }
244
245 rt->rindex = sizeof(struct nd_router_advert);
246 return 0;
247 }
248
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);
252
253 *ret = rt->hop_limit;
254 return 0;
255 }
256
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);
260
261 *ret_flags = rt->flags;
262 return 0;
263 }
264
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);
268
269 *ret_lifetime = rt->lifetime;
270 return 0;
271 }
272
273 _public_ int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret) {
274 assert_return(rt, -EINVAL);
275 assert_return(ret, -EINVAL);
276
277 *ret = rt->preference;
278 return 0;
279 }
280
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);
284
285 if (rt->mtu <= 0)
286 return -ENODATA;
287
288 *ret = rt->mtu;
289 return 0;
290 }
291
292 _public_ int sd_ndisc_router_option_rewind(sd_ndisc_router *rt) {
293 assert_return(rt, -EINVAL);
294
295 assert(rt->raw_size >= sizeof(struct nd_router_advert));
296 rt->rindex = sizeof(struct nd_router_advert);
297
298 return rt->rindex < rt->raw_size;
299 }
300
301 _public_ int sd_ndisc_router_option_next(sd_ndisc_router *rt) {
302 size_t length;
303
304 assert_return(rt, -EINVAL);
305
306 if (rt->rindex == rt->raw_size) /* EOF */
307 return -ESPIPE;
308
309 if (rt->rindex + 2 > rt->raw_size) /* Truncated message */
310 return -EBADMSG;
311
312 length = NDISC_ROUTER_OPTION_LENGTH(rt);
313 if (rt->rindex + length > rt->raw_size)
314 return -EBADMSG;
315
316 rt->rindex += length;
317 return rt->rindex < rt->raw_size;
318 }
319
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);
323
324 if (rt->rindex == rt->raw_size) /* EOF */
325 return -ESPIPE;
326
327 if (rt->rindex + 2 > rt->raw_size) /* Truncated message */
328 return -EBADMSG;
329
330 *ret = NDISC_ROUTER_OPTION_TYPE(rt);
331 return 0;
332 }
333
334 _public_ int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type) {
335 uint8_t k;
336 int r;
337
338 assert_return(rt, -EINVAL);
339
340 r = sd_ndisc_router_option_get_type(rt, &k);
341 if (r < 0)
342 return r;
343
344 return type == k;
345 }
346
347 _public_ int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size) {
348 size_t length;
349
350 assert_return(rt, -EINVAL);
351 assert_return(ret, -EINVAL);
352 assert_return(size, -EINVAL);
353
354 /* Note that this returns the full option, including the option header */
355
356 if (rt->rindex + 2 > rt->raw_size)
357 return -EBADMSG;
358
359 length = NDISC_ROUTER_OPTION_LENGTH(rt);
360 if (rt->rindex + length > rt->raw_size)
361 return -EBADMSG;
362
363 *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
364 *size = length;
365
366 return 0;
367 }
368
369 static int get_prefix_info(sd_ndisc_router *rt, struct nd_opt_prefix_info **ret) {
370 struct nd_opt_prefix_info *ri;
371 size_t length;
372 int r;
373
374 assert(rt);
375 assert(ret);
376
377 r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_PREFIX_INFORMATION);
378 if (r < 0)
379 return r;
380 if (r == 0)
381 return -EMEDIUMTYPE;
382
383 length = NDISC_ROUTER_OPTION_LENGTH(rt);
384 if (length != sizeof(struct nd_opt_prefix_info))
385 return -EBADMSG;
386
387 ri = (struct nd_opt_prefix_info*) ((uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex);
388 if (ri->nd_opt_pi_prefix_len > 128)
389 return -EBADMSG;
390
391 *ret = ri;
392 return 0;
393 }
394
395 _public_ int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
396 struct nd_opt_prefix_info *ri;
397 int r;
398
399 assert_return(rt, -EINVAL);
400 assert_return(ret, -EINVAL);
401
402 r = get_prefix_info(rt, &ri);
403 if (r < 0)
404 return r;
405
406 *ret = be32toh(ri->nd_opt_pi_valid_time);
407 return 0;
408 }
409
410 _public_ int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
411 struct nd_opt_prefix_info *pi;
412 int r;
413
414 assert_return(rt, -EINVAL);
415 assert_return(ret, -EINVAL);
416
417 r = get_prefix_info(rt, &pi);
418 if (r < 0)
419 return r;
420
421 *ret = be32toh(pi->nd_opt_pi_preferred_time);
422 return 0;
423 }
424
425 _public_ int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret) {
426 struct nd_opt_prefix_info *pi;
427 uint8_t flags;
428 int r;
429
430 assert_return(rt, -EINVAL);
431 assert_return(ret, -EINVAL);
432
433 r = get_prefix_info(rt, &pi);
434 if (r < 0)
435 return r;
436
437 flags = pi->nd_opt_pi_flags_reserved;
438
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;
442 }
443
444 *ret = flags;
445 return 0;
446 }
447
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;
450 int r;
451
452 assert_return(rt, -EINVAL);
453 assert_return(ret_addr, -EINVAL);
454
455 r = get_prefix_info(rt, &pi);
456 if (r < 0)
457 return r;
458
459 *ret_addr = pi->nd_opt_pi_prefix;
460 return 0;
461 }
462
463 _public_ int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *ret) {
464 struct nd_opt_prefix_info *pi;
465 int r;
466
467 assert_return(rt, -EINVAL);
468 assert_return(ret, -EINVAL);
469
470 r = get_prefix_info(rt, &pi);
471 if (r < 0)
472 return r;
473
474 if (pi->nd_opt_pi_prefix_len > 128)
475 return -EBADMSG;
476
477 *ret = pi->nd_opt_pi_prefix_len;
478 return 0;
479 }
480
481 static int get_route_info(sd_ndisc_router *rt, uint8_t **ret) {
482 uint8_t *ri;
483 size_t length;
484 int r;
485
486 assert(rt);
487 assert(ret);
488
489 r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_ROUTE_INFORMATION);
490 if (r < 0)
491 return r;
492 if (r == 0)
493 return -EMEDIUMTYPE;
494
495 length = NDISC_ROUTER_OPTION_LENGTH(rt);
496 if (length < 1*8 || length > 3*8)
497 return -EBADMSG;
498
499 ri = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
500
501 if (ri[2] > 128)
502 return -EBADMSG;
503
504 *ret = ri;
505 return 0;
506 }
507
508 _public_ int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
509 uint8_t *ri;
510 int r;
511
512 assert_return(rt, -EINVAL);
513 assert_return(ret, -EINVAL);
514
515 r = get_route_info(rt, &ri);
516 if (r < 0)
517 return r;
518
519 *ret = be32toh(*(uint32_t*) (ri + 4));
520 return 0;
521 }
522
523 _public_ int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr) {
524 uint8_t *ri;
525 int r;
526
527 assert_return(rt, -EINVAL);
528 assert_return(ret_addr, -EINVAL);
529
530 r = get_route_info(rt, &ri);
531 if (r < 0)
532 return r;
533
534 zero(*ret_addr);
535 memcpy(ret_addr, ri + 8, NDISC_ROUTER_OPTION_LENGTH(rt) - 8);
536
537 return 0;
538 }
539
540 _public_ int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *ret) {
541 uint8_t *ri;
542 int r;
543
544 assert_return(rt, -EINVAL);
545 assert_return(ret, -EINVAL);
546
547 r = get_route_info(rt, &ri);
548 if (r < 0)
549 return r;
550
551 *ret = ri[2];
552 return 0;
553 }
554
555 _public_ int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret) {
556 uint8_t *ri;
557 int r;
558
559 assert_return(rt, -EINVAL);
560 assert_return(ret, -EINVAL);
561
562 r = get_route_info(rt, &ri);
563 if (r < 0)
564 return r;
565
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;
569
570 return 0;
571 }
572
573 static int get_rdnss_info(sd_ndisc_router *rt, uint8_t **ret) {
574 size_t length;
575 int r;
576
577 assert(rt);
578 assert(ret);
579
580 r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_RDNSS);
581 if (r < 0)
582 return r;
583 if (r == 0)
584 return -EMEDIUMTYPE;
585
586 length = NDISC_ROUTER_OPTION_LENGTH(rt);
587 if (length < 3*8 || (length % (2*8)) != 1*8)
588 return -EBADMSG;
589
590 *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
591 return 0;
592 }
593
594 _public_ int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret) {
595 uint8_t *ri;
596 int r;
597
598 assert_return(rt, -EINVAL);
599 assert_return(ret, -EINVAL);
600
601 r = get_rdnss_info(rt, &ri);
602 if (r < 0)
603 return r;
604
605 *ret = (const struct in6_addr*) (ri + 8);
606 return (NDISC_ROUTER_OPTION_LENGTH(rt) - 8) / 16;
607 }
608
609 _public_ int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
610 uint8_t *ri;
611 int r;
612
613 assert_return(rt, -EINVAL);
614 assert_return(ret, -EINVAL);
615
616 r = get_rdnss_info(rt, &ri);
617 if (r < 0)
618 return r;
619
620 *ret = be32toh(*(uint32_t*) (ri + 4));
621 return 0;
622 }
623
624 static int get_dnssl_info(sd_ndisc_router *rt, uint8_t **ret) {
625 size_t length;
626 int r;
627
628 assert(rt);
629 assert(ret);
630
631 r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_DNSSL);
632 if (r < 0)
633 return r;
634 if (r == 0)
635 return -EMEDIUMTYPE;
636
637 length = NDISC_ROUTER_OPTION_LENGTH(rt);
638 if (length < 2*8)
639 return -EBADMSG;
640
641 *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
642 return 0;
643 }
644
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;
649 uint8_t *ri, *p;
650 bool first = true;
651 int r;
652 unsigned k = 0;
653
654 assert_return(rt, -EINVAL);
655 assert_return(ret, -EINVAL);
656
657 r = get_dnssl_info(rt, &ri);
658 if (r < 0)
659 return r;
660
661 p = ri + 8;
662 left = NDISC_ROUTER_OPTION_LENGTH(rt) - 8;
663
664 for (;;) {
665 if (left == 0) {
666
667 if (n > 0) /* Not properly NUL terminated */
668 return -EBADMSG;
669
670 break;
671 }
672
673 if (*p == 0) {
674 /* Found NUL termination */
675
676 if (n > 0) {
677 _cleanup_free_ char *normalized = NULL;
678
679 e[n] = 0;
680 r = dns_name_normalize(e, 0, &normalized);
681 if (r < 0)
682 return r;
683
684 /* Ignore the root domain name or "localhost" and friends */
685 if (!is_localhost(normalized) &&
686 !dns_name_is_root(normalized)) {
687
688 if (strv_push(&l, normalized) < 0)
689 return -ENOMEM;
690
691 normalized = NULL;
692 k++;
693 }
694 }
695
696 n = 0;
697 first = true;
698 p++, left--;
699 continue;
700 }
701
702 /* Check for compression (which is not allowed) */
703 if (*p > 63)
704 return -EBADMSG;
705
706 if (1U + *p + 1U > left)
707 return -EBADMSG;
708
709 if (!GREEDY_REALLOC(e, allocated, n + !first + DNS_LABEL_ESCAPED_MAX + 1U))
710 return -ENOMEM;
711
712 if (first)
713 first = false;
714 else
715 e[n++] = '.';
716
717 r = dns_label_escape((char*) p+1, *p, e + n, DNS_LABEL_ESCAPED_MAX);
718 if (r < 0)
719 return r;
720
721 n += r;
722
723 left -= 1 + *p;
724 p += 1 + *p;
725 }
726
727 if (strv_isempty(l)) {
728 *ret = NULL;
729 return 0;
730 }
731
732 *ret = TAKE_PTR(l);
733
734 return k;
735 }
736
737 _public_ int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint32_t *ret_sec) {
738 uint8_t *ri;
739 int r;
740
741 assert_return(rt, -EINVAL);
742 assert_return(ret_sec, -EINVAL);
743
744 r = get_dnssl_info(rt, &ri);
745 if (r < 0)
746 return r;
747
748 *ret_sec = be32toh(*(uint32_t*) (ri + 4));
749 return 0;
750 }