[BACK]Return to rtadvd.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / usr.sbin / rtadvd

Annotation of src/usr.sbin/rtadvd/rtadvd.c, Revision 1.53

1.53    ! roy         1: /*     $NetBSD: rtadvd.c,v 1.52 2016/12/16 09:09:38 ozaki-r Exp $      */
1.30      rpaulo      2: /*     $KAME: rtadvd.c,v 1.92 2005/10/17 14:40:02 suz Exp $    */
1.2       itojun      3:
1.1       itojun      4: /*
                      5:  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
                      6:  * All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. Neither the name of the project nor the names of its contributors
                     17:  *    may be used to endorse or promote products derived from this software
                     18:  *    without specific prior written permission.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
                     21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
                     24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     30:  * SUCH DAMAGE.
                     31:  */
                     32:
                     33: #include <sys/param.h>
                     34: #include <sys/socket.h>
                     35: #include <sys/uio.h>
                     36: #include <sys/time.h>
1.11      itojun     37: #include <sys/queue.h>
1.1       itojun     38:
                     39: #include <net/if.h>
                     40: #include <net/route.h>
                     41: #include <net/if_dl.h>
                     42: #include <netinet/in.h>
                     43: #include <netinet/ip6.h>
                     44: #include <netinet6/ip6_var.h>
                     45: #include <netinet/icmp6.h>
                     46:
                     47: #include <arpa/inet.h>
                     48:
                     49: #include <time.h>
                     50: #include <unistd.h>
                     51: #include <stdio.h>
                     52: #include <err.h>
                     53: #include <errno.h>
                     54: #include <string.h>
                     55: #include <stdlib.h>
                     56: #include <syslog.h>
1.39      roy        57: #ifdef __NetBSD__
1.17      itojun     58: #include <util.h>
1.39      roy        59: #endif
1.25      itojun     60: #include <poll.h>
1.44      roy        61: #include <pwd.h>
1.17      itojun     62:
1.1       itojun     63: #include "rtadvd.h"
                     64: #include "rrenum.h"
                     65: #include "advcap.h"
                     66: #include "timer.h"
                     67: #include "if.h"
                     68: #include "config.h"
1.9       itojun     69: #include "dump.h"
1.51      ozaki-r    70: #include "prog_ops.h"
1.1       itojun     71:
                     72: struct msghdr rcvmhdr;
1.36      roy        73: static unsigned char *rcvcmsgbuf;
1.6       itojun     74: static size_t rcvcmsgbuflen;
1.39      roy        75: static unsigned char *sndcmsgbuf;
1.6       itojun     76: static size_t sndcmsgbuflen;
1.18      itojun     77: volatile sig_atomic_t do_dump;
1.39      roy        78: volatile sig_atomic_t do_reconf;
1.18      itojun     79: volatile sig_atomic_t do_die;
1.1       itojun     80: struct msghdr sndmhdr;
                     81: struct iovec rcviov[2];
                     82: struct iovec sndiov[2];
1.30      rpaulo     83: struct sockaddr_in6 rcvfrom;
1.36      roy        84: static const char *dumpfilename = "/var/run/rtadvd.dump"; /* XXX configurable */
1.11      itojun     85: static char *mcastif;
1.12      itojun     86: int sock;
                     87: int rtsock = -1;
1.5       itojun     88: int accept_rr = 0;
1.1       itojun     89: int dflag = 0, sflag = 0;
                     90:
1.39      roy        91: static char **if_argv;
                     92: static int if_argc;
                     93:
1.31      mrg        94: char *conffile = NULL;
1.1       itojun     95:
1.36      roy        96: struct ralist_head_t ralist = TAILQ_HEAD_INITIALIZER(ralist);
                     97:
1.1       itojun     98: struct nd_optlist {
1.36      roy        99:        TAILQ_ENTRY(nd_optlist) next;
1.1       itojun    100:        struct nd_opt_hdr *opt;
                    101: };
                    102: union nd_opts {
1.18      itojun    103:        struct nd_opt_hdr *nd_opt_array[9];
1.1       itojun    104:        struct {
                    105:                struct nd_opt_hdr *zero;
                    106:                struct nd_opt_hdr *src_lladdr;
                    107:                struct nd_opt_hdr *tgt_lladdr;
                    108:                struct nd_opt_prefix_info *pi;
                    109:                struct nd_opt_rd_hdr *rh;
                    110:                struct nd_opt_mtu *mtu;
1.36      roy       111:                TAILQ_HEAD(, nd_optlist) list;
1.1       itojun    112:        } nd_opt_each;
                    113: };
                    114: #define nd_opts_src_lladdr     nd_opt_each.src_lladdr
                    115: #define nd_opts_tgt_lladdr     nd_opt_each.tgt_lladdr
                    116: #define nd_opts_pi             nd_opt_each.pi
                    117: #define nd_opts_rh             nd_opt_each.rh
                    118: #define nd_opts_mtu            nd_opt_each.mtu
                    119: #define nd_opts_list           nd_opt_each.list
                    120:
1.36      roy       121: #define NDOPT_FLAG_SRCLINKADDR (1 << 0)
                    122: #define NDOPT_FLAG_TGTLINKADDR (1 << 1)
                    123: #define NDOPT_FLAG_PREFIXINFO  (1 << 2)
                    124: #define NDOPT_FLAG_RDHDR       (1 << 3)
                    125: #define NDOPT_FLAG_MTU         (1 << 4)
                    126: #define NDOPT_FLAG_RDNSS       (1 << 5)
                    127: #define NDOPT_FLAG_DNSSL       (1 << 6)
                    128:
                    129: uint32_t ndopt_flags[] = {
                    130:        [ND_OPT_SOURCE_LINKADDR] =      NDOPT_FLAG_SRCLINKADDR,
                    131:        [ND_OPT_TARGET_LINKADDR] =      NDOPT_FLAG_TGTLINKADDR,
                    132:        [ND_OPT_PREFIX_INFORMATION] =   NDOPT_FLAG_PREFIXINFO,
                    133:        [ND_OPT_REDIRECTED_HEADER] =    NDOPT_FLAG_RDHDR,
                    134:        [ND_OPT_MTU] =                  NDOPT_FLAG_MTU,
                    135:        [ND_OPT_RDNSS] =                NDOPT_FLAG_RDNSS,
                    136:        [ND_OPT_DNSSL] =                NDOPT_FLAG_DNSSL,
                    137: };
                    138:
                    139: struct sockaddr_in6 sin6_linklocal_allnodes = {
                    140:        .sin6_len =     sizeof(sin6_linklocal_allnodes),
                    141:        .sin6_family =  AF_INET6,
                    142:        .sin6_addr =    IN6ADDR_LINKLOCAL_ALLNODES_INIT,
                    143: };
1.38      christos  144: #ifdef notdef
1.36      roy       145: struct sockaddr_in6 sin6_linklocal_allrouters = {
                    146:        .sin6_len =     sizeof(sin6_linklocal_allrouters),
                    147:        .sin6_family =  AF_INET6,
                    148:        .sin6_addr =    IN6ADDR_LINKLOCAL_ALLROUTERS_INIT,
                    149: };
1.38      christos  150: #endif
1.36      roy       151: struct sockaddr_in6 sin6_sitelocal_allrouters = {
                    152:        .sin6_len =     sizeof(sin6_sitelocal_allrouters),
                    153:        .sin6_family =  AF_INET6,
                    154:        .sin6_addr =    IN6ADDR_SITELOCAL_ALLROUTERS_INIT,
1.1       itojun    155: };
                    156:
1.36      roy       157: static void set_die(int);
1.41      roy       158: static void die(void);
1.39      roy       159: static void set_reconf(int);
1.36      roy       160: static void sock_open(void);
                    161: static void rtsock_open(void);
                    162: static void rtadvd_input(void);
                    163: static void rs_input(int, struct nd_router_solicit *,
                    164:     struct in6_pktinfo *, struct sockaddr_in6 *);
                    165: static void ra_input(int, struct nd_router_advert *,
                    166:     struct in6_pktinfo *, struct sockaddr_in6 *);
1.39      roy       167: static struct rainfo *ra_output(struct rainfo *);
1.36      roy       168: static int prefix_check(struct nd_opt_prefix_info *, struct rainfo *,
                    169:     struct sockaddr_in6 *);
                    170: static int nd6_options(struct nd_opt_hdr *, int, union nd_opts *, uint32_t);
                    171: static void free_ndopts(union nd_opts *);
                    172: static void rtmsg_input(void);
                    173: static void rtadvd_set_dump_file(int);
1.1       itojun    174:
                    175: int
