etc/protocols - sync with NetBSD-8
[minix.git] / external / bsd / dhcpcd / dist / ipv6nd.c
blob6dac8d6f55e04c8e3a61a6da0d7a24f9b7adfd02
1 #include <sys/cdefs.h>
2 __RCSID("$NetBSD: ipv6nd.c,v 1.26 2015/08/21 10:39:00 roy Exp $");
4 /*
5 * dhcpcd - DHCP client daemon
6 * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
7 * All rights reserved
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
31 #include <sys/ioctl.h>
32 #include <sys/param.h>
33 #include <sys/socket.h>
34 #include <net/if.h>
35 #include <net/route.h>
36 #include <netinet/in.h>
37 #include <netinet/ip6.h>
38 #include <netinet/icmp6.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <stddef.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
47 #define ELOOP_QUEUE 3
48 #include "common.h"
49 #include "dhcpcd.h"
50 #include "dhcp6.h"
51 #include "eloop.h"
52 #include "if.h"
53 #include "ipv6.h"
54 #include "ipv6nd.h"
55 #include "script.h"
57 /* Debugging Router Solicitations is a lot of spam, so disable it */
58 //#define DEBUG_RS
60 #ifndef ND_OPT_RDNSS
61 #define ND_OPT_RDNSS 25
62 struct nd_opt_rdnss { /* RDNSS option RFC 6106 */
63 uint8_t nd_opt_rdnss_type;
64 uint8_t nd_opt_rdnss_len;
65 uint16_t nd_opt_rdnss_reserved;
66 uint32_t nd_opt_rdnss_lifetime;
67 /* followed by list of IP prefixes */
68 } __packed;
69 #endif
71 #ifndef ND_OPT_DNSSL
72 #define ND_OPT_DNSSL 31
73 struct nd_opt_dnssl { /* DNSSL option RFC 6106 */
74 uint8_t nd_opt_dnssl_type;
75 uint8_t nd_opt_dnssl_len;
76 uint16_t nd_opt_dnssl_reserved;
77 uint32_t nd_opt_dnssl_lifetime;
78 /* followed by list of DNS servers */
79 } __packed;
80 #endif
82 /* Impossible options, so we can easily add extras */
83 #define _ND_OPT_PREFIX_ADDR 255 + 1
85 /* Minimal IPv6 MTU */
86 #ifndef IPV6_MMTU
87 #define IPV6_MMTU 1280
88 #endif
90 #ifndef ND_RA_FLAG_RTPREF_HIGH
91 #define ND_RA_FLAG_RTPREF_MASK 0x18
92 #define ND_RA_FLAG_RTPREF_HIGH 0x08
93 #define ND_RA_FLAG_RTPREF_MEDIUM 0x00
94 #define ND_RA_FLAG_RTPREF_LOW 0x18
95 #define ND_RA_FLAG_RTPREF_RSV 0x10
96 #endif
98 /* RTPREF_MEDIUM has to be 0! */
99 #define RTPREF_HIGH 1
100 #define RTPREF_MEDIUM 0
101 #define RTPREF_LOW (-1)
102 #define RTPREF_RESERVED (-2)
103 #define RTPREF_INVALID (-3) /* internal */
105 #define MIN_RANDOM_FACTOR 500 /* millisecs */
106 #define MAX_RANDOM_FACTOR 1500 /* millisecs */
107 #define MIN_RANDOM_FACTOR_U MIN_RANDOM_FACTOR * 1000 /* usecs */
108 #define MAX_RANDOM_FACTOR_U MAX_RANDOM_FACTOR * 1000 /* usecs */
110 #if BYTE_ORDER == BIG_ENDIAN
111 #define IPV6_ADDR_INT32_ONE 1
112 #define IPV6_ADDR_INT16_MLL 0xff02
113 #elif BYTE_ORDER == LITTLE_ENDIAN
114 #define IPV6_ADDR_INT32_ONE 0x01000000
115 #define IPV6_ADDR_INT16_MLL 0x02ff
116 #endif
118 /* Debugging Neighbor Solicitations is a lot of spam, so disable it */
119 //#define DEBUG_NS
122 static void ipv6nd_handledata(void *);
125 * Android ships buggy ICMP6 filter headers.
126 * Supply our own until they fix their shit.
127 * References:
128 * https://android-review.googlesource.com/#/c/58438/
129 * http://code.google.com/p/android/issues/original?id=32621&seq=24
131 #ifdef __ANDROID__
132 #undef ICMP6_FILTER_WILLPASS
133 #undef ICMP6_FILTER_WILLBLOCK
134 #undef ICMP6_FILTER_SETPASS
135 #undef ICMP6_FILTER_SETBLOCK
136 #undef ICMP6_FILTER_SETPASSALL
137 #undef ICMP6_FILTER_SETBLOCKALL
138 #define ICMP6_FILTER_WILLPASS(type, filterp) \
139 ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) == 0)
140 #define ICMP6_FILTER_WILLBLOCK(type, filterp) \
141 ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) != 0)
142 #define ICMP6_FILTER_SETPASS(type, filterp) \
143 ((((filterp)->icmp6_filt[(type) >> 5]) &= ~(1 << ((type) & 31))))
144 #define ICMP6_FILTER_SETBLOCK(type, filterp) \
145 ((((filterp)->icmp6_filt[(type) >> 5]) |= (1 << ((type) & 31))))
146 #define ICMP6_FILTER_SETPASSALL(filterp) \
147 memset(filterp, 0, sizeof(struct icmp6_filter));
148 #define ICMP6_FILTER_SETBLOCKALL(filterp) \
149 memset(filterp, 0xff, sizeof(struct icmp6_filter));
150 #endif
152 /* Support older systems with different defines */
153 #if !defined(IPV6_RECVHOPLIMIT) && defined(IPV6_HOPLIMIT)
154 #define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
155 #endif
156 #if !defined(IPV6_RECVPKTINFO) && defined(IPV6_PKTINFO)
157 #define IPV6_RECVPKTINFO IPV6_PKTINFO
158 #endif
160 void
161 ipv6nd_printoptions(const struct dhcpcd_ctx *ctx,
162 const struct dhcp_opt *opts, size_t opts_len)
164 size_t i, j;
165 const struct dhcp_opt *opt, *opt2;
166 int cols;
168 for (i = 0, opt = ctx->nd_opts;
169 i < ctx->nd_opts_len; i++, opt++)
171 for (j = 0, opt2 = opts; j < opts_len; j++, opt2++)
172 if (opt2->option == opt->option)
173 break;
174 if (j == opts_len) {
175 cols = printf("%03d %s", opt->option, opt->var);
176 dhcp_print_option_encoding(opt, cols);
179 for (i = 0, opt = opts; i < opts_len; i++, opt++) {
180 cols = printf("%03d %s", opt->option, opt->var);
181 dhcp_print_option_encoding(opt, cols);
185 static int
186 ipv6nd_open(struct dhcpcd_ctx *dctx)
188 struct ipv6_ctx *ctx;
189 int on;
190 struct icmp6_filter filt;
192 ctx = dctx->ipv6;
193 if (ctx->nd_fd != -1)
194 return ctx->nd_fd;
195 ctx->nd_fd = xsocket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6,
196 O_NONBLOCK|O_CLOEXEC);
197 if (ctx->nd_fd == -1)
198 return -1;
200 /* RFC4861 4.1 */
201 on = 255;
202 if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
203 &on, sizeof(on)) == -1)
204 goto eexit;
206 on = 1;
207 if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
208 &on, sizeof(on)) == -1)
209 goto eexit;
211 on = 1;
212 if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
213 &on, sizeof(on)) == -1)
214 goto eexit;
216 ICMP6_FILTER_SETBLOCKALL(&filt);
217 ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filt);
218 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
219 if (setsockopt(ctx->nd_fd, IPPROTO_ICMPV6, ICMP6_FILTER,
220 &filt, sizeof(filt)) == -1)
221 goto eexit;
223 eloop_event_add(dctx->eloop, ctx->nd_fd,
224 ipv6nd_handledata, dctx, NULL, NULL);
225 return ctx->nd_fd;
227 eexit:
228 if (ctx->nd_fd != -1) {
229 eloop_event_delete(dctx->eloop, ctx->nd_fd);
230 close(ctx->nd_fd);
231 ctx->nd_fd = -1;
233 return -1;
236 static int
237 ipv6nd_makersprobe(struct interface *ifp)
239 struct rs_state *state;
240 struct nd_router_solicit *rs;
241 struct nd_opt_hdr *nd;
243 state = RS_STATE(ifp);
244 free(state->rs);
245 state->rslen = sizeof(*rs) + (size_t)ROUNDUP8(ifp->hwlen + 2);
246 state->rs = calloc(1, state->rslen);
247 if (state->rs == NULL)
248 return -1;
249 rs = (struct nd_router_solicit *)(void *)state->rs;
250 rs->nd_rs_type = ND_ROUTER_SOLICIT;
251 rs->nd_rs_code = 0;
252 rs->nd_rs_cksum = 0;
253 rs->nd_rs_reserved = 0;
254 nd = (struct nd_opt_hdr *)(state->rs + sizeof(*rs));
255 nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
256 nd->nd_opt_len = (uint8_t)((ROUNDUP8(ifp->hwlen + 2)) >> 3);
257 memcpy(nd + 1, ifp->hwaddr, ifp->hwlen);
258 return 0;
261 static void
262 ipv6nd_sendrsprobe(void *arg)
264 struct interface *ifp = arg;
265 struct ipv6_ctx *ctx;
266 struct rs_state *state;
267 struct sockaddr_in6 dst;
268 struct cmsghdr *cm;
269 struct in6_pktinfo pi;
271 if (ipv6_linklocal(ifp) == NULL) {
272 logger(ifp->ctx, LOG_DEBUG,
273 "%s: delaying Router Solicitation for LL address",
274 ifp->name);
275 ipv6_addlinklocalcallback(ifp, ipv6nd_sendrsprobe, ifp);
276 return;
279 memset(&dst, 0, sizeof(dst));
280 dst.sin6_family = AF_INET6;
281 #ifdef SIN6_LEN
282 dst.sin6_len = sizeof(dst);
283 #endif
284 dst.sin6_scope_id = ifp->index;
285 if (inet_pton(AF_INET6, ALLROUTERS, &dst.sin6_addr) != 1) {
286 logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
287 return;
290 state = RS_STATE(ifp);
291 ctx = ifp->ctx->ipv6;
292 ctx->sndhdr.msg_name = (void *)&dst;
293 ctx->sndhdr.msg_iov[0].iov_base = state->rs;
294 ctx->sndhdr.msg_iov[0].iov_len = state->rslen;
296 /* Set the outbound interface */
297 cm = CMSG_FIRSTHDR(&ctx->sndhdr);
298 if (cm == NULL) /* unlikely */
299 return;
300 cm->cmsg_level = IPPROTO_IPV6;
301 cm->cmsg_type = IPV6_PKTINFO;
302 cm->cmsg_len = CMSG_LEN(sizeof(pi));
303 memset(&pi, 0, sizeof(pi));
304 pi.ipi6_ifindex = ifp->index;
305 memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
307 logger(ifp->ctx, LOG_DEBUG,
308 "%s: sending Router Solicitation", ifp->name);
309 if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) {
310 logger(ifp->ctx, LOG_ERR,
311 "%s: %s: sendmsg: %m", ifp->name, __func__);
312 ipv6nd_drop(ifp);
313 ifp->options->options &= ~(DHCPCD_IPV6 | DHCPCD_IPV6RS);
314 return;
317 if (state->rsprobes++ < MAX_RTR_SOLICITATIONS)
318 eloop_timeout_add_sec(ifp->ctx->eloop,
319 RTR_SOLICITATION_INTERVAL, ipv6nd_sendrsprobe, ifp);
320 else {
321 logger(ifp->ctx, LOG_WARNING,
322 "%s: no IPv6 Routers available", ifp->name);
323 ipv6nd_drop(ifp);
324 dhcp6_drop(ifp, "EXPIRE6");
328 void
329 ipv6nd_expire(struct interface *ifp, uint32_t seconds)
331 struct ra *rap;
332 struct timespec now;
334 if (ifp->ctx->ipv6 == NULL)
335 return;
337 clock_gettime(CLOCK_MONOTONIC, &now);
339 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
340 if (rap->iface == ifp) {
341 rap->acquired = now;
342 rap->expired = seconds ? 0 : 1;
343 if (seconds) {
344 struct ipv6_addr *ap;
346 rap->lifetime = seconds;
347 TAILQ_FOREACH(ap, &rap->addrs, next) {
348 if (ap->prefix_vltime) {
349 ap->prefix_vltime = seconds;
350 ap->prefix_pltime = seconds / 2;
353 ipv6_addaddrs(&rap->addrs);
357 if (seconds)
358 ipv6nd_expirera(ifp);
359 else
360 ipv6_buildroutes(ifp->ctx);
363 static void
364 ipv6nd_reachable(struct ra *rap, int flags)
367 if (flags & IPV6ND_REACHABLE) {
368 if (rap->lifetime && rap->expired) {
369 logger(rap->iface->ctx, LOG_INFO,
370 "%s: %s is reachable again",
371 rap->iface->name, rap->sfrom);
372 rap->expired = 0;
373 ipv6_buildroutes(rap->iface->ctx);
374 /* XXX Not really an RA */
375 script_runreason(rap->iface, "ROUTERADVERT");
377 } else {
378 if (rap->lifetime && !rap->expired) {
379 logger(rap->iface->ctx, LOG_WARNING,
380 "%s: %s is unreachable, expiring it",
381 rap->iface->name, rap->sfrom);
382 rap->expired = 1;
383 ipv6_buildroutes(rap->iface->ctx);
384 /* XXX Not really an RA */
385 script_runreason(rap->iface, "ROUTERADVERT");
390 void
391 ipv6nd_neighbour(struct dhcpcd_ctx *ctx, struct in6_addr *addr, int flags)
393 struct ra *rap;
395 if (ctx->ipv6) {
396 TAILQ_FOREACH(rap, ctx->ipv6->ra_routers, next) {
397 if (IN6_ARE_ADDR_EQUAL(&rap->from, addr)) {
398 ipv6nd_reachable(rap, flags);
399 break;
405 const struct ipv6_addr *
406 ipv6nd_iffindaddr(const struct interface *ifp, const struct in6_addr *addr,
407 short flags)
409 struct ra *rap;
410 struct ipv6_addr *ap;
412 if (ifp->ctx->ipv6 == NULL)
413 return NULL;
415 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
416 if (rap->iface != ifp)
417 continue;
418 TAILQ_FOREACH(ap, &rap->addrs, next) {
419 if (ipv6_findaddrmatch(ap, addr, flags))
420 return ap;
423 return NULL;
426 struct ipv6_addr *
427 ipv6nd_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr,
428 short flags)
430 struct ra *rap;
431 struct ipv6_addr *ap;
433 if (ctx->ipv6 == NULL)
434 return NULL;
436 TAILQ_FOREACH(rap, ctx->ipv6->ra_routers, next) {
437 TAILQ_FOREACH(ap, &rap->addrs, next) {
438 if (ipv6_findaddrmatch(ap, addr, flags))
439 return ap;
442 return NULL;
445 static void
446 ipv6nd_removefreedrop_ra(struct ra *rap, int remove_ra, int drop_ra)
449 eloop_timeout_delete(rap->iface->ctx->eloop, NULL, rap->iface);
450 eloop_timeout_delete(rap->iface->ctx->eloop, NULL, rap);
451 if (remove_ra && !drop_ra)
452 TAILQ_REMOVE(rap->iface->ctx->ipv6->ra_routers, rap, next);
453 ipv6_freedrop_addrs(&rap->addrs, drop_ra, NULL);
454 free(rap->data);
455 free(rap);
458 void
459 ipv6nd_freedrop_ra(struct ra *rap, int drop)
462 ipv6nd_removefreedrop_ra(rap, 1, drop);
465 ssize_t
466 ipv6nd_free(struct interface *ifp)
468 struct rs_state *state;
469 struct ra *rap, *ran;
470 struct dhcpcd_ctx *ctx;
471 ssize_t n;
473 state = RS_STATE(ifp);
474 if (state == NULL)
475 return 0;
477 free(state->rs);
478 free(state);
479 ifp->if_data[IF_DATA_IPV6ND] = NULL;
480 n = 0;
481 TAILQ_FOREACH_SAFE(rap, ifp->ctx->ipv6->ra_routers, next, ran) {
482 if (rap->iface == ifp) {
483 ipv6nd_free_ra(rap);
484 n++;
488 /* If we don't have any more IPv6 enabled interfaces,
489 * close the global socket and release resources */
490 ctx = ifp->ctx;
491 TAILQ_FOREACH(ifp, ctx->ifaces, next) {
492 if (RS_STATE(ifp))
493 break;
495 if (ifp == NULL) {
496 if (ctx->ipv6->nd_fd != -1) {
497 eloop_event_delete(ctx->eloop, ctx->ipv6->nd_fd);
498 close(ctx->ipv6->nd_fd);
499 ctx->ipv6->nd_fd = -1;
503 return n;
506 static int
507 rtpref(struct ra *rap)
510 switch (rap->flags & ND_RA_FLAG_RTPREF_MASK) {
511 case ND_RA_FLAG_RTPREF_HIGH:
512 return (RTPREF_HIGH);
513 case ND_RA_FLAG_RTPREF_MEDIUM:
514 case ND_RA_FLAG_RTPREF_RSV:
515 return (RTPREF_MEDIUM);
516 case ND_RA_FLAG_RTPREF_LOW:
517 return (RTPREF_LOW);
518 default:
519 logger(rap->iface->ctx, LOG_ERR,
520 "rtpref: impossible RA flag %x", rap->flags);
521 return (RTPREF_INVALID);
523 /* NOTREACHED */
526 static void
527 add_router(struct ipv6_ctx *ctx, struct ra *router)
529 struct ra *rap;
531 TAILQ_FOREACH(rap, ctx->ra_routers, next) {
532 if (router->iface->metric < rap->iface->metric ||
533 (router->iface->metric == rap->iface->metric &&
534 rtpref(router) > rtpref(rap)))
536 TAILQ_INSERT_BEFORE(rap, router, next);
537 return;
540 TAILQ_INSERT_TAIL(ctx->ra_routers, router, next);
543 static int
544 ipv6nd_scriptrun(struct ra *rap)
546 int hasdns, hasaddress, pid;
547 struct ipv6_addr *ap;
549 hasaddress = 0;
550 /* If all addresses have completed DAD run the script */
551 TAILQ_FOREACH(ap, &rap->addrs, next) {
552 if ((ap->flags & (IPV6_AF_AUTOCONF | IPV6_AF_ADDED)) ==
553 (IPV6_AF_AUTOCONF | IPV6_AF_ADDED))
555 hasaddress = 1;
556 if (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
557 ipv6_iffindaddr(ap->iface, &ap->addr))
558 ap->flags |= IPV6_AF_DADCOMPLETED;
559 if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0) {
560 logger(ap->iface->ctx, LOG_DEBUG,
561 "%s: waiting for Router Advertisement"
562 " DAD to complete",
563 rap->iface->name);
564 return 0;
569 /* If we don't require RDNSS then set hasdns = 1 so we fork */
570 if (!(rap->iface->options->options & DHCPCD_IPV6RA_REQRDNSS))
571 hasdns = 1;
572 else {
573 hasdns = rap->hasdns;
576 script_runreason(rap->iface, "ROUTERADVERT");
577 pid = 0;
578 if (hasdns && (hasaddress ||
579 !(rap->flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER))))
580 pid = dhcpcd_daemonise(rap->iface->ctx);
581 #if 0
582 else if (options & DHCPCD_DAEMONISE &&
583 !(options & DHCPCD_DAEMONISED) && new_data)
584 logger(rap->iface->ctx, LOG_WARNING,
585 "%s: did not fork due to an absent"
586 " RDNSS option in the RA",
587 ifp->name);
589 #endif
590 return pid;
593 static void
594 ipv6nd_addaddr(void *arg)
596 struct ipv6_addr *ap = arg;
598 ipv6_addaddr(ap, NULL);
602 ipv6nd_dadcompleted(const struct interface *ifp)
604 const struct ra *rap;
605 const struct ipv6_addr *ap;
607 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
608 if (rap->iface != ifp)
609 continue;
610 TAILQ_FOREACH(ap, &rap->addrs, next) {
611 if (ap->flags & IPV6_AF_AUTOCONF &&
612 ap->flags & IPV6_AF_ADDED &&
613 !(ap->flags & IPV6_AF_DADCOMPLETED))
614 return 0;
617 return 1;
620 static void
621 ipv6nd_dadcallback(void *arg)
623 struct ipv6_addr *ap = arg, *rapap;
624 struct interface *ifp;
625 struct ra *rap;
626 int wascompleted, found;
627 struct timespec tv;
628 char buf[INET6_ADDRSTRLEN];
629 const char *p;
630 int dadcounter;
632 ifp = ap->iface;
633 wascompleted = (ap->flags & IPV6_AF_DADCOMPLETED);
634 ap->flags |= IPV6_AF_DADCOMPLETED;
635 if (ap->flags & IPV6_AF_DUPLICATED) {
636 ap->dadcounter++;
637 logger(ifp->ctx, LOG_WARNING, "%s: DAD detected %s",
638 ifp->name, ap->saddr);
640 /* Try and make another stable private address.
641 * Because ap->dadcounter is always increamented,
642 * a different address is generated. */
643 /* XXX Cache DAD counter per prefix/id/ssid? */
644 if (ifp->options->options & DHCPCD_SLAACPRIVATE) {
645 if (ap->dadcounter >= IDGEN_RETRIES) {
646 logger(ifp->ctx, LOG_ERR,
647 "%s: unable to obtain a"
648 " stable private address",
649 ifp->name);
650 goto try_script;
652 logger(ifp->ctx, LOG_INFO, "%s: deleting address %s",
653 ifp->name, ap->saddr);
654 if (if_deladdress6(ap) == -1 &&
655 errno != EADDRNOTAVAIL && errno != ENXIO)
656 logger(ifp->ctx, LOG_ERR, "if_deladdress6: %m");
657 dadcounter = ap->dadcounter;
658 if (ipv6_makestableprivate(&ap->addr,
659 &ap->prefix, ap->prefix_len,
660 ifp, &dadcounter) == -1)
662 logger(ifp->ctx, LOG_ERR,
663 "%s: ipv6_makestableprivate: %m",
664 ifp->name);
665 return;
667 ap->dadcounter = dadcounter;
668 ap->flags &= ~(IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED);
669 ap->flags |= IPV6_AF_NEW;
670 p = inet_ntop(AF_INET6, &ap->addr, buf, sizeof(buf));
671 if (p)
672 snprintf(ap->saddr,
673 sizeof(ap->saddr),
674 "%s/%d",
675 p, ap->prefix_len);
676 else
677 ap->saddr[0] = '\0';
678 tv.tv_sec = 0;
679 tv.tv_nsec = (suseconds_t)
680 arc4random_uniform(IDGEN_DELAY * NSEC_PER_SEC);
681 timespecnorm(&tv);
682 eloop_timeout_add_tv(ifp->ctx->eloop, &tv,
683 ipv6nd_addaddr, ap);
684 return;
688 try_script:
689 if (!wascompleted) {
690 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
691 if (rap->iface != ifp)
692 continue;
693 wascompleted = 1;
694 found = 0;
695 TAILQ_FOREACH(rapap, &rap->addrs, next) {
696 if (rapap->flags & IPV6_AF_AUTOCONF &&
697 rapap->flags & IPV6_AF_ADDED &&
698 (rapap->flags & IPV6_AF_DADCOMPLETED) == 0)
700 wascompleted = 0;
701 break;
703 if (rapap == ap)
704 found = 1;
707 if (wascompleted && found) {
708 logger(rap->iface->ctx, LOG_DEBUG,
709 "%s: Router Advertisement DAD completed",
710 rap->iface->name);
711 if (ipv6nd_scriptrun(rap))
712 return;
718 static int
719 ipv6nd_has_public_addr(const struct interface *ifp)
721 const struct ra *rap;
722 const struct ipv6_addr *ia;
724 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
725 if (rap->iface == ifp) {
726 TAILQ_FOREACH(ia, &rap->addrs, next) {
727 if (ia->flags & IPV6_AF_AUTOCONF &&
728 ipv6_publicaddr(ia))
729 return 1;
733 return 0;
736 static void
737 ipv6nd_handlera(struct dhcpcd_ctx *dctx, struct interface *ifp,
738 struct icmp6_hdr *icp, size_t len, int hoplimit)
740 struct ipv6_ctx *ctx = dctx->ipv6;
741 size_t i, olen;
742 struct nd_router_advert *nd_ra;
743 struct nd_opt_prefix_info *pi;
744 struct nd_opt_mtu *mtu;
745 struct nd_opt_rdnss *rdnss;
746 uint32_t mtuv;
747 uint8_t *p;
748 char buf[INET6_ADDRSTRLEN];
749 const char *cbp;
750 struct ra *rap;
751 struct nd_opt_hdr *ndo;
752 struct ipv6_addr *ap;
753 struct dhcp_opt *dho;
754 uint8_t new_rap, new_data;
755 #ifdef IPV6_MANAGETEMPADDR
756 uint8_t new_ap;
757 #endif
759 if (ifp == NULL) {
760 #ifdef DEBUG_RS
761 logger(dctx, LOG_DEBUG,
762 "RA for unexpected interface from %s", ctx->sfrom);
763 #endif
764 return;
767 if (len < sizeof(struct nd_router_advert)) {
768 logger(dctx, LOG_ERR,
769 "IPv6 RA packet too short from %s", ctx->sfrom);
770 return;
773 /* RFC 4861 7.1.2 */
774 if (hoplimit != 255) {
775 logger(dctx, LOG_ERR,
776 "invalid hoplimit(%d) in RA from %s", hoplimit, ctx->sfrom);
777 return;
780 if (!IN6_IS_ADDR_LINKLOCAL(&ctx->from.sin6_addr)) {
781 logger(dctx, LOG_ERR,
782 "RA from non local address %s", ctx->sfrom);
783 return;
786 if (!(ifp->options->options & DHCPCD_IPV6RS)) {
787 #ifdef DEBUG_RS
788 logger(ifp->ctx, LOG_DEBUG, "%s: unexpected RA from %s",
789 ifp->name, ctx->sfrom);
790 #endif
791 return;
794 /* We could receive a RA before we sent a RS*/
795 if (ipv6_linklocal(ifp) == NULL) {
796 #ifdef DEBUG_RS
797 logger(ifp->ctx, LOG_DEBUG,
798 "%s: received RA from %s (no link-local)",
799 ifp->name, ctx->sfrom);
800 #endif
801 return;
804 if (ipv6_iffindaddr(ifp, &ctx->from.sin6_addr)) {
805 logger(ifp->ctx, LOG_DEBUG,
806 "%s: ignoring RA from ourself %s", ifp->name, ctx->sfrom);
807 return;
810 TAILQ_FOREACH(rap, ctx->ra_routers, next) {
811 if (ifp == rap->iface &&
812 IN6_ARE_ADDR_EQUAL(&rap->from, &ctx->from.sin6_addr))
813 break;
816 nd_ra = (struct nd_router_advert *)icp;
818 /* We don't want to spam the log with the fact we got an RA every
819 * 30 seconds or so, so only spam the log if it's different. */
820 if (rap == NULL || (rap->data_len != len ||
821 memcmp(rap->data, (unsigned char *)icp, rap->data_len) != 0))
823 if (rap) {
824 free(rap->data);
825 rap->data_len = 0;
826 rap->no_public_warned = 0;
828 new_data = 1;
829 } else
830 new_data = 0;
831 if (new_data || ifp->options->options & DHCPCD_DEBUG)
832 logger(ifp->ctx, LOG_INFO, "%s: Router Advertisement from %s",
833 ifp->name, ctx->sfrom);
835 if (rap == NULL) {
836 rap = calloc(1, sizeof(*rap));
837 if (rap == NULL) {
838 logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
839 return;
841 rap->iface = ifp;
842 rap->from = ctx->from.sin6_addr;
843 strlcpy(rap->sfrom, ctx->sfrom, sizeof(rap->sfrom));
844 TAILQ_INIT(&rap->addrs);
845 new_rap = 1;
846 } else
847 new_rap = 0;
848 if (rap->data_len == 0) {
849 rap->data = malloc(len);
850 if (rap->data == NULL) {
851 logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
852 if (new_rap)
853 free(rap);
854 return;
856 memcpy(rap->data, icp, len);
857 rap->data_len = len;
860 clock_gettime(CLOCK_MONOTONIC, &rap->acquired);
861 rap->flags = nd_ra->nd_ra_flags_reserved;
862 rap->lifetime = ntohs(nd_ra->nd_ra_router_lifetime);
863 if (nd_ra->nd_ra_reachable) {
864 rap->reachable = ntohl(nd_ra->nd_ra_reachable);
865 if (rap->reachable > MAX_REACHABLE_TIME)
866 rap->reachable = 0;
868 if (nd_ra->nd_ra_retransmit)
869 rap->retrans = ntohl(nd_ra->nd_ra_retransmit);
870 if (rap->lifetime)
871 rap->expired = 0;
872 rap->hasdns = 0;
874 ipv6_settempstale(ifp);
875 TAILQ_FOREACH(ap, &rap->addrs, next) {
876 ap->flags |= IPV6_AF_STALE;
879 len -= sizeof(struct nd_router_advert);
880 p = ((uint8_t *)icp) + sizeof(struct nd_router_advert);
881 for (; len > 0; p += olen, len -= olen) {
882 if (len < sizeof(struct nd_opt_hdr)) {
883 logger(ifp->ctx, LOG_ERR,
884 "%s: short option", ifp->name);
885 break;
887 ndo = (struct nd_opt_hdr *)p;
888 olen = (size_t)ndo->nd_opt_len * 8;
889 if (olen == 0) {
890 logger(ifp->ctx, LOG_ERR,
891 "%s: zero length option", ifp->name);
892 break;
894 if (olen > len) {
895 logger(ifp->ctx, LOG_ERR,
896 "%s: option length exceeds message", ifp->name);
897 break;
900 if (has_option_mask(ifp->options->rejectmasknd,
901 ndo->nd_opt_type))
903 for (i = 0, dho = dctx->nd_opts;
904 i < dctx->nd_opts_len;
905 i++, dho++)
907 if (dho->option == ndo->nd_opt_type)
908 break;
910 if (dho != NULL)
911 logger(ifp->ctx, LOG_WARNING,
912 "%s: reject RA (option %s) from %s",
913 ifp->name, dho->var, ctx->sfrom);
914 else
915 logger(ifp->ctx, LOG_WARNING,
916 "%s: reject RA (option %d) from %s",
917 ifp->name, ndo->nd_opt_type, ctx->sfrom);
918 if (new_rap)
919 ipv6nd_removefreedrop_ra(rap, 0, 0);
920 else
921 ipv6nd_free_ra(rap);
922 return;
925 if (has_option_mask(ifp->options->nomasknd, ndo->nd_opt_type))
926 continue;
928 switch (ndo->nd_opt_type) {
929 case ND_OPT_PREFIX_INFORMATION:
930 pi = (struct nd_opt_prefix_info *)(void *)ndo;
931 if (pi->nd_opt_pi_len != 4) {
932 logger(ifp->ctx, new_data ? LOG_ERR : LOG_DEBUG,
933 "%s: invalid option len for prefix",
934 ifp->name);
935 continue;
937 if (pi->nd_opt_pi_prefix_len > 128) {
938 logger(ifp->ctx, new_data ? LOG_ERR : LOG_DEBUG,
939 "%s: invalid prefix len",
940 ifp->name);
941 continue;
943 if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) ||
944 IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix))
946 logger(ifp->ctx, new_data ? LOG_ERR : LOG_DEBUG,
947 "%s: invalid prefix in RA", ifp->name);
948 continue;
950 if (ntohl(pi->nd_opt_pi_preferred_time) >
951 ntohl(pi->nd_opt_pi_valid_time))
953 logger(ifp->ctx, new_data ? LOG_ERR : LOG_DEBUG,
954 "%s: pltime > vltime", ifp->name);
955 continue;
957 TAILQ_FOREACH(ap, &rap->addrs, next)
958 if (ap->prefix_len ==pi->nd_opt_pi_prefix_len &&
959 IN6_ARE_ADDR_EQUAL(&ap->prefix,
960 &pi->nd_opt_pi_prefix))
961 break;
962 if (ap == NULL) {
963 if (!(pi->nd_opt_pi_flags_reserved &
964 ND_OPT_PI_FLAG_AUTO) &&
965 !(pi->nd_opt_pi_flags_reserved &
966 ND_OPT_PI_FLAG_ONLINK))
967 continue;
968 ap = calloc(1, sizeof(*ap));
969 if (ap == NULL)
970 break;
971 ap->iface = rap->iface;
972 ap->flags = IPV6_AF_NEW;
973 ap->prefix_len = pi->nd_opt_pi_prefix_len;
974 ap->prefix = pi->nd_opt_pi_prefix;
975 if (pi->nd_opt_pi_flags_reserved &
976 ND_OPT_PI_FLAG_AUTO &&
977 ap->iface->options->options &
978 DHCPCD_IPV6RA_AUTOCONF)
980 ap->flags |= IPV6_AF_AUTOCONF;
981 ap->dadcounter =
982 ipv6_makeaddr(&ap->addr, ifp,
983 &ap->prefix,
984 pi->nd_opt_pi_prefix_len);
985 if (ap->dadcounter == -1) {
986 free(ap);
987 break;
989 cbp = inet_ntop(AF_INET6,
990 &ap->addr,
991 buf, sizeof(buf));
992 if (cbp)
993 snprintf(ap->saddr,
994 sizeof(ap->saddr),
995 "%s/%d",
996 cbp, ap->prefix_len);
997 else
998 ap->saddr[0] = '\0';
999 } else {
1000 memset(&ap->addr, 0, sizeof(ap->addr));
1001 ap->saddr[0] = '\0';
1003 ap->dadcallback = ipv6nd_dadcallback;
1004 ap->created = ap->acquired = rap->acquired;
1005 TAILQ_INSERT_TAIL(&rap->addrs, ap, next);
1007 #ifdef IPV6_MANAGETEMPADDR
1008 /* New address to dhcpcd RA handling.
1009 * If the address already exists and a valid
1010 * temporary address also exists then
1011 * extend the existing one rather than
1012 * create a new one */
1013 if (ipv6_iffindaddr(ifp, &ap->addr) &&
1014 ipv6_settemptime(ap, 0))
1015 new_ap = 0;
1016 else
1017 new_ap = 1;
1018 #endif
1019 } else {
1020 #ifdef IPV6_MANAGETEMPADDR
1021 new_ap = 0;
1022 #endif
1023 ap->flags &= ~IPV6_AF_STALE;
1024 ap->acquired = rap->acquired;
1026 if (pi->nd_opt_pi_flags_reserved &
1027 ND_OPT_PI_FLAG_ONLINK)
1028 ap->flags |= IPV6_AF_ONLINK;
1029 ap->prefix_vltime =
1030 ntohl(pi->nd_opt_pi_valid_time);
1031 ap->prefix_pltime =
1032 ntohl(pi->nd_opt_pi_preferred_time);
1033 ap->nsprobes = 0;
1035 #ifdef IPV6_MANAGETEMPADDR
1036 /* RFC4941 Section 3.3.3 */
1037 if (ap->flags & IPV6_AF_AUTOCONF &&
1038 ap->iface->options->options & DHCPCD_IPV6RA_OWN &&
1039 ip6_use_tempaddr(ap->iface->name))
1041 if (!new_ap) {
1042 if (ipv6_settemptime(ap, 1) == NULL)
1043 new_ap = 1;
1045 if (new_ap && ap->prefix_pltime) {
1046 if (ipv6_createtempaddr(ap,
1047 &ap->acquired) == NULL)
1048 logger(ap->iface->ctx, LOG_ERR,
1049 "ipv6_createtempaddr: %m");
1052 #endif
1053 break;
1055 case ND_OPT_MTU:
1056 mtu = (struct nd_opt_mtu *)(void *)p;
1057 mtuv = ntohl(mtu->nd_opt_mtu_mtu);
1058 if (mtuv < IPV6_MMTU) {
1059 logger(ifp->ctx, LOG_ERR, "%s: invalid MTU %d",
1060 ifp->name, mtuv);
1061 break;
1063 rap->mtu = mtuv;
1064 break;
1066 case ND_OPT_RDNSS:
1067 rdnss = (struct nd_opt_rdnss *)(void *)p;
1068 if (rdnss->nd_opt_rdnss_lifetime &&
1069 rdnss->nd_opt_rdnss_len > 1)
1070 rap->hasdns = 1;
1072 default:
1073 continue;
1077 for (i = 0, dho = dctx->nd_opts;
1078 i < dctx->nd_opts_len;
1079 i++, dho++)
1081 if (has_option_mask(ifp->options->requiremasknd,
1082 dho->option))
1084 logger(ifp->ctx, LOG_WARNING,
1085 "%s: reject RA (no option %s) from %s",
1086 ifp->name, dho->var, ctx->sfrom);
1087 if (new_rap)
1088 ipv6nd_removefreedrop_ra(rap, 0, 0);
1089 else
1090 ipv6nd_free_ra(rap);
1091 return;
1095 if (new_rap)
1096 add_router(ifp->ctx->ipv6, rap);
1098 if (!ipv6nd_has_public_addr(rap->iface) &&
1099 !(rap->iface->options->options & DHCPCD_IPV6RA_ACCEPT_NOPUBLIC) &&
1100 (!(rap->flags & ND_RA_FLAG_MANAGED) ||
1101 !dhcp6_has_public_addr(rap->iface)))
1103 logger(rap->iface->ctx,
1104 rap->no_public_warned ? LOG_DEBUG : LOG_WARNING,
1105 "%s: ignoring RA from %s"
1106 " (no public prefix, no managed address)",
1107 rap->iface->name, rap->sfrom);
1108 rap->no_public_warned = 1;
1109 goto handle_flag;
1111 if (ifp->ctx->options & DHCPCD_TEST) {
1112 script_runreason(ifp, "TEST");
1113 goto handle_flag;
1115 ipv6_addaddrs(&rap->addrs);
1116 #ifdef IPV6_MANAGETEMPADDR
1117 ipv6_addtempaddrs(ifp, &rap->acquired);
1118 #endif
1120 /* Find any freshly added routes, such as the subnet route.
1121 * We do this because we cannot rely on recieving the kernel
1122 * notification right now via our link socket. */
1123 if_initrt6(ifp);
1125 ipv6_buildroutes(ifp->ctx);
1126 if (ipv6nd_scriptrun(rap))
1127 return;
1129 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
1130 eloop_timeout_delete(ifp->ctx->eloop, NULL, rap); /* reachable timer */
1132 handle_flag:
1133 if (!(ifp->options->options & DHCPCD_DHCP6))
1134 goto nodhcp6;
1135 if (rap->flags & ND_RA_FLAG_MANAGED) {
1136 if (new_data && dhcp6_start(ifp, DH6S_INIT) == -1)
1137 logger(ifp->ctx, LOG_ERR,
1138 "dhcp6_start: %s: %m", ifp->name);
1139 } else if (rap->flags & ND_RA_FLAG_OTHER) {
1140 if (new_data && dhcp6_start(ifp, DH6S_INFORM) == -1)
1141 logger(ifp->ctx, LOG_ERR,
1142 "dhcp6_start: %s: %m", ifp->name);
1143 } else {
1144 if (new_data)
1145 logger(ifp->ctx, LOG_DEBUG,
1146 "%s: No DHCPv6 instruction in RA", ifp->name);
1147 nodhcp6:
1148 if (ifp->ctx->options & DHCPCD_TEST) {
1149 eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
1150 return;
1154 /* Expire should be called last as the rap object could be destroyed */
1155 ipv6nd_expirera(ifp);
1158 /* Run RA's we ignored becuase they had no public addresses
1159 * This should only be called when DHCPv6 applies a public address */
1160 void
1161 ipv6nd_runignoredra(struct interface *ifp)
1163 struct ra *rap;
1165 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
1166 if (rap->iface == ifp &&
1167 !rap->expired &&
1168 rap->no_public_warned)
1170 rap->no_public_warned = 0;
1171 logger(rap->iface->ctx, LOG_INFO,
1172 "%s: applying ignored RA from %s",
1173 rap->iface->name, rap->sfrom);
1174 if (ifp->ctx->options & DHCPCD_TEST) {
1175 script_runreason(ifp, "TEST");
1176 continue;
1178 if (ipv6nd_scriptrun(rap))
1179 return;
1180 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
1181 eloop_timeout_delete(ifp->ctx->eloop, NULL, rap);
1187 ipv6nd_hasra(const struct interface *ifp)
1189 const struct ra *rap;
1191 if (ifp->ctx->ipv6) {
1192 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next)
1193 if (rap->iface == ifp && !rap->expired)
1194 return 1;
1196 return 0;
1200 ipv6nd_hasradhcp(const struct interface *ifp)
1202 const struct ra *rap;
1204 if (ifp->ctx->ipv6) {
1205 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
1206 if (rap->iface == ifp &&
1207 !rap->expired &&
1208 (rap->flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)))
1209 return 1;
1212 return 0;
1215 static const uint8_t *
1216 ipv6nd_getoption(struct dhcpcd_ctx *ctx,
1217 size_t *os, unsigned int *code, size_t *len,
1218 const uint8_t *od, size_t ol, struct dhcp_opt **oopt)
1220 const struct nd_opt_hdr *o;
1221 size_t i;
1222 struct dhcp_opt *opt;
1224 if (od) {
1225 *os = sizeof(*o);
1226 if (ol < *os) {
1227 errno = EINVAL;
1228 return NULL;
1230 o = (const struct nd_opt_hdr *)od;
1231 if (o->nd_opt_len > ol) {
1232 errno = EINVAL;
1233 return NULL;
1235 *len = ND_OPTION_LEN(o);
1236 *code = o->nd_opt_type;
1237 } else
1238 o = NULL;
1240 for (i = 0, opt = ctx->nd_opts;
1241 i < ctx->nd_opts_len; i++, opt++)
1243 if (opt->option == *code) {
1244 *oopt = opt;
1245 break;
1249 if (o)
1250 return ND_COPTION_DATA(o);
1251 return NULL;
1254 ssize_t
1255 ipv6nd_env(char **env, const char *prefix, const struct interface *ifp)
1257 size_t i, j, n, len;
1258 struct ra *rap;
1259 char ndprefix[32], abuf[24];
1260 struct dhcp_opt *opt;
1261 const struct nd_opt_hdr *o;
1262 struct ipv6_addr *ia;
1263 struct timespec now;
1265 clock_gettime(CLOCK_MONOTONIC, &now);
1266 i = n = 0;
1267 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
1268 if (rap->iface != ifp)
1269 continue;
1270 i++;
1271 if (prefix != NULL)
1272 snprintf(ndprefix, sizeof(ndprefix),
1273 "%s_nd%zu", prefix, i);
1274 else
1275 snprintf(ndprefix, sizeof(ndprefix),
1276 "nd%zu", i);
1277 if (env)
1278 setvar(rap->iface->ctx, &env[n], ndprefix,
1279 "from", rap->sfrom);
1280 n++;
1281 if (env)
1282 setvard(rap->iface->ctx, &env[n], ndprefix,
1283 "acquired", (size_t)rap->acquired.tv_sec);
1284 n++;
1285 if (env)
1286 setvard(rap->iface->ctx, &env[n], ndprefix,
1287 "now", (size_t)now.tv_sec);
1288 n++;
1290 /* Zero our indexes */
1291 if (env) {
1292 for (j = 0, opt = rap->iface->ctx->nd_opts;
1293 j < rap->iface->ctx->nd_opts_len;
1294 j++, opt++)
1295 dhcp_zero_index(opt);
1296 for (j = 0, opt = rap->iface->options->nd_override;
1297 j < rap->iface->options->nd_override_len;
1298 j++, opt++)
1299 dhcp_zero_index(opt);
1302 /* Unlike DHCP, ND6 options *may* occur more than once.
1303 * There is also no provision for option concatenation
1304 * unlike DHCP. */
1305 len = rap->data_len -
1306 ((size_t)((const uint8_t *)ND_CFIRST_OPTION(rap) -
1307 rap->data));
1309 for (o = ND_CFIRST_OPTION(rap);
1310 len >= (ssize_t)sizeof(*o);
1311 o = ND_CNEXT_OPTION(o))
1313 if ((size_t)o->nd_opt_len * 8 > len) {
1314 errno = EINVAL;
1315 break;
1317 len -= (size_t)(o->nd_opt_len * 8);
1318 if (has_option_mask(rap->iface->options->nomasknd,
1319 o->nd_opt_type))
1320 continue;
1321 for (j = 0, opt = rap->iface->options->nd_override;
1322 j < rap->iface->options->nd_override_len;
1323 j++, opt++)
1324 if (opt->option == o->nd_opt_type)
1325 break;
1326 if (j == rap->iface->options->nd_override_len) {
1327 for (j = 0, opt = rap->iface->ctx->nd_opts;
1328 j < rap->iface->ctx->nd_opts_len;
1329 j++, opt++)
1330 if (opt->option == o->nd_opt_type)
1331 break;
1332 if (j == rap->iface->ctx->nd_opts_len)
1333 opt = NULL;
1335 if (opt) {
1336 n += dhcp_envoption(rap->iface->ctx,
1337 env == NULL ? NULL : &env[n],
1338 ndprefix, rap->iface->name,
1339 opt, ipv6nd_getoption,
1340 ND_COPTION_DATA(o), ND_OPTION_LEN(o));
1344 /* We need to output the addresses we actually made
1345 * from the prefix information options as well. */
1346 j = 0;
1347 TAILQ_FOREACH(ia, &rap->addrs, next) {
1348 if (!(ia->flags & IPV6_AF_AUTOCONF)
1349 #ifdef IPV6_AF_TEMPORARY
1350 || ia->flags & IPV6_AF_TEMPORARY
1351 #endif
1353 continue;
1354 j++;
1355 if (env) {
1356 snprintf(abuf, sizeof(abuf), "addr%zu", j);
1357 setvar(rap->iface->ctx, &env[n], ndprefix,
1358 abuf, ia->saddr);
1360 n++;
1363 return (ssize_t)n;
1366 void
1367 ipv6nd_handleifa(struct dhcpcd_ctx *ctx, int cmd, const char *ifname,
1368 const struct in6_addr *addr, int flags)
1370 struct ra *rap;
1372 if (ctx->ipv6 == NULL)
1373 return;
1374 TAILQ_FOREACH(rap, ctx->ipv6->ra_routers, next) {
1375 if (strcmp(rap->iface->name, ifname))
1376 continue;
1377 ipv6_handleifa_addrs(cmd, &rap->addrs, addr, flags);
1381 void
1382 ipv6nd_expirera(void *arg)
1384 struct interface *ifp;
1385 struct ra *rap, *ran;
1386 struct timespec now, lt, expire, next;
1387 uint8_t expired, valid, validone;
1389 ifp = arg;
1390 clock_gettime(CLOCK_MONOTONIC, &now);
1391 expired = 0;
1392 timespecclear(&next);
1394 validone = 0;
1395 TAILQ_FOREACH_SAFE(rap, ifp->ctx->ipv6->ra_routers, next, ran) {
1396 if (rap->iface != ifp)
1397 continue;
1398 valid = 0;
1399 if (rap->lifetime) {
1400 lt.tv_sec = (time_t)rap->lifetime;
1401 lt.tv_nsec = 0;
1402 timespecadd(&rap->acquired, &lt, &expire);
1403 if (rap->lifetime == 0 || timespeccmp(&now, &expire, >))
1405 if (!rap->expired) {
1406 logger(ifp->ctx, LOG_WARNING,
1407 "%s: %s: router expired",
1408 ifp->name, rap->sfrom);
1409 rap->expired = expired = 1;
1410 rap->lifetime = 0;
1412 } else {
1413 valid = 1;
1414 timespecsub(&expire, &now, &lt);
1415 if (!timespecisset(&next) ||
1416 timespeccmp(&next, &lt, >))
1417 next = lt;
1421 /* XXX FixMe!
1422 * We need to extract the lifetime from each option and check
1423 * if that has expired or not.
1424 * If it has, zero the option out in the returned data. */
1426 /* No valid lifetimes are left on the RA, so we might
1427 * as well punt it. */
1428 if (!valid && TAILQ_FIRST(&rap->addrs) == NULL)
1429 ipv6nd_free_ra(rap);
1430 else
1431 validone = 1;
1434 if (timespecisset(&next))
1435 eloop_timeout_add_tv(ifp->ctx->eloop,
1436 &next, ipv6nd_expirera, ifp);
1437 if (expired) {
1438 ipv6_buildroutes(ifp->ctx);
1439 script_runreason(ifp, "ROUTERADVERT");
1442 /* No valid routers? Kill any DHCPv6. */
1443 if (!validone)
1444 dhcp6_drop(ifp, "EXPIRE6");
1447 void
1448 ipv6nd_drop(struct interface *ifp)
1450 struct ra *rap;
1451 uint8_t expired = 0;
1452 TAILQ_HEAD(rahead, ra) rtrs;
1454 if (ifp->ctx->ipv6 == NULL)
1455 return;
1457 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
1458 TAILQ_INIT(&rtrs);
1459 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
1460 if (rap->iface == ifp) {
1461 rap->expired = expired = 1;
1462 TAILQ_REMOVE(ifp->ctx->ipv6->ra_routers, rap, next);
1463 TAILQ_INSERT_TAIL(&rtrs, rap, next);
1466 if (expired) {
1467 while ((rap = TAILQ_FIRST(&rtrs))) {
1468 TAILQ_REMOVE(&rtrs, rap, next);
1469 ipv6nd_drop_ra(rap);
1471 ipv6_buildroutes(ifp->ctx);
1472 if ((ifp->options->options & DHCPCD_NODROP) != DHCPCD_NODROP)
1473 script_runreason(ifp, "ROUTERADVERT");
1477 static void
1478 ipv6nd_handlena(struct dhcpcd_ctx *dctx, struct interface *ifp,
1479 struct icmp6_hdr *icp, size_t len, int hoplimit)
1481 struct ipv6_ctx *ctx = dctx->ipv6;
1482 struct nd_neighbor_advert *nd_na;
1483 struct ra *rap;
1484 uint32_t is_router, is_solicited;
1485 char buf[INET6_ADDRSTRLEN];
1486 const char *taddr;
1488 if (ifp == NULL) {
1489 #ifdef DEBUG_NS
1490 logger(ctx, LOG_DEBUG, "NA for unexpected interface from %s",
1491 dctx->sfrom);
1492 #endif
1493 return;
1496 if ((size_t)len < sizeof(struct nd_neighbor_advert)) {
1497 logger(ifp->ctx, LOG_ERR, "%s: IPv6 NA too short from %s",
1498 ifp->name, ctx->sfrom);
1499 return;
1502 /* RFC 4861 7.1.2 */
1503 if (hoplimit != 255) {
1504 logger(dctx, LOG_ERR,
1505 "invalid hoplimit(%d) in NA from %s", hoplimit, ctx->sfrom);
1506 return;
1509 nd_na = (struct nd_neighbor_advert *)icp;
1510 is_router = nd_na->nd_na_flags_reserved & ND_NA_FLAG_ROUTER;
1511 is_solicited = nd_na->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED;
1512 taddr = inet_ntop(AF_INET6, &nd_na->nd_na_target,
1513 buf, INET6_ADDRSTRLEN);
1515 if (IN6_IS_ADDR_MULTICAST(&nd_na->nd_na_target)) {
1516 logger(ifp->ctx, LOG_ERR, "%s: NA multicast address %s (%s)",
1517 ifp->name, taddr, ctx->sfrom);
1518 return;
1521 TAILQ_FOREACH(rap, ctx->ra_routers, next) {
1522 if (rap->iface == ifp &&
1523 IN6_ARE_ADDR_EQUAL(&rap->from, &nd_na->nd_na_target))
1524 break;
1526 if (rap == NULL) {
1527 #ifdef DEBUG_NS
1528 logger(ifp->ctx, LOG_DEBUG, "%s: unexpected NA from %s for %s",
1529 ifp->name, ctx->sfrom, taddr);
1530 #endif
1531 return;
1534 #ifdef DEBUG_NS
1535 logger(ifp->ctx, LOG_DEBUG, "%s: %sNA for %s from %s",
1536 ifp->name, is_solicited ? "solicited " : "", taddr, ctx->sfrom);
1537 #endif
1539 /* Node is no longer a router, so remove it from consideration */
1540 if (!is_router && !rap->expired) {
1541 logger(ifp->ctx, LOG_INFO, "%s: %s not a router (%s)",
1542 ifp->name, taddr, ctx->sfrom);
1543 rap->expired = 1;
1544 ipv6_buildroutes(ifp->ctx);
1545 script_runreason(ifp, "ROUTERADVERT");
1546 return;
1549 if (is_solicited && is_router && rap->lifetime) {
1550 if (rap->expired) {
1551 rap->expired = 0;
1552 logger(ifp->ctx, LOG_INFO, "%s: %s reachable (%s)",
1553 ifp->name, taddr, ctx->sfrom);
1554 ipv6_buildroutes(ifp->ctx);
1555 script_runreason(rap->iface, "ROUTERADVERT"); /* XXX */
1560 static void
1561 ipv6nd_handledata(void *arg)
1563 struct dhcpcd_ctx *dctx;
1564 struct ipv6_ctx *ctx;
1565 ssize_t len;
1566 struct cmsghdr *cm;
1567 int hoplimit;
1568 struct in6_pktinfo pkt;
1569 struct icmp6_hdr *icp;
1570 struct interface *ifp;
1572 dctx = arg;
1573 ctx = dctx->ipv6;
1574 ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
1575 CMSG_SPACE(sizeof(int));
1576 len = recvmsg(ctx->nd_fd, &ctx->rcvhdr, 0);
1577 if (len == -1) {
1578 logger(dctx, LOG_ERR, "recvmsg: %m");
1579 eloop_event_delete(dctx->eloop, ctx->nd_fd);
1580 close(ctx->nd_fd);
1581 ctx->nd_fd = -1;
1582 return;
1584 ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr,
1585 ctx->ntopbuf, INET6_ADDRSTRLEN);
1586 if ((size_t)len < sizeof(struct icmp6_hdr)) {
1587 logger(dctx, LOG_ERR, "IPv6 ICMP packet too short from %s",
1588 ctx->sfrom);
1589 return;
1592 pkt.ipi6_ifindex = 0;
1593 hoplimit = 0;
1594 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&ctx->rcvhdr);
1596 cm = (struct cmsghdr *)CMSG_NXTHDR(&ctx->rcvhdr, cm))
1598 if (cm->cmsg_level != IPPROTO_IPV6)
1599 continue;
1600 switch(cm->cmsg_type) {
1601 case IPV6_PKTINFO:
1602 if (cm->cmsg_len == CMSG_LEN(sizeof(pkt)))
1603 memcpy(&pkt, CMSG_DATA(cm), sizeof(pkt));
1604 break;
1605 case IPV6_HOPLIMIT:
1606 if (cm->cmsg_len == CMSG_LEN(sizeof(int)))
1607 memcpy(&hoplimit, CMSG_DATA(cm), sizeof(int));
1608 break;
1612 if (pkt.ipi6_ifindex == 0) {
1613 logger(dctx, LOG_ERR,
1614 "IPv6 RA/NA did not contain index from %s",
1615 ctx->sfrom);
1616 return;
1619 TAILQ_FOREACH(ifp, dctx->ifaces, next) {
1620 if (ifp->index == (unsigned int)pkt.ipi6_ifindex) {
1621 if (!(ifp->options->options & DHCPCD_IPV6))
1622 return;
1623 break;
1627 icp = (struct icmp6_hdr *)ctx->rcvhdr.msg_iov[0].iov_base;
1628 if (icp->icmp6_code == 0) {
1629 switch(icp->icmp6_type) {
1630 case ND_NEIGHBOR_ADVERT:
1631 ipv6nd_handlena(dctx, ifp, icp, (size_t)len,
1632 hoplimit);
1633 return;
1634 case ND_ROUTER_ADVERT:
1635 ipv6nd_handlera(dctx, ifp, icp, (size_t)len,
1636 hoplimit);
1637 return;
1641 logger(dctx, LOG_ERR, "invalid IPv6 type %d or code %d from %s",
1642 icp->icmp6_type, icp->icmp6_code, ctx->sfrom);
1645 static void
1646 ipv6nd_startrs1(void *arg)
1648 struct interface *ifp = arg;
1649 struct rs_state *state;
1651 logger(ifp->ctx, LOG_INFO, "%s: soliciting an IPv6 router", ifp->name);
1652 if (ipv6nd_open(ifp->ctx) == -1) {
1653 logger(ifp->ctx, LOG_ERR, "%s: ipv6nd_open: %m", __func__);
1654 return;
1657 state = RS_STATE(ifp);
1658 if (state == NULL) {
1659 ifp->if_data[IF_DATA_IPV6ND] = calloc(1, sizeof(*state));
1660 state = RS_STATE(ifp);
1661 if (state == NULL) {
1662 logger(ifp->ctx, LOG_ERR, "%s: %m", __func__);
1663 return;
1667 /* Always make a new probe as the underlying hardware
1668 * address could have changed. */
1669 ipv6nd_makersprobe(ifp);
1670 if (state->rs == NULL) {
1671 logger(ifp->ctx, LOG_ERR,
1672 "%s: ipv6ns_makersprobe: %m", __func__);
1673 return;
1676 state->rsprobes = 0;
1677 ipv6nd_sendrsprobe(ifp);
1680 void
1681 ipv6nd_startrs(struct interface *ifp)
1683 struct timespec tv;
1685 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
1686 if (!(ifp->options->options & DHCPCD_INITIAL_DELAY)) {
1687 ipv6nd_startrs1(ifp);
1688 return;
1691 tv.tv_sec = 0;
1692 tv.tv_nsec = (suseconds_t)arc4random_uniform(
1693 MAX_RTR_SOLICITATION_DELAY * NSEC_PER_SEC);
1694 timespecnorm(&tv);
1695 logger(ifp->ctx, LOG_DEBUG,
1696 "%s: delaying IPv6 router solicitation for %0.1f seconds",
1697 ifp->name, timespec_to_double(&tv));
1698 eloop_timeout_add_tv(ifp->ctx->eloop, &tv, ipv6nd_startrs1, ifp);
1699 return;