]> git.ipfire.org Git - thirdparty/dhcpcd.git/blame - ipv6nd.c
RFC2131 section 4.4.1 states the client SHOULD wait a random time between
[thirdparty/dhcpcd.git] / ipv6nd.c
CommitLineData
8cc47ba2 1/*
91cd7324 2 * dhcpcd - DHCP client daemon
fad320b9 3 * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
91cd7324
RM
4 * All rights reserved
5
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
eebe9a18 28#include <sys/ioctl.h>
91cd7324
RM
29#include <sys/param.h>
30#include <sys/socket.h>
31#include <net/if.h>
32#include <netinet/in.h>
33#include <netinet/ip6.h>
34#include <netinet/icmp6.h>
35
d7555c12
RM
36#ifdef __linux__
37# define _LINUX_IN6_H
38# include <linux/ipv6.h>
39#endif
40
91cd7324 41#include <errno.h>
e8c8e9b9 42#include <fcntl.h>
91cd7324
RM
43#include <stddef.h>
44#include <stdlib.h>
45#include <string.h>
46#include <syslog.h>
fbbb0875 47#include <unistd.h>
91cd7324 48
e6ca60ee 49#define ELOOP_QUEUE 2
91cd7324 50#include "common.h"
91cd7324 51#include "dhcpcd.h"
d7555c12 52#include "dhcp6.h"
91cd7324 53#include "eloop.h"
eebe9a18 54#include "ipv6.h"
e82129a4 55#include "ipv6nd.h"
294eff4d 56#include "script.h"
91cd7324 57
d7555c12
RM
58/* Debugging Router Solicitations is a lot of spam, so disable it */
59//#define DEBUG_RS
60
91cd7324
RM
61#define RTR_SOLICITATION_INTERVAL 4 /* seconds */
62#define MAX_RTR_SOLICITATIONS 3 /* times */
63
64#ifndef ND_OPT_RDNSS
65#define ND_OPT_RDNSS 25
66struct nd_opt_rdnss { /* RDNSS option RFC 6106 */
67 uint8_t nd_opt_rdnss_type;
68 uint8_t nd_opt_rdnss_len;
69 uint16_t nd_opt_rdnss_reserved;
70 uint32_t nd_opt_rdnss_lifetime;
71 /* followed by list of IP prefixes */
3491ea4d 72} __packed;
91cd7324
RM
73#endif
74
75#ifndef ND_OPT_DNSSL
76#define ND_OPT_DNSSL 31
77struct nd_opt_dnssl { /* DNSSL option RFC 6106 */
78 uint8_t nd_opt_dnssl_type;
79 uint8_t nd_opt_dnssl_len;
80 uint16_t nd_opt_dnssl_reserved;
81 uint32_t nd_opt_dnssl_lifetime;
82 /* followed by list of DNS servers */
3491ea4d 83} __packed;
91cd7324
RM
84#endif
85
eebe9a18
RM
86/* Minimal IPv6 MTU */
87#ifndef IPV6_MMTU
88#define IPV6_MMTU 1280
89#endif
90
91#ifndef ND_RA_FLAG_RTPREF_HIGH
92#define ND_RA_FLAG_RTPREF_MASK 0x18
93#define ND_RA_FLAG_RTPREF_HIGH 0x08
94#define ND_RA_FLAG_RTPREF_MEDIUM 0x00
95#define ND_RA_FLAG_RTPREF_LOW 0x18
96#define ND_RA_FLAG_RTPREF_RSV 0x10
97#endif
98
99/* RTPREF_MEDIUM has to be 0! */
100#define RTPREF_HIGH 1
101#define RTPREF_MEDIUM 0
102#define RTPREF_LOW (-1)
103#define RTPREF_RESERVED (-2)
104#define RTPREF_INVALID (-3) /* internal */
105
e82129a4
RM
106#define MIN_RANDOM_FACTOR 500 /* millisecs */
107#define MAX_RANDOM_FACTOR 1500 /* millisecs */
108#define MIN_RANDOM_FACTOR_U MIN_RANDOM_FACTOR * 1000 /* usecs */
109#define MAX_RANDOM_FACTOR_U MAX_RANDOM_FACTOR * 1000 /* usecs */
110
111#if BYTE_ORDER == BIG_ENDIAN
112#define IPV6_ADDR_INT32_ONE 1
113#define IPV6_ADDR_INT16_MLL 0xff02
114#elif BYTE_ORDER == LITTLE_ENDIAN
115#define IPV6_ADDR_INT32_ONE 0x01000000
116#define IPV6_ADDR_INT16_MLL 0x02ff
117#endif
118
119/* Debugging Neighbor Solicitations is a lot of spam, so disable it */
120//#define DEBUG_NS
121//
122
8d5de853 123static void ipv6nd_handledata(void *);
ae4f8bd7 124static void ipv6nd_startproberouter(struct ra *);
7cece083 125
65e5b9f9
RM
126/*
127 * Android ships buggy ICMP6 filter headers.
128 * Supply our own until they fix their shit.
129 * References:
130 * https://android-review.googlesource.com/#/c/58438/
131 * http://code.google.com/p/android/issues/original?id=32621&seq=24
132 */
133#ifdef __ANDROID__
134#undef ICMP6_FILTER_WILLPASS
135#undef ICMP6_FILTER_WILLBLOCK
136#undef ICMP6_FILTER_SETPASS
137#undef ICMP6_FILTER_SETBLOCK
138#undef ICMP6_FILTER_SETPASSALL
139#undef ICMP6_FILTER_SETBLOCKALL
140#define ICMP6_FILTER_WILLPASS(type, filterp) \
141 ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) == 0)
142#define ICMP6_FILTER_WILLBLOCK(type, filterp) \
143 ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) != 0)
144#define ICMP6_FILTER_SETPASS(type, filterp) \
145 ((((filterp)->icmp6_filt[(type) >> 5]) &= ~(1 << ((type) & 31))))
146#define ICMP6_FILTER_SETBLOCK(type, filterp) \
147 ((((filterp)->icmp6_filt[(type) >> 5]) |= (1 << ((type) & 31))))
148#define ICMP6_FILTER_SETPASSALL(filterp) \
149 memset(filterp, 0, sizeof(struct icmp6_filter));
150#define ICMP6_FILTER_SETBLOCKALL(filterp) \
151 memset(filterp, 0xff, sizeof(struct icmp6_filter));
152#endif
153
62247de8
RM
154/* Support older systems with different defines */
155#if !defined(IPV6_RECVHOPLIMIT) && defined(IPV6_HOPLIMIT)
156#define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
157#endif
158#if !defined(IPV6_RECVPKTINFO) && defined(IPV6_PKTINFO)
159#define IPV6_RECVPKTINFO IPV6_PKTINFO
160#endif
161
aae24feb 162static int
4eb7b489 163ipv6nd_open(struct dhcpcd_ctx *dctx)
91cd7324 164{
4eb7b489 165 struct ipv6_ctx *ctx;
91cd7324 166 int on;
4eb7b489 167 struct icmp6_filter filt;
91cd7324 168
4eb7b489
RM
169 ctx = dctx->ipv6;
170 if (ctx->nd_fd != -1)
608fd9f4 171 return ctx->nd_fd;
e8c8e9b9 172#ifdef SOCK_CLOEXEC
4eb7b489 173 ctx->nd_fd = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
cc050202 174 IPPROTO_ICMPV6);
4eb7b489 175 if (ctx->nd_fd == -1)
fbbb0875 176 return -1;
e8c8e9b9
RM
177#else
178 if ((ctx->nd_fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1)
179 return -1;
180 if ((on = fcntl(ctx->nd_fd, F_GETFD, 0)) == -1 ||
181 fcntl(ctx->nd_fd, F_SETFD, on | FD_CLOEXEC) == -1)
182 {
183 close(ctx->nd_fd);
184 ctx->nd_fd = -1;
185 return -1;
186 }
187 if ((on = fcntl(ctx->nd_fd, F_GETFL, 0)) == -1 ||
188 fcntl(ctx->nd_fd, F_SETFL, on | O_NONBLOCK) == -1)
189 {
190 close(ctx->nd_fd);
191 ctx->nd_fd = -1;
192 return -1;
193 }
194#endif
fbbb0875 195
cc431339
RM
196 /* RFC4861 4.1 */
197 on = 255;
198 if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
199 &on, sizeof(on)) == -1)
200 goto eexit;
201
91cd7324 202 on = 1;
4eb7b489
RM
203 if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
204 &on, sizeof(on)) == -1)
fbbb0875 205 goto eexit;
91cd7324
RM
206
207 on = 1;
4eb7b489
RM
208 if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
209 &on, sizeof(on)) == -1)
fbbb0875 210 goto eexit;
91cd7324
RM
211
212 ICMP6_FILTER_SETBLOCKALL(&filt);
4eb7b489 213 ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filt);
91cd7324 214 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
4eb7b489
RM
215 if (setsockopt(ctx->nd_fd, IPPROTO_ICMPV6, ICMP6_FILTER,
216 &filt, sizeof(filt)) == -1)
fbbb0875 217 goto eexit;
fbbb0875 218
4eb7b489 219 eloop_event_add(dctx->eloop, ctx->nd_fd, ipv6nd_handledata, dctx);
4eb7b489 220 return ctx->nd_fd;
e82129a4
RM
221
222eexit:
4eb7b489 223 if (ctx->nd_fd != -1) {
4eb7b489 224 eloop_event_delete(dctx->eloop, ctx->nd_fd);
e9882fb0 225 close(ctx->nd_fd);
4eb7b489
RM
226 ctx->nd_fd = -1;
227 }
e82129a4
RM
228 return -1;
229}
230
231static int
232ipv6nd_makersprobe(struct interface *ifp)
91cd7324 233{
ca15a0aa 234 struct rs_state *state;
91cd7324
RM
235 struct nd_router_solicit *rs;
236 struct nd_opt_hdr *nd;
237
ca15a0aa
RM
238 state = RS_STATE(ifp);
239 free(state->rs);
240 state->rslen = sizeof(*rs) + ROUNDUP8(ifp->hwlen + 2);
10e17e3f 241 state->rs = calloc(1, state->rslen);
ca15a0aa 242 if (state->rs == NULL)
91cd7324 243 return -1;
ca15a0aa 244 rs = (struct nd_router_solicit *)(void *)state->rs;
91cd7324
RM
245 rs->nd_rs_type = ND_ROUTER_SOLICIT;
246 rs->nd_rs_code = 0;
247 rs->nd_rs_cksum = 0;
248 rs->nd_rs_reserved = 0;
ca15a0aa 249 nd = (struct nd_opt_hdr *)(state->rs + sizeof(*rs));
91cd7324
RM
250 nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
251 nd->nd_opt_len = (ROUNDUP8(ifp->hwlen + 2)) >> 3;
252 memcpy(nd + 1, ifp->hwaddr, ifp->hwlen);
253 return 0;
254}
673e81e5 255
91cd7324 256static void
e82129a4 257ipv6nd_sendrsprobe(void *arg)
91cd7324
RM
258{
259 struct interface *ifp = arg;
4eb7b489 260 struct ipv6_ctx *ctx;
ca15a0aa 261 struct rs_state *state;
91cd7324
RM
262 struct sockaddr_in6 dst;
263 struct cmsghdr *cm;
264 struct in6_pktinfo pi;
91cd7324 265
0e906716 266 if (ipv6_linklocal(ifp) == NULL) {
5331b839 267 syslog(LOG_DEBUG,
5301406a 268 "%s: delaying Router Solicitation for LL address",
5331b839 269 ifp->name);
e82129a4 270 ipv6_addlinklocalcallback(ifp, ipv6nd_sendrsprobe, ifp);
5331b839
RM
271 return;
272 }
273
4eb7b489
RM
274 memset(&dst, 0, sizeof(dst));
275 dst.sin6_family = AF_INET6;
276#ifdef SIN6_LEN
277 dst.sin6_len = sizeof(dst);
278#endif
22f64b55 279 dst.sin6_scope_id = ifp->index;
4eb7b489
RM
280 if (inet_pton(AF_INET6, ALLROUTERS, &dst.sin6_addr.s6_addr) != 1) {
281 syslog(LOG_ERR, "%s: %m", __func__);
282 return;
283 }
91cd7324 284
ca15a0aa 285 state = RS_STATE(ifp);
4eb7b489
RM
286 ctx = ifp->ctx->ipv6;
287 ctx->sndhdr.msg_name = (caddr_t)&dst;
288 ctx->sndhdr.msg_iov[0].iov_base = state->rs;
289 ctx->sndhdr.msg_iov[0].iov_len = state->rslen;
91cd7324
RM
290
291 /* Set the outbound interface */
4eb7b489 292 cm = CMSG_FIRSTHDR(&ctx->sndhdr);
8fc52ced
RM
293 if (cm == NULL) /* unlikely */
294 return;
91cd7324
RM
295 cm->cmsg_level = IPPROTO_IPV6;
296 cm->cmsg_type = IPV6_PKTINFO;
297 cm->cmsg_len = CMSG_LEN(sizeof(pi));
298 memset(&pi, 0, sizeof(pi));
2c77247b 299 pi.ipi6_ifindex = ifp->index;
91cd7324
RM
300 memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
301
ad574a91 302 syslog(LOG_DEBUG, "%s: sending Router Solicitation", ifp->name);
4eb7b489 303 if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) {
c5d2e393 304 syslog(LOG_ERR, "%s: %s: sendmsg: %m", ifp->name, __func__);
e82129a4 305 ipv6nd_drop(ifp);
7b9cd6f0 306 ifp->options->options &= ~(DHCPCD_IPV6 | DHCPCD_IPV6RS);
83e82504
RM
307 return;
308 }
91cd7324 309
ca15a0aa 310 if (state->rsprobes++ < MAX_RTR_SOLICITATIONS)
4eb7b489
RM
311 eloop_timeout_add_sec(ifp->ctx->eloop,
312 RTR_SOLICITATION_INTERVAL, ipv6nd_sendrsprobe, ifp);
91cd7324 313 else
ad574a91 314 syslog(LOG_WARNING, "%s: no IPv6 Routers available", ifp->name);
91cd7324
RM
315}
316
317static void
e82129a4 318ipv6nd_free_opts(struct ra *rap)
91cd7324 319{
eebe9a18 320 struct ra_opt *rao;
91cd7324 321
eebe9a18
RM
322 while ((rao = TAILQ_FIRST(&rap->options))) {
323 TAILQ_REMOVE(&rap->options, rao, next);
324 free(rao->option);
325 free(rao);
326 }
327}
91cd7324 328
e54dee19 329int
4eb7b489 330ipv6nd_addrexists(struct dhcpcd_ctx *ctx, const struct ipv6_addr *addr)
376e8b80
RM
331{
332 struct ra *rap;
333 struct ipv6_addr *ap;
334
4eb7b489 335 TAILQ_FOREACH(rap, ctx->ipv6->ra_routers, next) {
376e8b80 336 TAILQ_FOREACH(ap, &rap->addrs, next) {
7013b073
RM
337 if (addr == NULL) {
338 if ((ap->flags &
339 (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)) ==
340 (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED))
341 return 1;
73e77470 342 } else if (IN6_ARE_ADDR_EQUAL(&ap->addr, &addr->addr))
376e8b80
RM
343 return 1;
344 }
345 }
346 return 0;
347}
348
e82129a4 349void ipv6nd_freedrop_ra(struct ra *rap, int drop)
eebe9a18
RM
350{
351
4eb7b489
RM
352 eloop_timeout_delete(rap->iface->ctx->eloop, NULL, rap->iface);
353 eloop_timeout_delete(rap->iface->ctx->eloop, NULL, rap);
5b428df2 354 if (!drop)
4eb7b489 355 TAILQ_REMOVE(rap->iface->ctx->ipv6->ra_routers, rap, next);
8fdedf59 356 ipv6_freedrop_addrs(&rap->addrs, drop, NULL);
e82129a4 357 ipv6nd_free_opts(rap);
eebe9a18
RM
358 free(rap->data);
359 free(rap->ns);
360 free(rap);
361}
362
363ssize_t
e82129a4 364ipv6nd_free(struct interface *ifp)
eebe9a18 365{
ca15a0aa 366 struct rs_state *state;
eebe9a18 367 struct ra *rap, *ran;
4eb7b489 368 struct dhcpcd_ctx *ctx;
eebe9a18
RM
369 ssize_t n;
370
ca15a0aa 371 state = RS_STATE(ifp);
a9d78def
RM
372 if (state == NULL)
373 return 0;
374
375 free(state->rs);
376 free(state);
377 ifp->if_data[IF_DATA_IPV6ND] = NULL;
eebe9a18 378 n = 0;
4eb7b489 379 TAILQ_FOREACH_SAFE(rap, ifp->ctx->ipv6->ra_routers, next, ran) {
eebe9a18 380 if (rap->iface == ifp) {
e82129a4 381 ipv6nd_free_ra(rap);
eebe9a18 382 n++;
91cd7324 383 }
eebe9a18 384 }
a9d78def
RM
385
386 /* If we don't have any more IPv6 enabled interfaces,
387 * close the global socket and release resources */
4eb7b489
RM
388 ctx = ifp->ctx;
389 TAILQ_FOREACH(ifp, ctx->ifaces, next) {
a9d78def
RM
390 if (RS_STATE(ifp))
391 break;
392 }
393 if (ifp == NULL) {
4eb7b489 394 if (ctx->ipv6->nd_fd != -1) {
4eb7b489 395 eloop_event_delete(ctx->eloop, ctx->ipv6->nd_fd);
e9882fb0 396 close(ctx->ipv6->nd_fd);
4eb7b489 397 ctx->ipv6->nd_fd = -1;
a9d78def 398 }
a9d78def
RM
399 }
400
eebe9a18
RM
401 return n;
402}
403
404static int
405rtpref(struct ra *rap)
406{
ca15a0aa 407
eebe9a18
RM
408 switch (rap->flags & ND_RA_FLAG_RTPREF_MASK) {
409 case ND_RA_FLAG_RTPREF_HIGH:
410 return (RTPREF_HIGH);
411 case ND_RA_FLAG_RTPREF_MEDIUM:
412 case ND_RA_FLAG_RTPREF_RSV:
413 return (RTPREF_MEDIUM);
414 case ND_RA_FLAG_RTPREF_LOW:
415 return (RTPREF_LOW);
416 default:
417 syslog(LOG_ERR, "rtpref: impossible RA flag %x", rap->flags);
418 return (RTPREF_INVALID);
419 }
420 /* NOTREACHED */
421}
422
423static void
4eb7b489 424add_router(struct ipv6_ctx *ctx, struct ra *router)
eebe9a18
RM
425{
426 struct ra *rap;
427
4eb7b489 428 TAILQ_FOREACH(rap, ctx->ra_routers, next) {
eebe9a18
RM
429 if (router->iface->metric < rap->iface->metric ||
430 (router->iface->metric == rap->iface->metric &&
431 rtpref(router) > rtpref(rap)))
432 {
433 TAILQ_INSERT_BEFORE(rap, router, next);
434 return;
91cd7324
RM
435 }
436 }
4eb7b489 437 TAILQ_INSERT_TAIL(ctx->ra_routers, router, next);
91cd7324
RM
438}
439
b5b066a5 440static int
e82129a4 441ipv6nd_scriptrun(struct ra *rap)
a8df1b28 442{
e2c4a256 443 int hasdns, hasaddress, pid;
d5690e93 444 struct ipv6_addr *ap;
a8df1b28
RM
445 const struct ra_opt *rao;
446
e2c4a256 447 hasaddress = 0;
a8df1b28 448 /* If all addresses have completed DAD run the script */
a8df1b28 449 TAILQ_FOREACH(ap, &rap->addrs, next) {
a824f281
RM
450 if ((ap->flags & (IPV6_AF_ONLINK | IPV6_AF_AUTOCONF)) ==
451 (IPV6_AF_ONLINK | IPV6_AF_AUTOCONF))
452 {
e2c4a256 453 hasaddress = 1;
d5690e93
RM
454 if (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
455 ipv6_findaddr(ap->iface, &ap->addr))
456 ap->flags |= IPV6_AF_DADCOMPLETED;
457 if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0) {
458 syslog(LOG_DEBUG,
459 "%s: waiting for Router Advertisement"
460 " DAD to complete",
461 rap->iface->name);
b5b066a5 462 return 0;
d5690e93 463 }
d8194bcd 464 }
a8df1b28
RM
465 }
466
467 /* If we don't require RDNSS then set hasdns = 1 so we fork */
468 if (!(rap->iface->options->options & DHCPCD_IPV6RA_REQRDNSS))
469 hasdns = 1;
470 else {
471 hasdns = 0;
472 TAILQ_FOREACH(rao, &rap->options, next) {
473 if (rao->type == ND_OPT_RDNSS &&
474 rao->option &&
475 timerisset(&rao->expire))
476 {
477 hasdns = 1;
478 break;
479 }
480 }
481 }
482
483 script_runreason(rap->iface, "ROUTERADVERT");
e2c4a256
RM
484 pid = 0;
485 if (hasdns && (hasaddress ||
486 !(rap->flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER))))
94bec972 487 pid = dhcpcd_daemonise(rap->iface->ctx);
a8df1b28
RM
488#if 0
489 else if (options & DHCPCD_DAEMONISE &&
490 !(options & DHCPCD_DAEMONISED) && new_data)
491 syslog(LOG_WARNING,
492 "%s: did not fork due to an absent"
493 " RDNSS option in the RA",
494 ifp->name);
495}
496#endif
e2c4a256 497 return pid;
a8df1b28
RM
498}
499
d8194bcd 500static void
e82129a4 501ipv6nd_dadcallback(void *arg)
d8194bcd
RM
502{
503 struct ipv6_addr *ap = arg, *rapap;
504 struct interface *ifp;
505 struct ra *rap;
506 int wascompleted, found;
507
46b8a6b7 508 wascompleted = (ap->flags & IPV6_AF_DADCOMPLETED);
46b8a6b7
RM
509 ap->flags |= IPV6_AF_DADCOMPLETED;
510 if (ap->flags & IPV6_AF_DUPLICATED)
d8194bcd
RM
511 /* No idea what how to try and make another address :( */
512 syslog(LOG_WARNING, "%s: DAD detected %s",
513 ap->iface->name, ap->saddr);
d8194bcd
RM
514
515 if (!wascompleted) {
516 ifp = ap->iface;
517
4eb7b489 518 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
d8194bcd
RM
519 if (rap->iface != ifp)
520 continue;
521 wascompleted = 1;
e92ca600 522 found = 0;
d8194bcd 523 TAILQ_FOREACH(rapap, &rap->addrs, next) {
a824f281
RM
524 if (rapap->flags & IPV6_AF_AUTOCONF &&
525 (rapap->flags & IPV6_AF_DADCOMPLETED) == 0)
526 {
d8194bcd
RM
527 wascompleted = 0;
528 break;
529 }
530 if (rapap == ap)
531 found = 1;
532 }
533
4f422dd3 534 if (wascompleted && found) {
ad574a91 535 syslog(LOG_DEBUG,
d8194bcd
RM
536 "%s: Router Advertisement DAD completed",
537 rap->iface->name);
b5b066a5
RM
538 if (ipv6nd_scriptrun(rap))
539 return;
d8194bcd
RM
540 }
541 }
542 }
543}
544
aae24feb 545static void
4eb7b489 546ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
34457fe6 547 struct icmp6_hdr *icp, size_t len)
91cd7324 548{
34457fe6
RM
549 size_t olen, l, m, n;
550 ssize_t r;
7be4b9b3 551 struct nd_router_advert *nd_ra;
91cd7324
RM
552 struct nd_opt_prefix_info *pi;
553 struct nd_opt_mtu *mtu;
554 struct nd_opt_rdnss *rdnss;
555 struct nd_opt_dnssl *dnssl;
eebe9a18 556 uint32_t lifetime, mtuv;
91cd7324
RM
557 uint8_t *p, *op;
558 struct in6_addr addr;
559 char buf[INET6_ADDRSTRLEN];
560 const char *cbp;
561 struct ra *rap;
562 struct nd_opt_hdr *ndo;
eebe9a18
RM
563 struct ra_opt *rao;
564 struct ipv6_addr *ap;
d7555c12 565 char *opt, *tmp;
91cd7324 566 struct timeval expire;
a8df1b28 567 uint8_t new_rap, new_data;
91cd7324 568
34457fe6 569 if (len < sizeof(struct nd_router_advert)) {
4eb7b489 570 syslog(LOG_ERR, "IPv6 RA packet too short from %s", ctx->sfrom);
91cd7324
RM
571 return;
572 }
573
4eb7b489
RM
574 if (!IN6_IS_ADDR_LINKLOCAL(&ctx->from.sin6_addr)) {
575 syslog(LOG_ERR, "RA from non local address %s", ctx->sfrom);
91cd7324
RM
576 return;
577 }
578
91cd7324 579 if (ifp == NULL) {
d7555c12 580#ifdef DEBUG_RS
4eb7b489
RM
581 syslog(LOG_DEBUG, "RA for unexpected interface from %s",
582 ctx->sfrom);
4c6a8bec
RM
583#endif
584 return;
585 }
586 if (!(ifp->options->options & DHCPCD_IPV6RS)) {
587#ifdef DEBUG_RS
588 syslog(LOG_DEBUG, "%s: unexpected RA from %s",
4eb7b489 589 ifp->name, ctx->sfrom);
d7555c12 590#endif
91cd7324
RM
591 return;
592 }
0e906716 593
e7a30a46 594 /* We could receive a RA before we sent a RS*/
0e906716
RM
595 if (ipv6_linklocal(ifp) == NULL) {
596#ifdef DEBUG_RS
597 syslog(LOG_DEBUG, "%s: received RA from %s (no link-local)",
4eb7b489 598 ifp->name, ctx->sfrom);
0e906716
RM
599#endif
600 return;
601 }
602
4eb7b489 603 TAILQ_FOREACH(rap, ctx->ra_routers, next) {
fe292175 604 if (ifp == rap->iface &&
4eb7b489 605 memcmp(rap->from.s6_addr, ctx->from.sin6_addr.s6_addr,
91cd7324
RM
606 sizeof(rap->from.s6_addr)) == 0)
607 break;
608 }
46caaa5e 609
e42bbc9b 610 nd_ra = (struct nd_router_advert *)icp;
e42bbc9b 611
46caaa5e
RM
612 /* We don't want to spam the log with the fact we got an RA every
613 * 30 seconds or so, so only spam the log if it's different. */
ee70f4ab 614 if (rap == NULL || (rap->data_len != len ||
46caaa5e
RM
615 memcmp(rap->data, (unsigned char *)icp, rap->data_len) != 0))
616 {
617 if (rap) {
618 free(rap->data);
619 rap->data_len = 0;
ea112ab2
RM
620 free(rap->ns);
621 rap->ns = NULL;
622 rap->nslen = 0;
46caaa5e 623 }
d7555c12 624 new_data = 1;
d7555c12
RM
625 } else
626 new_data = 0;
ee70f4ab
RM
627 if (new_data || ifp->options->options & DHCPCD_DEBUG)
628 syslog(LOG_INFO, "%s: Router Advertisement from %s",
4eb7b489 629 ifp->name, ctx->sfrom);
46caaa5e 630
91cd7324 631 if (rap == NULL) {
10e17e3f
RM
632 rap = calloc(1, sizeof(*rap));
633 if (rap == NULL) {
634 syslog(LOG_ERR, "%s: %m", __func__);
635 return;
636 }
eebe9a18 637 rap->iface = ifp;
4eb7b489 638 memcpy(rap->from.s6_addr, ctx->from.sin6_addr.s6_addr,
91cd7324 639 sizeof(rap->from.s6_addr));
4eb7b489 640 strlcpy(rap->sfrom, ctx->sfrom, sizeof(rap->sfrom));
eebe9a18
RM
641 TAILQ_INIT(&rap->addrs);
642 TAILQ_INIT(&rap->options);
643 new_rap = 1;
644 } else
645 new_rap = 0;
46caaa5e 646 if (rap->data_len == 0) {
28382337
RM
647 rap->data = malloc(len);
648 if (rap->data == NULL) {
649 syslog(LOG_ERR, "%s: %m", __func__);
650 if (new_rap)
651 free(rap);
652 return;
653 }
46caaa5e
RM
654 memcpy(rap->data, icp, len);
655 rap->data_len = len;
91cd7324
RM
656 }
657
658 get_monotonic(&rap->received);
eebe9a18 659 rap->flags = nd_ra->nd_ra_flags_reserved;
e42bbc9b
RM
660 if (new_rap == 0 && rap->lifetime == 0)
661 syslog(LOG_WARNING, "%s: %s router available",
662 ifp->name, rap->sfrom);
7be4b9b3 663 rap->lifetime = ntohs(nd_ra->nd_ra_router_lifetime);
ea112ab2
RM
664 if (nd_ra->nd_ra_reachable) {
665 rap->reachable = ntohl(nd_ra->nd_ra_reachable);
666 if (rap->reachable > MAX_REACHABLE_TIME)
667 rap->reachable = 0;
668 }
669 if (nd_ra->nd_ra_retransmit)
670 rap->retrans = ntohl(nd_ra->nd_ra_retransmit);
b88df421
RM
671 if (rap->lifetime)
672 rap->expired = 0;
91cd7324
RM
673
674 len -= sizeof(struct nd_router_advert);
675 p = ((uint8_t *)icp) + sizeof(struct nd_router_advert);
91cd7324 676 lifetime = ~0U;
8fc52ced 677 for (; len > 0; p += olen, len -= olen) {
34457fe6 678 if (len < sizeof(struct nd_opt_hdr)) {
4eb7b489 679 syslog(LOG_ERR, "%s: short option", ifp->name);
91cd7324
RM
680 break;
681 }
682 ndo = (struct nd_opt_hdr *)p;
683 olen = ndo->nd_opt_len * 8 ;
684 if (olen == 0) {
685 syslog(LOG_ERR, "%s: zero length option", ifp->name);
686 break;
687 }
688 if (olen > len) {
689 syslog(LOG_ERR,
690 "%s: Option length exceeds message", ifp->name);
691 break;
692 }
693
694 opt = NULL;
695 switch (ndo->nd_opt_type) {
696 case ND_OPT_PREFIX_INFORMATION:
eebe9a18 697 pi = (struct nd_opt_prefix_info *)(void *)ndo;
91cd7324
RM
698 if (pi->nd_opt_pi_len != 4) {
699 syslog(LOG_ERR,
700 "%s: invalid option len for prefix",
701 ifp->name);
702 break;
703 }
704 if (pi->nd_opt_pi_prefix_len > 128) {
705 syslog(LOG_ERR, "%s: invalid prefix len",
706 ifp->name);
707 break;
708 }
709 if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) ||
710 IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix))
711 {
712 syslog(LOG_ERR,
713 "%s: invalid prefix in RA", ifp->name);
714 break;
715 }
e54dee19
RM
716 if (ntohl(pi->nd_opt_pi_preferred_time) >
717 ntohl(pi->nd_opt_pi_valid_time))
718 {
719 syslog(LOG_ERR,
720 "%s: pltime > vltime", ifp->name);
721 break;
722 }
eebe9a18
RM
723 TAILQ_FOREACH(ap, &rap->addrs, next)
724 if (ap->prefix_len ==pi->nd_opt_pi_prefix_len &&
725 memcmp(ap->prefix.s6_addr,
726 pi->nd_opt_pi_prefix.s6_addr,
727 sizeof(ap->prefix.s6_addr)) == 0)
728 break;
729 if (ap == NULL) {
cd3612e5
RM
730 if (!(pi->nd_opt_pi_flags_reserved &
731 ND_OPT_PI_FLAG_AUTO) &&
732 !(pi->nd_opt_pi_flags_reserved &
733 ND_OPT_PI_FLAG_ONLINK))
4242c5f2 734 continue;
66fd5d67 735 ap = calloc(1, sizeof(*ap));
28382337
RM
736 if (ap == NULL) {
737 syslog(LOG_ERR, "%s: %m", __func__);
738 break;
739 }
66fd5d67 740 ap->iface = rap->iface;
a824f281 741 ap->flags = IPV6_AF_NEW;
eebe9a18
RM
742 ap->prefix_len = pi->nd_opt_pi_prefix_len;
743 memcpy(ap->prefix.s6_addr,
744 pi->nd_opt_pi_prefix.s6_addr,
745 sizeof(ap->prefix.s6_addr));
e54dee19
RM
746 if (pi->nd_opt_pi_flags_reserved &
747 ND_OPT_PI_FLAG_AUTO)
748 {
a824f281 749 ap->flags |= IPV6_AF_AUTOCONF;
5331b839 750 ipv6_makeaddr(&ap->addr, ifp,
e54dee19
RM
751 &ap->prefix,
752 pi->nd_opt_pi_prefix_len);
753 cbp = inet_ntop(AF_INET6,
754 ap->addr.s6_addr,
4eb7b489 755 buf, sizeof(buf));
e54dee19
RM
756 if (cbp)
757 snprintf(ap->saddr,
758 sizeof(ap->saddr),
759 "%s/%d",
760 cbp, ap->prefix_len);
761 else
762 ap->saddr[0] = '\0';
763 } else {
764 memset(&ap->addr, 0, sizeof(ap->addr));
eebe9a18 765 ap->saddr[0] = '\0';
e54dee19 766 }
e82129a4 767 ap->dadcallback = ipv6nd_dadcallback;
eebe9a18 768 TAILQ_INSERT_TAIL(&rap->addrs, ap, next);
66fd5d67 769 }
cd3612e5
RM
770 if (pi->nd_opt_pi_flags_reserved &
771 ND_OPT_PI_FLAG_ONLINK)
46b8a6b7 772 ap->flags |= IPV6_AF_ONLINK;
eebe9a18
RM
773 ap->prefix_vltime =
774 ntohl(pi->nd_opt_pi_valid_time);
775 ap->prefix_pltime =
776 ntohl(pi->nd_opt_pi_preferred_time);
66fd5d67 777 ap->nsprobes = 0;
50083515 778 if (opt) {
3af8f2b2
RM
779 l = strlen(opt) + 1;
780 m = strlen(ap->saddr) + 1;
781 tmp = realloc(opt, l + m);
fa245a4d
RM
782 if (tmp) {
783 opt = tmp;
3af8f2b2
RM
784 opt[l - 1] = ' ';
785 strlcpy(opt + l, ap->saddr, m);
fa245a4d 786 }
50083515 787 } else
78369646 788 opt = strdup(ap->saddr);
50083515 789 lifetime = ap->prefix_vltime;
91cd7324
RM
790 break;
791
792 case ND_OPT_MTU:
eebe9a18
RM
793 mtu = (struct nd_opt_mtu *)(void *)p;
794 mtuv = ntohl(mtu->nd_opt_mtu_mtu);
795 if (mtuv < IPV6_MMTU) {
796 syslog(LOG_ERR, "%s: invalid MTU %d",
797 ifp->name, mtuv);
798 break;
799 }
f98846d4 800 rap->mtu = mtuv;
eebe9a18 801 snprintf(buf, sizeof(buf), "%d", mtuv);
78369646 802 opt = strdup(buf);
91cd7324
RM
803 break;
804
805 case ND_OPT_RDNSS:
806 rdnss = (struct nd_opt_rdnss *)p;
807 lifetime = ntohl(rdnss->nd_opt_rdnss_lifetime);
808 op = (uint8_t *)ndo;
809 op += offsetof(struct nd_opt_rdnss,
810 nd_opt_rdnss_lifetime);
811 op += sizeof(rdnss->nd_opt_rdnss_lifetime);
812 l = 0;
c2e168a8
RM
813 for (n = ndo->nd_opt_len - 1; n > 1; n -= 2,
814 op += sizeof(addr.s6_addr))
815 {
34457fe6
RM
816 r = ipv6_printaddr(NULL, 0, op, ifp->name);
817 if (r != -1)
818 l += (size_t)r + 1;
c2e168a8
RM
819 }
820 op = (uint8_t *)ndo;
821 op += offsetof(struct nd_opt_rdnss,
822 nd_opt_rdnss_lifetime);
823 op += sizeof(rdnss->nd_opt_rdnss_lifetime);
824 tmp = opt = malloc(l);
b2e8d8da
RM
825 if (opt) {
826 for (n = ndo->nd_opt_len - 1; n > 1; n -= 2,
827 op += sizeof(addr.s6_addr))
828 {
34457fe6 829 r = ipv6_printaddr(tmp, l, op,
b2e8d8da 830 ifp->name);
34457fe6
RM
831 if (r != -1) {
832 l -= ((size_t)r + 1);
833 tmp += (size_t)r;
b2e8d8da 834 *tmp++ = ' ';
b2e8d8da
RM
835 }
836 }
837 if (tmp != opt)
838 (*--tmp) = '\0';
839 else
840 *opt = '\0';
91cd7324
RM
841 }
842 break;
673e81e5 843
91cd7324
RM
844 case ND_OPT_DNSSL:
845 dnssl = (struct nd_opt_dnssl *)p;
846 lifetime = ntohl(dnssl->nd_opt_dnssl_lifetime);
847 op = p + offsetof(struct nd_opt_dnssl,
848 nd_opt_dnssl_lifetime);
849 op += sizeof(dnssl->nd_opt_dnssl_lifetime);
850 n = (dnssl->nd_opt_dnssl_len - 1) * 8;
34457fe6
RM
851 r = decode_rfc3397(NULL, 0, op, n);
852 if (r < 1) {
91cd7324
RM
853 syslog(LOG_ERR, "%s: invalid DNSSL option",
854 ifp->name);
855 } else {
34457fe6 856 l = (size_t)r;
78369646
RM
857 tmp = malloc(l);
858 if (tmp) {
34457fe6
RM
859 decode_rfc3397(tmp, l, op, n);
860 l -= 1;
861 n = (size_t)print_string(NULL, 0,
862 (const uint8_t *)tmp, l);
78369646
RM
863 opt = malloc(n);
864 if (opt)
865 print_string(opt, n,
34457fe6 866 (const uint8_t *)tmp, l);
78369646
RM
867 free(tmp);
868 }
91cd7324
RM
869 }
870 break;
17b0dbad
RM
871
872 default:
873 continue;
91cd7324
RM
874 }
875
78369646
RM
876 if (opt == NULL) {
877 syslog(LOG_ERR, "%s: %m", __func__);
91cd7324 878 continue;
78369646 879 }
eebe9a18 880 TAILQ_FOREACH(rao, &rap->options, next) {
91cd7324
RM
881 if (rao->type == ndo->nd_opt_type &&
882 strcmp(rao->option, opt) == 0)
883 break;
884 }
885 if (lifetime == 0) {
886 if (rao) {
eebe9a18 887 TAILQ_REMOVE(&rap->options, rao, next);
91cd7324
RM
888 free(rao->option);
889 free(rao);
890 }
f08afbd8 891 free(opt);
91cd7324
RM
892 continue;
893 }
894
895 if (rao == NULL) {
28382337
RM
896 rao = malloc(sizeof(*rao));
897 if (rao == NULL) {
898 syslog(LOG_ERR, "%s: %m", __func__);
899 continue;
900 }
91cd7324
RM
901 rao->type = ndo->nd_opt_type;
902 rao->option = opt;
eebe9a18 903 TAILQ_INSERT_TAIL(&rap->options, rao, next);
bb02dff1
RM
904 } else
905 free(opt);
449df9c8
RM
906 if (lifetime == ~0U)
907 timerclear(&rao->expire);
908 else {
717bc86c 909 expire.tv_sec = (time_t)lifetime;
91cd7324
RM
910 expire.tv_usec = 0;
911 timeradd(&rap->received, &expire, &rao->expire);
912 }
913 }
914
eebe9a18 915 if (new_rap)
4eb7b489
RM
916 add_router(ifp->ctx->ipv6, rap);
917 if (ifp->ctx->options & DHCPCD_TEST) {
294eff4d 918 script_runreason(ifp, "TEST");
d7555c12 919 goto handle_flag;
b88df421 920 }
7529fdf1 921 ipv6_addaddrs(&rap->addrs);
4eb7b489 922 ipv6_buildroutes(ifp->ctx);
4f422dd3
RM
923 if (ipv6nd_scriptrun(rap))
924 return;
61dd6cf9 925
4eb7b489
RM
926 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
927 eloop_timeout_delete(ifp->ctx->eloop, NULL, rap); /* reachable timer */
eebe9a18
RM
928
929 /* If we're owning the RA then we need to try and ensure the
930 * router is actually reachable */
fbbb0875
RM
931 if (ifp->options->options & DHCPCD_IPV6RA_OWN ||
932 ifp->options->options & DHCPCD_IPV6RA_OWN_DEFAULT)
eebe9a18
RM
933 {
934 rap->nsprobes = 0;
e42bbc9b 935 if (rap->lifetime)
ae4f8bd7 936 ipv6nd_startproberouter(rap);
eebe9a18 937 }
d7555c12
RM
938
939handle_flag:
940 if (rap->flags & ND_RA_FLAG_MANAGED) {
4f422dd3 941 if (new_data && dhcp6_start(ifp, DH6S_INIT) == -1)
e54dee19 942 syslog(LOG_ERR, "dhcp6_start: %s: %m", ifp->name);
d7555c12 943 } else if (rap->flags & ND_RA_FLAG_OTHER) {
4f422dd3 944 if (new_data && dhcp6_start(ifp, DH6S_INFORM) == -1)
d7555c12
RM
945 syslog(LOG_ERR, "dhcp6_start: %s: %m", ifp->name);
946 } else {
4f422dd3 947 if (new_data)
d7555c12
RM
948 syslog(LOG_DEBUG, "%s: No DHCPv6 instruction in RA",
949 ifp->name);
4eb7b489
RM
950 if (ifp->ctx->options & DHCPCD_TEST) {
951 eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
a9d78def
RM
952 return;
953 }
d7555c12 954 }
35308011
RM
955
956 /* Expire should be called last as the rap object could be destroyed */
e82129a4 957 ipv6nd_expirera(ifp);
eebe9a18
RM
958}
959
960int
e82129a4 961ipv6nd_has_ra(const struct interface *ifp)
eebe9a18
RM
962{
963 const struct ra *rap;
964
2433e54d
RM
965 if (ifp->ctx->ipv6) {
966 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next)
967 if (rap->iface == ifp)
968 return 1;
969 }
eebe9a18 970 return 0;
91cd7324
RM
971}
972
973ssize_t
e82129a4 974ipv6nd_env(char **env, const char *prefix, const struct interface *ifp)
91cd7324 975{
34457fe6 976 size_t i, len, l;
91cd7324
RM
977 const struct ra *rap;
978 const struct ra_opt *rao;
eebe9a18 979 char buffer[32];
91cd7324 980 const char *optn;
d4e41f4b 981 char **pref, **mtu, **rdnss, **dnssl, ***var, *new;
eebe9a18 982
34457fe6 983 i = l = 0;
4eb7b489 984 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
eebe9a18
RM
985 i++;
986 if (rap->iface != ifp)
987 continue;
91cd7324
RM
988 if (env) {
989 snprintf(buffer, sizeof(buffer),
76bb4d03 990 "ra%zu_from", i);
34457fe6 991 setvar(&env, prefix, buffer, rap->sfrom);
91cd7324
RM
992 }
993 l++;
449df9c8 994
f98846d4 995 pref = mtu = rdnss = dnssl = NULL;
eebe9a18 996 TAILQ_FOREACH(rao, &rap->options, next) {
91cd7324
RM
997 if (rao->option == NULL)
998 continue;
f98846d4
RM
999 var = NULL;
1000 switch(rao->type) {
91cd7324
RM
1001 case ND_OPT_PREFIX_INFORMATION:
1002 optn = "prefix";
d4e41f4b 1003 var = &pref;
91cd7324
RM
1004 break;
1005 case ND_OPT_MTU:
1006 optn = "mtu";
d4e41f4b 1007 var = &mtu;
91cd7324
RM
1008 break;
1009 case ND_OPT_RDNSS:
1010 optn = "rdnss";
673e81e5 1011 var = &rdnss;
91cd7324
RM
1012 break;
1013 case ND_OPT_DNSSL:
1014 optn = "dnssl";
d4e41f4b 1015 var = &dnssl;
91cd7324
RM
1016 break;
1017 default:
1018 continue;
1019 }
d4e41f4b
RM
1020 if (*var == NULL) {
1021 *var = env ? env : &new;
1022 l++;
1023 } else if (env) {
f98846d4
RM
1024 /* With single only options, last one takes
1025 * precedence */
1026 if (rao->type == ND_OPT_MTU) {
1027 new = strchr(**var, '=');
1028 if (new == NULL) {
1029 syslog(LOG_ERR, "new is null");
1030 continue;
1031 } else
1032 new++;
34457fe6 1033 len = (size_t)(new - **var) +
e54dee19 1034 strlen(rao->option) + 1;
f98846d4
RM
1035 if (len > strlen(**var))
1036 new = realloc(**var, len);
1037 else
1038 new = **var;
1039 if (new) {
1040 **var = new;
1041 new = strchr(**var, '=');
3af8f2b2 1042 if (new) {
34457fe6
RM
1043 len -=
1044 (size_t)
1045 (new - **var);
3af8f2b2
RM
1046 strlcpy(new + 1,
1047 rao->option,
1048 len - 1);
1049 } else
e54dee19
RM
1050 syslog(LOG_ERR,
1051 "new is null");
f98846d4
RM
1052 }
1053 continue;
1054 }
3af8f2b2
RM
1055 len = strlen(rao->option) + 1;
1056 new = realloc(**var, strlen(**var) + 1 + len);
34457fe6
RM
1057 if (new) {
1058 **var = new;
1059 new += strlen(new);
1060 *new++ = ' ';
1061 strlcpy(new, rao->option, len);
1062 } else
1063 syslog(LOG_ERR, "%s: %m", __func__);
28382337 1064 continue;
d4e41f4b
RM
1065 }
1066 if (env) {
1067 snprintf(buffer, sizeof(buffer),
76bb4d03 1068 "ra%zu_%s", i, optn);
34457fe6 1069 setvar(&env, prefix, buffer, rao->option);
d4e41f4b 1070 }
91cd7324
RM
1071 }
1072 }
1073
34457fe6
RM
1074 if (env)
1075 setvard(&env, prefix, "ra_count", i);
91cd7324 1076 l++;
34457fe6 1077 return (ssize_t)l;
91cd7324
RM
1078}
1079
a8df1b28 1080void
4eb7b489 1081ipv6nd_handleifa(struct dhcpcd_ctx *ctx, int cmd, const char *ifname,
d8194bcd 1082 const struct in6_addr *addr, int flags)
a8df1b28
RM
1083{
1084 struct ra *rap;
a8df1b28 1085
4eb7b489
RM
1086 if (ctx->ipv6 == NULL)
1087 return;
1088 TAILQ_FOREACH(rap, ctx->ipv6->ra_routers, next) {
a8df1b28
RM
1089 if (strcmp(rap->iface->name, ifname))
1090 continue;
d8194bcd 1091 ipv6_handleifa_addrs(cmd, &rap->addrs, addr, flags);
a8df1b28
RM
1092 }
1093}
1094
53017d65
RM
1095static void
1096ipv6nd_unreachable(void *arg)
1097{
1098 struct ra *rap = arg;
53017d65
RM
1099
1100 /* We could add an unreachable flag and persist the information,
1101 * but that is more effort than it's probably worth. */
1102 syslog(LOG_WARNING, "%s: %s is unreachable, expiring it",
1103 rap->iface->name, rap->sfrom);
1104 rap->expired = 1;
1105 ipv6_buildroutes(rap->iface->ctx);
1106 script_runreason(rap->iface, "ROUTERADVERT"); /* XXX not RA */
53017d65
RM
1107}
1108
1109static void
ae4f8bd7 1110ipv6nd_proberouter(void *arg)
53017d65 1111{
8d5de853 1112 struct ra *rap = arg;
53017d65
RM
1113 struct nd_neighbor_solicit *ns;
1114 struct nd_opt_hdr *nd;
1115 struct sockaddr_in6 dst;
1116 struct cmsghdr *cm;
1117 struct in6_pktinfo pi;
1118 struct ipv6_ctx *ctx;
ae4f8bd7 1119 struct timeval tv;
53017d65
RM
1120
1121 if (ipv6nd_open(rap->iface->ctx) == -1) {
1122 syslog(LOG_ERR, "%s: ipv6nd_open: %m", __func__);
1123 return;
1124 }
1125
1126 if (!rap->ns) {
1127 rap->nslen = sizeof(*ns) + ROUNDUP8(rap->iface->hwlen + 2);
1128 rap->ns = calloc(1, rap->nslen);
1129 if (rap->ns == NULL) {
1130 syslog(LOG_ERR, "%s: %m", __func__);
1131 return;
1132 }
1133 ns = (struct nd_neighbor_solicit *)(void *)rap->ns;
1134 ns->nd_ns_type = ND_NEIGHBOR_SOLICIT;
1135 //ns->nd_ns_cksum = 0;
1136 //ns->nd_ns_code = 0;
1137 //ns->nd_ns_reserved = 0;
1138 ns->nd_ns_target = rap->from;
1139 nd = (struct nd_opt_hdr *)(rap->ns + sizeof(*ns));
1140 nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
1141 nd->nd_opt_len = (ROUNDUP8(rap->iface->hwlen + 2)) >> 3;
1142 memcpy(nd + 1, rap->iface->hwaddr, rap->iface->hwlen);
1143 }
1144
1145 memset(&dst, 0, sizeof(dst));
1146 dst.sin6_family = AF_INET6;
1147#ifdef SIN6_LEN
1148 dst.sin6_len = sizeof(dst);
1149#endif
1150 memcpy(&dst.sin6_addr, &rap->from, sizeof(dst.sin6_addr));
1151 dst.sin6_scope_id = rap->iface->index;
1152
1153 ctx = rap->iface->ctx->ipv6;
1154 ctx->sndhdr.msg_name = (caddr_t)&dst;
1155 ctx->sndhdr.msg_iov[0].iov_base = rap->ns;
1156 ctx->sndhdr.msg_iov[0].iov_len = rap->nslen;
1157
1158 /* Set the outbound interface */
1159 cm = CMSG_FIRSTHDR(&ctx->sndhdr);
1160 if (cm == NULL) /* unlikely */
1161 return;
1162 cm->cmsg_level = IPPROTO_IPV6;
1163 cm->cmsg_type = IPV6_PKTINFO;
1164 cm->cmsg_len = CMSG_LEN(sizeof(pi));
1165 memset(&pi, 0, sizeof(pi));
1166 pi.ipi6_ifindex = rap->iface->index;
1167 memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
1168
e0328e42 1169#ifdef DEBUG_NS
53017d65
RM
1170 syslog(LOG_INFO, "%s: sending IPv6 NS for %s",
1171 rap->iface->name, rap->sfrom);
e0328e42 1172#endif
53017d65
RM
1173 if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) {
1174 syslog(LOG_ERR, "%s: %s: sendmsg: %m",
1175 rap->iface->name, __func__);
1176 return;
1177 }
1178
3c35f66f
RM
1179 if (rap->nsprobes++ == 0)
1180 eloop_timeout_add_sec(rap->iface->ctx->eloop,
1181 DELAY_FIRST_PROBE_TIME,
1182 ipv6nd_proberouter, rap);
1183 else {
1184 /* MAX_UNICAST_PROBES applies to this retrans loop,
1185 * so take one away for the above DELAY probe */
1186 ms_to_tv(&tv, rap->retrans ? rap->retrans : RETRANS_TIMER);
1187 eloop_timeout_add_tv(rap->iface->ctx->eloop, &tv,
1188 rap->nsprobes <= MAX_UNICAST_SOLICIT ?
1189 ipv6nd_proberouter : ipv6nd_unreachable,
1190 rap);
1191 }
53017d65
RM
1192}
1193
1194static void
ae4f8bd7
RM
1195ipv6nd_cancelproberouter(struct ra *rap)
1196{
1197
1198 eloop_timeout_delete(rap->iface->ctx->eloop, ipv6nd_proberouter, rap);
ae4f8bd7
RM
1199 eloop_timeout_delete(rap->iface->ctx->eloop, ipv6nd_unreachable, rap);
1200}
1201
1202
1203static void
1204ipv6nd_startproberouter(struct ra *rap)
53017d65 1205{
53017d65
RM
1206 struct timeval tv, rtv;
1207
ae4f8bd7 1208 ipv6nd_cancelproberouter(rap);
3c35f66f 1209 rap->nsprobes = 0;
ae4f8bd7
RM
1210
1211 ms_to_tv(&tv, rap->reachable ? rap->reachable : REACHABLE_TIME);
53017d65
RM
1212 ms_to_tv(&rtv, MIN_RANDOM_FACTOR);
1213 timeradd(&tv, &rtv, &tv);
1214 rtv.tv_sec = 0;
1215 rtv.tv_usec = arc4random() % (MAX_RANDOM_FACTOR_U -MIN_RANDOM_FACTOR_U);
1216 timeradd(&tv, &rtv, &tv);
1217 eloop_timeout_add_tv(rap->iface->ctx->eloop,
3c35f66f 1218 &tv, ipv6nd_proberouter, rap);
53017d65
RM
1219}
1220
91cd7324 1221void
e82129a4 1222ipv6nd_expirera(void *arg)
91cd7324
RM
1223{
1224 struct interface *ifp;
eebe9a18
RM
1225 struct ra *rap, *ran;
1226 struct ra_opt *rao, *raon;
91cd7324 1227 struct timeval now, lt, expire, next;
d4e41f4b 1228 int expired, valid;
91cd7324
RM
1229
1230 ifp = arg;
1231 get_monotonic(&now);
1232 expired = 0;
91cd7324
RM
1233 timerclear(&next);
1234
4eb7b489 1235 TAILQ_FOREACH_SAFE(rap, ifp->ctx->ipv6->ra_routers, next, ran) {
eebe9a18
RM
1236 if (rap->iface != ifp)
1237 continue;
4f422dd3
RM
1238 valid = 0;
1239 if (rap->lifetime) {
717bc86c 1240 lt.tv_sec = (time_t)rap->lifetime;
4f422dd3
RM
1241 lt.tv_usec = 0;
1242 timeradd(&rap->received, &lt, &expire);
1243 if (rap->lifetime == 0 || timercmp(&now, &expire, >)) {
1244 if (!rap->expired) {
1245 syslog(LOG_WARNING,
1246 "%s: %s: router expired",
1247 ifp->name, rap->sfrom);
1248 rap->expired = expired = 1;
1249 ipv6nd_cancelproberouter(rap);
1250 }
1251 } else {
1252 valid = 1;
1253 timersub(&expire, &now, &lt);
1254 if (!timerisset(&next) ||
1255 timercmp(&next, &lt, >))
1256 next = lt;
35308011 1257 }
35308011
RM
1258 }
1259
7529fdf1 1260 /* Addresses are expired in ipv6_addaddrs
78ae7296 1261 * so that DHCPv6 addresses can be removed also. */
eebe9a18 1262 TAILQ_FOREACH_SAFE(rao, &rap->options, next, raon) {
47102c83
RM
1263 if (rap->expired) {
1264 switch(rao->type) {
1265 case ND_OPT_RDNSS: /* FALLTHROUGH */
1266 case ND_OPT_DNSSL:
1267 /* RFC6018 end of section 5.2 states
1268 * that if tha RA has a lifetime of 0
1269 * then we should expire these
1270 * options */
1271 TAILQ_REMOVE(&rap->options, rao, next);
1272 expired = 1;
1273 free(rao->option);
1274 free(rao);
1275 continue;
1276 }
1277 }
449df9c8
RM
1278 if (!timerisset(&rao->expire))
1279 continue;
1280 if (timercmp(&now, &rao->expire, >)) {
35308011
RM
1281 /* Expired prefixes are logged above */
1282 if (rao->type != ND_OPT_PREFIX_INFORMATION)
ad574a91 1283 syslog(LOG_WARNING,
35308011
RM
1284 "%s: %s: expired option %d",
1285 ifp->name, rap->sfrom, rao->type);
eebe9a18
RM
1286 TAILQ_REMOVE(&rap->options, rao, next);
1287 expired = 1;
1288 free(rao->option);
1289 free(rao);
449df9c8
RM
1290 continue;
1291 }
d4e41f4b 1292 valid = 1;
449df9c8 1293 timersub(&rao->expire, &now, &lt);
91cd7324
RM
1294 if (!timerisset(&next) || timercmp(&next, &lt, >))
1295 next = lt;
1296 }
d4e41f4b
RM
1297
1298 /* No valid lifetimes are left on the RA, so we might
1299 * as well punt it. */
e42bbc9b 1300 if (!valid && TAILQ_FIRST(&rap->addrs) == NULL)
e82129a4 1301 ipv6nd_free_ra(rap);
91cd7324
RM
1302 }
1303
1304 if (timerisset(&next))
4eb7b489
RM
1305 eloop_timeout_add_tv(ifp->ctx->eloop,
1306 &next, ipv6nd_expirera, ifp);
e82129a4 1307 if (expired) {
4eb7b489 1308 ipv6_buildroutes(ifp->ctx);
e82129a4
RM
1309 script_runreason(ifp, "ROUTERADVERT");
1310 }
1311}
1312
1313void
1314ipv6nd_drop(struct interface *ifp)
1315{
1316 struct ra *rap;
1317 int expired = 0;
1318 TAILQ_HEAD(rahead, ra) rtrs;
1319
2433e54d
RM
1320 if (ifp->ctx->ipv6 == NULL)
1321 return;
1322
4eb7b489 1323 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
e82129a4 1324 TAILQ_INIT(&rtrs);
4eb7b489 1325 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
e82129a4
RM
1326 if (rap->iface == ifp) {
1327 rap->expired = expired = 1;
4eb7b489 1328 TAILQ_REMOVE(ifp->ctx->ipv6->ra_routers, rap, next);
e82129a4
RM
1329 TAILQ_INSERT_TAIL(&rtrs, rap, next);
1330 }
1331 }
eebe9a18 1332 if (expired) {
e82129a4
RM
1333 while ((rap = TAILQ_FIRST(&rtrs))) {
1334 TAILQ_REMOVE(&rtrs, rap, next);
1335 ipv6nd_drop_ra(rap);
1336 }
4eb7b489 1337 ipv6_buildroutes(ifp->ctx);
15fc1181
RM
1338 if ((ifp->options->options &
1339 (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
1340 (DHCPCD_EXITING | DHCPCD_PERSISTENT))
1341 script_runreason(ifp, "ROUTERADVERT");
e82129a4
RM
1342 }
1343}
a9d78def 1344
e82129a4 1345static void
4eb7b489 1346ipv6nd_handlena(struct ipv6_ctx *ctx, struct interface *ifp,
34457fe6 1347 struct icmp6_hdr *icp, size_t len)
e82129a4
RM
1348{
1349 struct nd_neighbor_advert *nd_na;
1350 struct ra *rap;
1351 int is_router, is_solicited;
e82129a4 1352
e82129a4 1353 if ((size_t)len < sizeof(struct nd_neighbor_advert)) {
4eb7b489 1354 syslog(LOG_ERR, "IPv6 NA packet too short from %s", ctx->sfrom);
e82129a4
RM
1355 return;
1356 }
1357
1358 if (ifp == NULL) {
1359#ifdef DEBUG_NS
4eb7b489
RM
1360 syslog(LOG_DEBUG, "NA for unexpected interface from %s",
1361 ctx->sfrom);
e82129a4
RM
1362#endif
1363 return;
1364 }
1365
1366 nd_na = (struct nd_neighbor_advert *)icp;
1367 is_router = nd_na->nd_na_flags_reserved & ND_NA_FLAG_ROUTER;
1368 is_solicited = nd_na->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED;
1369
1370 if (IN6_IS_ADDR_MULTICAST(&nd_na->nd_na_target)) {
1371 syslog(LOG_ERR, "%s: NA for multicast address from %s",
4eb7b489 1372 ifp->name, ctx->sfrom);
e82129a4
RM
1373 return;
1374 }
1375
4eb7b489 1376 TAILQ_FOREACH(rap, ctx->ra_routers, next) {
7529fdf1
RM
1377 if (rap->iface == ifp &&
1378 memcmp(rap->from.s6_addr, nd_na->nd_na_target.s6_addr,
e82129a4
RM
1379 sizeof(rap->from.s6_addr)) == 0)
1380 break;
e82129a4
RM
1381 }
1382 if (rap == NULL) {
e82129a4 1383#ifdef DEBUG_NS
7529fdf1
RM
1384 syslog(LOG_DEBUG, "%s: unexpected NA from s",
1385 ifp->name, ctx->sfrom);
e82129a4
RM
1386#endif
1387 return;
1388 }
1389
1390#ifdef DEBUG_NS
1391 syslog(LOG_DEBUG, "%s: %sNA from %s",
4eb7b489 1392 ifp->name, is_solicited ? "solicited " : "", ctx->sfrom);
e82129a4
RM
1393#endif
1394
1395 /* Node is no longer a router, so remove it from consideration */
1396 if (!is_router && !rap->expired) {
1397 syslog(LOG_INFO, "%s: %s is no longer a router",
4eb7b489 1398 ifp->name, ctx->sfrom);
e82129a4
RM
1399 rap->expired = 1;
1400 ipv6nd_cancelproberouter(rap);
4eb7b489 1401 ipv6_buildroutes(ifp->ctx);
294eff4d 1402 script_runreason(ifp, "ROUTERADVERT");
e82129a4
RM
1403 return;
1404 }
1405
1406 if (is_solicited && is_router && rap->lifetime) {
1407 if (rap->expired) {
1408 rap->expired = 0;
1409 syslog(LOG_INFO, "%s: %s is reachable again",
4eb7b489
RM
1410 ifp->name, ctx->sfrom);
1411 ipv6_buildroutes(ifp->ctx);
e82129a4
RM
1412 script_runreason(rap->iface, "ROUTERADVERT"); /* XXX */
1413 }
ae4f8bd7 1414 ipv6nd_startproberouter(rap);
eebe9a18 1415 }
91cd7324
RM
1416}
1417
e82129a4 1418static void
4eb7b489 1419ipv6nd_handledata(void *arg)
e82129a4 1420{
4eb7b489
RM
1421 struct dhcpcd_ctx *dhcpcd_ctx;
1422 struct ipv6_ctx *ctx;
e82129a4
RM
1423 ssize_t len;
1424 struct cmsghdr *cm;
1425 int hoplimit;
1426 struct in6_pktinfo pkt;
1427 struct icmp6_hdr *icp;
1428 struct interface *ifp;
1429
4eb7b489
RM
1430 dhcpcd_ctx = arg;
1431 ctx = dhcpcd_ctx->ipv6;
b826c088
RM
1432 ctx->rcvhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
1433 CMSG_SPACE(sizeof(int));
4eb7b489 1434 len = recvmsg(ctx->nd_fd, &ctx->rcvhdr, 0);
68e67270 1435 if (len == -1 || len == 0) {
e82129a4 1436 syslog(LOG_ERR, "recvmsg: %m");
68e67270
RM
1437 eloop_event_delete(dhcpcd_ctx->eloop, ctx->nd_fd);
1438 close(ctx->nd_fd);
1439 ctx->nd_fd = -1;
e82129a4
RM
1440 return;
1441 }
4eb7b489
RM
1442 ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr,
1443 ctx->ntopbuf, INET6_ADDRSTRLEN);
e82129a4 1444 if ((size_t)len < sizeof(struct icmp6_hdr)) {
4eb7b489
RM
1445 syslog(LOG_ERR, "IPv6 ICMP packet too short from %s",
1446 ctx->sfrom);
e82129a4
RM
1447 return;
1448 }
1449
1450 pkt.ipi6_ifindex = hoplimit = 0;
4eb7b489 1451 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&ctx->rcvhdr);
e82129a4 1452 cm;
4eb7b489 1453 cm = (struct cmsghdr *)CMSG_NXTHDR(&ctx->rcvhdr, cm))
e82129a4
RM
1454 {
1455 if (cm->cmsg_level != IPPROTO_IPV6)
1456 continue;
1457 switch(cm->cmsg_type) {
1458 case IPV6_PKTINFO:
1459 if (cm->cmsg_len == CMSG_LEN(sizeof(pkt)))
1460 memcpy(&pkt, CMSG_DATA(cm), sizeof(pkt));
1461 break;
1462 case IPV6_HOPLIMIT:
1463 if (cm->cmsg_len == CMSG_LEN(sizeof(int)))
1464 memcpy(&hoplimit, CMSG_DATA(cm), sizeof(int));
1465 break;
1466 }
1467 }
1468
1469 if (pkt.ipi6_ifindex == 0 || hoplimit == 0) {
1470 syslog(LOG_ERR,
4eb7b489
RM
1471 "IPv6 RA/NA did not contain index or hop limit from %s",
1472 ctx->sfrom);
e82129a4
RM
1473 return;
1474 }
1475
4eb7b489 1476 TAILQ_FOREACH(ifp, dhcpcd_ctx->ifaces, next) {
e82129a4
RM
1477 if (ifp->index == (unsigned int)pkt.ipi6_ifindex)
1478 break;
1479 }
1480
4eb7b489 1481 icp = (struct icmp6_hdr *)ctx->rcvhdr.msg_iov[0].iov_base;
e82129a4
RM
1482 if (icp->icmp6_code == 0) {
1483 switch(icp->icmp6_type) {
1484 case ND_NEIGHBOR_ADVERT:
34457fe6 1485 ipv6nd_handlena(ctx, ifp, icp, (size_t)len);
e82129a4
RM
1486 return;
1487 case ND_ROUTER_ADVERT:
34457fe6 1488 ipv6nd_handlera(ctx, ifp, icp, (size_t)len);
e82129a4
RM
1489 return;
1490 }
1491 }
7cece083 1492
e82129a4 1493 syslog(LOG_ERR, "invalid IPv6 type %d or code %d from %s",
4eb7b489 1494 icp->icmp6_type, icp->icmp6_code, ctx->sfrom);
e82129a4
RM
1495}
1496
6e6e06af
RM
1497static int
1498ipv6nd_startrs1(void *arg)
91cd7324 1499{
6e6e06af 1500 struct interface *ifp = arg;
ca15a0aa 1501 struct rs_state *state;
6e6e06af 1502 struct timeval tv;
91cd7324 1503
e42bbc9b 1504 syslog(LOG_INFO, "%s: soliciting an IPv6 router", ifp->name);
4eb7b489
RM
1505 if (ipv6nd_open(ifp->ctx) == -1) {
1506 syslog(LOG_ERR, "%s: ipv6nd_open: %m", __func__);
6e6e06af 1507 return;
ca15a0aa
RM
1508 }
1509
4eb7b489 1510 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
673e81e5
RM
1511
1512 state = RS_STATE(ifp);
1513 if (state == NULL) {
e82129a4 1514 ifp->if_data[IF_DATA_IPV6ND] = calloc(1, sizeof(*state));
673e81e5 1515 state = RS_STATE(ifp);
fbbb0875
RM
1516 if (state == NULL) {
1517 syslog(LOG_ERR, "%s: %m", __func__);
6e6e06af 1518 return;
fbbb0875 1519 }
673e81e5
RM
1520 }
1521
1522 /* Always make a new probe as the underlying hardware
1523 * address could have changed. */
e82129a4 1524 ipv6nd_makersprobe(ifp);
fbbb0875 1525 if (state->rs == NULL) {
e82129a4 1526 syslog(LOG_ERR, "%s: ipv6ns_makersprobe: %m", __func__);
6e6e06af 1527 return;
fbbb0875 1528 }
91cd7324 1529
ca15a0aa 1530 state->rsprobes = 0;
e82129a4 1531 ipv6nd_sendrsprobe(ifp);
6e6e06af
RM
1532}
1533
1534void
1535ipv6nd_startrs(struct interface *ifp)
1536{
1537 struct timeval tv;
1538
1539 tv.tv_sec = 0;
1540 tv.tv_usec = (suseconds_t)(arc4random() %
1541 (MAX_RTR_SOLICITATION_DELAY * 1000000));
1542 timernorm(&tv);
1543 syslog(LOG_DEBUG,
1544 "%s: delaying IPv6 router solictation for %0.1f seconds",
1545 ifp->name, timeval_to_double(&tv));
1546 eloop_timeout_add_tv(ifp->ctx->eloop, &tv, ipv6nd_startrs1, ifp);
1547 return;
91cd7324 1548}