1.36      roy       176: main(int argc, char *argv[])
1.1       itojun    177: {
1.23      mycroft   178:        struct pollfd set[2];
1.47      roy       179:        struct timespec *timeout;
1.1       itojun    180:        int i, ch;
1.14      itojun    181:        int fflag = 0, logopt;
1.44      roy       182:        struct passwd *pw;
1.52      ozaki-r   183:        const char *pidfilepath = NULL;
1.1       itojun    184:
                    185:        /* get command line options and arguments */
1.52      ozaki-r   186: #define OPTIONS "c:dDfM:p:Rs"
1.7       itojun    187:        while ((ch = getopt(argc, argv, OPTIONS)) != -1) {
                    188: #undef OPTIONS
1.14      itojun    189:                switch (ch) {
                    190:                case 'c':
                    191:                        conffile = optarg;
                    192:                        break;
                    193:                case 'd':
                    194:                        dflag = 1;
                    195:                        break;
                    196:                case 'D':
                    197:                        dflag = 2;
                    198:                        break;
                    199:                case 'f':
                    200:                        fflag = 1;
                    201:                        break;
1.11      itojun    202:                case 'M':
                    203:                        mcastif = optarg;
                    204:                        break;
1.52      ozaki-r   205:                case 'p':
                    206:                        pidfilepath = optarg;
                    207:                        break;
1.14      itojun    208:                case 'R':
                    209:                        fprintf(stderr, "rtadvd: "
                    210:                                "the -R option is currently ignored.\n");
                    211:                        /* accept_rr = 1; */
                    212:                        /* run anyway... */
                    213:                        break;
                    214:                case 's':
                    215:                        sflag = 1;
                    216:                        break;
1.1       itojun    217:                }
                    218:        }
                    219:        argc -= optind;
                    220:        argv += optind;
                    221:        if (argc == 0) {
                    222:                fprintf(stderr,
1.39      roy       223:                        "usage: rtadvd [-DdfRs] [-c conffile]"
1.52      ozaki-r   224:                        " [-M ifname] [-p pidfile] interface ...\n");
1.1       itojun    225:                exit(1);
                    226:        }
                    227:
1.51      ozaki-r   228:        if (prog_init && prog_init() == -1) {
                    229:                err(1, "init failed");
                    230:        }
                    231:
1.14      itojun    232:        logopt = LOG_NDELAY | LOG_PID;
                    233:        if (fflag)
                    234:                logopt |= LOG_PERROR;
                    235:        openlog("rtadvd", logopt, LOG_DAEMON);
                    236:
1.1       itojun    237:        /* set log level */
                    238:        if (dflag == 0)
                    239:                (void)setlogmask(LOG_UPTO(LOG_ERR));
                    240:        if (dflag == 1)
                    241:                (void)setlogmask(LOG_UPTO(LOG_INFO));
                    242:
1.44      roy       243:        errno = 0; /* Ensure errno is 0 so we know if getpwnam errors or not */
                    244:        if ((pw = getpwnam(RTADVD_USER)) == NULL) {
                    245:                if (errno == 0)
                    246:                        syslog(LOG_ERR,
                    247:                            "user %s does not exist, aborting",
                    248:                            RTADVD_USER);
                    249:                else
                    250:                        syslog(LOG_ERR, "getpwnam: %s: %m", RTADVD_USER);
                    251:                exit(1);
                    252:        }
                    253:
1.1       itojun    254:        /* timer initialization */
                    255:        rtadvd_timer_init();
                    256:
1.39      roy       257:        if_argc = argc;
                    258:        if_argv = argv;
1.1       itojun    259:        while (argc--)
1.39      roy       260:                getconfig(*argv++, 1);
1.1       itojun    261:
                    262:        if (!fflag)
1.51      ozaki-r   263:                prog_daemon(1, 0);
1.13      itojun    264:
                    265:        sock_open();
1.1       itojun    266:
1.39      roy       267: #ifdef __NetBSD__
1.9       itojun    268:        /* record the current PID */
1.52      ozaki-r   269:        if (pidfile(pidfilepath) < 0) {
1.18      itojun    270:                syslog(LOG_ERR,
                    271:                    "<%s> failed to open the pid log file, run anyway.",
1.21      itojun    272:                    __func__);
1.18      itojun    273:        }
1.39      roy       274: #endif
1.9       itojun    275:
1.23      mycroft   276:        set[0].fd = sock;
                    277:        set[0].events = POLLIN;
1.12      itojun    278:        if (sflag == 0) {
                    279:                rtsock_open();
1.23      mycroft   280:                set[1].fd = rtsock;
                    281:                set[1].events = POLLIN;
1.12      itojun    282:        } else
1.24      mycroft   283:                set[1].fd = -1;
1.19      itojun    284:
1.44      roy       285:        syslog(LOG_INFO, "dropping privileges to %s", RTADVD_USER);
1.51      ozaki-r   286:        if (prog_chroot(pw->pw_dir) == -1) {
1.44      roy       287:                syslog(LOG_ERR, "chroot: %s: %m", pw->pw_dir);
                    288:                exit(1);
                    289:        }
1.51      ozaki-r   290:        if (prog_chdir("/") == -1) {
1.44      roy       291:                syslog(LOG_ERR, "chdir: /: %m");
                    292:                exit(1);
                    293:        }
1.51      ozaki-r   294:        if (prog_setgroups(1, &pw->pw_gid) == -1 ||
                    295:            prog_setgid(pw->pw_gid) == -1 ||
                    296:            prog_setuid(pw->pw_uid) == -1)
1.44      roy       297:        {
                    298:                syslog(LOG_ERR, "failed to drop privileges: %m");
                    299:                exit(1);
                    300:        }
                    301:
1.41      roy       302:        signal(SIGINT, set_die);
1.22      itojun    303:        signal(SIGTERM, set_die);
1.39      roy       304:        signal(SIGHUP, set_reconf);
1.22      itojun    305:        signal(SIGUSR1, rtadvd_set_dump_file);
1.5       itojun    306:
1.23      mycroft   307:        for (;;) {
1.9       itojun    308:                if (do_dump) {  /* SIGUSR1 */
                    309:                        do_dump = 0;
                    310:                        rtadvd_dump_file(dumpfilename);
                    311:                }
                    312:
1.39      roy       313:                if (do_reconf) { /* SIGHUP */
                    314:                        do_reconf = 0;
                    315:                        syslog(LOG_INFO, "<%s> reloading config on SIGHUP",
                    316:                               __func__);
                    317:                        argc = if_argc;
                    318:                        argv = if_argv;
                    319:                        while (argc--)
                    320:                                getconfig(*argv++, 0);
                    321:                }
                    322:
1.47      roy       323:                /* timer expiration check and reset the timer */
                    324:                timeout = rtadvd_check_timer();
                    325:
1.11      itojun    326:                if (do_die) {
                    327:                        die();
                    328:                        /*NOTREACHED*/
                    329:                }
                    330:
1.10      itojun    331:                if (timeout != NULL) {
                    332:                        syslog(LOG_DEBUG,
1.30      rpaulo    333:                            "<%s> set timer to %ld:%ld. waiting for "
1.21      itojun    334:                            "inputs or timeout", __func__,
1.14      itojun    335:                            (long int)timeout->tv_sec,
1.47      roy       336:                            (long int)timeout->tv_nsec);
1.10      itojun    337:                } else {
                    338:                        syslog(LOG_DEBUG,
1.14      itojun    339:                            "<%s> there's no timer. waiting for inputs",
1.21      itojun    340:                            __func__);
1.10      itojun    341:                }
1.1       itojun    342:
1.51      ozaki-r   343:                if ((i = prog_poll(set, 2, timeout ? (timeout->tv_sec * 1000 +
1.47      roy       344:                    (timeout->tv_nsec + 999999) / 1000000) : INFTIM)) < 0)
                    345:                {
1.9       itojun    346:                        /* EINTR would occur upon SIGUSR1 for status dump */
                    347:                        if (errno != EINTR)
1.49      roy       348:                                syslog(LOG_ERR, "<%s> poll: %m", __func__);
1.1       itojun    349:                        continue;
                    350:                }
                    351:                if (i == 0)     /* timeout */
                    352:                        continue;
1.23      mycroft   353:                if (rtsock != -1 && set[1].revents & POLLIN)
1.1       itojun    354:                        rtmsg_input();
1.23      mycroft   355:                if (set[0].revents & POLLIN)
1.1       itojun    356:                        rtadvd_input();
                    357:        }
                    358:        exit(0);                /* NOTREACHED */
                    359: }
                    360:
                    361: static void
1.39      roy       362: rtadvd_set_dump_file(__unused int sig)
1.9       itojun    363: {
1.39      roy       364:
1.9       itojun    365:        do_dump = 1;
                    366: }
                    367:
                    368: static void
1.39      roy       369: set_reconf(__unused int sig)
1.5       itojun    370: {
1.39      roy       371:
                    372:        do_reconf = 1;
                    373: }
                    374:
                    375: static void
                    376: set_die(__unused int sig)
                    377: {
                    378:
1.11      itojun    379:        do_die = 1;
                    380: }
                    381:
                    382: static void
1.36      roy       383: die(void)
1.11      itojun    384: {
1.41      roy       385:        static int waiting;
                    386:        struct rainfo *rai, *ran;
1.39      roy       387:        struct rdnss *rdnss;
                    388:        struct dnssl *dnssl;
1.5       itojun    389:
1.41      roy       390:        if (waiting) {
                    391:                if (TAILQ_FIRST(&ralist)) {
                    392:                        syslog(LOG_INFO,
                    393:                               "<%s> waiting for expiration of all RA timers",
                    394:                               __func__);
                    395:                        return;
                    396:                }
                    397:                syslog(LOG_NOTICE, "<%s> gracefully terminated", __func__);
                    398:                free(rcvcmsgbuf);
                    399:                free(sndcmsgbuf);
                    400:                exit(0);
                    401:                /* NOT REACHED */
                    402:        }
                    403:
1.43      roy       404:        if (TAILQ_FIRST(&ralist) == NULL) {
                    405:                syslog(LOG_NOTICE, "<%s> gracefully terminated", __func__);
                    406:                exit(0);
                    407:                /* NOT REACHED */
                    408:        }
                    409:
1.41      roy       410:        waiting = 1;
                    411:        syslog(LOG_NOTICE, "<%s> final RA transmission started", __func__);
                    412:
                    413:        TAILQ_FOREACH_SAFE(rai, &ralist, next, ran) {
                    414:                if (rai->leaving) {
                    415:                        TAILQ_REMOVE(&ralist, rai, next);
                    416:                        TAILQ_INSERT_HEAD(&ralist, rai->leaving, next);
                    417:                        rai->leaving->leaving = rai->leaving;
                    418:                        rai->leaving->leaving_for = rai->leaving;
                    419:                        free_rainfo(rai);
                    420:                        continue;
                    421:                }
1.39      roy       422:                rai->lifetime = 0;
                    423:                TAILQ_FOREACH(rdnss, &rai->rdnss, next)
                    424:                        rdnss->lifetime = 0;
                    425:                TAILQ_FOREACH(dnssl, &rai->dnssl, next)
                    426:                        dnssl->lifetime = 0;
                    427:                make_packet(rai);
1.41      roy       428:                rai->leaving = rai;
                    429:                rai->leaving_for = rai;
                    430:                rai->initcounter = MAX_INITIAL_RTR_ADVERTISEMENTS;
                    431:                rai->mininterval = MIN_DELAY_BETWEEN_RAS;
                    432:                rai->maxinterval = MIN_DELAY_BETWEEN_RAS;
                    433:                rai->leaving_adv = MAX_FINAL_RTR_ADVERTISEMENTS;
                    434:                ra_output(rai);
                    435:                ra_timer_update((void *)rai, &rai->timer->tm);
                    436:                rtadvd_set_timer(&rai->timer->tm, rai->timer);
1.5       itojun    437:        }
                    438: }
                    439:
                    440: static void
