]> git.ipfire.org Git - thirdparty/dhcpcd.git/blame - src/ipv6nd.c
RA: expire whole RA on carrier up
[thirdparty/dhcpcd.git] / src / ipv6nd.c
CommitLineData
8cc47ba2 1/*
1a140c64 2 * dhcpcd - IPv6 ND handling
94354c03 3 * Copyright (c) 2006-2019 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>
23b899e4 32#include <net/route.h>
91cd7324
RM
33#include <netinet/in.h>
34#include <netinet/ip6.h>
35#include <netinet/icmp6.h>
36
cd09e583 37#include <assert.h>
91cd7324 38#include <errno.h>
e8c8e9b9 39#include <fcntl.h>
91cd7324
RM
40#include <stddef.h>
41#include <stdlib.h>
42#include <string.h>
fbbb0875 43#include <unistd.h>
91cd7324 44
e5cd8255 45#define ELOOP_QUEUE 3
91cd7324 46#include "common.h"
91cd7324 47#include "dhcpcd.h"
a1b1f0a8 48#include "dhcp-common.h"
d7555c12 49#include "dhcp6.h"
91cd7324 50#include "eloop.h"
a3ee6b23 51#include "if.h"
eebe9a18 52#include "ipv6.h"
e82129a4 53#include "ipv6nd.h"
94d1ded9 54#include "logerr.h"
9aa11487 55#include "route.h"
294eff4d 56#include "script.h"
91cd7324 57
d7555c12
RM
58/* Debugging Router Solicitations is a lot of spam, so disable it */
59//#define DEBUG_RS
60
91cd7324
RM
61#ifndef ND_OPT_RDNSS
62#define ND_OPT_RDNSS 25
63struct nd_opt_rdnss { /* RDNSS option RFC 6106 */
64 uint8_t nd_opt_rdnss_type;
65 uint8_t nd_opt_rdnss_len;
66 uint16_t nd_opt_rdnss_reserved;
67 uint32_t nd_opt_rdnss_lifetime;
68 /* followed by list of IP prefixes */
18fa35e1
RM
69};
70__CTASSERT(sizeof(struct nd_opt_rdnss) == 8);
91cd7324
RM
71#endif
72
73#ifndef ND_OPT_DNSSL
74#define ND_OPT_DNSSL 31
75struct nd_opt_dnssl { /* DNSSL option RFC 6106 */
76 uint8_t nd_opt_dnssl_type;
77 uint8_t nd_opt_dnssl_len;
78 uint16_t nd_opt_dnssl_reserved;
79 uint32_t nd_opt_dnssl_lifetime;
80 /* followed by list of DNS servers */
18fa35e1
RM
81};
82__CTASSERT(sizeof(struct nd_opt_rdnss) == 8);
91cd7324
RM
83#endif
84
fd3e7f65
RM
85/* Impossible options, so we can easily add extras */
86#define _ND_OPT_PREFIX_ADDR 255 + 1
87
eebe9a18
RM
88/* Minimal IPv6 MTU */
89#ifndef IPV6_MMTU
90#define IPV6_MMTU 1280
91#endif
92
93#ifndef ND_RA_FLAG_RTPREF_HIGH
94#define ND_RA_FLAG_RTPREF_MASK 0x18
95#define ND_RA_FLAG_RTPREF_HIGH 0x08
96#define ND_RA_FLAG_RTPREF_MEDIUM 0x00
97#define ND_RA_FLAG_RTPREF_LOW 0x18
98#define ND_RA_FLAG_RTPREF_RSV 0x10
99#endif
100
101/* RTPREF_MEDIUM has to be 0! */
102#define RTPREF_HIGH 1
103#define RTPREF_MEDIUM 0
104#define RTPREF_LOW (-1)
105#define RTPREF_RESERVED (-2)
106#define RTPREF_INVALID (-3) /* internal */
107
19005560
RM
108#define EXPIRED_MAX 5 /* Remember 5 expired routers to avoid
109 logspam. */
110
e82129a4
RM
111#define MIN_RANDOM_FACTOR 500 /* millisecs */
112#define MAX_RANDOM_FACTOR 1500 /* millisecs */
113#define MIN_RANDOM_FACTOR_U MIN_RANDOM_FACTOR * 1000 /* usecs */
114#define MAX_RANDOM_FACTOR_U MAX_RANDOM_FACTOR * 1000 /* usecs */
115
116#if BYTE_ORDER == BIG_ENDIAN
117#define IPV6_ADDR_INT32_ONE 1
118#define IPV6_ADDR_INT16_MLL 0xff02
119#elif BYTE_ORDER == LITTLE_ENDIAN
120#define IPV6_ADDR_INT32_ONE 0x01000000
121#define IPV6_ADDR_INT16_MLL 0x02ff
122#endif
123
124/* Debugging Neighbor Solicitations is a lot of spam, so disable it */
125//#define DEBUG_NS
126//
127
8d5de853 128static void ipv6nd_handledata(void *);
7cece083 129
65e5b9f9
RM
130/*
131 * Android ships buggy ICMP6 filter headers.
132 * Supply our own until they fix their shit.
133 * References:
134 * https://android-review.googlesource.com/#/c/58438/
135 * http://code.google.com/p/android/issues/original?id=32621&seq=24
136 */
137#ifdef __ANDROID__
138#undef ICMP6_FILTER_WILLPASS
139#undef ICMP6_FILTER_WILLBLOCK
140#undef ICMP6_FILTER_SETPASS
141#undef ICMP6_FILTER_SETBLOCK
142#undef ICMP6_FILTER_SETPASSALL
143#undef ICMP6_FILTER_SETBLOCKALL
144#define ICMP6_FILTER_WILLPASS(type, filterp) \
145 ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) == 0)
146#define ICMP6_FILTER_WILLBLOCK(type, filterp) \
147 ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) != 0)
148#define ICMP6_FILTER_SETPASS(type, filterp) \
149 ((((filterp)->icmp6_filt[(type) >> 5]) &= ~(1 << ((type) & 31))))
150#define ICMP6_FILTER_SETBLOCK(type, filterp) \
151 ((((filterp)->icmp6_filt[(type) >> 5]) |= (1 << ((type) & 31))))
152#define ICMP6_FILTER_SETPASSALL(filterp) \
153 memset(filterp, 0, sizeof(struct icmp6_filter));
154#define ICMP6_FILTER_SETBLOCKALL(filterp) \
155 memset(filterp, 0xff, sizeof(struct icmp6_filter));
156#endif
157
62247de8
RM
158/* Support older systems with different defines */
159#if !defined(IPV6_RECVHOPLIMIT) && defined(IPV6_HOPLIMIT)
160#define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
161#endif
162#if !defined(IPV6_RECVPKTINFO) && defined(IPV6_PKTINFO)
163#define IPV6_RECVPKTINFO IPV6_PKTINFO
164#endif
165
f1df29d2
RM
166/* Handy defines */
167#define ipv6nd_free_ra(ra) ipv6nd_freedrop_ra((ra), 0)
168#define ipv6nd_drop_ra(ra) ipv6nd_freedrop_ra((ra), 1)
169
2be15e88
RM
170void
171ipv6nd_printoptions(const struct dhcpcd_ctx *ctx,
172 const struct dhcp_opt *opts, size_t opts_len)
173{
174 size_t i, j;
175 const struct dhcp_opt *opt, *opt2;
176 int cols;
177
178 for (i = 0, opt = ctx->nd_opts;
179 i < ctx->nd_opts_len; i++, opt++)
180 {
181 for (j = 0, opt2 = opts; j < opts_len; j++, opt2++)
182 if (opt2->option == opt->option)
183 break;
184 if (j == opts_len) {
185 cols = printf("%03d %s", opt->option, opt->var);
186 dhcp_print_option_encoding(opt, cols);
187 }
188 }
189 for (i = 0, opt = opts; i < opts_len; i++, opt++) {
190 cols = printf("%03d %s", opt->option, opt->var);
191 dhcp_print_option_encoding(opt, cols);
192 }
193}
194
aae24feb 195static int
d48bfc96 196ipv6nd_open0(void)
91cd7324 197{
b2edc303 198 int s, on;
4eb7b489 199 struct icmp6_filter filt;
91cd7324 200
9843976a 201#define SOCK_FLAGS SOCK_CLOEXEC | SOCK_NONBLOCK
b2edc303 202 s = xsocket(PF_INET6, SOCK_RAW | SOCK_FLAGS, IPPROTO_ICMPV6);
9843976a 203#undef SOCK_FLAGS
b2edc303 204 if (s == -1)
fbbb0875
RM
205 return -1;
206
cc431339
RM
207 /* RFC4861 4.1 */
208 on = 255;
b2edc303 209 if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
4eb7b489 210 &on, sizeof(on)) == -1)
fbbb0875 211 goto eexit;
91cd7324
RM
212
213 on = 1;
b2edc303 214 if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
4eb7b489 215 &on, sizeof(on)) == -1)
fbbb0875 216 goto eexit;
91cd7324
RM
217
218 ICMP6_FILTER_SETBLOCKALL(&filt);
4eb7b489 219 ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filt);
91cd7324 220 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
b2edc303 221 if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER,
4eb7b489 222 &filt, sizeof(filt)) == -1)
fbbb0875 223 goto eexit;
fbbb0875 224
b2edc303 225 return s;
e82129a4
RM
226
227eexit:
b2edc303 228 close(s);
e82129a4
RM
229 return -1;
230}
231
b2edc303
RM
232#ifdef __sun
233static int
234ipv6nd_open(struct interface *ifp)
235{
236 int s;
237 struct ipv6_mreq mreq = {
e275f240 238 .ipv6mr_multiaddr = IN6ADDR_LINKLOCAL_ALLNODES_INIT,
b2edc303
RM
239 .ipv6mr_interface = ifp->index
240 };
241 struct rs_state *state = RS_STATE(ifp);
6fcd7ff4 242 uint_t ifindex = ifp->index;
b2edc303
RM
243
244 if (state->nd_fd != -1)
245 return state->nd_fd;
246
247 s = ipv6nd_open0();
248 if (s == -1)
249 return -1;
250
6fcd7ff4
RM
251 if (setsockopt(s, IPPROTO_IPV6, IPV6_BOUND_IF,
252 &ifindex, sizeof(ifindex)) == -1)
253 {
254 close(s);
255 return -1;
256 }
257
b2edc303
RM
258 if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP,
259 &mreq, sizeof(mreq)) == -1)
260 {
261 close(s);
262 return -1;
263 }
264
265 state->nd_fd = s;
266 eloop_event_add(ifp->ctx->eloop, s, ipv6nd_handledata, ifp);
267 return s;
268}
269#else
270static int
271ipv6nd_open(struct dhcpcd_ctx *ctx)
272{
b0a0f6d4 273 int s, on;
b2edc303
RM
274
275 if (ctx->nd_fd != -1)
276 return ctx->nd_fd;
277
b0a0f6d4
RM
278 s = ipv6nd_open0();
279 if (s == -1)
280 return -1;
281
b2edc303
RM
282 on = 1;
283 if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO,
284 &on, sizeof(on)) == -1)
285 {
286 close(s);
287 return -1;
288 }
289
290 ctx->nd_fd = s;
291 eloop_event_add(ctx->eloop, s, ipv6nd_handledata, ctx);
292 return s;
293}
294#endif
295
e82129a4
RM
296static int
297ipv6nd_makersprobe(struct interface *ifp)
91cd7324 298{
ca15a0aa 299 struct rs_state *state;
91cd7324 300 struct nd_router_solicit *rs;
91cd7324 301
ca15a0aa
RM
302 state = RS_STATE(ifp);
303 free(state->rs);
ba71fb8b
RM
304 state->rslen = sizeof(*rs);
305 if (ifp->hwlen != 0)
306 state->rslen += (size_t)ROUNDUP8(ifp->hwlen + 2);
10e17e3f 307 state->rs = calloc(1, state->rslen);
ca15a0aa 308 if (state->rs == NULL)
91cd7324 309 return -1;
2e704972 310 rs = state->rs;
91cd7324 311 rs->nd_rs_type = ND_ROUTER_SOLICIT;
2e704972
RM
312 //rs->nd_rs_code = 0;
313 //rs->nd_rs_cksum = 0;
314 //rs->nd_rs_reserved = 0;
ba71fb8b
RM
315
316 if (ifp->hwlen != 0) {
317 struct nd_opt_hdr *nd;
318
2e704972 319 nd = (struct nd_opt_hdr *)(state->rs + 1);
ba71fb8b
RM
320 nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
321 nd->nd_opt_len = (uint8_t)((ROUNDUP8(ifp->hwlen + 2)) >> 3);
322 memcpy(nd + 1, ifp->hwaddr, ifp->hwlen);
323 }
91cd7324
RM
324 return 0;
325}
673e81e5 326
91cd7324 327static void
e82129a4 328ipv6nd_sendrsprobe(void *arg)
91cd7324
RM
329{
330 struct interface *ifp = arg;
5fed9d43 331 struct rs_state *state = RS_STATE(ifp);
4d53b9d9
RM
332 struct sockaddr_in6 dst = {
333 .sin6_family = AF_INET6,
334 .sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT,
335 .sin6_scope_id = ifp->index,
336 };
5fed9d43
RM
337 struct iovec iov = { .iov_base = state->rs, .iov_len = state->rslen };
338 unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 };
339 struct msghdr msg = {
340 .msg_name = &dst, .msg_namelen = sizeof(dst),
341 .msg_iov = &iov, .msg_iovlen = 1,
342 .msg_control = ctl, .msg_controllen = sizeof(ctl),
343 };
91cd7324 344 struct cmsghdr *cm;
5fed9d43 345 struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
b2edc303 346 int s;
91cd7324 347
0e906716 348 if (ipv6_linklocal(ifp) == NULL) {
0e56d022 349 logdebugx("%s: delaying Router Solicitation for LL address",
5331b839 350 ifp->name);
e82129a4 351 ipv6_addlinklocalcallback(ifp, ipv6nd_sendrsprobe, ifp);
5331b839
RM
352 return;
353 }
354
4356c648 355#ifdef HAVE_SA_LEN
4eb7b489
RM
356 dst.sin6_len = sizeof(dst);
357#endif
91cd7324
RM
358
359 /* Set the outbound interface */
5fed9d43 360 cm = CMSG_FIRSTHDR(&msg);
8fc52ced
RM
361 if (cm == NULL) /* unlikely */
362 return;
91cd7324
RM
363 cm->cmsg_level = IPPROTO_IPV6;
364 cm->cmsg_type = IPV6_PKTINFO;
365 cm->cmsg_len = CMSG_LEN(sizeof(pi));
91cd7324
RM
366 memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
367
0e56d022 368 logdebugx("%s: sending Router Solicitation", ifp->name);
b2edc303
RM
369#ifdef __sun
370 s = state->nd_fd;
371#else
372 s = ifp->ctx->nd_fd;
373#endif
374 if (sendmsg(s, &msg, 0) == -1) {
94d1ded9 375 logerr(__func__);
9299f1c6
RM
376 /* Allow IPv6ND to continue .... at most a few errors
377 * would be logged.
378 * Generally the error is ENOBUFS when struggling to
379 * associate with an access point. */
83e82504 380 }
91cd7324 381
ca15a0aa 382 if (state->rsprobes++ < MAX_RTR_SOLICITATIONS)
4eb7b489
RM
383 eloop_timeout_add_sec(ifp->ctx->eloop,
384 RTR_SOLICITATION_INTERVAL, ipv6nd_sendrsprobe, ifp);
2f53bfd4 385 else {
94d1ded9 386 logwarnx("%s: no IPv6 Routers available", ifp->name);
2f53bfd4 387 ipv6nd_drop(ifp);
2f53bfd4
RM
388 }
389}
390
cd09e583
RM
391static void
392ipv6nd_sendadvertisement(void *arg)
393{
394 struct ipv6_addr *ia = arg;
395 struct interface *ifp = ia->iface;
396 struct dhcpcd_ctx *ctx = ifp->ctx;
5fed9d43
RM
397 struct sockaddr_in6 dst = {
398 .sin6_family = AF_INET6,
4d53b9d9 399 .sin6_addr = IN6ADDR_LINKLOCAL_ALLNODES_INIT,
5fed9d43
RM
400 .sin6_scope_id = ifp->index,
401 };
402 struct iovec iov = { .iov_base = ia->na, .iov_len = ia->na_len };
403 unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 };
404 struct msghdr msg = {
405 .msg_name = &dst, .msg_namelen = sizeof(dst),
406 .msg_iov = &iov, .msg_iovlen = 1,
407 .msg_control = ctl, .msg_controllen = sizeof(ctl),
408 };
cd09e583 409 struct cmsghdr *cm;
5fed9d43 410 struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
cd09e583 411 const struct rs_state *state = RS_CSTATE(ifp);
b2edc303 412 int s;
cd09e583 413
3458df61 414 if (state == NULL || ifp->carrier <= LINK_DOWN)
cd09e583
RM
415 goto freeit;
416
cd09e583
RM
417#ifdef SIN6_LEN
418 dst.sin6_len = sizeof(dst);
419#endif
cd09e583 420
cd09e583 421 /* Set the outbound interface. */
5fed9d43 422 cm = CMSG_FIRSTHDR(&msg);
cd09e583
RM
423 assert(cm != NULL);
424 cm->cmsg_level = IPPROTO_IPV6;
425 cm->cmsg_type = IPV6_PKTINFO;
426 cm->cmsg_len = CMSG_LEN(sizeof(pi));
cd09e583 427 memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
cd09e583 428 logdebugx("%s: sending NA for %s", ifp->name, ia->saddr);
b2edc303
RM
429#ifdef __sun
430 s = state->nd_fd;
431#else
432 s = ctx->nd_fd;
433#endif
434 if (sendmsg(s, &msg, 0) == -1)
fcc399ee
RM
435#ifdef __OpenBSD__
436/* This isn't too critical as they don't support IPv6 address sharing */
437#warning Cannot send NA messages on OpenBSD
438 logdebug(__func__);
439#else
cd09e583 440 logerr(__func__);
fcc399ee 441#endif
cd09e583
RM
442
443 if (++ia->na_count < MAX_NEIGHBOR_ADVERTISEMENT) {
444 eloop_timeout_add_sec(ctx->eloop,
445 state->retrans / 1000, ipv6nd_sendadvertisement, ia);
446 return;
447 }
448
449freeit:
450 free(ia->na);
451 ia->na = NULL;
452 ia->na_count = 0;
453}
454
455void
456ipv6nd_advertise(struct ipv6_addr *ia)
457{
458 struct dhcpcd_ctx *ctx;
459 struct interface *ifp;
460 struct ipv6_state *state;
461 struct ipv6_addr *iap, *iaf;
462 struct nd_neighbor_advert *na;
463
464 if (IN6_IS_ADDR_MULTICAST(&ia->addr))
465 return;
466
467 ctx = ia->iface->ctx;
cd09e583
RM
468 /* Find the most preferred address to advertise. */
469 iaf = NULL;
470 TAILQ_FOREACH(ifp, ctx->ifaces, next) {
471 state = IPV6_STATE(ifp);
3458df61 472 if (state == NULL || ifp->carrier <= LINK_DOWN)
cd09e583
RM
473 continue;
474
475 TAILQ_FOREACH(iap, &state->addrs, next) {
476 if (!IN6_ARE_ADDR_EQUAL(&iap->addr, &ia->addr))
477 continue;
478
479 /* Cancel any current advertisement. */
480 eloop_timeout_delete(ctx->eloop,
481 ipv6nd_sendadvertisement, iap);
482
483 /* Don't advertise what we can't use. */
484 if (iap->prefix_vltime == 0 ||
485 iap->addr_flags & IN6_IFF_NOTUSEABLE)
486 continue;
487
7d58ddf0
RM
488 if (iaf == NULL ||
489 iaf->iface->metric > iap->iface->metric)
cd09e583
RM
490 iaf = iap;
491 }
492 }
493 if (iaf == NULL)
494 return;
495
496 /* Make the packet. */
497 ifp = iaf->iface;
498 iaf->na_len = sizeof(*na);
499 if (ifp->hwlen != 0)
500 iaf->na_len += (size_t)ROUNDUP8(ifp->hwlen + 2);
501 na = calloc(1, iaf->na_len);
502 if (na == NULL) {
503 logerr(__func__);
504 return;
505 }
506
507 na->nd_na_type = ND_NEIGHBOR_ADVERT;
508 na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE;
509 if (ip6_forwarding(ifp->name) == 1)
510 na->nd_na_flags_reserved |= ND_NA_FLAG_ROUTER;
511 na->nd_na_target = ia->addr;
512
513 if (ifp->hwlen != 0) {
514 struct nd_opt_hdr *opt;
515
516 opt = (struct nd_opt_hdr *)(na + 1);
517 opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
518 opt->nd_opt_len = (uint8_t)((ROUNDUP8(ifp->hwlen + 2)) >> 3);
519 memcpy(opt + 1, ifp->hwaddr, ifp->hwlen);
520 }
521
522 iaf->na_count = 0;
523 free(iaf->na);
524 iaf->na = na;
525 eloop_timeout_delete(ctx->eloop, ipv6nd_sendadvertisement, iaf);
526 ipv6nd_sendadvertisement(iaf);
527}
528
cf94e2dd
RM
529static void
530ipv6nd_expire(void *arg)
2f53bfd4 531{
cf94e2dd 532 struct interface *ifp = arg;
2f53bfd4 533 struct ra *rap;
cf94e2dd
RM
534 struct ipv6_addr *ia;
535 struct timespec now = { .tv_sec = 1 };
2f53bfd4 536
cc9d9bf8 537 if (ifp->ctx->ra_routers == NULL)
aa9fc372
RM
538 return;
539
cc9d9bf8 540 TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) {
cf94e2dd
RM
541 if (rap->iface == ifp)
542 continue;
543 rap->acquired = now;
544 TAILQ_FOREACH(ia, &rap->addrs, next) {
545 ia->acquired = now;
2f53bfd4
RM
546 }
547 }
cf94e2dd
RM
548 ipv6nd_expirera(ifp);
549}
550
551void
552ipv6nd_startexpire(struct interface *ifp)
553{
554
555 eloop_timeout_add_sec(ifp->ctx->eloop, RTR_CARRIER_EXPIRE,
556 ipv6nd_expire, ifp);
91cd7324
RM
557}
558
72c37f5f
RM
559static void
560ipv6nd_reachable(struct ra *rap, int flags)
561{
562
07b28b41
RM
563 if (rap->lifetime == 0)
564 return;
565
72c37f5f 566 if (flags & IPV6ND_REACHABLE) {
07b28b41
RM
567 if (rap->expired == 0)
568 return;
569 loginfox("%s: %s is reachable again",
570 rap->iface->name, rap->sfrom);
571 rap->expired = 0;
72c37f5f 572 } else {
07b28b41
RM
573 if (rap->expired != 0)
574 return;
575 logwarnx("%s: %s is unreachable, expiring it",
576 rap->iface->name, rap->sfrom);
577 rap->expired = 1;
72c37f5f 578 }
07b28b41
RM
579
580 rt_build(rap->iface->ctx, AF_INET6);
581 /* XXX Not really an RA */
582 script_runreason(rap->iface, "ROUTERADVERT");
72c37f5f
RM
583}
584
72c37f5f
RM
585void
586ipv6nd_neighbour(struct dhcpcd_ctx *ctx, struct in6_addr *addr, int flags)
587{
588 struct ra *rap;
589
cc9d9bf8
RM
590 if (ctx->ra_routers) {
591 TAILQ_FOREACH(rap, ctx->ra_routers, next) {
362153f5
RM
592 if (IN6_ARE_ADDR_EQUAL(&rap->from, addr)) {
593 ipv6nd_reachable(rap, flags);
594 break;
595 }
72c37f5f
RM
596 }
597 }
598}
a3ee6b23 599
edb0ed37
RM
600const struct ipv6_addr *
601ipv6nd_iffindaddr(const struct interface *ifp, const struct in6_addr *addr,
c4d7d69a 602 unsigned int flags)
edb0ed37
RM
603{
604 struct ra *rap;
605 struct ipv6_addr *ap;
606
cc9d9bf8 607 if (ifp->ctx->ra_routers == NULL)
edb0ed37
RM
608 return NULL;
609
cc9d9bf8 610 TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) {
edb0ed37
RM
611 if (rap->iface != ifp)
612 continue;
613 TAILQ_FOREACH(ap, &rap->addrs, next) {
5b1f21d1 614 if (ipv6_findaddrmatch(ap, addr, flags))
edb0ed37
RM
615 return ap;
616 }
617 }
618 return NULL;
619}
5b1f21d1 620
f3047040
RM
621struct ipv6_addr *
622ipv6nd_findaddr(struct dhcpcd_ctx *ctx, const struct in6_addr *addr,
c4d7d69a 623 unsigned int flags)
376e8b80
RM
624{
625 struct ra *rap;
626 struct ipv6_addr *ap;
627
cc9d9bf8 628 if (ctx->ra_routers == NULL)
f3047040 629 return NULL;
fe6c1b9d 630
cc9d9bf8 631 TAILQ_FOREACH(rap, ctx->ra_routers, next) {
376e8b80 632 TAILQ_FOREACH(ap, &rap->addrs, next) {
5b1f21d1 633 if (ipv6_findaddrmatch(ap, addr, flags))
f3047040 634 return ap;
376e8b80
RM
635 }
636 }
f3047040 637 return NULL;
376e8b80
RM
638}
639
2be15e88 640static void
81af2589 641ipv6nd_removefreedrop_ra(struct ra *rap, int remove_ra, int drop_ra)
eebe9a18
RM
642{
643
4eb7b489
RM
644 eloop_timeout_delete(rap->iface->ctx->eloop, NULL, rap->iface);
645 eloop_timeout_delete(rap->iface->ctx->eloop, NULL, rap);
9a593d97 646 if (remove_ra)
cc9d9bf8 647 TAILQ_REMOVE(rap->iface->ctx->ra_routers, rap, next);
81af2589 648 ipv6_freedrop_addrs(&rap->addrs, drop_ra, NULL);
eebe9a18 649 free(rap->data);
eebe9a18
RM
650 free(rap);
651}
652
f1df29d2 653static void
2be15e88
RM
654ipv6nd_freedrop_ra(struct ra *rap, int drop)
655{
656
657 ipv6nd_removefreedrop_ra(rap, 1, drop);
658}
659
eebe9a18 660ssize_t
e82129a4 661ipv6nd_free(struct interface *ifp)
eebe9a18 662{
ca15a0aa 663 struct rs_state *state;
eebe9a18 664 struct ra *rap, *ran;
4eb7b489 665 struct dhcpcd_ctx *ctx;
eebe9a18
RM
666 ssize_t n;
667
ca15a0aa 668 state = RS_STATE(ifp);
a9d78def
RM
669 if (state == NULL)
670 return 0;
671
b2edc303
RM
672 ctx = ifp->ctx;
673#ifdef __sun
674 eloop_event_delete(ctx->eloop, state->nd_fd);
675 close(state->nd_fd);
676#endif
a9d78def
RM
677 free(state->rs);
678 free(state);
679 ifp->if_data[IF_DATA_IPV6ND] = NULL;
eebe9a18 680 n = 0;
cc9d9bf8 681 TAILQ_FOREACH_SAFE(rap, ifp->ctx->ra_routers, next, ran) {
eebe9a18 682 if (rap->iface == ifp) {
e82129a4 683 ipv6nd_free_ra(rap);
eebe9a18 684 n++;
91cd7324 685 }
eebe9a18 686 }
a9d78def 687
b2edc303 688#ifndef __sun
a9d78def
RM
689 /* If we don't have any more IPv6 enabled interfaces,
690 * close the global socket and release resources */
4eb7b489 691 TAILQ_FOREACH(ifp, ctx->ifaces, next) {
a9d78def
RM
692 if (RS_STATE(ifp))
693 break;
694 }
695 if (ifp == NULL) {
cc9d9bf8
RM
696 if (ctx->nd_fd != -1) {
697 eloop_event_delete(ctx->eloop, ctx->nd_fd);
698 close(ctx->nd_fd);
699 ctx->nd_fd = -1;
a9d78def 700 }
a9d78def 701 }
b2edc303 702#endif
a9d78def 703
eebe9a18
RM
704 return n;
705}
706
707static int
708rtpref(struct ra *rap)
709{
ca15a0aa 710
eebe9a18
RM
711 switch (rap->flags & ND_RA_FLAG_RTPREF_MASK) {
712 case ND_RA_FLAG_RTPREF_HIGH:
713 return (RTPREF_HIGH);
714 case ND_RA_FLAG_RTPREF_MEDIUM:
715 case ND_RA_FLAG_RTPREF_RSV:
716 return (RTPREF_MEDIUM);
717 case ND_RA_FLAG_RTPREF_LOW:
718 return (RTPREF_LOW);
719 default:
94d1ded9 720 logerrx("rtpref: impossible RA flag %x", rap->flags);
eebe9a18
RM
721 return (RTPREF_INVALID);
722 }
723 /* NOTREACHED */
724}
725
726static void
cc9d9bf8 727add_router(struct dhcpcd_ctx *ctx, struct ra *router)
eebe9a18
RM
728{
729 struct ra *rap;
730
4eb7b489 731 TAILQ_FOREACH(rap, ctx->ra_routers, next) {
eebe9a18
RM
732 if (router->iface->metric < rap->iface->metric ||
733 (router->iface->metric == rap->iface->metric &&
734 rtpref(router) > rtpref(rap)))
735 {
736 TAILQ_INSERT_BEFORE(rap, router, next);
737 return;
91cd7324
RM
738 }
739 }
4eb7b489 740 TAILQ_INSERT_TAIL(ctx->ra_routers, router, next);
91cd7324
RM
741}
742
b5b066a5 743static int
e82129a4 744ipv6nd_scriptrun(struct ra *rap)
a8df1b28 745{
e2c4a256 746 int hasdns, hasaddress, pid;
d5690e93 747 struct ipv6_addr *ap;
a8df1b28 748
e2c4a256 749 hasaddress = 0;
a8df1b28 750 /* If all addresses have completed DAD run the script */
a8df1b28 751 TAILQ_FOREACH(ap, &rap->addrs, next) {
de67b951
RM
752 if ((ap->flags & (IPV6_AF_AUTOCONF | IPV6_AF_ADDED)) ==
753 (IPV6_AF_AUTOCONF | IPV6_AF_ADDED))
a824f281 754 {
e2c4a256 755 hasaddress = 1;
d5690e93 756 if (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
03274c9c
RM
757 ipv6_iffindaddr(ap->iface, &ap->addr,
758 IN6_IFF_TENTATIVE))
d5690e93
RM
759 ap->flags |= IPV6_AF_DADCOMPLETED;
760 if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0) {
0e56d022 761 logdebugx("%s: waiting for Router Advertisement"
d5690e93
RM
762 " DAD to complete",
763 rap->iface->name);
b5b066a5 764 return 0;
d5690e93 765 }
d8194bcd 766 }
a8df1b28
RM
767 }
768
769 /* If we don't require RDNSS then set hasdns = 1 so we fork */
770 if (!(rap->iface->options->options & DHCPCD_IPV6RA_REQRDNSS))
771 hasdns = 1;
772 else {
2be15e88 773 hasdns = rap->hasdns;
a8df1b28
RM
774 }
775
776 script_runreason(rap->iface, "ROUTERADVERT");
e2c4a256
RM
777 pid = 0;
778 if (hasdns && (hasaddress ||
779 !(rap->flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER))))
94bec972 780 pid = dhcpcd_daemonise(rap->iface->ctx);
a8df1b28
RM
781#if 0
782 else if (options & DHCPCD_DAEMONISE &&
783 !(options & DHCPCD_DAEMONISED) && new_data)
94d1ded9 784 logwarnx("%s: did not fork due to an absent"
a8df1b28
RM
785 " RDNSS option in the RA",
786 ifp->name);
787}
788#endif
e2c4a256 789 return pid;
a8df1b28
RM
790}
791
3ed12ab8
RM
792static void
793ipv6nd_addaddr(void *arg)
794{
795 struct ipv6_addr *ap = arg;
796
0b3255ac 797 ipv6_addaddr(ap, NULL);
3ed12ab8
RM
798}
799
a0011b99
RM
800int
801ipv6nd_dadcompleted(const struct interface *ifp)
802{
803 const struct ra *rap;
804 const struct ipv6_addr *ap;
805
cc9d9bf8 806 TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) {
a0011b99
RM
807 if (rap->iface != ifp)
808 continue;
809 TAILQ_FOREACH(ap, &rap->addrs, next) {
810 if (ap->flags & IPV6_AF_AUTOCONF &&
de67b951 811 ap->flags & IPV6_AF_ADDED &&
a0011b99 812 !(ap->flags & IPV6_AF_DADCOMPLETED))
de67b951 813 return 0;
a0011b99
RM
814 }
815 }
816 return 1;
817}
818
d8194bcd 819static void
e82129a4 820ipv6nd_dadcallback(void *arg)
d8194bcd 821{
65ae27ee 822 struct ipv6_addr *ia = arg, *rapap;
d8194bcd
RM
823 struct interface *ifp;
824 struct ra *rap;
825 int wascompleted, found;
573d0487 826 struct timespec tv;
3ed12ab8
RM
827 char buf[INET6_ADDRSTRLEN];
828 const char *p;
4f5b9dd2 829 int dadcounter;
d8194bcd 830
65ae27ee
RM
831 ifp = ia->iface;
832 wascompleted = (ia->flags & IPV6_AF_DADCOMPLETED);
833 ia->flags |= IPV6_AF_DADCOMPLETED;
834 if (ia->flags & IPV6_AF_DUPLICATED) {
835 ia->dadcounter++;
836 logwarnx("%s: DAD detected %s", ifp->name, ia->saddr);
d8194bcd 837
3ed12ab8
RM
838 /* Try and make another stable private address.
839 * Because ap->dadcounter is always increamented,
840 * a different address is generated. */
841 /* XXX Cache DAD counter per prefix/id/ssid? */
fd89860f 842 if (ifp->options->options & DHCPCD_SLAACPRIVATE) {
65ae27ee 843 if (ia->dadcounter >= IDGEN_RETRIES) {
94d1ded9 844 logerrx("%s: unable to obtain a"
fd89860f
RM
845 " stable private address",
846 ifp->name);
847 goto try_script;
848 }
9efdc92f 849 loginfox("%s: deleting address %s",
65ae27ee
RM
850 ifp->name, ia->saddr);
851 if (if_address6(RTM_DELADDR, ia) == -1 &&
3ed12ab8 852 errno != EADDRNOTAVAIL && errno != ENXIO)
94d1ded9 853 logerr(__func__);
65ae27ee
RM
854 dadcounter = ia->dadcounter;
855 if (ipv6_makestableprivate(&ia->addr,
856 &ia->prefix, ia->prefix_len,
4f5b9dd2 857 ifp, &dadcounter) == -1)
3ed12ab8 858 {
94d1ded9 859 logerr("ipv6_makestableprivate");
3ed12ab8
RM
860 return;
861 }
65ae27ee
RM
862 ia->dadcounter = dadcounter;
863 ia->flags &= ~(IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED);
864 ia->flags |= IPV6_AF_NEW;
865 p = inet_ntop(AF_INET6, &ia->addr, buf, sizeof(buf));
3ed12ab8 866 if (p)
65ae27ee
RM
867 snprintf(ia->saddr,
868 sizeof(ia->saddr),
3ed12ab8 869 "%s/%d",
65ae27ee 870 p, ia->prefix_len);
3ed12ab8 871 else
65ae27ee 872 ia->saddr[0] = '\0';
3ed12ab8 873 tv.tv_sec = 0;
573d0487
RM
874 tv.tv_nsec = (suseconds_t)
875 arc4random_uniform(IDGEN_DELAY * NSEC_PER_SEC);
876 timespecnorm(&tv);
3ed12ab8 877 eloop_timeout_add_tv(ifp->ctx->eloop, &tv,
65ae27ee 878 ipv6nd_addaddr, ia);
3ed12ab8
RM
879 return;
880 }
881 }
d8194bcd 882
fd89860f 883try_script:
3ed12ab8 884 if (!wascompleted) {
cc9d9bf8 885 TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) {
d8194bcd
RM
886 if (rap->iface != ifp)
887 continue;
888 wascompleted = 1;
e92ca600 889 found = 0;
d8194bcd 890 TAILQ_FOREACH(rapap, &rap->addrs, next) {
a824f281 891 if (rapap->flags & IPV6_AF_AUTOCONF &&
de67b951 892 rapap->flags & IPV6_AF_ADDED &&
a824f281
RM
893 (rapap->flags & IPV6_AF_DADCOMPLETED) == 0)
894 {
d8194bcd
RM
895 wascompleted = 0;
896 break;
897 }
65ae27ee 898 if (rapap == ia)
d8194bcd
RM
899 found = 1;
900 }
901
4f422dd3 902 if (wascompleted && found) {
0e56d022 903 logdebugx("%s: Router Advertisement DAD "
94d1ded9 904 "completed",
d8194bcd 905 rap->iface->name);
b5b066a5
RM
906 if (ipv6nd_scriptrun(rap))
907 return;
d8194bcd
RM
908 }
909 }
cd09e583 910 ipv6nd_advertise(ia);
d8194bcd
RM
911 }
912}
913
6a765a4f
RM
914#ifndef DHCP6
915/* If DHCPv6 is compiled out, supply a shim to provide an error message
916 * if IPv6RA requests DHCPv6. */
a1b1f0a8
RM
917enum DH6S {
918 DH6S_REQUEST,
919 DH6S_INFORM,
920};
6a765a4f
RM
921static int
922dhcp6_start(__unused struct interface *ifp, __unused enum DH6S init_state)
923{
924
925 errno = ENOTSUP;
926 return -1;
927}
928#endif
929
aae24feb 930static void
5fed9d43
RM
931ipv6nd_handlera(struct dhcpcd_ctx *ctx,
932 const struct sockaddr_in6 *from, const char *sfrom,
933 struct interface *ifp, struct icmp6_hdr *icp, size_t len, int hoplimit)
91cd7324 934{
2be15e88 935 size_t i, olen;
7be4b9b3 936 struct nd_router_advert *nd_ra;
55a59017
RM
937 struct nd_opt_hdr ndo;
938 struct nd_opt_prefix_info pi;
939 struct nd_opt_mtu mtu;
940 struct nd_opt_rdnss rdnss;
2be15e88 941 uint8_t *p;
91cd7324 942 struct ra *rap;
7878d124 943 struct in6_addr pi_prefix;
eebe9a18 944 struct ipv6_addr *ap;
2be15e88 945 struct dhcp_opt *dho;
2aca3a18 946 bool new_rap, new_data;
c15437c1 947 uint32_t old_lifetime;
94d1ded9 948 __printflike(1, 2) void (*logfunc)(const char *, ...);
727cd92a
RM
949#ifdef IPV6_MANAGETEMPADDR
950 uint8_t new_ap;
951#endif
91cd7324 952
a708c891
RM
953 if (ifp == NULL) {
954#ifdef DEBUG_RS
5fed9d43 955 logdebugx("RA for unexpected interface from %s", sfrom);
a708c891
RM
956#endif
957 return;
958 }
959
34457fe6 960 if (len < sizeof(struct nd_router_advert)) {
5fed9d43 961 logerrx("IPv6 RA packet too short from %s", sfrom);
91cd7324
RM
962 return;
963 }
964
a708c891
RM
965 /* RFC 4861 7.1.2 */
966 if (hoplimit != 255) {
5fed9d43 967 logerrx("invalid hoplimit(%d) in RA from %s", hoplimit, sfrom);
91cd7324
RM
968 return;
969 }
5fed9d43
RM
970 if (!IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr)) {
971 logerrx("RA from non local address %s", sfrom);
4c6a8bec
RM
972 return;
973 }
a708c891 974
4c6a8bec
RM
975 if (!(ifp->options->options & DHCPCD_IPV6RS)) {
976#ifdef DEBUG_RS
5fed9d43 977 logerrx("%s: unexpected RA from %s", ifp->name, sfrom);
d7555c12 978#endif
91cd7324
RM
979 return;
980 }
0e906716 981
e7a30a46 982 /* We could receive a RA before we sent a RS*/
0e906716
RM
983 if (ipv6_linklocal(ifp) == NULL) {
984#ifdef DEBUG_RS
0e56d022 985 logdebugx("%s: received RA from %s (no link-local)",
5fed9d43 986 ifp->name, sfrom);
0e906716
RM
987#endif
988 return;
989 }
990
5fed9d43 991 if (ipv6_iffindaddr(ifp, &from->sin6_addr, IN6_IFF_TENTATIVE)) {
0e56d022 992 logdebugx("%s: ignoring RA from ourself %s",
5fed9d43 993 ifp->name, sfrom);
29211f25
RM
994 return;
995 }
996
4eb7b489 997 TAILQ_FOREACH(rap, ctx->ra_routers, next) {
fe292175 998 if (ifp == rap->iface &&
5fed9d43 999 IN6_ARE_ADDR_EQUAL(&rap->from, &from->sin6_addr))
91cd7324
RM
1000 break;
1001 }
46caaa5e 1002
e42bbc9b 1003 nd_ra = (struct nd_router_advert *)icp;
e42bbc9b 1004
46caaa5e
RM
1005 /* We don't want to spam the log with the fact we got an RA every
1006 * 30 seconds or so, so only spam the log if it's different. */
ee70f4ab 1007 if (rap == NULL || (rap->data_len != len ||
46caaa5e
RM
1008 memcmp(rap->data, (unsigned char *)icp, rap->data_len) != 0))
1009 {
1010 if (rap) {
1011 free(rap->data);
1012 rap->data_len = 0;
1013 }
2aca3a18 1014 new_data = true;
d7555c12 1015 } else
2aca3a18 1016 new_data = false;
91cd7324 1017 if (rap == NULL) {
10e17e3f
RM
1018 rap = calloc(1, sizeof(*rap));
1019 if (rap == NULL) {
94d1ded9 1020 logerr(__func__);
10e17e3f
RM
1021 return;
1022 }
eebe9a18 1023 rap->iface = ifp;
5fed9d43
RM
1024 rap->from = from->sin6_addr;
1025 strlcpy(rap->sfrom, sfrom, sizeof(rap->sfrom));
eebe9a18 1026 TAILQ_INIT(&rap->addrs);
2aca3a18 1027 new_rap = true;
eebe9a18 1028 } else
2aca3a18 1029 new_rap = false;
46caaa5e 1030 if (rap->data_len == 0) {
28382337
RM
1031 rap->data = malloc(len);
1032 if (rap->data == NULL) {
94d1ded9 1033 logerr(__func__);
28382337
RM
1034 if (new_rap)
1035 free(rap);
1036 return;
1037 }
46caaa5e
RM
1038 memcpy(rap->data, icp, len);
1039 rap->data_len = len;
91cd7324
RM
1040 }
1041
19e75b95
RM
1042 /* We could change the debug level based on new_data, but some
1043 * routers like to decrease the advertised valid and preferred times
1044 * in accordance with the own prefix times which would result in too
1045 * much needless log spam. */
9efdc92f 1046 logfunc = new_rap ? loginfox : logdebugx,
5fed9d43 1047 logfunc("%s: Router Advertisement from %s", ifp->name, rap->sfrom);
19e75b95 1048
f5c3ca19 1049 clock_gettime(CLOCK_MONOTONIC, &rap->acquired);
eebe9a18 1050 rap->flags = nd_ra->nd_ra_flags_reserved;
c15437c1 1051 old_lifetime = rap->lifetime;
7be4b9b3 1052 rap->lifetime = ntohs(nd_ra->nd_ra_router_lifetime);
c15437c1
RM
1053 if (!new_rap && rap->lifetime == 0 && old_lifetime != 0)
1054 logwarnx("%s: %s: no longer a default router",
1055 ifp->name, rap->sfrom);
ea112ab2
RM
1056 if (nd_ra->nd_ra_reachable) {
1057 rap->reachable = ntohl(nd_ra->nd_ra_reachable);
1058 if (rap->reachable > MAX_REACHABLE_TIME)
1059 rap->reachable = 0;
1060 }
cd09e583
RM
1061 if (nd_ra->nd_ra_retransmit) {
1062 struct rs_state *state = RS_STATE(ifp);
1063
1064 state->retrans = rap->retrans = ntohl(nd_ra->nd_ra_retransmit);
1065 }
b88df421
RM
1066 if (rap->lifetime)
1067 rap->expired = 0;
2be15e88 1068 rap->hasdns = 0;
91cd7324 1069
b4c49a9f 1070#ifdef IPV6_AF_TEMPORARY
a15bffa6 1071 ipv6_markaddrsstale(ifp, IPV6_AF_TEMPORARY);
b4c49a9f 1072#endif
9adc479c
RM
1073 TAILQ_FOREACH(ap, &rap->addrs, next) {
1074 ap->flags |= IPV6_AF_STALE;
1075 }
1076
91cd7324
RM
1077 len -= sizeof(struct nd_router_advert);
1078 p = ((uint8_t *)icp) + sizeof(struct nd_router_advert);
8fc52ced 1079 for (; len > 0; p += olen, len -= olen) {
55a59017 1080 if (len < sizeof(ndo)) {
94d1ded9 1081 logerrx("%s: short option", ifp->name);
91cd7324
RM
1082 break;
1083 }
55a59017
RM
1084 memcpy(&ndo, p, sizeof(ndo));
1085 olen = (size_t)ndo.nd_opt_len * 8;
91cd7324 1086 if (olen == 0) {
94d1ded9 1087 logerrx("%s: zero length option", ifp->name);
91cd7324
RM
1088 break;
1089 }
1090 if (olen > len) {
94d1ded9 1091 logerrx("%s: option length exceeds message",
03274c9c 1092 ifp->name);
91cd7324
RM
1093 break;
1094 }
1095
2be15e88 1096 if (has_option_mask(ifp->options->rejectmasknd,
55a59017 1097 ndo.nd_opt_type))
2be15e88 1098 {
cc9d9bf8
RM
1099 for (i = 0, dho = ctx->nd_opts;
1100 i < ctx->nd_opts_len;
2be15e88
RM
1101 i++, dho++)
1102 {
55a59017 1103 if (dho->option == ndo.nd_opt_type)
2be15e88
RM
1104 break;
1105 }
a708c891 1106 if (dho != NULL)
94d1ded9 1107 logwarnx("%s: reject RA (option %s) from %s",
5fed9d43 1108 ifp->name, dho->var, rap->sfrom);
2be15e88 1109 else
94d1ded9 1110 logwarnx("%s: reject RA (option %d) from %s",
5fed9d43 1111 ifp->name, ndo.nd_opt_type, rap->sfrom);
2be15e88
RM
1112 if (new_rap)
1113 ipv6nd_removefreedrop_ra(rap, 0, 0);
1114 else
1115 ipv6nd_free_ra(rap);
1116 return;
1117 }
1118
55a59017 1119 if (has_option_mask(ifp->options->nomasknd, ndo.nd_opt_type))
2be15e88
RM
1120 continue;
1121
55a59017 1122 switch (ndo.nd_opt_type) {
91cd7324 1123 case ND_OPT_PREFIX_INFORMATION:
0e56d022 1124 logfunc = new_data ? logerrx : logdebugx;
55a59017 1125 if (ndo.nd_opt_len != 4) {
94d1ded9 1126 logfunc("%s: invalid option len for prefix",
91cd7324 1127 ifp->name);
c448a53a 1128 continue;
91cd7324 1129 }
55a59017
RM
1130 memcpy(&pi, p, sizeof(pi));
1131 if (pi.nd_opt_pi_prefix_len > 128) {
94d1ded9 1132 logfunc("%s: invalid prefix len", ifp->name);
c448a53a 1133 continue;
91cd7324 1134 }
7878d124 1135 /* nd_opt_pi_prefix is not aligned. */
03274c9c
RM
1136 memcpy(&pi_prefix, &pi.nd_opt_pi_prefix,
1137 sizeof(pi_prefix));
7878d124
RM
1138 if (IN6_IS_ADDR_MULTICAST(&pi_prefix) ||
1139 IN6_IS_ADDR_LINKLOCAL(&pi_prefix))
91cd7324 1140 {
94d1ded9 1141 logfunc("%s: invalid prefix in RA", ifp->name);
c448a53a 1142 continue;
91cd7324 1143 }
55a59017
RM
1144 if (ntohl(pi.nd_opt_pi_preferred_time) >
1145 ntohl(pi.nd_opt_pi_valid_time))
e54dee19 1146 {
94d1ded9 1147 logfunc("%s: pltime > vltime", ifp->name);
c448a53a 1148 continue;
e54dee19 1149 }
eebe9a18 1150 TAILQ_FOREACH(ap, &rap->addrs, next)
55a59017 1151 if (ap->prefix_len ==pi.nd_opt_pi_prefix_len &&
7878d124 1152 IN6_ARE_ADDR_EQUAL(&ap->prefix, &pi_prefix))
eebe9a18
RM
1153 break;
1154 if (ap == NULL) {
c4d7d69a 1155 unsigned int flags;
61564d34 1156
61564d34 1157 flags = IPV6_AF_RAPFX;
55a59017 1158 if (pi.nd_opt_pi_flags_reserved &
62f12387 1159 ND_OPT_PI_FLAG_AUTO &&
61564d34 1160 rap->iface->options->options &
62f12387 1161 DHCPCD_IPV6RA_AUTOCONF)
61564d34
RM
1162 flags |= IPV6_AF_AUTOCONF;
1163
1164 ap = ipv6_newaddr(rap->iface,
1165 &pi_prefix, pi.nd_opt_pi_prefix_len, flags);
1166 if (ap == NULL)
1167 break;
1168 ap->prefix = pi_prefix;
d292d54e
RM
1169 if (flags & IPV6_AF_AUTOCONF)
1170 ap->dadcallback = ipv6nd_dadcallback;
f5c3ca19 1171 ap->created = ap->acquired = rap->acquired;
eebe9a18 1172 TAILQ_INSERT_TAIL(&rap->addrs, ap, next);
a1f7b32c 1173
727cd92a 1174#ifdef IPV6_MANAGETEMPADDR
a1f7b32c
RM
1175 /* New address to dhcpcd RA handling.
1176 * If the address already exists and a valid
1177 * temporary address also exists then
1178 * extend the existing one rather than
1179 * create a new one */
d292d54e
RM
1180 if (flags & IPV6_AF_AUTOCONF &&
1181 ipv6_iffindaddr(ifp, &ap->addr,
5119f4f3 1182 IN6_IFF_NOTUSEABLE) &&
a1f7b32c
RM
1183 ipv6_settemptime(ap, 0))
1184 new_ap = 0;
1185 else
1186 new_ap = 1;
727cd92a 1187#endif
a1f7b32c 1188 } else {
727cd92a 1189#ifdef IPV6_MANAGETEMPADDR
a1f7b32c 1190 new_ap = 0;
727cd92a 1191#endif
9adc479c 1192 ap->flags &= ~IPV6_AF_STALE;
f5c3ca19 1193 ap->acquired = rap->acquired;
a1f7b32c 1194 }
55a59017 1195 if (pi.nd_opt_pi_flags_reserved &
cd3612e5 1196 ND_OPT_PI_FLAG_ONLINK)
46b8a6b7 1197 ap->flags |= IPV6_AF_ONLINK;
eebe9a18 1198 ap->prefix_vltime =
55a59017 1199 ntohl(pi.nd_opt_pi_valid_time);
eebe9a18 1200 ap->prefix_pltime =
55a59017 1201 ntohl(pi.nd_opt_pi_preferred_time);
a1f7b32c 1202
727cd92a 1203#ifdef IPV6_MANAGETEMPADDR
a1f7b32c
RM
1204 /* RFC4941 Section 3.3.3 */
1205 if (ap->flags & IPV6_AF_AUTOCONF &&
a1f7b32c
RM
1206 ip6_use_tempaddr(ap->iface->name))
1207 {
1208 if (!new_ap) {
1209 if (ipv6_settemptime(ap, 1) == NULL)
1210 new_ap = 1;
1211 }
1212 if (new_ap && ap->prefix_pltime) {
1213 if (ipv6_createtempaddr(ap,
1214 &ap->acquired) == NULL)
94d1ded9 1215 logerr("ipv6_createtempaddr");
a1f7b32c
RM
1216 }
1217 }
727cd92a 1218#endif
91cd7324
RM
1219 break;
1220
1221 case ND_OPT_MTU:
19005560
RM
1222 if (len < sizeof(mtu)) {
1223 logerrx("%s: short MTU option", ifp->name);
1224 break;
1225 }
55a59017
RM
1226 memcpy(&mtu, p, sizeof(mtu));
1227 mtu.nd_opt_mtu_mtu = ntohl(mtu.nd_opt_mtu_mtu);
1228 if (mtu.nd_opt_mtu_mtu < IPV6_MMTU) {
94d1ded9 1229 logerrx("%s: invalid MTU %d",
55a59017 1230 ifp->name, mtu.nd_opt_mtu_mtu);
eebe9a18
RM
1231 break;
1232 }
55a59017 1233 rap->mtu = mtu.nd_opt_mtu_mtu;
91cd7324
RM
1234 break;
1235
1236 case ND_OPT_RDNSS:
19005560
RM
1237 if (len < sizeof(rdnss)) {
1238 logerrx("%s: short RDNSS option", ifp->name);
1239 break;
1240 }
55a59017
RM
1241 memcpy(&rdnss, p, sizeof(rdnss));
1242 if (rdnss.nd_opt_rdnss_lifetime &&
1243 rdnss.nd_opt_rdnss_len > 1)
2be15e88 1244 rap->hasdns = 1;
55a59017 1245 break;
17b0dbad
RM
1246 default:
1247 continue;
91cd7324 1248 }
2be15e88 1249 }
91cd7324 1250
cc9d9bf8
RM
1251 for (i = 0, dho = ctx->nd_opts;
1252 i < ctx->nd_opts_len;
2be15e88
RM
1253 i++, dho++)
1254 {
1255 if (has_option_mask(ifp->options->requiremasknd,
1256 dho->option))
1257 {
94d1ded9 1258 logwarnx("%s: reject RA (no option %s) from %s",
5fed9d43 1259 ifp->name, dho->var, rap->sfrom);
2be15e88
RM
1260 if (new_rap)
1261 ipv6nd_removefreedrop_ra(rap, 0, 0);
1262 else
1263 ipv6nd_free_ra(rap);
1264 return;
fd3e7f65 1265 }
91cd7324
RM
1266 }
1267
eebe9a18 1268 if (new_rap)
cc9d9bf8 1269 add_router(ifp->ctx, rap);
2be15e88 1270
4eb7b489 1271 if (ifp->ctx->options & DHCPCD_TEST) {
294eff4d 1272 script_runreason(ifp, "TEST");
d7555c12 1273 goto handle_flag;
b88df421 1274 }
7529fdf1 1275 ipv6_addaddrs(&rap->addrs);
727cd92a 1276#ifdef IPV6_MANAGETEMPADDR
f5c3ca19 1277 ipv6_addtempaddrs(ifp, &rap->acquired);
727cd92a 1278#endif
a19fe492 1279
9aa11487 1280 rt_build(ifp->ctx, AF_INET6);
4f422dd3
RM
1281 if (ipv6nd_scriptrun(rap))
1282 return;
61dd6cf9 1283
4eb7b489
RM
1284 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
1285 eloop_timeout_delete(ifp->ctx->eloop, NULL, rap); /* reachable timer */
eebe9a18 1286
d7555c12 1287handle_flag:
f6794c78
RM
1288 if (!(ifp->options->options & DHCPCD_DHCP6))
1289 goto nodhcp6;
6a765a4f
RM
1290/* Only log a DHCPv6 start error if compiled in or debugging is enabled. */
1291#ifdef DHCP6
94d1ded9 1292#define LOG_DHCP6 logerr
6a765a4f 1293#else
94d1ded9 1294#define LOG_DHCP6 logdebug
6a765a4f 1295#endif
d7555c12 1296 if (rap->flags & ND_RA_FLAG_MANAGED) {
385479d2 1297 if (new_data && dhcp6_start(ifp, DH6S_REQUEST) == -1)
94d1ded9 1298 LOG_DHCP6("dhcp6_start: %s", ifp->name);
d7555c12 1299 } else if (rap->flags & ND_RA_FLAG_OTHER) {
4f422dd3 1300 if (new_data && dhcp6_start(ifp, DH6S_INFORM) == -1)
94d1ded9 1301 LOG_DHCP6("dhcp6_start: %s", ifp->name);
d7555c12 1302 } else {
a1b1f0a8 1303#ifdef DHCP6
4f422dd3 1304 if (new_data)
0e56d022 1305 logdebugx("%s: No DHCPv6 instruction in RA", ifp->name);
a1b1f0a8 1306#endif
f6794c78 1307nodhcp6:
4eb7b489
RM
1308 if (ifp->ctx->options & DHCPCD_TEST) {
1309 eloop_exit(ifp->ctx->eloop, EXIT_SUCCESS);
a9d78def
RM
1310 return;
1311 }
d7555c12 1312 }
35308011
RM
1313
1314 /* Expire should be called last as the rap object could be destroyed */
e82129a4 1315 ipv6nd_expirera(ifp);
eebe9a18
RM
1316}
1317
1318int
047235d7 1319ipv6nd_hasra(const struct interface *ifp)
eebe9a18
RM
1320{
1321 const struct ra *rap;
1322
cc9d9bf8
RM
1323 if (ifp->ctx->ra_routers) {
1324 TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next)
047235d7 1325 if (rap->iface == ifp && !rap->expired)
2433e54d
RM
1326 return 1;
1327 }
eebe9a18 1328 return 0;
91cd7324
RM
1329}
1330
047235d7
RM
1331int
1332ipv6nd_hasradhcp(const struct interface *ifp)
1333{
1334 const struct ra *rap;
1335
cc9d9bf8
RM
1336 if (ifp->ctx->ra_routers) {
1337 TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) {
047235d7
RM
1338 if (rap->iface == ifp &&
1339 !rap->expired &&
1340 (rap->flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)))
1341 return 1;
1342 }
1343 }
1344 return 0;
1345}
1346
2be15e88
RM
1347static const uint8_t *
1348ipv6nd_getoption(struct dhcpcd_ctx *ctx,
1349 size_t *os, unsigned int *code, size_t *len,
1350 const uint8_t *od, size_t ol, struct dhcp_opt **oopt)
1351{
55a59017 1352 struct nd_opt_hdr ndo;
2be15e88
RM
1353 size_t i;
1354 struct dhcp_opt *opt;
1355
1356 if (od) {
55a59017 1357 *os = sizeof(ndo);
2be15e88
RM
1358 if (ol < *os) {
1359 errno = EINVAL;
1360 return NULL;
1361 }
55a59017 1362 memcpy(&ndo, od, sizeof(ndo));
81e9fc13 1363 i = (size_t)(ndo.nd_opt_len * 8);
55a59017 1364 if (i > ol) {
2be15e88
RM
1365 errno = EINVAL;
1366 return NULL;
1367 }
55a59017
RM
1368 *len = i;
1369 *code = ndo.nd_opt_type;
1370 }
2be15e88
RM
1371
1372 for (i = 0, opt = ctx->nd_opts;
1373 i < ctx->nd_opts_len; i++, opt++)
1374 {
1375 if (opt->option == *code) {
1376 *oopt = opt;
1377 break;
1378 }
1379 }
1380
55a59017
RM
1381 if (od)
1382 return od + sizeof(ndo);
2be15e88
RM
1383 return NULL;
1384}
1385
91cd7324 1386ssize_t
e82129a4 1387ipv6nd_env(char **env, const char *prefix, const struct interface *ifp)
91cd7324 1388{
55a59017 1389 size_t i, j, n, len, olen;
2be15e88
RM
1390 struct ra *rap;
1391 char ndprefix[32], abuf[24];
1392 struct dhcp_opt *opt;
55a59017
RM
1393 uint8_t *p;
1394 struct nd_opt_hdr ndo;
2be15e88 1395 struct ipv6_addr *ia;
f5c3ca19 1396 struct timespec now;
eebe9a18 1397
f5c3ca19 1398 clock_gettime(CLOCK_MONOTONIC, &now);
2be15e88 1399 i = n = 0;
cc9d9bf8 1400 TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) {
eebe9a18
RM
1401 if (rap->iface != ifp)
1402 continue;
0d593c43 1403 i++;
2be15e88
RM
1404 if (prefix != NULL)
1405 snprintf(ndprefix, sizeof(ndprefix),
1406 "%s_nd%zu", prefix, i);
1407 else
1408 snprintf(ndprefix, sizeof(ndprefix),
1409 "nd%zu", i);
1410 if (env)
03274c9c 1411 setvar(&env[n], ndprefix, "from", rap->sfrom);
2be15e88 1412 n++;
f5c3ca19 1413 if (env)
03274c9c
RM
1414 setvard(&env[n], ndprefix, "acquired",
1415 (size_t)rap->acquired.tv_sec);
f5c3ca19
RM
1416 n++;
1417 if (env)
03274c9c 1418 setvard(&env[n], ndprefix, "now", (size_t)now.tv_sec);
f5c3ca19 1419 n++;
2be15e88
RM
1420
1421 /* Zero our indexes */
91cd7324 1422 if (env) {
2be15e88
RM
1423 for (j = 0, opt = rap->iface->ctx->nd_opts;
1424 j < rap->iface->ctx->nd_opts_len;
1425 j++, opt++)
1426 dhcp_zero_index(opt);
1427 for (j = 0, opt = rap->iface->options->nd_override;
1428 j < rap->iface->options->nd_override_len;
1429 j++, opt++)
1430 dhcp_zero_index(opt);
91cd7324 1431 }
449df9c8 1432
2be15e88
RM
1433 /* Unlike DHCP, ND6 options *may* occur more than once.
1434 * There is also no provision for option concatenation
1435 * unlike DHCP. */
55a59017
RM
1436 len = rap->data_len - sizeof(struct nd_router_advert);
1437 for (p = rap->data + sizeof(struct nd_router_advert);
1438 len >= sizeof(ndo);
1439 p += olen, len -= olen)
2be15e88 1440 {
55a59017 1441 memcpy(&ndo, p, sizeof(ndo));
81e9fc13 1442 olen = (size_t)(ndo.nd_opt_len * 8);
55a59017 1443 if (olen > len) {
2be15e88 1444 errno = EINVAL;
91cd7324 1445 break;
91cd7324 1446 }
2be15e88 1447 if (has_option_mask(rap->iface->options->nomasknd,
55a59017 1448 ndo.nd_opt_type))
28382337 1449 continue;
2be15e88
RM
1450 for (j = 0, opt = rap->iface->options->nd_override;
1451 j < rap->iface->options->nd_override_len;
1452 j++, opt++)
55a59017 1453 if (opt->option == ndo.nd_opt_type)
2be15e88
RM
1454 break;
1455 if (j == rap->iface->options->nd_override_len) {
1456 for (j = 0, opt = rap->iface->ctx->nd_opts;
1457 j < rap->iface->ctx->nd_opts_len;
1458 j++, opt++)
55a59017 1459 if (opt->option == ndo.nd_opt_type)
2be15e88
RM
1460 break;
1461 if (j == rap->iface->ctx->nd_opts_len)
1462 opt = NULL;
1463 }
1464 if (opt) {
1465 n += dhcp_envoption(rap->iface->ctx,
1466 env == NULL ? NULL : &env[n],
1467 ndprefix, rap->iface->name,
1468 opt, ipv6nd_getoption,
55a59017 1469 p + sizeof(ndo), olen - sizeof(ndo));
d4e41f4b 1470 }
2be15e88
RM
1471 }
1472
1473 /* We need to output the addresses we actually made
1474 * from the prefix information options as well. */
1475 j = 0;
1476 TAILQ_FOREACH(ia, &rap->addrs, next) {
19005560 1477 if (!(ia->flags & IPV6_AF_AUTOCONF) ||
f5c3ca19 1478#ifdef IPV6_AF_TEMPORARY
19005560 1479 ia->flags & IPV6_AF_TEMPORARY ||
f5c3ca19 1480#endif
19005560
RM
1481 !(ia->flags & IPV6_AF_ADDED) ||
1482 ia->prefix_vltime == 0)
2be15e88
RM
1483 continue;
1484 j++;
d4e41f4b 1485 if (env) {
2be15e88 1486 snprintf(abuf, sizeof(abuf), "addr%zu", j);
03274c9c 1487 setvar(&env[n], ndprefix, abuf, ia->saddr);
d4e41f4b 1488 }
2be15e88 1489 n++;
91cd7324
RM
1490 }
1491 }
2be15e88 1492 return (ssize_t)n;
91cd7324
RM
1493}
1494
a8df1b28 1495void
90149620 1496ipv6nd_handleifa(int cmd, struct ipv6_addr *addr, pid_t pid)
a8df1b28
RM
1497{
1498 struct ra *rap;
a8df1b28 1499
d3826f33
RM
1500 /* IPv6 init may not have happened yet if we are learning
1501 * existing addresses when dhcpcd starts. */
cc9d9bf8 1502 if (addr->iface->ctx->ra_routers == NULL)
d3826f33
RM
1503 return;
1504
cc9d9bf8 1505 TAILQ_FOREACH(rap, addr->iface->ctx->ra_routers, next) {
e83c4813 1506 if (rap->iface != addr->iface)
a8df1b28 1507 continue;
90149620 1508 ipv6_handleifa_addrs(cmd, &rap->addrs, addr, pid);
a8df1b28
RM
1509 }
1510}
1511
91cd7324 1512void
e82129a4 1513ipv6nd_expirera(void *arg)
91cd7324
RM
1514{
1515 struct interface *ifp;
eebe9a18 1516 struct ra *rap, *ran;
573d0487 1517 struct timespec now, lt, expire, next;
a1b1f0a8 1518 bool expired, valid, validone;
6d189cb6 1519 struct ipv6_addr *ia;
19005560
RM
1520 size_t len, olen;
1521 uint8_t *p;
1522 struct nd_opt_hdr ndo;
1523#if 0
1524 struct nd_opt_prefix_info pi;
a1b1f0a8 1525#endif
19005560
RM
1526 struct nd_opt_dnssl dnssl;
1527 struct nd_opt_rdnss rdnss;
1528 uint32_t ltime;
1529 size_t nexpired = 0;
91cd7324
RM
1530
1531 ifp = arg;
b3f1735b 1532 clock_gettime(CLOCK_MONOTONIC, &now);
a1b1f0a8 1533 expired = false;
573d0487 1534 timespecclear(&next);
91cd7324 1535
cc9d9bf8 1536 TAILQ_FOREACH_SAFE(rap, ifp->ctx->ra_routers, next, ran) {
eebe9a18
RM
1537 if (rap->iface != ifp)
1538 continue;
a1b1f0a8 1539 valid = validone = false;
4f422dd3 1540 if (rap->lifetime) {
717bc86c 1541 lt.tv_sec = (time_t)rap->lifetime;
573d0487 1542 lt.tv_nsec = 0;
f5c3ca19 1543 timespecadd(&rap->acquired, &lt, &expire);
19005560 1544 if (timespeccmp(&now, &expire, >)) {
4f422dd3 1545 if (!rap->expired) {
94d1ded9 1546 logwarnx("%s: %s: router expired",
4f422dd3
RM
1547 ifp->name, rap->sfrom);
1548 rap->expired = expired = 1;
2f53bfd4 1549 rap->lifetime = 0;
4f422dd3
RM
1550 }
1551 } else {
a1b1f0a8 1552 valid = true;
573d0487
RM
1553 timespecsub(&expire, &now, &lt);
1554 if (!timespecisset(&next) ||
1555 timespeccmp(&next, &lt, >))
4f422dd3 1556 next = lt;
35308011 1557 }
35308011
RM
1558 }
1559
6d189cb6
RM
1560 /* Not every prefix is tied to an address which
1561 * the kernel can expire, so we need to handle it ourself.
1562 * Also, some OS don't support address lifetimes (Solaris). */
1563 TAILQ_FOREACH(ia, &rap->addrs, next) {
680ed015 1564 if (ia->prefix_vltime == 0)
6d189cb6 1565 continue;
680ed015 1566 if (ia->prefix_vltime == ND6_INFINITE_LIFETIME) {
a1b1f0a8 1567 validone = true;
680ed015
RM
1568 continue;
1569 }
6d189cb6
RM
1570 lt.tv_sec = (time_t)ia->prefix_vltime;
1571 lt.tv_nsec = 0;
1572 timespecadd(&ia->acquired, &lt, &expire);
1573 if (timespeccmp(&now, &expire, >)) {
1574 if (ia->flags & IPV6_AF_ADDED) {
94d1ded9 1575 logwarnx("%s: expired address %s",
6d189cb6
RM
1576 ia->iface->name, ia->saddr);
1577 if (if_address6(RTM_DELADDR, ia)== -1 &&
1578 errno != EADDRNOTAVAIL &&
1579 errno != ENXIO)
94d1ded9 1580 logerr(__func__);
6d189cb6
RM
1581 }
1582 ia->prefix_vltime = ia->prefix_pltime = 0;
1583 ia->flags &=
1584 ~(IPV6_AF_ADDED | IPV6_AF_DADCOMPLETED);
a1b1f0a8 1585 expired = true;
6d189cb6
RM
1586 } else {
1587 timespecsub(&expire, &now, &lt);
1588 if (!timespecisset(&next) ||
1589 timespeccmp(&next, &lt, >))
1590 next = lt;
a1b1f0a8 1591 validone = true;
6d189cb6
RM
1592 }
1593 }
1594
19005560
RM
1595 /* Work out expiry for ND options */
1596 len = rap->data_len - sizeof(struct nd_router_advert);
1597 for (p = rap->data + sizeof(struct nd_router_advert);
1598 len >= sizeof(ndo);
1599 p += olen, len -= olen)
1600 {
1601 memcpy(&ndo, p, sizeof(ndo));
1602 olen = (size_t)(ndo.nd_opt_len * 8);
1603 if (olen > len) {
1604 errno = EINVAL;
1605 break;
1606 }
d4e41f4b 1607
19005560
RM
1608 if (has_option_mask(rap->iface->options->nomasknd,
1609 ndo.nd_opt_type))
1610 continue;
1611
1612 switch (ndo.nd_opt_type) {
1613 /* Prefix info is already checked in the above loop. */
1614#if 0
1615 case ND_OPT_PREFIX_INFORMATION:
1616 if (len < sizeof(pi))
1617 break;
1618 memcpy(&pi, p, sizeof(pi));
1619 ltime = pi.nd_opt_pi_valid_time;
1620 break;
a1b1f0a8 1621#endif
19005560
RM
1622 case ND_OPT_DNSSL:
1623 if (len < sizeof(dnssl))
1624 break;
1625 memcpy(&dnssl, p, sizeof(dnssl));
1626 ltime = dnssl.nd_opt_dnssl_lifetime;
1627 break;
1628 case ND_OPT_RDNSS:
1629 if (len < sizeof(rdnss))
1630 break;
1631 memcpy(&rdnss, p, sizeof(rdnss));
1632 ltime = rdnss.nd_opt_rdnss_lifetime;
1633 break;
1634 default:
1635 continue;
1636 }
1637
1638 if (ltime == 0)
1639 continue;
1640 if (ltime == ND6_INFINITE_LIFETIME) {
1641 validone = true;
1642 continue;
1643 }
1644
1645 lt.tv_sec = (time_t)ntohl(ltime);
1646 lt.tv_nsec = 0;
1647 timespecadd(&rap->acquired, &lt, &expire);
1648 if (timespeccmp(&now, &expire, >)) {
1649 expired = true;
1650 continue;
1651 }
1652
1653 timespecsub(&expire, &now, &lt);
1654 if (!timespecisset(&next) ||
1655 timespeccmp(&next, &lt, >))
1656 {
1657 next = lt;
1658 validone = true;
1659 }
1660 }
1661
1662 if (valid || validone)
1663 continue;
d4e41f4b 1664
19005560
RM
1665 /* Router has expired. Let's not keep a lot of them.
1666 * We should work out if all the options have expired .... */
1667 if (++nexpired > EXPIRED_MAX)
e82129a4 1668 ipv6nd_free_ra(rap);
91cd7324
RM
1669 }
1670
573d0487 1671 if (timespecisset(&next))
4eb7b489
RM
1672 eloop_timeout_add_tv(ifp->ctx->eloop,
1673 &next, ipv6nd_expirera, ifp);
e82129a4 1674 if (expired) {
19005560 1675 logwarnx("%s: part of Router Advertisement expired", ifp->name);
9aa11487 1676 rt_build(ifp->ctx, AF_INET6);
e82129a4
RM
1677 script_runreason(ifp, "ROUTERADVERT");
1678 }
1679}
1680
1681void
1682ipv6nd_drop(struct interface *ifp)
1683{
9a593d97 1684 struct ra *rap, *ran;
b6285211 1685 uint8_t expired = 0;
e82129a4 1686
cc9d9bf8 1687 if (ifp->ctx->ra_routers == NULL)
2433e54d
RM
1688 return;
1689
4eb7b489 1690 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
9a593d97 1691 TAILQ_FOREACH_SAFE(rap, ifp->ctx->ra_routers, next, ran) {
e82129a4
RM
1692 if (rap->iface == ifp) {
1693 rap->expired = expired = 1;
9a593d97 1694 ipv6nd_drop_ra(rap);
e82129a4
RM
1695 }
1696 }
eebe9a18 1697 if (expired) {
9aa11487 1698 rt_build(ifp->ctx, AF_INET6);
389a250b 1699 if ((ifp->options->options & DHCPCD_NODROP) != DHCPCD_NODROP)
15fc1181 1700 script_runreason(ifp, "ROUTERADVERT");
e82129a4
RM
1701 }
1702}
a9d78def 1703
e82129a4 1704static void
5fed9d43
RM
1705ipv6nd_handlena(struct dhcpcd_ctx *ctx, const char *sfrom,
1706 struct interface *ifp, struct icmp6_hdr *icp, size_t len, int hoplimit)
e82129a4
RM
1707{
1708 struct nd_neighbor_advert *nd_na;
7878d124 1709 struct in6_addr nd_na_target;
e82129a4 1710 struct ra *rap;
8e4ea3a4 1711 uint32_t is_router, is_solicited;
3852009b
RM
1712 char buf[INET6_ADDRSTRLEN];
1713 const char *taddr;
e82129a4
RM
1714
1715 if (ifp == NULL) {
1716#ifdef DEBUG_NS
5fed9d43 1717 logdebugx("NA for unexpected interface from %s", sfrom);
e82129a4
RM
1718#endif
1719 return;
1720 }
1721
3852009b 1722 if ((size_t)len < sizeof(struct nd_neighbor_advert)) {
5fed9d43 1723 logerrx("%s: IPv6 NA too short from %s", ifp->name, sfrom);
3852009b
RM
1724 return;
1725 }
1726
a708c891
RM
1727 /* RFC 4861 7.1.2 */
1728 if (hoplimit != 255) {
94d1ded9 1729 logerrx("invalid hoplimit(%d) in NA from %s",
5fed9d43 1730 hoplimit, sfrom);
a708c891
RM
1731 return;
1732 }
1733
e82129a4
RM
1734 nd_na = (struct nd_neighbor_advert *)icp;
1735 is_router = nd_na->nd_na_flags_reserved & ND_NA_FLAG_ROUTER;
1736 is_solicited = nd_na->nd_na_flags_reserved & ND_NA_FLAG_SOLICITED;
3852009b
RM
1737 taddr = inet_ntop(AF_INET6, &nd_na->nd_na_target,
1738 buf, INET6_ADDRSTRLEN);
e82129a4 1739
7878d124
RM
1740 /* nd_na->nd_na_target is not aligned. */
1741 memcpy(&nd_na_target, &nd_na->nd_na_target, sizeof(nd_na_target));
1742 if (IN6_IS_ADDR_MULTICAST(&nd_na_target)) {
94d1ded9 1743 logerrx("%s: NA multicast address %s (%s)",
5fed9d43 1744 ifp->name, taddr, sfrom);
e82129a4
RM
1745 return;
1746 }
1747
4eb7b489 1748 TAILQ_FOREACH(rap, ctx->ra_routers, next) {
7529fdf1 1749 if (rap->iface == ifp &&
7878d124 1750 IN6_ARE_ADDR_EQUAL(&rap->from, &nd_na_target))
e82129a4 1751 break;
e82129a4
RM
1752 }
1753 if (rap == NULL) {
e82129a4 1754#ifdef DEBUG_NS
0e56d022 1755 logdebugx("%s: unexpected NA from %s for %s",
5fed9d43 1756 ifp->name, sfrom, taddr);
e82129a4
RM
1757#endif
1758 return;
1759 }
1760
1761#ifdef DEBUG_NS
0e56d022 1762 logdebugx("%s: %sNA for %s from %s",
5fed9d43 1763 ifp->name, is_solicited ? "solicited " : "", taddr, sfrom);
e82129a4
RM
1764#endif
1765
1766 /* Node is no longer a router, so remove it from consideration */
1767 if (!is_router && !rap->expired) {
9efdc92f 1768 loginfox("%s: %s not a router (%s)",
5fed9d43 1769 ifp->name, taddr, sfrom);
e82129a4 1770 rap->expired = 1;
9aa11487 1771 rt_build(ifp->ctx, AF_INET6);
294eff4d 1772 script_runreason(ifp, "ROUTERADVERT");
e82129a4
RM
1773 return;
1774 }
1775
07b28b41
RM
1776 if (is_solicited && is_router && rap->lifetime)
1777 ipv6nd_reachable(rap, IPV6ND_REACHABLE);
91cd7324
RM
1778}
1779
e82129a4 1780static void
4eb7b489 1781ipv6nd_handledata(void *arg)
e82129a4 1782{
cc9d9bf8 1783 struct dhcpcd_ctx *ctx;
b2edc303 1784 int s;
5fed9d43
RM
1785 struct sockaddr_in6 from;
1786 unsigned char buf[64 * 1024]; /* Maximum ICMPv6 size */
1787 struct iovec iov = {
1788 .iov_base = buf,
1789 .iov_len = sizeof(buf),
1790 };
1791 unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int))] = { 0 };
1792 struct msghdr msg = {
1793 .msg_name = &from, .msg_namelen = sizeof(from),
1794 .msg_iov = &iov, .msg_iovlen = 1,
1795 .msg_control = ctl, .msg_controllen = sizeof(ctl),
1796 };
e82129a4 1797 ssize_t len;
5fed9d43 1798 char sfrom[INET6_ADDRSTRLEN];
0ac6d9c9 1799 int hoplimit = 0;
e82129a4
RM
1800 struct icmp6_hdr *icp;
1801 struct interface *ifp;
1802
b2edc303
RM
1803#ifdef __sun
1804 struct rs_state *state;
1805
1806 ifp = arg;
1807 state = RS_STATE(ifp);
1808 ctx = ifp->ctx;
1809 s = state->nd_fd;
1810#else
cc9d9bf8 1811 ctx = arg;
b2edc303
RM
1812 s = ctx->nd_fd;
1813#endif
1814 len = recvmsg(s, &msg, 0);
fddd88ae 1815 if (len == -1) {
94d1ded9 1816 logerr(__func__);
e82129a4
RM
1817 return;
1818 }
5fed9d43 1819 inet_ntop(AF_INET6, &from.sin6_addr, sfrom, sizeof(sfrom));
e82129a4 1820 if ((size_t)len < sizeof(struct icmp6_hdr)) {
5fed9d43 1821 logerrx("IPv6 ICMP packet too short from %s", sfrom);
e82129a4
RM
1822 return;
1823 }
1824
b2edc303
RM
1825#ifdef __sun
1826 if_findifpfromcmsg(ctx, &msg, &hoplimit);
1827#else
0ac6d9c9
RM
1828 ifp = if_findifpfromcmsg(ctx, &msg, &hoplimit);
1829 if (ifp == NULL) {
1830 logerr(__func__);
e82129a4
RM
1831 return;
1832 }
b2edc303 1833#endif
e82129a4 1834
3479ca77 1835 /* Don't do anything if the user hasn't configured it. */
0ac6d9c9
RM
1836 if (ifp->active != IF_ACTIVE_USER ||
1837 !(ifp->options->options & DHCPCD_IPV6))
3479ca77
RM
1838 return;
1839
5fed9d43 1840 icp = (struct icmp6_hdr *)buf;
e82129a4
RM
1841 if (icp->icmp6_code == 0) {
1842 switch(icp->icmp6_type) {
1843 case ND_NEIGHBOR_ADVERT:
5fed9d43
RM
1844 ipv6nd_handlena(ctx, sfrom,
1845 ifp, icp, (size_t)len, hoplimit);
e82129a4
RM
1846 return;
1847 case ND_ROUTER_ADVERT:
5fed9d43
RM
1848 ipv6nd_handlera(ctx, &from, sfrom,
1849 ifp, icp, (size_t)len, hoplimit);
e82129a4
RM
1850 return;
1851 }
1852 }
7cece083 1853
94d1ded9 1854 logerrx("invalid IPv6 type %d or code %d from %s",
5fed9d43 1855 icp->icmp6_type, icp->icmp6_code, sfrom);
e82129a4
RM
1856}
1857
d936ec19 1858static void
6e6e06af 1859ipv6nd_startrs1(void *arg)
91cd7324 1860{
6e6e06af 1861 struct interface *ifp = arg;
ca15a0aa 1862 struct rs_state *state;
91cd7324 1863
9efdc92f 1864 loginfox("%s: soliciting an IPv6 router", ifp->name);
673e81e5
RM
1865 state = RS_STATE(ifp);
1866 if (state == NULL) {
e82129a4 1867 ifp->if_data[IF_DATA_IPV6ND] = calloc(1, sizeof(*state));
673e81e5 1868 state = RS_STATE(ifp);
fbbb0875 1869 if (state == NULL) {
94d1ded9 1870 logerr(__func__);
6e6e06af 1871 return;
fbbb0875 1872 }
b0a0f6d4 1873#ifdef __sun
b2edc303 1874 state->nd_fd = -1;
b0a0f6d4 1875#endif
673e81e5
RM
1876 }
1877
b2edc303
RM
1878#ifdef __sun
1879 if (ipv6nd_open(ifp) == -1) {
1880 logerr(__func__);
1881 return;
673e81e5 1882 }
b2edc303
RM
1883#else
1884 if (ipv6nd_open(ifp->ctx) == -1) {
1885 logerr(__func__);
1886 return;
1887 }
1888#endif
673e81e5
RM
1889
1890 /* Always make a new probe as the underlying hardware
1891 * address could have changed. */
e82129a4 1892 ipv6nd_makersprobe(ifp);
fbbb0875 1893 if (state->rs == NULL) {
94d1ded9 1894 logerr(__func__);
6e6e06af 1895 return;
fbbb0875 1896 }
91cd7324 1897
cd09e583 1898 state->retrans = RETRANS_TIMER;
ca15a0aa 1899 state->rsprobes = 0;
e82129a4 1900 ipv6nd_sendrsprobe(ifp);
6e6e06af
RM
1901}
1902
1903void
1904ipv6nd_startrs(struct interface *ifp)
1905{
573d0487 1906 struct timespec tv;
6e6e06af 1907
d936ec19 1908 eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
f572315d
RM
1909 if (!(ifp->options->options & DHCPCD_INITIAL_DELAY)) {
1910 ipv6nd_startrs1(ifp);
1911 return;
1912 }
1913
6e6e06af 1914 tv.tv_sec = 0;
573d0487
RM
1915 tv.tv_nsec = (suseconds_t)arc4random_uniform(
1916 MAX_RTR_SOLICITATION_DELAY * NSEC_PER_SEC);
1917 timespecnorm(&tv);
0e56d022 1918 logdebugx("%s: delaying IPv6 router solicitation for %0.1f seconds",
573d0487 1919 ifp->name, timespec_to_double(&tv));
6e6e06af
RM
1920 eloop_timeout_add_tv(ifp->ctx->eloop, &tv, ipv6nd_startrs1, ifp);
1921 return;
91cd7324 1922}