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