1.36      roy       441: rtmsg_input(void)
1.1       itojun    442: {
1.9       itojun    443:        int n, type, ifindex = 0, plen;
1.2       itojun    444:        size_t len;
1.32      tron      445:        union rt_msghdr_buf {
                    446:                struct rt_msghdr        rt_msghdr;
                    447:                char                    data[2048];
                    448:        } buffer;
1.39      roy       449:        char *msg, *next, *lim, **argv;
1.31      mrg       450:        char ifname[IF_NAMESIZE];
1.1       itojun    451:        struct prefix *prefix;
                    452:        struct rainfo *rai;
                    453:        struct in6_addr *addr;
                    454:        char addrbuf[INET6_ADDRSTRLEN];
1.39      roy       455:        int prefixchange = 0, argc;
1.1       itojun    456:
1.39      roy       457:        memset(&buffer, 0, sizeof(buffer));
1.51      ozaki-r   458:        n = prog_read(rtsock, &buffer, sizeof(buffer));
1.41      roy       459:
                    460:        /* We read the buffer first to clear the FD */
                    461:        if (do_die)
                    462:                return;
                    463:
1.32      tron      464:        msg = buffer.data;
1.1       itojun    465:        if (dflag > 1) {
1.14      itojun    466:                syslog(LOG_DEBUG, "<%s> received a routing message "
1.39      roy       467:                    "(type = %d, len = %d)", __func__, rtmsg_type(msg),
                    468:                    rtmsg_len(msg));
1.1       itojun    469:        }
                    470:        if (n > rtmsg_len(msg)) {
                    471:                /*
                    472:                 * This usually won't happen for messages received on
1.10      itojun    473:                 * a routing socket.
1.1       itojun    474:                 */
                    475:                if (dflag > 1)
                    476:                        syslog(LOG_DEBUG,
1.14      itojun    477:                            "<%s> received data length is larger than "
                    478:                            "1st routing message len. multiple messages? "
                    479:                            "read %d bytes, but 1st msg len = %d",
1.21      itojun    480:                            __func__, n, rtmsg_len(msg));
1.1       itojun    481: #if 0
                    482:                /* adjust length */
                    483:                n = rtmsg_len(msg);
                    484: #endif
                    485:        }
                    486:
                    487:        lim = msg + n;
                    488:        for (next = msg; next < lim; next += len) {
1.10      itojun    489:                int oldifflags;
                    490:
1.1       itojun    491:                next = get_next_msg(next, lim, 0, &len,
                    492:                                    RTADV_TYPE2BITMASK(RTM_ADD) |
                    493:                                    RTADV_TYPE2BITMASK(RTM_DELETE) |
                    494:                                    RTADV_TYPE2BITMASK(RTM_NEWADDR) |
                    495:                                    RTADV_TYPE2BITMASK(RTM_DELADDR) |
1.39      roy       496: #ifdef RTM_IFANNOUNCE
                    497:                                    RTADV_TYPE2BITMASK(RTM_IFANNOUNCE) |
                    498: #endif
1.1       itojun    499:                                    RTADV_TYPE2BITMASK(RTM_IFINFO));
                    500:                if (len == 0)
                    501:                        break;
                    502:                type = rtmsg_type(next);
                    503:                switch (type) {
                    504:                case RTM_ADD:
                    505:                case RTM_DELETE:
                    506:                        ifindex = get_rtm_ifindex(next);
                    507:                        break;
                    508:                case RTM_NEWADDR:
                    509:                case RTM_DELADDR:
                    510:                        ifindex = get_ifam_ifindex(next);
                    511:                        break;
1.39      roy       512: #ifdef RTM_IFANNOUNCE
                    513:                case RTM_IFANNOUNCE:
                    514:                        ifindex = get_ifan_ifindex(next);
                    515:                        if (get_ifan_what(next) == IFAN_ARRIVAL) {
                    516:                                syslog(LOG_DEBUG,
                    517:                                       "<%s> interface %s arrived",
                    518:                                       __func__,
                    519:                                       if_indextoname(ifindex, ifname));
                    520:                                if (if_argc == 0) {
                    521:                                        getconfig(ifname, 0);
                    522:                                        continue;
                    523:                                }
                    524:                                argc = if_argc;
                    525:                                argv = if_argv;
                    526:                                while (argc--) {
                    527:                                        if (strcmp(ifname, *argv++) == 0) {
                    528:                                                getconfig(ifname, 0);
                    529:                                                break;
                    530:                                        }
                    531:                                }
                    532:                                continue;
                    533:                        }
                    534:                        break;
                    535: #endif
1.1       itojun    536:                case RTM_IFINFO:
                    537:                        ifindex = get_ifm_ifindex(next);
                    538:                        break;
                    539:                default:
                    540:                        /* should not reach here */
                    541:                        if (dflag > 1) {
                    542:                                syslog(LOG_DEBUG,
                    543:                                       "<%s:%d> unknown rtmsg %d on %s",
1.21      itojun    544:                                       __func__, __LINE__, type,
1.1       itojun    545:                                       if_indextoname(ifindex, ifname));
                    546:                        }
1.10      itojun    547:                        continue;
1.1       itojun    548:                }
                    549:
                    550:                if ((rai = if_indextorainfo(ifindex)) == NULL) {
                    551:                        if (dflag > 1) {
                    552:                                syslog(LOG_DEBUG,
                    553:                                       "<%s> route changed on "
1.39      roy       554:                                       "non advertising interface %s (%d)",
1.21      itojun    555:                                       __func__,
1.39      roy       556:                                       if_indextoname(ifindex, ifname),
                    557:                                       ifindex);
1.1       itojun    558:                        }
1.10      itojun    559:                        continue;
1.1       itojun    560:                }
1.39      roy       561:                oldifflags = rai->ifflags;
1.1       itojun    562:
1.14      itojun    563:                switch (type) {
                    564:                case RTM_ADD:
                    565:                        /* init ifflags because it may have changed */
1.39      roy       566:                        rai->ifflags = if_getflags(ifindex, rai->ifflags);
1.14      itojun    567:
                    568:                        if (sflag)
                    569:                                break;  /* we aren't interested in prefixes  */
                    570:
                    571:                        addr = get_addr(msg);
                    572:                        plen = get_prefixlen(msg);
                    573:                        /* sanity check for plen */
                    574:                        /* as RFC2373, prefixlen is at least 4 */
                    575:                        if (plen < 4 || plen > 127) {
1.1       itojun    576:                                syslog(LOG_INFO, "<%s> new interface route's"
1.14      itojun    577:                                    "plen %d is invalid for a prefix",
1.21      itojun    578:                                    __func__, plen);
1.14      itojun    579:                                break;
                    580:                        }
                    581:                        prefix = find_prefix(rai, addr, plen);
                    582:                        if (prefix) {
1.30      rpaulo    583:                                if (prefix->timer) {
                    584:                                        /*
                    585:                                         * If the prefix has been invalidated,
                    586:                                         * make it available again.
                    587:                                         */
                    588:                                        update_prefix(prefix);
                    589:                                        prefixchange = 1;
                    590:                                } else if (dflag > 1) {
1.14      itojun    591:                                        syslog(LOG_DEBUG,
                    592:                                            "<%s> new prefix(%s/%d) "
                    593:                                            "added on %s, "
                    594:                                            "but it was already in list",
1.21      itojun    595:                                            __func__,
1.14      itojun    596:                                            inet_ntop(AF_INET6, addr,
                    597:                                            (char *)addrbuf, INET6_ADDRSTRLEN),
                    598:                                            plen, rai->ifname);
                    599:                                }
1.10      itojun    600:                                break;
1.14      itojun    601:                        }
                    602:                        make_prefix(rai, ifindex, addr, plen);
1.30      rpaulo    603:                        prefixchange = 1;
1.14      itojun    604:                        break;
                    605:                case RTM_DELETE:
                    606:                        /* init ifflags because it may have changed */
1.39      roy       607:                        rai->ifflags = if_getflags(ifindex, rai->ifflags);
1.14      itojun    608:
                    609:                        if (sflag)
1.10      itojun    610:                                break;
1.14      itojun    611:
                    612:                        addr = get_addr(msg);
                    613:                        plen = get_prefixlen(msg);
                    614:                        /* sanity check for plen */
                    615:                        /* as RFC2373, prefixlen is at least 4 */
                    616:                        if (plen < 4 || plen > 127) {
                    617:                                syslog(LOG_INFO,
                    618:                                    "<%s> deleted interface route's "
                    619:                                    "plen %d is invalid for a prefix",
1.21      itojun    620:                                    __func__, plen);
1.14      itojun    621:                                break;
                    622:                        }
                    623:                        prefix = find_prefix(rai, addr, plen);
                    624:                        if (prefix == NULL) {
                    625:                                if (dflag > 1) {
                    626:                                        syslog(LOG_DEBUG,
                    627:                                            "<%s> prefix(%s/%d) was "
                    628:                                            "deleted on %s, "
                    629:                                            "but it was not in list",
1.21      itojun    630:                                            __func__,
1.14      itojun    631:                                            inet_ntop(AF_INET6, addr,
                    632:                                            (char *)addrbuf, INET6_ADDRSTRLEN),
                    633:                                            plen, rai->ifname);
                    634:                                }
                    635:                                break;
                    636:                        }
1.30      rpaulo    637:                        invalidate_prefix(prefix);
                    638:                        prefixchange = 1;
1.14      itojun    639:                        break;
1.1       itojun    640:                case RTM_NEWADDR:
                    641:                case RTM_DELADDR:
1.14      itojun    642:                        /* init ifflags because it may have changed */
1.39      roy       643:                        rai->ifflags = if_getflags(ifindex, rai->ifflags);
1.14      itojun    644:                        break;
1.1       itojun    645:                case RTM_IFINFO:
1.39      roy       646:                        rai->ifflags = get_ifm_flags(next);
1.14      itojun    647:                        break;
1.39      roy       648: #ifdef RTM_IFANNOUNCE
                    649:                case RTM_IFANNOUNCE:
                    650:                        if (get_ifan_what(next) == IFAN_DEPARTURE) {
                    651:                                syslog(LOG_DEBUG,
                    652:                                       "<%s> interface %s departed",
                    653:                                       __func__, rai->ifname);
                    654:                                TAILQ_REMOVE(&ralist, rai, next);
                    655:                                if (rai->leaving)
                    656:                                        free_rainfo(rai->leaving);
                    657:                                free_rainfo(rai);
                    658:                                continue;
                    659:                        }
                    660:                        break;
                    661: #endif
1.1       itojun    662:                default:
                    663:                        /* should not reach here */
                    664:                        if (dflag > 1) {
                    665:                                syslog(LOG_DEBUG,
1.14      itojun    666:                                    "<%s:%d> unknown rtmsg %d on %s",
1.21      itojun    667:                                    __func__, __LINE__, type,
1.14      itojun    668:                                    if_indextoname(ifindex, ifname));
1.1       itojun    669:                        }
                    670:                        return;
                    671:                }
1.10      itojun    672:
                    673:                /* check if an interface flag is changed */
                    674:                if ((oldifflags & IFF_UP) != 0 &&       /* UP to DOWN */
1.39      roy       675:                    (rai->ifflags & IFF_UP) == 0) {
1.10      itojun    676:                        syslog(LOG_INFO,
1.14      itojun    677:                            "<%s> interface %s becomes down. stop timer.",
1.21      itojun    678:                            __func__, rai->ifname);
1.10      itojun    679:                        rtadvd_remove_timer(&rai->timer);
1.18      itojun    680:                } else if ((oldifflags & IFF_UP) == 0 && /* DOWN to UP */
1.39      roy       681:                         (rai->ifflags & IFF_UP) != 0) {
1.10      itojun    682:                        syslog(LOG_INFO,
1.14      itojun    683:                            "<%s> interface %s becomes up. restart timer.",
1.21      itojun    684:                            __func__, rai->ifname);
1.10      itojun    685:
                    686:                        rai->initcounter = 0; /* reset the counter */
                    687:                        rai->waiting = 0; /* XXX */
1.39      roy       688:                        rtadvd_remove_timer(&rai->timer);
1.10      itojun    689:                        rai->timer = rtadvd_add_timer(ra_timeout,
1.14      itojun    690:                            ra_timer_update, rai, rai);
1.10      itojun    691:                        ra_timer_update((void *)rai, &rai->timer->tm);
                    692:                        rtadvd_set_timer(&rai->timer->tm, rai->timer);
1.39      roy       693:                } else if (prefixchange && rai->ifflags & IFF_UP) {
1.30      rpaulo    694:                        /*
                    695:                         * An advertised prefix has been added or invalidated.
                    696:                         * Will notice the change in a short delay.
                    697:                         */
                    698:                        rai->initcounter = 0;
1.39      roy       699:                        ra_timer_set_short_delay(rai);
1.10      itojun    700:                }
1.1       itojun    701:        }
                    702:
                    703:        return;
                    704: }
                    705:
                    706: void
