- make command line argument parsing POSIX compliant. comment from

deraadt NOTE: -I needs to take an arg (there's no way we can take no
  arg/an arg with a single option)
- sscanf overrun
- no variable name on prototype.
- u_int32_t may not be u_long.
- skipped non-host route when printing neighbor cache entries.
- valid and preferred lifetimes are unsigned.
- wording.

Obtained from:	KAME
This commit is contained in:
ume 2003-11-13 16:02:44 +00:00
parent 70ed503f38
commit 775ceed26d
2 changed files with 284 additions and 185 deletions

View File

@ -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)

View File

@ -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 <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <err.h>
#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)