1 /* $NetBSD: rtsold.c,v 1.34 2008/06/23 04:55:27 dholland Exp $ */
2 /* $KAME: rtsold.c,v 1.77 2004/01/03 01:35:13 itojun Exp $ */
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
33 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/param.h>
39 #include <net/if_dl.h>
41 #include <netinet/in.h>
42 #include <netinet/icmp6.h>
60 #define timeradd(tvp, uvp, vvp) \
62 (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \
63 (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \
64 if ((vvp)->tv_usec >= 1000000) { \
66 (vvp)->tv_usec -= 1000000; \
68 } while (/* CONSTCOND */ 0)
69 #define timersub(tvp, uvp, vvp) \
71 (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
72 (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
73 if ((vvp)->tv_usec < 0) { \
75 (vvp)->tv_usec += 1000000; \
77 } while (/* CONSTCOND */ 0)
80 struct ifinfo
*iflist
;
81 struct timeval tm_max
= {0x7fffffff, 0x7fffffff};
82 static int log_upto
= 999;
88 /* protocol constatns */
89 #define MAX_RTR_SOLICITATION_DELAY 1 /* second */
90 #define RTR_SOLICITATION_INTERVAL 4 /* seconds */
91 #define MAX_RTR_SOLICITATIONS 3 /* times */
94 * implementation dependent constants in seconds
95 * XXX: should be configurable
97 #define PROBE_INTERVAL 60
99 int main
__P((int, char **));
101 /* static variables and functions */
102 static int mobile_node
= 0;
105 static const char *dumpfilename
= "/var/run/rtsold.dump"; /* XXX: should be configurable */
109 static int ifreconfig
__P((char *));
111 static int make_packet
__P((struct ifinfo
*));
112 static struct timeval
*rtsol_check_timer
__P((void));
115 static void rtsold_set_dump_file
__P((int));
117 static void usage
__P((char *));
120 main(int argc
, char **argv
)
123 struct timeval
*timeout
;
126 struct pollfd set
[2];
137 if (argv0
&& argv0
[strlen(argv0
) - 1] != 'd') {
144 while ((ch
= getopt(argc
, argv
, opts
)) != -1) {
172 if ((!aflag
&& argc
== 0) || (aflag
&& argc
!= 0)) {
179 log_upto
= LOG_NOTICE
;
183 ident
= strrchr(argv0
, '/');
188 openlog(ident
, LOG_NDELAY
|LOG_PID
, LOG_DAEMON
);
190 setlogmask(LOG_UPTO(log_upto
));
193 /* warn if accept_rtadv is down */
194 if (!getinet6sysctl(IPV6CTL_ACCEPT_RTADV
))
195 warnx("kernel is configured not to accept RAs");
196 /* warn if forwarding is up */
197 if (getinet6sysctl(IPV6CTL_FORWARDING
))
198 warnx("kernel is configured as a router, not a host");
201 /* initialization to dump internal status to a file */
202 signal(SIGUSR1
, rtsold_set_dump_file
);
206 daemon(0, 0); /* act as a daemon */
209 * Open a socket for sending RS and receiving RA.
210 * This should be done before calling ifinit(), since the function
213 if ((s
= sockopen()) < 0) {
214 warnmsg(LOG_ERR
, __func__
, "failed to open a socket");
219 set
[0].events
= POLLIN
;
224 if ((rtsock
= rtsock_open()) < 0) {
225 warnmsg(LOG_ERR
, __func__
, "failed to open a socket");
230 set
[1].events
= POLLIN
;
233 /* configuration per interface */
235 warnmsg(LOG_ERR
, __func__
,
236 "failed to initilizatoin interfaces");
241 argv
= autoifprobe();
242 while (argv
&& *argv
) {
243 if (ifconfig(*argv
)) {
244 warnmsg(LOG_ERR
, __func__
,
245 "failed to initialize %s", *argv
);
252 /* setup for probing default routers */
254 warnmsg(LOG_ERR
, __func__
,
255 "failed to setup for probing routers");
260 /* dump the current pid */
262 if (pidfile(NULL
) < 0) {
263 warnmsg(LOG_ERR
, __func__
,
264 "failed to open a pid log file: %s",
269 for (;;) { /* main loop */
273 if (do_dump
) { /* SIGUSR1 */
275 rtsold_dump_file(dumpfilename
);
279 timeout
= rtsol_check_timer();
284 /* if we have no timeout, we are done (or failed) */
288 /* if all interfaces have got RA packet, we are done */
289 for (ifi
= iflist
; ifi
; ifi
= ifi
->next
) {
290 if (ifi
->state
!= IFS_DOWN
&& ifi
->racnt
== 0)
296 e
= poll(set
, 2, timeout
? (timeout
->tv_sec
* 1000 + timeout
->tv_usec
/ 1000) : INFTIM
);
298 if (e
< 0 && errno
!= EINTR
) {
299 warnmsg(LOG_ERR
, __func__
, "poll: %s",
305 /* packet reception */
307 if (set
[1].revents
& POLLIN
)
308 rtsock_input(rtsock
);
310 if (set
[0].revents
& POLLIN
)
319 ifconfig(char *ifname
)
321 struct ifinfo
*ifinfo
;
322 struct sockaddr_dl
*sdl
;
325 if ((sdl
= if_nametosdl(ifname
)) == NULL
) {
326 warnmsg(LOG_ERR
, __func__
,
327 "failed to get link layer information for %s", ifname
);
330 if (find_ifinfo(sdl
->sdl_index
)) {
331 warnmsg(LOG_ERR
, __func__
,
332 "interface %s was already configured", ifname
);
337 if ((ifinfo
= malloc(sizeof(*ifinfo
))) == NULL
) {
338 warnmsg(LOG_ERR
, __func__
, "memory allocation failed");
342 memset(ifinfo
, 0, sizeof(*ifinfo
));
345 strlcpy(ifinfo
->ifname
, ifname
, sizeof(ifinfo
->ifname
));
347 /* construct a router solicitation message */
348 if (make_packet(ifinfo
))
351 /* set link ID of this interface. */
353 if (inet_zoneid(AF_INET6
, 2, ifname
, &ifinfo
->linkid
))
356 /* XXX: assume interface IDs as link IDs */
357 ifinfo
->linkid
= ifinfo
->sdl
->sdl_index
;
361 * check if the interface is available.
362 * also check if SIOCGIFMEDIA ioctl is OK on the interface.
364 ifinfo
->mediareqok
= 1;
365 ifinfo
->active
= interface_status(ifinfo
);
366 if (!ifinfo
->mediareqok
) {
368 * probe routers periodically even if the link status
371 ifinfo
->probeinterval
= PROBE_INTERVAL
;
374 /* activate interface: interface_up returns 0 on success */
375 flags
= interface_up(ifinfo
->ifname
);
377 ifinfo
->state
= IFS_DELAY
;
378 else if (flags
== IFS_TENTATIVE
)
379 ifinfo
->state
= IFS_TENTATIVE
;
381 ifinfo
->state
= IFS_DOWN
;
383 rtsol_timer_update(ifinfo
);
385 /* link into chain */
387 ifinfo
->next
= iflist
;
401 struct ifinfo
*ifi
, *next
;
403 for (ifi
= iflist
; ifi
; ifi
= next
) {
416 ifreconfig(char *ifname
)
418 struct ifinfo
*ifi
, *prev
;
422 for (ifi
= iflist
; ifi
; ifi
= ifi
->next
) {
423 if (strncmp(ifi
->ifname
, ifname
, sizeof(ifi
->ifname
)) == 0)
427 prev
->next
= ifi
->next
;
429 rv
= ifconfig(ifname
);
431 /* reclaim it after ifconfig() in case ifname is pointer inside ifi */
441 find_ifinfo(int ifindex
)
445 for (ifi
= iflist
; ifi
; ifi
= ifi
->next
)
446 if (ifi
->sdl
->sdl_index
== ifindex
)
452 make_packet(struct ifinfo
*ifinfo
)
454 size_t packlen
= sizeof(struct nd_router_solicit
), lladdroptlen
= 0;
455 struct nd_router_solicit
*rs
;
458 if ((lladdroptlen
= lladdropt_length(ifinfo
->sdl
)) == 0) {
459 warnmsg(LOG_INFO
, __func__
,
460 "link-layer address option has null length"
461 " on %s. Treat as not included.", ifinfo
->ifname
);
463 packlen
+= lladdroptlen
;
464 ifinfo
->rs_datalen
= packlen
;
466 /* allocate buffer */
467 if ((buf
= malloc(packlen
)) == NULL
) {
468 warnmsg(LOG_ERR
, __func__
,
469 "memory allocation failed for %s", ifinfo
->ifname
);
472 ifinfo
->rs_data
= buf
;
474 /* fill in the message */
475 rs
= (struct nd_router_solicit
*)buf
;
476 rs
->nd_rs_type
= ND_ROUTER_SOLICIT
;
479 rs
->nd_rs_reserved
= 0;
482 /* fill in source link-layer address option */
484 lladdropt_fill(ifinfo
->sdl
, (struct nd_opt_hdr
*)buf
);
489 static struct timeval
*
490 rtsol_check_timer(void)
492 static struct timeval returnval
;
493 struct timeval now
, rtsol_timer
;
494 struct ifinfo
*ifinfo
;
497 gettimeofday(&now
, NULL
);
499 rtsol_timer
= tm_max
;
501 for (ifinfo
= iflist
; ifinfo
; ifinfo
= ifinfo
->next
) {
502 if (timercmp(&ifinfo
->expire
, &now
, <=)) {
504 warnmsg(LOG_DEBUG
, __func__
,
505 "timer expiration on %s, "
506 "state = %d", ifinfo
->ifname
,
509 switch (ifinfo
->state
) {
512 /* interface_up returns 0 on success */
513 flags
= interface_up(ifinfo
->ifname
);
515 ifinfo
->state
= IFS_DELAY
;
516 else if (flags
== IFS_TENTATIVE
)
517 ifinfo
->state
= IFS_TENTATIVE
;
519 ifinfo
->state
= IFS_DOWN
;
523 int oldstatus
= ifinfo
->active
;
526 ifinfo
->active
= interface_status(ifinfo
);
528 if (oldstatus
!= ifinfo
->active
) {
529 warnmsg(LOG_DEBUG
, __func__
,
530 "%s status is changed"
533 oldstatus
, ifinfo
->active
);
535 ifinfo
->state
= IFS_DELAY
;
536 } else if (ifinfo
->probeinterval
&&
537 (ifinfo
->probetimer
-=
538 ifinfo
->timer
.tv_sec
) <= 0) {
539 /* probe timer expired */
541 ifinfo
->probeinterval
;
543 ifinfo
->state
= IFS_PROBE
;
546 if (probe
&& mobile_node
)
547 defrouter_probe(ifinfo
);
551 ifinfo
->state
= IFS_PROBE
;
555 if (ifinfo
->probes
< MAX_RTR_SOLICITATIONS
)
558 warnmsg(LOG_INFO
, __func__
,
559 "No answer after sending %d RSs",
562 ifinfo
->state
= IFS_IDLE
;
566 rtsol_timer_update(ifinfo
);
569 if (timercmp(&ifinfo
->expire
, &rtsol_timer
, <))
570 rtsol_timer
= ifinfo
->expire
;
573 if (timercmp(&rtsol_timer
, &tm_max
, ==)) {
574 warnmsg(LOG_DEBUG
, __func__
, "there is no timer");
576 } else if (timercmp(&rtsol_timer
, &now
, <))
577 /* this may occur when the interval is too small */
578 returnval
.tv_sec
= returnval
.tv_usec
= 0;
580 timersub(&rtsol_timer
, &now
, &returnval
);
583 warnmsg(LOG_DEBUG
, __func__
, "New timer is %ld:%08ld",
584 (long)returnval
.tv_sec
, (long)returnval
.tv_usec
);
590 rtsol_timer_update(struct ifinfo
*ifinfo
)
592 #define MILLION 1000000
593 #define DADRETRY 10 /* XXX: adhoc */
597 bzero(&ifinfo
->timer
, sizeof(ifinfo
->timer
));
599 switch (ifinfo
->state
) {
602 if (++ifinfo
->dadcount
> DADRETRY
) {
603 ifinfo
->dadcount
= 0;
604 ifinfo
->timer
.tv_sec
= PROBE_INTERVAL
;
606 ifinfo
->timer
.tv_sec
= 1;
610 /* XXX should be configurable */
611 ifinfo
->timer
.tv_sec
= 3;
613 ifinfo
->timer
= tm_max
; /* stop timer(valid?) */
616 interval
= arc4random() % (MAX_RTR_SOLICITATION_DELAY
* MILLION
);
617 ifinfo
->timer
.tv_sec
= interval
/ MILLION
;
618 ifinfo
->timer
.tv_usec
= interval
% MILLION
;
621 if (ifinfo
->probes
< MAX_RTR_SOLICITATIONS
)
622 ifinfo
->timer
.tv_sec
= RTR_SOLICITATION_INTERVAL
;
625 * After sending MAX_RTR_SOLICITATIONS solicitations,
626 * we're just waiting for possible replies; there
627 * will be no more solicatation. Thus, we change
628 * the timer value to MAX_RTR_SOLICITATION_DELAY based
629 * on RFC 2461, Section 6.3.7.
631 ifinfo
->timer
.tv_sec
= MAX_RTR_SOLICITATION_DELAY
;
635 warnmsg(LOG_ERR
, __func__
,
636 "illegal interface state(%d) on %s",
637 ifinfo
->state
, ifinfo
->ifname
);
641 /* reset the timer */
642 if (timercmp(&ifinfo
->timer
, &tm_max
, ==)) {
643 ifinfo
->expire
= tm_max
;
644 warnmsg(LOG_DEBUG
, __func__
,
645 "stop timer for %s", ifinfo
->ifname
);
647 gettimeofday(&now
, NULL
);
648 timeradd(&now
, &ifinfo
->timer
, &ifinfo
->expire
);
651 warnmsg(LOG_DEBUG
, __func__
,
652 "set timer for %s to %d:%d", ifinfo
->ifname
,
653 (int)ifinfo
->timer
.tv_sec
,
654 (int)ifinfo
->timer
.tv_usec
);
660 /* timer related utility functions */
661 #define MILLION 1000000
665 rtsold_set_dump_file(int sig
)
672 usage(char *progname
)
674 if (progname
&& progname
[strlen(progname
) - 1] != 'd') {
675 fprintf(stderr
, "usage: rtsol [-Dd] interface ...\n");
676 fprintf(stderr
, "usage: rtsol [-Dd] -a\n");
678 fprintf(stderr
, "usage: rtsold [-1Ddfm] interface ...\n");
679 fprintf(stderr
, "usage: rtsold [-1Ddfm] -a\n");
685 warnmsg(int priority
, const char *func
, const char *msg
, ...)
692 if (priority
<= log_upto
) {
693 (void)vfprintf(stderr
, msg
, ap
);
694 (void)fprintf(stderr
, "\n");
697 snprintf(buf
, sizeof(buf
), "<%s> %s", func
, msg
);
699 vsyslog(priority
, msg
, ap
);
705 * return a list of interfaces which is suitable to sending an RS.
710 static char **argv
= NULL
;
714 struct ifaddrs
*ifap
, *ifa
, *target
;
725 if (getifaddrs(&ifap
) != 0)
729 /* find an ethernet */
730 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
731 if ((ifa
->ifa_flags
& IFF_UP
) == 0)
733 if ((ifa
->ifa_flags
& IFF_POINTOPOINT
) != 0)
735 if ((ifa
->ifa_flags
& IFF_LOOPBACK
) != 0)
737 if ((ifa
->ifa_flags
& IFF_MULTICAST
) == 0)
740 if (ifa
->ifa_addr
->sa_family
!= AF_INET6
)
744 for (i
= 0; i
< n
; i
++) {
745 if (strcmp(argv
[i
], ifa
->ifa_name
) == 0) {
753 /* if we find multiple candidates, just warn. */
754 if (n
!= 0 && dflag
> 1)
755 warnx("multiple interfaces found");
757 a
= (char **)realloc(argv
, (n
+ 1) * sizeof(char **));
761 argv
[n
] = strdup(ifa
->ifa_name
);
768 a
= (char **)realloc(argv
, (n
+ 1) * sizeof(char **));
775 for (i
= 0; i
< n
; i
++)
776 warnx("probing %s", argv
[i
]);