Branch data 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 [ - + - + : 20 : DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_ndisc_router, sd_ndisc_router, mfree);
- + ]
20 : :
21 : 20 : sd_ndisc_router *ndisc_router_new(size_t raw_size) {
22 : : sd_ndisc_router *rt;
23 : :
24 : 20 : rt = malloc0(ALIGN(sizeof(sd_ndisc_router)) + raw_size);
25 [ - + ]: 20 : if (!rt)
26 : 0 : return NULL;
27 : :
28 : 20 : rt->raw_size = raw_size;
29 : 20 : rt->n_ref = 1;
30 : :
31 : 20 : 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 : 20 : _public_ int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr) {
56 [ - + - + ]: 20 : assert_return(rt, -EINVAL);
57 [ - + - + ]: 20 : assert_return(ret_addr, -EINVAL);
58 : :
59 [ + - + - : 20 : if (IN6_IS_ADDR_UNSPECIFIED(&rt->address))
+ - + - +
- ]
60 : 20 : return -ENODATA;
61 : :
62 : 0 : *ret_addr = rt->address;
63 : 0 : return 0;
64 : : }
65 : :
66 : 40 : _public_ int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret) {
67 [ - + - + ]: 40 : assert_return(rt, -EINVAL);
68 [ + - - + : 40 : assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP);
- + ]
69 [ - + - + ]: 40 : assert_return(clock_supported(clock), -EOPNOTSUPP);
70 [ - + - + ]: 40 : assert_return(ret, -EINVAL);
71 : :
72 [ - + ]: 40 : if (!triple_timestamp_is_set(&rt->timestamp))
73 : 0 : return -ENODATA;
74 : :
75 : 40 : *ret = triple_timestamp_by_clock(&rt->timestamp, clock);
76 : 40 : 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 : 20 : int ndisc_router_parse(sd_ndisc_router *rt) {
91 : : struct nd_router_advert *a;
92 : : const uint8_t *p;
93 : 20 : bool has_mtu = false, has_flag_extension = false;
94 : : size_t left;
95 : :
96 [ - + ]: 20 : assert(rt);
97 : :
98 [ - + ]: 20 : 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 : 20 : a = NDISC_ROUTER_RAW(rt);
105 : :
106 [ - + ]: 20 : 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 [ - + ]: 20 : 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 : 20 : rt->hop_limit = a->nd_ra_curhoplimit;
117 : 20 : rt->flags = a->nd_ra_flags_reserved; /* the first 8bit */
118 : 20 : rt->lifetime = be16toh(a->nd_ra_router_lifetime);
119 : :
120 : 20 : rt->preference = (rt->flags >> 3) & 3;
121 [ - + + - ]: 20 : if (!IN_SET(rt->preference, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_HIGH))
122 : 20 : rt->preference = SD_NDISC_PREFERENCE_MEDIUM;
123 : :
124 : 20 : p = (const uint8_t*) NDISC_ROUTER_RAW(rt) + sizeof(struct nd_router_advert);
125 : 20 : left = rt->raw_size - sizeof(struct nd_router_advert);
126 : :
127 : 80 : for (;;) {
128 : : uint8_t type;
129 : : size_t length;
130 : :
131 [ + + ]: 100 : if (left == 0)
132 : 20 : break;
133 : :
134 [ - + ]: 80 : if (left < 2) {
135 : 0 : log_ndisc("Option lacks header, ignoring datagram.");
136 : 0 : return -EBADMSG;
137 : : }
138 : :
139 : 80 : type = p[0];
140 : 80 : length = p[1] * 8;
141 : :
142 [ - + ]: 80 : if (length == 0) {
143 : 0 : log_ndisc("Zero-length option, ignoring datagram.");
144 : 0 : return -EBADMSG;
145 : : }
146 [ - + ]: 80 : if (left < length) {
147 : 0 : log_ndisc("Option truncated, ignoring datagram.");
148 : 0 : return -EBADMSG;
149 : : }
150 : :
151 [ + - - + : 80 : switch (type) {
- + + ]
152 : :
153 : 20 : case SD_NDISC_OPTION_PREFIX_INFORMATION:
154 : :
155 [ - + ]: 20 : if (length != 4*8) {
156 : 0 : log_ndisc("Prefix option of invalid size, ignoring datagram.");
157 : 0 : return -EBADMSG;
158 : : }
159 : :
160 [ - + ]: 20 : if (p[2] > 128) {
161 : 0 : log_ndisc("Bad prefix length, ignoring datagram.");
162 : 0 : return -EBADMSG;
163 : : }
164 : :
165 : 20 : 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 : 20 : case SD_NDISC_OPTION_RDNSS:
202 [ + - - + ]: 20 : 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 : 20 : 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 : 20 : case SD_NDISC_OPTION_DNSSL:
234 [ - + ]: 20 : if (length < 2*8) {
235 : 0 : log_ndisc("DNSSL option has invalid size.");
236 : 0 : return -EBADMSG;
237 : : }
238 : :
239 : 20 : break;
240 : : }
241 : :
242 : 80 : p += length, left -= length;
243 : : }
244 : :
245 : 20 : rt->rindex = sizeof(struct nd_router_advert);
246 : 20 : return 0;
247 : : }
248 : :
249 : 20 : _public_ int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret) {
250 [ - + - + ]: 20 : assert_return(rt, -EINVAL);
251 [ - + - + ]: 20 : assert_return(ret, -EINVAL);
252 : :
253 : 20 : *ret = rt->hop_limit;
254 : 20 : return 0;
255 : : }
256 : :
257 : 40 : _public_ int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret_flags) {
258 [ - + - + ]: 40 : assert_return(rt, -EINVAL);
259 [ - + - + ]: 40 : assert_return(ret_flags, -EINVAL);
260 : :
261 : 40 : *ret_flags = rt->flags;
262 : 40 : return 0;
263 : : }
264 : :
265 : 20 : _public_ int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint16_t *ret_lifetime) {
266 [ - + - + ]: 20 : assert_return(rt, -EINVAL);
267 [ - + - + ]: 20 : assert_return(ret_lifetime, -EINVAL);
268 : :
269 : 20 : *ret_lifetime = rt->lifetime;
270 : 20 : return 0;
271 : : }
272 : :
273 : 20 : _public_ int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret) {
274 [ - + - + ]: 20 : assert_return(rt, -EINVAL);
275 [ - + - + ]: 20 : assert_return(ret, -EINVAL);
276 : :
277 : 20 : *ret = rt->preference;
278 : 20 : return 0;
279 : : }
280 : :
281 : 20 : _public_ int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret) {
282 [ - + - + ]: 20 : assert_return(rt, -EINVAL);
283 [ - + - + ]: 20 : assert_return(ret, -EINVAL);
284 : :
285 [ + - ]: 20 : if (rt->mtu <= 0)
286 : 20 : return -ENODATA;
287 : :
288 : 0 : *ret = rt->mtu;
289 : 0 : return 0;
290 : : }
291 : :
292 : 20 : _public_ int sd_ndisc_router_option_rewind(sd_ndisc_router *rt) {
293 [ - + - + ]: 20 : assert_return(rt, -EINVAL);
294 : :
295 [ - + ]: 20 : assert(rt->raw_size >= sizeof(struct nd_router_advert));
296 : 20 : rt->rindex = sizeof(struct nd_router_advert);
297 : :
298 : 20 : return rt->rindex < rt->raw_size;
299 : : }
300 : :
301 : 80 : _public_ int sd_ndisc_router_option_next(sd_ndisc_router *rt) {
302 : : size_t length;
303 : :
304 [ - + - + ]: 80 : assert_return(rt, -EINVAL);
305 : :
306 [ - + ]: 80 : if (rt->rindex == rt->raw_size) /* EOF */
307 : 0 : return -ESPIPE;
308 : :
309 [ - + ]: 80 : if (rt->rindex + 2 > rt->raw_size) /* Truncated message */
310 : 0 : return -EBADMSG;
311 : :
312 : 80 : length = NDISC_ROUTER_OPTION_LENGTH(rt);
313 [ - + ]: 80 : if (rt->rindex + length > rt->raw_size)
314 : 0 : return -EBADMSG;
315 : :
316 : 80 : rt->rindex += length;
317 : 80 : return rt->rindex < rt->raw_size;
318 : : }
319 : :
320 : 260 : _public_ int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret) {
321 [ - + - + ]: 260 : assert_return(rt, -EINVAL);
322 [ - + - + ]: 260 : assert_return(ret, -EINVAL);
323 : :
324 [ - + ]: 260 : if (rt->rindex == rt->raw_size) /* EOF */
325 : 0 : return -ESPIPE;
326 : :
327 [ - + ]: 260 : if (rt->rindex + 2 > rt->raw_size) /* Truncated message */
328 : 0 : return -EBADMSG;
329 : :
330 : 260 : *ret = NDISC_ROUTER_OPTION_TYPE(rt);
331 : 260 : return 0;
332 : : }
333 : :
334 : 180 : _public_ int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type) {
335 : : uint8_t k;
336 : : int r;
337 : :
338 [ - + - + ]: 180 : assert_return(rt, -EINVAL);
339 : :
340 : 180 : r = sd_ndisc_router_option_get_type(rt, &k);
341 [ - + ]: 180 : if (r < 0)
342 : 0 : return r;
343 : :
344 : 180 : return type == k;
345 : : }
346 : :
347 : 20 : _public_ int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size) {
348 : : size_t length;
349 : :
350 [ - + - + ]: 20 : assert_return(rt, -EINVAL);
351 [ - + - + ]: 20 : assert_return(ret, -EINVAL);
352 [ - + - + ]: 20 : assert_return(size, -EINVAL);
353 : :
354 : : /* Note that this returns the full option, including the option header */
355 : :
356 [ - + ]: 20 : if (rt->rindex + 2 > rt->raw_size)
357 : 0 : return -EBADMSG;
358 : :
359 : 20 : length = NDISC_ROUTER_OPTION_LENGTH(rt);
360 [ - + ]: 20 : if (rt->rindex + length > rt->raw_size)
361 : 0 : return -EBADMSG;
362 : :
363 : 20 : *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
364 : 20 : *size = length;
365 : :
366 : 20 : return 0;
367 : : }
368 : :
369 : 100 : 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 [ - + ]: 100 : assert(rt);
375 [ - + ]: 100 : assert(ret);
376 : :
377 : 100 : r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_PREFIX_INFORMATION);
378 [ - + ]: 100 : if (r < 0)
379 : 0 : return r;
380 [ - + ]: 100 : if (r == 0)
381 : 0 : return -EMEDIUMTYPE;
382 : :
383 : 100 : length = NDISC_ROUTER_OPTION_LENGTH(rt);
384 [ - + ]: 100 : if (length != sizeof(struct nd_opt_prefix_info))
385 : 0 : return -EBADMSG;
386 : :
387 : 100 : ri = (struct nd_opt_prefix_info*) ((uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex);
388 [ - + ]: 100 : if (ri->nd_opt_pi_prefix_len > 128)
389 : 0 : return -EBADMSG;
390 : :
391 : 100 : *ret = ri;
392 : 100 : return 0;
393 : : }
394 : :
395 : 20 : _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 [ - + - + ]: 20 : assert_return(rt, -EINVAL);
400 [ - + - + ]: 20 : assert_return(ret, -EINVAL);
401 : :
402 : 20 : r = get_prefix_info(rt, &ri);
403 [ - + ]: 20 : if (r < 0)
404 : 0 : return r;
405 : :
406 : 20 : *ret = be32toh(ri->nd_opt_pi_valid_time);
407 : 20 : return 0;
408 : : }
409 : :
410 : 20 : _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 [ - + - + ]: 20 : assert_return(rt, -EINVAL);
415 [ - + - + ]: 20 : assert_return(ret, -EINVAL);
416 : :
417 : 20 : r = get_prefix_info(rt, &pi);
418 [ - + ]: 20 : if (r < 0)
419 : 0 : return r;
420 : :
421 : 20 : *ret = be32toh(pi->nd_opt_pi_preferred_time);
422 : 20 : return 0;
423 : : }
424 : :
425 : 20 : _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 [ - + - + ]: 20 : assert_return(rt, -EINVAL);
431 [ - + - + ]: 20 : assert_return(ret, -EINVAL);
432 : :
433 : 20 : r = get_prefix_info(rt, &pi);
434 [ - + ]: 20 : if (r < 0)
435 : 0 : return r;
436 : :
437 : 20 : flags = pi->nd_opt_pi_flags_reserved;
438 : :
439 [ + - - + ]: 20 : 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 : 20 : *ret = flags;
445 : 20 : return 0;
446 : : }
447 : :
448 : 20 : _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 [ - + - + ]: 20 : assert_return(rt, -EINVAL);
453 [ - + - + ]: 20 : assert_return(ret_addr, -EINVAL);
454 : :
455 : 20 : r = get_prefix_info(rt, &pi);
456 [ - + ]: 20 : if (r < 0)
457 : 0 : return r;
458 : :
459 : 20 : *ret_addr = pi->nd_opt_pi_prefix;
460 : 20 : return 0;
461 : : }
462 : :
463 : 20 : _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 [ - + - + ]: 20 : assert_return(rt, -EINVAL);
468 [ - + - + ]: 20 : assert_return(ret, -EINVAL);
469 : :
470 : 20 : r = get_prefix_info(rt, &pi);
471 [ - + ]: 20 : if (r < 0)
472 : 0 : return r;
473 : :
474 [ - + ]: 20 : if (pi->nd_opt_pi_prefix_len > 128)
475 : 0 : return -EBADMSG;
476 : :
477 : 20 : *ret = pi->nd_opt_pi_prefix_len;
478 : 20 : 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 : 40 : static int get_rdnss_info(sd_ndisc_router *rt, uint8_t **ret) {
574 : : size_t length;
575 : : int r;
576 : :
577 [ - + ]: 40 : assert(rt);
578 [ - + ]: 40 : assert(ret);
579 : :
580 : 40 : r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_RDNSS);
581 [ - + ]: 40 : if (r < 0)
582 : 0 : return r;
583 [ - + ]: 40 : if (r == 0)
584 : 0 : return -EMEDIUMTYPE;
585 : :
586 : 40 : length = NDISC_ROUTER_OPTION_LENGTH(rt);
587 [ + - - + ]: 40 : if (length < 3*8 || (length % (2*8)) != 1*8)
588 : 0 : return -EBADMSG;
589 : :
590 : 40 : *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
591 : 40 : return 0;
592 : : }
593 : :
594 : 20 : _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 [ - + - + ]: 20 : assert_return(rt, -EINVAL);
599 [ - + - + ]: 20 : assert_return(ret, -EINVAL);
600 : :
601 : 20 : r = get_rdnss_info(rt, &ri);
602 [ - + ]: 20 : if (r < 0)
603 : 0 : return r;
604 : :
605 : 20 : *ret = (const struct in6_addr*) (ri + 8);
606 : 20 : return (NDISC_ROUTER_OPTION_LENGTH(rt) - 8) / 16;
607 : : }
608 : :
609 : 20 : _public_ int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint32_t *ret) {
610 : : uint8_t *ri;
611 : : int r;
612 : :
613 [ - + - + ]: 20 : assert_return(rt, -EINVAL);
614 [ - + - + ]: 20 : assert_return(ret, -EINVAL);
615 : :
616 : 20 : r = get_rdnss_info(rt, &ri);
617 [ - + ]: 20 : if (r < 0)
618 : 0 : return r;
619 : :
620 : 20 : *ret = be32toh(*(uint32_t*) (ri + 4));
621 : 20 : return 0;
622 : : }
623 : :
624 : 40 : static int get_dnssl_info(sd_ndisc_router *rt, uint8_t **ret) {
625 : : size_t length;
626 : : int r;
627 : :
628 [ - + ]: 40 : assert(rt);
629 [ - + ]: 40 : assert(ret);
630 : :
631 : 40 : r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_DNSSL);
632 [ - + ]: 40 : if (r < 0)
633 : 0 : return r;
634 [ - + ]: 40 : if (r == 0)
635 : 0 : return -EMEDIUMTYPE;
636 : :
637 : 40 : length = NDISC_ROUTER_OPTION_LENGTH(rt);
638 [ - + ]: 40 : if (length < 2*8)
639 : 0 : return -EBADMSG;
640 : :
641 : 40 : *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex;
642 : 40 : return 0;
643 : : }
644 : :
645 : 20 : _public_ int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret) {
646 : 20 : _cleanup_strv_free_ char **l = NULL;
647 : 20 : _cleanup_free_ char *e = NULL;
648 : 20 : size_t allocated = 0, n = 0, left;
649 : : uint8_t *ri, *p;
650 : 20 : bool first = true;
651 : : int r;
652 : 20 : unsigned k = 0;
653 : :
654 [ - + - + ]: 20 : assert_return(rt, -EINVAL);
655 [ - + - + ]: 20 : assert_return(ret, -EINVAL);
656 : :
657 : 20 : r = get_dnssl_info(rt, &ri);
658 [ - + ]: 20 : if (r < 0)
659 : 0 : return r;
660 : :
661 : 20 : p = ri + 8;
662 : 20 : left = NDISC_ROUTER_OPTION_LENGTH(rt) - 8;
663 : :
664 : : for (;;) {
665 [ + + ]: 180 : if (left == 0) {
666 : :
667 [ - + ]: 20 : if (n > 0) /* Not properly NUL terminated */
668 : 0 : return -EBADMSG;
669 : :
670 : 20 : break;
671 : : }
672 : :
673 [ + + ]: 160 : if (*p == 0) {
674 : : /* Found NUL termination */
675 : :
676 [ + + ]: 120 : if (n > 0) {
677 [ + - ]: 20 : _cleanup_free_ char *normalized = NULL;
678 : :
679 : 20 : e[n] = 0;
680 : 20 : r = dns_name_normalize(e, 0, &normalized);
681 [ - + ]: 20 : if (r < 0)
682 : 0 : return r;
683 : :
684 : : /* Ignore the root domain name or "localhost" and friends */
685 [ + - ]: 20 : if (!is_localhost(normalized) &&
686 [ + - ]: 20 : !dns_name_is_root(normalized)) {
687 : :
688 [ - + ]: 20 : if (strv_push(&l, normalized) < 0)
689 : 0 : return -ENOMEM;
690 : :
691 : 20 : normalized = NULL;
692 : 20 : k++;
693 : : }
694 : : }
695 : :
696 : 120 : n = 0;
697 : 120 : first = true;
698 : 120 : p++, left--;
699 : 120 : continue;
700 : : }
701 : :
702 : : /* Check for compression (which is not allowed) */
703 [ - + ]: 40 : if (*p > 63)
704 : 0 : return -EBADMSG;
705 : :
706 [ - + ]: 40 : if (1U + *p + 1U > left)
707 : 0 : return -EBADMSG;
708 : :
709 [ - + ]: 40 : if (!GREEDY_REALLOC(e, allocated, n + !first + DNS_LABEL_ESCAPED_MAX + 1U))
710 : 0 : return -ENOMEM;
711 : :
712 [ + + ]: 40 : if (first)
713 : 20 : first = false;
714 : : else
715 : 20 : e[n++] = '.';
716 : :
717 : 40 : r = dns_label_escape((char*) p+1, *p, e + n, DNS_LABEL_ESCAPED_MAX);
718 [ - + ]: 40 : if (r < 0)
719 : 0 : return r;
720 : :
721 : 40 : n += r;
722 : :
723 : 40 : left -= 1 + *p;
724 : 40 : p += 1 + *p;
725 : : }
726 : :
727 [ - + ]: 20 : if (strv_isempty(l)) {
728 : 0 : *ret = NULL;
729 : 0 : return 0;
730 : : }
731 : :
732 : 20 : *ret = TAKE_PTR(l);
733 : :
734 : 20 : return k;
735 : : }
736 : :
737 : 20 : _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 [ - + - + ]: 20 : assert_return(rt, -EINVAL);
742 [ - + - + ]: 20 : assert_return(ret_sec, -EINVAL);
743 : :
744 : 20 : r = get_dnssl_info(rt, &ri);
745 [ - + ]: 20 : if (r < 0)
746 : 0 : return r;
747 : :
748 : 20 : *ret_sec = be32toh(*(uint32_t*) (ri + 4));
749 : 20 : return 0;
750 : : }
|