1 /* $KAME: rtsold.c,v 1.31 2001/05/22 06:03:06 jinmei Exp $ */
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
31 * $FreeBSD: src/usr.sbin/rtsold/rtsold.c,v 1.1.2.4 2002/04/04 11:07:19 ume Exp $
34 #include <sys/types.h>
36 #include <sys/socket.h>
39 #include <net/if_dl.h>
41 #include <netinet/in.h>
42 #include <netinet/icmp6.h>
56 struct ifinfo
*iflist
;
57 struct timeval tm_max
= {0x7fffffff, 0x7fffffff};
60 static int log_upto
= 999;
63 /* protocol constatns */
64 #define MAX_RTR_SOLICITATION_DELAY 1 /* second */
65 #define RTR_SOLICITATION_INTERVAL 4 /* seconds */
66 #define MAX_RTR_SOLICITATIONS 3 /* times */
68 /* implementation dependent constants */
69 #define PROBE_INTERVAL 60 /* secondes XXX: should be configurable */
73 #define TIMEVAL_LT(a, b) (((a).tv_sec < (b).tv_sec) ||\
74 (((a).tv_sec == (b).tv_sec) && \
75 ((a).tv_usec < (b).tv_usec)))
78 #define TIMEVAL_LEQ(a, b) (((a).tv_sec < (b).tv_sec) ||\
79 (((a).tv_sec == (b).tv_sec) &&\
80 ((a).tv_usec <= (b).tv_usec)))
83 #define TIMEVAL_EQ(a, b) (((a).tv_sec==(b).tv_sec) && ((a).tv_usec==(b).tv_usec))
85 /* static variables and functions */
86 static int mobile_node
= 0;
89 * XXX: the following two values should be configurable
91 static const char *dumpfilename
= "/var/run/rtsold.dump";
92 static const char *pidfilename
= "/var/run/rtsold.pid";
94 static int ifconfig(char *ifname
);
96 static int ifreconfig(char *ifname
);
98 static int make_packet(struct ifinfo
*ifinfo
);
99 static struct timeval
*rtsol_check_timer(void);
100 static void TIMEVAL_ADD(struct timeval
*a
, struct timeval
*b
,
101 struct timeval
*result
);
102 static void TIMEVAL_SUB(struct timeval
*a
, struct timeval
*b
,
103 struct timeval
*result
);
105 static void rtsold_set_dump_file(int);
106 static void usage(char *progname
);
107 static char **autoifprobe(void);
110 main(int argc
, char *argv
[])
112 int s
, rtsock
, maxfd
, ch
;
114 struct timeval
*timeout
;
125 if (argv0
&& argv0
[strlen(argv0
) - 1] != 'd') {
132 while ((ch
= getopt(argc
, argv
, opts
)) != -1) {
168 argv
= autoifprobe();
170 errx(1, "could not autoprobe interface");
174 for (i
= 0; argv
[i
]; i
++)
185 log_upto
= LOG_NOTICE
;
188 ident
= strrchr(argv0
, '/');
193 openlog(ident
, LOG_NDELAY
|LOG_PID
, LOG_DAEMON
);
195 setlogmask(LOG_UPTO(log_upto
));
198 #ifndef HAVE_ARC4RANDOM
199 /* random value initilization */
200 srandom((u_long
)time(NULL
));
203 /* warn if accept_rtadv is down */
204 if (!getinet6sysctl(IPV6CTL_ACCEPT_RTADV
))
205 warnx("kernel is configured not to accept RAs");
206 /* warn if forwarding is up */
207 if (getinet6sysctl(IPV6CTL_FORWARDING
))
208 warnx("kernel is configured as a router, not a host");
210 /* initialization to dump internal status to a file */
211 if (signal(SIGUSR1
, rtsold_set_dump_file
) == SIG_ERR
) {
212 errx(1, "failed to set signal for dump status");
217 * Open a socket for sending RS and receiving RA.
218 * This should be done before calling ifinit(), since the function
221 if ((s
= sockopen()) < 0) {
222 errx(1, "failed to open a socket");
226 if ((rtsock
= rtsock_open()) < 0) {
227 errx(1, "failed to open a socket");
233 /* configuration per interface */
235 errx(1, "failed to initilizatoin interfaces");
239 if (ifconfig(*argv
)) {
240 errx(1, "failed to initialize %s", *argv
);
246 /* setup for probing default routers */
248 errx(1, "failed to setup for probing routers");
253 daemon(0, 0); /* act as a daemon */
255 /* dump the current pid */
257 pid_t pid
= getpid();
260 if ((fp
= fopen(pidfilename
, "w")) == NULL
)
261 warnmsg(LOG_ERR
, __func__
,
262 "failed to open a log file(%s): %s",
263 pidfilename
, strerror(errno
));
265 fprintf(fp
, "%d\n", pid
);
272 FD_SET(rtsock
, &fdset
);
273 while (1) { /* main loop */
275 struct fd_set select_fd
= fdset
;
277 if (do_dump
) { /* SIGUSR1 */
279 rtsold_dump_file(dumpfilename
);
282 timeout
= rtsol_check_timer();
287 /* if we have no timeout, we are done (or failed) */
291 /* if all interfaces have got RA packet, we are done */
292 for (ifi
= iflist
; ifi
; ifi
= ifi
->next
) {
293 if (ifi
->state
!= IFS_DOWN
&& ifi
->racnt
== 0)
299 e
= select(maxfd
+ 1, &select_fd
, NULL
, NULL
, timeout
);
301 if (e
< 0 && errno
!= EINTR
) {
302 warnmsg(LOG_ERR
, __func__
, "select: %s",
308 /* packet reception */
309 if (FD_ISSET(rtsock
, &select_fd
))
310 rtsock_input(rtsock
);
311 if (FD_ISSET(s
, &select_fd
))
320 ifconfig(char *ifname
)
322 struct ifinfo
*ifinfo
;
323 struct sockaddr_dl
*sdl
;
326 if ((sdl
= if_nametosdl(ifname
)) == NULL
) {
327 warnmsg(LOG_ERR
, __func__
,
328 "failed to get link layer information for %s", ifname
);
331 if (find_ifinfo(sdl
->sdl_index
)) {
332 warnmsg(LOG_ERR
, __func__
,
333 "interface %s was already configured", ifname
);
338 if ((ifinfo
= malloc(sizeof(*ifinfo
))) == NULL
) {
339 warnmsg(LOG_ERR
, __func__
, "memory allocation failed");
343 memset(ifinfo
, 0, sizeof(*ifinfo
));
346 strncpy(ifinfo
->ifname
, ifname
, sizeof(ifinfo
->ifname
));
348 /* construct a router solicitation message */
349 if (make_packet(ifinfo
))
353 * check if the interface is available.
354 * also check if SIOCGIFMEDIA ioctl is OK on the interface.
356 ifinfo
->mediareqok
= 1;
357 ifinfo
->active
= interface_status(ifinfo
);
358 if (!ifinfo
->mediareqok
) {
360 * probe routers periodically even if the link status
363 ifinfo
->probeinterval
= PROBE_INTERVAL
;
366 /* activate interface: interface_up returns 0 on success */
367 flags
= interface_up(ifinfo
->ifname
);
369 ifinfo
->state
= IFS_DELAY
;
370 else if (flags
== IFS_TENTATIVE
)
371 ifinfo
->state
= IFS_TENTATIVE
;
373 ifinfo
->state
= IFS_DOWN
;
375 rtsol_timer_update(ifinfo
);
377 /* link into chain */
379 ifinfo
->next
= iflist
;
392 ifreconfig(char *ifname
)
394 struct ifinfo
*ifi
, *prev
;
398 for (ifi
= iflist
; ifi
; ifi
= ifi
->next
) {
399 if (strncmp(ifi
->ifname
, ifname
, sizeof(ifi
->ifname
)) == 0)
403 prev
->next
= ifi
->next
;
405 rv
= ifconfig(ifname
);
407 /* reclaim it after ifconfig() in case ifname is pointer inside ifi */
418 find_ifinfo(int ifindex
)
422 for (ifi
= iflist
; ifi
; ifi
= ifi
->next
)
423 if (ifi
->sdl
->sdl_index
== ifindex
)
430 make_packet(struct ifinfo
*ifinfo
)
433 struct nd_router_solicit
*rs
;
434 size_t packlen
= sizeof(struct nd_router_solicit
), lladdroptlen
= 0;
436 if ((lladdroptlen
= lladdropt_length(ifinfo
->sdl
)) == 0) {
437 warnmsg(LOG_INFO
, __func__
,
438 "link-layer address option has null length"
439 " on %s. Treat as not included.", ifinfo
->ifname
);
441 packlen
+= lladdroptlen
;
442 ifinfo
->rs_datalen
= packlen
;
444 /* allocate buffer */
445 if ((buf
= malloc(packlen
)) == NULL
) {
446 warnmsg(LOG_ERR
, __func__
,
447 "memory allocation failed for %s", ifinfo
->ifname
);
450 ifinfo
->rs_data
= buf
;
452 /* fill in the message */
453 rs
= (struct nd_router_solicit
*)buf
;
454 rs
->nd_rs_type
= ND_ROUTER_SOLICIT
;
457 rs
->nd_rs_reserved
= 0;
460 /* fill in source link-layer address option */
462 lladdropt_fill(ifinfo
->sdl
, (struct nd_opt_hdr
*)buf
);
467 static struct timeval
*
468 rtsol_check_timer(void)
470 static struct timeval returnval
;
471 struct timeval now
, rtsol_timer
;
472 struct ifinfo
*ifinfo
;
475 gettimeofday(&now
, NULL
);
477 rtsol_timer
= tm_max
;
479 for (ifinfo
= iflist
; ifinfo
; ifinfo
= ifinfo
->next
) {
480 if (TIMEVAL_LEQ(ifinfo
->expire
, now
)) {
482 warnmsg(LOG_DEBUG
, __func__
,
483 "timer expiration on %s, "
484 "state = %d", ifinfo
->ifname
,
487 switch (ifinfo
->state
) {
490 /* interface_up returns 0 on success */
491 flags
= interface_up(ifinfo
->ifname
);
493 ifinfo
->state
= IFS_DELAY
;
494 else if (flags
== IFS_TENTATIVE
)
495 ifinfo
->state
= IFS_TENTATIVE
;
497 ifinfo
->state
= IFS_DOWN
;
501 int oldstatus
= ifinfo
->active
;
505 interface_status(ifinfo
);
507 if (oldstatus
!= ifinfo
->active
) {
508 warnmsg(LOG_DEBUG
, __func__
,
509 "%s status is changed"
512 oldstatus
, ifinfo
->active
);
514 ifinfo
->state
= IFS_DELAY
;
516 else if (ifinfo
->probeinterval
&&
517 (ifinfo
->probetimer
-=
518 ifinfo
->timer
.tv_sec
) <= 0) {
519 /* probe timer expired */
521 ifinfo
->probeinterval
;
523 ifinfo
->state
= IFS_PROBE
;
526 if (probe
&& mobile_node
)
527 defrouter_probe(ifinfo
->sdl
->sdl_index
);
531 ifinfo
->state
= IFS_PROBE
;
535 if (ifinfo
->probes
< MAX_RTR_SOLICITATIONS
)
538 warnmsg(LOG_INFO
, __func__
,
540 "after sending %d RSs",
543 ifinfo
->state
= IFS_IDLE
;
547 rtsol_timer_update(ifinfo
);
550 if (TIMEVAL_LT(ifinfo
->expire
, rtsol_timer
))
551 rtsol_timer
= ifinfo
->expire
;
554 if (TIMEVAL_EQ(rtsol_timer
, tm_max
)) {
555 warnmsg(LOG_DEBUG
, __func__
, "there is no timer");
558 else if (TIMEVAL_LT(rtsol_timer
, now
))
559 /* this may occur when the interval is too small */
560 returnval
.tv_sec
= returnval
.tv_usec
= 0;
562 TIMEVAL_SUB(&rtsol_timer
, &now
, &returnval
);
565 warnmsg(LOG_DEBUG
, __func__
, "New timer is %ld:%08ld",
566 (long)returnval
.tv_sec
, (long)returnval
.tv_usec
);
572 rtsol_timer_update(struct ifinfo
*ifinfo
)
574 #define MILLION 1000000
575 #define DADRETRY 10 /* XXX: adhoc */
579 bzero(&ifinfo
->timer
, sizeof(ifinfo
->timer
));
581 switch (ifinfo
->state
) {
584 if (++ifinfo
->dadcount
> DADRETRY
) {
585 ifinfo
->dadcount
= 0;
586 ifinfo
->timer
.tv_sec
= PROBE_INTERVAL
;
589 ifinfo
->timer
.tv_sec
= 1;
593 /* XXX should be configurable */
594 ifinfo
->timer
.tv_sec
= 3;
597 ifinfo
->timer
= tm_max
; /* stop timer(valid?) */
600 #ifndef HAVE_ARC4RANDOM
601 interval
= random() % (MAX_RTR_SOLICITATION_DELAY
* MILLION
);
603 interval
= arc4random() % (MAX_RTR_SOLICITATION_DELAY
* MILLION
);
605 ifinfo
->timer
.tv_sec
= interval
/ MILLION
;
606 ifinfo
->timer
.tv_usec
= interval
% MILLION
;
609 if (ifinfo
->probes
< MAX_RTR_SOLICITATIONS
)
610 ifinfo
->timer
.tv_sec
= RTR_SOLICITATION_INTERVAL
;
613 * After sending MAX_RTR_SOLICITATIONS solicitations,
614 * we're just waiting for possible replies; there
615 * will be no more solicatation. Thus, we change
616 * the timer value to MAX_RTR_SOLICITATION_DELAY based
617 * on RFC 2461, Section 6.3.7.
619 ifinfo
->timer
.tv_sec
= MAX_RTR_SOLICITATION_DELAY
;
623 warnmsg(LOG_ERR
, __func__
,
624 "illegal interface state(%d) on %s",
625 ifinfo
->state
, ifinfo
->ifname
);
629 /* reset the timer */
630 if (TIMEVAL_EQ(ifinfo
->timer
, tm_max
)) {
631 ifinfo
->expire
= tm_max
;
632 warnmsg(LOG_DEBUG
, __func__
,
633 "stop timer for %s", ifinfo
->ifname
);
636 gettimeofday(&now
, NULL
);
637 TIMEVAL_ADD(&now
, &ifinfo
->timer
, &ifinfo
->expire
);
640 warnmsg(LOG_DEBUG
, __func__
,
641 "set timer for %s to %d:%d", ifinfo
->ifname
,
642 (int)ifinfo
->timer
.tv_sec
,
643 (int)ifinfo
->timer
.tv_usec
);
649 /* timer related utility functions */
650 #define MILLION 1000000
654 TIMEVAL_ADD(struct timeval
*a
, struct timeval
*b
, struct timeval
*result
)
658 if ((l
= a
->tv_usec
+ b
->tv_usec
) < MILLION
) {
660 result
->tv_sec
= a
->tv_sec
+ b
->tv_sec
;
663 result
->tv_usec
= l
- MILLION
;
664 result
->tv_sec
= a
->tv_sec
+ b
->tv_sec
+ 1;
670 * XXX: this function assumes that a >= b.
673 TIMEVAL_SUB(struct timeval
*a
, struct timeval
*b
, struct timeval
*result
)
677 if ((l
= a
->tv_usec
- b
->tv_usec
) >= 0) {
679 result
->tv_sec
= a
->tv_sec
- b
->tv_sec
;
682 result
->tv_usec
= MILLION
+ l
;
683 result
->tv_sec
= a
->tv_sec
- b
->tv_sec
- 1;
688 rtsold_set_dump_file(int signo __unused
)
694 usage(char *progname
)
696 if (progname
&& progname
[strlen(progname
) - 1] != 'd') {
697 fprintf(stderr
, "usage: rtsol [-dD] interfaces...\n");
698 fprintf(stderr
, "usage: rtsol [-dD] -a\n");
700 fprintf(stderr
, "usage: rtsold [-adDfm1] interfaces...\n");
701 fprintf(stderr
, "usage: rtsold [-dDfm1] -a\n");
707 warnmsg(int priority
, const char *func
, const char *msg
, ...)
714 if (priority
<= log_upto
) {
715 vfprintf(stderr
, msg
, ap
);
716 fprintf(stderr
, "\n");
719 snprintf(buf
, sizeof(buf
), "<%s> %s", func
, msg
);
721 vsyslog(priority
, msg
, ap
);
729 #ifndef HAVE_GETIFADDRS
730 errx(1, "-a is not available with the configuration");
732 static char ifname
[IFNAMSIZ
+ 1];
733 static char *argv
[2];
734 struct ifaddrs
*ifap
, *ifa
, *target
;
736 if (getifaddrs(&ifap
) != 0)
740 /* find an ethernet */
741 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
742 if ((ifa
->ifa_flags
& IFF_UP
) == 0)
744 if ((ifa
->ifa_flags
& IFF_POINTOPOINT
) != 0)
746 if ((ifa
->ifa_flags
& IFF_LOOPBACK
) != 0)
748 if ((ifa
->ifa_flags
& IFF_MULTICAST
) == 0)
751 if (ifa
->ifa_addr
->sa_family
!= AF_INET6
)
754 if (target
&& strcmp(target
->ifa_name
, ifa
->ifa_name
) == 0)
760 /* if we find multiple candidates, failure. */
762 warnx("multiple interfaces found");
769 strncpy(ifname
, target
->ifa_name
, sizeof(ifname
) - 1);
770 ifname
[sizeof(ifname
) - 1] = '\0';
775 warnx("probing %s", argv
[0]);