1.36      roy       707: rtadvd_input(void)
1.1       itojun    708: {
1.36      roy       709:        ssize_t i;
1.1       itojun    710:        int *hlimp = NULL;
                    711: #ifdef OLDRAWSOCKET
                    712:        struct ip6_hdr *ip;
                    713: #endif
                    714:        struct icmp6_hdr *icp;
                    715:        int ifindex = 0;
                    716:        struct cmsghdr *cm;
                    717:        struct in6_pktinfo *pi = NULL;
1.31      mrg       718:        char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
1.1       itojun    719:        struct in6_addr dst = in6addr_any;
1.39      roy       720:        struct rainfo *rai;
1.1       itojun    721:
                    722:        /*
                    723:         * Get message. We reset msg_controllen since the field could
                    724:         * be modified if we had received a message before setting
                    725:         * receive options.
                    726:         */
1.6       itojun    727:        rcvmhdr.msg_controllen = rcvcmsgbuflen;
1.51      ozaki-r   728:        if ((i = prog_recvmsg(sock, &rcvmhdr, 0)) < 0)
1.1       itojun    729:                return;
                    730:
1.41      roy       731:        /* We read the buffer first to clear the FD */
                    732:        if (do_die)
                    733:                return;
                    734:
1.1       itojun    735:        /* extract optional information via Advanced API */
                    736:        for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr);
                    737:             cm;
                    738:             cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) {
                    739:                if (cm->cmsg_level == IPPROTO_IPV6 &&
                    740:                    cm->cmsg_type == IPV6_PKTINFO &&
                    741:                    cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) {
                    742:                        pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
                    743:                        ifindex = pi->ipi6_ifindex;
                    744:                        dst = pi->ipi6_addr;
                    745:                }
                    746:                if (cm->cmsg_level == IPPROTO_IPV6 &&
                    747:                    cm->cmsg_type == IPV6_HOPLIMIT &&
                    748:                    cm->cmsg_len == CMSG_LEN(sizeof(int)))
                    749:                        hlimp = (int *)CMSG_DATA(cm);
                    750:        }
                    751:        if (ifindex == 0) {
                    752:                syslog(LOG_ERR,
                    753:                       "<%s> failed to get receiving interface",
1.21      itojun    754:                       __func__);
1.1       itojun    755:                return;
                    756:        }
                    757:        if (hlimp == NULL) {
                    758:                syslog(LOG_ERR,
                    759:                       "<%s> failed to get receiving hop limit",
1.21      itojun    760:                       __func__);
1.1       itojun    761:                return;
                    762:        }
                    763:
1.39      roy       764:        if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == NULL) {
                    765:                if (dflag > 1) {
                    766:                        syslog(LOG_DEBUG,
                    767:                               "<%s> received data for non advertising "
                    768:                               "interface (%s)",
                    769:                               __func__,
                    770:                               if_indextoname(pi->ipi6_ifindex, ifnamebuf));
                    771:                }
                    772:                return;
                    773:        }
1.10      itojun    774:        /*
                    775:         * If we happen to receive data on an interface which is now down,
                    776:         * just discard the data.
                    777:         */
1.39      roy       778:        if ((rai->ifflags & IFF_UP) == 0) {
1.10      itojun    779:                syslog(LOG_INFO,
                    780:                       "<%s> received data on a disabled interface (%s)",
1.21      itojun    781:                       __func__,
1.10      itojun    782:                       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
                    783:                return;
                    784:        }
                    785:
1.1       itojun    786: #ifdef OLDRAWSOCKET
1.36      roy       787:        if ((size_t)i < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) {
1.1       itojun    788:                syslog(LOG_ERR,
                    789:                       "<%s> packet size(%d) is too short",
1.21      itojun    790:                       __func__, i);
1.1       itojun    791:                return;
                    792:        }
                    793:
                    794:        ip = (struct ip6_hdr *)rcvmhdr.msg_iov[0].iov_base;
                    795:        icp = (struct icmp6_hdr *)(ip + 1); /* XXX: ext. hdr? */
                    796: #else
1.36      roy       797:        if ((size_t)i < sizeof(struct icmp6_hdr)) {
1.1       itojun    798:                syslog(LOG_ERR,
1.36      roy       799:                       "<%s> packet size(%zd) is too short",
1.21      itojun    800:                       __func__, i);
1.1       itojun    801:                return;
                    802:        }
                    803:
                    804:        icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base;
1.10      itojun    805: #endif
1.1       itojun    806:
1.14      itojun    807:        switch (icp->icmp6_type) {
                    808:        case ND_ROUTER_SOLICIT:
                    809:                /*
                    810:                 * Message verification - RFC-2461 6.1.1
                    811:                 * XXX: these checks must be done in the kernel as well,
                    812:                 *      but we can't completely rely on them.
                    813:                 */
                    814:                if (*hlimp != 255) {
                    815:                        syslog(LOG_NOTICE,
                    816:                            "<%s> RS with invalid hop limit(%d) "
                    817:                            "received from %s on %s",
1.21      itojun    818:                            __func__, *hlimp,
1.30      rpaulo    819:                            inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
1.14      itojun    820:                            INET6_ADDRSTRLEN),
                    821:                            if_indextoname(pi->ipi6_ifindex, ifnamebuf));
                    822:                        return;
                    823:                }
                    824:                if (icp->icmp6_code) {
                    825:                        syslog(LOG_NOTICE,
                    826:                            "<%s> RS with invalid ICMP6 code(%d) "
                    827:                            "received from %s on %s",
1.21      itojun    828:                            __func__, icp->icmp6_code,
1.30      rpaulo    829:                            inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
1.14      itojun    830:                            INET6_ADDRSTRLEN),
                    831:                            if_indextoname(pi->ipi6_ifindex, ifnamebuf));
                    832:                        return;
                    833:                }
1.36      roy       834:                if ((size_t)i < sizeof(struct nd_router_solicit)) {
1.14      itojun    835:                        syslog(LOG_NOTICE,
                    836:                            "<%s> RS from %s on %s does not have enough "
1.36      roy       837:                            "length (len = %zd)",
1.21      itojun    838:                            __func__,
1.30      rpaulo    839:                            inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
1.14      itojun    840:                            INET6_ADDRSTRLEN),
                    841:                            if_indextoname(pi->ipi6_ifindex, ifnamebuf), i);
                    842:                        return;
                    843:                }
1.30      rpaulo    844:                rs_input(i, (struct nd_router_solicit *)icp, pi, &rcvfrom);
1.14      itojun    845:                break;
                    846:        case ND_ROUTER_ADVERT:
                    847:                /*
                    848:                 * Message verification - RFC-2461 6.1.2
                    849:                 * XXX: there's a same dilemma as above...
                    850:                 */
                    851:                if (*hlimp != 255) {
                    852:                        syslog(LOG_NOTICE,
                    853:                            "<%s> RA with invalid hop limit(%d) "
                    854:                            "received from %s on %s",
1.21      itojun    855:                            __func__, *hlimp,
1.30      rpaulo    856:                            inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
1.14      itojun    857:                            INET6_ADDRSTRLEN),
                    858:                            if_indextoname(pi->ipi6_ifindex, ifnamebuf));
                    859:                        return;
                    860:                }
                    861:                if (icp->icmp6_code) {
                    862:                        syslog(LOG_NOTICE,
                    863:                            "<%s> RA with invalid ICMP6 code(%d) "
                    864:                            "received from %s on %s",
1.21      itojun    865:                            __func__, icp->icmp6_code,
1.30      rpaulo    866:                            inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
1.14      itojun    867:                            INET6_ADDRSTRLEN),
                    868:                            if_indextoname(pi->ipi6_ifindex, ifnamebuf));
                    869:                        return;
                    870:                }
1.36      roy       871:                if ((size_t)i < sizeof(struct nd_router_advert)) {
1.14      itojun    872:                        syslog(LOG_NOTICE,
                    873:                            "<%s> RA from %s on %s does not have enough "
1.36      roy       874:                            "length (len = %zd)",
1.21      itojun    875:                            __func__,
1.30      rpaulo    876:                            inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
1.14      itojun    877:                            INET6_ADDRSTRLEN),
                    878:                            if_indextoname(pi->ipi6_ifindex, ifnamebuf), i);
                    879:                        return;
                    880:                }
1.30      rpaulo    881:                ra_input(i, (struct nd_router_advert *)icp, pi, &rcvfrom);
1.14      itojun    882:                break;
                    883:        case ICMP6_ROUTER_RENUMBERING:
                    884:                if (accept_rr == 0) {
                    885:                        syslog(LOG_ERR, "<%s> received a router renumbering "
                    886:                            "message, but not allowed to be accepted",
1.21      itojun    887:                            __func__);
1.14      itojun    888:                        break;
                    889:                }
