diff --git a/usr.sbin/ndp/ndp.8 b/usr.sbin/ndp/ndp.8 index f845d5e79d2c..fc99d3696eed 100644 --- a/usr.sbin/ndp/ndp.8 +++ b/usr.sbin/ndp/ndp.8 @@ -1,3 +1,6 @@ +.\" $FreeBSD$ +.\" $KAME: ndp.8,v 1.12 2000/06/20 21:50:17 itojun Exp $ +.\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. .\" @@ -25,9 +28,6 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: ndp.8,v 1.2 1999/10/07 05:26:13 itojun Exp $ -.\" $FreeBSD$ -.\" .Dd May 17, 1998 .Dt NDP 8 .Os KAME @@ -57,8 +57,12 @@ .Nm ndp .Fl H .Nm ndp +.Fl I +.Op delete \(ba Ar interface +.Nm ndp .Fl i .Ar interface +.Op Ar flags... .Nm ndp .Fl p .Nm ndp @@ -72,7 +76,8 @@ .Op Fl nt .Ar nodename .Ar ether_addr -.Op temp +.Op Li temp +.Op Li proxy .\" .Sh DESCRIPTION The @@ -99,8 +104,35 @@ Parse the file specified by .It Fl H Harmonize consistency between the routing table and the default router list; install the top entry of the list into the kernel routing table. -.It Fl i -view ND information for specified interface. +.It Fl I Op delete \(ba Ar interface +Shows or specifies the default interface used as the default route when +there is no default router. If no argument is given to the option, +the current default interface will be shown. +If an +.Ar interface +is specified, the interface will be used as the default. +If a special keyword +.Ic delete +is specified, the current default interface will be deleted from the kernel. +.It Fl i Ar interface Op Ar flags... +View ND information for the specified interface. +If additional arguments +.Ar flags +are given, +.Nm +sets or clears the specified flags for the interface. +Possible flags are as follows. All of the flags can begin with the +special character +.Ql - , +which means the flag should be cleared. +.\" +.Bl -tag -width Ds -compact +.It Xo +.Ic nud +.Xc +turn on or off NUD (Neighbor Unreachability Detection) on the +interface. NUD is usually turned on by default. +.El .It Fl l Do not truncate numeric IPv6 address. .It Fl n @@ -115,6 +147,15 @@ Show default router list. Flush all the entries in the default router list. .It Fl s Register a NDP entry for a node. +The entry will be permanent unless the word +.Li temp +is given in the command. +If the word +.Li proxy +is given, this system will act as an proxy NDP server, +responding to requests for +.Ar hostname +even though the host address is not its own. .It Fl t Print timestamp on each entries, to make it possible to merge output with diff --git a/usr.sbin/ndp/ndp.c b/usr.sbin/ndp/ndp.c index 54568a404c0c..8010c1906354 100644 --- a/usr.sbin/ndp/ndp.c +++ b/usr.sbin/ndp/ndp.c @@ -1,3 +1,6 @@ +/* $FreeBSD$ */ +/* $KAME: ndp.c,v 1.41 2000/07/04 12:54:11 jinmei Exp $ */ + /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. * All rights reserved. @@ -25,8 +28,6 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ /* * Copyright (c) 1984, 1993 @@ -111,47 +112,55 @@ #include #include "gmt2local.h" +#ifndef NI_WITHSCOPEID +#define NI_WITHSCOPEID 0 +#endif + /* packing rule for routing socket */ -#define ROUNDUP(a) \ +#define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) -#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) +#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) -extern int errno; -static int pid; -static int fflag; -static int nflag; -static int tflag; -static int32_t thiszone; /* time difference with gmt */ -static int s = -1; -static int repeat = 0; -static int lflag = 0; +static int pid; +static int fflag; +static int nflag; +static int tflag; +static int32_t thiszone; /* time difference with gmt */ +static int s = -1; +static int repeat = 0; +static int lflag = 0; -char ntop_buf[INET6_ADDRSTRLEN]; /* inet_ntop() */ -char host_buf[NI_MAXHOST]; /* getnameinfo() */ -char ifix_buf[IFNAMSIZ]; /* if_indextoname() */ +char ntop_buf[INET6_ADDRSTRLEN]; /* inet_ntop() */ +char host_buf[NI_MAXHOST]; /* getnameinfo() */ +char ifix_buf[IFNAMSIZ]; /* if_indextoname() */ -int main __P((int, char **)); -int file __P((char *)); -void getsocket __P((void)); -int set __P((int, char **)); -void get __P((char *)); -int delete __P((char *)); -void dump __P((struct in6_addr *)); -static struct in6_nbrinfo *getnbrinfo __P((struct in6_addr *addr, int ifindex)); -static char *ether_str __P((struct sockaddr_dl *)); -int ndp_ether_aton __P((char *, u_char *)); -void usage __P((void)); -int rtmsg __P((int)); -void ifinfo __P((char *)); -void list __P((void)); -void plist __P((void)); -void pfx_flush __P((void)); -void rtrlist __P((void)); -void rtr_flush __P((void)); -void harmonize_rtr __P((void)); -static char *sec2str __P((time_t t)); -static char *ether_str __P((struct sockaddr_dl *sdl)); -static void ts_print __P((const struct timeval *)); +int main __P((int, char **)); +int file __P((char *)); +void getsocket __P((void)); +int set __P((int, char **)); +void get __P((char *)); +int delete __P((char *)); +void dump __P((struct in6_addr *)); +static struct in6_nbrinfo *getnbrinfo __P((struct in6_addr *addr, + int ifindex, int)); +static char *ether_str __P((struct sockaddr_dl *)); +int ndp_ether_aton __P((char *, u_char *)); +void usage __P((void)); +int rtmsg __P((int)); +void ifinfo __P((int, char **)); +void rtrlist __P((void)); +void plist __P((void)); +void pfx_flush __P((void)); +void rtrlist __P((void)); +void rtr_flush __P((void)); +void harmonize_rtr __P((void)); +#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ +static void getdefif __P((void)); +static void setdefif __P((char *)); +#endif +static char *sec2str __P((time_t t)); +static char *ether_str __P((struct sockaddr_dl *sdl)); +static void ts_print __P((const struct timeval *)); int main(argc, argv) @@ -161,12 +170,10 @@ main(argc, argv) int ch; int aflag = 0, cflag = 0, dflag = 0, sflag = 0, Hflag = 0, pflag = 0, rflag = 0, Pflag = 0, Rflag = 0; - extern char *optarg; - extern int optind; pid = getpid(); thiszone = gmt2local(0); - while ((ch = getopt(argc, argv, "acndfilprstA:HPR")) != EOF) + while ((ch = getopt(argc, argv, "acndfIilprstA:HPR")) != EOF) switch ((char)ch) { case 'a': aflag = 1; @@ -178,10 +185,22 @@ main(argc, argv) case 'd': dflag = 1; break; + case 'I': +#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ + if (argc > 2) + setdefif(argv[2]); + getdefif(); /* always call it to print the result */ + exit(0); +#else + errx(1, "not supported yet"); + /*NOTREACHED*/ +#endif case 'i' : - if (argc != 3) + argc -= optind; + argv += optind; + if (argc < 1) usage(); - ifinfo(argv[2]); + ifinfo(argc, argv); exit(0); case 'n': nflag = 1; @@ -236,6 +255,7 @@ main(argc, argv) if (argc != 1) usage(); delete(argv[0]); + exit(0); } if (pflag) { plist(); @@ -317,7 +337,7 @@ getsocket() } } -struct sockaddr_in so_mask = {8, 0, 0, { 0xffffffff}}; +struct sockaddr_in6 so_mask = {sizeof(so_mask), AF_INET6 }; struct sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m; struct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m; int expire_time, flags, found_entry; @@ -357,6 +377,12 @@ set(argc, argv) return 1; } sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; +#ifdef __KAME__ + if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { + *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = + htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); + } +#endif ea = (u_char *)LLADDR(&sdl_m); if (ndp_ether_aton(eaddr, ea) == 0) sdl_m.sdl_alen = 6; @@ -366,10 +392,10 @@ set(argc, argv) struct timeval time; gettimeofday(&time, 0); expire_time = time.tv_sec + 20 * 60; - } + } else if (strncmp(argv[0], "proxy", 5) == 0) + flags |= RTF_ANNOUNCE; argv++; } -tryagain: if (rtmsg(RTM_GET) < 0) { perror(host); return (1); @@ -384,8 +410,13 @@ set(argc, argv) case IFT_ISO88024: case IFT_ISO88025: goto overwrite; } - goto tryagain; + /* + * IPv4 arp command retries with sin_other = SIN_PROXY here. + */ + fprintf(stderr, "set: cannot configure a new entry\n"); + return 1; } + overwrite: if (sdl->sdl_family != AF_LINK) { printf("cannot intuit interface index and type for %s\n", host); @@ -417,6 +448,12 @@ get(host) return; } sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; +#ifdef __KAME__ + if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { + *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = + htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); + } +#endif dump(&sin->sin6_addr); if (found_entry == 0) { getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, @@ -452,7 +489,12 @@ delete(host) return 1; } sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; -/*tryagain:*/ +#ifdef __KAME__ + if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { + *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = + htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); + } +#endif if (rtmsg(RTM_GET) < 0) { perror(host); return (1); @@ -462,23 +504,38 @@ delete(host) if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { if (sdl->sdl_family == AF_LINK && (rtm->rtm_flags & RTF_LLINFO) && - !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) { - case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: - case IFT_ISO88024: case IFT_ISO88025: - goto delete; + !(rtm->rtm_flags & RTF_GATEWAY)) { + switch (sdl->sdl_type) { + case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: + case IFT_ISO88024: case IFT_ISO88025: + goto delete; + } } + /* + * IPv4 arp command retries with sin_other = SIN_PROXY here. + */ + fprintf(stderr, "delete: cannot delete non-NDP entry\n"); + return 1; } - return 0; + delete: if (sdl->sdl_family != AF_LINK) { printf("cannot locate %s\n", host); return (1); } if (rtmsg(RTM_DELETE) == 0) { - getnameinfo((struct sockaddr *)sin, - sin->sin6_len, host_buf, - sizeof(host_buf), NULL, 0, - NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); + struct sockaddr_in6 s6 = *sin; /* XXX: for safety */ + +#ifdef __KAME__ + if (IN6_IS_ADDR_LINKLOCAL(&s6.sin6_addr)) { + s6.sin6_scope_id = ntohs(*(u_int16_t *)&s6.sin6_addr.s6_addr[2]); + *(u_int16_t *)&s6.sin6_addr.s6_addr[2] = 0; + } +#endif + getnameinfo((struct sockaddr *)&s6, + s6.sin6_len, host_buf, + sizeof(host_buf), NULL, 0, + NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); printf("%s (%s) deleted\n", host, host_buf); } @@ -494,19 +551,19 @@ dump(addr) { int mib[6]; size_t needed; - char *host, *lim, *buf, *next; + char *lim, *buf, *next; struct rt_msghdr *rtm; struct sockaddr_in6 *sin; struct sockaddr_dl *sdl; extern int h_errno; - struct hostent *hp; struct in6_nbrinfo *nbi; struct timeval time; int addrwidth; + char flgbuf[8]; /* Print header */ if (!tflag) - printf("%-29.29s %-18.18s %6.6s %-9.9s %2s %4s %4s\n", + printf("%-31.31s %-17.17s %6.6s %-9.9s %2s %4s %4s\n", "Neighbor", "Linklayer Address", "Netif", "Expire", "St", "Flgs", "Prbs"); @@ -564,18 +621,17 @@ again:; if (lflag) { addrwidth = strlen(host_buf); - if (addrwidth < 29) - addrwidth = 29; + if (addrwidth < 31) + addrwidth = 31; } else - addrwidth = 29; + addrwidth = 31; - printf("%-*.*s %-18.18s %6.6s", addrwidth, addrwidth, host_buf, + printf("%-*.*s %-17.17s %6.6s", addrwidth, addrwidth, host_buf, ether_str(sdl), if_indextoname(sdl->sdl_index, ifix_buf)); /* Print neighbor discovery specific informations */ - putchar(' '); - nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index); + nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1); if (nbi) { if (nbi->expire > time.tv_sec) { printf(" %-9.9s", @@ -620,31 +676,30 @@ again:; warnx("failed to get neighbor information"); printf(" "); } - - /* other flags */ putchar(' '); - { - u_char flgbuf[8], *p = flgbuf; - flgbuf[0] = '\0'; - if (isrouter) - p += sprintf((char *)p, "R"); -#ifndef RADISH - if (rtm->rtm_addrs & RTA_NETMASK) { - sin = (struct sockaddr_in6 *) - (sdl->sdl_len + (char *)sdl); - if (!IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr)) - p += sprintf((char *)p, "P"); - if (sin->sin6_len != sizeof(struct sockaddr_in6)) - p += sprintf((char *)p, "W"); - } -#endif /*RADISH*/ - printf("%4s", flgbuf); + /* + * other flags. R: router, P: proxy, W: ?? + */ + if ((rtm->rtm_addrs & RTA_NETMASK) == 0) { + snprintf(flgbuf, sizeof(flgbuf), "%s%s", + isrouter ? "R" : "", + (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); + } else { + sin = (struct sockaddr_in6 *) + (sdl->sdl_len + (char *)sdl); + snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s", + isrouter ? "R" : "", + !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr) + ? "P" : "", + (sin->sin6_len != sizeof(struct sockaddr_in6)) + ? "W" : "", + (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); } + printf(" %-4.4s", flgbuf); - putchar(' '); if (prbs) - printf("% 4d", prbs); + printf(" %4d", prbs); printf("\n"); } @@ -657,9 +712,10 @@ again:; } static struct in6_nbrinfo * -getnbrinfo(addr, ifindex) +getnbrinfo(addr, ifindex, warning) struct in6_addr *addr; int ifindex; + int warning; { static struct in6_nbrinfo nbi; int s; @@ -671,7 +727,8 @@ getnbrinfo(addr, ifindex) if_indextoname(ifindex, nbi.ifname); nbi.addr = *addr; if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) { - warn("ioctl"); + if (warning) + warn("ioctl(SIOCGNBRINFO_IN6)"); close(s); return(NULL); } @@ -726,10 +783,13 @@ usage() printf(" ndp -c[nt]\n"); printf(" ndp -d[nt] hostname\n"); printf(" ndp -f[nt] filename\n"); - printf(" ndp -i interface\n"); + printf(" ndp -i interface [flags...]\n"); +#ifdef SIOCSDEFIFACE_IN6 + printf(" ndp -I [interface|delete]\n"); +#endif printf(" ndp -p\n"); printf(" ndp -r\n"); - printf(" ndp -s hostname ether_addr [temp]\n"); + printf(" ndp -s hostname ether_addr [temp] [proxy]\n"); printf(" ndp -H\n"); printf(" ndp -P\n"); printf(" ndp -R\n"); @@ -762,16 +822,21 @@ rtmsg(cmd) rtm->rtm_rmx.rmx_expire = expire_time; rtm->rtm_inits = RTV_EXPIRE; rtm->rtm_flags |= (RTF_HOST | RTF_STATIC); + if (rtm->rtm_flags & RTF_ANNOUNCE) { + rtm->rtm_flags &= ~RTF_HOST; + rtm->rtm_flags |= RTA_NETMASK; + } /* FALLTHROUGH */ case RTM_GET: rtm->rtm_addrs |= RTA_DST; } -#define NEXTADDR(w, s) \ +#define NEXTADDR(w, s) \ if (rtm->rtm_addrs & (w)) { \ bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);} NEXTADDR(RTA_DST, sin_m); NEXTADDR(RTA_GATEWAY, sdl_m); + memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr)); NEXTADDR(RTA_NETMASK, so_mask); rtm->rtm_msglen = cp - (char *)&m_rtmsg; @@ -795,11 +860,14 @@ rtmsg(cmd) } void -ifinfo(ifname) - char *ifname; +ifinfo(argc, argv) + int argc; + char **argv; { struct in6_ndireq nd; - int s; + int i, s; + char *ifname = argv[0]; + u_int32_t newflags; if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { perror("ndp: socket"); @@ -811,14 +879,50 @@ ifinfo(ifname) perror("ioctl (SIOCGIFINFO_IN6)"); exit(1); } -#define ND nd.ndi +#define ND nd.ndi + newflags = ND.flags; + for (i = 1; i < argc; i++) { + int clear = 0; + char *cp = argv[i]; + + if (*cp == '-') { + clear = 1; + cp++; + } + +#define SETFLAG(s, f) \ + do {\ + if (strcmp(cp, (s)) == 0) {\ + if (clear)\ + newflags &= ~(f);\ + else\ + newflags |= (f);\ + }\ + } while (0) + SETFLAG("nud", ND6_IFF_PERFORMNUD); + + ND.flags = newflags; + if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd) < 0) { + perror("ioctl(SIOCSIFINFO_FLAGS)"); + exit(1); + } +#undef SETFLAG + } + printf("linkmtu=%d", ND.linkmtu); printf(", curhlim=%d", ND.chlim); printf(", basereachable=%ds%dms", ND.basereachable / 1000, ND.basereachable % 1000); printf(", reachable=%ds", ND.reachable); - printf(", retrans=%ds%dms\n", ND.retrans / 1000, ND.retrans % 1000); + printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000); + if (ND.flags) { + printf("\nFlags: "); + if ((ND.flags & ND6_IFF_PERFORMNUD) != 0) + printf("PERFORMNUD "); + } + putc('\n', stdout); #undef ND + close(s); } @@ -839,7 +943,7 @@ rtrlist() perror("ioctl (SIOCGDRLST_IN6)"); exit(1); } -#define DR dr.defrouter[i] +#define DR dr.defrouter[i] for (i = 0 ; DR.if_index && i < PRLSTSIZ ; i++) { struct sockaddr_in6 sin6; @@ -850,7 +954,7 @@ rtrlist() getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf, sizeof(host_buf), NULL, 0, NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); - + printf("%s if=%s", host_buf, if_indextoname(DR.if_index, ifix_buf)); printf(", flags=%s%s", @@ -886,14 +990,19 @@ plist() perror("ioctl (SIOCGPRLST_IN6)"); exit(1); } -#define PR pr.prefix[i] +#define PR pr.prefix[i] for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) { printf("%s/%d if=%s\n", inet_ntop(AF_INET6, &PR.prefix, ntop_buf, sizeof(ntop_buf)), PR.prefixlen, if_indextoname(PR.if_index, ifix_buf)); gettimeofday(&time, 0); - printf(" flags=%s%s", + /* + * meaning of fields, especially flags, is very different + * by origin. notify the difference to the users. + */ + printf(" %s", PR.origin == PR_ORIG_RA ? "" : "advertise: "); + printf("flags=%s%s", PR.raflags.onlink ? "L" : "", PR.raflags.autonomous ? "A" : ""); if (PR.vltime == ND6_INFINITE_LIFETIME) @@ -905,34 +1014,75 @@ plist() else printf(", pltime=%ld", (long)PR.pltime); if (PR.expire == 0) - printf(", expire=Never\n"); + printf(", expire=Never"); else if (PR.expire >= time.tv_sec) - printf(", expire=%s\n", + printf(", expire=%s", sec2str(PR.expire - time.tv_sec)); else - printf(", expired\n"); - if (PR.advrtrs) { + printf(", expired"); + switch (PR.origin) { + case PR_ORIG_RA: + printf(", origin=RA"); + break; + case PR_ORIG_RR: + printf(", origin=RR"); + break; + case PR_ORIG_STATIC: + printf(", origin=static"); + break; + case PR_ORIG_KERNEL: + printf(", origin=kernel"); + break; + default: + printf(", origin=?"); + break; + } + printf("\n"); + /* + * "advertising router" list is meaningful only if the prefix + * information is from RA. + */ + if (PR.origin != PR_ORIG_RA) + ; + else if (PR.advrtrs) { int j; printf(" advertised by\n"); for (j = 0; j < PR.advrtrs; j++) { struct sockaddr_in6 sin6; + struct in6_nbrinfo *nbi; bzero(&sin6, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_len = sizeof(sin6); sin6.sin6_addr = PR.advrtr[j]; + sin6.sin6_scope_id = PR.if_index; /* XXX */ getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf, sizeof(host_buf), NULL, 0, NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); + printf(" %s", host_buf); - printf(" %s\n", host_buf); + nbi = getnbrinfo(&sin6.sin6_addr, PR.if_index, + 0); + if (nbi) { + switch(nbi->state) { + case ND6_LLINFO_REACHABLE: + case ND6_LLINFO_STALE: + case ND6_LLINFO_DELAY: + case ND6_LLINFO_PROBE: + printf(" (reachable)\n"); + break; + default: + printf(" (unreachable)\n"); + } + } + else + printf(" (no neighbor state)\n"); } if (PR.advrtrs > DRLSTSIZ) printf(" and %d routers\n", PR.advrtrs - DRLSTSIZ); - } - else + } else printf(" No advertising router\n"); } #undef PR @@ -963,6 +1113,8 @@ rtr_flush() strcpy(dummyif, "lo0"); /* dummy */ if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0) err(1, "ioctl(SIOCSRTRFLUSH_IN6)"); + + close(s); } void @@ -971,17 +1123,70 @@ harmonize_rtr() char dummyif[IFNAMSIZ+8]; int s; - if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { - perror("ndp: socket"); - exit(1); - } + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + err(1, "socket"); strcpy(dummyif, "lo0"); /* dummy */ - if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0) { - perror("ioctl (SIOCSNDFLUSH_IN6)"); - exit(1); - } + if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0) + err(1, "ioctl (SIOCSNDFLUSH_IN6)"); + + close(s); } +#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ +static void +setdefif(ifname) + char *ifname; +{ + struct in6_ndifreq ndifreq; + unsigned int ifindex; + + if (strcasecmp(ifname, "delete") == 0) + ifindex = 0; + else { + if ((ifindex = if_nametoindex(ifname)) == 0) + err(1, "failed to resolve i/f index for %s", ifname); + } + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + err(1, "socket"); + + strcpy(ndifreq.ifname, "lo0"); /* dummy */ + ndifreq.ifindex = ifindex; + + if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0) + err(1, "ioctl (SIOCSDEFIFACE_IN6)"); + + close(s); +} + +static void +getdefif() +{ + struct in6_ndifreq ndifreq; + char ifname[IFNAMSIZ+8]; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + err(1, "socket"); + + memset(&ndifreq, 0, sizeof(ndifreq)); + strcpy(ndifreq.ifname, "lo0"); /* dummy */ + + if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0) + err(1, "ioctl (SIOCGDEFIFACE_IN6)"); + + if (ndifreq.ifindex == 0) + printf("No default interface.\n"); + else { + if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL) + err(1, "failed to resolve ifname for index %lu", + ndifreq.ifindex); + printf("ND default interface = %s\n", ifname); + } + + close(s); +} +#endif + static char * sec2str(total) time_t total;