Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : : /***
3 : : Copyright © 2017 Intel Corporation. All rights reserved.
4 : : ***/
5 : :
6 : : #include <netinet/icmp6.h>
7 : : #include <netinet/in.h>
8 : : #include <arpa/inet.h>
9 : :
10 : : #include "sd-radv.h"
11 : :
12 : : #include "alloc-util.h"
13 : : #include "dns-domain.h"
14 : : #include "ether-addr-util.h"
15 : : #include "event-util.h"
16 : : #include "fd-util.h"
17 : : #include "icmp6-util.h"
18 : : #include "in-addr-util.h"
19 : : #include "io-util.h"
20 : : #include "macro.h"
21 : : #include "memory-util.h"
22 : : #include "radv-internal.h"
23 : : #include "random-util.h"
24 : : #include "socket-util.h"
25 : : #include "string-util.h"
26 : : #include "strv.h"
27 : :
28 : 8 : _public_ int sd_radv_new(sd_radv **ret) {
29 : 8 : _cleanup_(sd_radv_unrefp) sd_radv *ra = NULL;
30 : :
31 [ - + - + ]: 8 : assert_return(ret, -EINVAL);
32 : :
33 : 8 : ra = new(sd_radv, 1);
34 [ - + ]: 8 : if (!ra)
35 : 0 : return -ENOMEM;
36 : :
37 : 8 : *ra = (sd_radv) {
38 : : .n_ref = 1,
39 : : .fd = -1,
40 : : };
41 : :
42 : 8 : *ret = TAKE_PTR(ra);
43 : :
44 : 8 : return 0;
45 : : }
46 : :
47 : 4 : _public_ int sd_radv_attach_event(sd_radv *ra, sd_event *event, int64_t priority) {
48 : : int r;
49 : :
50 [ - + - + ]: 4 : assert_return(ra, -EINVAL);
51 [ - + - + ]: 4 : assert_return(!ra->event, -EBUSY);
52 : :
53 [ + - ]: 4 : if (event)
54 : 4 : ra->event = sd_event_ref(event);
55 : : else {
56 : 0 : r = sd_event_default(&ra->event);
57 [ # # ]: 0 : if (r < 0)
58 : 0 : return 0;
59 : : }
60 : :
61 : 4 : ra->event_priority = priority;
62 : :
63 : 4 : return 0;
64 : : }
65 : :
66 : 8 : _public_ int sd_radv_detach_event(sd_radv *ra) {
67 : :
68 [ - + - + ]: 8 : assert_return(ra, -EINVAL);
69 : :
70 : 8 : ra->event = sd_event_unref(ra->event);
71 : 8 : return 0;
72 : : }
73 : :
74 : 4 : _public_ sd_event *sd_radv_get_event(sd_radv *ra) {
75 [ - + - + ]: 4 : assert_return(ra, NULL);
76 : :
77 : 4 : return ra->event;
78 : : }
79 : :
80 : 12 : static void radv_reset(sd_radv *ra) {
81 [ - + ]: 12 : assert(ra);
82 : :
83 : 12 : (void) event_source_disable(ra->timeout_event_source);
84 : :
85 : 12 : ra->recv_event_source =
86 : 12 : sd_event_source_unref(ra->recv_event_source);
87 : :
88 : 12 : ra->ra_sent = 0;
89 : 12 : }
90 : :
91 : 8 : static sd_radv *radv_free(sd_radv *ra) {
92 [ - + ]: 8 : if (!ra)
93 : 0 : return NULL;
94 : :
95 [ + + ]: 20 : while (ra->prefixes) {
96 : 12 : sd_radv_prefix *p = ra->prefixes;
97 : :
98 [ - + + + : 12 : LIST_REMOVE(prefix, ra->prefixes, p);
- + - + ]
99 : 12 : sd_radv_prefix_unref(p);
100 : : }
101 : :
102 : 8 : free(ra->rdnss);
103 : 8 : free(ra->dnssl);
104 : :
105 : 8 : ra->timeout_event_source = sd_event_source_unref(ra->timeout_event_source);
106 : :
107 : 8 : radv_reset(ra);
108 : :
109 : 8 : sd_radv_detach_event(ra);
110 : :
111 : 8 : ra->fd = safe_close(ra->fd);
112 : :
113 : 8 : return mfree(ra);
114 : : }
115 : :
116 [ + + - + : 36 : DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv, sd_radv, radv_free);
- + ]
117 : :
118 : 8 : static int radv_send(sd_radv *ra, const struct in6_addr *dst, uint32_t router_lifetime) {
119 : : sd_radv_prefix *p;
120 : 8 : struct sockaddr_in6 dst_addr = {
121 : : .sin6_family = AF_INET6,
122 : : .sin6_addr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
123 : : };
124 : 8 : struct nd_router_advert adv = {};
125 : : struct {
126 : : struct nd_opt_hdr opthdr;
127 : : struct ether_addr slladdr;
128 : 8 : } _packed_ opt_mac = {
129 : : .opthdr = {
130 : : .nd_opt_type = ND_OPT_SOURCE_LINKADDR,
131 : : .nd_opt_len = (sizeof(struct nd_opt_hdr) +
132 : : sizeof(struct ether_addr) - 1) /8 + 1,
133 : : },
134 : : };
135 : 8 : struct nd_opt_mtu opt_mtu = {
136 : : .nd_opt_mtu_type = ND_OPT_MTU,
137 : : .nd_opt_mtu_len = 1,
138 : : };
139 : : /* Reserve iov space for RA header, linkaddr, MTU, N prefixes, RDNSS
140 : : and DNSSL */
141 : 8 : struct iovec iov[5 + ra->n_prefixes];
142 : 8 : struct msghdr msg = {
143 : : .msg_name = &dst_addr,
144 : : .msg_namelen = sizeof(dst_addr),
145 : : .msg_iov = iov,
146 : : };
147 : : usec_t time_now;
148 : : int r;
149 : :
150 [ - + ]: 8 : assert(ra);
151 : :
152 : 8 : r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
153 [ - + ]: 8 : if (r < 0)
154 : 0 : return r;
155 : :
156 [ - + # # : 8 : if (dst && !IN6_IS_ADDR_UNSPECIFIED(dst))
# # # # #
# # # ]
157 : 0 : dst_addr.sin6_addr = *dst;
158 : :
159 : 8 : adv.nd_ra_type = ND_ROUTER_ADVERT;
160 : 8 : adv.nd_ra_curhoplimit = ra->hop_limit;
161 : 8 : adv.nd_ra_flags_reserved = ra->flags;
162 : 8 : adv.nd_ra_router_lifetime = htobe16(router_lifetime);
163 : 8 : iov[msg.msg_iovlen++] = IOVEC_MAKE(&adv, sizeof(adv));
164 : :
165 : : /* MAC address is optional, either because the link does not use L2
166 : : addresses or load sharing is desired. See RFC 4861, Section 4.2 */
167 [ + - ]: 8 : if (!ether_addr_is_null(&ra->mac_addr)) {
168 : 8 : opt_mac.slladdr = ra->mac_addr;
169 : 8 : iov[msg.msg_iovlen++] = IOVEC_MAKE(&opt_mac, sizeof(opt_mac));
170 : : }
171 : :
172 [ - + ]: 8 : if (ra->mtu) {
173 : 0 : opt_mtu.nd_opt_mtu_mtu = htobe32(ra->mtu);
174 : 0 : iov[msg.msg_iovlen++] = IOVEC_MAKE(&opt_mtu, sizeof(opt_mtu));
175 : : }
176 : :
177 [ + + ]: 32 : LIST_FOREACH(prefix, p, ra->prefixes) {
178 [ - + ]: 24 : if (p->valid_until) {
179 : :
180 [ # # ]: 0 : if (time_now > p->valid_until)
181 : 0 : p->opt.valid_lifetime = 0;
182 : : else
183 : 0 : p->opt.valid_lifetime = htobe32((p->valid_until - time_now) / USEC_PER_SEC);
184 : :
185 [ # # ]: 0 : if (time_now > p->preferred_until)
186 : 0 : p->opt.preferred_lifetime = 0;
187 : : else
188 : 0 : p->opt.preferred_lifetime = htobe32((p->preferred_until - time_now) / USEC_PER_SEC);
189 : : }
190 : 24 : iov[msg.msg_iovlen++] = IOVEC_MAKE(&p->opt, sizeof(p->opt));
191 : : }
192 : :
193 [ + - ]: 8 : if (ra->rdnss)
194 : 8 : iov[msg.msg_iovlen++] = IOVEC_MAKE(ra->rdnss, ra->rdnss->length * 8);
195 : :
196 [ + - ]: 8 : if (ra->dnssl)
197 : 8 : iov[msg.msg_iovlen++] = IOVEC_MAKE(ra->dnssl, ra->dnssl->length * 8);
198 : :
199 [ - + ]: 8 : if (sendmsg(ra->fd, &msg, 0) < 0)
200 : 0 : return -errno;
201 : :
202 : 8 : return 0;
203 : : }
204 : :
205 : 0 : static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
206 : 0 : sd_radv *ra = userdata;
207 : 0 : _cleanup_free_ char *addr = NULL;
208 : : struct in6_addr src;
209 : : triple_timestamp timestamp;
210 : : int r;
211 : : ssize_t buflen;
212 : 0 : _cleanup_free_ char *buf = NULL;
213 : :
214 [ # # ]: 0 : assert(s);
215 [ # # ]: 0 : assert(ra);
216 [ # # ]: 0 : assert(ra->event);
217 : :
218 : 0 : buflen = next_datagram_size_fd(fd);
219 [ # # ]: 0 : if (buflen < 0)
220 : 0 : return (int) buflen;
221 : :
222 [ # # ]: 0 : buf = new0(char, buflen);
223 [ # # ]: 0 : if (!buf)
224 : 0 : return -ENOMEM;
225 : :
226 : 0 : r = icmp6_receive(fd, buf, buflen, &src, ×tamp);
227 [ # # ]: 0 : if (r < 0) {
228 [ # # # # : 0 : switch (r) {
# ]
229 : 0 : case -EADDRNOTAVAIL:
230 : 0 : (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &src, &addr);
231 : 0 : log_radv("Received RS from non-link-local address %s. Ignoring", addr);
232 : 0 : break;
233 : :
234 : 0 : case -EMULTIHOP:
235 : 0 : log_radv("Received RS with invalid hop limit. Ignoring.");
236 : 0 : break;
237 : :
238 : 0 : case -EPFNOSUPPORT:
239 : 0 : log_radv("Received invalid source address from ICMPv6 socket. Ignoring.");
240 : 0 : break;
241 : :
242 : 0 : case -EAGAIN: /* ignore spurious wakeups */
243 : 0 : break;
244 : :
245 : 0 : default:
246 : 0 : log_radv_errno(r, "Unexpected error receiving from ICMPv6 socket: %m");
247 : 0 : break;
248 : : }
249 : :
250 : 0 : return 0;
251 : : }
252 : :
253 [ # # ]: 0 : if ((size_t) buflen < sizeof(struct nd_router_solicit)) {
254 : 0 : log_radv("Too short packet received");
255 : 0 : return 0;
256 : : }
257 : :
258 : 0 : (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &src, &addr);
259 : :
260 : 0 : r = radv_send(ra, &src, ra->lifetime);
261 [ # # ]: 0 : if (r < 0)
262 : 0 : log_radv_errno(r, "Unable to send solicited Router Advertisement to %s: %m", strnull(addr));
263 : : else
264 : 0 : log_radv("Sent solicited Router Advertisement to %s", strnull(addr));
265 : :
266 : 0 : return 0;
267 : : }
268 : :
269 : 4 : static usec_t radv_compute_timeout(usec_t min, usec_t max) {
270 [ - + - + ]: 4 : assert_return(min <= max, SD_RADV_DEFAULT_MIN_TIMEOUT_USEC);
271 : :
272 : 4 : return min + (random_u32() % (max - min));
273 : : }
274 : :
275 : 4 : static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
276 : : int r;
277 : 4 : sd_radv *ra = userdata;
278 : 4 : usec_t min_timeout = SD_RADV_DEFAULT_MIN_TIMEOUT_USEC;
279 : 4 : usec_t max_timeout = SD_RADV_DEFAULT_MAX_TIMEOUT_USEC;
280 : : usec_t time_now, timeout;
281 : : char time_string[FORMAT_TIMESPAN_MAX];
282 : :
283 [ - + ]: 4 : assert(s);
284 [ - + ]: 4 : assert(ra);
285 [ - + ]: 4 : assert(ra->event);
286 : :
287 : 4 : r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
288 [ - + ]: 4 : if (r < 0)
289 : 0 : goto fail;
290 : :
291 : 4 : r = radv_send(ra, NULL, ra->lifetime);
292 [ - + ]: 4 : if (r < 0)
293 : 0 : log_radv_errno(r, "Unable to send Router Advertisement: %m");
294 : :
295 : : /* RFC 4861, Section 6.2.4, sending initial Router Advertisements */
296 [ + - ]: 4 : if (ra->ra_sent < SD_RADV_MAX_INITIAL_RTR_ADVERTISEMENTS) {
297 : 4 : max_timeout = SD_RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC;
298 : 4 : min_timeout = SD_RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC / 3;
299 : : }
300 : :
301 : 4 : timeout = radv_compute_timeout(min_timeout, max_timeout);
302 : :
303 : 4 : log_radv("Next Router Advertisement in %s",
304 : : format_timespan(time_string, FORMAT_TIMESPAN_MAX,
305 : : timeout, USEC_PER_SEC));
306 : :
307 : 4 : r = event_reset_time(ra->event, &ra->timeout_event_source,
308 : : clock_boottime_or_monotonic(),
309 : : time_now + timeout, MSEC_PER_SEC,
310 : : radv_timeout, ra,
311 : 4 : ra->event_priority, "radv-timeout", true);
312 [ - + ]: 4 : if (r < 0)
313 : 0 : goto fail;
314 : :
315 : 4 : ra->ra_sent++;
316 : :
317 : 4 : return 0;
318 : :
319 : 0 : fail:
320 : 0 : sd_radv_stop(ra);
321 : :
322 : 0 : return 0;
323 : : }
324 : :
325 : 4 : _public_ int sd_radv_stop(sd_radv *ra) {
326 : : int r;
327 : :
328 [ - + - + ]: 4 : assert_return(ra, -EINVAL);
329 : :
330 [ - + ]: 4 : if (ra->state == SD_RADV_STATE_IDLE)
331 : 0 : return 0;
332 : :
333 : 4 : log_radv("Stopping IPv6 Router Advertisement daemon");
334 : :
335 : : /* RFC 4861, Section 6.2.5, send at least one Router Advertisement
336 : : with zero lifetime */
337 : 4 : r = radv_send(ra, NULL, 0);
338 [ - + ]: 4 : if (r < 0)
339 : 0 : log_radv_errno(r, "Unable to send last Router Advertisement with router lifetime set to zero: %m");
340 : :
341 : 4 : radv_reset(ra);
342 : 4 : ra->fd = safe_close(ra->fd);
343 : 4 : ra->state = SD_RADV_STATE_IDLE;
344 : :
345 : 4 : return 0;
346 : : }
347 : :
348 : 4 : _public_ int sd_radv_start(sd_radv *ra) {
349 : : int r;
350 : :
351 [ - + - + ]: 4 : assert_return(ra, -EINVAL);
352 [ - + - + ]: 4 : assert_return(ra->event, -EINVAL);
353 [ - + - + ]: 4 : assert_return(ra->ifindex > 0, -EINVAL);
354 : :
355 [ - + ]: 4 : if (ra->state != SD_RADV_STATE_IDLE)
356 : 0 : return 0;
357 : :
358 : 4 : r = event_reset_time(ra->event, &ra->timeout_event_source,
359 : : clock_boottime_or_monotonic(),
360 : : 0, 0,
361 : : radv_timeout, ra,
362 : 4 : ra->event_priority, "radv-timeout", true);
363 [ - + ]: 4 : if (r < 0)
364 : 0 : goto fail;
365 : :
366 : 4 : r = icmp6_bind_router_advertisement(ra->ifindex);
367 [ - + ]: 4 : if (r < 0)
368 : 0 : goto fail;
369 : :
370 : 4 : ra->fd = r;
371 : :
372 : 4 : r = sd_event_add_io(ra->event, &ra->recv_event_source, ra->fd, EPOLLIN, radv_recv, ra);
373 [ - + ]: 4 : if (r < 0)
374 : 0 : goto fail;
375 : :
376 : 4 : r = sd_event_source_set_priority(ra->recv_event_source, ra->event_priority);
377 [ - + ]: 4 : if (r < 0)
378 : 0 : goto fail;
379 : :
380 : 4 : (void) sd_event_source_set_description(ra->recv_event_source, "radv-receive-message");
381 : :
382 : 4 : ra->state = SD_RADV_STATE_ADVERTISING;
383 : :
384 : 4 : log_radv("Started IPv6 Router Advertisement daemon");
385 : :
386 : 4 : return 0;
387 : :
388 : 0 : fail:
389 : 0 : radv_reset(ra);
390 : :
391 : 0 : return r;
392 : : }
393 : :
394 : 24 : _public_ int sd_radv_set_ifindex(sd_radv *ra, int ifindex) {
395 [ + + + + ]: 24 : assert_return(ra, -EINVAL);
396 [ + + + + ]: 20 : assert_return(ifindex >= -1, -EINVAL);
397 : :
398 [ - + ]: 16 : if (ra->state != SD_RADV_STATE_IDLE)
399 : 0 : return -EBUSY;
400 : :
401 : 16 : ra->ifindex = ifindex;
402 : :
403 : 16 : return 0;
404 : : }
405 : :
406 : 16 : _public_ int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr) {
407 [ + + + + ]: 16 : assert_return(ra, -EINVAL);
408 : :
409 [ - + ]: 12 : if (ra->state != SD_RADV_STATE_IDLE)
410 : 0 : return -EBUSY;
411 : :
412 [ + + ]: 12 : if (mac_addr)
413 : 8 : ra->mac_addr = *mac_addr;
414 : : else
415 [ + - ]: 4 : zero(ra->mac_addr);
416 : :
417 : 12 : return 0;
418 : : }
419 : :
420 : 20 : _public_ int sd_radv_set_mtu(sd_radv *ra, uint32_t mtu) {
421 [ + + + + ]: 20 : assert_return(ra, -EINVAL);
422 [ + + + + ]: 16 : assert_return(mtu >= 1280, -EINVAL);
423 : :
424 : 8 : ra->mtu = mtu;
425 : :
426 : 8 : return 0;
427 : : }
428 : :
429 : 16 : _public_ int sd_radv_set_hop_limit(sd_radv *ra, uint8_t hop_limit) {
430 [ + + + + ]: 16 : assert_return(ra, -EINVAL);
431 : :
432 [ - + ]: 12 : if (ra->state != SD_RADV_STATE_IDLE)
433 : 0 : return -EBUSY;
434 : :
435 : 12 : ra->hop_limit = hop_limit;
436 : :
437 : 12 : return 0;
438 : : }
439 : :
440 : 28 : _public_ int sd_radv_set_router_lifetime(sd_radv *ra, uint32_t router_lifetime) {
441 [ + + + + ]: 28 : assert_return(ra, -EINVAL);
442 : :
443 [ - + ]: 24 : if (ra->state != SD_RADV_STATE_IDLE)
444 : 0 : return -EBUSY;
445 : :
446 : : /* RFC 4191, Section 2.2, "...If the Router Lifetime is zero, the
447 : : preference value MUST be set to (00) by the sender..." */
448 [ + + ]: 24 : if (router_lifetime == 0 &&
449 [ + + ]: 12 : (ra->flags & (0x3 << 3)) != (SD_NDISC_PREFERENCE_MEDIUM << 3))
450 : 4 : return -ETIME;
451 : :
452 : 20 : ra->lifetime = router_lifetime;
453 : :
454 : 20 : return 0;
455 : : }
456 : :
457 : 16 : _public_ int sd_radv_set_managed_information(sd_radv *ra, int managed) {
458 [ + + + + ]: 16 : assert_return(ra, -EINVAL);
459 : :
460 [ - + ]: 12 : if (ra->state != SD_RADV_STATE_IDLE)
461 : 0 : return -EBUSY;
462 : :
463 [ + + ]: 12 : SET_FLAG(ra->flags, ND_RA_FLAG_MANAGED, managed);
464 : :
465 : 12 : return 0;
466 : : }
467 : :
468 : 16 : _public_ int sd_radv_set_other_information(sd_radv *ra, int other) {
469 [ + + + + ]: 16 : assert_return(ra, -EINVAL);
470 : :
471 [ - + ]: 12 : if (ra->state != SD_RADV_STATE_IDLE)
472 : 0 : return -EBUSY;
473 : :
474 [ + + ]: 12 : SET_FLAG(ra->flags, ND_RA_FLAG_OTHER, other);
475 : :
476 : 12 : return 0;
477 : : }
478 : :
479 : 28 : _public_ int sd_radv_set_preference(sd_radv *ra, unsigned preference) {
480 : 28 : int r = 0;
481 : :
482 [ + + + + ]: 28 : assert_return(ra, -EINVAL);
483 [ + + + + : 24 : assert_return(IN_SET(preference,
+ + ]
484 : : SD_NDISC_PREFERENCE_LOW,
485 : : SD_NDISC_PREFERENCE_MEDIUM,
486 : : SD_NDISC_PREFERENCE_HIGH), -EINVAL);
487 : :
488 : 20 : ra->flags = (ra->flags & ~(0x3 << 3)) | (preference << 3);
489 : :
490 : 20 : return r;
491 : : }
492 : :
493 : 56 : _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, int dynamic) {
494 : : sd_radv_prefix *cur;
495 : : int r;
496 : 56 : _cleanup_free_ char *addr_p = NULL;
497 : : char time_string_preferred[FORMAT_TIMESPAN_MAX];
498 : : char time_string_valid[FORMAT_TIMESPAN_MAX];
499 : : usec_t time_now, valid, preferred, valid_until, preferred_until;
500 : :
501 [ - + - + ]: 56 : assert_return(ra, -EINVAL);
502 : :
503 [ - + ]: 56 : if (!p)
504 : 0 : return -EINVAL;
505 : :
506 : : /* Refuse prefixes that don't have a prefix set */
507 [ - + # # : 56 : if (IN6_IS_ADDR_UNSPECIFIED(&p->opt.in6_addr))
# # # # -
+ ]
508 : 0 : return -ENOEXEC;
509 : :
510 [ + + ]: 112 : LIST_FOREACH(prefix, cur, ra->prefixes) {
511 : :
512 : 300 : r = in_addr_prefix_intersect(AF_INET6,
513 : 100 : (union in_addr_union*) &cur->opt.in6_addr,
514 : 100 : cur->opt.prefixlen,
515 : 100 : (union in_addr_union*) &p->opt.in6_addr,
516 : 100 : p->opt.prefixlen);
517 [ + + ]: 100 : if (r > 0) {
518 [ - + ]: 44 : _cleanup_free_ char *addr_cur = NULL;
519 : :
520 : 44 : (void) in_addr_to_string(AF_INET6,
521 : 44 : (union in_addr_union*) &p->opt.in6_addr,
522 : : &addr_p);
523 : :
524 [ - + # # ]: 44 : if (dynamic && cur->opt.prefixlen == p->opt.prefixlen)
525 : 0 : goto update;
526 : :
527 : 44 : (void) in_addr_to_string(AF_INET6,
528 : 44 : (union in_addr_union*) &cur->opt.in6_addr,
529 : : &addr_cur);
530 : 44 : log_radv("IPv6 prefix %s/%u already configured, ignoring %s/%u",
531 : : addr_cur, cur->opt.prefixlen,
532 : : addr_p, p->opt.prefixlen);
533 : :
534 : 44 : return -EEXIST;
535 : : }
536 : : }
537 : :
538 : 12 : p = sd_radv_prefix_ref(p);
539 : :
540 [ + + + + : 16 : LIST_APPEND(prefix, ra->prefixes, p);
- + + + -
+ - + ]
541 : :
542 : 12 : ra->n_prefixes++;
543 : :
544 : 12 : (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &p->opt.in6_addr, &addr_p);
545 : :
546 [ + - ]: 12 : if (!dynamic) {
547 : 12 : log_radv("Added prefix %s/%d", addr_p, p->opt.prefixlen);
548 : 12 : return 0;
549 : : }
550 : :
551 : 0 : cur = p;
552 : :
553 : 0 : update:
554 : 0 : r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
555 [ # # ]: 0 : if (r < 0)
556 : 0 : return r;
557 : :
558 : 0 : valid = be32toh(p->opt.valid_lifetime) * USEC_PER_SEC;
559 : 0 : valid_until = usec_add(valid, time_now);
560 [ # # ]: 0 : if (valid_until == USEC_INFINITY)
561 : 0 : return -EOVERFLOW;
562 : :
563 : 0 : preferred = be32toh(p->opt.preferred_lifetime) * USEC_PER_SEC;
564 : 0 : preferred_until = usec_add(preferred, time_now);
565 [ # # ]: 0 : if (preferred_until == USEC_INFINITY)
566 : 0 : return -EOVERFLOW;
567 : :
568 : 0 : cur->valid_until = valid_until;
569 : 0 : cur->preferred_until = preferred_until;
570 : :
571 [ # # ]: 0 : log_radv("%s prefix %s/%u preferred %s valid %s",
572 : : cur? "Updated": "Added",
573 : : addr_p, p->opt.prefixlen,
574 : : format_timespan(time_string_preferred, FORMAT_TIMESPAN_MAX,
575 : : preferred, USEC_PER_SEC),
576 : : format_timespan(time_string_valid, FORMAT_TIMESPAN_MAX,
577 : : valid, USEC_PER_SEC));
578 : :
579 : 0 : return 0;
580 : : }
581 : :
582 : 0 : _public_ sd_radv_prefix *sd_radv_remove_prefix(sd_radv *ra,
583 : : const struct in6_addr *prefix,
584 : : unsigned char prefixlen) {
585 : : sd_radv_prefix *cur, *next;
586 : :
587 [ # # # # ]: 0 : assert_return(ra, NULL);
588 [ # # # # ]: 0 : assert_return(prefix, NULL);
589 : :
590 [ # # ]: 0 : LIST_FOREACH_SAFE(prefix, cur, next, ra->prefixes) {
591 [ # # ]: 0 : if (prefixlen != cur->opt.prefixlen)
592 : 0 : continue;
593 : :
594 [ # # ]: 0 : if (!in_addr_equal(AF_INET6,
595 : : (union in_addr_union *)prefix,
596 : 0 : (union in_addr_union *)&cur->opt.in6_addr))
597 : 0 : continue;
598 : :
599 [ # # # # : 0 : LIST_REMOVE(prefix, ra->prefixes, cur);
# # # # ]
600 : 0 : ra->n_prefixes--;
601 : 0 : sd_radv_prefix_unref(cur);
602 : :
603 : 0 : break;
604 : : }
605 : :
606 : 0 : return cur;
607 : : }
608 : :
609 : 32 : _public_ int sd_radv_set_rdnss(sd_radv *ra, uint32_t lifetime,
610 : : const struct in6_addr *dns, size_t n_dns) {
611 : 32 : _cleanup_free_ struct sd_radv_opt_dns *opt_rdnss = NULL;
612 : : size_t len;
613 : :
614 [ + + + + ]: 32 : assert_return(ra, -EINVAL);
615 [ + + + + ]: 28 : assert_return(n_dns < 128, -EINVAL);
616 : :
617 [ + + + + ]: 24 : if (!dns || n_dns == 0) {
618 : 12 : ra->rdnss = mfree(ra->rdnss);
619 : 12 : ra->n_rdnss = 0;
620 : :
621 : 12 : return 0;
622 : : }
623 : :
624 : 12 : len = sizeof(struct sd_radv_opt_dns) + sizeof(struct in6_addr) * n_dns;
625 : :
626 : 12 : opt_rdnss = malloc0(len);
627 [ - + ]: 12 : if (!opt_rdnss)
628 : 0 : return -ENOMEM;
629 : :
630 : 12 : opt_rdnss->type = SD_RADV_OPT_RDNSS;
631 : 12 : opt_rdnss->length = len / 8;
632 : 12 : opt_rdnss->lifetime = htobe32(lifetime);
633 : :
634 : 12 : memcpy(opt_rdnss + 1, dns, n_dns * sizeof(struct in6_addr));
635 : :
636 : 12 : free_and_replace(ra->rdnss, opt_rdnss);
637 : :
638 : 12 : ra->n_rdnss = n_dns;
639 : :
640 : 12 : return 0;
641 : : }
642 : :
643 : 20 : _public_ int sd_radv_set_dnssl(sd_radv *ra, uint32_t lifetime,
644 : : char **search_list) {
645 : 20 : _cleanup_free_ struct sd_radv_opt_dns *opt_dnssl = NULL;
646 : 20 : size_t len = 0;
647 : : char **s;
648 : : uint8_t *p;
649 : :
650 [ - + - + ]: 20 : assert_return(ra, -EINVAL);
651 : :
652 [ + + ]: 20 : if (strv_isempty(search_list)) {
653 : 8 : ra->dnssl = mfree(ra->dnssl);
654 : 8 : return 0;
655 : : }
656 : :
657 [ + - + + ]: 24 : STRV_FOREACH(s, search_list)
658 : 12 : len += strlen(*s) + 2;
659 : :
660 : 12 : len = (sizeof(struct sd_radv_opt_dns) + len + 7) & ~0x7;
661 : :
662 : 12 : opt_dnssl = malloc0(len);
663 [ - + ]: 12 : if (!opt_dnssl)
664 : 0 : return -ENOMEM;
665 : :
666 : 12 : opt_dnssl->type = SD_RADV_OPT_DNSSL;
667 : 12 : opt_dnssl->length = len / 8;
668 : 12 : opt_dnssl->lifetime = htobe32(lifetime);
669 : :
670 : 12 : p = (uint8_t *)(opt_dnssl + 1);
671 : 12 : len -= sizeof(struct sd_radv_opt_dns);
672 : :
673 [ + - + + ]: 24 : STRV_FOREACH(s, search_list) {
674 : : int r;
675 : :
676 : 12 : r = dns_name_to_wire_format(*s, p, len, false);
677 [ - + ]: 12 : if (r < 0)
678 : 0 : return r;
679 : :
680 [ - + ]: 12 : if (len < (size_t)r)
681 : 0 : return -ENOBUFS;
682 : :
683 : 12 : p += r;
684 : 12 : len -= r;
685 : : }
686 : :
687 : 12 : free_and_replace(ra->dnssl, opt_dnssl);
688 : :
689 : 12 : return 0;
690 : : }
691 : :
692 : 32 : _public_ int sd_radv_prefix_new(sd_radv_prefix **ret) {
693 : : sd_radv_prefix *p;
694 : :
695 [ - + - + ]: 32 : assert_return(ret, -EINVAL);
696 : :
697 : 32 : p = new(sd_radv_prefix, 1);
698 [ - + ]: 32 : if (!p)
699 : 0 : return -ENOMEM;
700 : :
701 : 32 : *p = (sd_radv_prefix) {
702 : : .n_ref = 1,
703 : :
704 : : .opt.type = ND_OPT_PREFIX_INFORMATION,
705 : : .opt.length = (sizeof(p->opt) - 1)/8 + 1,
706 : : .opt.prefixlen = 64,
707 : :
708 : : /* RFC 4861, Section 6.2.1 */
709 : : .opt.flags = ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO,
710 : :
711 : 32 : .opt.preferred_lifetime = htobe32(604800),
712 : 32 : .opt.valid_lifetime = htobe32(2592000),
713 : : };
714 : :
715 : 32 : *ret = p;
716 : 32 : return 0;
717 : : }
718 : :
719 [ - + - + : 56 : DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv_prefix, sd_radv_prefix, mfree);
+ + ]
720 : :
721 : 72 : _public_ int sd_radv_prefix_set_prefix(sd_radv_prefix *p, const struct in6_addr *in6_addr,
722 : : unsigned char prefixlen) {
723 [ + + + + ]: 72 : assert_return(p, -EINVAL);
724 [ + + + + ]: 68 : assert_return(in6_addr, -EINVAL);
725 : :
726 [ + + + + ]: 64 : if (prefixlen < 3 || prefixlen > 128)
727 : 20 : return -EINVAL;
728 : :
729 [ + + ]: 44 : if (prefixlen > 64)
730 : : /* unusual but allowed, log it */
731 : 12 : log_radv("Unusual prefix length %d greater than 64", prefixlen);
732 : :
733 : 44 : p->opt.in6_addr = *in6_addr;
734 : 44 : p->opt.prefixlen = prefixlen;
735 : :
736 : 44 : return 0;
737 : : }
738 : :
739 : 12 : _public_ int sd_radv_prefix_set_onlink(sd_radv_prefix *p, int onlink) {
740 [ + + + + ]: 12 : assert_return(p, -EINVAL);
741 : :
742 [ + + ]: 8 : SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_ONLINK, onlink);
743 : :
744 : 8 : return 0;
745 : : }
746 : :
747 : 12 : _public_ int sd_radv_prefix_set_address_autoconfiguration(sd_radv_prefix *p,
748 : : int address_autoconfiguration) {
749 [ + + + + ]: 12 : assert_return(p, -EINVAL);
750 : :
751 [ + + ]: 8 : SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_AUTO, address_autoconfiguration);
752 : :
753 : 8 : return 0;
754 : : }
755 : :
756 : 20 : _public_ int sd_radv_prefix_set_valid_lifetime(sd_radv_prefix *p,
757 : : uint32_t valid_lifetime) {
758 [ + + + + ]: 20 : assert_return(p, -EINVAL);
759 : :
760 : 16 : p->opt.valid_lifetime = htobe32(valid_lifetime);
761 : :
762 : 16 : return 0;
763 : : }
764 : :
765 : 20 : _public_ int sd_radv_prefix_set_preferred_lifetime(sd_radv_prefix *p,
766 : : uint32_t preferred_lifetime) {
767 [ + + + + ]: 20 : assert_return(p, -EINVAL);
768 : :
769 : 16 : p->opt.preferred_lifetime = htobe32(preferred_lifetime);
770 : :
771 : 16 : return 0;
772 : : }
|