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