diff options
author | kris <kris@FreeBSD.org> | 2000-07-05 22:09:50 +0000 |
---|---|---|
committer | kris <kris@FreeBSD.org> | 2000-07-05 22:09:50 +0000 |
commit | be25e6d5a3011595e06fb10a53a7587b25568915 (patch) | |
tree | d63aea49b1873cbe6c9664cfc5aadb668f5175f1 | |
parent | 13d90d944f154efa9feb5a06266329c85d01f979 (diff) | |
download | FreeBSD-src-be25e6d5a3011595e06fb10a53a7587b25568915.zip FreeBSD-src-be25e6d5a3011595e06fb10a53a7587b25568915.tar.gz |
Sync with latest KAME
Obtained from: KAME
-rw-r--r-- | usr.sbin/rtadvd/Makefile | 8 | ||||
-rw-r--r-- | usr.sbin/rtadvd/advcap.c | 39 | ||||
-rw-r--r-- | usr.sbin/rtadvd/advcap.h | 10 | ||||
-rw-r--r-- | usr.sbin/rtadvd/config.c | 143 | ||||
-rw-r--r-- | usr.sbin/rtadvd/config.h | 13 | ||||
-rw-r--r-- | usr.sbin/rtadvd/if.c | 72 | ||||
-rw-r--r-- | usr.sbin/rtadvd/if.h | 53 | ||||
-rw-r--r-- | usr.sbin/rtadvd/pathnames.h | 4 | ||||
-rw-r--r-- | usr.sbin/rtadvd/rrenum.c | 34 | ||||
-rw-r--r-- | usr.sbin/rtadvd/rrenum.h | 8 | ||||
-rw-r--r-- | usr.sbin/rtadvd/rtadvd.8 | 116 | ||||
-rw-r--r-- | usr.sbin/rtadvd/rtadvd.c | 623 | ||||
-rw-r--r-- | usr.sbin/rtadvd/rtadvd.conf | 33 | ||||
-rw-r--r-- | usr.sbin/rtadvd/rtadvd.conf.5 | 61 | ||||
-rw-r--r-- | usr.sbin/rtadvd/rtadvd.h | 142 | ||||
-rw-r--r-- | usr.sbin/rtadvd/timer.c | 26 | ||||
-rw-r--r-- | usr.sbin/rtadvd/timer.h | 45 |
17 files changed, 984 insertions, 446 deletions
diff --git a/usr.sbin/rtadvd/Makefile b/usr.sbin/rtadvd/Makefile index 7b5d2a8..32e6425 100644 --- a/usr.sbin/rtadvd/Makefile +++ b/usr.sbin/rtadvd/Makefile @@ -14,11 +14,11 @@ # $FreeBSD$ PROG= rtadvd -SRCS= rtadvd.c rrenum.c advcap.c if.c config.c timer.c +SRCS= rtadvd.c rrenum.c advcap.c if.c config.c timer.c dump.c -CFLAGS+=-DINET6 -DIPSEC -LDADD+= -lcompat -lipsec -DPADD+= ${LIBCOMPAT} ${LIBIPSEC} +CFLAGS+=-DINET6 +LDADD+= -lcompat +DPADD+= ${LIBCOMPAT} MAN5= rtadvd.conf.5 MAN8= rtadvd.8 diff --git a/usr.sbin/rtadvd/advcap.c b/usr.sbin/rtadvd/advcap.c index f0825b5..868066d 100644 --- a/usr.sbin/rtadvd/advcap.c +++ b/usr.sbin/rtadvd/advcap.c @@ -1,3 +1,5 @@ +/* $KAME: advcap.c,v 1.3 2000/05/16 13:34:13 itojun Exp $ */ + /* * Copyright (c) 1983 The Regents of the University of California. * All rights reserved. @@ -33,10 +35,6 @@ * $FreeBSD$ */ -#ifndef lint -static char sccsid[] = "@(#)remcap.c 5.5 (Berkeley) 2/2/91"; -#endif /* not lint */ - /* * remcap - routines for dealing with the remote host data base * @@ -66,6 +64,11 @@ static char sccsid[] = "@(#)remcap.c 5.5 (Berkeley) 2/2/91"; #define tgetflag agetflag #define tgetstr agetstr +#if 0 +#define V_TERMCAP "REMOTE" +#define V_TERM "HOST" +#endif + char *RM; /* @@ -82,22 +85,22 @@ char *RM; * doesn't, and because living w/o it is not hard. */ -static char *tbuf; -static int hopcount; /* detect infinite loops in termcap, init 0 */ +static char *tbuf; +static int hopcount; /* detect infinite loops in termcap, init 0 */ -static char *remotefile; +static char *remotefile; -extern char *conffile; +extern char *conffile; -int tgetent __P((char *, char *)); -int getent __P((char *, char *, char *)); -int tnchktc __P((void)); -int tnamatch __P((char *)); -static char *tskip __P((char *)); -int tgetnum __P((char *)); -int tgetflag __P((char *)); -char *tgetstr __P((char *, char **)); -static char *tdecode __P((char *, char **)); +int tgetent __P((char *, char *)); +int getent __P((char *, char *, char *)); +int tnchktc __P((void)); +int tnamatch __P((char *)); +static char *tskip __P((char *)); +int tgetnum __P((char *)); +int tgetflag __P((char *)); +char *tgetstr __P((char *, char **)); +static char *tdecode __P((char *, char **)); /* * Get an entry for terminal name in buffer bp, @@ -136,7 +139,7 @@ getent(bp, name, cp) tf = open(RM = cp, O_RDONLY); } if (tf < 0) { - syslog(LOG_WARNING, + syslog(LOG_INFO, "<%s> open: %s", __FUNCTION__, strerror(errno)); return (-2); } diff --git a/usr.sbin/rtadvd/advcap.h b/usr.sbin/rtadvd/advcap.h index 9c4520b..40ed46a 100644 --- a/usr.sbin/rtadvd/advcap.h +++ b/usr.sbin/rtadvd/advcap.h @@ -1,3 +1,5 @@ +/* $KAME$ */ + /* * Copyright (C) 1994,1995 by Andrey A. Chernov, Moscow, Russia. * All rights reserved. @@ -35,10 +37,10 @@ __BEGIN_DECLS -extern int agetent __P((char *, const char *)); -extern int agetflag __P((const char *)); -extern int agetnum __P((const char *)); -extern char *agetstr __P((const char *, char **)); +extern int agetent __P((char *, const char *)); +extern int agetflag __P((const char *)); +extern int agetnum __P((const char *)); +extern char *agetstr __P((const char *, char **)); __END_DECLS diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c index 964c79c..4220112 100644 --- a/usr.sbin/rtadvd/config.c +++ b/usr.sbin/rtadvd/config.c @@ -1,7 +1,9 @@ +/* $KAME: config.c,v 1.11 2000/05/16 13:34:13 itojun Exp $ */ + /* * Copyright (C) 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -13,7 +15,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -35,7 +37,9 @@ #include <sys/time.h> #include <net/if.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 #include <net/if_var.h> +#endif /* __FreeBSD__ >= 3 */ #include <net/route.h> #include <net/if_dl.h> @@ -44,6 +48,9 @@ #include <netinet/ip6.h> #include <netinet6/ip6_var.h> #include <netinet/icmp6.h> +#ifdef MIP6 +#include <netinet6/mip6.h> +#endif #include <arpa/inet.h> @@ -52,6 +59,9 @@ #include <errno.h> #include <string.h> #include <stdlib.h> +#if defined(__NetBSD__) || defined(__OpenBSD__) +#include <search.h> +#endif #include <unistd.h> #include "rtadvd.h" @@ -60,11 +70,10 @@ #include "if.h" #include "config.h" -static void makeentry __P((char *, int, char *, int)); -static void make_packet __P((struct rainfo *)); -static void get_prefix __P((struct rainfo *)); +static void makeentry __P((char *, int, char *, int)); +static void get_prefix __P((struct rainfo *)); -extern struct rainfo *ralist; +extern struct rainfo *ralist; void getconfig(intface) @@ -78,8 +87,8 @@ getconfig(intface) char *bp = buf; char *addr; -#define MUSTHAVE(var, cap) \ - { \ +#define MUSTHAVE(var, cap) \ + do { \ int t; \ if ((t = agetnum(cap)) < 0) { \ fprintf(stderr, "rtadvd: need %s for interface %s\n", \ @@ -87,12 +96,12 @@ getconfig(intface) exit(1); \ } \ var = t; \ - } -#define MAYHAVE(var, cap, def) \ - { \ + } while (0) +#define MAYHAVE(var, cap, def) \ + do { \ if ((var = agetnum(cap)) < 0) \ var = def; \ - } + } while (0) if ((stat = agetent(tbuf, intface)) <= 0) { memset(tbuf, 0, sizeof(tbuf)); @@ -136,7 +145,7 @@ getconfig(intface) MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL); if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) { syslog(LOG_ERR, - "<%s> maxinterval must be between %d and %d", + "<%s> maxinterval must be between %e and %u", __FUNCTION__, MIN_MAXINTERVAL, MAX_MAXINTERVAL); exit(1); } @@ -144,7 +153,7 @@ getconfig(intface) MAYHAVE(val, "mininterval", tmp->maxinterval/3); if (val < MIN_MININTERVAL || val > (tmp->maxinterval * 3) / 4) { syslog(LOG_ERR, - "<%s> mininterval must be between %d and %d", + "<%s> mininterval must be between %e and %d", __FUNCTION__, MIN_MININTERVAL, (tmp->maxinterval * 3) / 4); @@ -158,6 +167,10 @@ getconfig(intface) MAYHAVE(val, "raflags", 0); tmp->managedflg= val & ND_RA_FLAG_MANAGED; tmp->otherflg = val & ND_RA_FLAG_OTHER; +#ifdef MIP6 + if (mobileip6) + tmp->haflg = val & ND_RA_FLAG_HA; +#endif MAYHAVE(val, "rltime", tmp->maxinterval * 3); if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) { @@ -187,6 +200,39 @@ getconfig(intface) } tmp->retranstimer = (u_int32_t)val; +#ifdef MIP6 + if (!mobileip6) +#else + if (1) +#endif + { + if (agetstr("hapref", &bp) || agetstr("hatime", &bp)) { + syslog(LOG_ERR, + "<%s> mobile-ip6 configuration without " + "proper command line option", + __FUNCTION__); + exit(1); + } + } +#ifdef MIP6 + else { + tmp->hapref = 0; + if ((val = agetnum("hapref")) >= 0) + tmp->hapref = (int16_t)val; + if (tmp->hapref != 0) { + tmp->hatime = 0; + MUSTHAVE(val, "hatime"); + tmp->hatime = (u_int16_t)val; + if (tmp->hatime <= 0) { + syslog(LOG_ERR, + "<%s> home agent lifetime must be greater than 0", + __FUNCTION__); + exit(1); + } + } + } +#endif + /* prefix information */ if ((pfxs = agetnum("addrs")) < 0) { /* auto configure prefix information */ @@ -216,6 +262,8 @@ getconfig(intface) /* link into chain */ insque(pfx, &tmp->prefix); + pfx->origin = PREFIX_FROM_CONFIG; + makeentry(entbuf, i, "prefixlen", added); MAYHAVE(val, entbuf, 64); if (val < 0 || val > 128) { @@ -227,10 +275,24 @@ getconfig(intface) pfx->prefixlen = (int)val; makeentry(entbuf, i, "pinfoflags", added); - MAYHAVE(val, entbuf, - (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO)); +#ifdef MIP6 + if (mobileip6) + { + MAYHAVE(val, entbuf, + (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO| + ND_OPT_PI_FLAG_RTADDR)); + } else +#endif + { + MAYHAVE(val, entbuf, + (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO)); + } pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK; pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO; +#ifdef MIP6 + if (mobileip6) + pfx->routeraddr = val & ND_OPT_PI_FLAG_RTADDR; +#endif makeentry(entbuf, i, "vltime", added); MAYHAVE(val, entbuf, DEF_ADVVALIDLIFETIME); @@ -380,6 +442,7 @@ get_prefix(struct rainfo *rai) pp->preflifetime = DEF_ADVPREFERREDLIFETIME; pp->onlinkflg = 1; pp->autoconfflg = 1; + pp->origin = PREFIX_FROM_KERNEL; /* link into chain */ insque(pp, &rai->prefix); @@ -435,6 +498,7 @@ add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) prefix->preflifetime = ipr->ipr_pltime; prefix->onlinkflg = ipr->ipr_raf_onlink; prefix->autoconfflg = ipr->ipr_raf_auto; + prefix->origin = PREFIX_FROM_DYNAMIC; insque(prefix, &rai->prefix); @@ -462,7 +526,7 @@ add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) /* * Delete a prefix to the list of specified interface and reconstruct * the outgoing packet. - * The prefix must be in the list + * The prefix must be in the list. */ void delete_prefix(struct rainfo *rai, struct prefix *prefix) @@ -543,7 +607,7 @@ make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen) add_prefix(rai, &ipr); } -static void +void make_packet(struct rainfo *rainfo) { size_t packlen, lladdroptlen = 0; @@ -551,6 +615,10 @@ make_packet(struct rainfo *rainfo) struct nd_router_advert *ra; struct nd_opt_prefix_info *ndopt_pi; struct nd_opt_mtu *ndopt_mtu; +#ifdef MIP6 + struct nd_opt_advint *ndopt_advint; + struct nd_opt_hai *ndopt_hai; +#endif struct prefix *pfx; /* calculate total length */ @@ -570,6 +638,12 @@ make_packet(struct rainfo *rainfo) packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs; if (rainfo->linkmtu) packlen += sizeof(struct nd_opt_mtu); +#ifdef MIP6 + if (mobileip6 && rainfo->maxinterval) + packlen += sizeof(struct nd_opt_advint); + if (mobileip6 && rainfo->hatime) + packlen += sizeof(struct nd_opt_hai); +#endif /* allocate memory for the packet */ if ((buf = malloc(packlen)) == NULL) { @@ -595,6 +669,10 @@ make_packet(struct rainfo *rainfo) rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0; ra->nd_ra_flags_reserved |= rainfo->otherflg ? ND_RA_FLAG_OTHER : 0; +#ifdef MIP6 + ra->nd_ra_flags_reserved |= + rainfo->haflg ? ND_RA_FLAG_HA : 0; +#endif ra->nd_ra_router_lifetime = htons(rainfo->lifetime); ra->nd_ra_reachable = htonl(rainfo->reachabletime); ra->nd_ra_retransmit = htonl(rainfo->retranstimer); @@ -614,6 +692,30 @@ make_packet(struct rainfo *rainfo) buf += sizeof(struct nd_opt_mtu); } +#ifdef MIP6 + if (mobileip6 && rainfo->maxinterval) { + ndopt_advint = (struct nd_opt_advint *)buf; + ndopt_advint->nd_opt_int_type = ND_OPT_ADV_INTERVAL; + ndopt_advint->nd_opt_int_len = 1; + ndopt_advint->nd_opt_int_reserved = 0; + ndopt_advint->nd_opt_int_interval = ntohl(rainfo->maxinterval * + 1000); + buf += sizeof(struct nd_opt_advint); + } +#endif + +#ifdef MIP6 + if (rainfo->hatime) { + ndopt_hai = (struct nd_opt_hai *)buf; + ndopt_hai->nd_opt_hai_type = ND_OPT_HA_INFORMATION; + ndopt_hai->nd_opt_hai_len = 1; + ndopt_hai->nd_opt_hai_reserved = 0; + ndopt_hai->nd_opt_hai_pref = ntohs(rainfo->hapref); + ndopt_hai->nd_opt_hai_lifetime = ntohs(rainfo->hatime); + buf += sizeof(struct nd_opt_hai); + } +#endif + for (pfx = rainfo->prefix.next; pfx != &rainfo->prefix; pfx = pfx->next) { ndopt_pi = (struct nd_opt_prefix_info *)buf; @@ -627,6 +729,11 @@ make_packet(struct rainfo *rainfo) if (pfx->autoconfflg) ndopt_pi->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO; +#ifdef MIP6 + if (pfx->routeraddr) + ndopt_pi->nd_opt_pi_flags_reserved |= + ND_OPT_PI_FLAG_RTADDR; +#endif ndopt_pi->nd_opt_pi_valid_time = ntohl(pfx->validlifetime); ndopt_pi->nd_opt_pi_preferred_time = ntohl(pfx->preflifetime); diff --git a/usr.sbin/rtadvd/config.h b/usr.sbin/rtadvd/config.h index f8729d4..76f42a0 100644 --- a/usr.sbin/rtadvd/config.h +++ b/usr.sbin/rtadvd/config.h @@ -1,7 +1,9 @@ +/* $KAME$ */ + /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -13,7 +15,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -29,6 +31,7 @@ * $FreeBSD$ */ -extern void getconfig __P((char *)); -extern void delete_prefix __P((struct rainfo *, struct prefix *)); -extern void make_prefix __P((struct rainfo *, int, struct in6_addr *, int)); +extern void getconfig __P((char *)); +extern void delete_prefix __P((struct rainfo *, struct prefix *)); +extern void make_prefix __P((struct rainfo *, int, struct in6_addr *, int)); +extern void make_packet __P((struct rainfo *)); diff --git a/usr.sbin/rtadvd/if.c b/usr.sbin/rtadvd/if.c index 81aa47d..99eec64 100644 --- a/usr.sbin/rtadvd/if.c +++ b/usr.sbin/rtadvd/if.c @@ -1,7 +1,9 @@ +/* $KAME: if.c,v 1.9 2000/05/27 11:30:43 jinmei Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -13,7 +15,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -35,11 +37,23 @@ #include <sys/ioctl.h> #include <net/if.h> #include <net/if_types.h> -#include <net/ethernet.h> +#ifdef __FreeBSD__ +# include <net/ethernet.h> +#endif +#include <ifaddrs.h> +#ifdef __NetBSD__ +#include <net/if_ether.h> +#endif #include <net/route.h> #include <net/if_dl.h> #include <netinet/in.h> #include <netinet/icmp6.h> +#ifdef __bsdi__ +# include <netinet/if_ether.h> +#endif +#ifdef __OpenBSD__ +#include <netinet/if_ether.h> +#endif #include <unistd.h> #include <errno.h> #include <stdlib.h> @@ -48,28 +62,28 @@ #include "rtadvd.h" #include "if.h" -#define ROUNDUP(a, size) \ +#define ROUNDUP(a, size) \ (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) -#define NEXT_SA(ap) (ap) = (struct sockaddr *) \ +#define NEXT_SA(ap) (ap) = (struct sockaddr *) \ ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\ sizeof(u_long)) :\ sizeof(u_long))) -struct if_msghdr **iflist; -int iflist_init_ok; -size_t ifblock_size; -char *ifblock; +struct if_msghdr **iflist; +int iflist_init_ok; +size_t ifblock_size; +char *ifblock; -static void get_iflist __P((char **buf, size_t *size)); -static void parse_iflist __P((struct if_msghdr ***ifmlist_p, char *buf, +static void get_iflist __P((char **buf, size_t *size)); +static void parse_iflist __P((struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize)); static void get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) { int i; - + for (i = 0; i < RTAX_MAX; i++) { if (addrs & (1 << i)) { rti_info[i] = sa; @@ -108,6 +122,8 @@ if_nametosdl(char *name) if ((sa = rti_info[RTAX_IFP]) != NULL) { if (sa->sa_family == AF_LINK) { sdl = (struct sockaddr_dl *)sa; + if (strlen(name) != sdl->sdl_nlen) + continue; /* not same len */ if (strncmp(&sdl->sdl_data[0], name, sdl->sdl_nlen) == 0) { @@ -132,6 +148,7 @@ if_nametosdl(char *name) int if_getmtu(char *name) { +#if 0 struct ifreq ifr; int s; @@ -148,6 +165,25 @@ if_getmtu(char *name) close(s); return(ifr.ifr_mtu); +#else + struct ifaddrs *ifap, *ifa; + struct if_data *ifd; + + if (getifaddrs(&ifap) < 0) + return(0); + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (strcmp(ifa->ifa_name, name) == 0) { + ifd = ifa->ifa_data; + freeifaddrs(ifap); + if (ifd) + return ifd->ifi_mtu; + else + return 0; + } + } + freeifaddrs(ifap); + return 0; +#endif } /* give interface index and its old flags, then new flags returned */ @@ -170,11 +206,10 @@ if_getflags(int ifindex, int oifflags) close(s); return (oifflags & ~IFF_UP); } - close(s); return (ifr.ifr_flags); } -#define ROUNDUP8(a) (1 + (((a) - 1) | 7)) +#define ROUNDUP8(a) (1 + (((a) - 1) | 7)) int lladdropt_length(struct sockaddr_dl *sdl) { @@ -233,9 +268,9 @@ get_rtinfo(char *buf, size_t *len) return(0); } -#define FILTER_MATCH(type, filter) ((0x1 << type) & filter) -#define SIN6(s) ((struct sockaddr_in6 *)(s)) -#define SDL(s) ((struct sockaddr_dl *)(s)) +#define FILTER_MATCH(type, filter) ((0x1 << type) & filter) +#define SIN6(s) ((struct sockaddr_in6 *)(s)) +#define SDL(s) ((struct sockaddr_dl *)(s)) char * get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter) { @@ -377,7 +412,7 @@ get_prefixlen(char *buf) struct sockaddr *sa, *rti_info[RTAX_MAX]; int masklen; u_char *p, *lim; - + sa = (struct sockaddr *)(rtm + 1); get_rtaddrs(rtm->rtm_addrs, sa, rti_info); sa = rti_info[RTAX_NETMASK]; @@ -553,5 +588,4 @@ init_iflist() /* make list of pointers to each if_msghdr */ parse_iflist(&iflist, ifblock, ifblock_size); - } diff --git a/usr.sbin/rtadvd/if.h b/usr.sbin/rtadvd/if.h index e8e14d4..8d74557 100644 --- a/usr.sbin/rtadvd/if.h +++ b/usr.sbin/rtadvd/if.h @@ -1,7 +1,9 @@ +/* $KAME: if.h,v 1.2 2000/05/16 13:34:13 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -13,7 +15,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -29,29 +31,30 @@ * $FreeBSD$ */ -#define RTADV_TYPE2BITMASK(type) (0x1 << type) +#define RTADV_TYPE2BITMASK(type) (0x1 << type) -extern struct if_msghdr **iflist; -extern size_t ifblock_size; -extern char *ifblock; +extern struct if_msghdr **iflist; +extern size_t ifblock_size; +extern char *ifblock; -struct sockaddr_dl *if_nametosdl __P((char *name)); -int if_getmtu __P((char *name)); -int if_getflags __P((int ifindex, int oifflags)); -int lladdropt_length __P((struct sockaddr_dl *sdl)); -void lladdropt_fill __P((struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt)); -int rtbuf_len __P((void)); -int get_rtinfo __P((char *buf, size_t *len)); -char *get_next_msg __P((char *buf, char *lim, int ifindex, size_t *lenp, +struct nd_opt_hdr; +struct sockaddr_dl *if_nametosdl __P((char *name)); +int if_getmtu __P((char *name)); +int if_getflags __P((int ifindex, int oifflags)); +int lladdropt_length __P((struct sockaddr_dl *sdl)); +void lladdropt_fill __P((struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt)); +int rtbuf_len __P((void)); +int get_rtinfo __P((char *buf, size_t *len)); +char *get_next_msg __P((char *buf, char *lim, int ifindex, size_t *lenp, int filter)); -struct in6_addr *get_addr __P((char *buf)); -int get_rtm_ifindex __P((char *buf)); -int get_ifm_ifindex __P((char *buf)); -int get_ifam_ifindex __P((char *buf)); -int get_ifm_flags __P((char *buf)); -int get_prefixlen __P((char *buf)); -int rtmsg_type __P((char *buf)); -int ifmsg_type __P((char *buf)); -int rtmsg_len __P((char *buf)); -int ifmsg_len __P((char *buf)); -void init_iflist __P((void)); +struct in6_addr *get_addr __P((char *buf)); +int get_rtm_ifindex __P((char *buf)); +int get_ifm_ifindex __P((char *buf)); +int get_ifam_ifindex __P((char *buf)); +int get_ifm_flags __P((char *buf)); +int get_prefixlen __P((char *buf)); +int rtmsg_type __P((char *buf)); +int ifmsg_type __P((char *buf)); +int rtmsg_len __P((char *buf)); +int ifmsg_len __P((char *buf)); +void init_iflist __P((void)); diff --git a/usr.sbin/rtadvd/pathnames.h b/usr.sbin/rtadvd/pathnames.h index cd8b0e0..85ca33c 100644 --- a/usr.sbin/rtadvd/pathnames.h +++ b/usr.sbin/rtadvd/pathnames.h @@ -1,2 +1,4 @@ -/* $FreeBSD$ */ +/* $KAME$ */ +/* $FreeBSD$ */ + #define _PATH_RTADVDCONF "/etc/rtadvd.conf" diff --git a/usr.sbin/rtadvd/rrenum.c b/usr.sbin/rtadvd/rrenum.c index f4c71f1..f64ebc3 100644 --- a/usr.sbin/rtadvd/rrenum.c +++ b/usr.sbin/rtadvd/rrenum.c @@ -1,3 +1,5 @@ +/* $KAME: rrenum.c,v 1.3 2000/05/16 13:34:14 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. @@ -35,7 +37,9 @@ #include <sys/sysctl.h> #include <net/if.h> +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 #include <net/if_var.h> +#endif /* __FreeBSD__ >= 3 */ #include <net/route.h> #include <netinet/in.h> #include <netinet/in_var.h> @@ -60,14 +64,15 @@ struct rr_operation { u_long rro_segnum_bits[8]; }; -static struct rr_operation rro; -static int rr_rcvifindex; -static int rrcmd2pco[4] = {0, - SIOCAIFPREFIX_IN6, - SIOCCIFPREFIX_IN6, - SIOCSGIFPREFIX_IN6 +static struct rr_operation rro; +static int rr_rcvifindex; +static int rrcmd2pco[RPM_PCO_MAX] = { + 0, + SIOCAIFPREFIX_IN6, + SIOCCIFPREFIX_IN6, + SIOCSGIFPREFIX_IN6 }; -static int s; +static int s = -1; /* * Check validity of a Prefix Control Operation(PCO). @@ -206,6 +211,12 @@ do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm) if ((rr_pco_check(len, rpm) != NULL)) return 1; + if (s == -1 && (s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, + strerror(errno)); + exit(1); + } + memset(&irr, 0, sizeof(irr)); irr.irr_origin = PR_ORIG_RR; irr.irr_m_len = rpm->rpm_matchlen; @@ -254,12 +265,6 @@ do_rr(int len, struct icmp6_router_renum *rr) /* get iflist block from kernel again, to get up-to-date information */ init_iflist(); - if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { - syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, - strerror(errno)); - exit(1); - } - while (cp < lim) { int rpmlen; @@ -268,7 +273,6 @@ do_rr(int len, struct icmp6_router_renum *rr) tooshort: syslog(LOG_ERR, "<%s> pkt too short. left len = %d. " "gabage at end of pkt?", __FUNCTION__, len); - close(s); return 1; } rpmlen = rpm->rpm_len << 3; @@ -284,7 +288,7 @@ do_rr(int len, struct icmp6_router_renum *rr) cp += rpmlen; len -= rpmlen; } - close(s); + return 0; } diff --git a/usr.sbin/rtadvd/rrenum.h b/usr.sbin/rtadvd/rrenum.h index d3c73a7..729b96f 100644 --- a/usr.sbin/rtadvd/rrenum.h +++ b/usr.sbin/rtadvd/rrenum.h @@ -1,7 +1,9 @@ +/* $KAME$ */ + /* * Copyright (C) 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -13,7 +15,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -29,6 +31,6 @@ * $FreeBSD$ */ -void rr_input __P((int len, struct icmp6_router_renum *rr, +void rr_input __P((int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi, struct sockaddr_in6 *from, struct in6_addr *dst)); diff --git a/usr.sbin/rtadvd/rtadvd.8 b/usr.sbin/rtadvd/rtadvd.8 index 2c56bae..5f1f91b 100644 --- a/usr.sbin/rtadvd/rtadvd.8 +++ b/usr.sbin/rtadvd/rtadvd.8 @@ -1,3 +1,5 @@ +.\" $KAME: rtadvd.8,v 1.8 2000/05/22 22:12:11 itojun Exp $ +.\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. .\" @@ -25,59 +27,58 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: rtadvd.8,v 1.1.1.1 1999/08/08 23:31:42 itojun Exp $ -.\" $FreeBSD$ +.\" $FreeBSD$ .\" .Dd May 17, 1998 .Dt RTADVD 8 -.Os KAME +.Os .Sh NAME .Nm rtadvd .Nd router advertisement daemon .Sh SYNOPSIS .Nm .Op Fl c Ar configfile -.Op Fl P Ar policy -.Op Fl dDfs +.Op Fl dDfmRs .Ar interface ... .Sh DESCRIPTION -.Nm Rtadvd +.Nm advertises router advertisement packet to the specified .Ar interfaces . .Pp The program will daemonize itself on invocation. -Then, it will voluntarily send router advertisement packet periodically. -If a router solicitation packet from host has reached the program, -the program will respond by router advertisement packet. +It will then periodically send router advertisement packets, as well +as in response to router solicitation messages sent by end hosts. .Pp -For each interface, which is called advertising interface, -content of router advertisement can be described in +Router advertisements can be configured on a per-interface basis, as +described in .Xr rtadvd.conf 5 . .Pp -If there is no description for the interface in the configuration file -or if the configuration file does not exist, +In the event of no configuration file entry for an interface, +or if the configuration file does not exist altogether, .Nm sets all the parameters to their default values. In particular, .Nm -gets all the interface routes from the routing table and advertises +reads all the interface routes from the routing table and advertises them as on-link prefixes. .Pp -.Nm Rtadvd -watches the routing table. +.Nm +also watches the routing table. By default, if an interface direct route is -added/deleted on an advertising interface, +added/deleted on an advertising interface and no static prefixes are +specified by the configuration file, .Nm adds/deletes the corresponding prefix to/from its advertising list, respectively. -If you do not want to enable this feature, you should specify the +The .Ic Fl s -command line option when advocation. +may be used to disable this behavior. +Moreover, if the status of an advertising interface changes, +.Nm +will start or stop sending router advertisements according +to the latest status. .Pp -.Nm Rtadvd -can also receive router renumbering packets, and can do router -renumbering for the system it runs on, as the contents of those -packets. +The command line options are: .Bl -tag -width indent .\" .It Fl c @@ -87,37 +88,53 @@ for the configuration file. By default, .Pa /etc/rtadvd.conf is used. -.It Fl P -Specifies that -.Nm -receives router renumbering messages. -Also, specifies IPsec policy for -rrenumd sessions. -Because router renumbering can change the system's -IPv6 prefix, its messages must be protected by IPsec. -For details about -.Ar policy , -please refer to -.Xr ipsec 4 -and -.Xr ipsec_set_policy 3 . .It Fl d -Debug. +Print debugging information. .It Fl D -More debug. +Even more debugging information is printed. .It Fl f -Foreground mode. -Do not become daemon. +Foreground mode (useful when debugging). +.It Fl m +Enables mobile IPv6 support. +This changes the content of router advertisement option, as well as +permitted configuration directives. +.It Fl R +Accept router renumbering requests. +If you enable it, certain IPsec setup is suggested for security reasons. .It Fl s -Static prefix. -Do not watch the routing table. +Do not add or delete prefixes dynamically. +Only statically configured prefixes, if any, will be advertised. .El +.Pp +Upon receipt of signal +.Dv SIGUSR1 , +.Nm +will dump the current internal state into +.Pa /var/run/rtadvd.dump. +.Pp +Use +.Dv SIGTERM +to kill +.Nm +gracefully. +In this case, +.Nm +will transmit router advertisement with router lifetime 0 +to all the interfaces +.Pq according to RFC2461 6.2.5 . .Sh RETURN VALUES The program exits with 0 on success, and non-zero on failures. .Sh FILES .Bl -tag -width /etc/rtadvd.conf -compact .It Pa /etc/rtadvd.conf The default configuration file. +.It Pa /var/run/rtadvd.pid +contains pid of the currently running +.Nm rtadvd . +.It Pa /var/run/rtadvd.dump +on which +.Nm +dumps its internal state. .El .Sh SEE ALSO .Xr daemon 3 , @@ -128,10 +145,9 @@ The .Nm command first appeared in WIDE Hydrangea IPv6 protocol stack kit. .Sh CAVEAT -Do not perform router advertisement toward upstream direction, -you should only advertise to downstream direction. -If you advertise toward upstream by mistake, -you will see icmp6 redirect storm on that subnet. -This is because of the specification, -which says that advertising router is assumed to become -the default outgoing router for end hosts in the subnet. +Router advertisements should only be performed downstream. +Erroneous upstream advertisements will cause +.Xr icmp6 4 +redirect packet storms in the subnet, as (per the specification) the +advertising router is assumed to become the default router for +end hosts in the subnet. diff --git a/usr.sbin/rtadvd/rtadvd.c b/usr.sbin/rtadvd/rtadvd.c index d5a5845..1cd602e 100644 --- a/usr.sbin/rtadvd/rtadvd.c +++ b/usr.sbin/rtadvd/rtadvd.c @@ -1,7 +1,9 @@ +/* $KAME: rtadvd.c,v 1.30 2000/06/22 20:16:12 itojun Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -13,7 +15,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -44,17 +46,13 @@ #include <arpa/inet.h> -#ifdef IPSEC -#include <netinet6/ipsec.h> -#endif /*IPSEC*/ - #include <time.h> #include <unistd.h> #include <stdio.h> +#include <stdlib.h> #include <err.h> #include <errno.h> #include <string.h> -#include <sysexits.h> #include <stdlib.h> #include <syslog.h> #include "rtadvd.h" @@ -63,74 +61,85 @@ #include "timer.h" #include "if.h" #include "config.h" +#include "dump.h" + +struct msghdr rcvmhdr; +static u_char *rcvcmsgbuf; +static size_t rcvcmsgbuflen; +static u_char *sndcmsgbuf = NULL; +static size_t sndcmsgbuflen; +static int do_dump; +struct msghdr sndmhdr; +struct iovec rcviov[2]; +struct iovec sndiov[2]; +struct sockaddr_in6 from; +struct sockaddr_in6 sin6_allnodes = {sizeof(sin6_allnodes), AF_INET6}; +static char *dumpfilename = "/var/run/rtadvd.dump"; /* XXX: should be configurable */ +static char *pidfilename = "/var/run/rtadvd.pid"; /* should be configurable */ +int sock, rtsock; +#ifdef MIP6 +int mobileip6 = 0; +#endif +int accept_rr = 0; +int dflag = 0, sflag = 0; -struct msghdr rcvmhdr; -static u_char rcvcmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo)) + - CMSG_SPACE(sizeof(int))]; -struct msghdr sndmhdr; -struct iovec rcviov[2]; -struct iovec sndiov[2]; -struct sockaddr_in6 from; -struct sockaddr_in6 sin6_allnodes = {sizeof(sin6_allnodes), AF_INET6}; -int sock, rrsock, rtsock; -int accept_rr = 0; -int dflag = 0, sflag = 0; - -u_char *conffile = NULL; - -struct rainfo *ralist = NULL; -struct nd_optlist { - struct nd_optlist *next; - struct nd_opt_hdr *opt; +u_char *conffile = NULL; + +struct rainfo *ralist = NULL; +struct nd_optlist { + struct nd_optlist *next; + struct nd_opt_hdr *opt; }; union nd_opts { - struct nd_opt_hdr *nd_opt_array[7]; + struct nd_opt_hdr *nd_opt_array[7]; struct { - struct nd_opt_hdr *zero; - struct nd_opt_hdr *src_lladdr; - struct nd_opt_hdr *tgt_lladdr; - struct nd_opt_prefix_info *pi; - struct nd_opt_rd_hdr *rh; - struct nd_opt_mtu *mtu; - struct nd_optlist *list; + struct nd_opt_hdr *zero; + struct nd_opt_hdr *src_lladdr; + struct nd_opt_hdr *tgt_lladdr; + struct nd_opt_prefix_info *pi; + struct nd_opt_rd_hdr *rh; + struct nd_opt_mtu *mtu; + struct nd_optlist *list; } nd_opt_each; }; -#define nd_opts_src_lladdr nd_opt_each.src_lladdr -#define nd_opts_tgt_lladdr nd_opt_each.tgt_lladdr -#define nd_opts_pi nd_opt_each.pi -#define nd_opts_rh nd_opt_each.rh -#define nd_opts_mtu nd_opt_each.mtu -#define nd_opts_list nd_opt_each.list - -#define NDOPT_FLAG_SRCLINKADDR 0x1 -#define NDOPT_FLAG_TGTLINKADDR 0x2 -#define NDOPT_FLAG_PREFIXINFO 0x4 -#define NDOPT_FLAG_RDHDR 0x8 -#define NDOPT_FLAG_MTU 0x10 +#define nd_opts_src_lladdr nd_opt_each.src_lladdr +#define nd_opts_tgt_lladdr nd_opt_each.tgt_lladdr +#define nd_opts_pi nd_opt_each.pi +#define nd_opts_rh nd_opt_each.rh +#define nd_opts_mtu nd_opt_each.mtu +#define nd_opts_list nd_opt_each.list + +#define NDOPT_FLAG_SRCLINKADDR 0x1 +#define NDOPT_FLAG_TGTLINKADDR 0x2 +#define NDOPT_FLAG_PREFIXINFO 0x4 +#define NDOPT_FLAG_RDHDR 0x8 +#define NDOPT_FLAG_MTU 0x10 u_int32_t ndopt_flags[] = { 0, NDOPT_FLAG_SRCLINKADDR, NDOPT_FLAG_TGTLINKADDR, NDOPT_FLAG_PREFIXINFO, NDOPT_FLAG_RDHDR, NDOPT_FLAG_MTU }; -int main __P((int, char *[])); -static void sock_open __P((int *, int, char *)); -static void rtsock_open __P((void)); -static void rtadvd_input __P((int)); -static void rs_input __P((int, struct nd_router_solicit *, +int main __P((int, char *[])); +static void die __P((int)); +static void sock_open __P((void)); +static void rtsock_open __P((void)); +static void rtadvd_input __P((void)); +static void rs_input __P((int, struct nd_router_solicit *, struct in6_pktinfo *, struct sockaddr_in6 *)); -static void ra_input __P((int, struct nd_router_advert *, +static void ra_input __P((int, struct nd_router_advert *, struct in6_pktinfo *, struct sockaddr_in6 *)); -static void prefix_check __P((struct nd_opt_prefix_info *, struct rainfo *, - struct sockaddr_in6 *)); -static int nd6_options __P((struct nd_opt_hdr *, int, +static int prefix_check __P((struct nd_opt_prefix_info *, struct rainfo *, + struct sockaddr_in6 *)); +static int nd6_options __P((struct nd_opt_hdr *, int, union nd_opts *, u_int32_t)); -static void free_ndopts __P((union nd_opts *)); -static struct rainfo *if_indextorainfo __P((int)); -static void ra_output __P((struct rainfo *)); -static void rtmsg_input __P((void)); -struct prefix *find_prefix __P((struct rainfo *, struct in6_addr *, int)); +static void free_ndopts __P((union nd_opts *)); +static struct rainfo *if_indextorainfo __P((int)); +static void ra_output __P((struct rainfo *)); +static void rtmsg_input __P((void)); +static void rtadvd_set_dump_file __P((void)); +struct prefix *find_prefix __P((struct rainfo *, struct in6_addr *, int)); int main(argc, argv) @@ -142,21 +151,19 @@ main(argc, argv) struct timeval *timeout; int i, ch; int fflag = 0; -#ifdef IPSEC -#ifdef IPSEC_POLICY_IPSEC - char *policy = NULL; -#endif /*IPSEC_POLICY_IPSEC*/ -#endif /*IPSEC*/ + FILE *pidfp; + pid_t pid; - openlog(*argv, LOG_NDELAY|LOG_PID, LOG_DAEMON); + openlog("rtadvd", LOG_NDELAY|LOG_PID, LOG_DAEMON); /* get command line options and arguments */ -#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) - while ((ch = getopt(argc, argv, "c:dDfP:R:s")) != -1) +#ifdef MIP6 +#define OPTIONS "c:dDfmRs" #else - while ((ch = getopt(argc, argv, "c:dDfR:s")) != -1) +#define OPTIONS "c:dDfRs" #endif - { + while ((ch = getopt(argc, argv, OPTIONS)) != -1) { +#undef OPTIONS switch(ch) { case 'c': conffile = optarg; @@ -170,23 +177,28 @@ main(argc, argv) case 'f': fflag = 1; break; -#ifdef IPSEC -#ifdef IPSEC_POLICY_IPSEC - case 'P': - policy = strdup(optarg); +#ifdef MIP6 + case 'm': + mobileip6 = 1; + break; +#endif + case 'R': accept_rr = 1; break; -#endif /*IPSEC_POLICY_IPSEC*/ -#endif /*IPSEC*/ case 's': sflag = 1; + break; } } argc -= optind; argv += optind; if (argc == 0) { fprintf(stderr, - "usage: rtadvd [-c conffile] [-d|D] [-f] [-s]" +#ifdef MIP6 + "usage: rtadvd [-dDfmRs] [-c conffile] " +#else + "usage: rtadvd [-dDfRs] [-c conffile] " +#endif "interfaces...\n"); exit(1); } @@ -213,41 +225,63 @@ main(argc, argv) fprintf(stderr, "fatal: inet_pton failed\n"); exit(1); } - sock_open(&sock, 0, NULL); - if (accept_rr != 0) - sock_open(&rrsock, 1, policy); + sock_open(); if (!fflag) daemon(1, 0); + /* record the current PID */ + pid = getpid(); + if ((pidfp = fopen(pidfilename, "w")) == NULL) + syslog(LOG_ERR, + "<%s> failed to open a log file(%s), run anyway.", + __FUNCTION__, pidfilename); + else { + fprintf(pidfp, "%d\n", pid); + fclose(pidfp); + } + FD_ZERO(&fdset); FD_SET(sock, &fdset); - if (accept_rr) - FD_SET(rrsock, &fdset); - maxfd = sock > rrsock ? sock : rrsock; - if (sflag == 0) { - rtsock_open(); - FD_SET(rtsock, &fdset); - if (rtsock > maxfd) + maxfd = sock; + rtsock_open(); + FD_SET(rtsock, &fdset); + if (rtsock > sock) maxfd = rtsock; - } + + signal(SIGTERM, (void *)die); + signal(SIGUSR1, (void *)rtadvd_set_dump_file); while (1) { struct fd_set select_fd = fdset; /* reinitialize */ + if (do_dump) { /* SIGUSR1 */ + do_dump = 0; + rtadvd_dump_file(dumpfilename); + } + /* timer expiration check and reset the timer */ timeout = rtadvd_check_timer(); - syslog(LOG_DEBUG, - "<%s> set timer to %ld:%ld. waiting for inputs " - "or timeout", - __FUNCTION__, - timeout->tv_sec, timeout->tv_usec); + if (timeout != NULL) { + syslog(LOG_DEBUG, + "<%s> set timer to %ld:%ld. waiting for " + "inputs or timeout", + __FUNCTION__, + (long int)timeout->tv_sec, + (long int)timeout->tv_usec); + } else { + syslog(LOG_DEBUG, + "<%s> there's no timer. waiting for inputs", + __FUNCTION__); + } if ((i = select(maxfd + 1, &select_fd, - NULL, NULL, timeout)) < 0){ - syslog(LOG_ERR, "<%s> select: %s", - __FUNCTION__, strerror(errno)); + NULL, NULL, timeout)) < 0) { + /* EINTR would occur upon SIGUSR1 for status dump */ + if (errno != EINTR) + syslog(LOG_ERR, "<%s> select: %s", + __FUNCTION__, strerror(errno)); continue; } if (i == 0) /* timeout */ @@ -255,17 +289,47 @@ main(argc, argv) if (sflag == 0 && FD_ISSET(rtsock, &select_fd)) rtmsg_input(); if (FD_ISSET(sock, &select_fd)) - rtadvd_input(sock); - if (accept_rr && FD_ISSET(rrsock, &select_fd)) - rtadvd_input(rrsock); + rtadvd_input(); } exit(0); /* NOTREACHED */ } static void +rtadvd_set_dump_file() +{ + do_dump = 1; +} + +static void +die(sig) + int sig; +{ + struct rainfo *ra; + int i; + const int retrans = MAX_FINAL_RTR_ADVERTISEMENTS; + + if (dflag > 1) { + syslog(LOG_DEBUG, "<%s> cease to be an advertising router\n", + __FUNCTION__); + } + + for (ra = ralist; ra; ra = ra->next) { + ra->lifetime = 0; + make_packet(ra); + } + for (i = 0; i < retrans; i++) { + for (ra = ralist; ra; ra = ra->next) + ra_output(ra); + sleep(MIN_DELAY_BETWEEN_RAS); + } + exit(0); + /*NOTREACHED*/ +} + +static void rtmsg_input() { - int n, type, ifindex, plen; + int n, type, ifindex = 0, plen; size_t len; char msg[2048], *next, *lim; u_char ifname[16]; @@ -284,8 +348,8 @@ rtmsg_input() } if (n > rtmsg_len(msg)) { /* - * This usually won't happen for messages received on - * an routing socket. + * This usually won't happen for messages received on + * a routing socket. */ if (dflag > 1) syslog(LOG_DEBUG, @@ -293,10 +357,16 @@ rtmsg_input() "1st routing message len. multiple messages?" " read %d bytes, but 1st msg len = %d", __FUNCTION__, n, rtmsg_len(msg)); +#if 0 + /* adjust length */ + n = rtmsg_len(msg); +#endif } lim = msg + n; for (next = msg; next < lim; next += len) { + int oldifflags; + next = get_next_msg(next, lim, 0, &len, RTADV_TYPE2BITMASK(RTM_ADD) | RTADV_TYPE2BITMASK(RTM_DELETE) | @@ -326,7 +396,7 @@ rtmsg_input() __FUNCTION__, __LINE__, type, if_indextoname(ifindex, ifname)); } - return; + continue; } if ((rai = if_indextorainfo(ifindex)) == NULL) { @@ -337,16 +407,20 @@ rtmsg_input() __FUNCTION__, if_indextoname(ifindex, ifname)); } - return; + continue; } + oldifflags = iflist[ifindex]->ifm_flags; switch(type) { case RTM_ADD: - /* init iffalgs because it may have changed */ + /* init ifflags because it may have changed */ iflist[ifindex]->ifm_flags = if_getflags(ifindex, iflist[ifindex]->ifm_flags); + if (sflag) + break; /* we aren't interested in prefixes */ + addr = get_addr(msg); plen = get_prefixlen(msg); /* sanity check for plen */ @@ -355,7 +429,7 @@ rtmsg_input() syslog(LOG_INFO, "<%s> new interface route's" "plen %d is invalid for a prefix", __FUNCTION__, plen); - return; + break; } prefix = find_prefix(rai, addr, plen); if (prefix) { @@ -371,7 +445,7 @@ rtmsg_input() plen, rai->ifname); } - return; + break; } make_prefix(rai, ifindex, addr, plen); break; @@ -381,6 +455,9 @@ rtmsg_input() if_getflags(ifindex, iflist[ifindex]->ifm_flags); + if (sflag) + break; + addr = get_addr(msg); plen = get_prefixlen(msg); /* sanity check for plen */ @@ -390,7 +467,7 @@ rtmsg_input() "route's" "plen %d is invalid for a prefix", __FUNCTION__, plen); - return; + break; } prefix = find_prefix(rai, addr, plen); if (prefix == NULL) { @@ -406,7 +483,7 @@ rtmsg_input() plen, rai->ifname); } - return; + break; } delete_prefix(rai, prefix); break; @@ -430,16 +507,42 @@ rtmsg_input() } return; } + + /* check if an interface flag is changed */ + if ((oldifflags & IFF_UP) != 0 && /* UP to DOWN */ + (iflist[ifindex]->ifm_flags & IFF_UP) == 0) { + syslog(LOG_INFO, + "<%s> interface %s becomes down. stop timer.", + __FUNCTION__, rai->ifname); + rtadvd_remove_timer(&rai->timer); + } + else if ((oldifflags & IFF_UP) == 0 && /* DOWN to UP */ + (iflist[ifindex]->ifm_flags & IFF_UP) != 0) { + syslog(LOG_INFO, + "<%s> interface %s becomes up. restart timer.", + __FUNCTION__, rai->ifname); + + rai->initcounter = 0; /* reset the counter */ + rai->waiting = 0; /* XXX */ + rai->timer = rtadvd_add_timer(ra_timeout, + ra_timer_update, + rai, rai); + ra_timer_update((void *)rai, &rai->timer->tm); + rtadvd_set_timer(&rai->timer->tm, rai->timer); + } } return; } void -rtadvd_input(skt) +rtadvd_input() { int i; int *hlimp = NULL; +#ifdef OLDRAWSOCKET + struct ip6_hdr *ip; +#endif struct icmp6_hdr *icp; int ifindex = 0; struct cmsghdr *cm; @@ -452,8 +555,8 @@ rtadvd_input(skt) * be modified if we had received a message before setting * receive options. */ - rcvmhdr.msg_controllen = sizeof(rcvcmsgbuf); - if ((i = recvmsg(skt, &rcvmhdr, 0)) < 0) + rcvmhdr.msg_controllen = rcvcmsgbuflen; + if ((i = recvmsg(sock, &rcvmhdr, 0)) < 0) return; /* extract optional information via Advanced API */ @@ -485,6 +588,29 @@ rtadvd_input(skt) return; } + /* + * If we happen to receive data on an interface which is now down, + * just discard the data. + */ + if ((iflist[pi->ipi6_ifindex]->ifm_flags & IFF_UP) == 0) { + syslog(LOG_INFO, + "<%s> received data on a disabled interface (%s)", + __FUNCTION__, + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + +#ifdef OLDRAWSOCKET + if (i < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) { + syslog(LOG_ERR, + "<%s> packet size(%d) is too short", + __FUNCTION__, i); + return; + } + + ip = (struct ip6_hdr *)rcvmhdr.msg_iov[0].iov_base; + icp = (struct icmp6_hdr *)(ip + 1); /* XXX: ext. hdr? */ +#else if (i < sizeof(struct icmp6_hdr)) { syslog(LOG_ERR, "<%s> packet size(%d) is too short", @@ -493,13 +619,18 @@ rtadvd_input(skt) } icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base; +#endif switch(icp->icmp6_type) { case ND_ROUTER_SOLICIT: - /* hop limit verification - RFC-2461 6.1.1 */ + /* + * Message verification - RFC-2461 6.1.1 + * XXX: these checks must be done in the kernel as well, + * but we can't completely rely on them. + */ if (*hlimp != 255) { syslog(LOG_NOTICE, - "<%s> invalid hop limit(%d) " + "<%s> RS with invalid hop limit(%d) " "received from %s on %s", __FUNCTION__, *hlimp, inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, @@ -507,13 +638,36 @@ rtadvd_input(skt) if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } + if (icp->icmp6_code) { + syslog(LOG_NOTICE, + "<%s> RS with invalid ICMP6 code(%d) " + "received from %s on %s", + __FUNCTION__, icp->icmp6_code, + inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + if (i < sizeof(struct nd_router_solicit)) { + syslog(LOG_NOTICE, + "<%s> RS from %s on %s does not have enough " + "length (len = %d)", + __FUNCTION__, + inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf), i); + return; + } rs_input(i, (struct nd_router_solicit *)icp, pi, &from); break; case ND_ROUTER_ADVERT: - /* hop limit verification - RFC-2461 6.1.1 */ + /* + * Message verification - RFC-2461 6.1.2 + * XXX: there's a same dilemma as above... + */ if (*hlimp != 255) { syslog(LOG_NOTICE, - "<%s> invalid hop limit(%d) " + "<%s> RA with invalid hop limit(%d) " "received from %s on %s", __FUNCTION__, *hlimp, inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, @@ -521,6 +675,26 @@ rtadvd_input(skt) if_indextoname(pi->ipi6_ifindex, ifnamebuf)); return; } + if (icp->icmp6_code) { + syslog(LOG_NOTICE, + "<%s> RA with invalid ICMP6 code(%d) " + "received from %s on %s", + __FUNCTION__, icp->icmp6_code, + inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + if (i < sizeof(struct nd_router_advert)) { + syslog(LOG_NOTICE, + "<%s> RA from %s on %s does not have enough " + "length (len = %d)", + __FUNCTION__, + inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf), i); + return; + } ra_input(i, (struct nd_router_advert *)icp, pi, &from); break; case ICMP6_ROUTER_RENUMBERING: @@ -608,6 +782,8 @@ rs_input(int len, struct nd_router_solicit *rs, goto done; } + ra->rsinput++; /* increment statistics */ + /* * Decide whether to send RA according to the rate-limit * consideration. @@ -615,6 +791,19 @@ rs_input(int len, struct nd_router_solicit *rs, { long delay; /* must not be greater than 1000000 */ struct timeval interval, now, min_delay, tm_tmp, *rest; + struct soliciter *sol; + + /* + * record sockaddr waiting for RA, if possible + */ + sol = (struct soliciter *)malloc(sizeof(*sol)); + if (sol) { + sol->addr = *from; + /*XXX RFC2553 need clarification on flowinfo */ + sol->addr.sin6_flowinfo = 0; + sol->next = ra->soliciter; + ra->soliciter = sol->next; + } /* * If there is already a waiting RS packet, don't @@ -658,7 +847,7 @@ rs_input(int len, struct nd_router_solicit *rs, TIMEVAL_ADD(&min_delay, &interval, &interval); } rtadvd_set_timer(&interval, ra->timer); - goto done; + goto done; } done: @@ -675,6 +864,7 @@ ra_input(int len, struct nd_router_advert *ra, union nd_opts ndopts; char *on_off[] = {"OFF", "ON"}; u_int32_t reachabletime, retranstimer, mtu; + int inconsistent = 0; syslog(LOG_DEBUG, "<%s> RA received from %s on %s", @@ -682,13 +872,13 @@ ra_input(int len, struct nd_router_advert *ra, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), if_indextoname(pi->ipi6_ifindex, ifnamebuf)); - + /* ND option check */ memset(&ndopts, 0, sizeof(ndopts)); if (nd6_options((struct nd_opt_hdr *)(ra + 1), len - sizeof(struct nd_router_advert), &ndopts, - NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU)) { + NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU)) { syslog(LOG_ERR, "<%s> ND option check failed for an RA from %s on %s", __FUNCTION__, @@ -711,6 +901,8 @@ ra_input(int len, struct nd_router_advert *ra, if_indextoname(pi->ipi6_ifindex, ifnamebuf)); goto done; } + rai->rainput++; /* increment statistics */ + /* Cur Hop Limit value */ if (ra->nd_ra_curhoplimit && rai->hoplimit && ra->nd_ra_curhoplimit != rai->hoplimit) { @@ -723,6 +915,7 @@ ra_input(int len, struct nd_router_advert *ra, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), rai->hoplimit); + inconsistent++; } /* M flag */ if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != @@ -736,6 +929,7 @@ ra_input(int len, struct nd_router_advert *ra, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), on_off[rai->managedflg]); + inconsistent++; } /* O flag */ if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != @@ -749,6 +943,7 @@ ra_input(int len, struct nd_router_advert *ra, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), on_off[rai->otherflg]); + inconsistent++; } /* Reachable Time */ reachabletime = ntohl(ra->nd_ra_reachable); @@ -763,6 +958,7 @@ ra_input(int len, struct nd_router_advert *ra, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), rai->reachabletime); + inconsistent++; } /* Retrans Timer */ retranstimer = ntohl(ra->nd_ra_retransmit); @@ -777,6 +973,7 @@ ra_input(int len, struct nd_router_advert *ra, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), rai->retranstimer); + inconsistent++; } /* Values in the MTU options */ if (ndopts.nd_opts_mtu) { @@ -790,34 +987,50 @@ ra_input(int len, struct nd_router_advert *ra, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), rai->linkmtu); + inconsistent++; } } /* Preferred and Valid Lifetimes for prefixes */ { struct nd_optlist *optp = ndopts.nd_opts_list; - - if (ndopts.nd_opts_pi) - prefix_check(ndopts.nd_opts_pi, rai, from); + + if (ndopts.nd_opts_pi) { + if (prefix_check(ndopts.nd_opts_pi, rai, from)) + inconsistent++; + } while (optp) { - prefix_check((struct nd_opt_prefix_info *)optp->opt, - rai, from); + if (prefix_check((struct nd_opt_prefix_info *)optp->opt, + rai, from)) + inconsistent++; optp = optp->next; } } + if (inconsistent) { + printf("RA input %d inconsistents\n", inconsistent); + rai->rainconsistent++; + } + done: free_ndopts(&ndopts); return; } -static void +/* return a non-zero value if the received prefix is inconsitent with ours */ +static int prefix_check(struct nd_opt_prefix_info *pinfo, struct rainfo *rai, struct sockaddr_in6 *from) { u_int32_t preferred_time, valid_time; struct prefix *pp; + int inconsistent = 0; u_char ntopbuf[INET6_ADDRSTRLEN], prefixbuf[INET6_ADDRSTRLEN]; +#if 0 /* impossible */ + if (pinfo->nd_opt_pi_type != ND_OPT_PREFIX_INFORMATION) + return(0); +#endif + /* * log if the adveritsed prefix has link-local scope(sanity check?) */ @@ -845,11 +1058,11 @@ prefix_check(struct nd_opt_prefix_info *pinfo, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), rai->ifname); - return; + return(0); } preferred_time = ntohl(pinfo->nd_opt_pi_preferred_time); - if (preferred_time != pp->preflifetime) + if (preferred_time != pp->preflifetime) { syslog(LOG_WARNING, "<%s> prefeerred lifetime for %s/%d" " inconsistent on %s:" @@ -862,9 +1075,11 @@ prefix_check(struct nd_opt_prefix_info *pinfo, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), pp->preflifetime); + inconsistent++; + } valid_time = ntohl(pinfo->nd_opt_pi_valid_time); - if (valid_time != pp->validlifetime) + if (valid_time != pp->validlifetime) { syslog(LOG_WARNING, "<%s> valid lifetime for %s/%d" " inconsistent on %s:" @@ -877,6 +1092,10 @@ prefix_check(struct nd_opt_prefix_info *pinfo, inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), pp->validlifetime); + inconsistent++; + } + + return(inconsistent); } struct prefix * @@ -993,19 +1212,32 @@ free_ndopts(union nd_opts *ndopts) } void -sock_open(int *sockp, int is_rr, char *policy) +sock_open() { struct icmp6_filter filt; struct ipv6_mreq mreq; struct rainfo *ra = ralist; int on; - char *rtr_str; /* XXX: should be max MTU attached to the node */ static u_char answer[1500]; - static u_char sndcmsgbuf[CMSG_SPACE(sizeof(struct in6_pktinfo)) + - CMSG_SPACE(sizeof(int))]; - if ((*sockp = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { + rcvcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + + CMSG_SPACE(sizeof(int)); + rcvcmsgbuf = (u_char *)malloc(rcvcmsgbuflen); + if (rcvcmsgbuf == NULL) { + syslog(LOG_ERR, "<%s> not enough core", __FUNCTION__); + exit(1); + } + + sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + + CMSG_SPACE(sizeof(int)); + sndcmsgbuf = (u_char *)malloc(sndcmsgbuflen); + if (sndcmsgbuf == NULL) { + syslog(LOG_ERR, "<%s> not enough core", __FUNCTION__); + exit(1); + } + + if ((sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, strerror(errno)); exit(1); @@ -1013,77 +1245,73 @@ sock_open(int *sockp, int is_rr, char *policy) /* specify to tell receiving interface */ on = 1; - if (setsockopt(*sockp, IPPROTO_IPV6, IPV6_PKTINFO, &on, +#ifdef IPV6_RECVPKTINFO + if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, + sizeof(on)) < 0) { + syslog(LOG_ERR, "<%s> IPV6_RECVPKTINFO: %s", + __FUNCTION__, strerror(errno)); + exit(1); + } +#else /* old adv. API */ + if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)) < 0) { syslog(LOG_ERR, "<%s> IPV6_PKTINFO: %s", __FUNCTION__, strerror(errno)); exit(1); } +#endif on = 1; /* specify to tell value of hoplimit field of received IP6 hdr */ - if (setsockopt(*sockp, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, +#ifdef IPV6_RECVHOPLIMIT + if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, + sizeof(on)) < 0) { + syslog(LOG_ERR, "<%s> IPV6_RECVHOPLIMIT: %s", + __FUNCTION__, strerror(errno)); + exit(1); + } +#else /* old adv. API */ + if (setsockopt(sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on)) < 0) { syslog(LOG_ERR, "<%s> IPV6_HOPLIMIT: %s", __FUNCTION__, strerror(errno)); exit(1); } +#endif ICMP6_FILTER_SETBLOCKALL(&filt); - if (is_rr) + ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt); + ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); + if (accept_rr) ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt); - else { - ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt); - ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); - } - if (setsockopt(*sockp, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, + if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)) < 0) { syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s", __FUNCTION__, strerror(errno)); exit(1); } - -#ifdef IPSEC -#ifdef IPSEC_POLICY_IPSEC - if (is_rr && policy != NULL) { - char *buf; - - buf = ipsec_set_policy(policy, strlen(policy)); - if (buf == NULL) - errx(EX_CONFIG, ipsec_strerror()); - if (setsockopt(*sockp, IPPROTO_IPV6, IPV6_IPSEC_POLICY, - buf, ipsec_get_policylen(buf)) < 0) - err(EX_CONFIG, "ipsec policy cannot be configured"); - free(buf); - } -#endif /*IPSEC_POLICY_IPSEC*/ -#endif /*IPSEC*/ - /* * join all routers multicast address on each advertising interface. */ - rtr_str = is_rr ? ALLSITEROUTERS : ALLROUTERS; - if (inet_pton(AF_INET6, rtr_str, &mreq.ipv6mr_multiaddr.s6_addr) + if (inet_pton(AF_INET6, ALLROUTERS, &mreq.ipv6mr_multiaddr.s6_addr) != 1) { - syslog(LOG_ERR, "<%s> inet_pton for %s failed(library bug?)", - __FUNCTION__, rtr_str); + syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)", + __FUNCTION__); exit(1); } while(ra) { mreq.ipv6mr_interface = ra->ifindex; - if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, + if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &mreq, sizeof(mreq)) < 0) { - syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP for %s on" - "%s: %s", __FUNCTION__, - rtr_str, ra->ifname, strerror(errno)); + syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP on %s: %s", + __FUNCTION__, ra->ifname, strerror(errno)); exit(1); } ra = ra->next; } - if (is_rr) /* msghdrs should have been alreadey initialized. */ - return; - + /* initialize msghdr for receiving packets */ rcviov[0].iov_base = (caddr_t)answer; rcviov[0].iov_len = sizeof(answer); @@ -1092,15 +1320,15 @@ sock_open(int *sockp, int is_rr, char *policy) rcvmhdr.msg_iov = rcviov; rcvmhdr.msg_iovlen = 1; rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf; - rcvmhdr.msg_controllen = sizeof(rcvcmsgbuf); + rcvmhdr.msg_controllen = rcvcmsgbuflen; /* initialize msghdr for sending packets */ sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); sndmhdr.msg_iov = sndiov; sndmhdr.msg_iovlen = 1; sndmhdr.msg_control = (caddr_t)sndcmsgbuf; - sndmhdr.msg_controllen = sizeof(sndcmsgbuf); - + sndmhdr.msg_controllen = sndcmsgbuflen; + return; } @@ -1133,9 +1361,15 @@ ra_output(rainfo) struct rainfo *rainfo; { int i; - struct cmsghdr *cm; struct in6_pktinfo *pi; + struct soliciter *sol, *nextsol; + + if ((iflist[rainfo->ifindex]->ifm_flags & IFF_UP) == 0) { + syslog(LOG_DEBUG, "<%s> %s is not up, skip sending RA", + __FUNCTION__, rainfo->ifname); + return; + } sndmhdr.msg_name = (caddr_t)&sin6_allnodes; sndmhdr.msg_iov[0].iov_base = (caddr_t)rainfo->ra_data; @@ -1163,20 +1397,48 @@ struct rainfo *rainfo; syslog(LOG_DEBUG, "<%s> send RA on %s, # of waitings = %d", - __FUNCTION__, rainfo->ifname, rainfo->waiting); + __FUNCTION__, rainfo->ifname, rainfo->waiting); i = sendmsg(sock, &sndmhdr, 0); if (i < 0 || i != rainfo->ra_datalen) { if (i < 0) { - syslog(LOG_ERR, "<%s> sendmsg to %s: %s", - __FUNCTION__, rainfo->ifname, strerror(errno)); + syslog(LOG_ERR, "<%s> sendmsg on %s: %s", + __FUNCTION__, rainfo->ifname, + strerror(errno)); + } + } + + /* + * unicast advertisements + * XXX commented out. reason: though spec does not forbit it, unicast + * advert does not really help + */ + for (sol = rainfo->soliciter; sol; sol = nextsol) { + nextsol = sol->next; + +#if 0 + sndmhdr.msg_name = (caddr_t)&sol->addr; + i = sendmsg(sock, &sndmhdr, 0); + if (i < 0 || i != rainfo->ra_datalen) { + if (i < 0) { + syslog(LOG_ERR, + "<%s> unicast sendmsg on %s: %s", + __FUNCTION__, rainfo->ifname, + strerror(errno)); + } } +#endif + + sol->next = NULL; + free(sol); } + rainfo->soliciter = NULL; /* update counter */ if (rainfo->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS) rainfo->initcounter++; + rainfo->raoutput++; /* update timestamp */ gettimeofday(&rainfo->lastsent, NULL); @@ -1199,11 +1461,7 @@ ra_timeout(void *data) "<%s> RA timer on %s is expired", __FUNCTION__, rai->ifname); - if (iflist[rai->ifindex]->ifm_flags & IFF_UP) - ra_output(rai); - else - syslog(LOG_DEBUG, "<%s> %s is not up, skip sending RA", - __FUNCTION__, rai->ifname); + ra_output(rai); } /* update RA timer */ @@ -1219,7 +1477,7 @@ ra_timer_update(void *data, struct timeval *tm) * between the interface's configured MinRtrAdvInterval and * MaxRtrAdvInterval(discovery-v2-02 6.2.4). */ - interval = rai->mininterval; + interval = rai->mininterval; interval += random() % (rai->maxinterval - rai->mininterval); /* @@ -1238,7 +1496,8 @@ ra_timer_update(void *data, struct timeval *tm) syslog(LOG_DEBUG, "<%s> RA timer on %s is set to %ld:%ld", - __FUNCTION__, rai->ifname, tm->tv_sec, tm->tv_usec); + __FUNCTION__, rai->ifname, + (long int)tm->tv_sec, (long int)tm->tv_usec); return; } diff --git a/usr.sbin/rtadvd/rtadvd.conf b/usr.sbin/rtadvd/rtadvd.conf index f40a650..bdac4f1 100644 --- a/usr.sbin/rtadvd/rtadvd.conf +++ b/usr.sbin/rtadvd/rtadvd.conf @@ -1,14 +1,29 @@ # $FreeBSD$ + # # common definitions. # -default:\ - :chlim#64:raflags#0:rltime#1800:rtime#30000:retrans#1000:\ - :pinfoflags#192:vltime#3600000:pltime#3600000:mtu#1500: -ether:\ - :mtu#1500:tc=default: +# Note: All of the following parameters have default values defined +# in specifications, and hence you usually do not have to set them +# by hand unless you need special non-default values. # -# interfaces. -# -ef0:\ - :addrs#1:addr="fec0:0:0:1000::":prefixlen#64:tc=ether: +# You even do not need to create the configuration file. rtadvd +# would usually work well without a configuration file. +# See also: rtadvd(8) + +#default:\ +# :chlim#64:raflags#0:rltime#1800:rtime#30000:retrans#1000:\ +# :pinfoflags#192:vltime#3600000:pltime#3600000:mtu#1500: +#ether:\ +# :mtu#1500:tc=default: + +# per-interface definitions. +# Mainly IPv6 prefixes are configured in this part. However, rtadvd +# automatically learns appropriate prefixes from the kernel's routing +# table and advertises the prefixes, so you don't have to configure +# this part, either. +# If you don't want the automatic advertisement, invoke rtadvd with +# the -s option and configure this part by hand. + +#ef0:\ +# :addrs#1:addr="3ffe:501:4819:1000::":prefixlen#64:tc=ether: diff --git a/usr.sbin/rtadvd/rtadvd.conf.5 b/usr.sbin/rtadvd/rtadvd.conf.5 index 5d1fed2..cc0b63d 100644 --- a/usr.sbin/rtadvd/rtadvd.conf.5 +++ b/usr.sbin/rtadvd/rtadvd.conf.5 @@ -1,3 +1,5 @@ +.\" $KAME: rtadvd.conf.5,v 1.5 2000/05/22 22:22:56 itojun Exp $ +.\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. .\" @@ -25,49 +27,51 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: rtadvd.conf.5,v 1.1.1.1 1999/08/08 23:31:42 itojun Exp $ -.\" $FreeBSD$ +.\" $FreeBSD$ .\" .Dd May 17, 1998 .Dt RTADVD.CONF 5 -.Os KAME +.Os .Sh NAME .Nm rtadvd.conf .Nd config file for router advertisement daemon .Sh DESCRIPTION -The file describes how the router advertisement packet must be constructed +This file describes how the router advertisement packet must be constructed for each of the interfaces. .Pp -It obeys famous +It obeys the famous .Xr termcap 5 file format. Each line in the file describes a network interface. Fields are separated by a colon -.Po -.Dq \&: -.Pc , +.Pq Sq \&: , and each field contains one capability description. -Lines may be concatenated by \e character. -The comment marker is `#' character. +Lines may be concatenated by +.Sq \e +character. +The comment marker is the +.Sq \# +character. .Pp .Sh CAPABILITIES Capabilities describe the value to be filled into ICMPv6 router -advertisement message and to control +advertisement messages and to control .Xr rtadvd 8 behavior. Therefore, you are encouraged to read IETF neighbor discovery documents -if you would like to modify sample configuration file. +if you would like to modify the sample configuration file. .Pp Note that almost all items have default values. If you omit an item, the default value of the item will be used. .Pp -There are two items to control interval of sending router advertisements. +There are two items which control the interval of sending router advertisements. .Bl -tag -width indent .It Cm \&maxinterval (num) The maximum time allowed between sending unsolicited multicast router advertisements .Pq unit: seconds . -The default value is 600. Its value must be no less than 4 seconds +The default value is 600. +Its value must be no less than 4 seconds and no greater than 1800 seconds. .It Cm \&mininterval (num) The minimum time allowed between sending unsolicited multicast @@ -130,8 +134,8 @@ If its value is more than 1, you must specify the index of the prefix for each item below. Indices vary from 0 to N-1, where N is the value of -.Ic addrs. -Each index shall follows the name of each item, e.g. +.Ic addrs . +Each index shall follow the name of each item, e.g., .Dq prefixlen2 . .It Cm \&prefixlen (num) Prefix length field. @@ -148,7 +152,7 @@ and Bit 6 .Li 0x40 .Pc means Autonomous address-configuration flag bit. -The default value is 0xc0, i.e. both bits are set. +The default value is 0xc0, i.e., both bits are set. .It Cm \&addr (str) The address filled into Prefix field. Since @@ -177,7 +181,8 @@ which will be attached to router advertisement header. .It Cm \&mtu (num or str) MTU (maximum transmission unit) field. If 0 is specified, it means that the option will not be included. -The default value is 0. If the special string +The default value is 0. +If the special string .Dq auto is specified for this item, MTU option will be included and its value will be set to the interface MTU automatically. @@ -202,6 +207,26 @@ will not attach source link-layer address option to router advertisement packets. .El .Pp +The following item controls ICMPV6 home agent information option, +which was defined with mobile IPv6 support. +It will be attached to router advertisement header just like other options do. +.Bl -tag -width indent +.It Cm \&hapref +(num) Specifies home agent preference. +If set to non-zero, +.Cm \&hatime +must be present as well. +.It Cm \&hatime +(num) Specifies home agent lifetime. +.El +.Pp +When mobile IPv6 support is turned on for +.Xr rtadvd 8 , +advertisement interval option will be attached to router advertisement +packet, by configuring +.Cm \&maxinterval +explicitly. +.Pp You can also refer one line from another by using .Cm tc capability. diff --git a/usr.sbin/rtadvd/rtadvd.h b/usr.sbin/rtadvd/rtadvd.h index 92fbcdf..40beb1d 100644 --- a/usr.sbin/rtadvd/rtadvd.h +++ b/usr.sbin/rtadvd/rtadvd.h @@ -1,7 +1,9 @@ +/* $KAME: rtadvd.h,v 1.8 2000/05/16 13:34:14 itojun Exp $ */ + /* * Copyright (C) 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -13,7 +15,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -29,43 +31,64 @@ * $FreeBSD$ */ -#define ALLNODES "ff02::1" -#define ALLROUTERS "ff02::2" -#define ALLSITEROUTERS "ff05::2" -#define ANY "::" -#define RTSOLLEN 8 +#define ALLNODES "ff02::1" +#define ALLROUTERS "ff02::2" +#define ANY "::" +#define RTSOLLEN 8 /* protocol constants and default values */ -#define DEF_MAXRTRADVINTERVAL 600 -#define DEF_ADVLINKMTU 0 -#define DEF_ADVREACHABLETIME 0 -#define DEF_ADVRETRANSTIMER 0 -#define DEF_ADVCURHOPLIMIT 64 -#define DEF_ADVVALIDLIFETIME 2592000 -#define DEF_ADVPREFERREDLIFETIME 604800 - -#define MAXROUTERLIFETIME 9000 -#define MIN_MAXINTERVAL 4 -#define MAX_MAXINTERVAL 1800 -#define MIN_MININTERVAL 3 -#define MAXREACHABLETIME 3600000 - -#define MAX_INITIAL_RTR_ADVERT_INTERVAL 16 -#define MAX_INITIAL_RTR_ADVERTISEMENTS 3 -#define MAX_FINAL_RTR_ADVERTISEMENTS 3 -#define MIN_DELAY_BETWEEN_RAS 3 -#define MAX_RA_DELAY_TIME 500000 /* usec */ +#define DEF_MAXRTRADVINTERVAL 600 +#define DEF_ADVLINKMTU 0 +#define DEF_ADVREACHABLETIME 0 +#define DEF_ADVRETRANSTIMER 0 +#define DEF_ADVCURHOPLIMIT 64 +#define DEF_ADVVALIDLIFETIME 2592000 +#define DEF_ADVPREFERREDLIFETIME 604800 + +/*XXX int-to-double comparison for INTERVAL items */ +#ifndef MIP6 +#define mobileip6 0 +#endif + +#define MAXROUTERLIFETIME 9000 +#define MIN_MAXINTERVAL (mobileip6 ? 1.5 : 4.0) +#define MAX_MAXINTERVAL 1800 +#define MIN_MININTERVAL (mobileip6 ? 0.5 : 3) +#define MAXREACHABLETIME 3600000 + +#ifndef MIP6 +#undef miobileip6 +#endif + +#define MAX_INITIAL_RTR_ADVERT_INTERVAL 16 +#define MAX_INITIAL_RTR_ADVERTISEMENTS 3 +#define MAX_FINAL_RTR_ADVERTISEMENTS 3 +#define MIN_DELAY_BETWEEN_RAS 3 +#define MAX_RA_DELAY_TIME 500000 /* usec */ + +#define PREFIX_FROM_KERNEL 1 +#define PREFIX_FROM_CONFIG 2 +#define PREFIX_FROM_DYNAMIC 3 struct prefix { - struct prefix *next; /* forward link */ - struct prefix *prev; /* previous link */ - - u_int32_t validlifetime; /* AdvValidLifetime */ - u_int32_t preflifetime; /* AdvPreferredLifetime */ - u_int onlinkflg; /* bool: AdvOnLinkFlag */ - u_int autoconfflg; /* bool: AdvAutonomousFlag */ - int prefixlen; - struct in6_addr prefix; + struct prefix *next; /* forward link */ + struct prefix *prev; /* previous link */ + + u_int32_t validlifetime; /* AdvValidLifetime */ + u_int32_t preflifetime; /* AdvPreferredLifetime */ + u_int onlinkflg; /* bool: AdvOnLinkFlag */ + u_int autoconfflg; /* bool: AdvAutonomousFlag */ +#ifdef MIP6 + u_int routeraddr; /* bool: RouterAddress */ +#endif + int prefixlen; + int origin; /* from kernel or cofig */ + struct in6_addr prefix; +}; + +struct soliciter { + struct soliciter *next; + struct sockaddr_in6 addr; }; struct rainfo { @@ -73,35 +96,56 @@ struct rainfo { struct rainfo *next; /* timer related parameters */ - struct rtadvd_timer *timer; - int initcounter; /* counter for the first few advertisements */ - struct timeval lastsent; /* timestamp when the lates RA was sent */ - int waiting; /* number of RS waiting for RA */ + struct rtadvd_timer *timer; + int initcounter; /* counter for the first few advertisements */ + struct timeval lastsent; /* timestamp when the latest RA was sent */ + int waiting; /* number of RS waiting for RA */ /* interface information */ int ifindex; int advlinkopt; /* bool: whether include link-layer addr opt */ - struct sockaddr_dl *sdl; + struct sockaddr_dl *sdl; char ifname[16]; int phymtu; /* mtu of the physical interface */ /* Router configuration variables */ - u_short lifetime; /* AdvDefaultLifetime */ + u_short lifetime; /* AdvDefaultLifetime */ u_int maxinterval; /* MaxRtrAdvInterval */ u_int mininterval; /* MinRtrAdvInterval */ int managedflg; /* AdvManagedFlag */ int otherflg; /* AdvOtherConfigFlag */ - u_int32_t linkmtu; /* AdvLinkMTU */ - u_int32_t reachabletime; /* AdvReachableTime */ - u_int32_t retranstimer; /* AdvRetransTimer */ +#ifdef MIP6 + int haflg; /* HAFlag */ +#endif + u_int32_t linkmtu; /* AdvLinkMTU */ + u_int32_t reachabletime; /* AdvReachableTime */ + u_int32_t retranstimer; /* AdvRetransTimer */ u_int hoplimit; /* AdvCurHopLimit */ - struct prefix prefix; /* AdvPrefixList(link head) */ + struct prefix prefix; /* AdvPrefixList(link head) */ int pfxs; /* number of prefixes */ +#ifdef MIP6 + u_short hapref; /* Home Agent Preference */ + u_short hatime; /* Home Agent Lifetime */ +#endif + /* actual RA packet data and its length */ - size_t ra_datalen; - u_char *ra_data; + size_t ra_datalen; + u_char *ra_data; + + /* statistics */ + u_quad_t raoutput; /* number of RAs sent */ + u_quad_t rainput; /* number of RAs received */ + u_quad_t rainconsistent; /* number of RAs inconsistent with ours */ + u_quad_t rsinput; /* number of RSs received */ + + /* info about soliciter */ + struct soliciter *soliciter; /* recent solication source */ }; -void ra_timeout __P((void *)); -void ra_timer_update __P((void *, struct timeval *)); +void ra_timeout __P((void *)); +void ra_timer_update __P((void *, struct timeval *)); + +#ifdef MIP6 +extern int mobileip6; +#endif diff --git a/usr.sbin/rtadvd/timer.c b/usr.sbin/rtadvd/timer.c index f93968a..d03eddd 100644 --- a/usr.sbin/rtadvd/timer.c +++ b/usr.sbin/rtadvd/timer.c @@ -1,7 +1,9 @@ +/* $KAME: timer.c,v 1.3 2000/05/22 22:23:07 itojun Exp $ */ + /* * Copyright (C) 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -13,7 +15,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -35,14 +37,16 @@ #include <syslog.h> #include <stdlib.h> #include <string.h> -#ifdef __NetBSD__ +#if defined(__NetBSD__) || defined(__OpenBSD__) #include <search.h> #endif #include "timer.h" static struct rtadvd_timer timer_head; -#define MILLION 1000000 +#define MILLION 1000000 +#define TIMEVAL_EQUAL(t1,t2) ((t1)->tv_sec == (t2)->tv_sec &&\ + (t1)->tv_usec == (t2)->tv_usec) static struct timeval tm_max = {0x7fffffff, 0x7fffffff}; @@ -93,6 +97,14 @@ rtadvd_add_timer(void (*timeout) __P((void *)), } void +rtadvd_remove_timer(struct rtadvd_timer **timer) +{ + remque(*timer); + free(*timer); + *timer = NULL; +} + +void rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *timer) { struct timeval now; @@ -138,7 +150,11 @@ rtadvd_check_timer() tm = tm->next; } - if (TIMEVAL_LT(timer_head.tm, now)) { + if (TIMEVAL_EQUAL(&tm_max, &timer_head.tm)) { + /* no need to timeout */ + return(NULL); + } + else if (TIMEVAL_LT(timer_head.tm, now)) { /* this may occur when the interval is too small */ returnval.tv_sec = returnval.tv_usec = 0; } diff --git a/usr.sbin/rtadvd/timer.h b/usr.sbin/rtadvd/timer.h index e9f2c35..9a97c91 100644 --- a/usr.sbin/rtadvd/timer.h +++ b/usr.sbin/rtadvd/timer.h @@ -1,7 +1,9 @@ +/* $KAME: timer.h,v 1.2 2000/05/16 13:34:14 itojun Exp $ */ + /* * Copyright (C) 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -13,7 +15,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -30,34 +32,35 @@ */ /* a < b */ -#define TIMEVAL_LT(a, b) (((a).tv_sec < (b).tv_sec) ||\ +#define TIMEVAL_LT(a, b) (((a).tv_sec < (b).tv_sec) ||\ (((a).tv_sec == (b).tv_sec) && \ ((a).tv_usec < (b).tv_usec))) /* a <= b */ -#define TIMEVAL_LEQ(a, b) (((a).tv_sec < (b).tv_sec) ||\ +#define TIMEVAL_LEQ(a, b) (((a).tv_sec < (b).tv_sec) ||\ (((a).tv_sec == (b).tv_sec) &&\ ((a).tv_usec <= (b).tv_usec))) struct rtadvd_timer { - struct rtadvd_timer *next; - struct rtadvd_timer *prev; - struct rainfo *rai; - struct timeval tm; + struct rtadvd_timer *next; + struct rtadvd_timer *prev; + struct rainfo *rai; + struct timeval tm; - void (*expire) __P((void *)); /* expiration function */ - void *expire_data; - void (*update) __P((void *, struct timeval *)); /* update function */ - void *update_data; + void (*expire) __P((void *)); /* expiration function */ + void *expire_data; + void (*update) __P((void *, struct timeval *)); /* update function */ + void *update_data; }; -void rtadvd_timer_init __P((void)); -struct rtadvd_timer *rtadvd_add_timer __P((void (*) __P((void *)), +void rtadvd_timer_init __P((void)); +struct rtadvd_timer *rtadvd_add_timer __P((void (*) __P((void *)), void (*) __P((void *, struct timeval *)), void *, void *)); -void rtadvd_set_timer __P((struct timeval *, struct rtadvd_timer *)); -struct timeval * rtadvd_check_timer __P((void)); -struct timeval * rtadvd_timer_rest __P((struct rtadvd_timer *)); -void TIMEVAL_ADD __P((struct timeval *, struct timeval *, - struct timeval *)); -void TIMEVAL_SUB __P((struct timeval *, struct timeval *, - struct timeval *)); +void rtadvd_set_timer __P((struct timeval *, struct rtadvd_timer *)); +void rtadvd_remove_timer __P((struct rtadvd_timer **)); +struct timeval * rtadvd_check_timer __P((void)); +struct timeval * rtadvd_timer_rest __P((struct rtadvd_timer *)); +void TIMEVAL_ADD __P((struct timeval *, struct timeval *, + struct timeval *)); +void TIMEVAL_SUB __P((struct timeval *, struct timeval *, + struct timeval *)); |