source: rtems-libbsd/dhcpcd/ipv6nd.c @ 338f300

55-freebsd-126-freebsd-12
Last change on this file since 338f300 was 338f300, checked in by Christian Mauderer <christian.mauderer@…>, on 04/25/18 at 14:28:00

buildset: Add minimal and everything config.

This adds two new buildset configurations: One that leaves out as much
features as possible and one that enables all features. For the default
configuration WiFi? support is now disabled.

To disable IPv6 for the minimal configuration, all -DINET6 are
eliminated in libbsd.py. They are now replaced by a #ifdef that checks
for RTEMS_BSD_MODULE_NETINET6 instead.

Close #3351.

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