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 2 : _public_ int sd_radv_new(sd_radv **ret) {
29 2 : _cleanup_(sd_radv_unrefp) sd_radv *ra = NULL;
30 :
31 2 : assert_return(ret, -EINVAL);
32 :
33 2 : ra = new(sd_radv, 1);
34 2 : if (!ra)
35 0 : return -ENOMEM;
36 :
37 2 : *ra = (sd_radv) {
38 : .n_ref = 1,
39 : .fd = -1,
40 : };
41 :
42 2 : *ret = TAKE_PTR(ra);
43 :
44 2 : return 0;
45 : }
46 :
47 1 : _public_ int sd_radv_attach_event(sd_radv *ra, sd_event *event, int64_t priority) {
48 : int r;
49 :
50 1 : assert_return(ra, -EINVAL);
51 1 : assert_return(!ra->event, -EBUSY);
52 :
53 1 : if (event)
54 1 : 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 1 : ra->event_priority = priority;
62 :
63 1 : return 0;
64 : }
65 :
66 2 : _public_ int sd_radv_detach_event(sd_radv *ra) {
67 :
68 2 : assert_return(ra, -EINVAL);
69 :
70 2 : ra->event = sd_event_unref(ra->event);
71 2 : return 0;
72 : }
73 :
74 1 : _public_ sd_event *sd_radv_get_event(sd_radv *ra) {
75 1 : assert_return(ra, NULL);
76 :
77 1 : return ra->event;
78 : }
79 :
80 3 : static void radv_reset(sd_radv *ra) {
81 3 : assert(ra);
82 :
83 3 : (void) event_source_disable(ra->timeout_event_source);
84 :
85 3 : ra->recv_event_source =
86 3 : sd_event_source_unref(ra->recv_event_source);
87 :
88 3 : ra->ra_sent = 0;
89 3 : }
90 :
91 2 : static sd_radv *radv_free(sd_radv *ra) {
92 2 : if (!ra)
93 0 : return NULL;
94 :
95 5 : while (ra->prefixes) {
96 3 : sd_radv_prefix *p = ra->prefixes;
97 :
98 3 : LIST_REMOVE(prefix, ra->prefixes, p);
99 3 : sd_radv_prefix_unref(p);
100 : }
101 :
102 2 : free(ra->rdnss);
103 2 : free(ra->dnssl);
104 :
105 2 : ra->timeout_event_source = sd_event_source_unref(ra->timeout_event_source);
106 :
107 2 : radv_reset(ra);
108 :
109 2 : sd_radv_detach_event(ra);
110 :
111 2 : ra->fd = safe_close(ra->fd);
112 :
113 2 : return mfree(ra);
114 : }
115 :
116 8 : DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv, sd_radv, radv_free);
117 :
118 2 : static int radv_send(sd_radv *ra, const struct in6_addr *dst, uint32_t router_lifetime) {
119 : sd_radv_prefix *p;
120 2 : struct sockaddr_in6 dst_addr = {
121 : .sin6_family = AF_INET6,
122 : .sin6_addr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
123 : };
124 2 : struct nd_router_advert adv = {};
125 : struct {
126 : struct nd_opt_hdr opthdr;
127 : struct ether_addr slladdr;
128 2 : } _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 2 : 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 2 : struct iovec iov[5 + ra->n_prefixes];
142 2 : 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 2 : assert(ra);
151 :
152 2 : r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
153 2 : if (r < 0)
154 0 : return r;
155 :
156 2 : if (dst && !IN6_IS_ADDR_UNSPECIFIED(dst))
157 0 : dst_addr.sin6_addr = *dst;
158 :
159 2 : adv.nd_ra_type = ND_ROUTER_ADVERT;
160 2 : adv.nd_ra_curhoplimit = ra->hop_limit;
161 2 : adv.nd_ra_flags_reserved = ra->flags;
162 2 : adv.nd_ra_router_lifetime = htobe16(router_lifetime);
163 2 : 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 2 : if (!ether_addr_is_null(&ra->mac_addr)) {
168 2 : opt_mac.slladdr = ra->mac_addr;
169 2 : iov[msg.msg_iovlen++] = IOVEC_MAKE(&opt_mac, sizeof(opt_mac));
170 : }
171 :
172 2 : 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 8 : LIST_FOREACH(prefix, p, ra->prefixes) {
178 6 : 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 6 : iov[msg.msg_iovlen++] = IOVEC_MAKE(&p->opt, sizeof(p->opt));
191 : }
192 :
193 2 : if (ra->rdnss)
194 2 : iov[msg.msg_iovlen++] = IOVEC_MAKE(ra->rdnss, ra->rdnss->length * 8);
195 :
196 2 : if (ra->dnssl)
197 2 : iov[msg.msg_iovlen++] = IOVEC_MAKE(ra->dnssl, ra->dnssl->length * 8);
198 :
199 2 : if (sendmsg(ra->fd, &msg, 0) < 0)
200 0 : return -errno;
201 :
202 2 : 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 1 : static usec_t radv_compute_timeout(usec_t min, usec_t max) {
270 1 : assert_return(min <= max, SD_RADV_DEFAULT_MIN_TIMEOUT_USEC);
271 :
272 1 : return min + (random_u32() % (max - min));
273 : }
274 :
275 1 : static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
276 : int r;
277 1 : sd_radv *ra = userdata;
278 1 : usec_t min_timeout = SD_RADV_DEFAULT_MIN_TIMEOUT_USEC;
279 1 : 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 1 : assert(s);
284 1 : assert(ra);
285 1 : assert(ra->event);
286 :
287 1 : r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
288 1 : if (r < 0)
289 0 : goto fail;
290 :
291 1 : r = radv_send(ra, NULL, ra->lifetime);
292 1 : 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 1 : if (ra->ra_sent < SD_RADV_MAX_INITIAL_RTR_ADVERTISEMENTS) {
297 1 : max_timeout = SD_RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC;
298 1 : min_timeout = SD_RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC / 3;
299 : }
300 :
301 1 : timeout = radv_compute_timeout(min_timeout, max_timeout);
302 :
303 1 : log_radv("Next Router Advertisement in %s",
304 : format_timespan(time_string, FORMAT_TIMESPAN_MAX,
305 : timeout, USEC_PER_SEC));
306 :
307 1 : 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 1 : ra->event_priority, "radv-timeout", true);
312 1 : if (r < 0)
313 0 : goto fail;
314 :
315 1 : ra->ra_sent++;
316 :
317 1 : return 0;
318 :
319 0 : fail:
320 0 : sd_radv_stop(ra);
321 :
322 0 : return 0;
323 : }
324 :
325 1 : _public_ int sd_radv_stop(sd_radv *ra) {
326 : int r;
327 :
328 1 : assert_return(ra, -EINVAL);
329 :
330 1 : if (ra->state == SD_RADV_STATE_IDLE)
331 0 : return 0;
332 :
333 1 : 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 1 : r = radv_send(ra, NULL, 0);
338 1 : if (r < 0)
339 0 : log_radv_errno(r, "Unable to send last Router Advertisement with router lifetime set to zero: %m");
340 :
341 1 : radv_reset(ra);
342 1 : ra->fd = safe_close(ra->fd);
343 1 : ra->state = SD_RADV_STATE_IDLE;
344 :
345 1 : return 0;
346 : }
347 :
348 1 : _public_ int sd_radv_start(sd_radv *ra) {
349 : int r;
350 :
351 1 : assert_return(ra, -EINVAL);
352 1 : assert_return(ra->event, -EINVAL);
353 1 : assert_return(ra->ifindex > 0, -EINVAL);
354 :
355 1 : if (ra->state != SD_RADV_STATE_IDLE)
356 0 : return 0;
357 :
358 1 : r = event_reset_time(ra->event, &ra->timeout_event_source,
359 : clock_boottime_or_monotonic(),
360 : 0, 0,
361 : radv_timeout, ra,
362 1 : ra->event_priority, "radv-timeout", true);
363 1 : if (r < 0)
364 0 : goto fail;
365 :
366 1 : r = icmp6_bind_router_advertisement(ra->ifindex);
367 1 : if (r < 0)
368 0 : goto fail;
369 :
370 1 : ra->fd = r;
371 :
372 1 : r = sd_event_add_io(ra->event, &ra->recv_event_source, ra->fd, EPOLLIN, radv_recv, ra);
373 1 : if (r < 0)
374 0 : goto fail;
375 :
376 1 : r = sd_event_source_set_priority(ra->recv_event_source, ra->event_priority);
377 1 : if (r < 0)
378 0 : goto fail;
379 :
380 1 : (void) sd_event_source_set_description(ra->recv_event_source, "radv-receive-message");
381 :
382 1 : ra->state = SD_RADV_STATE_ADVERTISING;
383 :
384 1 : log_radv("Started IPv6 Router Advertisement daemon");
385 :
386 1 : return 0;
387 :
388 0 : fail:
389 0 : radv_reset(ra);
390 :
391 0 : return r;
392 : }
393 :
394 6 : _public_ int sd_radv_set_ifindex(sd_radv *ra, int ifindex) {
395 6 : assert_return(ra, -EINVAL);
396 5 : assert_return(ifindex >= -1, -EINVAL);
397 :
398 4 : if (ra->state != SD_RADV_STATE_IDLE)
399 0 : return -EBUSY;
400 :
401 4 : ra->ifindex = ifindex;
402 :
403 4 : return 0;
404 : }
405 :
406 4 : _public_ int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr) {
407 4 : assert_return(ra, -EINVAL);
408 :
409 3 : if (ra->state != SD_RADV_STATE_IDLE)
410 0 : return -EBUSY;
411 :
412 3 : if (mac_addr)
413 2 : ra->mac_addr = *mac_addr;
414 : else
415 1 : zero(ra->mac_addr);
416 :
417 3 : return 0;
418 : }
419 :
420 5 : _public_ int sd_radv_set_mtu(sd_radv *ra, uint32_t mtu) {
421 5 : assert_return(ra, -EINVAL);
422 4 : assert_return(mtu >= 1280, -EINVAL);
423 :
424 2 : ra->mtu = mtu;
425 :
426 2 : return 0;
427 : }
428 :
429 4 : _public_ int sd_radv_set_hop_limit(sd_radv *ra, uint8_t hop_limit) {
430 4 : assert_return(ra, -EINVAL);
431 :
432 3 : if (ra->state != SD_RADV_STATE_IDLE)
433 0 : return -EBUSY;
434 :
435 3 : ra->hop_limit = hop_limit;
436 :
437 3 : return 0;
438 : }
439 :
440 7 : _public_ int sd_radv_set_router_lifetime(sd_radv *ra, uint32_t router_lifetime) {
441 7 : assert_return(ra, -EINVAL);
442 :
443 6 : 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 6 : if (router_lifetime == 0 &&
449 3 : (ra->flags & (0x3 << 3)) != (SD_NDISC_PREFERENCE_MEDIUM << 3))
450 1 : return -ETIME;
451 :
452 5 : ra->lifetime = router_lifetime;
453 :
454 5 : return 0;
455 : }
456 :
457 4 : _public_ int sd_radv_set_managed_information(sd_radv *ra, int managed) {
458 4 : assert_return(ra, -EINVAL);
459 :
460 3 : if (ra->state != SD_RADV_STATE_IDLE)
461 0 : return -EBUSY;
462 :
463 3 : SET_FLAG(ra->flags, ND_RA_FLAG_MANAGED, managed);
464 :
465 3 : return 0;
466 : }
467 :
468 4 : _public_ int sd_radv_set_other_information(sd_radv *ra, int other) {
469 4 : assert_return(ra, -EINVAL);
470 :
471 3 : if (ra->state != SD_RADV_STATE_IDLE)
472 0 : return -EBUSY;
473 :
474 3 : SET_FLAG(ra->flags, ND_RA_FLAG_OTHER, other);
475 :
476 3 : return 0;
477 : }
478 :
479 7 : _public_ int sd_radv_set_preference(sd_radv *ra, unsigned preference) {
480 7 : int r = 0;
481 :
482 7 : assert_return(ra, -EINVAL);
483 6 : assert_return(IN_SET(preference,
484 : SD_NDISC_PREFERENCE_LOW,
485 : SD_NDISC_PREFERENCE_MEDIUM,
486 : SD_NDISC_PREFERENCE_HIGH), -EINVAL);
487 :
488 5 : ra->flags = (ra->flags & ~(0x3 << 3)) | (preference << 3);
489 :
490 5 : return r;
491 : }
492 :
493 14 : _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, int dynamic) {
494 : sd_radv_prefix *cur;
495 : int r;
496 14 : _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 14 : assert_return(ra, -EINVAL);
502 :
503 14 : if (!p)
504 0 : return -EINVAL;
505 :
506 : /* Refuse prefixes that don't have a prefix set */
507 14 : if (IN6_IS_ADDR_UNSPECIFIED(&p->opt.in6_addr))
508 0 : return -ENOEXEC;
509 :
510 28 : LIST_FOREACH(prefix, cur, ra->prefixes) {
511 :
512 75 : r = in_addr_prefix_intersect(AF_INET6,
513 25 : (union in_addr_union*) &cur->opt.in6_addr,
514 25 : cur->opt.prefixlen,
515 25 : (union in_addr_union*) &p->opt.in6_addr,
516 25 : p->opt.prefixlen);
517 25 : if (r > 0) {
518 11 : _cleanup_free_ char *addr_cur = NULL;
519 :
520 11 : (void) in_addr_to_string(AF_INET6,
521 11 : (union in_addr_union*) &p->opt.in6_addr,
522 : &addr_p);
523 :
524 11 : if (dynamic && cur->opt.prefixlen == p->opt.prefixlen)
525 0 : goto update;
526 :
527 11 : (void) in_addr_to_string(AF_INET6,
528 11 : (union in_addr_union*) &cur->opt.in6_addr,
529 : &addr_cur);
530 11 : 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 11 : return -EEXIST;
535 : }
536 : }
537 :
538 3 : p = sd_radv_prefix_ref(p);
539 :
540 4 : LIST_APPEND(prefix, ra->prefixes, p);
541 :
542 3 : ra->n_prefixes++;
543 :
544 3 : (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &p->opt.in6_addr, &addr_p);
545 :
546 3 : if (!dynamic) {
547 3 : log_radv("Added prefix %s/%d", addr_p, p->opt.prefixlen);
548 3 : 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 8 : _public_ int sd_radv_set_rdnss(sd_radv *ra, uint32_t lifetime,
610 : const struct in6_addr *dns, size_t n_dns) {
611 8 : _cleanup_free_ struct sd_radv_opt_dns *opt_rdnss = NULL;
612 : size_t len;
613 :
614 8 : assert_return(ra, -EINVAL);
615 7 : assert_return(n_dns < 128, -EINVAL);
616 :
617 6 : if (!dns || n_dns == 0) {
618 3 : ra->rdnss = mfree(ra->rdnss);
619 3 : ra->n_rdnss = 0;
620 :
621 3 : return 0;
622 : }
623 :
624 3 : len = sizeof(struct sd_radv_opt_dns) + sizeof(struct in6_addr) * n_dns;
625 :
626 3 : opt_rdnss = malloc0(len);
627 3 : if (!opt_rdnss)
628 0 : return -ENOMEM;
629 :
630 3 : opt_rdnss->type = SD_RADV_OPT_RDNSS;
631 3 : opt_rdnss->length = len / 8;
632 3 : opt_rdnss->lifetime = htobe32(lifetime);
633 :
634 3 : memcpy(opt_rdnss + 1, dns, n_dns * sizeof(struct in6_addr));
635 :
636 3 : free_and_replace(ra->rdnss, opt_rdnss);
637 :
638 3 : ra->n_rdnss = n_dns;
639 :
640 3 : return 0;
641 : }
642 :
643 5 : _public_ int sd_radv_set_dnssl(sd_radv *ra, uint32_t lifetime,
644 : char **search_list) {
645 5 : _cleanup_free_ struct sd_radv_opt_dns *opt_dnssl = NULL;
646 5 : size_t len = 0;
647 : char **s;
648 : uint8_t *p;
649 :
650 5 : assert_return(ra, -EINVAL);
651 :
652 5 : if (strv_isempty(search_list)) {
653 2 : ra->dnssl = mfree(ra->dnssl);
654 2 : return 0;
655 : }
656 :
657 6 : STRV_FOREACH(s, search_list)
658 3 : len += strlen(*s) + 2;
659 :
660 3 : len = (sizeof(struct sd_radv_opt_dns) + len + 7) & ~0x7;
661 :
662 3 : opt_dnssl = malloc0(len);
663 3 : if (!opt_dnssl)
664 0 : return -ENOMEM;
665 :
666 3 : opt_dnssl->type = SD_RADV_OPT_DNSSL;
667 3 : opt_dnssl->length = len / 8;
668 3 : opt_dnssl->lifetime = htobe32(lifetime);
669 :
670 3 : p = (uint8_t *)(opt_dnssl + 1);
671 3 : len -= sizeof(struct sd_radv_opt_dns);
672 :
673 6 : STRV_FOREACH(s, search_list) {
674 : int r;
675 :
676 3 : r = dns_name_to_wire_format(*s, p, len, false);
677 3 : if (r < 0)
678 0 : return r;
679 :
680 3 : if (len < (size_t)r)
681 0 : return -ENOBUFS;
682 :
683 3 : p += r;
684 3 : len -= r;
685 : }
686 :
687 3 : free_and_replace(ra->dnssl, opt_dnssl);
688 :
689 3 : return 0;
690 : }
691 :
692 8 : _public_ int sd_radv_prefix_new(sd_radv_prefix **ret) {
693 : sd_radv_prefix *p;
694 :
695 8 : assert_return(ret, -EINVAL);
696 :
697 8 : p = new(sd_radv_prefix, 1);
698 8 : if (!p)
699 0 : return -ENOMEM;
700 :
701 8 : *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 8 : .opt.preferred_lifetime = htobe32(604800),
712 8 : .opt.valid_lifetime = htobe32(2592000),
713 : };
714 :
715 8 : *ret = p;
716 8 : return 0;
717 : }
718 :
719 14 : DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv_prefix, sd_radv_prefix, mfree);
720 :
721 18 : _public_ int sd_radv_prefix_set_prefix(sd_radv_prefix *p, const struct in6_addr *in6_addr,
722 : unsigned char prefixlen) {
723 18 : assert_return(p, -EINVAL);
724 17 : assert_return(in6_addr, -EINVAL);
725 :
726 16 : if (prefixlen < 3 || prefixlen > 128)
727 5 : return -EINVAL;
728 :
729 11 : if (prefixlen > 64)
730 : /* unusual but allowed, log it */
731 3 : log_radv("Unusual prefix length %d greater than 64", prefixlen);
732 :
733 11 : p->opt.in6_addr = *in6_addr;
734 11 : p->opt.prefixlen = prefixlen;
735 :
736 11 : return 0;
737 : }
738 :
739 3 : _public_ int sd_radv_prefix_set_onlink(sd_radv_prefix *p, int onlink) {
740 3 : assert_return(p, -EINVAL);
741 :
742 2 : SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_ONLINK, onlink);
743 :
744 2 : return 0;
745 : }
746 :
747 3 : _public_ int sd_radv_prefix_set_address_autoconfiguration(sd_radv_prefix *p,
748 : int address_autoconfiguration) {
749 3 : assert_return(p, -EINVAL);
750 :
751 2 : SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_AUTO, address_autoconfiguration);
752 :
753 2 : return 0;
754 : }
755 :
756 5 : _public_ int sd_radv_prefix_set_valid_lifetime(sd_radv_prefix *p,
757 : uint32_t valid_lifetime) {
758 5 : assert_return(p, -EINVAL);
759 :
760 4 : p->opt.valid_lifetime = htobe32(valid_lifetime);
761 :
762 4 : return 0;
763 : }
764 :
765 5 : _public_ int sd_radv_prefix_set_preferred_lifetime(sd_radv_prefix *p,
766 : uint32_t preferred_lifetime) {
767 5 : assert_return(p, -EINVAL);
768 :
769 4 : p->opt.preferred_lifetime = htobe32(preferred_lifetime);
770 :
771 4 : return 0;
772 : }
|