]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/sd-radv.c
sd-radv: fix memory leak
[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"
1925f829 28#include "unaligned.h"
04473969 29
17347053 30int sd_radv_new(sd_radv **ret) {
204f99d2
PF
31 _cleanup_(sd_radv_unrefp) sd_radv *ra = NULL;
32
33 assert_return(ret, -EINVAL);
34
78f9d24f 35 ra = new(sd_radv, 1);
204f99d2
PF
36 if (!ra)
37 return -ENOMEM;
38
78f9d24f
YW
39 *ra = (sd_radv) {
40 .n_ref = 1,
254d1313 41 .fd = -EBADF,
72db0a71 42 .lifetime_usec = RADV_DEFAULT_ROUTER_LIFETIME_USEC,
78f9d24f 43 };
204f99d2 44
1cc6c93a 45 *ret = TAKE_PTR(ra);
204f99d2
PF
46
47 return 0;
48}
49
17347053 50int sd_radv_attach_event(sd_radv *ra, sd_event *event, int64_t priority) {
204f99d2
PF
51 int r;
52
53 assert_return(ra, -EINVAL);
54 assert_return(!ra->event, -EBUSY);
55
56 if (event)
57 ra->event = sd_event_ref(event);
58 else {
59 r = sd_event_default(&ra->event);
60 if (r < 0)
61 return 0;
62 }
63
64 ra->event_priority = priority;
65
66 return 0;
67}
68
17347053 69int sd_radv_detach_event(sd_radv *ra) {
204f99d2
PF
70
71 assert_return(ra, -EINVAL);
72
73 ra->event = sd_event_unref(ra->event);
74 return 0;
75}
76
17347053 77sd_event *sd_radv_get_event(sd_radv *ra) {
204f99d2
PF
78 assert_return(ra, NULL);
79
80 return ra->event;
81}
82
17347053 83int sd_radv_is_running(sd_radv *ra) {
96fe813c
YW
84 assert_return(ra, false);
85
d6fc0d67 86 return ra->state != RADV_STATE_IDLE;
96fe813c
YW
87}
88
204fb681 89static void radv_reset(sd_radv *ra) {
c4b6dda0 90 assert(ra);
204fb681 91
807a8ede 92 (void) event_source_disable(ra->timeout_event_source);
204fb681 93
eb2f7502 94 ra->recv_event_source = sd_event_source_disable_unref(ra->recv_event_source);
88d5a3db 95
204fb681
PF
96 ra->ra_sent = 0;
97}
98
8301aa0b 99static sd_radv *radv_free(sd_radv *ra) {
e866e17b
LP
100 if (!ra)
101 return NULL;
204f99d2 102
9aad490e
DT
103 LIST_CLEAR(prefix, ra->prefixes, sd_radv_prefix_unref);
104 LIST_CLEAR(prefix, ra->route_prefixes, sd_radv_route_prefix_unref);
1a6b1214 105 LIST_CLEAR(prefix, ra->pref64_prefixes, sd_radv_pref64_prefix_unref);
69d7eba1 106
e9c6da38 107 free(ra->rdnss);
f9aa5417 108 free(ra->dnssl);
e9c6da38 109
204fb681
PF
110 radv_reset(ra);
111
eb2f7502 112 sd_event_source_unref(ra->timeout_event_source);
204f99d2 113 sd_radv_detach_event(ra);
c4b6dda0
LP
114
115 ra->fd = safe_close(ra->fd);
61a9fa8f 116 free(ra->ifname);
c4b6dda0 117
204f99d2
PF
118 return mfree(ra);
119}
120
8301aa0b
YW
121DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv, sd_radv, radv_free);
122
09457670
YW
123static bool router_lifetime_is_valid(usec_t lifetime_usec) {
124 return lifetime_usec == 0 ||
125 (lifetime_usec >= RADV_MIN_ROUTER_LIFETIME_USEC &&
126 lifetime_usec <= RADV_MAX_ROUTER_LIFETIME_USEC);
127}
128
95e104e0
YW
129static be32_t usec_to_be32_sec(usec_t usec) {
130 if (usec == USEC_INFINITY)
131 /* UINT32_MAX is handled as infinity. */
132 return htobe32(UINT32_MAX);
133
134 if (usec >= UINT32_MAX * USEC_PER_SEC)
135 /* Finite but too large. Let's use the largest finite value. */
136 return htobe32(UINT32_MAX - 1);
137
138 return htobe32(usec / USEC_PER_SEC);
139}
140
7003b114 141static int radv_send(sd_radv *ra, const struct in6_addr *dst, usec_t lifetime_usec) {
77baf5ae
PF
142 struct sockaddr_in6 dst_addr = {
143 .sin6_family = AF_INET6,
144 .sin6_addr = IN6ADDR_ALL_NODES_MULTICAST_INIT,
145 };
146 struct nd_router_advert adv = {};
147 struct {
148 struct nd_opt_hdr opthdr;
149 struct ether_addr slladdr;
150 } _packed_ opt_mac = {
151 .opthdr = {
152 .nd_opt_type = ND_OPT_SOURCE_LINKADDR,
153 .nd_opt_len = (sizeof(struct nd_opt_hdr) +
154 sizeof(struct ether_addr) - 1) /8 + 1,
155 },
156 };
157 struct nd_opt_mtu opt_mtu = {
158 .nd_opt_mtu_type = ND_OPT_MTU,
159 .nd_opt_mtu_len = 1,
160 };
203d4df5 161 /* Reserve iov space for RA header, linkaddr, MTU, N prefixes, N routes, RDNSS
6852c0f6 162 and DNSSL */
203d4df5 163 struct iovec iov[5 + ra->n_prefixes + ra->n_route_prefixes];
77baf5ae
PF
164 struct msghdr msg = {
165 .msg_name = &dst_addr,
166 .msg_namelen = sizeof(dst_addr),
167 .msg_iov = iov,
168 };
d601b566
PF
169 usec_t time_now;
170 int r;
171
dc0ec5e2 172 assert(ra);
09457670 173 assert(router_lifetime_is_valid(lifetime_usec));
dc0ec5e2 174
ba4e0427 175 r = sd_event_now(ra->event, CLOCK_BOOTTIME, &time_now);
d601b566
PF
176 if (r < 0)
177 return r;
77baf5ae 178
94876904 179 if (dst && in6_addr_is_set(dst))
77baf5ae 180 dst_addr.sin6_addr = *dst;
88d5a3db 181
77baf5ae
PF
182 adv.nd_ra_type = ND_ROUTER_ADVERT;
183 adv.nd_ra_curhoplimit = ra->hop_limit;
fdc4c67c 184 adv.nd_ra_retransmit = htobe32(ra->retransmit_msec);
77baf5ae 185 adv.nd_ra_flags_reserved = ra->flags;
09457670
YW
186 assert_cc(RADV_MAX_ROUTER_LIFETIME_USEC <= UINT16_MAX * USEC_PER_SEC);
187 adv.nd_ra_router_lifetime = htobe16(DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC));
5cfa2c3d 188 iov[msg.msg_iovlen++] = IOVEC_MAKE(&adv, sizeof(adv));
77baf5ae
PF
189
190 /* MAC address is optional, either because the link does not use L2
191 addresses or load sharing is desired. See RFC 4861, Section 4.2 */
ae25915d 192 if (!ether_addr_is_null(&ra->mac_addr)) {
77baf5ae 193 opt_mac.slladdr = ra->mac_addr;
5cfa2c3d 194 iov[msg.msg_iovlen++] = IOVEC_MAKE(&opt_mac, sizeof(opt_mac));
77baf5ae
PF
195 }
196
41521417 197 if (ra->mtu > 0) {
77baf5ae 198 opt_mtu.nd_opt_mtu_mtu = htobe32(ra->mtu);
5cfa2c3d 199 iov[msg.msg_iovlen++] = IOVEC_MAKE(&opt_mtu, sizeof(opt_mtu));
77baf5ae
PF
200 }
201
202 LIST_FOREACH(prefix, p, ra->prefixes) {
95e104e0 203 usec_t lifetime_valid_usec, lifetime_preferred_usec;
d601b566 204
95e104e0
YW
205 lifetime_valid_usec = MIN(usec_sub_unsigned(p->valid_until, time_now),
206 p->lifetime_valid_usec);
207
208 lifetime_preferred_usec = MIN3(usec_sub_unsigned(p->preferred_until, time_now),
209 p->lifetime_preferred_usec,
210 lifetime_valid_usec);
211
212 p->opt.lifetime_valid = usec_to_be32_sec(lifetime_valid_usec);
213 p->opt.lifetime_preferred = usec_to_be32_sec(lifetime_preferred_usec);
d601b566 214
5cfa2c3d 215 iov[msg.msg_iovlen++] = IOVEC_MAKE(&p->opt, sizeof(p->opt));
77baf5ae
PF
216 }
217
95e104e0
YW
218 LIST_FOREACH(prefix, rt, ra->route_prefixes) {
219 rt->opt.lifetime = usec_to_be32_sec(MIN(usec_sub_unsigned(rt->valid_until, time_now),
220 rt->lifetime_usec));
221
203d4df5 222 iov[msg.msg_iovlen++] = IOVEC_MAKE(&rt->opt, sizeof(rt->opt));
95e104e0 223 }
203d4df5 224
1925f829
SS
225 LIST_FOREACH(prefix, p, ra->pref64_prefixes)
226 iov[msg.msg_iovlen++] = IOVEC_MAKE(&p->opt, sizeof(p->opt));
227
5cfa2c3d
LP
228 if (ra->rdnss)
229 iov[msg.msg_iovlen++] = IOVEC_MAKE(ra->rdnss, ra->rdnss->length * 8);
e9c6da38 230
5cfa2c3d
LP
231 if (ra->dnssl)
232 iov[msg.msg_iovlen++] = IOVEC_MAKE(ra->dnssl, ra->dnssl->length * 8);
e965d6ab 233
77baf5ae
PF
234 if (sendmsg(ra->fd, &msg, 0) < 0)
235 return -errno;
204fb681 236
77baf5ae 237 return 0;
204fb681
PF
238}
239
88d5a3db 240static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
99534007 241 sd_radv *ra = ASSERT_PTR(userdata);
88d5a3db
PF
242 struct in6_addr src;
243 triple_timestamp timestamp;
244 int r;
88d5a3db
PF
245
246 assert(s);
88d5a3db
PF
247 assert(ra->event);
248
dd6d433a 249 ssize_t buflen = next_datagram_size_fd(fd);
1f2db2e3
ZJS
250 if (ERRNO_IS_NEG_TRANSIENT(buflen) || ERRNO_IS_NEG_DISCONNECT(buflen))
251 return 0;
ab8a8a4e 252 if (buflen < 0) {
ab8a8a4e
YW
253 log_radv_errno(ra, buflen, "Failed to determine datagram size to read, ignoring: %m");
254 return 0;
255 }
88d5a3db 256
dd6d433a 257 _cleanup_free_ char *buf = new0(char, buflen);
88d5a3db 258 if (!buf)
e55a6eae 259 return -ENOMEM;
88d5a3db
PF
260
261 r = icmp6_receive(fd, buf, buflen, &src, &timestamp);
1f2db2e3
ZJS
262 if (ERRNO_IS_NEG_TRANSIENT(r) || ERRNO_IS_NEG_DISCONNECT(r))
263 return 0;
264 if (r < 0)
88d5a3db
PF
265 switch (r) {
266 case -EADDRNOTAVAIL:
84dbb3fd
ZJS
267 log_radv(ra, "Received RS from non-link-local address %s. Ignoring",
268 IN6_ADDR_TO_STRING(&src));
1f2db2e3 269 return 0;
88d5a3db
PF
270
271 case -EMULTIHOP:
35388783 272 log_radv(ra, "Received RS with invalid hop limit. Ignoring.");
1f2db2e3 273 return 0;
88d5a3db
PF
274
275 case -EPFNOSUPPORT:
35388783 276 log_radv(ra, "Received invalid source address from ICMPv6 socket. Ignoring.");
1f2db2e3 277 return 0;
88d5a3db
PF
278
279 default:
ab8a8a4e 280 log_radv_errno(ra, r, "Unexpected error receiving from ICMPv6 socket, ignoring: %m");
1f2db2e3 281 return 0;
88d5a3db
PF
282 }
283
cfffddea 284 if ((size_t) buflen < sizeof(struct nd_router_solicit)) {
35388783 285 log_radv(ra, "Too short packet received, ignoring");
cfffddea
LP
286 return 0;
287 }
288
84dbb3fd 289 const char *addr = IN6_ADDR_TO_STRING(&src);
88d5a3db 290
7003b114 291 r = radv_send(ra, &src, ra->lifetime_usec);
88d5a3db 292 if (r < 0)
84dbb3fd 293 log_radv_errno(ra, r, "Unable to send solicited Router Advertisement to %s, ignoring: %m", addr);
88d5a3db 294 else
84dbb3fd 295 log_radv(ra, "Sent solicited Router Advertisement to %s", addr);
88d5a3db
PF
296
297 return 0;
298}
299
204fb681 300static int radv_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
7003b114 301 usec_t min_timeout, max_timeout, time_now, timeout;
99534007 302 sd_radv *ra = ASSERT_PTR(userdata);
7003b114 303 int r;
204fb681
PF
304
305 assert(s);
204fb681 306 assert(ra->event);
80477557 307 assert(router_lifetime_is_valid(ra->lifetime_usec));
204fb681 308
ba4e0427 309 r = sd_event_now(ra->event, CLOCK_BOOTTIME, &time_now);
204fb681
PF
310 if (r < 0)
311 goto fail;
312
7003b114 313 r = radv_send(ra, NULL, ra->lifetime_usec);
204fb681 314 if (r < 0)
abb977a6 315 log_radv_errno(ra, r, "Unable to send Router Advertisement, ignoring: %m");
204fb681
PF
316
317 /* RFC 4861, Section 6.2.4, sending initial Router Advertisements */
80477557 318 if (ra->ra_sent < RADV_MAX_INITIAL_RTR_ADVERTISEMENTS)
d6fc0d67 319 max_timeout = RADV_MAX_INITIAL_RTR_ADVERT_INTERVAL_USEC;
80477557 320 else
03ec10fd 321 max_timeout = RADV_DEFAULT_MAX_TIMEOUT_USEC;
204fb681 322
ef90b6a4 323 /* RFC 4861, Section 6.2.1, lifetime must be at least MaxRtrAdvInterval,
80477557
YW
324 * so lower the interval here */
325 if (ra->lifetime_usec > 0)
326 max_timeout = MIN(max_timeout, ra->lifetime_usec);
327
328 if (max_timeout >= 9 * USEC_PER_SEC)
ef90b6a4 329 min_timeout = max_timeout / 3;
80477557
YW
330 else
331 min_timeout = max_timeout * 3 / 4;
ef90b6a4 332
80477557
YW
333 /* RFC 4861, Section 6.2.1.
334 * MaxRtrAdvInterval MUST be no less than 4 seconds and no greater than 1800 seconds.
335 * MinRtrAdvInterval MUST be no less than 3 seconds and no greater than .75 * MaxRtrAdvInterval. */
336 assert(max_timeout >= RADV_MIN_MAX_TIMEOUT_USEC);
337 assert(max_timeout <= RADV_MAX_MAX_TIMEOUT_USEC);
338 assert(min_timeout >= RADV_MIN_MIN_TIMEOUT_USEC);
339 assert(min_timeout <= max_timeout * 3 / 4);
ef90b6a4 340
80477557 341 timeout = min_timeout + random_u64_range(max_timeout - min_timeout);
5291f26d 342 log_radv(ra, "Next Router Advertisement in %s", FORMAT_TIMESPAN(timeout, USEC_PER_SEC));
204fb681 343
807a8ede 344 r = event_reset_time(ra->event, &ra->timeout_event_source,
ba4e0427 345 CLOCK_BOOTTIME,
80477557 346 usec_add(time_now, timeout), MSEC_PER_SEC,
807a8ede
YW
347 radv_timeout, ra,
348 ra->event_priority, "radv-timeout", true);
204fb681
PF
349 if (r < 0)
350 goto fail;
351
352 ra->ra_sent++;
353
807a8ede
YW
354 return 0;
355
204fb681 356fail:
290696e5 357 sd_radv_stop(ra);
204fb681
PF
358
359 return 0;
360}
361
17347053 362int sd_radv_stop(sd_radv *ra) {
204fb681
PF
363 int r;
364
c8bae363
YW
365 if (!ra)
366 return 0;
204f99d2 367
d6fc0d67 368 if (ra->state == RADV_STATE_IDLE)
6f8a8b84
SS
369 return 0;
370
35388783 371 log_radv(ra, "Stopping IPv6 Router Advertisement daemon");
204f99d2 372
290696e5
YW
373 /* RFC 4861, Section 6.2.5, send at least one Router Advertisement
374 with zero lifetime */
375 r = radv_send(ra, NULL, 0);
376 if (r < 0)
abb977a6 377 log_radv_errno(ra, r, "Unable to send last Router Advertisement with router lifetime set to zero, ignoring: %m");
204fb681
PF
378
379 radv_reset(ra);
77baf5ae 380 ra->fd = safe_close(ra->fd);
d6fc0d67 381 ra->state = RADV_STATE_IDLE;
204f99d2
PF
382
383 return 0;
384}
385
17347053 386int sd_radv_start(sd_radv *ra) {
f474884c 387 int r;
204fb681 388
204f99d2
PF
389 assert_return(ra, -EINVAL);
390 assert_return(ra->event, -EINVAL);
391 assert_return(ra->ifindex > 0, -EINVAL);
392
d6fc0d67 393 if (ra->state != RADV_STATE_IDLE)
204f99d2
PF
394 return 0;
395
807a8ede 396 r = event_reset_time(ra->event, &ra->timeout_event_source,
ba4e0427 397 CLOCK_BOOTTIME,
807a8ede
YW
398 0, 0,
399 radv_timeout, ra,
400 ra->event_priority, "radv-timeout", true);
204fb681
PF
401 if (r < 0)
402 goto fail;
403
77baf5ae
PF
404 r = icmp6_bind_router_advertisement(ra->ifindex);
405 if (r < 0)
406 goto fail;
407
408 ra->fd = r;
88d5a3db
PF
409
410 r = sd_event_add_io(ra->event, &ra->recv_event_source, ra->fd, EPOLLIN, radv_recv, ra);
411 if (r < 0)
412 goto fail;
413
414 r = sd_event_source_set_priority(ra->recv_event_source, ra->event_priority);
415 if (r < 0)
416 goto fail;
417
418 (void) sd_event_source_set_description(ra->recv_event_source, "radv-receive-message");
77baf5ae 419
d6fc0d67 420 ra->state = RADV_STATE_ADVERTISING;
204f99d2 421
35388783 422 log_radv(ra, "Started IPv6 Router Advertisement daemon");
204f99d2
PF
423
424 return 0;
204fb681
PF
425
426 fail:
427 radv_reset(ra);
428
429 return r;
204f99d2
PF
430}
431
17347053 432int sd_radv_set_ifindex(sd_radv *ra, int ifindex) {
204f99d2 433 assert_return(ra, -EINVAL);
7fa69c0a 434 assert_return(ifindex > 0, -EINVAL);
204f99d2 435
d6fc0d67 436 if (ra->state != RADV_STATE_IDLE)
204f99d2
PF
437 return -EBUSY;
438
439 ra->ifindex = ifindex;
440
441 return 0;
442}
443
61a9fa8f
YW
444int sd_radv_set_ifname(sd_radv *ra, const char *ifname) {
445 assert_return(ra, -EINVAL);
446 assert_return(ifname, -EINVAL);
447
448 if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE))
449 return -EINVAL;
450
451 return free_and_strdup(&ra->ifname, ifname);
452}
453
5977b71f
YW
454int sd_radv_get_ifname(sd_radv *ra, const char **ret) {
455 int r;
456
457 assert_return(ra, -EINVAL);
61a9fa8f 458
5977b71f
YW
459 r = get_ifname(ra->ifindex, &ra->ifname);
460 if (r < 0)
461 return r;
462
463 if (ret)
464 *ret = ra->ifname;
465
466 return 0;
61a9fa8f
YW
467}
468
17347053 469int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr) {
204f99d2
PF
470 assert_return(ra, -EINVAL);
471
d6fc0d67 472 if (ra->state != RADV_STATE_IDLE)
204f99d2
PF
473 return -EBUSY;
474
475 if (mac_addr)
476 ra->mac_addr = *mac_addr;
477 else
478 zero(ra->mac_addr);
479
480 return 0;
481}
482
17347053 483int sd_radv_set_mtu(sd_radv *ra, uint32_t mtu) {
204f99d2
PF
484 assert_return(ra, -EINVAL);
485 assert_return(mtu >= 1280, -EINVAL);
486
204f99d2
PF
487 ra->mtu = mtu;
488
489 return 0;
490}
491
17347053 492int sd_radv_set_hop_limit(sd_radv *ra, uint8_t hop_limit) {
204f99d2
PF
493 assert_return(ra, -EINVAL);
494
d6fc0d67 495 if (ra->state != RADV_STATE_IDLE)
204f99d2
PF
496 return -EBUSY;
497
498 ra->hop_limit = hop_limit;
499
500 return 0;
501}
502
fdc4c67c
SS
503int sd_radv_set_retransmit(sd_radv *ra, uint32_t retransmit_msec) {
504 assert_return(ra, -EINVAL);
505
506 if (ra->state != RADV_STATE_IDLE)
507 return -EBUSY;
508
509 ra->retransmit_msec = retransmit_msec;
510
511 return 0;
512}
513
17347053 514int sd_radv_set_router_lifetime(sd_radv *ra, uint64_t lifetime_usec) {
204f99d2
PF
515 assert_return(ra, -EINVAL);
516
d6fc0d67 517 if (ra->state != RADV_STATE_IDLE)
204f99d2
PF
518 return -EBUSY;
519
09457670
YW
520 if (!router_lifetime_is_valid(lifetime_usec))
521 return -EINVAL;
522
ac138551
YW
523 /* RFC 4191, Section 2.2, "...If the Router Lifetime is zero, the preference value MUST be set
524 * to (00) by the sender..." */
7003b114 525 if (lifetime_usec == 0 &&
204f99d2 526 (ra->flags & (0x3 << 3)) != (SD_NDISC_PREFERENCE_MEDIUM << 3))
09457670 527 return -EINVAL;
204f99d2 528
7003b114 529 ra->lifetime_usec = lifetime_usec;
204f99d2
PF
530
531 return 0;
532}
533
17347053 534int sd_radv_set_managed_information(sd_radv *ra, int managed) {
204f99d2
PF
535 assert_return(ra, -EINVAL);
536
d6fc0d67 537 if (ra->state != RADV_STATE_IDLE)
204f99d2
PF
538 return -EBUSY;
539
540 SET_FLAG(ra->flags, ND_RA_FLAG_MANAGED, managed);
541
542 return 0;
543}
544
17347053 545int sd_radv_set_other_information(sd_radv *ra, int other) {
204f99d2
PF
546 assert_return(ra, -EINVAL);
547
d6fc0d67 548 if (ra->state != RADV_STATE_IDLE)
204f99d2
PF
549 return -EBUSY;
550
551 SET_FLAG(ra->flags, ND_RA_FLAG_OTHER, other);
552
553 return 0;
554}
555
17347053 556int sd_radv_set_preference(sd_radv *ra, unsigned preference) {
204f99d2
PF
557 assert_return(ra, -EINVAL);
558 assert_return(IN_SET(preference,
559 SD_NDISC_PREFERENCE_LOW,
560 SD_NDISC_PREFERENCE_MEDIUM,
561 SD_NDISC_PREFERENCE_HIGH), -EINVAL);
562
dd1b1870
YW
563 /* RFC 4191, Section 2.2, "...If the Router Lifetime is zero, the preference value MUST be set
564 * to (00) by the sender..." */
7003b114 565 if (ra->lifetime_usec == 0 && preference != SD_NDISC_PREFERENCE_MEDIUM)
dd1b1870
YW
566 return -EINVAL;
567
204f99d2
PF
568 ra->flags = (ra->flags & ~(0x3 << 3)) | (preference << 3);
569
dd1b1870 570 return 0;
204f99d2
PF
571}
572
17347053 573int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p) {
03677889 574 sd_radv_prefix *found = NULL;
d601b566 575 int r;
204f99d2
PF
576
577 assert_return(ra, -EINVAL);
acbb5500 578 assert_return(p, -EINVAL);
204f99d2 579
59ea6e57 580 /* Refuse prefixes that don't have a prefix set */
94876904 581 if (in6_addr_is_null(&p->opt.in6_addr))
59ea6e57
LP
582 return -ENOEXEC;
583
c71384a9 584 const char *addr_p = IN6_ADDR_PREFIX_TO_STRING(&p->opt.in6_addr, p->opt.prefixlen);
5380707a 585
204f99d2 586 LIST_FOREACH(prefix, cur, ra->prefixes) {
204f99d2 587 r = in_addr_prefix_intersect(AF_INET6,
c633628d 588 (const union in_addr_union*) &cur->opt.in6_addr,
204f99d2 589 cur->opt.prefixlen,
c633628d 590 (const union in_addr_union*) &p->opt.in6_addr,
204f99d2 591 p->opt.prefixlen);
5380707a
YW
592 if (r < 0)
593 return r;
594 if (r == 0)
595 continue;
204f99d2 596
95e104e0 597 if (cur->opt.prefixlen == p->opt.prefixlen) {
56aa5143 598 found = cur;
b9f27a05 599 break;
95e104e0 600 }
d601b566 601
35388783 602 return log_radv_errno(ra, SYNTHETIC_ERRNO(EEXIST),
95e104e0 603 "IPv6 prefix %s conflicts with %s, ignoring.",
c71384a9
ZJS
604 addr_p,
605 IN6_ADDR_PREFIX_TO_STRING(&cur->opt.in6_addr, cur->opt.prefixlen));
204f99d2
PF
606 }
607
56aa5143 608 if (found) {
b9f27a05
YW
609 /* p and cur may be equivalent. First increment the reference counter. */
610 sd_radv_prefix_ref(p);
611
612 /* Then, remove the old entry. */
56aa5143
YW
613 LIST_REMOVE(prefix, ra->prefixes, found);
614 sd_radv_prefix_unref(found);
b9f27a05
YW
615
616 /* Finally, add the new entry. */
617 LIST_APPEND(prefix, ra->prefixes, p);
618
619 log_radv(ra, "Updated/replaced IPv6 prefix %s (preferred: %s, valid: %s)",
c71384a9 620 addr_p,
b9f27a05
YW
621 FORMAT_TIMESPAN(p->lifetime_preferred_usec, USEC_PER_SEC),
622 FORMAT_TIMESPAN(p->lifetime_valid_usec, USEC_PER_SEC));
623 } else {
624 /* The prefix is new. Let's simply add it. */
625
626 sd_radv_prefix_ref(p);
627 LIST_APPEND(prefix, ra->prefixes, p);
628 ra->n_prefixes++;
204f99d2 629
c71384a9 630 log_radv(ra, "Added prefix %s", addr_p);
b9f27a05 631 }
059d7b6e
YW
632
633 if (ra->state == RADV_STATE_IDLE)
634 return 0;
635
059d7b6e 636 if (ra->ra_sent == 0)
d601b566 637 return 0;
d601b566 638
97efde65 639 /* If RAs have already been sent, send an RA immediately to announce the newly-added prefix */
059d7b6e
YW
640 r = radv_send(ra, NULL, ra->lifetime_usec);
641 if (r < 0)
abb977a6 642 log_radv_errno(ra, r, "Unable to send Router Advertisement for added prefix %s, ignoring: %m", addr_p);
059d7b6e 643 else
c71384a9 644 log_radv(ra, "Sent Router Advertisement for added/updated prefix %s.", addr_p);
97efde65 645
204f99d2
PF
646 return 0;
647}
648
95931532
YW
649void sd_radv_remove_prefix(
650 sd_radv *ra,
651 const struct in6_addr *prefix,
652 unsigned char prefixlen) {
34c169c4 653
95931532
YW
654 if (!ra)
655 return;
34c169c4 656
95931532
YW
657 if (!prefix)
658 return;
659
660 LIST_FOREACH(prefix, cur, ra->prefixes) {
34c169c4
PF
661 if (prefixlen != cur->opt.prefixlen)
662 continue;
663
94876904 664 if (!in6_addr_equal(prefix, &cur->opt.in6_addr))
34c169c4
PF
665 continue;
666
667 LIST_REMOVE(prefix, ra->prefixes, cur);
668 ra->n_prefixes--;
62bbbedf 669 sd_radv_prefix_unref(cur);
95931532 670 return;
34c169c4 671 }
34c169c4
PF
672}
673
17347053 674int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p) {
03677889 675 sd_radv_route_prefix *found = NULL;
203d4df5
SS
676 int r;
677
678 assert_return(ra, -EINVAL);
acbb5500 679 assert_return(p, -EINVAL);
203d4df5 680
c71384a9 681 const char *addr_p = IN6_ADDR_PREFIX_TO_STRING(&p->opt.in6_addr, p->opt.prefixlen);
203d4df5
SS
682
683 LIST_FOREACH(prefix, cur, ra->route_prefixes) {
203d4df5 684 r = in_addr_prefix_intersect(AF_INET6,
c633628d 685 (const union in_addr_union*) &cur->opt.in6_addr,
203d4df5 686 cur->opt.prefixlen,
c633628d 687 (const union in_addr_union*) &p->opt.in6_addr,
203d4df5
SS
688 p->opt.prefixlen);
689 if (r < 0)
690 return r;
691 if (r == 0)
692 continue;
693
95e104e0 694 if (cur->opt.prefixlen == p->opt.prefixlen) {
56aa5143 695 found = cur;
b9f27a05 696 break;
95e104e0 697 }
203d4df5 698
35388783 699 return log_radv_errno(ra, SYNTHETIC_ERRNO(EEXIST),
95e104e0 700 "IPv6 route prefix %s conflicts with %s, ignoring.",
c71384a9
ZJS
701 addr_p,
702 IN6_ADDR_PREFIX_TO_STRING(&cur->opt.in6_addr, cur->opt.prefixlen));
203d4df5
SS
703 }
704
56aa5143 705 if (found) {
b9f27a05
YW
706 /* p and cur may be equivalent. First increment the reference counter. */
707 sd_radv_route_prefix_ref(p);
708
709 /* Then, remove the old entry. */
56aa5143
YW
710 LIST_REMOVE(prefix, ra->route_prefixes, found);
711 sd_radv_route_prefix_unref(found);
b9f27a05
YW
712
713 /* Finally, add the new entry. */
714 LIST_APPEND(prefix, ra->route_prefixes, p);
715
716 log_radv(ra, "Updated/replaced IPv6 route prefix %s (lifetime: %s)",
717 strna(addr_p),
718 FORMAT_TIMESPAN(p->lifetime_usec, USEC_PER_SEC));
719 } else {
720 /* The route prefix is new. Let's simply add it. */
721
722 sd_radv_route_prefix_ref(p);
723 LIST_APPEND(prefix, ra->route_prefixes, p);
724 ra->n_route_prefixes++;
725
726 log_radv(ra, "Added route prefix %s", strna(addr_p));
727 }
059d7b6e
YW
728
729 if (ra->state == RADV_STATE_IDLE)
730 return 0;
731
059d7b6e 732 if (ra->ra_sent == 0)
203d4df5 733 return 0;
203d4df5 734
97efde65 735 /* If RAs have already been sent, send an RA immediately to announce the newly-added route prefix */
059d7b6e
YW
736 r = radv_send(ra, NULL, ra->lifetime_usec);
737 if (r < 0)
abb977a6 738 log_radv_errno(ra, r, "Unable to send Router Advertisement for added route prefix %s, ignoring: %m",
b9f27a05 739 strna(addr_p));
059d7b6e 740 else
b9f27a05 741 log_radv(ra, "Sent Router Advertisement for added route prefix %s.", strna(addr_p));
97efde65 742
203d4df5
SS
743 return 0;
744}
745
1925f829
SS
746int sd_radv_add_pref64_prefix(sd_radv *ra, sd_radv_pref64_prefix *p) {
747 sd_radv_pref64_prefix *found = NULL;
748 int r;
749
750 assert_return(ra, -EINVAL);
751 assert_return(p, -EINVAL);
752
753 const char *addr_p = IN6_ADDR_PREFIX_TO_STRING(&p->in6_addr, p->prefixlen);
754
755 LIST_FOREACH(prefix, cur, ra->pref64_prefixes) {
756 r = in_addr_prefix_intersect(AF_INET6,
757 (const union in_addr_union*) &cur->in6_addr,
758 cur->prefixlen,
759 (const union in_addr_union*) &p->in6_addr,
760 p->prefixlen);
761 if (r < 0)
762 return r;
763 if (r == 0)
764 continue;
765
766 if (cur->prefixlen == p->prefixlen) {
767 found = cur;
768 break;
769 }
770
771 return log_radv_errno(ra, SYNTHETIC_ERRNO(EEXIST),
772 "IPv6 PREF64 prefix %s conflicts with %s, ignoring.",
773 addr_p,
774 IN6_ADDR_PREFIX_TO_STRING(&cur->in6_addr, cur->prefixlen));
775 }
776
777 if (found) {
778 /* p and cur may be equivalent. First increment the reference counter. */
779 sd_radv_pref64_prefix_ref(p);
780
781 /* Then, remove the old entry. */
782 LIST_REMOVE(prefix, ra->pref64_prefixes, found);
783 sd_radv_pref64_prefix_unref(found);
784
785 /* Finally, add the new entry. */
786 LIST_APPEND(prefix, ra->pref64_prefixes, p);
787
788 log_radv(ra, "Updated/replaced IPv6 PREF64 prefix %s (lifetime: %s)",
789 strna(addr_p),
790 FORMAT_TIMESPAN(p->lifetime_usec, USEC_PER_SEC));
791 } else {
792 /* The route prefix is new. Let's simply add it. */
793
794 sd_radv_pref64_prefix_ref(p);
795 LIST_APPEND(prefix, ra->pref64_prefixes, p);
796 ra->n_pref64_prefixes++;
797
798 log_radv(ra, "Added PREF64 prefix %s", strna(addr_p));
799 }
800
801 if (ra->state == RADV_STATE_IDLE)
802 return 0;
803
804 if (ra->ra_sent == 0)
805 return 0;
806
807 /* If RAs have already been sent, send an RA immediately to announce the newly-added route prefix */
808 r = radv_send(ra, NULL, ra->lifetime_usec);
809 if (r < 0)
810 log_radv_errno(ra, r, "Unable to send Router Advertisement for added PREF64 prefix %s, ignoring: %m",
811 strna(addr_p));
812 else
813 log_radv(ra, "Sent Router Advertisement for added PREF64 prefix %s.", strna(addr_p));
814
815 return 0;
816}
817
faaf3d66
YW
818int sd_radv_set_rdnss(
819 sd_radv *ra,
820 uint32_t lifetime,
821 const struct in6_addr *dns,
822 size_t n_dns) {
823
e9c6da38
PF
824 _cleanup_free_ struct sd_radv_opt_dns *opt_rdnss = NULL;
825 size_t len;
826
827 assert_return(ra, -EINVAL);
828 assert_return(n_dns < 128, -EINVAL);
829
830 if (!dns || n_dns == 0) {
831 ra->rdnss = mfree(ra->rdnss);
832 ra->n_rdnss = 0;
833
834 return 0;
835 }
836
837 len = sizeof(struct sd_radv_opt_dns) + sizeof(struct in6_addr) * n_dns;
838
839 opt_rdnss = malloc0(len);
840 if (!opt_rdnss)
841 return -ENOMEM;
842
d6fc0d67 843 opt_rdnss->type = RADV_OPT_RDNSS;
e9c6da38
PF
844 opt_rdnss->length = len / 8;
845 opt_rdnss->lifetime = htobe32(lifetime);
846
847 memcpy(opt_rdnss + 1, dns, n_dns * sizeof(struct in6_addr));
848
1cc6c93a 849 free_and_replace(ra->rdnss, opt_rdnss);
e9c6da38
PF
850
851 ra->n_rdnss = n_dns;
852
853 return 0;
854}
855
faaf3d66
YW
856int sd_radv_set_dnssl(
857 sd_radv *ra,
858 uint32_t lifetime,
859 char **search_list) {
860
e965d6ab
PF
861 _cleanup_free_ struct sd_radv_opt_dns *opt_dnssl = NULL;
862 size_t len = 0;
e965d6ab
PF
863 uint8_t *p;
864
865 assert_return(ra, -EINVAL);
866
97d7974b 867 if (strv_isempty(search_list)) {
e965d6ab 868 ra->dnssl = mfree(ra->dnssl);
e965d6ab
PF
869 return 0;
870 }
871
872 STRV_FOREACH(s, search_list)
873 len += strlen(*s) + 2;
874
875 len = (sizeof(struct sd_radv_opt_dns) + len + 7) & ~0x7;
876
877 opt_dnssl = malloc0(len);
878 if (!opt_dnssl)
879 return -ENOMEM;
880
d6fc0d67 881 opt_dnssl->type = RADV_OPT_DNSSL;
e965d6ab
PF
882 opt_dnssl->length = len / 8;
883 opt_dnssl->lifetime = htobe32(lifetime);
884
885 p = (uint8_t *)(opt_dnssl + 1);
886 len -= sizeof(struct sd_radv_opt_dns);
887
888 STRV_FOREACH(s, search_list) {
889 int r;
890
891 r = dns_name_to_wire_format(*s, p, len, false);
892 if (r < 0)
893 return r;
894
895 if (len < (size_t)r)
896 return -ENOBUFS;
897
898 p += r;
899 len -= r;
900 }
901
1cc6c93a 902 free_and_replace(ra->dnssl, opt_dnssl);
e965d6ab
PF
903
904 return 0;
905}
906
17347053 907int sd_radv_prefix_new(sd_radv_prefix **ret) {
d2c8eed2 908 sd_radv_prefix *p;
04473969
PF
909
910 assert_return(ret, -EINVAL);
911
d2c8eed2 912 p = new(sd_radv_prefix, 1);
04473969
PF
913 if (!p)
914 return -ENOMEM;
915
d2c8eed2
LP
916 *p = (sd_radv_prefix) {
917 .n_ref = 1,
04473969 918
d2c8eed2
LP
919 .opt.type = ND_OPT_PREFIX_INFORMATION,
920 .opt.length = (sizeof(p->opt) - 1)/8 + 1,
921 .opt.prefixlen = 64,
04473969 922
d2c8eed2
LP
923 /* RFC 4861, Section 6.2.1 */
924 .opt.flags = ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO,
204f99d2 925
d951507d
YW
926 .lifetime_valid_usec = RADV_DEFAULT_VALID_LIFETIME_USEC,
927 .lifetime_preferred_usec = RADV_DEFAULT_PREFERRED_LIFETIME_USEC,
95e104e0
YW
928 .valid_until = USEC_INFINITY,
929 .preferred_until = USEC_INFINITY,
d2c8eed2 930 };
04473969 931
d2c8eed2 932 *ret = p;
04473969
PF
933 return 0;
934}
935
8301aa0b 936DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv_prefix, sd_radv_prefix, mfree);
04473969 937
faaf3d66
YW
938int sd_radv_prefix_set_prefix(
939 sd_radv_prefix *p,
940 const struct in6_addr *in6_addr,
941 unsigned char prefixlen) {
942
04473969
PF
943 assert_return(p, -EINVAL);
944 assert_return(in6_addr, -EINVAL);
945
946 if (prefixlen < 3 || prefixlen > 128)
947 return -EINVAL;
948
949 if (prefixlen > 64)
950 /* unusual but allowed, log it */
35388783 951 log_radv(NULL, "Unusual prefix length %d greater than 64", prefixlen);
04473969
PF
952
953 p->opt.in6_addr = *in6_addr;
954 p->opt.prefixlen = prefixlen;
955
956 return 0;
957}
958
faaf3d66
YW
959int sd_radv_prefix_get_prefix(
960 sd_radv_prefix *p,
961 struct in6_addr *ret_in6_addr,
962 unsigned char *ret_prefixlen) {
963
34332af2
SS
964 assert_return(p, -EINVAL);
965 assert_return(ret_in6_addr, -EINVAL);
966 assert_return(ret_prefixlen, -EINVAL);
967
968 *ret_in6_addr = p->opt.in6_addr;
969 *ret_prefixlen = p->opt.prefixlen;
970
971 return 0;
972}
973
17347053 974int sd_radv_prefix_set_onlink(sd_radv_prefix *p, int onlink) {
04473969
PF
975 assert_return(p, -EINVAL);
976
977 SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_ONLINK, onlink);
978
979 return 0;
980}
981
faaf3d66 982int sd_radv_prefix_set_address_autoconfiguration(sd_radv_prefix *p, int address_autoconfiguration) {
04473969
PF
983 assert_return(p, -EINVAL);
984
985 SET_FLAG(p->opt.flags, ND_OPT_PI_FLAG_AUTO, address_autoconfiguration);
986
987 return 0;
988}
989
17347053 990int sd_radv_prefix_set_valid_lifetime(sd_radv_prefix *p, uint64_t lifetime_usec, uint64_t valid_until) {
04473969
PF
991 assert_return(p, -EINVAL);
992
95e104e0
YW
993 p->lifetime_valid_usec = lifetime_usec;
994 p->valid_until = valid_until;
04473969
PF
995
996 return 0;
997}
998
17347053 999int sd_radv_prefix_set_preferred_lifetime(sd_radv_prefix *p, uint64_t lifetime_usec, uint64_t valid_until) {
04473969
PF
1000 assert_return(p, -EINVAL);
1001
95e104e0
YW
1002 p->lifetime_preferred_usec = lifetime_usec;
1003 p->preferred_until = valid_until;
04473969
PF
1004
1005 return 0;
1006}
203d4df5 1007
17347053 1008int sd_radv_route_prefix_new(sd_radv_route_prefix **ret) {
203d4df5
SS
1009 sd_radv_route_prefix *p;
1010
1011 assert_return(ret, -EINVAL);
1012
1013 p = new(sd_radv_route_prefix, 1);
1014 if (!p)
1015 return -ENOMEM;
1016
1017 *p = (sd_radv_route_prefix) {
1018 .n_ref = 1,
1019
d6fc0d67 1020 .opt.type = RADV_OPT_ROUTE_INFORMATION,
203d4df5
SS
1021 .opt.length = DIV_ROUND_UP(sizeof(p->opt), 8),
1022 .opt.prefixlen = 64,
1023
d951507d 1024 .lifetime_usec = RADV_DEFAULT_VALID_LIFETIME_USEC,
95e104e0 1025 .valid_until = USEC_INFINITY,
203d4df5
SS
1026 };
1027
1028 *ret = p;
1029 return 0;
1030}
1031
1032DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv_route_prefix, sd_radv_route_prefix, mfree);
1033
faaf3d66
YW
1034int sd_radv_route_prefix_set_prefix(
1035 sd_radv_route_prefix *p,
1036 const struct in6_addr *in6_addr,
1037 unsigned char prefixlen) {
1038
203d4df5
SS
1039 assert_return(p, -EINVAL);
1040 assert_return(in6_addr, -EINVAL);
1041
1042 if (prefixlen > 128)
1043 return -EINVAL;
1044
1045 if (prefixlen > 64)
1046 /* unusual but allowed, log it */
35388783 1047 log_radv(NULL, "Unusual prefix length %u greater than 64", prefixlen);
203d4df5
SS
1048
1049 p->opt.in6_addr = *in6_addr;
1050 p->opt.prefixlen = prefixlen;
1051
1052 return 0;
1053}
1054
17347053 1055int sd_radv_route_prefix_set_lifetime(sd_radv_route_prefix *p, uint64_t lifetime_usec, uint64_t valid_until) {
203d4df5
SS
1056 assert_return(p, -EINVAL);
1057
95e104e0
YW
1058 p->lifetime_usec = lifetime_usec;
1059 p->valid_until = valid_until;
203d4df5
SS
1060
1061 return 0;
1062}
1925f829
SS
1063
1064int sd_radv_pref64_prefix_new(sd_radv_pref64_prefix **ret) {
1065 sd_radv_pref64_prefix *p;
1066
1067 assert_return(ret, -EINVAL);
1068
1069 p = new(sd_radv_pref64_prefix, 1);
1070 if (!p)
1071 return -ENOMEM;
1072
1073 *p = (sd_radv_pref64_prefix) {
1074 .n_ref = 1,
1075
1076 .opt.type = RADV_OPT_PREF64,
1077 .opt.length = 2,
1078 };
1079
1080 *ret = p;
1081 return 0;
1082}
1083
1084DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_radv_pref64_prefix, sd_radv_pref64_prefix, mfree);
1085
1086int sd_radv_pref64_prefix_set_prefix(
1087 sd_radv_pref64_prefix *p,
1088 const struct in6_addr *prefix,
1089 uint8_t prefixlen,
1090 uint64_t lifetime_usec) {
1091
1092 uint16_t pref64_lifetime;
1093 uint8_t prefixlen_code;
1094
1095 assert_return(p, -EINVAL);
1096 assert_return(prefix, -EINVAL);
1097
1098 switch (prefixlen) {
1099 case 96:
1100 prefixlen_code = 0;
1101 break;
1102 case 64:
1103 prefixlen_code = 1;
1104 break;
1105 case 56:
1106 prefixlen_code = 2;
1107 break;
1108 case 48:
1109 prefixlen_code = 3;
1110 break;
1111 case 40:
1112 prefixlen_code = 4;
1113 break;
1114 case 32:
1115 prefixlen_code = 5;
1116 break;
1117 default:
1118 log_radv(NULL, "Unsupported PREF64 prefix length %u. Valid lengths are 32, 40, 48, 56, 64 and 96", prefixlen);
1119 return -EINVAL;
1120 }
1121
1122 if (lifetime_usec == USEC_INFINITY || DIV_ROUND_UP(lifetime_usec, 8 * USEC_PER_SEC) >= UINT64_C(1) << 13)
1123 return -EINVAL;
1124
1125 /* RFC 8781 - 4.1 rounding up lifetime to multiply of 8 */
1126 pref64_lifetime = DIV_ROUND_UP(lifetime_usec, 8 * USEC_PER_SEC) << 3;
1127 pref64_lifetime |= prefixlen_code;
1128
1129 unaligned_write_be16(&p->opt.lifetime_and_plc, pref64_lifetime);
1130 memcpy(&p->opt.prefix, prefix, sizeof(p->opt.prefix));
1131
1132 p->in6_addr = *prefix;
1133 p->prefixlen = prefixlen;
1134
1135 return 0;
1136}