]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-radv.c
tree-wide: add FORMAT_TIMESPAN()
[thirdparty/systemd.git] / src / libsystemd-network / sd-radv.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
04473969 2/***
810adae9 3 Copyright © 2017 Intel Corporation. All rights reserved.
04473969
PF
4***/
5
6#include <netinet/icmp6.h>
7#include <netinet/in.h>
204f99d2 8#include <arpa/inet.h>
04473969
PF
9
10#include "sd-radv.h"
11
12#include "alloc-util.h"
e965d6ab 13#include "dns-domain.h"
ae25915d 14#include "ether-addr-util.h"
807a8ede 15#include "event-util.h"
04473969
PF
16#include "fd-util.h"
17#include "icmp6-util.h"
18#include "in-addr-util.h"
5cfa2c3d
LP
19#include "io-util.h"
20#include "macro.h"
0a970718 21#include "memory-util.h"
61a9fa8f 22#include "network-common.h"
04473969 23#include "radv-internal.h"
5cfa2c3d 24#include "random-util.h"
04473969
PF
25#include "socket-util.h"
26#include "string-util.h"
e965d6ab 27#include "strv.h"
04473969 28
204f99d2
PF
29_public_ int sd_radv_new(sd_radv **ret) {
30 _cleanup_(sd_radv_unrefp) sd_radv *ra = NULL;
31
32 assert_return(ret, -EINVAL);
33
78f9d24f 34 ra = new(sd_radv, 1);
204f99d2
PF
35 if (!ra)
36 return -ENOMEM;
37
78f9d24f
YW
38 *ra = (sd_radv) {
39 .n_ref = 1,
40 .fd = -1,
41 };
204f99d2 42
1cc6c93a 43 *ret = TAKE_PTR(ra);
204f99d2
PF
44
45 return 0;
46}
47
48_public_ int sd_radv_attach_event(sd_radv *ra, sd_event *event, int64_t priority) {
49 int r;
50
51 assert_return(ra, -EINVAL);
52 assert_return(!ra->event, -EBUSY);
53
54 if (event)
55 ra->event = sd_event_ref(event);
56 else {
57 r = sd_event_default(&ra->event);
58 if (r < 0)
59 return 0;
60 }
61
62 ra->event_priority = priority;
63
64 return 0;
65}
66
67_public_ int sd_radv_detach_event(sd_radv *ra) {
68
69 assert_return(ra, -EINVAL);
70
71 ra->event = sd_event_unref(ra->event);
72 return 0;
73}
74
75_public_ sd_event *sd_radv_get_event(sd_radv *ra) {
76 assert_return(ra, NULL);
77
78 return ra->event;
79}
80
96fe813c
YW
81_public_ int sd_radv_is_running(sd_radv *ra) {
82 assert_return(ra, false);
83
84 return ra->state != SD_RADV_STATE_IDLE;
85}
86
204fb681 87static void radv_reset(sd_radv *ra) {
c4b6dda0 88 assert(ra);
204fb681 89
807a8ede 90 (void) event_source_disable(ra->timeout_event_source);
204fb681 91
88d5a3db
PF
92 ra->recv_event_source =
93 sd_event_source_unref(ra->recv_event_source);
94
204fb681
PF
95 ra->ra_sent = 0;
96}
97
8301aa0b 98static sd_radv *radv_free(sd_radv *ra) {
e866e17b
LP
99 if (!ra)
100 return NULL;
204f99d2
PF
101
102 while (ra->prefixes) {
103 sd_radv_prefix *p = ra->prefixes;
104
105 LIST_REMOVE(prefix, ra->prefixes, p);
106 sd_radv_prefix_unref(p);
107 }
108
69d7eba1
YW
109 while (ra->route_prefixes) {
110 sd_radv_route_prefix *p = ra->route_prefixes;
111
112 LIST_REMOVE(prefix, ra->route_prefixes, p);
113 sd_radv_route_prefix_unref(p);
114 }
115
e9c6da38 116 free(ra->rdnss);
f9aa5417 117 free(ra->dnssl);
e9c6da38 118
807a8ede
YW
119 ra->timeout_event_source = sd_event_source_unref(ra->timeout_event_source);
120
204fb681
PF
121 radv_reset(ra);
122
204f99d2 123 sd_radv_detach_event(ra);
c4b6dda0
LP
124
125 ra->fd = safe_close(ra->fd);
61a9fa8f 126 free(ra->ifname);
c4b6dda0 127
204f99d2
PF
128 return mfree(ra);
129}
130
8301aa0b
YW
131DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv, sd_radv, radv_free);
132
83ef9d14 133static int radv_send(sd_radv *ra, const struct in6_addr *dst, uint32_t router_lifetime) {
203d4df5 134 sd_radv_route_prefix *rt;
77baf5ae
PF
135 sd_radv_prefix *p;
136 struct sockaddr_in6 dst_addr = {
137 .sin6_family = AF_INET6,
138 .sin6_addr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
139 };
140 struct nd_router_advert adv = {};
141 struct {
142 struct nd_opt_hdr opthdr;
143 struct ether_addr slladdr;
144 } _packed_ opt_mac = {
145 .opthdr = {
146 .nd_opt_type = ND_OPT_SOURCE_LINKADDR,
147 .nd_opt_len = (sizeof(struct nd_opt_hdr) +
148 sizeof(struct ether_addr) - 1) /8 + 1,
149 },
150 };
151 struct nd_opt_mtu opt_mtu = {
152 .nd_opt_mtu_type = ND_OPT_MTU,
153 .nd_opt_mtu_len = 1,
154 };
203d4df5 155 /* Reserve iov space for RA header, linkaddr, MTU, N prefixes, N routes, RDNSS
6852c0f6 156 and DNSSL */
203d4df5 157 struct iovec iov[5 + ra->n_prefixes + ra->n_route_prefixes];
77baf5ae
PF
158 struct msghdr msg = {
159 .msg_name = &dst_addr,
160 .msg_namelen = sizeof(dst_addr),
161 .msg_iov = iov,
162 };
d601b566
PF
163 usec_t time_now;
164 int r;
165
dc0ec5e2
LP
166 assert(ra);
167
d601b566
PF
168 r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
169 if (r < 0)
170 return r;
77baf5ae 171
94876904 172 if (dst && in6_addr_is_set(dst))
77baf5ae 173 dst_addr.sin6_addr = *dst;
88d5a3db 174
77baf5ae
PF
175 adv.nd_ra_type = ND_ROUTER_ADVERT;
176 adv.nd_ra_curhoplimit = ra->hop_limit;
177 adv.nd_ra_flags_reserved = ra->flags;
178 adv.nd_ra_router_lifetime = htobe16(router_lifetime);
5cfa2c3d 179 iov[msg.msg_iovlen++] = IOVEC_MAKE(&adv, sizeof(adv));
77baf5ae
PF
180
181 /* MAC address is optional, either because the link does not use L2
182 addresses or load sharing is desired. See RFC 4861, Section 4.2 */
ae25915d 183 if (!ether_addr_is_null(&ra->mac_addr)) {
77baf5ae 184 opt_mac.slladdr = ra->mac_addr;
5cfa2c3d 185 iov[msg.msg_iovlen++] = IOVEC_MAKE(&opt_mac, sizeof(opt_mac));
77baf5ae
PF
186 }
187
188 if (ra->mtu) {
189 opt_mtu.nd_opt_mtu_mtu = htobe32(ra->mtu);
5cfa2c3d 190 iov[msg.msg_iovlen++] = IOVEC_MAKE(&opt_mtu, sizeof(opt_mtu));
77baf5ae
PF
191 }
192
193 LIST_FOREACH(prefix, p, ra->prefixes) {
d601b566
PF
194 if (p->valid_until) {
195
196 if (time_now > p->valid_until)
197 p->opt.valid_lifetime = 0;
198 else
199 p->opt.valid_lifetime = htobe32((p->valid_until - time_now) / USEC_PER_SEC);
200
201 if (time_now > p->preferred_until)
202 p->opt.preferred_lifetime = 0;
203 else
204 p->opt.preferred_lifetime = htobe32((p->preferred_until - time_now) / USEC_PER_SEC);
205 }
5cfa2c3d 206 iov[msg.msg_iovlen++] = IOVEC_MAKE(&p->opt, sizeof(p->opt));
77baf5ae
PF
207 }
208
203d4df5
SS
209 LIST_FOREACH(prefix, rt, ra->route_prefixes)
210 iov[msg.msg_iovlen++] = IOVEC_MAKE(&rt->opt, sizeof(rt->opt));
211
5cfa2c3d
LP
212 if (ra->rdnss)
213 iov[msg.msg_iovlen++] = IOVEC_MAKE(ra->rdnss, ra->rdnss->length * 8);
e9c6da38 214
5cfa2c3d
LP
215 if (ra->dnssl)
216 iov[msg.msg_iovlen++] = IOVEC_MAKE(ra->dnssl, ra->dnssl->length * 8);
e965d6ab 217
77baf5ae
PF
218 if (sendmsg(ra->fd, &msg, 0) < 0)
219 return -errno;
204fb681 220
77baf5ae 221 return 0;
204fb681
PF
222}
223
88d5a3db
PF
224static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
225 sd_radv *ra = userdata;
226 _cleanup_free_ char *addr = NULL;
227 struct in6_addr src;
228 triple_timestamp timestamp;
229 int r;
230 ssize_t buflen;
231 _cleanup_free_ char *buf = NULL;
232
233 assert(s);
234 assert(ra);
235 assert(ra->event);
236
237 buflen = next_datagram_size_fd(fd);
cfffddea
LP
238 if (buflen < 0)
239 return (int) buflen;
88d5a3db
PF
240
241 buf = new0(char, buflen);
242 if (!buf)
e55a6eae 243 return -ENOMEM;
88d5a3db
PF
244
245 r = icmp6_receive(fd, buf, buflen, &src, &timestamp);
246 if (r < 0) {
247 switch (r) {
248 case -EADDRNOTAVAIL:
c633628d 249 (void) in_addr_to_string(AF_INET6, (const union in_addr_union*) &src, &addr);
35388783 250 log_radv(ra, "Received RS from non-link-local address %s. Ignoring", addr);
88d5a3db
PF
251 break;
252
253 case -EMULTIHOP:
35388783 254 log_radv(ra, "Received RS with invalid hop limit. Ignoring.");
88d5a3db
PF
255 break;
256
257 case -EPFNOSUPPORT:
35388783 258 log_radv(ra, "Received invalid source address from ICMPv6 socket. Ignoring.");
88d5a3db
PF
259 break;
260
8eb41f4c
LP
261 case -EAGAIN: /* ignore spurious wakeups */
262 break;
263
88d5a3db 264 default:
35388783 265 log_radv_errno(ra, r, "Unexpected error receiving from ICMPv6 socket, Ignoring: %m");
88d5a3db
PF
266 break;
267 }
268
269 return 0;
270 }
271
cfffddea 272 if ((size_t) buflen < sizeof(struct nd_router_solicit)) {
35388783 273 log_radv(ra, "Too short packet received, ignoring");
cfffddea
LP
274 return 0;
275 }
276
c633628d 277 (void) in_addr_to_string(AF_INET6, (const union in_addr_union*) &src, &addr);
88d5a3db
PF
278
279 r = radv_send(ra, &src, ra->lifetime);
280 if (r < 0)
35388783 281 log_radv_errno(ra, r, "Unable to send solicited Router Advertisement to %s, ignoring: %m", strnull(addr));
88d5a3db 282 else
35388783 283 log_radv(ra, "Sent solicited Router Advertisement to %s", strnull(addr));
88d5a3db
PF
284
285 return 0;
286}
287
204fb681
PF
288static usec_t radv_compute_timeout(usec_t min, usec_t max) {
289 assert_return(min <= max, SD_RADV_DEFAULT_MIN_TIMEOUT_USEC);
290
ef90b6a4
GM
291 /* RFC 4861: min must be no less than 3s, max must be no less than 4s */
292 min = MAX(min, 3*USEC_PER_SEC);
293 max = MAX(max, 4*USEC_PER_SEC);
294
204fb681
PF
295 return min + (random_u32() % (max - min));
296}
297
298static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
299 int r;
300 sd_radv *ra = userdata;
301 usec_t min_timeout = SD_RADV_DEFAULT_MIN_TIMEOUT_USEC;
302 usec_t max_timeout = SD_RADV_DEFAULT_MAX_TIMEOUT_USEC;
303 usec_t time_now, timeout;
204fb681
PF
304
305 assert(s);
306 assert(ra);
307 assert(ra->event);
308
204fb681
PF
309 r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
310 if (r < 0)
311 goto fail;
312
313 r = radv_send(ra, NULL, ra->lifetime);
314 if (r < 0)
35388783 315 log_radv_errno(ra, r, "Unable to send Router Advertisement: %m");
204fb681
PF
316
317 /* RFC 4861, Section 6.2.4, sending initial Router Advertisements */
318 if (ra->ra_sent < SD_RADV_MAX_INITIAL_RTR_ADVERTISEMENTS) {
319 max_timeout = SD_RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC;
320 min_timeout = SD_RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC / 3;
321 }
322
ef90b6a4
GM
323 /* RFC 4861, Section 6.2.1, lifetime must be at least MaxRtrAdvInterval,
324 so lower the interval here */
325 if (ra->lifetime > 0 && (ra->lifetime * USEC_PER_SEC) < max_timeout) {
326 max_timeout = ra->lifetime * USEC_PER_SEC;
327 min_timeout = max_timeout / 3;
328 }
329
204fb681 330 timeout = radv_compute_timeout(min_timeout, max_timeout);
5291f26d 331 log_radv(ra, "Next Router Advertisement in %s", FORMAT_TIMESPAN(timeout, USEC_PER_SEC));
204fb681 332
807a8ede
YW
333 r = event_reset_time(ra->event, &ra->timeout_event_source,
334 clock_boottime_or_monotonic(),
335 time_now + timeout, MSEC_PER_SEC,
336 radv_timeout, ra,
337 ra->event_priority, "radv-timeout", true);
204fb681
PF
338 if (r < 0)
339 goto fail;
340
341 ra->ra_sent++;
342
807a8ede
YW
343 return 0;
344
204fb681 345fail:
290696e5 346 sd_radv_stop(ra);
204fb681
PF
347
348 return 0;
349}
350
290696e5 351_public_ int sd_radv_stop(sd_radv *ra) {
204fb681
PF
352 int r;
353
c8bae363
YW
354 if (!ra)
355 return 0;
204f99d2 356
6f8a8b84
SS
357 if (ra->state == SD_RADV_STATE_IDLE)
358 return 0;
359
35388783 360 log_radv(ra, "Stopping IPv6 Router Advertisement daemon");
204f99d2 361
290696e5
YW
362 /* RFC 4861, Section 6.2.5, send at least one Router Advertisement
363 with zero lifetime */
364 r = radv_send(ra, NULL, 0);
365 if (r < 0)
35388783 366 log_radv_errno(ra, r, "Unable to send last Router Advertisement with router lifetime set to zero: %m");
204fb681
PF
367
368 radv_reset(ra);
77baf5ae 369 ra->fd = safe_close(ra->fd);
204f99d2
PF
370 ra->state = SD_RADV_STATE_IDLE;
371
372 return 0;
373}
374
375_public_ int sd_radv_start(sd_radv *ra) {
f474884c 376 int r;
204fb681 377
204f99d2
PF
378 assert_return(ra, -EINVAL);
379 assert_return(ra->event, -EINVAL);
380 assert_return(ra->ifindex > 0, -EINVAL);
381
382 if (ra->state != SD_RADV_STATE_IDLE)
383 return 0;
384
807a8ede
YW
385 r = event_reset_time(ra->event, &ra->timeout_event_source,
386 clock_boottime_or_monotonic(),
387 0, 0,
388 radv_timeout, ra,
389 ra->event_priority, "radv-timeout", true);
204fb681
PF
390 if (r < 0)
391 goto fail;
392
77baf5ae
PF
393 r = icmp6_bind_router_advertisement(ra->ifindex);
394 if (r < 0)
395 goto fail;
396
397 ra->fd = r;
88d5a3db
PF
398
399 r = sd_event_add_io(ra->event, &ra->recv_event_source, ra->fd, EPOLLIN, radv_recv, ra);
400 if (r < 0)
401 goto fail;
402
403 r = sd_event_source_set_priority(ra->recv_event_source, ra->event_priority);
404 if (r < 0)
405 goto fail;
406
407 (void) sd_event_source_set_description(ra->recv_event_source, "radv-receive-message");
77baf5ae 408
204f99d2
PF
409 ra->state = SD_RADV_STATE_ADVERTISING;
410
35388783 411 log_radv(ra, "Started IPv6 Router Advertisement daemon");
204f99d2
PF
412
413 return 0;
204fb681
PF
414
415 fail:
416 radv_reset(ra);
417
418 return r;
204f99d2
PF
419}
420
421_public_ int sd_radv_set_ifindex(sd_radv *ra, int ifindex) {
422 assert_return(ra, -EINVAL);
7fa69c0a 423 assert_return(ifindex > 0, -EINVAL);
204f99d2
PF
424
425 if (ra->state != SD_RADV_STATE_IDLE)
426 return -EBUSY;
427
428 ra->ifindex = ifindex;
429
430 return 0;
431}
432
61a9fa8f
YW
433int sd_radv_set_ifname(sd_radv *ra, const char *ifname) {
434 assert_return(ra, -EINVAL);
435 assert_return(ifname, -EINVAL);
436
437 if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE))
438 return -EINVAL;
439
440 return free_and_strdup(&ra->ifname, ifname);
441}
442
443const char *sd_radv_get_ifname(sd_radv *ra) {
444 if (!ra)
445 return NULL;
446
447 return get_ifname(ra->ifindex, &ra->ifname);
448}
449
204f99d2
PF
450_public_ int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr) {
451 assert_return(ra, -EINVAL);
452
453 if (ra->state != SD_RADV_STATE_IDLE)
454 return -EBUSY;
455
456 if (mac_addr)
457 ra->mac_addr = *mac_addr;
458 else
459 zero(ra->mac_addr);
460
461 return 0;
462}
463
464_public_ int sd_radv_set_mtu(sd_radv *ra, uint32_t mtu) {
465 assert_return(ra, -EINVAL);
466 assert_return(mtu >= 1280, -EINVAL);
467
204f99d2
PF
468 ra->mtu = mtu;
469
470 return 0;
471}
472
473_public_ int sd_radv_set_hop_limit(sd_radv *ra, uint8_t hop_limit) {
474 assert_return(ra, -EINVAL);
475
476 if (ra->state != SD_RADV_STATE_IDLE)
477 return -EBUSY;
478
479 ra->hop_limit = hop_limit;
480
481 return 0;
482}
483
ac138551 484_public_ int sd_radv_set_router_lifetime(sd_radv *ra, uint16_t router_lifetime) {
204f99d2
PF
485 assert_return(ra, -EINVAL);
486
487 if (ra->state != SD_RADV_STATE_IDLE)
488 return -EBUSY;
489
ac138551
YW
490 /* RFC 4191, Section 2.2, "...If the Router Lifetime is zero, the preference value MUST be set
491 * to (00) by the sender..." */
204f99d2
PF
492 if (router_lifetime == 0 &&
493 (ra->flags & (0x3 << 3)) != (SD_NDISC_PREFERENCE_MEDIUM << 3))
494 return -ETIME;
495
496 ra->lifetime = router_lifetime;
497
498 return 0;
499}
500
501_public_ int sd_radv_set_managed_information(sd_radv *ra, int managed) {
502 assert_return(ra, -EINVAL);
503
504 if (ra->state != SD_RADV_STATE_IDLE)
505 return -EBUSY;
506
507 SET_FLAG(ra->flags, ND_RA_FLAG_MANAGED, managed);
508
509 return 0;
510}
511
512_public_ int sd_radv_set_other_information(sd_radv *ra, int other) {
513 assert_return(ra, -EINVAL);
514
515 if (ra->state != SD_RADV_STATE_IDLE)
516 return -EBUSY;
517
518 SET_FLAG(ra->flags, ND_RA_FLAG_OTHER, other);
519
520 return 0;
521}
522
523_public_ int sd_radv_set_preference(sd_radv *ra, unsigned preference) {
204f99d2
PF
524 assert_return(ra, -EINVAL);
525 assert_return(IN_SET(preference,
526 SD_NDISC_PREFERENCE_LOW,
527 SD_NDISC_PREFERENCE_MEDIUM,
528 SD_NDISC_PREFERENCE_HIGH), -EINVAL);
529
dd1b1870
YW
530 /* RFC 4191, Section 2.2, "...If the Router Lifetime is zero, the preference value MUST be set
531 * to (00) by the sender..." */
532 if (ra->lifetime == 0 && preference != SD_NDISC_PREFERENCE_MEDIUM)
533 return -EINVAL;
534
204f99d2
PF
535 ra->flags = (ra->flags & ~(0x3 << 3)) | (preference << 3);
536
dd1b1870 537 return 0;
204f99d2
PF
538}
539
a3a98776 540_public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, int dynamic) {
204f99d2 541 sd_radv_prefix *cur;
d601b566 542 int r;
204f99d2 543 _cleanup_free_ char *addr_p = NULL;
d601b566 544 usec_t time_now, valid, preferred, valid_until, preferred_until;
204f99d2
PF
545
546 assert_return(ra, -EINVAL);
547
548 if (!p)
549 return -EINVAL;
550
59ea6e57 551 /* Refuse prefixes that don't have a prefix set */
94876904 552 if (in6_addr_is_null(&p->opt.in6_addr))
59ea6e57
LP
553 return -ENOEXEC;
554
5380707a 555 (void) in_addr_prefix_to_string(AF_INET6,
c633628d 556 (const union in_addr_union*) &p->opt.in6_addr,
5380707a
YW
557 p->opt.prefixlen, &addr_p);
558
204f99d2 559 LIST_FOREACH(prefix, cur, ra->prefixes) {
204f99d2
PF
560
561 r = in_addr_prefix_intersect(AF_INET6,
c633628d 562 (const union in_addr_union*) &cur->opt.in6_addr,
204f99d2 563 cur->opt.prefixlen,
c633628d 564 (const union in_addr_union*) &p->opt.in6_addr,
204f99d2 565 p->opt.prefixlen);
5380707a
YW
566 if (r < 0)
567 return r;
568 if (r == 0)
569 continue;
204f99d2 570
5380707a
YW
571 if (dynamic && cur->opt.prefixlen == p->opt.prefixlen)
572 goto update;
d601b566 573
5380707a
YW
574 _cleanup_free_ char *addr_cur = NULL;
575 (void) in_addr_prefix_to_string(AF_INET6,
c633628d 576 (const union in_addr_union*) &cur->opt.in6_addr,
5380707a 577 cur->opt.prefixlen, &addr_cur);
35388783
YW
578 return log_radv_errno(ra, SYNTHETIC_ERRNO(EEXIST),
579 "IPv6 prefix %s already configured, ignoring %s",
580 strna(addr_cur), strna(addr_p));
204f99d2
PF
581 }
582
583 p = sd_radv_prefix_ref(p);
584
585 LIST_APPEND(prefix, ra->prefixes, p);
586
587 ra->n_prefixes++;
588
d601b566 589 if (!dynamic) {
35388783 590 log_radv(ra, "Added prefix %s", strna(addr_p));
d601b566
PF
591 return 0;
592 }
593
594 cur = p;
595
97efde65
MM
596 /* If RAs have already been sent, send an RA immediately to announce the newly-added prefix */
597 if (ra->ra_sent > 0) {
6333aa9d
LP
598 r = radv_send(ra, NULL, ra->lifetime);
599 if (r < 0)
35388783 600 log_radv_errno(ra, r, "Unable to send Router Advertisement for added prefix: %m");
6333aa9d 601 else
35388783 602 log_radv(ra, "Sent Router Advertisement for added prefix");
97efde65
MM
603 }
604
d601b566
PF
605 update:
606 r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
607 if (r < 0)
608 return r;
609
610 valid = be32toh(p->opt.valid_lifetime) * USEC_PER_SEC;
611 valid_until = usec_add(valid, time_now);
612 if (valid_until == USEC_INFINITY)
613 return -EOVERFLOW;
614
615 preferred = be32toh(p->opt.preferred_lifetime) * USEC_PER_SEC;
616 preferred_until = usec_add(preferred, time_now);
617 if (preferred_until == USEC_INFINITY)
618 return -EOVERFLOW;
619
620 cur->valid_until = valid_until;
621 cur->preferred_until = preferred_until;
622
35388783 623 log_radv(ra, "Updated prefix %s preferred %s valid %s",
5380707a 624 strna(addr_p),
5291f26d
ZJS
625 FORMAT_TIMESPAN(preferred, USEC_PER_SEC),
626 FORMAT_TIMESPAN(valid, USEC_PER_SEC));
204f99d2
PF
627
628 return 0;
629}
630
34c169c4 631_public_ sd_radv_prefix *sd_radv_remove_prefix(sd_radv *ra,
f5a5706a
LP
632 const struct in6_addr *prefix,
633 unsigned char prefixlen) {
34c169c4
PF
634 sd_radv_prefix *cur, *next;
635
636 assert_return(ra, NULL);
637 assert_return(prefix, NULL);
638
639 LIST_FOREACH_SAFE(prefix, cur, next, ra->prefixes) {
640 if (prefixlen != cur->opt.prefixlen)
641 continue;
642
94876904 643 if (!in6_addr_equal(prefix, &cur->opt.in6_addr))
34c169c4
PF
644 continue;
645
646 LIST_REMOVE(prefix, ra->prefixes, cur);
647 ra->n_prefixes--;
62bbbedf 648 sd_radv_prefix_unref(cur);
34c169c4
PF
649
650 break;
651 }
652
653 return cur;
654}
655
203d4df5 656_public_ int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p, int dynamic) {
203d4df5
SS
657 usec_t time_now, valid, valid_until;
658 _cleanup_free_ char *pretty = NULL;
659 sd_radv_route_prefix *cur;
660 int r;
661
662 assert_return(ra, -EINVAL);
663
664 if (!p)
665 return -EINVAL;
666
5380707a 667 (void) in_addr_prefix_to_string(AF_INET6,
c633628d 668 (const union in_addr_union*) &p->opt.in6_addr,
5380707a 669 p->opt.prefixlen, &pretty);
203d4df5
SS
670
671 LIST_FOREACH(prefix, cur, ra->route_prefixes) {
203d4df5
SS
672
673 r = in_addr_prefix_intersect(AF_INET6,
c633628d 674 (const union in_addr_union*) &cur->opt.in6_addr,
203d4df5 675 cur->opt.prefixlen,
c633628d 676 (const union in_addr_union*) &p->opt.in6_addr,
203d4df5
SS
677 p->opt.prefixlen);
678 if (r < 0)
679 return r;
680 if (r == 0)
681 continue;
682
683 if (dynamic && cur->opt.prefixlen == p->opt.prefixlen)
684 goto update;
685
5380707a
YW
686 _cleanup_free_ char *addr = NULL;
687 (void) in_addr_prefix_to_string(AF_INET6,
c633628d 688 (const union in_addr_union*) &cur->opt.in6_addr,
5380707a 689 cur->opt.prefixlen, &addr);
35388783
YW
690 return log_radv_errno(ra, SYNTHETIC_ERRNO(EEXIST),
691 "IPv6 route prefix %s already configured, ignoring %s",
692 strna(addr), strna(pretty));
203d4df5
SS
693 }
694
695 p = sd_radv_route_prefix_ref(p);
696
697 LIST_APPEND(prefix, ra->route_prefixes, p);
698 ra->n_route_prefixes++;
699
203d4df5 700 if (!dynamic) {
35388783 701 log_radv(ra, "Added prefix %s", strna(pretty));
203d4df5
SS
702 return 0;
703 }
704
97efde65
MM
705 /* If RAs have already been sent, send an RA immediately to announce the newly-added route prefix */
706 if (ra->ra_sent > 0) {
6333aa9d
LP
707 r = radv_send(ra, NULL, ra->lifetime);
708 if (r < 0)
35388783 709 log_radv_errno(ra, r, "Unable to send Router Advertisement for added route prefix: %m");
6333aa9d 710 else
35388783 711 log_radv(ra, "Sent Router Advertisement for added route prefix");
97efde65
MM
712 }
713
203d4df5
SS
714 update:
715 r = sd_event_now(ra->event, clock_boottime_or_monotonic(), &time_now);
716 if (r < 0)
717 return r;
718
719 valid = be32toh(p->opt.lifetime) * USEC_PER_SEC;
720 valid_until = usec_add(valid, time_now);
721 if (valid_until == USEC_INFINITY)
722 return -EOVERFLOW;
723
35388783 724 log_radv(ra, "Updated route prefix %s valid %s",
5380707a 725 strna(pretty),
5291f26d 726 FORMAT_TIMESPAN(valid, USEC_PER_SEC));
203d4df5
SS
727
728 return 0;
729}
730
e9c6da38
PF
731_public_ int sd_radv_set_rdnss(sd_radv *ra, uint32_t lifetime,
732 const struct in6_addr *dns, size_t n_dns) {
733 _cleanup_free_ struct sd_radv_opt_dns *opt_rdnss = NULL;
734 size_t len;
735
736 assert_return(ra, -EINVAL);
737 assert_return(n_dns < 128, -EINVAL);
738
739 if (!dns || n_dns == 0) {
740 ra->rdnss = mfree(ra->rdnss);
741 ra->n_rdnss = 0;
742
743 return 0;
744 }
745
746 len = sizeof(struct sd_radv_opt_dns) + sizeof(struct in6_addr) * n_dns;
747
748 opt_rdnss = malloc0(len);
749 if (!opt_rdnss)
750 return -ENOMEM;
751
752 opt_rdnss->type = SD_RADV_OPT_RDNSS;
753 opt_rdnss->length = len / 8;
754 opt_rdnss->lifetime = htobe32(lifetime);
755
756 memcpy(opt_rdnss + 1, dns, n_dns * sizeof(struct in6_addr));
757
1cc6c93a 758 free_and_replace(ra->rdnss, opt_rdnss);
e9c6da38
PF
759
760 ra->n_rdnss = n_dns;
761
762 return 0;
763}
764
e965d6ab
PF
765_public_ int sd_radv_set_dnssl(sd_radv *ra, uint32_t lifetime,
766 char **search_list) {
767 _cleanup_free_ struct sd_radv_opt_dns *opt_dnssl = NULL;
768 size_t len = 0;
769 char **s;
770 uint8_t *p;
771
772 assert_return(ra, -EINVAL);
773
97d7974b 774 if (strv_isempty(search_list)) {
e965d6ab 775 ra->dnssl = mfree(ra->dnssl);
e965d6ab
PF
776 return 0;
777 }
778
779 STRV_FOREACH(s, search_list)
780 len += strlen(*s) + 2;
781
782 len = (sizeof(struct sd_radv_opt_dns) + len + 7) & ~0x7;
783
784 opt_dnssl = malloc0(len);
785 if (!opt_dnssl)
786 return -ENOMEM;
787
788 opt_dnssl->type = SD_RADV_OPT_DNSSL;
789 opt_dnssl->length = len / 8;
790 opt_dnssl->lifetime = htobe32(lifetime);
791
792 p = (uint8_t *)(opt_dnssl + 1);
793 len -= sizeof(struct sd_radv_opt_dns);
794
795 STRV_FOREACH(s, search_list) {
796 int r;
797
798 r = dns_name_to_wire_format(*s, p, len, false);
799 if (r < 0)
800 return r;
801
802 if (len < (size_t)r)
803 return -ENOBUFS;
804
805 p += r;
806 len -= r;
807 }
808
1cc6c93a 809 free_and_replace(ra->dnssl, opt_dnssl);
e965d6ab
PF
810
811 return 0;
812}
813
04473969 814_public_ int sd_radv_prefix_new(sd_radv_prefix **ret) {
d2c8eed2 815 sd_radv_prefix *p;
04473969
PF
816
817 assert_return(ret, -EINVAL);
818
d2c8eed2 819 p = new(sd_radv_prefix, 1);
04473969
PF
820 if (!p)
821 return -ENOMEM;
822
d2c8eed2
LP
823 *p = (sd_radv_prefix) {
824 .n_ref = 1,
04473969 825
d2c8eed2
LP
826 .opt.type = ND_OPT_PREFIX_INFORMATION,
827 .opt.length = (sizeof(p->opt) - 1)/8 + 1,
828 .opt.prefixlen = 64,
04473969 829
d2c8eed2
LP
830 /* RFC 4861, Section 6.2.1 */
831 .opt.flags = ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO,
204f99d2 832
d2c8eed2
LP
833 .opt.preferred_lifetime = htobe32(604800),
834 .opt.valid_lifetime = htobe32(2592000),
835 };
04473969 836
d2c8eed2 837 *ret = p;
04473969
PF
838 return 0;
839}
840
8301aa0b 841DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv_prefix, sd_radv_prefix, mfree);
04473969 842
f5a5706a 843_public_ int sd_radv_prefix_set_prefix(sd_radv_prefix *p, const struct in6_addr *in6_addr,
04473969
PF
844 unsigned char prefixlen) {
845 assert_return(p, -EINVAL);
846 assert_return(in6_addr, -EINVAL);
847
848 if (prefixlen < 3 || prefixlen > 128)
849 return -EINVAL;
850
851 if (prefixlen > 64)
852 /* unusual but allowed, log it */
35388783 853 log_radv(NULL, "Unusual prefix length %d greater than 64", prefixlen);
04473969
PF
854
855 p->opt.in6_addr = *in6_addr;
856 p->opt.prefixlen = prefixlen;
857
858 return 0;
859}
860
34332af2
SS
861_public_ int sd_radv_prefix_get_prefix(sd_radv_prefix *p, struct in6_addr *ret_in6_addr,
862 unsigned char *ret_prefixlen) {
863 assert_return(p, -EINVAL);
864 assert_return(ret_in6_addr, -EINVAL);
865 assert_return(ret_prefixlen, -EINVAL);
866
867 *ret_in6_addr = p->opt.in6_addr;
868 *ret_prefixlen = p->opt.prefixlen;
869
870 return 0;
871}
872
04473969
PF
873_public_ int sd_radv_prefix_set_onlink(sd_radv_prefix *p, int onlink) {
874 assert_return(p, -EINVAL);
875
876 SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_ONLINK, onlink);
877
878 return 0;
879}
880
881_public_ int sd_radv_prefix_set_address_autoconfiguration(sd_radv_prefix *p,
882 int address_autoconfiguration) {
883 assert_return(p, -EINVAL);
884
885 SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_AUTO, address_autoconfiguration);
886
887 return 0;
888}
889
890_public_ int sd_radv_prefix_set_valid_lifetime(sd_radv_prefix *p,
891 uint32_t valid_lifetime) {
892 assert_return(p, -EINVAL);
893
894 p->opt.valid_lifetime = htobe32(valid_lifetime);
895
896 return 0;
897}
898
899_public_ int sd_radv_prefix_set_preferred_lifetime(sd_radv_prefix *p,
900 uint32_t preferred_lifetime) {
901 assert_return(p, -EINVAL);
902
903 p->opt.preferred_lifetime = htobe32(preferred_lifetime);
904
905 return 0;
906}
203d4df5
SS
907
908_public_ int sd_radv_route_prefix_new(sd_radv_route_prefix **ret) {
909 sd_radv_route_prefix *p;
910
911 assert_return(ret, -EINVAL);
912
913 p = new(sd_radv_route_prefix, 1);
914 if (!p)
915 return -ENOMEM;
916
917 *p = (sd_radv_route_prefix) {
918 .n_ref = 1,
919
920 .opt.type = SD_RADV_OPT_ROUTE_INFORMATION,
921 .opt.length = DIV_ROUND_UP(sizeof(p->opt), 8),
922 .opt.prefixlen = 64,
923
924 .opt.lifetime = htobe32(604800),
925 };
926
927 *ret = p;
928 return 0;
929}
930
931DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv_route_prefix, sd_radv_route_prefix, mfree);
932
933_public_ int sd_radv_prefix_set_route_prefix(sd_radv_route_prefix *p, const struct in6_addr *in6_addr,
934 unsigned char prefixlen) {
935 assert_return(p, -EINVAL);
936 assert_return(in6_addr, -EINVAL);
937
938 if (prefixlen > 128)
939 return -EINVAL;
940
941 if (prefixlen > 64)
942 /* unusual but allowed, log it */
35388783 943 log_radv(NULL, "Unusual prefix length %u greater than 64", prefixlen);
203d4df5
SS
944
945 p->opt.in6_addr = *in6_addr;
946 p->opt.prefixlen = prefixlen;
947
948 return 0;
949}
950
951_public_ int sd_radv_route_prefix_set_lifetime(sd_radv_route_prefix *p, uint32_t valid_lifetime) {
952 assert_return(p, -EINVAL);
953
954 p->opt.lifetime = htobe32(valid_lifetime);
955
956 return 0;
957}