1.30      rpaulo    890:                rr_input(i, (struct icmp6_router_renum *)icp, pi, &rcvfrom,
1.14      itojun    891:                         &dst);
                    892:                break;
                    893:        default:
                    894:                /*
                    895:                 * Note that this case is POSSIBLE, especially just
                    896:                 * after invocation of the daemon. This is because we
                    897:                 * could receive message after opening the socket and
                    898:                 * before setting ICMP6 type filter(see sock_open()).
                    899:                 */
                    900:                syslog(LOG_ERR, "<%s> invalid icmp type(%d)",
1.21      itojun    901:                    __func__, icp->icmp6_type);
1.14      itojun    902:                return;
1.1       itojun    903:        }
                    904:
                    905:        return;
                    906: }
                    907:
                    908: static void
                    909: rs_input(int len, struct nd_router_solicit *rs,
                    910:         struct in6_pktinfo *pi, struct sockaddr_in6 *from)
                    911: {
1.31      mrg       912:        char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
1.1       itojun    913:        union nd_opts ndopts;
1.39      roy       914:        struct rainfo *rai;
1.30      rpaulo    915:        struct soliciter *sol;
1.1       itojun    916:
                    917:        syslog(LOG_DEBUG,
                    918:               "<%s> RS received from %s on %s",
1.21      itojun    919:               __func__,
1.1       itojun    920:               inet_ntop(AF_INET6, &from->sin6_addr,
                    921:                         ntopbuf, INET6_ADDRSTRLEN),
                    922:               if_indextoname(pi->ipi6_ifindex, ifnamebuf));
                    923:
                    924:        /* ND option check */
                    925:        memset(&ndopts, 0, sizeof(ndopts));
1.36      roy       926:        TAILQ_INIT(&ndopts.nd_opts_list);
1.1       itojun    927:        if (nd6_options((struct nd_opt_hdr *)(rs + 1),
                    928:                        len - sizeof(struct nd_router_solicit),
1.18      itojun    929:                        &ndopts, NDOPT_FLAG_SRCLINKADDR)) {
1.30      rpaulo    930:                syslog(LOG_INFO,
1.1       itojun    931:                       "<%s> ND option check failed for an RS from %s on %s",
1.21      itojun    932:                       __func__,
1.1       itojun    933:                       inet_ntop(AF_INET6, &from->sin6_addr,
                    934:                                 ntopbuf, INET6_ADDRSTRLEN),
                    935:                       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
                    936:                return;
                    937:        }
                    938:
                    939:        /*
                    940:         * If the IP source address is the unspecified address, there
                    941:         * must be no source link-layer address option in the message.
                    942:         * (RFC-2461 6.1.1)
                    943:         */
                    944:        if (IN6_IS_ADDR_UNSPECIFIED(&from->sin6_addr) &&
                    945:            ndopts.nd_opts_src_lladdr) {
1.30      rpaulo    946:                syslog(LOG_INFO,
1.1       itojun    947:                       "<%s> RS from unspecified src on %s has a link-layer"
                    948:                       " address option",
1.21      itojun    949:                       __func__,
1.1       itojun    950:                       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
                    951:                goto done;
                    952:        }
                    953:
1.39      roy       954:        if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == NULL) {
1.1       itojun    955:                syslog(LOG_INFO,
                    956:                       "<%s> RS received on non advertising interface(%s)",
1.21      itojun    957:                       __func__,
1.1       itojun    958:                       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
                    959:                goto done;
                    960:        }
                    961:
1.39      roy       962:        if (rai->leaving) {
                    963:                syslog(LOG_INFO,
                    964:                       "<%s> RS received on reconfiguring advertising interface(%s)",
                    965:                       __func__, rai->ifname);
                    966:                goto done;
                    967:        }
                    968:
                    969:        rai->rsinput++;         /* increment statistics */
1.9       itojun    970:
1.1       itojun    971:        /*
                    972:         * Decide whether to send RA according to the rate-limit
                    973:         * consideration.
                    974:         */
1.10      itojun    975:
1.30      rpaulo    976:        /* record sockaddr waiting for RA, if possible */
1.36      roy       977:        sol = malloc(sizeof(*sol));
1.30      rpaulo    978:        if (sol) {
                    979:                sol->addr = *from;
                    980:                /* XXX RFC2553 need clarification on flowinfo */
                    981:                sol->addr.sin6_flowinfo = 0;
1.39      roy       982:                TAILQ_INSERT_HEAD(&rai->soliciter, sol, next);
1.30      rpaulo    983:        }
                    984:
                    985:        /*
                    986:         * If there is already a waiting RS packet, don't
                    987:         * update the timer.
                    988:         */
1.39      roy       989:        if (rai->waiting++)
1.30      rpaulo    990:                goto done;
                    991:
1.39      roy       992:        ra_timer_set_short_delay(rai);
1.1       itojun    993:
1.30      rpaulo    994: done:
                    995:        free_ndopts(&ndopts);
                    996:        return;
                    997: }
1.1       itojun    998:
1.39      roy       999: void
                   1000: ra_timer_set_short_delay(struct rainfo *rai)
1.30      rpaulo   1001: {
                   1002:        long delay;     /* must not be greater than 1000000 */
1.47      roy      1003:        struct timespec interval, now, min_delay, tm_tmp, *rest;
1.1       itojun   1004:
1.30      rpaulo   1005:        /*
                   1006:         * Compute a random delay. If the computed value
                   1007:         * corresponds to a time later than the time the next
                   1008:         * multicast RA is scheduled to be sent, ignore the random
                   1009:         * delay and send the advertisement at the
                   1010:         * already-scheduled time. RFC2461 6.2.6
                   1011:         */
                   1012:        delay = arc4random() % MAX_RA_DELAY_TIME;
                   1013:        interval.tv_sec = 0;
1.47      roy      1014:        interval.tv_nsec = delay;
1.30      rpaulo   1015:        rest = rtadvd_timer_rest(rai->timer);
1.47      roy      1016:        if (timespeccmp(rest, &interval, <)) {
1.30      rpaulo   1017:                syslog(LOG_DEBUG, "<%s> random delay is larger than "
                   1018:                    "the rest of current timer", __func__);
                   1019:                interval = *rest;
1.1       itojun   1020:        }
                   1021:
1.30      rpaulo   1022:        /*
                   1023:         * If we sent a multicast Router Advertisement within
                   1024:         * the last MIN_DELAY_BETWEEN_RAS seconds, schedule
                   1025:         * the advertisement to be sent at a time corresponding to
                   1026:         * MIN_DELAY_BETWEEN_RAS plus the random value after the
                   1027:         * previous advertisement was sent.
                   1028:         */
1.51      ozaki-r  1029:        prog_clock_gettime(CLOCK_MONOTONIC, &now);
1.47      roy      1030:        timespecsub(&now, &rai->lastsent, &tm_tmp);
1.30      rpaulo   1031:        min_delay.tv_sec = MIN_DELAY_BETWEEN_RAS;
1.47      roy      1032:        min_delay.tv_nsec = 0;
                   1033:        if (timespeccmp(&tm_tmp, &min_delay, <)) {
                   1034:                timespecsub(&min_delay, &tm_tmp, &min_delay);
                   1035:                timespecadd(&min_delay, &interval, &interval);
1.30      rpaulo   1036:        }
                   1037:        rtadvd_set_timer(&interval, rai->timer);
1.1       itojun   1038: }
                   1039:
                   1040: static void
                   1041: ra_input(int len, struct nd_router_advert *ra,
                   1042:         struct in6_pktinfo *pi, struct sockaddr_in6 *from)
                   1043: {
                   1044:        struct rainfo *rai;
1.31      mrg      1045:        char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
1.1       itojun   1046:        union nd_opts ndopts;
1.36      roy      1047:        const char *on_off[] = {"OFF", "ON"};
                   1048:        uint32_t reachabletime, retranstimer, mtu;
                   1049:        struct nd_optlist *optp;
1.9       itojun   1050:        int inconsistent = 0;
1.1       itojun   1051:
                   1052:        syslog(LOG_DEBUG,
                   1053:               "<%s> RA received from %s on %s",
1.21      itojun   1054:               __func__,
1.1       itojun   1055:               inet_ntop(AF_INET6, &from->sin6_addr,
                   1056:                         ntopbuf, INET6_ADDRSTRLEN),
                   1057:               if_indextoname(pi->ipi6_ifindex, ifnamebuf));
1.36      roy      1058:
1.1       itojun   1059:        /* ND option check */
                   1060:        memset(&ndopts, 0, sizeof(ndopts));
1.36      roy      1061:        TAILQ_INIT(&ndopts.nd_opts_list);
1.1       itojun   1062:        if (nd6_options((struct nd_opt_hdr *)(ra + 1),
1.36      roy      1063:            len - sizeof(struct nd_router_advert),
                   1064:            &ndopts, NDOPT_FLAG_SRCLINKADDR |
                   1065:            NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU |
                   1066:            NDOPT_FLAG_RDNSS | NDOPT_FLAG_DNSSL))
                   1067:        {
1.30      rpaulo   1068:                syslog(LOG_INFO,
1.36      roy      1069:                    "<%s> ND option check failed for an RA from %s on %s",
                   1070:                    __func__,
                   1071:                    inet_ntop(AF_INET6, &from->sin6_addr,
                   1072:                        ntopbuf, INET6_ADDRSTRLEN),
                   1073:                        if_indextoname(pi->ipi6_ifindex, ifnamebuf));
1.1       itojun   1074:                return;
                   1075:        }
                   1076:
                   1077:        /*
                   1078:         * RA consistency check according to RFC-2461 6.2.7
                   1079:         */
                   1080:        if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == 0) {
                   1081:                syslog(LOG_INFO,
                   1082:                       "<%s> received RA from %s on non-advertising"
                   1083:                       " interface(%s)",
1.21      itojun   1084:                       __func__,
1.1       itojun   1085:                       inet_ntop(AF_INET6, &from->sin6_addr,
                   1086:                                 ntopbuf, INET6_ADDRSTRLEN),
                   1087:                       if_indextoname(pi->ipi6_ifindex, ifnamebuf));
                   1088:                goto done;
                   1089:        }
1.39      roy      1090:        if (rai->leaving) {
                   1091:                syslog(LOG_DEBUG,
1.45      plunky   1092:                       "<%s> received RA on re-configuring interface (%s)",
1.39      roy      1093:                        __func__, rai->ifname);
                   1094:                goto done;
                   1095:        }
1.9       itojun   1096:        rai->rainput++;         /* increment statistics */
                   1097:
1.1       itojun   1098:        /* Cur Hop Limit value */
                   1099:        if (ra->nd_ra_curhoplimit && rai->hoplimit &&
                   1100:            ra->nd_ra_curhoplimit != rai->hoplimit) {
1.11      itojun   1101:                syslog(LOG_INFO,
1.1       itojun   1102:                       "<%s> CurHopLimit inconsistent on %s:"
                   1103:                       " %d from %s, %d from us",
1.21      itojun   1104:                       __func__,
1.1       itojun   1105:                       rai->ifname,
                   1106:                       ra->nd_ra_curhoplimit,
                   1107:                       inet_ntop(AF_INET6, &from->sin6_addr,
                   1108:                                 ntopbuf, INET6_ADDRSTRLEN),
                   1109:                       rai->hoplimit);
1.9       itojun   1110:                inconsistent++;
1.1       itojun   1111:        }
                   1112:        /* M flag */
                   1113:        if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) !=
                   1114:            rai->managedflg) {
1.11      itojun   1115:                syslog(LOG_INFO,
1.1       itojun   1116:                       "<%s> M flag inconsistent on %s:"
                   1117:                       " %s from %s, %s from us",
1.21      itojun   1118:                       __func__,
1.1       itojun   1119:                       rai->ifname,
                   1120:                       on_off[!rai->managedflg],
                   1121:                       inet_ntop(AF_INET6, &from->sin6_addr,
                   1122:                                 ntopbuf, INET6_ADDRSTRLEN),
                   1123:                       on_off[rai->managedflg]);
1.9       itojun   1124:                inconsistent++;
1.1       itojun   1125:        }
                   1126:        /* O flag */
                   1127:        if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) !=
                   1128:            rai->otherflg) {
1.11      itojun   1129:                syslog(LOG_INFO,
1.1       itojun   1130:                       "<%s> O flag inconsistent on %s:"
                   1131:                       " %s from %s, %s from us",
1.21      itojun   1132:                       __func__,
1.1       itojun   1133:                       rai->ifname,
                   1134:                       on_off[!rai->otherflg],
                   1135:                       inet_ntop(AF_INET6, &from->sin6_addr,
                   1136:                                 ntopbuf, INET6_ADDRSTRLEN),
                   1137:                       on_off[rai->otherflg]);
1.9       itojun   1138:                inconsistent++;
1.1       itojun   1139:        }
                   1140:        /* Reachable Time */
                   1141:        reachabletime = ntohl(ra->nd_ra_reachable);
                   1142:        if (reachabletime && rai->reachabletime &&
                   1143:            reachabletime != rai->reachabletime) {
1.11      itojun   1144:                syslog(LOG_INFO,
1.1       itojun   1145:                       "<%s> ReachableTime inconsistent on %s:"
                   1146:                       " %d from %s, %d from us",
1.21      itojun   1147:                       __func__,
1.1       itojun   1148:                       rai->ifname,
                   1149:                       reachabletime,
                   1150:                       inet_ntop(AF_INET6, &from->sin6_addr,
                   1151:                                 ntopbuf, INET6_ADDRSTRLEN),
                   1152:                       rai->reachabletime);
1.9       itojun   1153:                inconsistent++;
1.1       itojun   1154:        }
                   1155:        /* Retrans Timer */
                   1156:        retranstimer = ntohl(ra->nd_ra_retransmit);
                   1157:        if (retranstimer && rai->retranstimer &&
                   1158:            retranstimer != rai->retranstimer) {
1.11      itojun   1159:                syslog(LOG_INFO,
1.1       itojun   1160:                       "<%s> RetranceTimer inconsistent on %s:"
                   1161:                       " %d from %s, %d from us",
1.21      itojun   1162:                       __func__,
1.1       itojun   1163:                       rai->ifname,
                   1164:                       retranstimer,
                   1165:                       inet_ntop(AF_INET6, &from->sin6_addr,
                   1166:                                 ntopbuf, INET6_ADDRSTRLEN),
                   1167:                       rai->retranstimer);
1.9       itojun   1168:                inconsistent++;
1.1       itojun   1169:        }
                   1170:        /* Values in the MTU options */
                   1171:        if (ndopts.nd_opts_mtu) {
                   1172:                mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
                   1173:                if (mtu && rai->linkmtu && mtu != rai->linkmtu) {
1.11      itojun   1174:                        syslog(LOG_INFO,
1.1       itojun   1175:                               "<%s> MTU option value inconsistent on %s:"
                   1176:                               " %d from %s, %d from us",
1.21      itojun   1177:                               __func__,
1.1       itojun   1178:                               rai->ifname, mtu,
                   1179:                               inet_ntop(AF_INET6, &from->sin6_addr,
                   1180:                                         ntopbuf, INET6_ADDRSTRLEN),
                   1181:                               rai->linkmtu);
1.9       itojun   1182:                        inconsistent++;
1.1       itojun   1183:                }
                   1184:        }
                   1185:        /* Preferred and Valid Lifetimes for prefixes */
