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