]> git.ipfire.org Git - thirdparty/dhcpcd.git/blame - ipv6nd.c
Fix some possible pointer checks.
[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
4eb7b489
RM
49/* Currently, no known kernel allows us to send from the unspecified address
50 * which is required for DAD to work. This isn't that much of a problem as
51 * the kernel will do DAD for us correctly, however we don't know the exact
52 * randomness the kernel applies to the timeouts. So we just follow the same
53 * logic and have a little faith.
54 * This define is purely for completeness */
55// #define IPV6_SEND_DAD
56
e6ca60ee 57#define ELOOP_QUEUE 2
91cd7324 58#include "common.h"
91cd7324 59#include "dhcpcd.h"
d7555c12 60#include "dhcp6.h"
91cd7324 61#include "eloop.h"
eebe9a18 62#include "ipv6.h"
e82129a4 63#include "ipv6nd.h"
294eff4d 64#include "script.h"
91cd7324 65
0acfc5e3
RM
66#if defined(LISTEN_DAD) && defined(INET6)
67# warning kernel does not report DAD results to userland
68# warning listening to duplicated addresses on the wire
69#endif
70
d7555c12
RM
71/* Debugging Router Solicitations is a lot of spam, so disable it */
72//#define DEBUG_RS
73
91cd7324
RM
74#define RTR_SOLICITATION_INTERVAL 4 /* seconds */
75#define MAX_RTR_SOLICITATIONS 3 /* times */
76
77#ifndef ND_OPT_RDNSS
78#define ND_OPT_RDNSS 25
79struct nd_opt_rdnss { /* RDNSS option RFC 6106 */
80 uint8_t nd_opt_rdnss_type;
81 uint8_t nd_opt_rdnss_len;
82 uint16_t nd_opt_rdnss_reserved;
83 uint32_t nd_opt_rdnss_lifetime;
84 /* followed by list of IP prefixes */
3491ea4d 85} __packed;
91cd7324
RM
86#endif
87
88#ifndef ND_OPT_DNSSL
89#define ND_OPT_DNSSL 31
90struct nd_opt_dnssl { /* DNSSL option RFC 6106 */
91 uint8_t nd_opt_dnssl_type;
92 uint8_t nd_opt_dnssl_len;
93 uint16_t nd_opt_dnssl_reserved;
94 uint32_t nd_opt_dnssl_lifetime;
95 /* followed by list of DNS servers */
3491ea4d 96} __packed;
91cd7324
RM
97#endif
98
eebe9a18
RM
99/* Minimal IPv6 MTU */
100#ifndef IPV6_MMTU
101#define IPV6_MMTU 1280
102#endif
103
104#ifndef ND_RA_FLAG_RTPREF_HIGH
105#define ND_RA_FLAG_RTPREF_MASK 0x18
106#define ND_RA_FLAG_RTPREF_HIGH 0x08
107#define ND_RA_FLAG_RTPREF_MEDIUM 0x00
108#define ND_RA_FLAG_RTPREF_LOW 0x18
109#define ND_RA_FLAG_RTPREF_RSV 0x10
110#endif
111
112/* RTPREF_MEDIUM has to be 0! */
113#define RTPREF_HIGH 1
114#define RTPREF_MEDIUM 0
115#define RTPREF_LOW (-1)
116#define RTPREF_RESERVED (-2)
117#define RTPREF_INVALID (-3) /* internal */
118
e82129a4
RM
119#define MIN_RANDOM_FACTOR 500 /* millisecs */
120#define MAX_RANDOM_FACTOR 1500 /* millisecs */
121#define MIN_RANDOM_FACTOR_U MIN_RANDOM_FACTOR * 1000 /* usecs */
122#define MAX_RANDOM_FACTOR_U MAX_RANDOM_FACTOR * 1000 /* usecs */
123
124#if BYTE_ORDER == BIG_ENDIAN
125#define IPV6_ADDR_INT32_ONE 1
126#define IPV6_ADDR_INT16_MLL 0xff02
127#elif BYTE_ORDER == LITTLE_ENDIAN
128#define IPV6_ADDR_INT32_ONE 0x01000000
129#define IPV6_ADDR_INT16_MLL 0x02ff
130#endif
131
132/* Debugging Neighbor Solicitations is a lot of spam, so disable it */
133//#define DEBUG_NS
134//
135
7cece083
RM
136static void ipv6nd_handledata(void *arg);
137
65e5b9f9
RM
138/*
139 * Android ships buggy ICMP6 filter headers.
140 * Supply our own until they fix their shit.
141 * References:
142 * https://android-review.googlesource.com/#/c/58438/
143 * http://code.google.com/p/android/issues/original?id=32621&seq=24
144 */
145#ifdef __ANDROID__
146#undef ICMP6_FILTER_WILLPASS
147#undef ICMP6_FILTER_WILLBLOCK
148#undef ICMP6_FILTER_SETPASS
149#undef ICMP6_FILTER_SETBLOCK
150#undef ICMP6_FILTER_SETPASSALL
151#undef ICMP6_FILTER_SETBLOCKALL
152#define ICMP6_FILTER_WILLPASS(type, filterp) \
153 ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) == 0)
154#define ICMP6_FILTER_WILLBLOCK(type, filterp) \
155 ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) != 0)
156#define ICMP6_FILTER_SETPASS(type, filterp) \
157 ((((filterp)->icmp6_filt[(type) >> 5]) &= ~(1 << ((type) & 31))))
158#define ICMP6_FILTER_SETBLOCK(type, filterp) \
159 ((((filterp)->icmp6_filt[(type) >> 5]) |= (1 << ((type) & 31))))
160#define ICMP6_FILTER_SETPASSALL(filterp) \
161 memset(filterp, 0, sizeof(struct icmp6_filter));
162#define ICMP6_FILTER_SETBLOCKALL(filterp) \
163 memset(filterp, 0xff, sizeof(struct icmp6_filter));
164#endif
165
aae24feb 166static int
4eb7b489 167ipv6nd_open(struct dhcpcd_ctx *dctx)
91cd7324 168{
4eb7b489 169 struct ipv6_ctx *ctx;
91cd7324 170 int on;
4eb7b489 171 struct icmp6_filter filt;
e82129a4
RM
172#ifdef IPV6_SEND_DAD
173 union {
174 struct sockaddr sa;
175 struct sockaddr_in6 sin;
176 } su;
177#endif
91cd7324 178
4eb7b489
RM
179 ctx = dctx->ipv6;
180 if (ctx->nd_fd != -1)
181 goto unspec;
e8c8e9b9 182#ifdef SOCK_CLOEXEC
4eb7b489 183 ctx->nd_fd = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
cc050202 184 IPPROTO_ICMPV6);
4eb7b489 185 if (ctx->nd_fd == -1)
fbbb0875 186 return -1;
e8c8e9b9
RM
187#else
188 if ((ctx->nd_fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1)
189 return -1;
190 if ((on = fcntl(ctx->nd_fd, F_GETFD, 0)) == -1 ||
191 fcntl(ctx->nd_fd, F_SETFD, on | FD_CLOEXEC) == -1)
192 {
193 close(ctx->nd_fd);
194 ctx->nd_fd = -1;
195 return -1;
196 }
197 if ((on = fcntl(ctx->nd_fd, F_GETFL, 0)) == -1 ||
198 fcntl(ctx->nd_fd, F_SETFL, on | O_NONBLOCK) == -1)
199 {
200 close(ctx->nd_fd);
201 ctx->nd_fd = -1;
202 return -1;
203 }
204#endif
fbbb0875 205
91cd7324 206 on = 1;
4eb7b489
RM
207 if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
208 &on, sizeof(on)) == -1)
fbbb0875 209 goto eexit;
91cd7324
RM
210
211 on = 1;
4eb7b489
RM
212 if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
213 &on, sizeof(on)) == -1)
fbbb0875 214 goto eexit;
91cd7324
RM
215
216 ICMP6_FILTER_SETBLOCKALL(&filt);
4eb7b489 217 ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filt);
91cd7324 218 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
4eb7b489
RM
219 if (setsockopt(ctx->nd_fd, IPPROTO_ICMPV6, ICMP6_FILTER,
220 &filt, sizeof(filt)) == -1)
fbbb0875 221 goto eexit;
fbbb0875 222
4eb7b489 223 eloop_event_add(dctx->eloop, ctx->nd_fd, ipv6nd_handledata, dctx);
91cd7324 224
4eb7b489 225unspec:
e82129a4 226#ifdef IPV6_SEND_DAD
4eb7b489
RM
227 if (ctx->unspec_fd != -1)
228 return ctx->nd_fd;
e82129a4 229
4eb7b489 230 ICMP6_FILTER_SETBLOCKALL(&filt);
e82129a4 231
e82129a4 232 /* We send DAD requests from the unspecified address. */
e8c8e9b9
RM
233#ifdef SOCK_CLOEXEC
234 ctx->unspec_fd = socket(AF_INET6,
235 SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
236 IPPROTO_ICMPV6);
4eb7b489 237 if (ctx->unspec_fd == -1)
e8c8e9b9
RM
238 return -1;
239#else
240 if ((ctx->unspec_fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1)
241 return -1;
242 if ((on = fcntl(ctx->unspec_fd, F_GETFD, 0)) == -1 ||
243 fcntl(ctx->unspec_fd, F_SETFD, on | FD_CLOEXEC) == -1)
244 {
245 close(ctx->unspec_fd);
246 ctx->unspec_fd = -1;
247 return -1;
248 }
249 if ((on = fcntl(ctx->unspec_fd, F_GETFL, 0)) == -1 ||
250 fcntl(ctx->unspec_fd, F_SETFL, on | O_NONBLOCK) == -1)
251 {
252 close(ctx->unspec_fd);
253 ctx->unspec_fd = -1;
254 return -1;
255 }
256#endif
257
4eb7b489
RM
258 if (setsockopt(ctx->unspec_fd, IPPROTO_ICMPV6, ICMP6_FILTER,
259 &filt, sizeof(filt)) == -1)
e82129a4
RM
260 goto eexit;
261 memset(&su, 0, sizeof(su));
262 su.sin.sin6_family = AF_INET6;
263#ifdef SIN6_LEN
264 su.sin.sin6_len = sizeof(su.sin);
265#endif
4eb7b489 266 if (bind(ctx->unspec_fd, &su.sa, sizeof(su.sin)) == -1)
e82129a4
RM
267 goto eexit;
268#endif
269
e82129a4 270#ifdef LISTEN_DAD
0d033d17
RM
271 if (!ctx->dad_warned) {
272 syslog(LOG_WARNING,
273 "kernel does not report DAD results to userland");
274 syslog(LOG_WARNING,
275 "warning listening to duplicated addresses on the wire");
276 ctx->dad_warned = 1;
277 }
e82129a4
RM
278#endif
279
4eb7b489 280 return ctx->nd_fd;
e82129a4
RM
281
282eexit:
4eb7b489 283 if (ctx->nd_fd != -1) {
4eb7b489 284 eloop_event_delete(dctx->eloop, ctx->nd_fd);
e9882fb0 285 close(ctx->nd_fd);
4eb7b489
RM
286 ctx->nd_fd = -1;
287 }
5b0fe196 288#ifdef IPV6_SEND_DAD
4eb7b489
RM
289 if (ctx->unpsec_fd != -1) {
290 close(ctx->unspec_fd);
291 ctx->unspec_fd = -1;
292 }
e82129a4
RM
293#endif
294 return -1;
295}
296
297static int
298ipv6nd_makersprobe(struct interface *ifp)
91cd7324 299{
ca15a0aa 300 struct rs_state *state;
91cd7324
RM
301 struct nd_router_solicit *rs;
302 struct nd_opt_hdr *nd;
303
ca15a0aa
RM
304 state = RS_STATE(ifp);
305 free(state->rs);
306 state->rslen = sizeof(*rs) + ROUNDUP8(ifp->hwlen + 2);
10e17e3f 307 state->rs = calloc(1, state->rslen);
ca15a0aa 308 if (state->rs == NULL)
91cd7324 309 return -1;
ca15a0aa 310 rs = (struct nd_router_solicit *)(void *)state->rs;
91cd7324
RM
311 rs->nd_rs_type = ND_ROUTER_SOLICIT;
312 rs->nd_rs_code = 0;
313 rs->nd_rs_cksum = 0;
314 rs->nd_rs_reserved = 0;
ca15a0aa 315 nd = (struct nd_opt_hdr *)(state->rs + sizeof(*rs));
91cd7324
RM
316 nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
317 nd->nd_opt_len = (ROUNDUP8(ifp->hwlen + 2)) >> 3;
318 memcpy(nd + 1, ifp->hwaddr, ifp->hwlen);
319 return 0;
320}
673e81e5 321
91cd7324 322static void
e82129a4 323ipv6nd_sendrsprobe(void *arg)
91cd7324
RM
324{
325 struct interface *ifp = arg;
4eb7b489 326 struct ipv6_ctx *ctx;
ca15a0aa 327 struct rs_state *state;
91cd7324
RM
328 struct sockaddr_in6 dst;
329 struct cmsghdr *cm;
330 struct in6_pktinfo pi;
331 int hoplimit = HOPLIMIT;
332
0e906716 333 if (ipv6_linklocal(ifp) == NULL) {
5331b839 334 syslog(LOG_DEBUG,
5301406a 335 "%s: delaying Router Solicitation for LL address",
5331b839 336 ifp->name);
e82129a4 337 ipv6_addlinklocalcallback(ifp, ipv6nd_sendrsprobe, ifp);
5331b839
RM
338 return;
339 }
340
4eb7b489
RM
341 memset(&dst, 0, sizeof(dst));
342 dst.sin6_family = AF_INET6;
343#ifdef SIN6_LEN
344 dst.sin6_len = sizeof(dst);
345#endif
22f64b55 346 dst.sin6_scope_id = ifp->index;
4eb7b489
RM
347 if (inet_pton(AF_INET6, ALLROUTERS, &dst.sin6_addr.s6_addr) != 1) {
348 syslog(LOG_ERR, "%s: %m", __func__);
349 return;
350 }
91cd7324 351
ca15a0aa 352 state = RS_STATE(ifp);
4eb7b489
RM
353 ctx = ifp->ctx->ipv6;
354 ctx->sndhdr.msg_name = (caddr_t)&dst;
355 ctx->sndhdr.msg_iov[0].iov_base = state->rs;
356 ctx->sndhdr.msg_iov[0].iov_len = state->rslen;
91cd7324
RM
357
358 /* Set the outbound interface */
4eb7b489 359 cm = CMSG_FIRSTHDR(&ctx->sndhdr);
91cd7324
RM
360 cm->cmsg_level = IPPROTO_IPV6;
361 cm->cmsg_type = IPV6_PKTINFO;
362 cm->cmsg_len = CMSG_LEN(sizeof(pi));
363 memset(&pi, 0, sizeof(pi));
2c77247b 364 pi.ipi6_ifindex = ifp->index;
91cd7324
RM
365 memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
366
367 /* Hop limit */
4eb7b489 368 cm = CMSG_NXTHDR(&ctx->sndhdr, cm);
91cd7324
RM
369 cm->cmsg_level = IPPROTO_IPV6;
370 cm->cmsg_type = IPV6_HOPLIMIT;
371 cm->cmsg_len = CMSG_LEN(sizeof(hoplimit));
372 memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit));
373
ad574a91 374 syslog(LOG_DEBUG, "%s: sending Router Solicitation", ifp->name);
4eb7b489 375 if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) {
c5d2e393 376 syslog(LOG_ERR, "%s: %s: sendmsg: %m", ifp->name, __func__);
e82129a4 377 ipv6nd_drop(ifp);
7b9cd6f0 378 ifp->options->options &= ~(DHCPCD_IPV6 | DHCPCD_IPV6RS);
83e82504
RM
379 return;
380 }
91cd7324 381
ca15a0aa 382 if (state->rsprobes++ < MAX_RTR_SOLICITATIONS)
4eb7b489
RM
383 eloop_timeout_add_sec(ifp->ctx->eloop,
384 RTR_SOLICITATION_INTERVAL, ipv6nd_sendrsprobe, ifp);
91cd7324 385 else
ad574a91 386 syslog(LOG_WARNING, "%s: no IPv6 Routers available", ifp->name);
91cd7324
RM
387}
388
389static void
e82129a4 390ipv6nd_free_opts(struct ra *rap)
91cd7324 391{
eebe9a18 392 struct ra_opt *rao;
91cd7324 393
eebe9a18
RM
394 while ((rao = TAILQ_FIRST(&rap->options))) {
395 TAILQ_REMOVE(&rap->options, rao, next);
396 free(rao->option);
397 free(rao);
398 }
399}
91cd7324 400
e54dee19 401int
4eb7b489 402ipv6nd_addrexists(struct dhcpcd_ctx *ctx, const struct ipv6_addr *addr)
376e8b80
RM
403{
404 struct ra *rap;
405 struct ipv6_addr *ap;
406
4eb7b489 407 TAILQ_FOREACH(rap, ctx->ipv6->ra_routers, next) {
376e8b80 408 TAILQ_FOREACH(ap, &rap->addrs, next) {
7013b073
RM
409 if (addr == NULL) {
410 if ((ap->flags &
411 (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED)) ==
412 (IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED))
413 return 1;
73e77470 414 } else if (IN6_ARE_ADDR_EQUAL(&ap->addr, &addr->addr))
376e8b80
RM
415 return 1;
416 }
417 }
418 return 0;
419}
420
e82129a4 421void ipv6nd_freedrop_ra(struct ra *rap, int drop)
eebe9a18
RM
422{
423
4eb7b489
RM
424 eloop_timeout_delete(rap->iface->ctx->eloop, NULL, rap->iface);
425 eloop_timeout_delete(rap->iface->ctx->eloop, NULL, rap);
5b428df2 426 if (!drop)
4eb7b489 427 TAILQ_REMOVE(rap->iface->ctx->ipv6->ra_routers, rap, next);
8fdedf59 428 ipv6_freedrop_addrs(&rap->addrs, drop, NULL);
e82129a4 429 ipv6nd_free_opts(rap);
eebe9a18
RM
430 free(rap->data);
431 free(rap->ns);
432 free(rap);
433}
434
435ssize_t
e82129a4 436ipv6nd_free(struct interface *ifp)
eebe9a18 437{
ca15a0aa 438 struct rs_state *state;
eebe9a18 439 struct ra *rap, *ran;
4eb7b489 440 struct dhcpcd_ctx *ctx;
eebe9a18
RM
441 ssize_t n;
442
ca15a0aa 443 state = RS_STATE(ifp);
a9d78def
RM
444 if (state == NULL)
445 return 0;
446
447 free(state->rs);
448 free(state);
449 ifp->if_data[IF_DATA_IPV6ND] = NULL;
eebe9a18 450 n = 0;
4eb7b489 451 TAILQ_FOREACH_SAFE(rap, ifp->ctx->ipv6->ra_routers, next, ran) {
eebe9a18 452 if (rap->iface == ifp) {
e82129a4 453 ipv6nd_free_ra(rap);
eebe9a18 454 n++;
91cd7324 455 }
eebe9a18 456 }
a9d78def
RM
457
458 /* If we don't have any more IPv6 enabled interfaces,
459 * close the global socket and release resources */
4eb7b489
RM
460 ctx = ifp->ctx;
461 TAILQ_FOREACH(ifp, ctx->ifaces, next) {
a9d78def
RM
462 if (RS_STATE(ifp))
463 break;
464 }
465 if (ifp == NULL) {
4eb7b489 466 if (ctx->ipv6->nd_fd != -1) {
4eb7b489 467 eloop_event_delete(ctx->eloop, ctx->ipv6->nd_fd);
e9882fb0 468 close(ctx->ipv6->nd_fd);
4eb7b489 469 ctx->ipv6->nd_fd = -1;
a9d78def 470 }
a9d78def
RM
471 }
472
eebe9a18
RM
473 return n;
474}
475
476static int
477rtpref(struct ra *rap)
478{
ca15a0aa 479
eebe9a18
RM
480 switch (rap->flags & ND_RA_FLAG_RTPREF_MASK) {
481 case ND_RA_FLAG_RTPREF_HIGH:
482 return (RTPREF_HIGH);
483 case ND_RA_FLAG_RTPREF_MEDIUM:
484 case ND_RA_FLAG_RTPREF_RSV:
485 return (RTPREF_MEDIUM);
486 case ND_RA_FLAG_RTPREF_LOW:
487 return (RTPREF_LOW);
488 default:
489 syslog(LOG_ERR, "rtpref: impossible RA flag %x", rap->flags);
490 return (RTPREF_INVALID);
491 }
492 /* NOTREACHED */
493}
494
495static void
4eb7b489 496add_router(struct ipv6_ctx *ctx, struct ra *router)
eebe9a18
RM
497{
498 struct ra *rap;
499
4eb7b489 500 TAILQ_FOREACH(rap, ctx->ra_routers, next) {
eebe9a18
RM
501 if (router->iface->metric < rap->iface->metric ||
502 (router->iface->metric == rap->iface->metric &&
503 rtpref(router) > rtpref(rap)))
504 {
505 TAILQ_INSERT_BEFORE(rap, router, next);
506 return;
91cd7324
RM
507 }
508 }
4eb7b489 509 TAILQ_INSERT_TAIL(ctx->ra_routers, router, next);
91cd7324
RM
510}
511
b5b066a5 512static int
e82129a4 513ipv6nd_scriptrun(struct ra *rap)
a8df1b28 514{
e3e77f72 515 int hasdns;
d5690e93 516 struct ipv6_addr *ap;
a8df1b28
RM
517 const struct ra_opt *rao;
518
519 /* If all addresses have completed DAD run the script */
a8df1b28 520 TAILQ_FOREACH(ap, &rap->addrs, next) {
a824f281
RM
521 if ((ap->flags & (IPV6_AF_ONLINK | IPV6_AF_AUTOCONF)) ==
522 (IPV6_AF_ONLINK | IPV6_AF_AUTOCONF))
523 {
d5690e93
RM
524 if (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
525 ipv6_findaddr(ap->iface, &ap->addr))
526 ap->flags |= IPV6_AF_DADCOMPLETED;
527 if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0) {
528 syslog(LOG_DEBUG,
529 "%s: waiting for Router Advertisement"
530 " DAD to complete",
531 rap->iface->name);
b5b066a5 532 return 0;
d5690e93 533 }
d8194bcd 534 }
a8df1b28
RM
535 }
536
537 /* If we don't require RDNSS then set hasdns = 1 so we fork */
538 if (!(rap->iface->options->options & DHCPCD_IPV6RA_REQRDNSS))
539 hasdns = 1;
540 else {
541 hasdns = 0;
542 TAILQ_FOREACH(rao, &rap->options, next) {
543 if (rao->type == ND_OPT_RDNSS &&
544 rao->option &&
545 timerisset(&rao->expire))
546 {
547 hasdns = 1;
548 break;
549 }
550 }
551 }
552
553 script_runreason(rap->iface, "ROUTERADVERT");
554 if (hasdns)
4eb7b489 555 hasdns = daemonise(rap->iface->ctx);
a8df1b28
RM
556#if 0
557 else if (options & DHCPCD_DAEMONISE &&
558 !(options & DHCPCD_DAEMONISED) && new_data)
559 syslog(LOG_WARNING,
560 "%s: did not fork due to an absent"
561 " RDNSS option in the RA",
562 ifp->name);
563}
564#endif
b5b066a5 565 return hasdns;
a8df1b28
RM
566}
567
d8194bcd 568static void
e82129a4 569ipv6nd_dadcallback(void *arg)
d8194bcd
RM
570{
571 struct ipv6_addr *ap = arg, *rapap;
572 struct interface *ifp;
573 struct ra *rap;
574 int wascompleted, found;
575
46b8a6b7 576 wascompleted = (ap->flags & IPV6_AF_DADCOMPLETED);
e82129a4 577 ipv6nd_cancelprobeaddr(ap);
46b8a6b7
RM
578 ap->flags |= IPV6_AF_DADCOMPLETED;
579 if (ap->flags & IPV6_AF_DUPLICATED)
d8194bcd
RM
580 /* No idea what how to try and make another address :( */
581 syslog(LOG_WARNING, "%s: DAD detected %s",
582 ap->iface->name, ap->saddr);
583#ifdef IPV6_SEND_DAD
584 else
585 ipv6_addaddr(ap);
586#endif
587
588 if (!wascompleted) {
589 ifp = ap->iface;
590
4eb7b489 591 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
d8194bcd
RM
592 if (rap->iface != ifp)
593 continue;
594 wascompleted = 1;
e92ca600 595 found = 0;
d8194bcd 596 TAILQ_FOREACH(rapap, &rap->addrs, next) {
a824f281
RM
597 if (rapap->flags & IPV6_AF_AUTOCONF &&
598 (rapap->flags & IPV6_AF_DADCOMPLETED) == 0)
599 {
d8194bcd
RM
600 wascompleted = 0;
601 break;
602 }
603 if (rapap == ap)
604 found = 1;
605 }
606
607 if (wascompleted && found && rap->lifetime) {
ad574a91 608 syslog(LOG_DEBUG,
d8194bcd
RM
609 "%s: Router Advertisement DAD completed",
610 rap->iface->name);
b5b066a5
RM
611 if (ipv6nd_scriptrun(rap))
612 return;
d8194bcd
RM
613 }
614 }
615 }
616}
617
aae24feb 618static void
4eb7b489
RM
619ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
620 struct icmp6_hdr *icp, ssize_t len)
91cd7324 621{
e82129a4 622 ssize_t l, m, n, olen;
7be4b9b3 623 struct nd_router_advert *nd_ra;
91cd7324
RM
624 struct nd_opt_prefix_info *pi;
625 struct nd_opt_mtu *mtu;
626 struct nd_opt_rdnss *rdnss;
627 struct nd_opt_dnssl *dnssl;
eebe9a18 628 uint32_t lifetime, mtuv;
91cd7324
RM
629 uint8_t *p, *op;
630 struct in6_addr addr;
631 char buf[INET6_ADDRSTRLEN];
632 const char *cbp;
633 struct ra *rap;
634 struct nd_opt_hdr *ndo;
eebe9a18
RM
635 struct ra_opt *rao;
636 struct ipv6_addr *ap;
d7555c12 637 char *opt, *tmp;
91cd7324 638 struct timeval expire;
a8df1b28 639 uint8_t new_rap, new_data;
91cd7324 640
91cd7324 641 if ((size_t)len < sizeof(struct nd_router_advert)) {
4eb7b489 642 syslog(LOG_ERR, "IPv6 RA packet too short from %s", ctx->sfrom);
91cd7324
RM
643 return;
644 }
645
4eb7b489
RM
646 if (!IN6_IS_ADDR_LINKLOCAL(&ctx->from.sin6_addr)) {
647 syslog(LOG_ERR, "RA from non local address %s", ctx->sfrom);
91cd7324
RM
648 return;
649 }
650
91cd7324 651 if (ifp == NULL) {
d7555c12 652#ifdef DEBUG_RS
4eb7b489
RM
653 syslog(LOG_DEBUG, "RA for unexpected interface from %s",
654 ctx->sfrom);
4c6a8bec
RM
655#endif
656 return;
657 }
658 if (!(ifp->options->options & DHCPCD_IPV6RS)) {
659#ifdef DEBUG_RS
660 syslog(LOG_DEBUG, "%s: unexpected RA from %s",
4eb7b489 661 ifp->name, ctx->sfrom);
d7555c12 662#endif
91cd7324
RM
663 return;
664 }
0e906716 665
e7a30a46 666 /* We could receive a RA before we sent a RS*/
0e906716
RM
667 if (ipv6_linklocal(ifp) == NULL) {
668#ifdef DEBUG_RS
669 syslog(LOG_DEBUG, "%s: received RA from %s (no link-local)",
4eb7b489 670 ifp->name, ctx->sfrom);
0e906716
RM
671#endif
672 return;
673 }
674
4eb7b489 675 TAILQ_FOREACH(rap, ctx->ra_routers, next) {
fe292175 676 if (ifp == rap->iface &&
4eb7b489 677 memcmp(rap->from.s6_addr, ctx->from.sin6_addr.s6_addr,
91cd7324
RM
678 sizeof(rap->from.s6_addr)) == 0)
679 break;
680 }
46caaa5e 681
e42bbc9b
RM
682 nd_ra = (struct nd_router_advert *)icp;
683 /* Don't bother doing anything if we don't know about a router
684 * expiring */
685 if ((rap == NULL || rap->lifetime == 0)
686 && nd_ra->nd_ra_router_lifetime == 0)
687 return;
688
46caaa5e
RM
689 /* We don't want to spam the log with the fact we got an RA every
690 * 30 seconds or so, so only spam the log if it's different. */
ee70f4ab 691 if (rap == NULL || (rap->data_len != len ||
46caaa5e
RM
692 memcmp(rap->data, (unsigned char *)icp, rap->data_len) != 0))
693 {
694 if (rap) {
695 free(rap->data);
696 rap->data_len = 0;
ea112ab2
RM
697 free(rap->ns);
698 rap->ns = NULL;
699 rap->nslen = 0;
46caaa5e 700 }
d7555c12 701 new_data = 1;
d7555c12
RM
702 } else
703 new_data = 0;
ee70f4ab
RM
704 if (new_data || ifp->options->options & DHCPCD_DEBUG)
705 syslog(LOG_INFO, "%s: Router Advertisement from %s",
4eb7b489 706 ifp->name, ctx->sfrom);
46caaa5e 707
91cd7324 708 if (rap == NULL) {
10e17e3f
RM
709 rap = calloc(1, sizeof(*rap));
710 if (rap == NULL) {
711 syslog(LOG_ERR, "%s: %m", __func__);
712 return;
713 }
eebe9a18 714 rap->iface = ifp;
4eb7b489 715 memcpy(rap->from.s6_addr, ctx->from.sin6_addr.s6_addr,
91cd7324 716 sizeof(rap->from.s6_addr));
4eb7b489 717 strlcpy(rap->sfrom, ctx->sfrom, sizeof(rap->sfrom));
eebe9a18
RM
718 TAILQ_INIT(&rap->addrs);
719 TAILQ_INIT(&rap->options);
720 new_rap = 1;
721 } else
722 new_rap = 0;
46caaa5e 723 if (rap->data_len == 0) {
28382337
RM
724 rap->data = malloc(len);
725 if (rap->data == NULL) {
726 syslog(LOG_ERR, "%s: %m", __func__);
727 if (new_rap)
728 free(rap);
729 return;
730 }
46caaa5e
RM
731 memcpy(rap->data, icp, len);
732 rap->data_len = len;
91cd7324
RM
733 }
734
735 get_monotonic(&rap->received);
eebe9a18 736 rap->flags = nd_ra->nd_ra_flags_reserved;
e42bbc9b
RM
737 if (new_rap == 0 && rap->lifetime == 0)
738 syslog(LOG_WARNING, "%s: %s router available",
739 ifp->name, rap->sfrom);
7be4b9b3 740 rap->lifetime = ntohs(nd_ra->nd_ra_router_lifetime);
ea112ab2
RM
741 if (nd_ra->nd_ra_reachable) {
742 rap->reachable = ntohl(nd_ra->nd_ra_reachable);
743 if (rap->reachable > MAX_REACHABLE_TIME)
744 rap->reachable = 0;
745 }
746 if (nd_ra->nd_ra_retransmit)
747 rap->retrans = ntohl(nd_ra->nd_ra_retransmit);
b88df421
RM
748 if (rap->lifetime)
749 rap->expired = 0;
91cd7324
RM
750
751 len -= sizeof(struct nd_router_advert);
752 p = ((uint8_t *)icp) + sizeof(struct nd_router_advert);
753 olen = 0;
754 lifetime = ~0U;
755 for (olen = 0; len > 0; p += olen, len -= olen) {
756 if ((size_t)len < sizeof(struct nd_opt_hdr)) {
4eb7b489 757 syslog(LOG_ERR, "%s: short option", ifp->name);
91cd7324
RM
758 break;
759 }
760 ndo = (struct nd_opt_hdr *)p;
761 olen = ndo->nd_opt_len * 8 ;
762 if (olen == 0) {
763 syslog(LOG_ERR, "%s: zero length option", ifp->name);
764 break;
765 }
766 if (olen > len) {
767 syslog(LOG_ERR,
768 "%s: Option length exceeds message", ifp->name);
769 break;
770 }
771
772 opt = NULL;
773 switch (ndo->nd_opt_type) {
774 case ND_OPT_PREFIX_INFORMATION:
eebe9a18 775 pi = (struct nd_opt_prefix_info *)(void *)ndo;
91cd7324
RM
776 if (pi->nd_opt_pi_len != 4) {
777 syslog(LOG_ERR,
778 "%s: invalid option len for prefix",
779 ifp->name);
780 break;
781 }
782 if (pi->nd_opt_pi_prefix_len > 128) {
783 syslog(LOG_ERR, "%s: invalid prefix len",
784 ifp->name);
785 break;
786 }
787 if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) ||
788 IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix))
789 {
790 syslog(LOG_ERR,
791 "%s: invalid prefix in RA", ifp->name);
792 break;
793 }
e54dee19
RM
794 if (ntohl(pi->nd_opt_pi_preferred_time) >
795 ntohl(pi->nd_opt_pi_valid_time))
796 {
797 syslog(LOG_ERR,
798 "%s: pltime > vltime", ifp->name);
799 break;
800 }
eebe9a18
RM
801 TAILQ_FOREACH(ap, &rap->addrs, next)
802 if (ap->prefix_len ==pi->nd_opt_pi_prefix_len &&
803 memcmp(ap->prefix.s6_addr,
804 pi->nd_opt_pi_prefix.s6_addr,
805 sizeof(ap->prefix.s6_addr)) == 0)
806 break;
807 if (ap == NULL) {
cd3612e5
RM
808 if (!(pi->nd_opt_pi_flags_reserved &
809 ND_OPT_PI_FLAG_AUTO) &&
810 !(pi->nd_opt_pi_flags_reserved &
811 ND_OPT_PI_FLAG_ONLINK))
4242c5f2 812 continue;
66fd5d67 813 ap = calloc(1, sizeof(*ap));
28382337
RM
814 if (ap == NULL) {
815 syslog(LOG_ERR, "%s: %m", __func__);
816 break;
817 }
66fd5d67 818 ap->iface = rap->iface;
a824f281 819 ap->flags = IPV6_AF_NEW;
eebe9a18
RM
820 ap->prefix_len = pi->nd_opt_pi_prefix_len;
821 memcpy(ap->prefix.s6_addr,
822 pi->nd_opt_pi_prefix.s6_addr,
823 sizeof(ap->prefix.s6_addr));
e54dee19
RM
824 if (pi->nd_opt_pi_flags_reserved &
825 ND_OPT_PI_FLAG_AUTO)
826 {
a824f281 827 ap->flags |= IPV6_AF_AUTOCONF;
5331b839 828 ipv6_makeaddr(&ap->addr, ifp,
e54dee19
RM
829 &ap->prefix,
830 pi->nd_opt_pi_prefix_len);
831 cbp = inet_ntop(AF_INET6,
832 ap->addr.s6_addr,
4eb7b489 833 buf, sizeof(buf));
e54dee19
RM
834 if (cbp)
835 snprintf(ap->saddr,
836 sizeof(ap->saddr),
837 "%s/%d",
838 cbp, ap->prefix_len);
839 else
840 ap->saddr[0] = '\0';
841 } else {
842 memset(&ap->addr, 0, sizeof(ap->addr));
eebe9a18 843 ap->saddr[0] = '\0';
e54dee19 844 }
e82129a4 845 ap->dadcallback = ipv6nd_dadcallback;
eebe9a18 846 TAILQ_INSERT_TAIL(&rap->addrs, ap, next);
66fd5d67 847 }
cd3612e5
RM
848 if (pi->nd_opt_pi_flags_reserved &
849 ND_OPT_PI_FLAG_ONLINK)
46b8a6b7 850 ap->flags |= IPV6_AF_ONLINK;
eebe9a18
RM
851 ap->prefix_vltime =
852 ntohl(pi->nd_opt_pi_valid_time);
853 ap->prefix_pltime =
854 ntohl(pi->nd_opt_pi_preferred_time);
66fd5d67 855 ap->nsprobes = 0;
50083515
RM
856 if (opt) {
857 l = strlen(opt);
fa245a4d 858 tmp = realloc(opt,
50083515 859 l + strlen(ap->saddr) + 2);
fa245a4d
RM
860 if (tmp) {
861 opt = tmp;
862 opt[l] = ' ';
863 strcpy(opt + l + 1, ap->saddr);
864 }
50083515 865 } else
78369646 866 opt = strdup(ap->saddr);
50083515 867 lifetime = ap->prefix_vltime;
91cd7324
RM
868 break;
869
870 case ND_OPT_MTU:
eebe9a18
RM
871 mtu = (struct nd_opt_mtu *)(void *)p;
872 mtuv = ntohl(mtu->nd_opt_mtu_mtu);
873 if (mtuv < IPV6_MMTU) {
874 syslog(LOG_ERR, "%s: invalid MTU %d",
875 ifp->name, mtuv);
876 break;
877 }
f98846d4 878 rap->mtu = mtuv;
eebe9a18 879 snprintf(buf, sizeof(buf), "%d", mtuv);
78369646 880 opt = strdup(buf);
91cd7324
RM
881 break;
882
883 case ND_OPT_RDNSS:
884 rdnss = (struct nd_opt_rdnss *)p;
885 lifetime = ntohl(rdnss->nd_opt_rdnss_lifetime);
886 op = (uint8_t *)ndo;
887 op += offsetof(struct nd_opt_rdnss,
888 nd_opt_rdnss_lifetime);
889 op += sizeof(rdnss->nd_opt_rdnss_lifetime);
890 l = 0;
c2e168a8
RM
891 for (n = ndo->nd_opt_len - 1; n > 1; n -= 2,
892 op += sizeof(addr.s6_addr))
893 {
b2e8d8da
RM
894 m = ipv6_printaddr(NULL, 0, op, ifp->name);
895 if (m != -1)
896 l += m + 1;
c2e168a8
RM
897 }
898 op = (uint8_t *)ndo;
899 op += offsetof(struct nd_opt_rdnss,
900 nd_opt_rdnss_lifetime);
901 op += sizeof(rdnss->nd_opt_rdnss_lifetime);
902 tmp = opt = malloc(l);
b2e8d8da
RM
903 if (opt) {
904 for (n = ndo->nd_opt_len - 1; n > 1; n -= 2,
905 op += sizeof(addr.s6_addr))
906 {
907 m = ipv6_printaddr(tmp, l, op,
908 ifp->name);
909 if (m != -1) {
910 l -= (m + 1);
911 tmp += m;
912 *tmp++ = ' ';
b2e8d8da
RM
913 }
914 }
915 if (tmp != opt)
916 (*--tmp) = '\0';
917 else
918 *opt = '\0';
91cd7324
RM
919 }
920 break;
673e81e5 921
91cd7324
RM
922 case ND_OPT_DNSSL:
923 dnssl = (struct nd_opt_dnssl *)p;
924 lifetime = ntohl(dnssl->nd_opt_dnssl_lifetime);
925 op = p + offsetof(struct nd_opt_dnssl,
926 nd_opt_dnssl_lifetime);
927 op += sizeof(dnssl->nd_opt_dnssl_lifetime);
928 n = (dnssl->nd_opt_dnssl_len - 1) * 8;
929 l = decode_rfc3397(NULL, 0, n, op);
930 if (l < 1) {
931 syslog(LOG_ERR, "%s: invalid DNSSL option",
932 ifp->name);
933 } else {
78369646
RM
934 tmp = malloc(l);
935 if (tmp) {
936 decode_rfc3397(tmp, l, n, op);
937 n = print_string(NULL, 0,
938 l - 1, (const uint8_t *)tmp);
939 opt = malloc(n);
940 if (opt)
941 print_string(opt, n,
942 l - 1,
943 (const uint8_t *)tmp);
944 free(tmp);
945 }
91cd7324
RM
946 }
947 break;
17b0dbad
RM
948
949 default:
950 continue;
91cd7324
RM
951 }
952
78369646
RM
953 if (opt == NULL) {
954 syslog(LOG_ERR, "%s: %m", __func__);
91cd7324 955 continue;
78369646 956 }
eebe9a18 957 TAILQ_FOREACH(rao, &rap->options, next) {
91cd7324
RM
958 if (rao->type == ndo->nd_opt_type &&
959 strcmp(rao->option, opt) == 0)
960 break;
961 }
962 if (lifetime == 0) {
963 if (rao) {
eebe9a18 964 TAILQ_REMOVE(&rap->options, rao, next);
91cd7324
RM
965 free(rao->option);
966 free(rao);
967 }
f08afbd8 968 free(opt);
91cd7324
RM
969 continue;
970 }
971
972 if (rao == NULL) {
28382337
RM
973 rao = malloc(sizeof(*rao));
974 if (rao == NULL) {
975 syslog(LOG_ERR, "%s: %m", __func__);
976 continue;
977 }
91cd7324
RM
978 rao->type = ndo->nd_opt_type;
979 rao->option = opt;
eebe9a18 980 TAILQ_INSERT_TAIL(&rap->options, rao, next);
bb02dff1
RM
981 } else
982 free(opt);
449df9c8
RM
983 if (lifetime == ~0U)
984 timerclear(&rao->expire);
985 else {
91cd7324
RM
986 expire.tv_sec = lifetime;
987 expire.tv_usec = 0;
988 timeradd(&rap->received, &expire, &rao->expire);
989 }
990 }
991
eebe9a18 992 if (new_rap)
4eb7b489
RM
993 add_router(ifp->ctx->ipv6, rap);
994 if (ifp->ctx->options & DHCPCD_TEST) {
294eff4d 995 script_runreason(ifp, "TEST");
d7555c12 996 goto handle_flag;
b88df421 997 }
ef0f1a1c 998 ipv6nd_probeaddrs(&rap->addrs);
4eb7b489 999 ipv6_buildroutes(ifp->ctx);
a8df1b28 1000
b88df421 1001 /* We will get run by the expire function */
b5b066a5
RM
1002 if (rap->lifetime) {
1003 if (ipv6nd_scriptrun(rap))
1004 return;
1005 }
61dd6cf9 1006
4eb7b489
RM
1007 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
1008 eloop_timeout_delete(ifp->ctx->eloop, NULL, rap); /* reachable timer */
eebe9a18
RM
1009
1010 /* If we're owning the RA then we need to try and ensure the
1011 * router is actually reachable */
fbbb0875
RM
1012 if (ifp->options->options & DHCPCD_IPV6RA_OWN ||
1013 ifp->options->options & DHCPCD_IPV6RA_OWN_DEFAULT)
eebe9a18
RM
1014 {
1015 rap->nsprobes = 0;
e42bbc9b 1016 if (rap->lifetime)
e82129a4 1017 ipv6nd_proberouter(rap);
eebe9a18 1018 }
d7555c12
RM
1019
1020handle_flag:
1021 if (rap->flags & ND_RA_FLAG_MANAGED) {
ee70f4ab
RM
1022 if (rap->lifetime && new_data &&
1023 dhcp6_start(ifp, DH6S_INIT) == -1)
e54dee19 1024 syslog(LOG_ERR, "dhcp6_start: %s: %m", ifp->name);
d7555c12 1025 } else if (rap->flags & ND_RA_FLAG_OTHER) {
ee70f4ab
RM
1026 if (rap->lifetime && new_data &&
1027 dhcp6_start(ifp, DH6S_INFORM) == -1)
d7555c12
RM
1028 syslog(LOG_ERR, "dhcp6_start: %s: %m", ifp->name);
1029 } else {
8fdedf59 1030 if (rap->lifetime && new_data)
d7555c12
RM
1031 syslog(LOG_DEBUG, "%s: No DHCPv6 instruction in RA",
1032 ifp->name);
4eb7b489
RM
1033 if (ifp->ctx->options & DHCPCD_TEST) {
1034 eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
a9d78def
RM
1035 return;
1036 }
d7555c12 1037 }
35308011
RM
1038
1039 /* Expire should be called last as the rap object could be destroyed */
e82129a4 1040 ipv6nd_expirera(ifp);
eebe9a18
RM
1041}
1042
1043int
e82129a4 1044ipv6nd_has_ra(const struct interface *ifp)
eebe9a18
RM
1045{
1046 const struct ra *rap;
1047
2433e54d
RM
1048 if (ifp->ctx->ipv6) {
1049 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next)
1050 if (rap->iface == ifp)
1051 return 1;
1052 }
eebe9a18 1053 return 0;
91cd7324
RM
1054}
1055
1056ssize_t
e82129a4 1057ipv6nd_env(char **env, const char *prefix, const struct interface *ifp)
91cd7324
RM
1058{
1059 ssize_t l;
f98846d4 1060 size_t len;
91cd7324
RM
1061 const struct ra *rap;
1062 const struct ra_opt *rao;
1063 int i;
eebe9a18 1064 char buffer[32];
91cd7324 1065 const char *optn;
d4e41f4b 1066 char **pref, **mtu, **rdnss, **dnssl, ***var, *new;
eebe9a18 1067
50083515 1068 i = 0;
91cd7324 1069 l = 0;
4eb7b489 1070 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
eebe9a18
RM
1071 i++;
1072 if (rap->iface != ifp)
1073 continue;
91cd7324
RM
1074 if (env) {
1075 snprintf(buffer, sizeof(buffer),
1076 "ra%d_from", i);
28382337
RM
1077 if (setvar(&env, prefix, buffer, rap->sfrom) == -1)
1078 return -1;
91cd7324
RM
1079 }
1080 l++;
449df9c8 1081
f98846d4 1082 pref = mtu = rdnss = dnssl = NULL;
eebe9a18 1083 TAILQ_FOREACH(rao, &rap->options, next) {
91cd7324
RM
1084 if (rao->option == NULL)
1085 continue;
f98846d4
RM
1086 var = NULL;
1087 switch(rao->type) {
91cd7324
RM
1088 case ND_OPT_PREFIX_INFORMATION:
1089 optn = "prefix";
d4e41f4b 1090 var = &pref;
91cd7324
RM
1091 break;
1092 case ND_OPT_MTU:
1093 optn = "mtu";
d4e41f4b 1094 var = &mtu;
91cd7324
RM
1095 break;
1096 case ND_OPT_RDNSS:
1097 optn = "rdnss";
673e81e5 1098 var = &rdnss;
91cd7324
RM
1099 break;
1100 case ND_OPT_DNSSL:
1101 optn = "dnssl";
d4e41f4b 1102 var = &dnssl;
91cd7324
RM
1103 break;
1104 default:
1105 continue;
1106 }
d4e41f4b
RM
1107 if (*var == NULL) {
1108 *var = env ? env : &new;
1109 l++;
1110 } else if (env) {
f98846d4
RM
1111 /* With single only options, last one takes
1112 * precedence */
1113 if (rao->type == ND_OPT_MTU) {
1114 new = strchr(**var, '=');
1115 if (new == NULL) {
1116 syslog(LOG_ERR, "new is null");
1117 continue;
1118 } else
1119 new++;
e54dee19
RM
1120 len = (new - **var) +
1121 strlen(rao->option) + 1;
f98846d4
RM
1122 if (len > strlen(**var))
1123 new = realloc(**var, len);
1124 else
1125 new = **var;
1126 if (new) {
1127 **var = new;
1128 new = strchr(**var, '=');
1129 if (new)
e54dee19
RM
1130 strcpy(new + 1,
1131 rao->option);
f98846d4 1132 else
e54dee19
RM
1133 syslog(LOG_ERR,
1134 "new is null");
f98846d4
RM
1135 }
1136 continue;
1137 }
d4e41f4b
RM
1138 new = realloc(**var,
1139 strlen(**var) + 1 +
1140 strlen(rao->option) + 1);
28382337
RM
1141 if (new == NULL)
1142 return -1;
1143 **var = new;
1144 new += strlen(new);
1145 *new++ = ' ';
1146 strcpy(new, rao->option);
1147 continue;
d4e41f4b
RM
1148 }
1149 if (env) {
1150 snprintf(buffer, sizeof(buffer),
1151 "ra%d_%s", i, optn);
28382337
RM
1152 if (setvar(&env, prefix, buffer, rao->option)
1153 == -1)
1154 return -1;
d4e41f4b 1155 }
91cd7324
RM
1156 }
1157 }
1158
28382337
RM
1159 if (env) {
1160 if (setvard(&env, prefix, "ra_count", i) == -1)
1161 return -1;
1162 }
91cd7324
RM
1163 l++;
1164 return l;
1165}
1166
a8df1b28 1167void
4eb7b489 1168ipv6nd_handleifa(struct dhcpcd_ctx *ctx, int cmd, const char *ifname,
d8194bcd 1169 const struct in6_addr *addr, int flags)
a8df1b28
RM
1170{
1171 struct ra *rap;
a8df1b28 1172
4eb7b489
RM
1173 if (ctx->ipv6 == NULL)
1174 return;
1175 TAILQ_FOREACH(rap, ctx->ipv6->ra_routers, next) {
a8df1b28
RM
1176 if (strcmp(rap->iface->name, ifname))
1177 continue;
d8194bcd 1178 ipv6_handleifa_addrs(cmd, &rap->addrs, addr, flags);
a8df1b28
RM
1179 }
1180}
1181
91cd7324 1182void
e82129a4 1183ipv6nd_expirera(void *arg)
91cd7324
RM
1184{
1185 struct interface *ifp;
eebe9a18
RM
1186 struct ra *rap, *ran;
1187 struct ra_opt *rao, *raon;
91cd7324 1188 struct timeval now, lt, expire, next;
d4e41f4b 1189 int expired, valid;
91cd7324
RM
1190
1191 ifp = arg;
1192 get_monotonic(&now);
1193 expired = 0;
91cd7324
RM
1194 timerclear(&next);
1195
4eb7b489 1196 TAILQ_FOREACH_SAFE(rap, ifp->ctx->ipv6->ra_routers, next, ran) {
eebe9a18
RM
1197 if (rap->iface != ifp)
1198 continue;
91cd7324
RM
1199 lt.tv_sec = rap->lifetime;
1200 lt.tv_usec = 0;
1201 timeradd(&rap->received, &lt, &expire);
e42bbc9b 1202 if (rap->lifetime == 0 || timercmp(&now, &expire, >)) {
d4e41f4b 1203 valid = 0;
35308011 1204 if (!rap->expired) {
ad574a91 1205 syslog(LOG_WARNING,
e42bbc9b 1206 "%s: %s: router expired",
35308011
RM
1207 ifp->name, rap->sfrom);
1208 rap->expired = expired = 1;
e82129a4 1209 ipv6nd_cancelproberouter(rap);
35308011
RM
1210 }
1211 } else {
d4e41f4b 1212 valid = 1;
35308011
RM
1213 timersub(&expire, &now, &lt);
1214 if (!timerisset(&next) || timercmp(&next, &lt, >))
1215 next = lt;
1216 }
1217
78ae7296
RM
1218 /* Addresses are expired in ipv6ns_probeaddrs
1219 * so that DHCPv6 addresses can be removed also. */
eebe9a18 1220 TAILQ_FOREACH_SAFE(rao, &rap->options, next, raon) {
47102c83
RM
1221 if (rap->expired) {
1222 switch(rao->type) {
1223 case ND_OPT_RDNSS: /* FALLTHROUGH */
1224 case ND_OPT_DNSSL:
1225 /* RFC6018 end of section 5.2 states
1226 * that if tha RA has a lifetime of 0
1227 * then we should expire these
1228 * options */
1229 TAILQ_REMOVE(&rap->options, rao, next);
1230 expired = 1;
1231 free(rao->option);
1232 free(rao);
1233 continue;
1234 }
1235 }
449df9c8
RM
1236 if (!timerisset(&rao->expire))
1237 continue;
1238 if (timercmp(&now, &rao->expire, >)) {
35308011
RM
1239 /* Expired prefixes are logged above */
1240 if (rao->type != ND_OPT_PREFIX_INFORMATION)
ad574a91 1241 syslog(LOG_WARNING,
35308011
RM
1242 "%s: %s: expired option %d",
1243 ifp->name, rap->sfrom, rao->type);
eebe9a18
RM
1244 TAILQ_REMOVE(&rap->options, rao, next);
1245 expired = 1;
1246 free(rao->option);
1247 free(rao);
449df9c8
RM
1248 continue;
1249 }
d4e41f4b 1250 valid = 1;
449df9c8 1251 timersub(&rao->expire, &now, &lt);
91cd7324
RM
1252 if (!timerisset(&next) || timercmp(&next, &lt, >))
1253 next = lt;
1254 }
d4e41f4b
RM
1255
1256 /* No valid lifetimes are left on the RA, so we might
1257 * as well punt it. */
e42bbc9b 1258 if (!valid && TAILQ_FIRST(&rap->addrs) == NULL)
e82129a4 1259 ipv6nd_free_ra(rap);
91cd7324
RM
1260 }
1261
1262 if (timerisset(&next))
4eb7b489
RM
1263 eloop_timeout_add_tv(ifp->ctx->eloop,
1264 &next, ipv6nd_expirera, ifp);
e82129a4 1265 if (expired) {
4eb7b489 1266 ipv6_buildroutes(ifp->ctx);
e82129a4
RM
1267 script_runreason(ifp, "ROUTERADVERT");
1268 }
1269}
1270
1271void
1272ipv6nd_drop(struct interface *ifp)
1273{
1274 struct ra *rap;
1275 int expired = 0;
1276 TAILQ_HEAD(rahead, ra) rtrs;
1277
2433e54d
RM
1278 if (ifp->ctx->ipv6 == NULL)
1279 return;
1280
4eb7b489 1281 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
e82129a4 1282 TAILQ_INIT(&rtrs);
4eb7b489 1283 TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) {
e82129a4
RM
1284 if (rap->iface == ifp) {
1285 rap->expired = expired = 1;
4eb7b489 1286 TAILQ_REMOVE(ifp->ctx->ipv6->ra_routers, rap, next);
e82129a4
RM
1287 TAILQ_INSERT_TAIL(&rtrs, rap, next);
1288 }
1289 }
eebe9a18 1290 if (expired) {
e82129a4
RM
1291 while ((rap = TAILQ_FIRST(&rtrs))) {
1292 TAILQ_REMOVE(&rtrs, rap, next);
1293 ipv6nd_drop_ra(rap);
1294 }
4eb7b489 1295 ipv6_buildroutes(ifp->ctx);
15fc1181
RM
1296 if ((ifp->options->options &
1297 (DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
1298 (DHCPCD_EXITING | DHCPCD_PERSISTENT))
1299 script_runreason(ifp, "ROUTERADVERT");
e82129a4
RM
1300 }
1301}
a9d78def 1302
e82129a4
RM
1303static void
1304ipv6nd_unreachable(void *arg)
1305{
1306 struct ra *rap = arg;
1307 struct timeval tv;
1308
1309 /* We could add an unreachable flag and persist the information,
1310 * but that is more effort than it's probably worth. */
1311 syslog(LOG_WARNING, "%s: %s is unreachable, expiring it",
1312 rap->iface->name, rap->sfrom);
1313 rap->expired = 1;
4eb7b489 1314 ipv6_buildroutes(rap->iface->ctx);
e82129a4
RM
1315 script_runreason(rap->iface, "ROUTERADVERT"); /* XXX not RA */
1316
1317 /* We should still test if it's reachable or not so
1318 * incase it comes back to life and it's preferable. */
1319 if (rap->reachable) {
1320 ms_to_tv(&tv, rap->reachable);
1321 } else {
1322 tv.tv_sec = REACHABLE_TIME;
1323 tv.tv_usec = 0;
1324 }
4eb7b489
RM
1325 eloop_timeout_add_tv(rap->iface->ctx->eloop,
1326 &tv, ipv6nd_proberouter, rap);
e82129a4
RM
1327}
1328
1329#ifdef LISTEN_DAD
1330void
1331ipv6nd_cancelprobeaddr(struct ipv6_addr *ap)
1332{
1333
4eb7b489 1334 eloop_timeout_delete(ap->iface->ctx->eloop, ipv6nd_probeaddr, ap);
e82129a4 1335 if (ap->dadcallback)
4eb7b489 1336 eloop_timeout_delete(ap->iface->ctx->eloop, ap->dadcallback,ap);
e82129a4
RM
1337}
1338#endif
1339
1340void
1341ipv6nd_probeaddr(void *arg)
1342{
1343 struct ipv6_addr *ap = arg;
1344#ifdef IPV6_SEND_DAD
1345 struct nd_neighbor_solicit *ns;
1346 struct nd_opt_hdr *nd;
1347 struct sockaddr_in6 dst;
1348 struct cmsghdr *cm;
1349 struct in6_pktinfo pi;
1350 int hoplimit = HOPLIMIT;
1351#else
1352#ifdef LISTEN_DAD
1353 struct timeval tv, rtv;
1354 struct timeval mtv;
1355 int i;
1356#endif
1357#endif
1358
1359 if (ap->dadcallback &&
1360 ((ap->flags & IPV6_AF_NEW) == 0 ||
1361 ap->nsprobes >= ap->iface->options->dadtransmits))
1362 {
1363#ifdef IPV6_SEND_DAD
1364 ap->dadcallback(ap);
1365#else
ef0f1a1c
RM
1366 if (!(ap->flags & IPV6_AF_AUTOCONF) ||
1367 ap->iface->options->options & DHCPCD_IPV6RA_OWN)
1368 ipv6_addaddr(ap);
e82129a4
RM
1369#endif
1370 return;
1371 }
1372
4eb7b489
RM
1373 if (ipv6nd_open(ap->iface->ctx) == -1) {
1374 syslog(LOG_ERR, "%s: ipv6nd_open: %m", __func__);
e82129a4 1375 return;
4eb7b489 1376 }
e82129a4
RM
1377
1378 ap->flags &= ~IPV6_AF_DADCOMPLETED;
1379
1380#ifdef IPV6_SEND_DAD
1381 if (!ap->ns) {
1382 ap->nslen = sizeof(*ns) + ROUNDUP8(ap->iface->hwlen + 2);
1383 ap->ns = calloc(1, ap->nslen);
1384 if (ap->ns == NULL) {
1385 syslog(LOG_ERR, "%s: %m", __func__);
1386 return;
1387 }
1388 ns = (struct nd_neighbor_solicit *)(void *)ap->ns;
1389 ns->nd_ns_type = ND_NEIGHBOR_SOLICIT;
1390 //ns->nd_ns_cksum = 0;
1391 //ns->nd_ns_code = 0;
1392 //ns->nd_ns_reserved = 0;
1393 ns->nd_ns_target = ap->addr;
1394 nd = (struct nd_opt_hdr *)(ap->ns + sizeof(*ns));
1395 nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
1396 nd->nd_opt_len = (ROUNDUP8(ap->iface->hwlen + 2)) >> 3;
1397 memcpy(nd + 1, ap->iface->hwaddr, ap->iface->hwlen);
1398 }
1399
1400 memset(&dst, 0, sizeof(dst));
1401 dst.sin6_family = AF_INET6;
1402#ifdef SIN6_LEN
1403 dst.sin6_len = sizeof(dst);
1404#endif
1405 dst.sin6_addr.s6_addr16[0] = IPV6_ADDR_INT16_MLL;
1406 dst.sin6_addr.s6_addr16[1] = 0;
1407 dst.sin6_addr.s6_addr32[1] = 0;
1408 dst.sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_ONE;
1409 dst.sin6_addr.s6_addr32[3] = ap->addr.s6_addr32[3];
1410 dst.sin6_addr.s6_addr[12] = 0xff;
1411
1412 //memcpy(&dst.sin6_addr, &ap->addr, sizeof(dst.sin6_addr));
1413 dst.sin6_scope_id = ap->iface->index;
1414
1415 sndhdr.msg_name = (caddr_t)&dst;
1416 sndhdr.msg_iov[0].iov_base = ap->ns;
1417 sndhdr.msg_iov[0].iov_len = ap->nslen;
1418
1419 /* Set the outbound interface */
1420 cm = CMSG_FIRSTHDR(&sndhdr);
1421 cm->cmsg_level = IPPROTO_IPV6;
1422 cm->cmsg_type = IPV6_PKTINFO;
1423 cm->cmsg_len = CMSG_LEN(sizeof(pi));
1424 memset(&pi, 0, sizeof(pi));
1425 pi.ipi6_ifindex = ap->iface->index;
1426 memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
1427
1428 /* Hop limit */
1429 cm = CMSG_NXTHDR(&sndhdr, cm);
1430 cm->cmsg_level = IPPROTO_IPV6;
1431 cm->cmsg_type = IPV6_HOPLIMIT;
1432 cm->cmsg_len = CMSG_LEN(sizeof(hoplimit));
1433 memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit));
1434
1435#ifdef DEBUG_NS
1436 syslog(LOG_INFO, "%s: sending IPv6 NS for %s",
1437 ap->iface->name, ap->saddr);
1438 if (ap->dadcallback == NULL)
1439 syslog(LOG_WARNING, "%s: no callback!", ap->iface->name);
1440#endif
1441 if (sendmsg(unspec_sock, &sndhdr, 0) == -1) {
1442 syslog(LOG_ERR, "%s: %s: sendmsg: %m",
1443 ap->iface->name, __func__);
1444 return;
1445 }
1446
1447 if (ap->dadcallback) {
1448 ms_to_tv(&tv, RETRANS_TIMER);
1449 ms_to_tv(&rtv, MIN_RANDOM_FACTOR);
1450 timeradd(&tv, &rtv, &tv);
1451 rtv.tv_sec = 0;
1452 rtv.tv_usec = arc4random() %
1453 (MAX_RANDOM_FACTOR_U - MIN_RANDOM_FACTOR_U);
1454 timeradd(&tv, &rtv, &tv);
1455
4eb7b489 1456 eloop_timeout_add_tv(ap->iface->ctx->eloop, &tv,
e82129a4
RM
1457 ++(ap->nsprobes) < ap->iface->options->dadtransmits ?
1458 ipv6nd_probeaddr : ap->dadcallback,
1459 ap);
1460 }
1461#else /* IPV6_SEND_DAD */
ef0f1a1c
RM
1462
1463 if (!(ap->flags & IPV6_AF_AUTOCONF) ||
1464 ap->iface->options->options & DHCPCD_IPV6RA_OWN)
1465 ipv6_addaddr(ap);
1466
e82129a4
RM
1467#ifdef LISTEN_DAD
1468 /* Let the kernel handle DAD.
1469 * We don't know the timings, so just wait for the max */
1470 if (ap->dadcallback) {
1471 mtv.tv_sec = 0;
1472 mtv.tv_usec = 0;
1473 for (i = 0; i < ap->iface->options->dadtransmits; i++) {
1474 ms_to_tv(&tv, RETRANS_TIMER);
1475 ms_to_tv(&rtv, MAX_RANDOM_FACTOR);
1476 timeradd(&tv, &rtv, &tv);
1477 timeradd(&mtv, &tv, &mtv);
1478 }
4eb7b489
RM
1479 eloop_timeout_add_tv(ap->iface->ctx->eloop,
1480 &mtv, ap->dadcallback, ap);
e82129a4
RM
1481 }
1482#endif
1483#endif /* IPV6_SEND_DAD */
1484}
1485
1486ssize_t
1487ipv6nd_probeaddrs(struct ipv6_addrhead *addrs)
1488{
1489 struct ipv6_addr *ap, *apn;
1490 ssize_t i;
1491
1492 i = 0;
1493 TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
1494 if (ap->prefix_vltime == 0) {
1495 TAILQ_REMOVE(addrs, ap, next);
1496 if (ap->flags & IPV6_AF_ADDED) {
1497 syslog(LOG_INFO, "%s: deleting address %s",
1498 ap->iface->name, ap->saddr);
1499 i++;
ef0f1a1c
RM
1500 if (!IN6_IS_ADDR_UNSPECIFIED(&ap->addr) &&
1501 del_address6(ap) == -1 &&
1502 errno != EADDRNOTAVAIL && errno != ENXIO)
1503 syslog(LOG_ERR, "del_address6 %m");
e82129a4 1504 }
e82129a4 1505 if (ap->dadcallback)
4eb7b489
RM
1506 eloop_q_timeout_delete(ap->iface->ctx->eloop,
1507 0, NULL, ap->dadcallback);
e82129a4 1508 free(ap);
38f20553 1509 } else if (!IN6_IS_ADDR_UNSPECIFIED(&ap->addr)) {
e82129a4
RM
1510 ipv6nd_probeaddr(ap);
1511 if (ap->flags & IPV6_AF_NEW)
1512 i++;
1513 }
1514 }
1515
1516 return i;
1517}
1518
1519void
1520ipv6nd_proberouter(void *arg)
1521{
1522 struct ra *rap = arg;
1523 struct nd_neighbor_solicit *ns;
1524 struct nd_opt_hdr *nd;
1525 struct sockaddr_in6 dst;
1526 struct cmsghdr *cm;
1527 struct in6_pktinfo pi;
1528 int hoplimit = HOPLIMIT;
1529 struct timeval tv, rtv;
4eb7b489 1530 struct ipv6_ctx *ctx;
e82129a4 1531
4eb7b489
RM
1532 if (ipv6nd_open(rap->iface->ctx) == -1) {
1533 syslog(LOG_ERR, "%s: ipv6nd_open: %m", __func__);
e82129a4 1534 return;
4eb7b489 1535 }
e82129a4
RM
1536
1537 if (!rap->ns) {
1538 rap->nslen = sizeof(*ns) + ROUNDUP8(rap->iface->hwlen + 2);
1539 rap->ns = calloc(1, rap->nslen);
1540 if (rap->ns == NULL) {
1541 syslog(LOG_ERR, "%s: %m", __func__);
1542 return;
1543 }
1544 ns = (struct nd_neighbor_solicit *)(void *)rap->ns;
1545 ns->nd_ns_type = ND_NEIGHBOR_SOLICIT;
1546 //ns->nd_ns_cksum = 0;
1547 //ns->nd_ns_code = 0;
1548 //ns->nd_ns_reserved = 0;
1549 ns->nd_ns_target = rap->from;
1550 nd = (struct nd_opt_hdr *)(rap->ns + sizeof(*ns));
1551 nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
1552 nd->nd_opt_len = (ROUNDUP8(rap->iface->hwlen + 2)) >> 3;
1553 memcpy(nd + 1, rap->iface->hwaddr, rap->iface->hwlen);
1554 }
1555
1556 memset(&dst, 0, sizeof(dst));
1557 dst.sin6_family = AF_INET6;
1558#ifdef SIN6_LEN
1559 dst.sin6_len = sizeof(dst);
1560#endif
1561 memcpy(&dst.sin6_addr, &rap->from, sizeof(dst.sin6_addr));
1562 dst.sin6_scope_id = rap->iface->index;
1563
4eb7b489
RM
1564 ctx = rap->iface->ctx->ipv6;
1565 ctx->sndhdr.msg_name = (caddr_t)&dst;
1566 ctx->sndhdr.msg_iov[0].iov_base = rap->ns;
1567 ctx->sndhdr.msg_iov[0].iov_len = rap->nslen;
e82129a4
RM
1568
1569 /* Set the outbound interface */
4eb7b489 1570 cm = CMSG_FIRSTHDR(&ctx->sndhdr);
e82129a4
RM
1571 cm->cmsg_level = IPPROTO_IPV6;
1572 cm->cmsg_type = IPV6_PKTINFO;
1573 cm->cmsg_len = CMSG_LEN(sizeof(pi));
1574 memset(&pi, 0, sizeof(pi));
1575 pi.ipi6_ifindex = rap->iface->index;
1576 memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
1577
1578 /* Hop limit */
4eb7b489 1579 cm = CMSG_NXTHDR(&ctx->sndhdr, cm);
e82129a4
RM
1580 cm->cmsg_level = IPPROTO_IPV6;
1581 cm->cmsg_type = IPV6_HOPLIMIT;
1582 cm->cmsg_len = CMSG_LEN(sizeof(hoplimit));
1583 memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit));
1584
1585#ifdef DEBUG_NS
1586 syslog(LOG_INFO, "%s: sending IPv6 NS for %s",
1587 rap->iface->name, rap->sfrom);
1588#endif
4eb7b489 1589 if (sendmsg(ctx->nd_fd, &ctx->sndhdr, 0) == -1) {
e82129a4
RM
1590 syslog(LOG_ERR, "%s: %s: sendmsg: %m",
1591 rap->iface->name, __func__);
1592 return;
1593 }
1594
1595 ms_to_tv(&tv, rap->retrans == 0 ? RETRANS_TIMER : rap->retrans);
1596 ms_to_tv(&rtv, MIN_RANDOM_FACTOR);
1597 timeradd(&tv, &rtv, &tv);
1598 rtv.tv_sec = 0;
1599 rtv.tv_usec = arc4random() % (MAX_RANDOM_FACTOR_U -MIN_RANDOM_FACTOR_U);
1600 timeradd(&tv, &rtv, &tv);
4eb7b489
RM
1601 eloop_timeout_add_tv(rap->iface->ctx->eloop,
1602 &tv, ipv6nd_proberouter, rap);
e82129a4
RM
1603
1604 if (rap->nsprobes++ == 0)
4eb7b489
RM
1605 eloop_timeout_add_sec(rap->iface->ctx->eloop,
1606 DELAY_FIRST_PROBE_TIME, ipv6nd_unreachable, rap);
e82129a4
RM
1607}
1608
1609void
1610ipv6nd_cancelproberouter(struct ra *rap)
1611{
1612
4eb7b489
RM
1613 eloop_timeout_delete(rap->iface->ctx->eloop, ipv6nd_proberouter, rap);
1614 eloop_timeout_delete(rap->iface->ctx->eloop, ipv6nd_unreachable, rap);
e82129a4
RM
1615}
1616
e82129a4 1617static void
4eb7b489
RM
1618ipv6nd_handlena(struct ipv6_ctx *ctx, struct interface *ifp,
1619 struct icmp6_hdr *icp, ssize_t len)
e82129a4
RM
1620{
1621 struct nd_neighbor_advert *nd_na;
1622 struct ra *rap;
1623 int is_router, is_solicited;
1624#ifdef DEBUG_NS
1625 int found;
1626#endif
1627 struct timeval tv;
1628
1629#ifdef LISTEN_DAD
1630 struct dhcp6_state *d6state;
1631 struct ipv6_addr *ap;
1632#endif
1633
1634 if ((size_t)len < sizeof(struct nd_neighbor_advert)) {
4eb7b489 1635 syslog(LOG_ERR, "IPv6 NA packet too short from %s", ctx->sfrom);
e82129a4
RM
1636 return;
1637 }
1638
1639 if (ifp == NULL) {
1640#ifdef DEBUG_NS
4eb7b489
RM
1641 syslog(LOG_DEBUG, "NA for unexpected interface from %s",
1642 ctx->sfrom);
e82129a4
RM
1643#endif
1644 return;
1645 }
1646
1647 nd_na = (struct nd_neighbor_advert *)icp;
1648 is_router = nd_na->nd_na_flags_reserved & ND_NA_FLAG_ROUTER;
1649 is_solicited = nd_na->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED;
1650
1651 if (IN6_IS_ADDR_MULTICAST(&nd_na->nd_na_target)) {
1652 syslog(LOG_ERR, "%s: NA for multicast address from %s",
4eb7b489 1653 ifp->name, ctx->sfrom);
e82129a4
RM
1654 return;
1655 }
1656
1657#ifdef DEBUG_NS
1658 found = 0;
1659#endif
4eb7b489 1660 TAILQ_FOREACH(rap, ctx->ra_routers, next) {
e82129a4
RM
1661 if (rap->iface != ifp)
1662 continue;
1663 if (memcmp(rap->from.s6_addr, nd_na->nd_na_target.s6_addr,
1664 sizeof(rap->from.s6_addr)) == 0)
1665 break;
1666#ifdef LISTEN_DAD
1667 TAILQ_FOREACH(ap, &rap->addrs, next) {
1668 if (memcmp(ap->addr.s6_addr,
1669 nd_na->nd_na_target.s6_addr,
1670 sizeof(ap->addr.s6_addr)) == 0)
1671 {
1672 ap->flags |= IPV6_AF_DUPLICATED;
1673 if (ap->dadcallback)
1674 ap->dadcallback(ap);
1675#ifdef DEBUG_NS
1676 found++;
1677#endif
1678 }
1679 }
1680#endif
1681 }
1682 if (rap == NULL) {
1683#ifdef LISTEN_DAD
1684 d6state = D6_STATE(ifp);
1685 if (d6state) {
1686 TAILQ_FOREACH(ap, &d6state->addrs, next) {
1687 if (memcmp(ap->addr.s6_addr,
1688 nd_na->nd_na_target.s6_addr,
1689 sizeof(ap->addr.s6_addr)) == 0)
1690 {
1691 ap->flags |= IPV6_AF_DUPLICATED;
1692 if (ap->dadcallback)
1693 ap->dadcallback(ap);
1694#ifdef DEBUG_NS
1695 found++;
1696#endif
1697 }
1698 }
1699 }
1700#endif
1701
1702#ifdef DEBUG_NS
1703 if (found == 0)
1704 syslog(LOG_DEBUG, "%s: unexpected NA from %s",
4eb7b489 1705 ifp->name, ctx->sfrom);
e82129a4
RM
1706#endif
1707 return;
1708 }
1709
1710#ifdef DEBUG_NS
1711 syslog(LOG_DEBUG, "%s: %sNA from %s",
4eb7b489 1712 ifp->name, is_solicited ? "solicited " : "", ctx->sfrom);
e82129a4
RM
1713#endif
1714
1715 /* Node is no longer a router, so remove it from consideration */
1716 if (!is_router && !rap->expired) {
1717 syslog(LOG_INFO, "%s: %s is no longer a router",
4eb7b489 1718 ifp->name, ctx->sfrom);
e82129a4
RM
1719 rap->expired = 1;
1720 ipv6nd_cancelproberouter(rap);
4eb7b489 1721 ipv6_buildroutes(ifp->ctx);
294eff4d 1722 script_runreason(ifp, "ROUTERADVERT");
e82129a4
RM
1723 return;
1724 }
1725
1726 if (is_solicited && is_router && rap->lifetime) {
1727 if (rap->expired) {
1728 rap->expired = 0;
1729 syslog(LOG_INFO, "%s: %s is reachable again",
4eb7b489
RM
1730 ifp->name, ctx->sfrom);
1731 ipv6_buildroutes(ifp->ctx);
e82129a4
RM
1732 script_runreason(rap->iface, "ROUTERADVERT"); /* XXX */
1733 }
1734 rap->nsprobes = 0;
1735 if (rap->reachable) {
1736 ms_to_tv(&tv, rap->reachable);
1737 } else {
1738 tv.tv_sec = REACHABLE_TIME;
1739 tv.tv_usec = 0;
1740 }
4eb7b489
RM
1741 eloop_timeout_add_tv(rap->iface->ctx->eloop,
1742 &tv, ipv6nd_proberouter, rap);
1743 eloop_timeout_delete(rap->iface->ctx->eloop,
1744 ipv6nd_unreachable, rap);
eebe9a18 1745 }
91cd7324
RM
1746}
1747
e82129a4 1748static void
4eb7b489 1749ipv6nd_handledata(void *arg)
e82129a4 1750{
4eb7b489
RM
1751 struct dhcpcd_ctx *dhcpcd_ctx;
1752 struct ipv6_ctx *ctx;
e82129a4
RM
1753 ssize_t len;
1754 struct cmsghdr *cm;
1755 int hoplimit;
1756 struct in6_pktinfo pkt;
1757 struct icmp6_hdr *icp;
1758 struct interface *ifp;
1759
4eb7b489
RM
1760 dhcpcd_ctx = arg;
1761 ctx = dhcpcd_ctx->ipv6;
1762 len = recvmsg(ctx->nd_fd, &ctx->rcvhdr, 0);
e82129a4
RM
1763 if (len == -1) {
1764 syslog(LOG_ERR, "recvmsg: %m");
1765 return;
1766 }
4eb7b489
RM
1767 ctx->sfrom = inet_ntop(AF_INET6, &ctx->from.sin6_addr,
1768 ctx->ntopbuf, INET6_ADDRSTRLEN);
e82129a4 1769 if ((size_t)len < sizeof(struct icmp6_hdr)) {
4eb7b489
RM
1770 syslog(LOG_ERR, "IPv6 ICMP packet too short from %s",
1771 ctx->sfrom);
e82129a4
RM
1772 return;
1773 }
1774
1775 pkt.ipi6_ifindex = hoplimit = 0;
4eb7b489 1776 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&ctx->rcvhdr);
e82129a4 1777 cm;
4eb7b489 1778 cm = (struct cmsghdr *)CMSG_NXTHDR(&ctx->rcvhdr, cm))
e82129a4
RM
1779 {
1780 if (cm->cmsg_level != IPPROTO_IPV6)
1781 continue;
1782 switch(cm->cmsg_type) {
1783 case IPV6_PKTINFO:
1784 if (cm->cmsg_len == CMSG_LEN(sizeof(pkt)))
1785 memcpy(&pkt, CMSG_DATA(cm), sizeof(pkt));
1786 break;
1787 case IPV6_HOPLIMIT:
1788 if (cm->cmsg_len == CMSG_LEN(sizeof(int)))
1789 memcpy(&hoplimit, CMSG_DATA(cm), sizeof(int));
1790 break;
1791 }
1792 }
1793
1794 if (pkt.ipi6_ifindex == 0 || hoplimit == 0) {
1795 syslog(LOG_ERR,
4eb7b489
RM
1796 "IPv6 RA/NA did not contain index or hop limit from %s",
1797 ctx->sfrom);
e82129a4
RM
1798 return;
1799 }
1800
4eb7b489 1801 TAILQ_FOREACH(ifp, dhcpcd_ctx->ifaces, next) {
e82129a4
RM
1802 if (ifp->index == (unsigned int)pkt.ipi6_ifindex)
1803 break;
1804 }
1805
4eb7b489 1806 icp = (struct icmp6_hdr *)ctx->rcvhdr.msg_iov[0].iov_base;
e82129a4
RM
1807 if (icp->icmp6_code == 0) {
1808 switch(icp->icmp6_type) {
1809 case ND_NEIGHBOR_ADVERT:
4eb7b489 1810 ipv6nd_handlena(ctx, ifp, icp, len);
e82129a4
RM
1811 return;
1812 case ND_ROUTER_ADVERT:
4eb7b489 1813 ipv6nd_handlera(ctx, ifp, icp, len);
e82129a4
RM
1814 return;
1815 }
1816 }
7cece083 1817
e82129a4 1818 syslog(LOG_ERR, "invalid IPv6 type %d or code %d from %s",
4eb7b489 1819 icp->icmp6_type, icp->icmp6_code, ctx->sfrom);
e82129a4
RM
1820}
1821
91cd7324 1822int
e82129a4 1823ipv6nd_startrs(struct interface *ifp)
91cd7324 1824{
ca15a0aa 1825 struct rs_state *state;
91cd7324 1826
e42bbc9b 1827 syslog(LOG_INFO, "%s: soliciting an IPv6 router", ifp->name);
4eb7b489
RM
1828 if (ipv6nd_open(ifp->ctx) == -1) {
1829 syslog(LOG_ERR, "%s: ipv6nd_open: %m", __func__);
1830 return -1;
ca15a0aa
RM
1831 }
1832
4eb7b489 1833 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
673e81e5
RM
1834
1835 state = RS_STATE(ifp);
1836 if (state == NULL) {
e82129a4 1837 ifp->if_data[IF_DATA_IPV6ND] = calloc(1, sizeof(*state));
673e81e5 1838 state = RS_STATE(ifp);
fbbb0875
RM
1839 if (state == NULL) {
1840 syslog(LOG_ERR, "%s: %m", __func__);
1841 return -1;
1842 }
673e81e5
RM
1843 }
1844
1845 /* Always make a new probe as the underlying hardware
1846 * address could have changed. */
e82129a4 1847 ipv6nd_makersprobe(ifp);
fbbb0875 1848 if (state->rs == NULL) {
e82129a4 1849 syslog(LOG_ERR, "%s: ipv6ns_makersprobe: %m", __func__);
673e81e5 1850 return -1;
fbbb0875 1851 }
91cd7324 1852
ca15a0aa 1853 state->rsprobes = 0;
e82129a4 1854 ipv6nd_sendrsprobe(ifp);
91cd7324
RM
1855 return 0;
1856}