1.36      roy      1186:        if (ndopts.nd_opts_pi)
                   1187:                if (prefix_check(ndopts.nd_opts_pi, rai, from))
                   1188:                        inconsistent++;
                   1189:        TAILQ_FOREACH(optp, &ndopts.nd_opts_list, next)
                   1190:                if (prefix_check((struct nd_opt_prefix_info *)optp->opt,
                   1191:                    rai, from))
                   1192:                        inconsistent++;
1.9       itojun   1193:
1.11      itojun   1194:        if (inconsistent)
1.9       itojun   1195:                rai->rainconsistent++;
1.1       itojun   1196:
1.30      rpaulo   1197: done:
1.1       itojun   1198:        free_ndopts(&ndopts);
                   1199:        return;
                   1200: }
                   1201:
1.9       itojun   1202: /* return a non-zero value if the received prefix is inconsitent with ours */
                   1203: static int
1.1       itojun   1204: prefix_check(struct nd_opt_prefix_info *pinfo,
                   1205:             struct rainfo *rai, struct sockaddr_in6 *from)
                   1206: {
1.36      roy      1207:        uint32_t preferred_time, valid_time;
1.1       itojun   1208:        struct prefix *pp;
1.9       itojun   1209:        int inconsistent = 0;
1.31      mrg      1210:        char ntopbuf[INET6_ADDRSTRLEN], prefixbuf[INET6_ADDRSTRLEN];
1.47      roy      1211:        struct timespec now;
1.1       itojun   1212:
                   1213: #if 0                          /* impossible */
                   1214:        if (pinfo->nd_opt_pi_type != ND_OPT_PREFIX_INFORMATION)
1.9       itojun   1215:                return(0);
1.1       itojun   1216: #endif
                   1217:
                   1218:        /*
                   1219:         * log if the adveritsed prefix has link-local scope(sanity check?)
                   1220:         */
                   1221:        if (IN6_IS_ADDR_LINKLOCAL(&pinfo->nd_opt_pi_prefix)) {
                   1222:                syslog(LOG_INFO,
                   1223:                       "<%s> link-local prefix %s/%d is advertised "
                   1224:                       "from %s on %s",
1.21      itojun   1225:                       __func__,
1.1       itojun   1226:                       inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
                   1227:                                 prefixbuf, INET6_ADDRSTRLEN),
                   1228:                       pinfo->nd_opt_pi_prefix_len,
                   1229:                       inet_ntop(AF_INET6, &from->sin6_addr,
                   1230:                                 ntopbuf, INET6_ADDRSTRLEN),
                   1231:                       rai->ifname);
                   1232:        }
                   1233:
                   1234:        if ((pp = find_prefix(rai, &pinfo->nd_opt_pi_prefix,
                   1235:                              pinfo->nd_opt_pi_prefix_len)) == NULL) {
                   1236:                syslog(LOG_INFO,
                   1237:                       "<%s> prefix %s/%d from %s on %s is not in our list",
1.21      itojun   1238:                       __func__,
1.1       itojun   1239:                       inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
                   1240:                                 prefixbuf, INET6_ADDRSTRLEN),
                   1241:                       pinfo->nd_opt_pi_prefix_len,
                   1242:                       inet_ntop(AF_INET6, &from->sin6_addr,
                   1243:                                 ntopbuf, INET6_ADDRSTRLEN),
                   1244:                       rai->ifname);
1.9       itojun   1245:                return(0);
1.1       itojun   1246:        }
                   1247:
                   1248:        preferred_time = ntohl(pinfo->nd_opt_pi_preferred_time);
1.11      itojun   1249:        if (pp->pltimeexpire) {
                   1250:                /*
                   1251:                 * The lifetime is decremented in real time, so we should
                   1252:                 * compare the expiration time.
                   1253:                 * (RFC 2461 Section 6.2.7.)
                   1254:                 * XXX: can we really expect that all routers on the link
                   1255:                 * have synchronized clocks?
                   1256:                 */
1.51      ozaki-r  1257:                prog_clock_gettime(CLOCK_MONOTONIC, &now);
1.11      itojun   1258:                preferred_time += now.tv_sec;
                   1259:
1.30      rpaulo   1260:                if (!pp->timer && rai->clockskew &&
1.46      joerg    1261:                    llabs((long long)preferred_time - pp->pltimeexpire) > rai->clockskew) {
1.11      itojun   1262:                        syslog(LOG_INFO,
1.30      rpaulo   1263:                               "<%s> preferred lifetime for %s/%d"
1.11      itojun   1264:                               " (decr. in real time) inconsistent on %s:"
                   1265:                               " %d from %s, %ld from us",
1.21      itojun   1266:                               __func__,
1.11      itojun   1267:                               inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
                   1268:                                         prefixbuf, INET6_ADDRSTRLEN),
                   1269:                               pinfo->nd_opt_pi_prefix_len,
                   1270:                               rai->ifname, preferred_time,
                   1271:                               inet_ntop(AF_INET6, &from->sin6_addr,
                   1272:                                         ntopbuf, INET6_ADDRSTRLEN),
                   1273:                               pp->pltimeexpire);
                   1274:                        inconsistent++;
                   1275:                }
1.30      rpaulo   1276:        } else if (!pp->timer && preferred_time != pp->preflifetime) {
1.11      itojun   1277:                syslog(LOG_INFO,
1.30      rpaulo   1278:                       "<%s> preferred lifetime for %s/%d"
1.1       itojun   1279:                       " inconsistent on %s:"
                   1280:                       " %d from %s, %d from us",
1.21      itojun   1281:                       __func__,
1.1       itojun   1282:                       inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
                   1283:                                 prefixbuf, INET6_ADDRSTRLEN),
                   1284:                       pinfo->nd_opt_pi_prefix_len,
                   1285:                       rai->ifname, preferred_time,
                   1286:                       inet_ntop(AF_INET6, &from->sin6_addr,
                   1287:                                 ntopbuf, INET6_ADDRSTRLEN),
                   1288:                       pp->preflifetime);
1.9       itojun   1289:        }
1.1       itojun   1290:
                   1291:        valid_time = ntohl(pinfo->nd_opt_pi_valid_time);
1.11      itojun   1292:        if (pp->vltimeexpire) {
1.51      ozaki-r  1293:                prog_clock_gettime(CLOCK_MONOTONIC, &now);
1.11      itojun   1294:                valid_time += now.tv_sec;
                   1295:
1.30      rpaulo   1296:                if (!pp->timer && rai->clockskew &&
1.46      joerg    1297:                    llabs((long long)valid_time - pp->vltimeexpire) > rai->clockskew) {
1.11      itojun   1298:                        syslog(LOG_INFO,
                   1299:                               "<%s> valid lifetime for %s/%d"
                   1300:                               " (decr. in real time) inconsistent on %s:"
                   1301:                               " %d from %s, %ld from us",
1.21      itojun   1302:                               __func__,
1.11      itojun   1303:                               inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
                   1304:                                         prefixbuf, INET6_ADDRSTRLEN),
                   1305:                               pinfo->nd_opt_pi_prefix_len,
                   1306:                               rai->ifname, preferred_time,
                   1307:                               inet_ntop(AF_INET6, &from->sin6_addr,
                   1308:                                         ntopbuf, INET6_ADDRSTRLEN),
                   1309:                               pp->vltimeexpire);
                   1310:                        inconsistent++;
                   1311:                }
1.30      rpaulo   1312:        } else if (!pp->timer && valid_time != pp->validlifetime) {
1.11      itojun   1313:                syslog(LOG_INFO,
1.1       itojun   1314:                       "<%s> valid lifetime for %s/%d"
                   1315:                       " inconsistent on %s:"
                   1316:                       " %d from %s, %d from us",
1.21      itojun   1317:                       __func__,
1.1       itojun   1318:                       inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
                   1319:                                 prefixbuf, INET6_ADDRSTRLEN),
                   1320:                       pinfo->nd_opt_pi_prefix_len,
                   1321:                       rai->ifname, valid_time,
                   1322:                       inet_ntop(AF_INET6, &from->sin6_addr,
                   1323:                                 ntopbuf, INET6_ADDRSTRLEN),
                   1324:                       pp->validlifetime);
1.9       itojun   1325:                inconsistent++;
                   1326:        }
                   1327:
                   1328:        return(inconsistent);
1.1       itojun   1329: }
                   1330:
                   1331: struct prefix *
                   1332: find_prefix(struct rainfo *rai, struct in6_addr *prefix, int plen)
                   1333: {
                   1334:        struct prefix *pp;
                   1335:        int bytelen, bitlen;
1.36      roy      1336:        unsigned char bitmask;
1.1       itojun   1337:
1.36      roy      1338:        TAILQ_FOREACH(pp, &rai->prefix, next) {
1.1       itojun   1339:                if (plen != pp->prefixlen)
                   1340:                        continue;
                   1341:                bytelen = plen / 8;
                   1342:                bitlen = plen % 8;
1.15      itojun   1343:                bitmask = 0xff << (8 - bitlen);
1.1       itojun   1344:                if (memcmp((void *)prefix, (void *)&pp->prefix, bytelen))
                   1345:                        continue;
1.15      itojun   1346:                if (bitlen == 0 ||
                   1347:                    ((prefix->s6_addr[bytelen] & bitmask) ==
                   1348:                     (pp->prefix.s6_addr[bytelen] & bitmask))) {
1.1       itojun   1349:                        return(pp);
1.15      itojun   1350:                }
1.1       itojun   1351:        }
                   1352:
                   1353:        return(NULL);
                   1354: }
                   1355:
1.11      itojun   1356: /* check if p0/plen0 matches p1/plen1; return 1 if matches, otherwise 0. */
                   1357: int
                   1358: prefix_match(struct in6_addr *p0, int plen0,
                   1359:             struct in6_addr *p1, int plen1)
                   1360: {
                   1361:        int bytelen, bitlen;
1.36      roy      1362:        unsigned char bitmask;
1.11      itojun   1363:
                   1364:        if (plen0 < plen1)
                   1365:                return(0);
                   1366:        bytelen = plen1 / 8;
                   1367:        bitlen = plen1 % 8;
1.15      itojun   1368:        bitmask = 0xff << (8 - bitlen);
1.11      itojun   1369:        if (memcmp((void *)p0, (void *)p1, bytelen))
                   1370:                return(0);
1.15      itojun   1371:        if (bitlen == 0 ||
                   1372:            ((p0->s6_addr[bytelen] & bitmask) ==
                   1373:             (p1->s6_addr[bytelen] & bitmask))) {
1.11      itojun   1374:                return(1);
1.15      itojun   1375:        }
1.11      itojun   1376:
                   1377:        return(0);
                   1378: }
                   1379:
