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