]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/ndisc-router.c
sd-ndisc: drop unused function
[thirdparty/systemd.git] / src / libsystemd-network / ndisc-router.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
1e7a0e21 2/***
810adae9 3 Copyright © 2014 Intel Corporation. All rights reserved.
1e7a0e21
LP
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"
0a970718 13#include "memory-util.h"
f5947a5e 14#include "missing_network.h"
1e7a0e21
LP
15#include "ndisc-internal.h"
16#include "ndisc-router.h"
17#include "strv.h"
18
8301aa0b 19DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_ndisc_router, sd_ndisc_router, mfree);
1e7a0e21
LP
20
21sd_ndisc_router *ndisc_router_new(size_t raw_size) {
22 sd_ndisc_router *rt;
23
4e88a46b
YW
24 if (raw_size > SIZE_MAX - ALIGN(sizeof(sd_ndisc_router)))
25 return NULL;
26
1e7a0e21
LP
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
17347053 37int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr) {
1e7a0e21
LP
38 assert_return(rt, -EINVAL);
39 assert_return(ret_addr, -EINVAL);
40
94876904 41 if (in6_addr_is_null(&rt->address))
1e7a0e21
LP
42 return -ENODATA;
43
44 *ret_addr = rt->address;
45 return 0;
46}
47
17347053 48int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret) {
1e7a0e21
LP
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
17347053 61int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size) {
1e7a0e21
LP
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
35388783 72int ndisc_router_parse(sd_ndisc *nd, sd_ndisc_router *rt) {
1e7a0e21
LP
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
35388783
YW
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.");
1e7a0e21
LP
83
84 /* Router advertisement packets are neatly aligned to 64bit boundaries, hence we can access them directly */
85 a = NDISC_ROUTER_RAW(rt);
86
35388783
YW
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.");
1e7a0e21 90
35388783
YW
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.");
1e7a0e21
LP
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
35388783
YW
113 if (left < 2)
114 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
115 "Option lacks header, ignoring datagram.");
1e7a0e21
LP
116
117 type = p[0];
118 length = p[1] * 8;
119
35388783
YW
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.");
1e7a0e21
LP
126
127 switch (type) {
128
129 case SD_NDISC_OPTION_PREFIX_INFORMATION:
130
35388783
YW
131 if (length != 4*8)
132 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
133 "Prefix option of invalid size, ignoring datagram.");
1e7a0e21 134
35388783
YW
135 if (p[2] > 128)
136 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
137 "Bad prefix length, ignoring datagram.");
1e7a0e21
LP
138
139 break;
140
141 case SD_NDISC_OPTION_MTU: {
142 uint32_t m;
143
144 if (has_mtu) {
35388783 145 log_ndisc(nd, "MTU option specified twice, ignoring.");
f3241c61 146 break;
1e7a0e21
LP
147 }
148
35388783
YW
149 if (length != 8)
150 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
151 "MTU option of invalid size, ignoring datagram.");
1e7a0e21
LP
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:
35388783
YW
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.");
1e7a0e21 165
35388783
YW
166 if (p[2] > 128)
167 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
168 "Bad route prefix length, ignoring datagram.");
1e7a0e21
LP
169
170 break;
171
172 case SD_NDISC_OPTION_RDNSS:
35388783
YW
173 if (length < 3*8 || (length % (2*8)) != 1*8)
174 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG), "RDNSS option has invalid size.");
1e7a0e21
LP
175
176 break;
177
178 case SD_NDISC_OPTION_FLAGS_EXTENSION:
179
180 if (has_flag_extension) {
35388783 181 log_ndisc(nd, "Flags extension option specified twice, ignoring.");
f3241c61 182 break;
1e7a0e21
LP
183 }
184
35388783
YW
185 if (length < 1*8)
186 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
187 "Flags extension option has invalid size.");
1e7a0e21
LP
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:
35388783
YW
202 if (length < 2*8)
203 return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
204 "DNSSL option has invalid size.");
1e7a0e21
LP
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
17347053 216int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret) {
1e7a0e21
LP
217 assert_return(rt, -EINVAL);
218 assert_return(ret, -EINVAL);
219
220 *ret = rt->hop_limit;
221 return 0;
222}
223
17347053 224int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret_flags) {
1e7a0e21
LP
225 assert_return(rt, -EINVAL);
226 assert_return(ret_flags, -EINVAL);
227
228 *ret_flags = rt->flags;
229 return 0;
230}
231
17347053 232int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint16_t *ret_lifetime) {
1e7a0e21
LP
233 assert_return(rt, -EINVAL);
234 assert_return(ret_lifetime, -EINVAL);
235
236 *ret_lifetime = rt->lifetime;
237 return 0;
238}
239
17347053 240int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret) {
1e7a0e21
LP
241 assert_return(rt, -EINVAL);
242 assert_return(ret, -EINVAL);
243
244 *ret = rt->preference;
245 return 0;
246}
247
17347053 248int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret) {
1e7a0e21
LP
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
17347053 259int sd_ndisc_router_option_rewind(sd_ndisc_router *rt) {
1e7a0e21
LP
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
17347053 268int sd_ndisc_router_option_next(sd_ndisc_router *rt) {
1e7a0e21
LP
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
17347053 287int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret) {
1e7a0e21
LP
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
17347053 301int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type) {
1e7a0e21
LP
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
17347053 314int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size) {
1e7a0e21
LP
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
336static 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
17347053 362int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
1e7a0e21
LP
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
17347053 377int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
1e7a0e21
LP
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
17347053 392int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret) {
1e7a0e21 393 struct nd_opt_prefix_info *pi;
9f702d00 394 uint8_t flags;
1e7a0e21
LP
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
9f702d00
JT
404 flags = pi->nd_opt_pi_flags_reserved;
405
406 if ((flags & ND_OPT_PI_FLAG_AUTO) && (pi->nd_opt_pi_prefix_len != 64)) {
35388783 407 log_ndisc(NULL, "Invalid prefix length, ignoring prefix for stateless autoconfiguration.");
9f702d00
JT
408 flags &= ~ND_OPT_PI_FLAG_AUTO;
409 }
410
411 *ret = flags;
1e7a0e21
LP
412 return 0;
413}
414
17347053 415int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr) {
1e7a0e21
LP
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
17347053 430int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *ret) {
1e7a0e21
LP
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
448static 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
17347053 475int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
1e7a0e21
LP
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
17347053 490int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr) {
1e7a0e21
LP
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
17347053 507int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *ret) {
1e7a0e21
LP
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
17347053 522int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret) {
1e7a0e21
LP
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
540static 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
17347053 561int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret) {
1e7a0e21
LP
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
17347053 576int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
1e7a0e21
LP
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
591static 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
17347053 612int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret) {
1e7a0e21
LP
613 _cleanup_strv_free_ char **l = NULL;
614 _cleanup_free_ char *e = NULL;
319a4f4b 615 size_t n = 0, left;
1e7a0e21
LP
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;
7470cc4c 647 r = dns_name_normalize(e, 0, &normalized);
1e7a0e21
LP
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
319a4f4b 676 if (!GREEDY_REALLOC(e, n + !first + DNS_LABEL_ESCAPED_MAX + 1U))
1e7a0e21
LP
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
1cc6c93a 699 *ret = TAKE_PTR(l);
1e7a0e21
LP
700
701 return k;
702}
703
17347053 704int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint32_t *ret_sec) {
1e7a0e21
LP
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}