1.1       itojun   1380: static int
                   1381: nd6_options(struct nd_opt_hdr *hdr, int limit,
1.36      roy      1382:            union nd_opts *ndopts, uint32_t optflags)
1.1       itojun   1383: {
                   1384:        int optlen = 0;
                   1385:
                   1386:        for (; limit > 0; limit -= optlen) {
1.36      roy      1387:                if ((size_t)limit < sizeof(struct nd_opt_hdr)) {
1.27      itojun   1388:                        syslog(LOG_INFO, "<%s> short option header", __func__);
                   1389:                        goto bad;
                   1390:                }
                   1391:
1.36      roy      1392:                hdr = (struct nd_opt_hdr *)((char *)hdr + optlen);
1.1       itojun   1393:                if (hdr->nd_opt_len == 0) {
1.30      rpaulo   1394:                        syslog(LOG_INFO,
1.14      itojun   1395:                            "<%s> bad ND option length(0) (type = %d)",
1.21      itojun   1396:                            __func__, hdr->nd_opt_type);
1.1       itojun   1397:                        goto bad;
                   1398:                }
1.27      itojun   1399:                optlen = hdr->nd_opt_len << 3;
                   1400:                if (optlen > limit) {
                   1401:                        syslog(LOG_INFO, "<%s> short option", __func__);
                   1402:                        goto bad;
                   1403:                }
1.1       itojun   1404:
1.36      roy      1405:                if (hdr->nd_opt_type > ND_OPT_MTU &&
                   1406:                    hdr->nd_opt_type != ND_OPT_RDNSS &&
                   1407:                    hdr->nd_opt_type != ND_OPT_DNSSL)
1.17      itojun   1408:                {
1.14      itojun   1409:                        syslog(LOG_INFO, "<%s> unknown ND option(type %d)",
1.21      itojun   1410:                            __func__, hdr->nd_opt_type);
1.1       itojun   1411:                        continue;
                   1412:                }
                   1413:
                   1414:                if ((ndopt_flags[hdr->nd_opt_type] & optflags) == 0) {
1.14      itojun   1415:                        syslog(LOG_INFO, "<%s> unexpected ND option(type %d)",
1.21      itojun   1416:                            __func__, hdr->nd_opt_type);
1.1       itojun   1417:                        continue;
                   1418:                }
                   1419:
1.27      itojun   1420:                /*
                   1421:                 * Option length check.  Do it here for all fixed-length
                   1422:                 * options.
                   1423:                 */
                   1424:                if ((hdr->nd_opt_type == ND_OPT_MTU &&
                   1425:                    (optlen != sizeof(struct nd_opt_mtu))) ||
                   1426:                    ((hdr->nd_opt_type == ND_OPT_PREFIX_INFORMATION &&
1.42      roy      1427:                    optlen != sizeof(struct nd_opt_prefix_info))) ||
                   1428:                    (hdr->nd_opt_type == ND_OPT_RDNSS &&
                   1429:                    ((optlen < (int)sizeof(struct nd_opt_rdnss) ||
                   1430:                    (optlen - sizeof(struct nd_opt_rdnss)) % 16 != 0))) ||
                   1431:                    (hdr->nd_opt_type == ND_OPT_DNSSL &&
                   1432:                    optlen < (int)sizeof(struct nd_opt_dnssl)))
                   1433:                {
1.27      itojun   1434:                        syslog(LOG_INFO, "<%s> invalid option length",
                   1435:                            __func__);
                   1436:                        continue;
                   1437:                }
                   1438:
1.14      itojun   1439:                switch (hdr->nd_opt_type) {
                   1440:                case ND_OPT_TARGET_LINKADDR:
                   1441:                case ND_OPT_REDIRECTED_HEADER:
1.42      roy      1442:                case ND_OPT_RDNSS:
                   1443:                case ND_OPT_DNSSL:
1.27      itojun   1444:                        break;  /* we don't care about these options */
1.30      rpaulo   1445:                case ND_OPT_SOURCE_LINKADDR:
1.14      itojun   1446:                case ND_OPT_MTU:
                   1447:                        if (ndopts->nd_opt_array[hdr->nd_opt_type]) {
                   1448:                                syslog(LOG_INFO,
                   1449:                                    "<%s> duplicated ND option (type = %d)",
1.21      itojun   1450:                                    __func__, hdr->nd_opt_type);
1.14      itojun   1451:                        }
                   1452:                        ndopts->nd_opt_array[hdr->nd_opt_type] = hdr;
                   1453:                        break;
                   1454:                case ND_OPT_PREFIX_INFORMATION:
                   1455:                {
                   1456:                        struct nd_optlist *pfxlist;
                   1457:
                   1458:                        if (ndopts->nd_opts_pi == 0) {
                   1459:                                ndopts->nd_opts_pi =
                   1460:                                    (struct nd_opt_prefix_info *)hdr;
                   1461:                                continue;
                   1462:                        }
                   1463:                        if ((pfxlist = malloc(sizeof(*pfxlist))) == NULL) {
                   1464:                                syslog(LOG_ERR, "<%s> can't allocate memory",
1.21      itojun   1465:                                    __func__);
1.14      itojun   1466:                                goto bad;
                   1467:                        }
                   1468:                        pfxlist->opt = hdr;
1.36      roy      1469:                        TAILQ_INSERT_TAIL(&ndopts->nd_opts_list, pfxlist, next);
1.14      itojun   1470:
                   1471:                        break;
                   1472:                }
                   1473:                default:        /* impossible */
                   1474:                        break;
1.1       itojun   1475:                }
                   1476:        }
                   1477:
                   1478:        return(0);
                   1479:
                   1480:   bad:
                   1481:        free_ndopts(ndopts);
                   1482:
                   1483:        return(-1);
                   1484: }
                   1485:
                   1486: static void
                   1487: free_ndopts(union nd_opts *ndopts)
                   1488: {
1.36      roy      1489:        struct nd_optlist *opt;
1.1       itojun   1490:
1.36      roy      1491:        while ((opt = TAILQ_FIRST(&ndopts->nd_opts_list)) != NULL) {
                   1492:                TAILQ_REMOVE(&ndopts->nd_opts_list, opt, next);
1.1       itojun   1493:                free(opt);
                   1494:        }
                   1495: }
                   1496:
                   1497: void
1.36      roy      1498: sock_open(void)
1.1       itojun   1499: {
                   1500:        struct icmp6_filter filt;
                   1501:        struct ipv6_mreq mreq;
1.36      roy      1502:        struct rainfo *ra;
1.1       itojun   1503:        int on;
                   1504:        /* XXX: should be max MTU attached to the node */
1.36      roy      1505:        static unsigned char answer[1500];
1.6       itojun   1506:
                   1507:        rcvcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
                   1508:                                CMSG_SPACE(sizeof(int));
1.36      roy      1509:        rcvcmsgbuf = malloc(rcvcmsgbuflen);
1.6       itojun   1510:        if (rcvcmsgbuf == NULL) {
1.49      roy      1511:                syslog(LOG_ERR, "<%s> malloc: %m", __func__);
1.6       itojun   1512:                exit(1);
                   1513:        }
                   1514:
1.50      ozaki-r  1515:        sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo));
1.36      roy      1516:        sndcmsgbuf = malloc(sndcmsgbuflen);
1.6       itojun   1517:        if (sndcmsgbuf == NULL) {
1.49      roy      1518:                syslog(LOG_ERR, "<%s> malloc: %m", __func__);
1.6       itojun   1519:                exit(1);
                   1520:        }
1.1       itojun   1521:
1.51      ozaki-r  1522:        if ((sock = prog_socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
1.49      roy      1523:                syslog(LOG_ERR, "<%s> socket: %m", __func__);
1.1       itojun   1524:                exit(1);
                   1525:        }
                   1526:
1.48      roy      1527:        /* RFC 4861 Section 4.2 */
                   1528:        on = 255;
1.51      ozaki-r  1529:        if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &on,
1.48      roy      1530:                       sizeof(on)) == -1) {
                   1531:                syslog(LOG_ERR, "<%s> IPV6_MULTICAST_HOPS: %m", __func__);
                   1532:                exit(1);
                   1533:        }
                   1534:
1.1       itojun   1535:        /* specify to tell receiving interface */
                   1536:        on = 1;
1.5       itojun   1537: #ifdef IPV6_RECVPKTINFO
1.51      ozaki-r  1538:        if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
1.5       itojun   1539:                       sizeof(on)) < 0) {
1.49      roy      1540:                syslog(LOG_ERR, "<%s> IPV6_RECVPKTINFO: %m", __func__);
1.5       itojun   1541:                exit(1);
                   1542:        }
                   1543: #else  /* old adv. API */
1.51      ozaki-r  1544:        if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
1.1       itojun   1545:                       sizeof(on)) < 0) {
1.49      roy      1546:                syslog(LOG_ERR, "<%s> IPV6_PKTINFO: %m", __func__);
1.1       itojun   1547:                exit(1);
                   1548:        }
1.5       itojun   1549: #endif
1.1       itojun   1550:
                   1551:        on = 1;
                   1552:        /* specify to tell value of hoplimit field of received IP6 hdr */
1.5       itojun   1553: #ifdef IPV6_RECVHOPLIMIT
1.51      ozaki-r  1554:        if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
1.5       itojun   1555:                       sizeof(on)) < 0) {
1.49      roy      1556:                syslog(LOG_ERR, "<%s> IPV6_RECVHOPLIMIT: %m", __func__);
1.5       itojun   1557:                exit(1);
                   1558:        }
                   1559: #else  /* old adv. API */
1.51      ozaki-r  1560:        if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
1.1       itojun   1561:                       sizeof(on)) < 0) {
1.49      roy      1562:                syslog(LOG_ERR, "<%s> IPV6_HOPLIMIT: %m", __func__);
1.1       itojun   1563:                exit(1);
                   1564:        }
1.11      itojun   1565: #endif
1.1       itojun   1566:
                   1567:        ICMP6_FILTER_SETBLOCKALL(&filt);
                   1568:        ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt);
                   1569:        ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
                   1570:        if (accept_rr)
                   1571:                ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt);
1.51      ozaki-r  1572:        if (prog_setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
1.1       itojun   1573:                       sizeof(filt)) < 0) {
1.49      roy      1574:                syslog(LOG_ERR, "<%s> IICMP6_FILTER: %m", __func__);
1.1       itojun   1575:                exit(1);
                   1576:        }
                   1577:
                   1578:        /*
                   1579:         * join all routers multicast address on each advertising interface.
                   1580:         */
1.11      itojun   1581:        if (inet_pton(AF_INET6, ALLROUTERS_LINK,
1.36      roy      1582:            mreq.ipv6mr_multiaddr.s6_addr) != 1)
                   1583:        {
1.1       itojun   1584:                syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)",
1.36      roy      1585:                    __func__);
1.1       itojun   1586:                exit(1);
                   1587:        }
1.36      roy      1588:        TAILQ_FOREACH(ra, &ralist, next) {
1.1       itojun   1589:                mreq.ipv6mr_interface = ra->ifindex;
1.51      ozaki-r  1590:                if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq,
1.1       itojun   1591:                               sizeof(mreq)) < 0) {
1.49      roy      1592:                        syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP(link) on %s: %m",
                   1593:                               __func__, ra->ifname);
1.1       itojun   1594:                        exit(1);
                   1595:                }
                   1596:        }
1.11      itojun   1597:
                   1598:        /*
                   1599:         * When attending router renumbering, join all-routers site-local
                   1600:         * multicast group.
                   1601:         */
                   1602:        if (accept_rr) {
                   1603:                if (inet_pton(AF_INET6, ALLROUTERS_SITE,
1.36      roy      1604:                     mreq.ipv6mr_multiaddr.s6_addr) != 1)
                   1605:                {
1.11      itojun   1606:                        syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)",
1.36      roy      1607:                            __func__);
1.11      itojun   1608:                        exit(1);
                   1609:                }
1.36      roy      1610:                ra = TAILQ_FIRST(&ralist);
1.11      itojun   1611:                if (mcastif) {
                   1612:                        if ((mreq.ipv6mr_interface = if_nametoindex(mcastif))
                   1613:                            == 0) {
                   1614:                                syslog(LOG_ERR,
                   1615:                                       "<%s> invalid interface: %s",
1.21      itojun   1616:                                       __func__, mcastif);
1.11      itojun   1617:                                exit(1);
                   1618:                        }
                   1619:                } else
