+/*
+ * Copyright (c) 2009-2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
/* $FreeBSD: src/usr.sbin/ndp/ndp.c,v 1.2.2.5 2001/08/13 02:58:26 sumikawa Exp $ */
/* $KAME: ndp.c,v 1.65 2001/05/08 04:36:34 itojun Exp $ */
* ndp - display, set, delete and flush neighbor cache
*/
-
+#include <stdint.h>
#include <sys/param.h>
#include <sys/file.h>
#include <sys/ioctl.h>
/* packing rule for routing socket */
#define ROUNDUP(a) \
- ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
static int pid;
void get __P((char *));
int delete __P((char *));
void dump __P((struct in6_addr *));
+void dump_ext __P((struct in6_addr *, int));
static struct in6_nbrinfo *getnbrinfo __P((struct in6_addr *addr,
int ifindex, int));
static char *ether_str __P((struct sockaddr_dl *));
{
int ch;
int aflag = 0, dflag = 0, sflag = 0, Hflag = 0,
- pflag = 0, rflag = 0, Pflag = 0, Rflag = 0;
+ pflag = 0, rflag = 0, Pflag = 0, Rflag = 0, lflag = 0,
+ xflag = 0;
pid = getpid();
// thiszone = gmt2local(0);
- while ((ch = getopt(argc, argv, "acndfIilprstA:HPR")) != -1)
+ while ((ch = getopt(argc, argv, "acndfIilprstA:HPRx")) != -1)
switch ((char)ch) {
case 'a':
aflag = 1;
file(argv[2]);
exit(0);
case 'l' :
- /* obsolete, ignored */
+ lflag = 1;
break;
case 'r' :
rflag = 1;
case 'R':
Rflag = 1;
break;
+ case 'x':
+ xflag = 1;
+ lflag = 1;
+ break;
default:
usage();
}
argv += optind;
if (aflag || cflag) {
- dump(0);
+ if (lflag)
+ dump_ext(0, xflag);
+ else
+ dump(0);
exit(0);
}
if (dflag) {
struct rt_msghdr *rtm;
struct sockaddr_in6 *sin;
struct sockaddr_dl *sdl;
- extern int h_errno;
struct in6_nbrinfo *nbi;
struct timeval time;
int addrwidth;
} else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
continue;
if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
+ IN6_IS_ADDR_MC_NODELOCAL(&sin->sin6_addr) ||
IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
/* XXX: should scope id be filled in the kernel? */
if (sin->sin6_scope_id == 0)
}
}
+/*
+ * Dump the entire neighbor cache (extended)
+ */
+void
+dump_ext(addr, xflag)
+ struct in6_addr *addr;
+ int xflag;
+{
+ int mib[6];
+ size_t needed;
+ char *lim, *buf, *next;
+ struct rt_msghdr_ext *ertm;
+ struct sockaddr_in6 *sin;
+ struct sockaddr_dl *sdl;
+ struct in6_nbrinfo *nbi;
+ struct timeval time;
+ int addrwidth;
+ int llwidth;
+ int ifwidth;
+ char flgbuf[8];
+ char *ifname;
+
+ /* Print header */
+ if (!tflag && !cflag) {
+ printf("%-*.*s %-*.*s %*.*s %-9.9s %-9.9s %2s %4s %4s",
+ W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address",
+ W_IF, W_IF, "Netif", "Expire(O)", "Expire(I)", "St",
+ "Flgs", "Prbs");
+ if (xflag)
+ printf(" %-7.7s %-7.7s %-7.7s", "RSSI", "LQM", "NPM");
+ printf("\n");
+ }
+
+again:;
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET6;
+ mib[4] = NET_RT_DUMPX_FLAGS;
+ mib[5] = RTF_LLINFO;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ err(1, "sysctl(PF_ROUTE estimate)");
+ if (needed > 0) {
+ if ((buf = malloc(needed)) == NULL)
+ errx(1, "malloc");
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+ err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
+ lim = buf + needed;
+ } else
+ buf = lim = NULL;
+
+ for (next = buf; next && next < lim; next += ertm->rtm_msglen) {
+ int isrouter = 0, prbs = 0;
+
+ ertm = (struct rt_msghdr_ext *)next;
+ sin = (struct sockaddr_in6 *)(ertm + 1);
+ sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len));
+
+ /*
+ * Some OSes can produce a route that has the LINK flag but
+ * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
+ * and BSD/OS, where xx is not the interface identifier on
+ * lo0). Such routes entry would annoy getnbrinfo() below,
+ * so we skip them.
+ * XXX: such routes should have the GATEWAY flag, not the
+ * LINK flag. However, there are rotten routing software
+ * that advertises all routes that have the GATEWAY flag.
+ * Thus, KAME kernel intentionally does not set the LINK flag.
+ * What is to be fixed is not ndp, but such routing software
+ * (and the kernel workaround)...
+ */
+ if (sdl->sdl_family != AF_LINK)
+ continue;
+
+ if (addr) {
+ if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
+ continue;
+ found_entry = 1;
+ } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
+ continue;
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
+ IN6_IS_ADDR_MC_NODELOCAL(&sin->sin6_addr) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
+ /* XXX: should scope id be filled in the kernel? */
+ if (sin->sin6_scope_id == 0)
+ sin->sin6_scope_id = sdl->sdl_index;
+#ifdef __KAME__
+ /* KAME specific hack; removed the embedded id */
+ *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0;
+#endif
+ }
+ getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
+ sizeof(host_buf), NULL, 0,
+ NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
+ if (cflag == 1) {
+#ifdef RTF_WASCLONED
+ if (ertm->rtm_flags & RTF_WASCLONED)
+ delete(host_buf);
+#else
+ delete(host_buf);
+#endif
+ continue;
+ }
+ gettimeofday(&time, 0);
+ if (tflag)
+ ts_print(&time);
+
+ addrwidth = strlen(host_buf);
+ if (addrwidth < W_ADDR)
+ addrwidth = W_ADDR;
+ llwidth = strlen(ether_str(sdl));
+ if (W_ADDR + W_LL - addrwidth > llwidth)
+ llwidth = W_ADDR + W_LL - addrwidth;
+ ifname = if_indextoname(sdl->sdl_index, ifix_buf);
+ if (!ifname)
+ ifname = "?";
+ ifwidth = strlen(ifname);
+ if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth)
+ ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth;
+
+ printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
+ llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
+
+ if (ertm->rtm_ri.ri_refcnt == 0 ||
+ ertm->rtm_ri.ri_snd_expire == 0)
+ printf(" %-9.9s", "(none)");
+ else if (ertm->rtm_ri.ri_snd_expire > time.tv_sec)
+ printf(" %-9.9s",
+ sec2str(ertm->rtm_ri.ri_snd_expire - time.tv_sec));
+ else
+ printf(" %-9.9s", "expired");
+
+ if (ertm->rtm_ri.ri_refcnt == 0 ||
+ ertm->rtm_ri.ri_rcv_expire == 0)
+ printf(" %-9.9s", "(none)");
+ else if (ertm->rtm_ri.ri_rcv_expire > time.tv_sec)
+ printf(" %-9.9s",
+ sec2str(ertm->rtm_ri.ri_rcv_expire - time.tv_sec));
+ else
+ printf(" %-9.9s", "expired");
+
+ /* Print neighbor discovery specific informations */
+ nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
+ if (nbi) {
+ switch(nbi->state) {
+ case ND6_LLINFO_NOSTATE:
+ printf(" N");
+ break;
+#ifdef ND6_LLINFO_WAITDELETE
+ case ND6_LLINFO_WAITDELETE:
+ printf(" W");
+ break;
+#endif
+ case ND6_LLINFO_INCOMPLETE:
+ printf(" I");
+ break;
+ case ND6_LLINFO_REACHABLE:
+ printf(" R");
+ break;
+ case ND6_LLINFO_STALE:
+ printf(" S");
+ break;
+ case ND6_LLINFO_DELAY:
+ printf(" D");
+ break;
+ case ND6_LLINFO_PROBE:
+ printf(" P");
+ break;
+ default:
+ printf(" ?");
+ break;
+ }
+
+ isrouter = nbi->isrouter;
+ prbs = nbi->asked;
+ } else {
+ warnx("failed to get neighbor information");
+ printf(" ");
+ }
+ putchar(' ');
+
+ /*
+ * other flags. R: router, P: proxy, W: ??
+ */
+ if ((ertm->rtm_addrs & RTA_NETMASK) == 0) {
+ snprintf(flgbuf, sizeof(flgbuf), "%s%s",
+ isrouter ? "R" : "",
+ (ertm->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" : "",
+ (ertm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
+ }
+ printf(" %-4.4s", flgbuf);
+
+ if (prbs)
+ printf(" %4d", prbs);
+
+ if (xflag) {
+ if (!prbs)
+ printf(" %-4.4s", "none");
+
+ if (ertm->rtm_ri.ri_rssi != IFNET_RSSI_UNKNOWN)
+ printf(" %7d", ertm->rtm_ri.ri_rssi);
+ else
+ printf(" %-7.7s", "unknown");
+
+ switch (ertm->rtm_ri.ri_lqm)
+ {
+ case IFNET_LQM_THRESH_OFF:
+ printf(" %-7.7s", "off");
+ break;
+ case IFNET_LQM_THRESH_UNKNOWN:
+ printf(" %-7.7s", "unknown");
+ break;
+ case IFNET_LQM_THRESH_POOR:
+ printf(" %-7.7s", "poor");
+ break;
+ case IFNET_LQM_THRESH_GOOD:
+ printf(" %-7.7s", "good");
+ break;
+ default:
+ printf(" %7d", ertm->rtm_ri.ri_lqm);
+ break;
+ }
+
+ switch (ertm->rtm_ri.ri_npm)
+ {
+ case IFNET_NPM_THRESH_UNKNOWN:
+ printf(" %-7.7s", "unknown");
+ break;
+ case IFNET_NPM_THRESH_NEAR:
+ printf(" %-7.7s", "near");
+ break;
+ case IFNET_NPM_THRESH_GENERAL:
+ printf(" %-7.7s", "general");
+ break;
+ case IFNET_NPM_THRESH_FAR:
+ printf(" %-7.7s", "far");
+ break;
+ default:
+ printf(" %7d", ertm->rtm_ri.ri_npm);
+ break;
+ }
+ }
+
+ printf("\n");
+ }
+ if (buf != NULL)
+ free(buf);
+
+ if (repeat) {
+ printf("\n");
+ sleep(repeat);
+ goto again;
+ }
+}
+
static struct in6_nbrinfo *
getnbrinfo(addr, ifindex, warning)
struct in6_addr *addr;
if (sdl->sdl_alen) {
cp = (u_char *)LLADDR(sdl);
- sprintf(ebuf, "%x:%x:%x:%x:%x:%x",
+ snprintf(ebuf, sizeof(ebuf), "%x:%x:%x:%x:%x:%x",
cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
} else {
- sprintf(ebuf, "(incomplete)");
+ snprintf(ebuf, sizeof(ebuf), "(incomplete)");
}
return(ebuf);
usage()
{
printf("usage: ndp hostname\n");
- printf(" ndp -a[nt]\n");
+ printf(" ndp -a[lnt]\n");
printf(" ndp [-nt] -A wait\n");
printf(" ndp -c[nt]\n");
printf(" ndp -d[nt] hostname\n");
exit(1);
}
bzero(&nd, sizeof(nd));
- strcpy(nd.ifname, ifname);
+ strlcpy(nd.ifname, ifname, sizeof(nd.ifname));
if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
perror("ioctl (SIOCGIFINFO_IN6)");
exit(1);
}\
} while (0)
SETFLAG("nud", ND6_IFF_PERFORMNUD);
+ SETFLAG("proxy_prefixes", ND6_IFF_PROXY_PREFIXES);
+ SETFLAG("ignore_na", ND6_IFF_IGNORE_NA);
ND.flags = newflags;
if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd) < 0) {
memset(nullbuf, 0, sizeof(nullbuf));
if (memcmp(nullbuf, ND.randomid, sizeof(nullbuf)) != 0) {
int j;
- u_int8_t *rbuf;
+ u_int8_t *rbuf = NULL;
for (i = 0; i < 3; i++) {
switch(i) {
printf("\nFlags: ");
if ((ND.flags & ND6_IFF_PERFORMNUD) != 0)
printf("PERFORMNUD ");
+ if ((ND.flags & ND6_IFF_PROXY_PREFIXES) != 0)
+ printf("PROXY_PREFIXES ");
+ if ((ND.flags & ND6_IFF_IFDISABLED) != 0)
+ printf("IFDISABLED ");
+ if ((ND.flags & ND6_IFF_IGNORE_NA) != 0)
+ printf("IGNORE_NA ");
}
putc('\n', stdout);
#undef ND
printf("%s if=%s", host_buf,
if_indextoname(p->if_index, ifix_buf));
- printf(", flags=%s%s",
+ printf(", flags=%s%s%s%s%s",
p->flags & ND_RA_FLAG_MANAGED ? "M" : "",
- p->flags & ND_RA_FLAG_OTHER ? "O" : "");
+ p->flags & ND_RA_FLAG_OTHER ? "O" : "",
+ p->stateflags & NDDRF_INSTALLED ? "T" : "",
+ p->stateflags & NDDRF_IFSCOPE ? "I" : "",
+ p->stateflags & NDDRF_STATIC ? "S" : "");
rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff;
printf(", pref=%s", rtpref_str[rtpref]);
exit(1);
}
bzero(&dr, sizeof(dr));
- strcpy(dr.ifname, "lo0"); /* dummy */
+ strlcpy(dr.ifname, "lo0", sizeof(dr.ifname)); /* dummy */
if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) {
perror("ioctl (SIOCGDRLST_IN6)");
exit(1);
* meaning of fields, especially flags, is very different
* by origin. notify the difference to the users.
*/
- printf("flags=%s%s%s%s%s",
+ printf("flags=%s%s%s%s%s%s%s%s",
p->raflags.onlink ? "L" : "",
p->raflags.autonomous ? "A" : "",
(p->flags & NDPRF_ONLINK) != 0 ? "O" : "",
(p->flags & NDPRF_DETACHED) != 0 ? "D" : "",
+ (p->flags & NDPRF_IFSCOPE) != 0 ? "I" : "",
+ (p->flags & NDPRF_PRPROXY) != 0 ? "Y" : "",
#ifdef NDPRF_HOME
- (p->flags & NDPRF_HOME) != 0 ? "H" : ""
+ (p->flags & NDPRF_HOME) != 0 ? "H" : "",
+#else
+ "",
+#endif
+#ifdef NDPRF_STATIC
+ (p->flags & NDPRF_STATIC) != 0 ? "S" : ""
#else
""
#endif
exit(1);
}
bzero(&pr, sizeof(pr));
- strcpy(pr.ifname, "lo0"); /* dummy */
+ strlcpy(pr.ifname, "lo0", sizeof(pr.ifname)); /* dummy */
if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) {
perror("ioctl (SIOCGPRLST_IN6)");
exit(1);
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
err(1, "socket");
- strcpy(dummyif, "lo0"); /* dummy */
+ strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0)
err(1, "ioctl(SIOCSPFXFLUSH_IN6)");
}
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
err(1, "socket");
- strcpy(dummyif, "lo0"); /* dummy */
+ strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0)
err(1, "ioctl(SIOCSRTRFLUSH_IN6)");
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
err(1, "socket");
- strcpy(dummyif, "lo0"); /* dummy */
+ strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0)
err(1, "ioctl (SIOCSNDFLUSH_IN6)");
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
err(1, "socket");
- strcpy(ndifreq.ifname, "lo0"); /* dummy */
+ strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */
ndifreq.ifindex = ifindex;
if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
err(1, "socket");
memset(&ndifreq, 0, sizeof(ndifreq));
- strcpy(ndifreq.ifname, "lo0"); /* dummy */
+ strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */
if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
err(1, "ioctl (SIOCGDEFIFACE_IN6)");
if (days) {
first = 0;
- p += sprintf(p, "%dd", days);
+ p += snprintf(p, sizeof(result) - (p - result), "%dd", days);
}
if (!first || hours) {
first = 0;
- p += sprintf(p, "%dh", hours);
+ p += snprintf(p, sizeof(result) - (p - result), "%dh", hours);
}
if (!first || mins) {
first = 0;
- p += sprintf(p, "%dm", mins);
+ p += snprintf(p, sizeof(result) - (p - result), "%dm", mins);
}
- sprintf(p, "%ds", secs);
+ snprintf(p, sizeof(result) - (p - result), "%ds", secs);
return(result);
}