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