1.36      roy      1620:                        mreq.ipv6mr_interface = ra->ifindex;
1.51      ozaki-r  1621:                if (prog_setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1.11      itojun   1622:                               &mreq, sizeof(mreq)) < 0) {
                   1623:                        syslog(LOG_ERR,
1.49      roy      1624:                               "<%s> IPV6_JOIN_GROUP(site) on %s: %m",
1.21      itojun   1625:                               __func__,
1.49      roy      1626:                               mcastif ? mcastif : ra->ifname);
1.11      itojun   1627:                        exit(1);
                   1628:                }
                   1629:        }
1.1       itojun   1630:
                   1631:        /* initialize msghdr for receiving packets */
1.36      roy      1632:        rcviov[0].iov_base = answer;
1.1       itojun   1633:        rcviov[0].iov_len = sizeof(answer);
1.36      roy      1634:        rcvmhdr.msg_name = &rcvfrom;
1.30      rpaulo   1635:        rcvmhdr.msg_namelen = sizeof(rcvfrom);
1.1       itojun   1636:        rcvmhdr.msg_iov = rcviov;
                   1637:        rcvmhdr.msg_iovlen = 1;
1.36      roy      1638:        rcvmhdr.msg_control = rcvcmsgbuf;
1.6       itojun   1639:        rcvmhdr.msg_controllen = rcvcmsgbuflen;
1.1       itojun   1640:
                   1641:        /* initialize msghdr for sending packets */
                   1642:        sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
                   1643:        sndmhdr.msg_iov = sndiov;
                   1644:        sndmhdr.msg_iovlen = 1;
1.36      roy      1645:        sndmhdr.msg_control = (void *)sndcmsgbuf;
1.6       itojun   1646:        sndmhdr.msg_controllen = sndcmsgbuflen;
1.1       itojun   1647:
                   1648:        return;
                   1649: }
                   1650:
                   1651: /* open a routing socket to watch the routing table */
                   1652: static void
1.36      roy      1653: rtsock_open(void)
1.1       itojun   1654: {
1.53    ! roy      1655: #ifdef RO_MSGFILTER
        !          1656:        unsigned char msgfilter[] = {
        !          1657:                RTM_ADD, RTM_DELETE,
        !          1658:                RTM_NEWADDR, RTM_DELADDR,
        !          1659: #ifdef RTM_IFANNOUNCE
        !          1660:                RTM_IFANNOUNCE,
        !          1661: #endif
        !          1662:                RTM_IFINFO,
        !          1663:        };
        !          1664: #endif
        !          1665:
1.51      ozaki-r  1666:        if ((rtsock = prog_socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
1.49      roy      1667:                syslog(LOG_ERR, "<%s> socket: %m", __func__);
1.1       itojun   1668:                exit(1);
                   1669:        }
1.53    ! roy      1670: #ifdef RO_MSGFILTER
        !          1671:        if (setsockopt(rtsock, PF_ROUTE, RO_MSGFILTER,
        !          1672:            &msgfilter, sizeof(msgfilter) == -1))
        !          1673:                syslog(LOG_ERR, "<%s> RO_MSGFILTER: %m", __func__);
        !          1674: #endif
1.1       itojun   1675: }
                   1676:
1.11      itojun   1677: struct rainfo *
1.36      roy      1678: if_indextorainfo(unsigned int idx)
1.1       itojun   1679: {
1.36      roy      1680:        struct rainfo *rai;
1.1       itojun   1681:
1.36      roy      1682:        TAILQ_FOREACH(rai, &ralist, next) {
1.35      lukem    1683:                if (rai->ifindex == idx)
1.1       itojun   1684:                        return(rai);
                   1685:        }
                   1686:
                   1687:        return(NULL);           /* search failed */
                   1688: }
                   1689:
1.39      roy      1690: struct rainfo *
                   1691: ra_output(struct rainfo *rai)
1.1       itojun   1692: {
                   1693:        int i;
                   1694:        struct cmsghdr *cm;
                   1695:        struct in6_pktinfo *pi;
1.36      roy      1696:        struct soliciter *sol;
1.10      itojun   1697:
1.39      roy      1698:        if ((rai->ifflags & IFF_UP) == 0) {
1.10      itojun   1699:                syslog(LOG_DEBUG, "<%s> %s is not up, skip sending RA",
1.39      roy      1700:                       __func__, rai->ifname);
                   1701:                return NULL;
1.10      itojun   1702:        }
1.1       itojun   1703:
1.39      roy      1704:        make_packet(rai);       /* XXX: inefficient */
1.11      itojun   1705:
1.36      roy      1706:        sndmhdr.msg_name = (void *)&sin6_linklocal_allnodes;
1.39      roy      1707:        sndmhdr.msg_iov[0].iov_base = (void *)rai->ra_data;
                   1708:        sndmhdr.msg_iov[0].iov_len = rai->ra_datalen;
1.1       itojun   1709:
                   1710:        cm = CMSG_FIRSTHDR(&sndmhdr);
                   1711:        /* specify the outgoing interface */
                   1712:        cm->cmsg_level = IPPROTO_IPV6;
                   1713:        cm->cmsg_type = IPV6_PKTINFO;
                   1714:        cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
                   1715:        pi = (struct in6_pktinfo *)CMSG_DATA(cm);
                   1716:        memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr));       /*XXX*/
1.39      roy      1717:        pi->ipi6_ifindex = rai->ifindex;
1.1       itojun   1718:
                   1719:        syslog(LOG_DEBUG,
                   1720:               "<%s> send RA on %s, # of waitings = %d",
1.39      roy      1721:               __func__, rai->ifname, rai->waiting);
1.1       itojun   1722:
1.51      ozaki-r  1723:        i = prog_sendmsg(sock, &sndmhdr, 0);
1.1       itojun   1724:
1.39      roy      1725:        if (i < 0 || (size_t)i != rai->ra_datalen)  {
1.1       itojun   1726:                if (i < 0) {
1.49      roy      1727:                        syslog(LOG_ERR, "<%s> sendmsg on %s: %m",
                   1728:                               __func__, rai->ifname);
1.1       itojun   1729:                }
                   1730:        }
                   1731:
1.10      itojun   1732:        /*
                   1733:         * unicast advertisements
                   1734:         * XXX commented out.  reason: though spec does not forbit it, unicast
                   1735:         * advert does not really help
                   1736:         */
1.39      roy      1737:        while ((sol = TAILQ_FIRST(&rai->soliciter)) != NULL) {
1.10      itojun   1738: #if 0
1.36      roy      1739:                sndmhdr.msg_name = (void *)&sol->addr;
1.10      itojun   1740:                i = sendmsg(sock, &sndmhdr, 0);
1.39      roy      1741:                if (i < 0 || i != rai->ra_datalen)  {
1.10      itojun   1742:                        if (i < 0) {
                   1743:                                syslog(LOG_ERR,
1.49      roy      1744:                                    "<%s> unicast sendmsg on %s: %m",
                   1745:                                    __func__, rai->ifname);
1.10      itojun   1746:                        }
                   1747:                }
                   1748: #endif
1.39      roy      1749:                TAILQ_REMOVE(&rai->soliciter, sol, next);
1.10      itojun   1750:                free(sol);
                   1751:        }
                   1752:
1.39      roy      1753:        if (rai->leaving_adv > 0) {
                   1754:                if (--(rai->leaving_adv) == 0) {
1.41      roy      1755:                        /* leaving for ourself means we're shutting down */
                   1756:                        if (rai->leaving_for == rai) {
                   1757:                                TAILQ_REMOVE(&ralist, rai, next);
                   1758:                                free_rainfo(rai);
                   1759:                                return NULL;
                   1760:                        }
1.39      roy      1761:                        syslog(LOG_DEBUG,
                   1762:                               "<%s> expired RA,"
                   1763:                               " new config active for interface (%s)",
                   1764:                               __func__, rai->ifname);
                   1765:                        rai->leaving_for->timer = rtadvd_add_timer(ra_timeout,
                   1766:                            ra_timer_update,
                   1767:                            rai->leaving_for, rai->leaving_for);
                   1768:                        ra_timer_set_short_delay(rai->leaving_for);
                   1769:                        rai->leaving_for->leaving = NULL;
                   1770:                        free_rainfo(rai);
                   1771:                        return NULL;
                   1772:                }
                   1773:        }
                   1774:
1.1       itojun   1775:        /* update counter */
1.39      roy      1776:        if (rai->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS)
                   1777:                rai->initcounter++;
                   1778:        rai->raoutput++;
1.1       itojun   1779:
                   1780:        /* update timestamp */
1.51      ozaki-r  1781:        prog_clock_gettime(CLOCK_MONOTONIC, &rai->lastsent);
1.1       itojun   1782:
                   1783:        /* reset waiting conter */
1.39      roy      1784:        rai->waiting = 0;
                   1785:
                   1786:        return rai;
1.1       itojun   1787: }
                   1788:
                   1789: /* process RA timer */
1.30      rpaulo   1790: struct rtadvd_timer *
1.1       itojun   1791: ra_timeout(void *data)
                   1792: {
                   1793:        struct rainfo *rai = (struct rainfo *)data;
                   1794:
                   1795: #ifdef notyet
                   1796:        /* if necessary, reconstruct the packet. */
                   1797: #endif
                   1798:
                   1799:        syslog(LOG_DEBUG,
                   1800:               "<%s> RA timer on %s is expired",
1.21      itojun   1801:               __func__, rai->ifname);
1.1       itojun   1802:
1.39      roy      1803:        if (ra_output(rai))
                   1804:                return(rai->timer);
                   1805:        return NULL;
1.1       itojun   1806: }
                   1807:
                   1808: /* update RA timer */
                   1809: void
1.47      roy      1810: ra_timer_update(void *data, struct timespec *tm)
1.1       itojun   1811: {
                   1812:        struct rainfo *rai = (struct rainfo *)data;
                   1813:        long interval;
                   1814:
                   1815:        /*
                   1816:         * Whenever a multicast advertisement is sent from an interface,
                   1817:         * the timer is reset to a uniformly-distributed random value
                   1818:         * between the interface's configured MinRtrAdvInterval and
1.11      itojun   1819:         * MaxRtrAdvInterval (RFC2461 6.2.4).
1.1       itojun   1820:         */
1.39      roy      1821:        interval = rai->mininterval;
                   1822:        if (rai->mininterval != rai->maxinterval)
                   1823:                interval += arc4random() % (rai->maxinterval-rai->mininterval);
1.1       itojun   1824:
                   1825:        /*
                   1826:         * For the first few advertisements (up to
                   1827:         * MAX_INITIAL_RTR_ADVERTISEMENTS), if the randomly chosen interval
                   1828:         * is greater than MAX_INITIAL_RTR_ADVERT_INTERVAL, the timer
                   1829:         * SHOULD be set to MAX_INITIAL_RTR_ADVERT_INTERVAL instead.
                   1830:         * (RFC-2461 6.2.4)
                   1831:         */
                   1832:        if (rai->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS &&
                   1833:            interval > MAX_INITIAL_RTR_ADVERT_INTERVAL)
                   1834:                interval = MAX_INITIAL_RTR_ADVERT_INTERVAL;
                   1835:
                   1836:        tm->tv_sec = interval;
1.47      roy      1837:        tm->tv_nsec = 0;
1.1       itojun   1838:
                   1839:        syslog(LOG_DEBUG,
                   1840:               "<%s> RA timer on %s is set to %ld:%ld",
1.21      itojun   1841:               __func__, rai->ifname,
1.47      roy      1842:               (long int)tm->tv_sec, (long int)tm->tv_nsec);
1.1       itojun   1843:
                   1844:        return;
                   1845: }

CVSweb <webmaster@jp.NetBSD.org>