]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/rtsold/rtsold.c
MFV ntp 4.2.8p2 (r281348)
[FreeBSD/FreeBSD.git] / usr.sbin / rtsold / rtsold.c
1 /*      $KAME: rtsold.c,v 1.67 2003/05/17 18:16:15 itojun Exp $ */
2
3 /*
4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5  * All rights reserved.
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the project nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  * 
19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * $FreeBSD$
32  */
33
34 #include <sys/types.h>
35 #include <sys/ioctl.h>
36 #include <sys/socket.h>
37 #include <sys/param.h>
38
39 #include <net/if.h>
40 #include <net/if_dl.h>
41
42 #include <netinet/in.h>
43 #include <netinet/icmp6.h>
44 #include <netinet/in_var.h>
45 #include <arpa/inet.h>
46
47 #include <netinet6/nd6.h>
48
49 #include <signal.h>
50 #include <unistd.h>
51 #include <syslog.h>
52 #include <string.h>
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <time.h>
56 #include <errno.h>
57 #include <err.h>
58 #include <stdarg.h>
59 #include <ifaddrs.h>
60 #ifdef HAVE_POLL_H
61 #include <poll.h>
62 #endif
63
64 #include "rtsold.h"
65
66 #define RTSOL_DUMPFILE  "/var/run/rtsold.dump";
67 #define RTSOL_PIDFILE   "/var/run/rtsold.pid";
68
69 struct timespec tm_max;
70 static int log_upto = 999;
71 static int fflag = 0;
72
73 int Fflag = 0;  /* force setting sysctl parameters */
74 int aflag = 0;
75 int dflag = 0;
76 int uflag = 0;
77
78 const char *otherconf_script;
79 const char *resolvconf_script = "/sbin/resolvconf";
80
81 /* protocol constants */
82 #define MAX_RTR_SOLICITATION_DELAY      1 /* second */
83 #define RTR_SOLICITATION_INTERVAL       4 /* seconds */
84 #define MAX_RTR_SOLICITATIONS           3 /* times */
85
86 /*
87  * implementation dependent constants in seconds
88  * XXX: should be configurable
89  */
90 #define PROBE_INTERVAL 60
91
92 /* static variables and functions */
93 static int mobile_node = 0;
94 static const char *pidfilename = RTSOL_PIDFILE;
95
96 #ifndef SMALL
97 static int do_dump;
98 static const char *dumpfilename = RTSOL_DUMPFILE;
99 #endif
100
101 #if 0
102 static int ifreconfig(char *);
103 #endif
104
105 static int make_packet(struct ifinfo *);
106 static struct timespec *rtsol_check_timer(void);
107
108 #ifndef SMALL
109 static void rtsold_set_dump_file(int);
110 #endif
111 static void usage(void);
112
113 int
114 main(int argc, char **argv)
115 {
116         int s, ch, once = 0;
117         struct timespec *timeout;
118         const char *opts;
119 #ifdef HAVE_POLL_H
120         struct pollfd set[2];
121 #else
122         fd_set *fdsetp, *selectfdp;
123         int fdmasks;
124         int maxfd;
125 #endif
126         int rtsock;
127         char *argv0;
128
129 #ifndef SMALL
130         /* rtsold */
131         opts = "adDfFm1O:p:R:u";
132 #else
133         /* rtsol */
134         opts = "adDFO:R:u";
135         fflag = 1;
136         once = 1;
137 #endif
138         argv0 = argv[0];
139
140         while ((ch = getopt(argc, argv, opts)) != -1) {
141                 switch (ch) {
142                 case 'a':
143                         aflag = 1;
144                         break;
145                 case 'd':
146                         dflag += 1;
147                         break;
148                 case 'D':
149                         dflag += 2;
150                         break;
151                 case 'f':
152                         fflag = 1;
153                         break;
154                 case 'F':
155                         Fflag = 1;
156                         break;
157                 case 'm':
158                         mobile_node = 1;
159                         break;
160                 case '1':
161                         once = 1;
162                         break;
163                 case 'O':
164                         otherconf_script = optarg;
165                         break;
166                 case 'p':
167                         pidfilename = optarg;
168                         break;
169                 case 'R':
170                         resolvconf_script = optarg;
171                         break;
172                 case 'u':
173                         uflag = 1;
174                         break;
175                 default:
176                         usage();
177                         exit(1);
178                 }
179         }
180         argc -= optind;
181         argv += optind;
182
183         if ((!aflag && argc == 0) || (aflag && argc != 0)) {
184                 usage();
185                 exit(1);
186         }
187
188         /* Generate maximum time in timespec. */
189         tm_max.tv_sec = (-1) & ~((time_t)1 << ((sizeof(tm_max.tv_sec) * 8) - 1));
190         tm_max.tv_nsec = (-1) & ~((long)1 << ((sizeof(tm_max.tv_nsec) * 8) - 1));
191
192         /* set log level */
193         if (dflag > 1)
194                 log_upto = LOG_DEBUG;
195         else if (dflag > 0)
196                 log_upto = LOG_INFO;
197         else
198                 log_upto = LOG_NOTICE;
199
200         if (!fflag) {
201                 char *ident;
202
203                 ident = strrchr(argv0, '/');
204                 if (!ident)
205                         ident = argv0;
206                 else
207                         ident++;
208                 openlog(ident, LOG_NDELAY|LOG_PID, LOG_DAEMON);
209                 if (log_upto >= 0)
210                         setlogmask(LOG_UPTO(log_upto));
211         }
212
213         if (otherconf_script && *otherconf_script != '/') {
214                 errx(1, "configuration script (%s) must be an absolute path",
215                     otherconf_script);
216         }
217         if (resolvconf_script && *resolvconf_script != '/') {
218                 errx(1, "configuration script (%s) must be an absolute path",
219                     resolvconf_script);
220         }
221         if (pidfilename && *pidfilename != '/') {
222                 errx(1, "pid filename (%s) must be an absolute path",
223                     pidfilename);
224         }
225 #ifndef HAVE_ARC4RANDOM
226         /* random value initialization */
227         srandom((u_long)time(NULL));
228 #endif
229
230 #if (__FreeBSD_version < 900000)
231         if (Fflag) {
232                 setinet6sysctl(IPV6CTL_FORWARDING, 0);
233         } else {
234                 /* warn if forwarding is up */
235                 if (getinet6sysctl(IPV6CTL_FORWARDING))
236                         warnx("kernel is configured as a router, not a host");
237         }
238 #endif
239
240 #ifndef SMALL
241         /* initialization to dump internal status to a file */
242         signal(SIGUSR1, rtsold_set_dump_file);
243 #endif
244
245         if (!fflag)
246                 daemon(0, 0);           /* act as a daemon */
247
248         /*
249          * Open a socket for sending RS and receiving RA.
250          * This should be done before calling ifinit(), since the function
251          * uses the socket.
252          */
253         if ((s = sockopen()) < 0) {
254                 warnmsg(LOG_ERR, __func__, "failed to open a socket");
255                 exit(1);
256         }
257 #ifdef HAVE_POLL_H
258         set[0].fd = s;
259         set[0].events = POLLIN;
260 #else
261         maxfd = s;
262 #endif
263
264 #ifdef HAVE_POLL_H
265         set[1].fd = -1;
266 #endif
267
268         if ((rtsock = rtsock_open()) < 0) {
269                 warnmsg(LOG_ERR, __func__, "failed to open a socket");
270                 exit(1);
271         }
272 #ifdef HAVE_POLL_H
273         set[1].fd = rtsock;
274         set[1].events = POLLIN;
275 #else
276         if (rtsock > maxfd)
277                 maxfd = rtsock;
278 #endif
279
280 #ifndef HAVE_POLL_H
281         fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask);
282         if ((fdsetp = malloc(fdmasks)) == NULL) {
283                 warnmsg(LOG_ERR, __func__, "malloc");
284                 exit(1);
285         }
286         if ((selectfdp = malloc(fdmasks)) == NULL) {
287                 warnmsg(LOG_ERR, __func__, "malloc");
288                 exit(1);
289         }
290 #endif
291
292         /* configuration per interface */
293         if (ifinit()) {
294                 warnmsg(LOG_ERR, __func__,
295                     "failed to initialize interfaces");
296                 exit(1);
297         }
298         if (aflag)
299                 argv = autoifprobe();
300         while (argv && *argv) {
301                 if (ifconfig(*argv)) {
302                         warnmsg(LOG_ERR, __func__,
303                             "failed to initialize %s", *argv);
304                         exit(1);
305                 }
306                 argv++;
307         }
308
309         /* setup for probing default routers */
310         if (probe_init()) {
311                 warnmsg(LOG_ERR, __func__,
312                     "failed to setup for probing routers");
313                 exit(1);
314                 /*NOTREACHED*/
315         }
316
317         /* dump the current pid */
318         if (!once) {
319                 pid_t pid = getpid();
320                 FILE *fp;
321
322                 if ((fp = fopen(pidfilename, "w")) == NULL)
323                         warnmsg(LOG_ERR, __func__,
324                             "failed to open a pid log file(%s): %s",
325                             pidfilename, strerror(errno));
326                 else {
327                         fprintf(fp, "%d\n", pid);
328                         fclose(fp);
329                 }
330         }
331 #ifndef HAVE_POLL_H
332         memset(fdsetp, 0, fdmasks);
333         FD_SET(s, fdsetp);
334         FD_SET(rtsock, fdsetp);
335 #endif
336         while (1) {             /* main loop */
337                 int e;
338
339 #ifndef HAVE_POLL_H
340                 memcpy(selectfdp, fdsetp, fdmasks);
341 #endif
342
343 #ifndef SMALL
344                 if (do_dump) {  /* SIGUSR1 */
345                         do_dump = 0;
346                         rtsold_dump_file(dumpfilename);
347                 }
348 #endif
349
350                 timeout = rtsol_check_timer();
351
352                 if (once) {
353                         struct ifinfo *ifi;
354
355                         /* if we have no timeout, we are done (or failed) */
356                         if (timeout == NULL)
357                                 break;
358
359                         /* if all interfaces have got RA packet, we are done */
360                         TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
361                                 if (ifi->state != IFS_DOWN && ifi->racnt == 0)
362                                         break;
363                         }
364                         if (ifi == NULL)
365                                 break;
366                 }
367 #ifdef HAVE_POLL_H
368                 e = poll(set, 2, timeout ? (timeout->tv_sec * 1000 + timeout->tv_nsec / 1000 / 1000) : INFTIM);
369 #else
370                 e = select(maxfd + 1, selectfdp, NULL, NULL, timeout);
371 #endif
372                 if (e < 1) {
373                         if (e < 0 && errno != EINTR) {
374                                 warnmsg(LOG_ERR, __func__, "select: %s",
375                                     strerror(errno));
376                         }
377                         continue;
378                 }
379
380                 /* packet reception */
381 #ifdef HAVE_POLL_H
382                 if (set[1].revents & POLLIN)
383 #else
384                 if (FD_ISSET(rtsock, selectfdp))
385 #endif
386                         rtsock_input(rtsock);
387 #ifdef HAVE_POLL_H
388                 if (set[0].revents & POLLIN)
389 #else
390                 if (FD_ISSET(s, selectfdp))
391 #endif
392                         rtsol_input(s);
393         }
394         /* NOTREACHED */
395
396         return (0);
397 }
398
399 int
400 ifconfig(char *ifname)
401 {
402         struct ifinfo *ifi;
403         struct sockaddr_dl *sdl;
404         int flags;
405
406         if ((sdl = if_nametosdl(ifname)) == NULL) {
407                 warnmsg(LOG_ERR, __func__,
408                     "failed to get link layer information for %s", ifname);
409                 return (-1);
410         }
411         if (find_ifinfo(sdl->sdl_index)) {
412                 warnmsg(LOG_ERR, __func__,
413                     "interface %s was already configured", ifname);
414                 free(sdl);
415                 return (-1);
416         }
417
418         if (Fflag) {
419                 struct in6_ndireq nd;
420                 int s;
421
422                 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
423                         warnmsg(LOG_ERR, __func__, "socket() failed.");
424                         return (-1);
425                 }
426                 memset(&nd, 0, sizeof(nd));
427                 strlcpy(nd.ifname, ifname, sizeof(nd.ifname));
428                 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
429                         warnmsg(LOG_ERR, __func__,
430                             "cannot get accept_rtadv flag");
431                         close(s);
432                         return (-1);
433                 }
434                 nd.ndi.flags |= ND6_IFF_ACCEPT_RTADV;
435                 if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd) < 0) {
436                         warnmsg(LOG_ERR, __func__,
437                             "cannot set accept_rtadv flag");
438                         close(s);
439                         return (-1);
440                 }
441                 close(s);
442         }
443
444         if ((ifi = malloc(sizeof(*ifi))) == NULL) {
445                 warnmsg(LOG_ERR, __func__, "memory allocation failed");
446                 free(sdl);
447                 return (-1);
448         }
449         memset(ifi, 0, sizeof(*ifi));
450         ifi->sdl = sdl;
451         ifi->ifi_rdnss = IFI_DNSOPT_STATE_NOINFO;
452         ifi->ifi_dnssl = IFI_DNSOPT_STATE_NOINFO;
453         TAILQ_INIT(&ifi->ifi_rainfo);
454         strlcpy(ifi->ifname, ifname, sizeof(ifi->ifname));
455
456         /* construct a router solicitation message */
457         if (make_packet(ifi))
458                 goto bad;
459
460         /* set link ID of this interface. */
461 #ifdef HAVE_SCOPELIB
462         if (inet_zoneid(AF_INET6, 2, ifname, &ifi->linkid))
463                 goto bad;
464 #else
465         /* XXX: assume interface IDs as link IDs */
466         ifi->linkid = ifi->sdl->sdl_index;
467 #endif
468
469         /*
470          * check if the interface is available.
471          * also check if SIOCGIFMEDIA ioctl is OK on the interface.
472          */
473         ifi->mediareqok = 1;
474         ifi->active = interface_status(ifi);
475         if (!ifi->mediareqok) {
476                 /*
477                  * probe routers periodically even if the link status
478                  * does not change.
479                  */
480                 ifi->probeinterval = PROBE_INTERVAL;
481         }
482
483         /* activate interface: interface_up returns 0 on success */
484         flags = interface_up(ifi->ifname);
485         if (flags == 0)
486                 ifi->state = IFS_DELAY;
487         else if (flags == IFS_TENTATIVE)
488                 ifi->state = IFS_TENTATIVE;
489         else
490                 ifi->state = IFS_DOWN;
491
492         rtsol_timer_update(ifi);
493
494         TAILQ_INSERT_TAIL(&ifinfo_head, ifi, ifi_next);
495         return (0);
496
497 bad:
498         free(ifi->sdl);
499         free(ifi);
500         return (-1);
501 }
502
503 void
504 iflist_init(void)
505 {
506         struct ifinfo *ifi;
507
508         while ((ifi = TAILQ_FIRST(&ifinfo_head)) != NULL) {
509                 TAILQ_REMOVE(&ifinfo_head, ifi, ifi_next);
510                 if (ifi->sdl != NULL)
511                         free(ifi->sdl);
512                 if (ifi->rs_data != NULL)
513                         free(ifi->rs_data);
514                 free(ifi);
515         }
516 }
517
518 #if 0
519 static int
520 ifreconfig(char *ifname)
521 {
522         struct ifinfo *ifi, *prev;
523         int rv;
524
525         prev = NULL;
526         TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
527                 if (strncmp(ifi->ifname, ifname, sizeof(ifi->ifname)) == 0)
528                         break;
529                 prev = ifi;
530         }
531         prev->next = ifi->next;
532
533         rv = ifconfig(ifname);
534
535         /* reclaim it after ifconfig() in case ifname is pointer inside ifi */
536         if (ifi->rs_data)
537                 free(ifi->rs_data);
538         free(ifi->sdl);
539         free(ifi);
540
541         return (rv);
542 }
543 #endif
544
545 struct rainfo *
546 find_rainfo(struct ifinfo *ifi, struct sockaddr_in6 *sin6)
547 {
548         struct rainfo *rai;
549
550         TAILQ_FOREACH(rai, &ifi->ifi_rainfo, rai_next)
551                 if (memcmp(&rai->rai_saddr.sin6_addr, &sin6->sin6_addr,
552                     sizeof(rai->rai_saddr.sin6_addr)) == 0)
553                         return (rai);
554
555         return (NULL);
556 }
557
558 struct ifinfo *
559 find_ifinfo(int ifindex)
560 {
561         struct ifinfo *ifi;
562
563         TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
564                 if (ifi->sdl->sdl_index == ifindex)
565                         return (ifi);
566         }
567         return (NULL);
568 }
569
570 static int
571 make_packet(struct ifinfo *ifi)
572 {
573         size_t packlen = sizeof(struct nd_router_solicit), lladdroptlen = 0;
574         struct nd_router_solicit *rs;
575         char *buf;
576
577         if ((lladdroptlen = lladdropt_length(ifi->sdl)) == 0) {
578                 warnmsg(LOG_INFO, __func__,
579                     "link-layer address option has null length"
580                     " on %s. Treat as not included.", ifi->ifname);
581         }
582         packlen += lladdroptlen;
583         ifi->rs_datalen = packlen;
584
585         /* allocate buffer */
586         if ((buf = malloc(packlen)) == NULL) {
587                 warnmsg(LOG_ERR, __func__,
588                     "memory allocation failed for %s", ifi->ifname);
589                 return (-1);
590         }
591         ifi->rs_data = buf;
592
593         /* fill in the message */
594         rs = (struct nd_router_solicit *)buf;
595         rs->nd_rs_type = ND_ROUTER_SOLICIT;
596         rs->nd_rs_code = 0;
597         rs->nd_rs_cksum = 0;
598         rs->nd_rs_reserved = 0;
599         buf += sizeof(*rs);
600
601         /* fill in source link-layer address option */
602         if (lladdroptlen)
603                 lladdropt_fill(ifi->sdl, (struct nd_opt_hdr *)buf);
604
605         return (0);
606 }
607
608 static struct timespec *
609 rtsol_check_timer(void)
610 {
611         static struct timespec returnval;
612         struct timespec now, rtsol_timer;
613         struct ifinfo *ifi;
614         struct rainfo *rai;
615         struct ra_opt *rao;
616         int flags;
617
618         clock_gettime(CLOCK_MONOTONIC_FAST, &now);
619
620         rtsol_timer = tm_max;
621
622         TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
623                 if (TS_CMP(&ifi->expire, &now, <=)) {
624                         warnmsg(LOG_DEBUG, __func__, "timer expiration on %s, "
625                             "state = %d", ifi->ifname, ifi->state);
626
627                         while((rai = TAILQ_FIRST(&ifi->ifi_rainfo)) != NULL) {
628                                 /* Remove all RA options. */
629                                 TAILQ_REMOVE(&ifi->ifi_rainfo, rai, rai_next);
630                                 while ((rao = TAILQ_FIRST(&rai->rai_ra_opt)) !=
631                                     NULL) {
632                                         TAILQ_REMOVE(&rai->rai_ra_opt, rao,
633                                             rao_next);
634                                         if (rao->rao_msg != NULL)
635                                                 free(rao->rao_msg);
636                                         free(rao);
637                                 }
638                                 free(rai);
639                         }
640                         switch (ifi->state) {
641                         case IFS_DOWN:
642                         case IFS_TENTATIVE:
643                                 /* interface_up returns 0 on success */
644                                 flags = interface_up(ifi->ifname);
645                                 if (flags == 0)
646                                         ifi->state = IFS_DELAY;
647                                 else if (flags == IFS_TENTATIVE)
648                                         ifi->state = IFS_TENTATIVE;
649                                 else
650                                         ifi->state = IFS_DOWN;
651                                 break;
652                         case IFS_IDLE:
653                         {
654                                 int oldstatus = ifi->active;
655                                 int probe = 0;
656
657                                 ifi->active = interface_status(ifi);
658
659                                 if (oldstatus != ifi->active) {
660                                         warnmsg(LOG_DEBUG, __func__,
661                                             "%s status is changed"
662                                             " from %d to %d",
663                                             ifi->ifname,
664                                             oldstatus, ifi->active);
665                                         probe = 1;
666                                         ifi->state = IFS_DELAY;
667                                 } else if (ifi->probeinterval &&
668                                     (ifi->probetimer -=
669                                     ifi->timer.tv_sec) <= 0) {
670                                         /* probe timer expired */
671                                         ifi->probetimer =
672                                             ifi->probeinterval;
673                                         probe = 1;
674                                         ifi->state = IFS_PROBE;
675                                 }
676
677                                 /*
678                                  * If we need a probe, clear the previous
679                                  * status wrt the "other" configuration.
680                                  */
681                                 if (probe)
682                                         ifi->otherconfig = 0;
683
684                                 if (probe && mobile_node)
685                                         defrouter_probe(ifi);
686                                 break;
687                         }
688                         case IFS_DELAY:
689                                 ifi->state = IFS_PROBE;
690                                 sendpacket(ifi);
691                                 break;
692                         case IFS_PROBE:
693                                 if (ifi->probes < MAX_RTR_SOLICITATIONS)
694                                         sendpacket(ifi);
695                                 else {
696                                         warnmsg(LOG_INFO, __func__,
697                                             "No answer after sending %d RSs",
698                                             ifi->probes);
699                                         ifi->probes = 0;
700                                         ifi->state = IFS_IDLE;
701                                 }
702                                 break;
703                         }
704                         rtsol_timer_update(ifi);
705                 } else {
706                         /* Expiration check for RA options. */
707                         int expire = 0;
708
709                         TAILQ_FOREACH(rai, &ifi->ifi_rainfo, rai_next) {
710                                 TAILQ_FOREACH(rao, &rai->rai_ra_opt, rao_next) {
711                                         warnmsg(LOG_DEBUG, __func__,
712                                             "RA expiration timer: "
713                                             "type=%d, msg=%s, expire=%s",
714                                             rao->rao_type, (char *)rao->rao_msg,
715                                                 sec2str(&rao->rao_expire));
716                                         if (TS_CMP(&now, &rao->rao_expire,
717                                             >=)) {
718                                                 warnmsg(LOG_DEBUG, __func__,
719                                                     "RA expiration timer: "
720                                                     "expired.");
721                                                 TAILQ_REMOVE(&rai->rai_ra_opt,
722                                                     rao, rao_next);
723                                                 if (rao->rao_msg != NULL)
724                                                         free(rao->rao_msg);
725                                                 free(rao);
726                                                 expire = 1;
727                                         }
728                                 }
729                         }
730                         if (expire)
731                                 ra_opt_handler(ifi);
732                 }
733                 if (TS_CMP(&ifi->expire, &rtsol_timer, <))
734                         rtsol_timer = ifi->expire;
735         }
736
737         if (TS_CMP(&rtsol_timer, &tm_max, ==)) {
738                 warnmsg(LOG_DEBUG, __func__, "there is no timer");
739                 return (NULL);
740         } else if (TS_CMP(&rtsol_timer, &now, <))
741                 /* this may occur when the interval is too small */
742                 returnval.tv_sec = returnval.tv_nsec = 0;
743         else
744                 TS_SUB(&rtsol_timer, &now, &returnval);
745
746         now.tv_sec += returnval.tv_sec;
747         now.tv_nsec += returnval.tv_nsec;
748         warnmsg(LOG_DEBUG, __func__, "New timer is %s",
749             sec2str(&now));
750
751         return (&returnval);
752 }
753
754 void
755 rtsol_timer_update(struct ifinfo *ifi)
756 {
757 #define MILLION 1000000
758 #define DADRETRY 10             /* XXX: adhoc */
759         long interval;
760         struct timespec now;
761
762         bzero(&ifi->timer, sizeof(ifi->timer));
763
764         switch (ifi->state) {
765         case IFS_DOWN:
766         case IFS_TENTATIVE:
767                 if (++ifi->dadcount > DADRETRY) {
768                         ifi->dadcount = 0;
769                         ifi->timer.tv_sec = PROBE_INTERVAL;
770                 } else
771                         ifi->timer.tv_sec = 1;
772                 break;
773         case IFS_IDLE:
774                 if (mobile_node) {
775                         /* XXX should be configurable */
776                         ifi->timer.tv_sec = 3;
777                 }
778                 else
779                         ifi->timer = tm_max;    /* stop timer(valid?) */
780                 break;
781         case IFS_DELAY:
782 #ifndef HAVE_ARC4RANDOM
783                 interval = random() % (MAX_RTR_SOLICITATION_DELAY * MILLION);
784 #else
785                 interval = arc4random_uniform(MAX_RTR_SOLICITATION_DELAY * MILLION);
786 #endif
787                 ifi->timer.tv_sec = interval / MILLION;
788                 ifi->timer.tv_nsec = (interval % MILLION) * 1000;
789                 break;
790         case IFS_PROBE:
791                 if (ifi->probes < MAX_RTR_SOLICITATIONS)
792                         ifi->timer.tv_sec = RTR_SOLICITATION_INTERVAL;
793                 else {
794                         /*
795                          * After sending MAX_RTR_SOLICITATIONS solicitations,
796                          * we're just waiting for possible replies; there
797                          * will be no more solicitation.  Thus, we change
798                          * the timer value to MAX_RTR_SOLICITATION_DELAY based
799                          * on RFC 2461, Section 6.3.7.
800                          */
801                         ifi->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY;
802                 }
803                 break;
804         default:
805                 warnmsg(LOG_ERR, __func__,
806                     "illegal interface state(%d) on %s",
807                     ifi->state, ifi->ifname);
808                 return;
809         }
810
811         /* reset the timer */
812         if (TS_CMP(&ifi->timer, &tm_max, ==)) {
813                 ifi->expire = tm_max;
814                 warnmsg(LOG_DEBUG, __func__,
815                     "stop timer for %s", ifi->ifname);
816         } else {
817                 clock_gettime(CLOCK_MONOTONIC_FAST, &now);
818                 TS_ADD(&now, &ifi->timer, &ifi->expire);
819
820                 now.tv_sec += ifi->timer.tv_sec;
821                 now.tv_nsec += ifi->timer.tv_nsec;
822                 warnmsg(LOG_DEBUG, __func__, "set timer for %s to %s",
823                     ifi->ifname, sec2str(&now));
824         }
825
826 #undef MILLION
827 }
828
829 /* timer related utility functions */
830 #define MILLION 1000000
831
832 #ifndef SMALL
833 static void
834 rtsold_set_dump_file(int sig __unused)
835 {
836         do_dump = 1;
837 }
838 #endif
839
840 static void
841 usage(void)
842 {
843 #ifndef SMALL
844         fprintf(stderr, "usage: rtsold [-adDfFm1] [-O script-name] "
845             "[-P pidfile] [-R script-name] interfaces...\n");
846         fprintf(stderr, "usage: rtsold [-dDfFm1] [-O script-name] "
847             "[-P pidfile] [-R script-name] -a\n");
848 #else
849         fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] "
850             "[-P pidfile] [-R script-name] interfaces...\n");
851         fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] "
852             "[-P pidfile] [-R script-name] -a\n");
853 #endif
854 }
855
856 void
857 warnmsg(int priority, const char *func, const char *msg, ...)
858 {
859         va_list ap;
860         char buf[BUFSIZ];
861
862         va_start(ap, msg);
863         if (fflag) {
864                 if (priority <= log_upto) {
865                         (void)vfprintf(stderr, msg, ap);
866                         (void)fprintf(stderr, "\n");
867                 }
868         } else {
869                 snprintf(buf, sizeof(buf), "<%s> %s", func, msg);
870                 msg = buf;
871                 vsyslog(priority, msg, ap);
872         }
873         va_end(ap);
874 }
875
876 /*
877  * return a list of interfaces which is suitable to sending an RS.
878  */
879 char **
880 autoifprobe(void)
881 {
882         static char **argv = NULL;
883         static int n = 0;
884         char **a;
885         int s = 0, i, found;
886         struct ifaddrs *ifap, *ifa;
887         struct in6_ndireq nd;
888
889         /* initialize */
890         while (n--)
891                 free(argv[n]);
892         if (argv) {
893                 free(argv);
894                 argv = NULL;
895         }
896         n = 0;
897
898         if (getifaddrs(&ifap) != 0)
899                 return (NULL);
900
901         if (!Fflag && (s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
902                 warnmsg(LOG_ERR, __func__, "socket");
903                 exit(1);
904         }
905
906         /* find an ethernet */
907         for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
908                 if ((ifa->ifa_flags & IFF_UP) == 0)
909                         continue;
910                 if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0)
911                         continue;
912                 if ((ifa->ifa_flags & IFF_LOOPBACK) != 0)
913                         continue;
914                 if ((ifa->ifa_flags & IFF_MULTICAST) == 0)
915                         continue;
916
917                 if (ifa->ifa_addr->sa_family != AF_INET6)
918                         continue;
919
920                 found = 0;
921                 for (i = 0; i < n; i++) {
922                         if (strcmp(argv[i], ifa->ifa_name) == 0) {
923                                 found++;
924                                 break;
925                         }
926                 }
927                 if (found)
928                         continue;
929
930                 /*
931                  * Skip the interfaces which IPv6 and/or accepting RA
932                  * is disabled.
933                  */
934                 if (!Fflag) {
935                         memset(&nd, 0, sizeof(nd));
936                         strlcpy(nd.ifname, ifa->ifa_name, sizeof(nd.ifname));
937                         if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
938                                 warnmsg(LOG_ERR, __func__,
939                                         "ioctl(SIOCGIFINFO_IN6)");
940                                 exit(1);
941                         }
942                         if ((nd.ndi.flags & ND6_IFF_IFDISABLED))
943                                 continue;
944                         if (!(nd.ndi.flags & ND6_IFF_ACCEPT_RTADV))
945                                 continue;
946                 }
947
948                 /* if we find multiple candidates, just warn. */
949                 if (n != 0 && dflag > 1)
950                         warnmsg(LOG_WARNING, __func__,
951                                 "multiple interfaces found");
952
953                 a = (char **)realloc(argv, (n + 1) * sizeof(char **));
954                 if (a == NULL) {
955                         warnmsg(LOG_ERR, __func__, "realloc");
956                         exit(1);
957                 }
958                 argv = a;
959                 argv[n] = strdup(ifa->ifa_name);
960                 if (!argv[n]) {
961                         warnmsg(LOG_ERR, __func__, "malloc");
962                         exit(1);
963                 }
964                 n++;
965         }
966
967         if (n) {
968                 a = (char **)realloc(argv, (n + 1) * sizeof(char **));
969                 if (a == NULL) {
970                         warnmsg(LOG_ERR, __func__, "realloc");
971                         exit(1);
972                 }
973                 argv = a;
974                 argv[n] = NULL;
975
976                 if (dflag > 0) {
977                         for (i = 0; i < n; i++)
978                                 warnmsg(LOG_WARNING, __func__, "probing %s",
979                                         argv[i]);
980                 }
981         }
982         if (!Fflag)
983                 close(s);
984         freeifaddrs(ifap);
985         return (argv);
986 }