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