diff --git a/usr.sbin/ndp/ndp.8 b/usr.sbin/ndp/ndp.8 index e9b75ddee870..c74e13995152 100644 --- a/usr.sbin/ndp/ndp.8 +++ b/usr.sbin/ndp/ndp.8 @@ -1,5 +1,5 @@ .\" $FreeBSD$ -.\" $KAME: ndp.8,v 1.15 2001/02/08 07:17:03 itojun Exp $ +.\" $KAME: ndp.8,v 1.28 2002/07/17 08:46:33 itojun Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. .\" All rights reserved. @@ -37,60 +37,97 @@ .Nd control/diagnose IPv6 neighbor discovery protocol .\" .Sh SYNOPSIS -.Nm -.Fl a -.Op Fl nt -.Nm -.Fl A Ar wait -.Op Fl nt -.Nm -.Fl c -.Op Fl nt -.Nm -.Fl d +.Nm ndp .Op Fl nt .Ar hostname -.Nm -.Fl f +.Nm ndp +.Op Fl nt +.Fl a | Fl c | Fl p +.Nm ndp +.Op Fl nt +.Fl r +.Nm ndp +.Op Fl nt +.Fl H | Fl P | Fl R +.Nm ndp +.Op Fl nt +.Fl A Ar wait +.Nm ndp +.Op Fl nt +.Fl d Ar hostname +.Nm ndp +.Op Fl nt +.Fl f Ar filename +.Nm ndp .Op Fl nt -.Ar filename -.Nm -.Fl H -.Nm -.Fl I -.Op Cm delete | Ar interface -.Nm .Fl i .Ar interface -.Op Ar flags... -.Nm -.Fl p -.Nm -.Fl P -.Nm -.Fl r -.Nm -.Fl R -.Nm -.Fl s +.Op Ar flags ... +.Nm ndp .Op Fl nt -.Ar nodename -.Ar ether_addr +.Fl I Op Ar interface | Li delete +.Nm ndp +.Op Fl nt +.Fl s Ar nodename etheraddr .Op Li temp .Op Li proxy .\" .Sh DESCRIPTION The .Nm -utility manipulates the address mapping table -used by Neighbor Discovery Protocol (NDP). +command manipulates the address mapping table +used by the Neighbor Discovery Protocol (NDP). .Bl -tag -width Ds .It Fl a Dump the currently existing NDP entries. +The following information will be printed: +.Bl -tag -width NeighborXX +.It Neighbor +IPv6 address of the neighbor. +.It Linklayer Address +Linklayer address of the neighbor. +It could be +.Dq Li (incomplete) +when the address is not available. +.It Netif +Network interface associated with the neighbor cache entry. +.It Expire +The time until expiry of the entry. +The entry could become +.Dq Li permanent , +in which case it will never expire. +.It S +State of the neighbor cache entry, as a single letter: +.Pp +.Bl -tag -width indent -compact +.It N +Nostate +.It W +Waitdelete +.It I +Incomplete +.It R +Reachable +.It S +Stale +.It D +Delay +.It P +Probe +.It ? +Unknown state (should never happen). +.El +.It Flags +Flags on the neighbor cache entry, in a single letter. +They are: Router, proxy neighbor advertisement +.Pq Dq p . +The field could be followed by a decimal number, +which means the number of NS probes the node has sent during the current state. +.El .It Fl A Ar wait Repeat .Fl a -(dump NDP entries) +.Pq dump NDP entries every .Ar wait seconds. @@ -104,35 +141,42 @@ 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 Op Cm delete | Ar interface -Shows or specifies the default interface used as the default route when +.It Fl I +Shows 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 +.It Fl I Ar interface +Specifies the default interface used as the default route when +there is no default router. +The .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... +will be used as the default. +.It Fl I Li delete +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. +Each flag should be separated by white spaces or tab characters. Possible flags are as follows. All of the flags can begin with the special character .Ql - , which means the flag should be cleared. +Note that you need +.Fl - +before +.Fl foo +in this case. .\" +.Pp .Bl -tag -width Ds -compact .It Xo .Ic nud .Xc -turn on or off NUD (Neighbor Unreachability Detection) on the +Turn on or off NUD (Neighbor Unreachability Detection) on the interface. NUD is usually turned on by default. .It Xo @@ -146,9 +190,20 @@ unless the .Li net.inet6.ip6.accept_rtadv variable is non-0, even if the flag is on. This flag is set to 1 by default. +.It Xo +.Ic prefer_source +.Xc +Prefer addresses on the +.Ar interface +as candidates of the source address for outgoing packets. +The default value of this flag is off. +For more details about the entire algorithm of source address +selection, see the +.Pa IMPLEMENTATION +file supplied with the KAME kit. .El .It Fl n -Do not try to resolve numeric address to hostname. +Do not try to resolve numeric addresses to hostnames. .It Fl p Show prefix list. .It Fl P @@ -158,20 +213,20 @@ Show default router list. .It Fl R Flush all the entries in the default router list. .It Fl s -Register an NDP entry for a node. +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 a proxy NDP server, +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 -.Xr tcpdump 1 . +Print timestamp on each entry, +making it possible to merge output with +.Xr tcpdump 8 . Most useful when used with .Fl A . .El @@ -179,7 +234,7 @@ Most useful when used with .Sh RETURN VALUES The .Nm -utility will exit with 0 on success, and non-zero on errors. +command will exit with 0 on success, and non-zero on errors. .\" .Sh SEE ALSO .Xr arp 8 @@ -187,7 +242,7 @@ utility will exit with 0 on success, and non-zero on errors. .Sh HISTORY The .Nm -utility first appeared in WIDE Hydrangea IPv6 protocol stack kit. +command first appeared in the WIDE Hydrangea IPv6 protocol stack kit. .\" .\" .Sh BUGS .\" (to be written) diff --git a/usr.sbin/ndp/ndp.c b/usr.sbin/ndp/ndp.c index bd55ef732695..a761f96260b4 100644 --- a/usr.sbin/ndp/ndp.c +++ b/usr.sbin/ndp/ndp.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ndp.c,v 1.65 2001/05/08 04:36:34 itojun Exp $ */ +/* $KAME: ndp.c,v 1.104 2003/06/27 07:48:39 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -111,6 +111,7 @@ #include #include #include +#include #include "gmt2local.h" /* packing rule for routing socket */ @@ -119,7 +120,6 @@ #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) static pid_t pid; -static int cflag; static int nflag; static int tflag; static int32_t thiszone; /* time difference with gmt */ @@ -136,14 +136,13 @@ 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)); +void dump __P((struct in6_addr *, int)); +static struct in6_nbrinfo *getnbrinfo __P((struct in6_addr *, int, 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 ifinfo __P((char *, int, char **)); void rtrlist __P((void)); void plist __P((void)); void pfx_flush __P((void)); @@ -154,16 +153,21 @@ void harmonize_rtr __P((void)); 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 char *sec2str __P((time_t)); +static char *ether_str __P((struct sockaddr_dl *)); static void ts_print __P((const struct timeval *)); +#ifdef ICMPV6CTL_ND6_DRLIST static char *rtpref_str[] = { "medium", /* 00 */ "high", /* 01 */ "rsv", /* 10 */ "low" /* 11 */ }; +#endif + +int mode = 0; +char *arg = NULL; int main(argc, argv) @@ -171,76 +175,54 @@ main(argc, argv) char **argv; { int ch; - int aflag = 0, dflag = 0, sflag = 0, Hflag = 0, - pflag = 0, rflag = 0, Pflag = 0, Rflag = 0; pid = getpid(); thiszone = gmt2local(0); - while ((ch = getopt(argc, argv, "acndfIilprstA:HPR")) != -1) + while ((ch = getopt(argc, argv, "acd:f:Ii:nprstA:HPR")) != -1) switch (ch) { case 'a': - aflag = 1; - break; case 'c': - cflag = 1; + case 'p': + case 'r': + case 'H': + case 'P': + case 'R': + case 's': + case 'I': + if (mode) { + usage(); + /*NOTREACHED*/ + } + mode = ch; + arg = NULL; break; 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 'f': case 'i' : - argc -= optind; - argv += optind; - if (argc < 1) + if (mode) { usage(); - ifinfo(argc, argv); - exit(0); + /*NOTREACHED*/ + } + mode = ch; + arg = optarg; + break; case 'n': nflag = 1; - continue; - case 'p': - pflag = 1; - break; - case 'f' : - if (argc != 3) - usage(); - file(argv[2]); - exit(0); - case 'l' : - /* obsolete, ignored */ - break; - case 'r' : - rflag = 1; - break; - case 's': - sflag = 1; break; case 't': tflag = 1; break; case 'A': - aflag = 1; - repeat = atoi(optarg); - if (repeat < 0) + if (mode) { usage(); - break; - case 'H' : - Hflag = 1; - break; - case 'P': - Pflag = 1; - break; - case 'R': - Rflag = 1; + /*NOTREACHED*/ + } + mode = 'a'; + repeat = atoi(optarg); + if (repeat < 0) { + usage(); + /*NOTREACHED*/ + } break; default: usage(); @@ -249,45 +231,90 @@ main(argc, argv) argc -= optind; argv += optind; - if (aflag || cflag) { - dump(0); - exit(0); - } - if (dflag) { - if (argc != 1) + switch (mode) { + case 'a': + case 'c': + if (argc != 0) { usage(); - delete(argv[0]); - exit(0); - } - if (pflag) { + /*NOTREACHED*/ + } + dump(0, mode == 'c'); + break; + case 'd': + if (argc != 0) { + usage(); + /*NOTREACHED*/ + } + delete(arg); + break; + case 'I': +#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ + if (argc > 1) { + usage(); + /*NOTREACHED*/ + } else if (argc == 1) { + if (strcmp(*argv, "delete") == 0 || + if_nametoindex(*argv)) + setdefif(*argv); + else + errx(1, "invalid interface %s", *argv); + } + getdefif(); /* always call it to print the result */ + break; +#else + errx(1, "not supported yet"); + /*NOTREACHED*/ +#endif + case 'p': + if (argc != 0) { + usage(); + /*NOTREACHED*/ + } plist(); - exit(0); - } - if (rflag) { + break; + case 'i': + ifinfo(arg, argc, argv); + break; + case 'r': + if (argc != 0) { + usage(); + /*NOTREACHED*/ + } rtrlist(); - exit(0); - } - if (sflag) { + break; + case 's': if (argc < 2 || argc > 4) usage(); exit(set(argc, argv) ? 1 : 0); - } - if (Hflag) { + case 'H': + if (argc != 0) { + usage(); + /*NOTREACHED*/ + } harmonize_rtr(); - exit(0); - } - if (Pflag) { + break; + case 'P': + if (argc != 0) { + usage(); + /*NOTREACHED*/ + } pfx_flush(); - exit(0); - } - if (Rflag) { + break; + case 'R': + if (argc != 0) { + usage(); + /*NOTREACHED*/ + } rtr_flush(); - exit(0); + break; + case 0: + if (argc != 1) { + usage(); + /*NOTREACHED*/ + } + get(argv[0]); + break; } - - if (argc != 1) - usage(); - get(argv[0]); exit(0); } @@ -313,8 +340,8 @@ file(name) args[4] = &arg[4][0]; retval = 0; while (fgets(line, 100, fp) != NULL) { - i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2], - arg[3], arg[4]); + i = sscanf(line, "%49s %49s %49s %49s %49s", + arg[0], arg[1], arg[2], arg[3], arg[4]); if (i < 2) { fprintf(stderr, "ndp: bad line: %s\n", line); retval = 1; @@ -408,10 +435,12 @@ set(argc, argv) 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 overwrite; + !(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 overwrite; + } } /* * IPv4 arp command retries with sin_other = SIN_PROXY here. @@ -457,7 +486,7 @@ get(host) htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); } #endif - dump(&sin->sin6_addr); + dump(&sin->sin6_addr, 0); if (found_entry == 0) { getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, sizeof(host_buf), NULL ,0, @@ -541,7 +570,7 @@ delete(host) return 0; } -#define W_ADDR 31 +#define W_ADDR 36 #define W_LL 17 #define W_IF 6 @@ -549,8 +578,9 @@ delete(host) * Dump the entire neighbor cache */ void -dump(addr) +dump(addr, cflag) struct in6_addr *addr; + int cflag; { int mib[6]; size_t needed; @@ -569,9 +599,9 @@ dump(addr) /* Print header */ if (!tflag && !cflag) - printf("%-*.*s %-*.*s %*.*s %-9.9s %2s %4s %4s\n", + printf("%-*.*s %-*.*s %*.*s %-9.9s %1s %5s\n", W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address", - W_IF, W_IF, "Netif", "Expire", "St", "Flgs", "Prbs"); + W_IF, W_IF, "Netif", "Expire", "S", "Flags"); again:; mib[0] = CTL_NET; @@ -614,6 +644,9 @@ again:; if (sdl->sdl_family != AF_LINK) continue; + if (!(rtm->rtm_flags & RTF_HOST)) + continue; + if (addr) { if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr)) continue; @@ -632,10 +665,13 @@ again:; } getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, sizeof(host_buf), NULL, 0, (nflag ? NI_NUMERICHOST : 0)); - if (cflag == 1) { + if (cflag) { #ifdef RTF_WASCLONED if (rtm->rtm_flags & RTF_WASCLONED) delete(host_buf); +#elif defined(RTF_CLONED) + if (rtm->rtm_flags & RTF_CLONED) + delete(host_buf); #else delete(host_buf); #endif @@ -707,7 +743,6 @@ again:; warnx("failed to get neighbor information"); printf(" "); } - putchar(' '); /* * other flags. R: router, P: proxy, W: ?? @@ -719,16 +754,22 @@ again:; } else { sin = (struct sockaddr_in6 *) (sdl->sdl_len + (char *)sdl); +#if 0 /* W and P are mystery even for us */ 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" : ""); +#else + snprintf(flgbuf, sizeof(flgbuf), "%s%s", + isrouter ? "R" : "", + (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); +#endif } - printf(" %-4.4s", flgbuf); + printf(" %s", flgbuf); if (prbs) - printf(" %4d", prbs); + printf(" %d", prbs); printf("\n"); } @@ -806,22 +847,16 @@ ndp_ether_aton(a, n) void usage() { - printf("usage: ndp hostname\n"); - printf(" ndp -a[nt]\n"); + printf("usage: ndp [-nt] hostname\n"); + printf(" ndp [-nt] -a | -c | -p | -r | -H | -P | -R\n"); printf(" ndp [-nt] -A wait\n"); - printf(" ndp -c[nt]\n"); - printf(" ndp -d[nt] hostname\n"); - printf(" ndp -f[nt] filename\n"); - printf(" ndp -i interface [flags...]\n"); + printf(" ndp [-nt] -d hostname\n"); + printf(" ndp [-nt] -f filename\n"); + printf(" ndp [-nt] -i interface [flags...]\n"); #ifdef SIOCSDEFIFACE_IN6 - printf(" ndp -I [interface|delete]\n"); + printf(" ndp [-nt] -I [interface|delete]\n"); #endif - printf(" ndp -p\n"); - printf(" ndp -r\n"); - printf(" ndp -s hostname ether_addr [temp] [proxy]\n"); - printf(" ndp -H\n"); - printf(" ndp -P\n"); - printf(" ndp -R\n"); + printf(" ndp [-nt] -s nodename etheraddr [temp] [proxy]\n"); exit(1); } @@ -848,8 +883,10 @@ rtmsg(cmd) exit(1); case RTM_ADD: rtm->rtm_addrs |= RTA_GATEWAY; - rtm->rtm_rmx.rmx_expire = expire_time; - rtm->rtm_inits = RTV_EXPIRE; + if (expire_time) { + 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; @@ -889,13 +926,13 @@ rtmsg(cmd) } void -ifinfo(argc, argv) +ifinfo(ifname, argc, argv) + char *ifname; int argc; char **argv; { struct in6_ndireq nd; int i, s; - char *ifname = argv[0]; u_int32_t newflags; #ifdef IPV6CTL_USETEMPADDR u_int8_t nullbuf[8]; @@ -910,10 +947,10 @@ ifinfo(argc, argv) if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { err(1, "ioctl(SIOCGIFINFO_IN6)"); /* NOTREACHED */ - } + } #define ND nd.ndi newflags = ND.flags; - for (i = 1; i < argc; i++) { + for (i = 0; i < argc; i++) { int clear = 0; char *cp = argv[i]; @@ -935,6 +972,9 @@ ifinfo(argc, argv) #ifdef ND6_IFF_ACCEPT_RTADV SETFLAG("accept_rtadv", ND6_IFF_ACCEPT_RTADV); #endif +#ifdef ND6_IFF_PREFER_SOURCE + SETFLAG("prefer_source", ND6_IFF_PREFER_SOURCE); +#endif ND.flags = newflags; if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd) < 0) { @@ -990,7 +1030,11 @@ ifinfo(argc, argv) if ((ND.flags & ND6_IFF_ACCEPT_RTADV)) printf("accept_rtadv "); #endif -} +#ifdef ND6_IFF_PREFER_SOURCE + if ((ND.flags & ND6_IFF_PREFER_SOURCE)) + printf("prefer_source "); +#endif + } putc('\n', stdout); #undef ND @@ -1153,11 +1197,11 @@ plist() if (p->vltime == ND6_INFINITE_LIFETIME) printf(" vltime=infinity"); else - printf(" vltime=%ld", (long)p->vltime); + printf(" vltime=%lu", (unsigned long)p->vltime); if (p->pltime == ND6_INFINITE_LIFETIME) printf(", pltime=infinity"); else - printf(", pltime=%ld", (long)p->pltime); + printf(", pltime=%lu", (unsigned long)p->pltime); if (p->expire == 0) printf(", expire=Never"); else if (p->expire >= time.tv_sec) @@ -1175,7 +1219,7 @@ plist() int j; struct sockaddr_in6 *sin6; - sin6 = (struct sockaddr_in6 *)(p + 1); + sin6 = advrtr; printf(" advertised by\n"); for (j = 0; j < p->advrtrs; j++) { struct in6_nbrinfo *nbi; @@ -1293,11 +1337,11 @@ plist() if (PR.vltime == ND6_INFINITE_LIFETIME) printf(" vltime=infinity"); else - printf(" vltime=%ld", (long)PR.vltime); + printf(" vltime=%lu", PR.vltime); if (PR.pltime == ND6_INFINITE_LIFETIME) printf(", pltime=infinity"); else - printf(", pltime=%ld", (long)PR.pltime); + printf(", pltime=%lu", PR.pltime); if (PR.expire == 0) printf(", expire=Never"); else if (PR.expire >= time.tv_sec)