aboutsummaryrefslogtreecommitdiff
path: root/usr.bin/netstat
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/netstat')
-rw-r--r--usr.bin/netstat/Makefile17
-rw-r--r--usr.bin/netstat/atalk.c286
-rw-r--r--usr.bin/netstat/if.c674
-rw-r--r--usr.bin/netstat/inet.c832
-rw-r--r--usr.bin/netstat/inet6.c1137
-rw-r--r--usr.bin/netstat/ipsec.c322
-rw-r--r--usr.bin/netstat/ipx.c356
-rw-r--r--usr.bin/netstat/main.c698
-rw-r--r--usr.bin/netstat/mbuf.c197
-rw-r--r--usr.bin/netstat/mcast.c148
-rw-r--r--usr.bin/netstat/mroute.c303
-rw-r--r--usr.bin/netstat/mroute6.c235
-rw-r--r--usr.bin/netstat/netgraph.c184
-rw-r--r--usr.bin/netstat/netstat.1441
-rw-r--r--usr.bin/netstat/netstat.h153
-rw-r--r--usr.bin/netstat/route.c1125
-rw-r--r--usr.bin/netstat/unix.c160
17 files changed, 7268 insertions, 0 deletions
diff --git a/usr.bin/netstat/Makefile b/usr.bin/netstat/Makefile
new file mode 100644
index 000000000000..a47f735e56ee
--- /dev/null
+++ b/usr.bin/netstat/Makefile
@@ -0,0 +1,17 @@
+# @(#)Makefile 8.1 (Berkeley) 6/12/93
+# $FreeBSD$
+
+PROG= netstat
+SRCS= if.c inet.c inet6.c main.c mbuf.c mcast.c mroute.c ipx.c route.c \
+ unix.c atalk.c netgraph.c mroute6.c ipsec.c
+CFLAGS+=-DIPSEC
+CFLAGS+=-DINET6
+WARNS?= 2
+NO_WERROR?=
+
+BINGRP= kmem
+BINMODE=2555
+DPADD= ${LIBKVM} ${LIBIPX} ${LIBNETGRAPH} ${LIBUTIL}
+LDADD= -lkvm -lipx -lnetgraph -lutil
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/netstat/atalk.c b/usr.bin/netstat/atalk.c
new file mode 100644
index 000000000000..517325c7a645
--- /dev/null
+++ b/usr.bin/netstat/atalk.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)atalk.c 1.1 (Whistle) 6/6/96";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+
+#include <arpa/inet.h>
+#include <net/route.h>
+
+#include <netatalk/at.h>
+#include <netatalk/ddp_var.h>
+
+#include <errno.h>
+#include <nlist.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include "netstat.h"
+
+struct ddpcb ddpcb;
+struct socket sockb;
+
+static int first = 1;
+
+/*
+ * Print a summary of connections related to a Network Systems
+ * protocol. For XXX, also give state of connection.
+ * Listening processes (aflag) are suppressed unless the
+ * -a (all) flag is specified.
+ */
+
+static const char *
+at_pr_net(struct sockaddr_at *sat, int numeric)
+{
+static char mybuf[50];
+
+ if (!numeric) {
+ switch(sat->sat_addr.s_net) {
+ case 0xffff:
+ return "????";
+ case ATADDR_ANYNET:
+ return("*");
+ }
+ }
+ sprintf(mybuf,"%hu",ntohs(sat->sat_addr.s_net));
+ return mybuf;
+}
+
+static const char *
+at_pr_host(struct sockaddr_at *sat, int numeric)
+{
+static char mybuf[50];
+
+ if (!numeric) {
+ switch(sat->sat_addr.s_node) {
+ case ATADDR_BCAST:
+ return "bcast";
+ case ATADDR_ANYNODE:
+ return("*");
+ }
+ }
+ sprintf(mybuf,"%d",(unsigned int)sat->sat_addr.s_node);
+ return mybuf;
+}
+
+static const char *
+at_pr_port(struct sockaddr_at *sat)
+{
+static char mybuf[50];
+ struct servent *serv;
+
+ switch(sat->sat_port) {
+ case ATADDR_ANYPORT:
+ return("*");
+ case 0xff:
+ return "????";
+ default:
+ if (numeric_port) {
+ (void)snprintf(mybuf, sizeof(mybuf), "%d",
+ (unsigned int)sat->sat_port);
+ } else {
+ serv = getservbyport(sat->sat_port, "ddp");
+ if (serv == NULL)
+ (void)snprintf(mybuf, sizeof(mybuf), "%d",
+ (unsigned int) sat->sat_port);
+ else
+ (void) snprintf(mybuf, sizeof(mybuf), "%s",
+ serv->s_name);
+ }
+ }
+ return mybuf;
+}
+
+static char *
+at_pr_range(struct sockaddr_at *sat)
+{
+static char mybuf[50];
+
+ if(sat->sat_range.r_netrange.nr_firstnet
+ != sat->sat_range.r_netrange.nr_lastnet) {
+ sprintf(mybuf,"%d-%d",
+ ntohs(sat->sat_range.r_netrange.nr_firstnet),
+ ntohs(sat->sat_range.r_netrange.nr_lastnet));
+ } else {
+ sprintf(mybuf,"%d",
+ ntohs(sat->sat_range.r_netrange.nr_firstnet));
+ }
+ return mybuf;
+}
+
+
+/* what == 0 for addr only == 3 */
+/* 1 for net */
+/* 2 for host */
+/* 4 for port */
+/* 8 for numeric only */
+char *
+atalk_print(struct sockaddr *sa, int what)
+{
+ struct sockaddr_at *sat = (struct sockaddr_at *)sa;
+ static char mybuf[50];
+ int numeric = (what & 0x08);
+
+ mybuf[0] = 0;
+ switch (what & 0x13) {
+ case 0:
+ mybuf[0] = 0;
+ break;
+ case 1:
+ sprintf(mybuf,"%s",at_pr_net(sat, numeric));
+ break;
+ case 2:
+ sprintf(mybuf,"%s",at_pr_host(sat, numeric));
+ break;
+ case 3:
+ sprintf(mybuf,"%s.%s",
+ at_pr_net(sat, numeric),
+ at_pr_host(sat, numeric));
+ break;
+ case 0x10:
+ sprintf(mybuf,"%s", at_pr_range(sat));
+ }
+ if (what & 4) {
+ sprintf(mybuf+strlen(mybuf),".%s",at_pr_port(sat));
+ }
+ return mybuf;
+}
+
+char *
+atalk_print2(struct sockaddr *sa, struct sockaddr *mask, int what)
+{
+ int n;
+ static char buf[100];
+ struct sockaddr_at *sat1, *sat2;
+ struct sockaddr_at thesockaddr;
+ struct sockaddr *sa2;
+
+ sat1 = (struct sockaddr_at *)sa;
+ sat2 = (struct sockaddr_at *)mask;
+ sa2 = (struct sockaddr *)&thesockaddr;
+
+ thesockaddr.sat_addr.s_net = sat1->sat_addr.s_net & sat2->sat_addr.s_net;
+ snprintf(buf, sizeof(buf), "%s", atalk_print(sa2, 1 |(what & 8)));
+ if(sat2->sat_addr.s_net != 0xFFFF) {
+ thesockaddr.sat_addr.s_net = sat1->sat_addr.s_net | ~sat2->sat_addr.s_net;
+ n = strlen(buf);
+ snprintf(buf + n, sizeof(buf) - n, "-%s", atalk_print(sa2, 1 |(what & 8)));
+ }
+ if(what & 2) {
+ n = strlen(buf);
+ snprintf(buf + n, sizeof(buf) - n, ".%s", atalk_print(sa, what & (~1)));
+ }
+ return(buf);
+}
+
+void
+atalkprotopr(u_long off __unused, const char *name, int af1 __unused)
+{
+ struct ddpcb *this, *next;
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&this, sizeof (struct ddpcb *));
+ for ( ; this != NULL; this = next) {
+ kread((u_long)this, (char *)&ddpcb, sizeof (ddpcb));
+ next = ddpcb.ddp_next;
+#if 0
+ if (!aflag && atalk_nullhost(ddpcb.ddp_lsat) ) {
+ continue;
+ }
+#endif
+ kread((u_long)ddpcb.ddp_socket, (char *)&sockb, sizeof (sockb));
+ if (first) {
+ printf("Active ATALK connections");
+ if (aflag)
+ printf(" (including servers)");
+ putchar('\n');
+ if (Aflag)
+ printf("%-8.8s ", "PCB");
+ printf(Aflag ?
+ "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" :
+ "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n",
+ "Proto", "Recv-Q", "Send-Q",
+ "Local Address", "Foreign Address", "(state)");
+ first = 0;
+ }
+ if (Aflag)
+ printf("%8lx ", (u_long) this);
+ printf("%-5.5s %6u %6u ", name, sockb.so_rcv.sb_cc,
+ sockb.so_snd.sb_cc);
+ printf(Aflag?" %-18.18s":" %-22.22s", atalk_print(
+ (struct sockaddr *)&ddpcb.ddp_lsat,7));
+ printf(Aflag?" %-18.18s":" %-22.22s", atalk_print(
+ (struct sockaddr *)&ddpcb.ddp_fsat,7));
+ putchar('\n');
+ }
+}
+
+#define ANY(x,y,z) if (x || sflag <= 1) \
+ printf("\t%lu %s%s%s\n",x,y,plural(x),z)
+
+/*
+ * Dump DDP statistics structure.
+ */
+void
+ddp_stats(u_long off __unused, const char *name, int af1 __unused)
+{
+ struct ddpstat ddpstat;
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&ddpstat, sizeof (ddpstat));
+ printf("%s:\n", name);
+ ANY(ddpstat.ddps_short, "packet", " with short headers ");
+ ANY(ddpstat.ddps_long, "packet", " with long headers ");
+ ANY(ddpstat.ddps_nosum, "packet", " with no checksum ");
+ ANY(ddpstat.ddps_tooshort, "packet", " too short ");
+ ANY(ddpstat.ddps_badsum, "packet", " with bad checksum ");
+ ANY(ddpstat.ddps_toosmall, "packet", " with not enough data ");
+ ANY(ddpstat.ddps_forward, "packet", " forwarded ");
+ ANY(ddpstat.ddps_encap, "packet", " encapsulated ");
+ ANY(ddpstat.ddps_cantforward, "packet", " rcvd for unreachable dest ");
+ ANY(ddpstat.ddps_nosockspace, "packet", " dropped due to no socket space ");
+}
diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c
new file mode 100644
index 000000000000..0a8725b186a0
--- /dev/null
+++ b/usr.bin/netstat/if.c
@@ -0,0 +1,674 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)if.c 8.3 (Berkeley) 4/28/95";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/bridge.h>
+#include <net/ethernet.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#include <arpa/inet.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "netstat.h"
+
+#define YES 1
+#define NO 0
+
+static void sidewaysintpr (u_int, u_long);
+static void catchalarm (int);
+
+#ifdef INET6
+static char ntop_buf[INET6_ADDRSTRLEN]; /* for inet_ntop() */
+static int bdg_done;
+#endif
+
+/* print bridge statistics */
+void
+bdg_stats(u_long dummy __unused, const char *name, int af1 __unused)
+{
+ int i;
+ size_t slen ;
+ struct bdg_stats s ;
+ int mib[4] ;
+
+ slen = sizeof(s);
+
+ mib[0] = CTL_NET ;
+ mib[1] = PF_LINK ;
+ mib[2] = IFT_ETHER ;
+ mib[3] = PF_BDG ;
+ if (sysctl(mib,4, &s,&slen,NULL,0)==-1)
+ return ; /* no bridging */
+#ifdef INET6
+ if (bdg_done != 0)
+ return;
+ else
+ bdg_done = 1;
+#endif
+ printf("-- Bridging statistics (%s) --\n", name) ;
+ printf(
+"Name In Out Forward Drop Bcast Mcast Local Unknown\n");
+ for (i = 0 ; i < 16 ; i++) {
+ if (s.s[i].name[0])
+ printf("%-6s %9ld%9ld%9ld%9ld%9ld%9ld%9ld%9ld\n",
+ s.s[i].name,
+ s.s[i].p_in[(int)BDG_IN],
+ s.s[i].p_in[(int)BDG_OUT],
+ s.s[i].p_in[(int)BDG_FORWARD],
+ s.s[i].p_in[(int)BDG_DROP],
+ s.s[i].p_in[(int)BDG_BCAST],
+ s.s[i].p_in[(int)BDG_MCAST],
+ s.s[i].p_in[(int)BDG_LOCAL],
+ s.s[i].p_in[(int)BDG_UNKNOWN] );
+ }
+}
+
+
+
+
+/*
+ * Display a formatted value, or a '-' in the same space.
+ */
+static void
+show_stat(const char *fmt, int width, u_long value, short showvalue)
+{
+ char newfmt[32];
+
+ /* Construct the format string */
+ if (showvalue) {
+ sprintf(newfmt, "%%%d%s", width, fmt);
+ printf(newfmt, value);
+ } else {
+ sprintf(newfmt, "%%%ds", width);
+ printf(newfmt, "-");
+ }
+}
+
+
+
+/*
+ * Print a description of the network interfaces.
+ */
+void
+intpr(int _interval, u_long ifnetaddr, void (*pfunc)(char *))
+{
+ struct ifnet ifnet;
+ struct ifnethead ifnethead;
+ union {
+ struct ifaddr ifa;
+ struct in_ifaddr in;
+#ifdef INET6
+ struct in6_ifaddr in6;
+#endif
+ struct ipx_ifaddr ipx;
+ } ifaddr;
+ u_long ifaddraddr;
+ u_long ifaddrfound;
+ u_long ifnetfound;
+ u_long opackets;
+ u_long ipackets;
+ u_long obytes;
+ u_long ibytes;
+ u_long omcasts;
+ u_long imcasts;
+ u_long oerrors;
+ u_long ierrors;
+ u_long collisions;
+ short timer;
+ int drops;
+ struct sockaddr *sa = NULL;
+ char name[IFNAMSIZ];
+ short network_layer;
+ short link_layer;
+
+ if (ifnetaddr == 0) {
+ printf("ifnet: symbol not defined\n");
+ return;
+ }
+ if (_interval) {
+ sidewaysintpr((unsigned)_interval, ifnetaddr);
+ return;
+ }
+ if (kread(ifnetaddr, (char *)&ifnethead, sizeof ifnethead))
+ return;
+ ifnetaddr = (u_long)TAILQ_FIRST(&ifnethead);
+ if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet))
+ return;
+
+ if (!pfunc) {
+ if (Wflag)
+ printf("%-7.7s", "Name");
+ else
+ printf("%-5.5s", "Name");
+ printf(" %5.5s %-13.13s %-17.17s %8.8s %5.5s",
+ "Mtu", "Network", "Address", "Ipkts", "Ierrs");
+ if (bflag)
+ printf(" %10.10s","Ibytes");
+ printf(" %8.8s %5.5s", "Opkts", "Oerrs");
+ if (bflag)
+ printf(" %10.10s","Obytes");
+ printf(" %5s", "Coll");
+ if (tflag)
+ printf(" %s", "Time");
+ if (dflag)
+ printf(" %s", "Drop");
+ putchar('\n');
+ }
+ ifaddraddr = 0;
+ while (ifnetaddr || ifaddraddr) {
+ struct sockaddr_in *sockin;
+#ifdef INET6
+ struct sockaddr_in6 *sockin6;
+#endif
+ char *cp;
+ int n, m;
+
+ network_layer = 0;
+ link_layer = 0;
+
+ if (ifaddraddr == 0) {
+ ifnetfound = ifnetaddr;
+ if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet))
+ return;
+ strlcpy(name, ifnet.if_xname, sizeof(name));
+ ifnetaddr = (u_long)TAILQ_NEXT(&ifnet, if_link);
+ if (interface != 0 && (strcmp(name, interface) != 0))
+ continue;
+ cp = index(name, '\0');
+
+ if (pfunc) {
+ (*pfunc)(name);
+ continue;
+ }
+
+ if ((ifnet.if_flags&IFF_UP) == 0)
+ *cp++ = '*';
+ *cp = '\0';
+ ifaddraddr = (u_long)TAILQ_FIRST(&ifnet.if_addrhead);
+ }
+ ifaddrfound = ifaddraddr;
+
+ /*
+ * Get the interface stats. These may get
+ * overriden below on a per-interface basis.
+ */
+ opackets = ifnet.if_opackets;
+ ipackets = ifnet.if_ipackets;
+ obytes = ifnet.if_obytes;
+ ibytes = ifnet.if_ibytes;
+ omcasts = ifnet.if_omcasts;
+ imcasts = ifnet.if_imcasts;
+ oerrors = ifnet.if_oerrors;
+ ierrors = ifnet.if_ierrors;
+ collisions = ifnet.if_collisions;
+ timer = ifnet.if_timer;
+ drops = ifnet.if_snd.ifq_drops;
+
+ if (ifaddraddr == 0) {
+ if (Wflag)
+ printf("%-7.7s", name);
+ else
+ printf("%-5.5s", name);
+ printf(" %5lu ", ifnet.if_mtu);
+ printf("%-13.13s ", "none");
+ printf("%-17.17s ", "none");
+ } else {
+ if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) {
+ ifaddraddr = 0;
+ continue;
+ }
+#define CP(x) ((char *)(x))
+ cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) +
+ CP(&ifaddr);
+ sa = (struct sockaddr *)cp;
+ if (af != AF_UNSPEC && sa->sa_family != af) {
+ ifaddraddr =
+ (u_long)TAILQ_NEXT(&ifaddr.ifa, ifa_link);
+ continue;
+ }
+ if (Wflag)
+ printf("%-7.7s", name);
+ else
+ printf("%-5.5s", name);
+ printf(" %5lu ", ifnet.if_mtu);
+ switch (sa->sa_family) {
+ case AF_UNSPEC:
+ printf("%-13.13s ", "none");
+ printf("%-15.15s ", "none");
+ break;
+ case AF_INET:
+ sockin = (struct sockaddr_in *)sa;
+#ifdef notdef
+ /* can't use inet_makeaddr because kernel
+ * keeps nets unshifted.
+ */
+ in = inet_makeaddr(ifaddr.in.ia_subnet,
+ INADDR_ANY);
+ printf("%-13.13s ", netname(in.s_addr,
+ ifaddr.in.ia_subnetmask));
+#else
+ printf("%-13.13s ",
+ netname(htonl(ifaddr.in.ia_subnet),
+ ifaddr.in.ia_subnetmask));
+#endif
+ printf("%-17.17s ",
+ routename(sockin->sin_addr.s_addr));
+
+ network_layer = 1;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ sockin6 = (struct sockaddr_in6 *)sa;
+ printf("%-13.13s ",
+ netname6(&ifaddr.in6.ia_addr,
+ &ifaddr.in6.ia_prefixmask.sin6_addr));
+ printf("%-17.17s ",
+ inet_ntop(AF_INET6,
+ &sockin6->sin6_addr,
+ ntop_buf, sizeof(ntop_buf)));
+
+ network_layer = 1;
+ break;
+#endif /*INET6*/
+ case AF_IPX:
+ {
+ struct sockaddr_ipx *sipx =
+ (struct sockaddr_ipx *)sa;
+ u_long net;
+ char netnum[10];
+
+ *(union ipx_net *) &net = sipx->sipx_addr.x_net;
+ sprintf(netnum, "%lx", (u_long)ntohl(net));
+ printf("ipx:%-8s ", netnum);
+/* printf("ipx:%-8s ", netname(net, 0L)); */
+ printf("%-17s ",
+ ipx_phost((struct sockaddr *)sipx));
+ }
+
+ network_layer = 1;
+ break;
+
+ case AF_APPLETALK:
+ printf("atalk:%-12.12s ",atalk_print(sa,0x10) );
+ printf("%-11.11s ",atalk_print(sa,0x0b) );
+ break;
+ case AF_LINK:
+ {
+ struct sockaddr_dl *sdl =
+ (struct sockaddr_dl *)sa;
+ char linknum[10];
+ cp = (char *)LLADDR(sdl);
+ n = sdl->sdl_alen;
+ sprintf(linknum, "<Link#%d>", sdl->sdl_index);
+ m = printf("%-13.13s ", linknum);
+ }
+ goto hexprint;
+ default:
+ m = printf("(%d)", sa->sa_family);
+ for (cp = sa->sa_len + (char *)sa;
+ --cp > sa->sa_data && (*cp == 0);) {}
+ n = cp - sa->sa_data + 1;
+ cp = sa->sa_data;
+ hexprint:
+ while (--n >= 0)
+ m += printf("%02x%c", *cp++ & 0xff,
+ n > 0 ? ':' : ' ');
+ m = 32 - m;
+ while (m-- > 0)
+ putchar(' ');
+
+ link_layer = 1;
+ break;
+ }
+
+ /*
+ * Fixup the statistics for interfaces that
+ * update stats for their network addresses
+ */
+ if (network_layer) {
+ opackets = ifaddr.in.ia_ifa.if_opackets;
+ ipackets = ifaddr.in.ia_ifa.if_ipackets;
+ obytes = ifaddr.in.ia_ifa.if_obytes;
+ ibytes = ifaddr.in.ia_ifa.if_ibytes;
+ }
+
+ ifaddraddr = (u_long)TAILQ_NEXT(&ifaddr.ifa, ifa_link);
+ }
+
+ show_stat("lu", 8, ipackets, link_layer|network_layer);
+ printf(" ");
+ show_stat("lu", 5, ierrors, link_layer);
+ printf(" ");
+ if (bflag) {
+ show_stat("lu", 10, ibytes, link_layer|network_layer);
+ printf(" ");
+ }
+ show_stat("lu", 8, opackets, link_layer|network_layer);
+ printf(" ");
+ show_stat("lu", 5, oerrors, link_layer);
+ printf(" ");
+ if (bflag) {
+ show_stat("lu", 10, obytes, link_layer|network_layer);
+ printf(" ");
+ }
+ show_stat("lu", 5, collisions, link_layer);
+ if (tflag) {
+ printf(" ");
+ show_stat("d", 3, timer, link_layer);
+ }
+ if (dflag) {
+ printf(" ");
+ show_stat("d", 3, drops, link_layer);
+ }
+ putchar('\n');
+ if (aflag && ifaddrfound) {
+ /*
+ * Print family's multicast addresses
+ */
+ struct ifmultiaddr *multiaddr;
+ struct ifmultiaddr ifma;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+#ifdef INET6
+ struct sockaddr_in6 in6;
+#endif /* INET6 */
+ struct sockaddr_dl dl;
+ } msa;
+ const char *fmt;
+
+ TAILQ_FOREACH(multiaddr, &ifnet.if_multiaddrs, ifma_link) {
+ if (kread((u_long)multiaddr, (char *)&ifma,
+ sizeof ifma))
+ break;
+ multiaddr = &ifma;
+ if (kread((u_long)ifma.ifma_addr, (char *)&msa,
+ sizeof msa))
+ break;
+ if (msa.sa.sa_family != sa->sa_family)
+ continue;
+
+ fmt = 0;
+ switch (msa.sa.sa_family) {
+ case AF_INET:
+ fmt = routename(msa.in.sin_addr.s_addr);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ printf("%*s %-19.19s(refs: %d)\n",
+ Wflag ? 27 : 25, "",
+ inet_ntop(AF_INET6,
+ &msa.in6.sin6_addr,
+ ntop_buf,
+ sizeof(ntop_buf)),
+ ifma.ifma_refcount);
+ break;
+#endif /* INET6 */
+ case AF_LINK:
+ switch (msa.dl.sdl_type) {
+ case IFT_ETHER:
+ case IFT_FDDI:
+ fmt = ether_ntoa(
+ (struct ether_addr *)
+ LLADDR(&msa.dl));
+ break;
+ }
+ break;
+ }
+ if (fmt) {
+ printf("%*s %-17.17s",
+ Wflag ? 27 : 25, "", fmt);
+ if (msa.sa.sa_family == AF_LINK) {
+ printf(" %8lu", imcasts);
+ printf("%*s",
+ bflag ? 17 : 6, "");
+ printf(" %8lu", omcasts);
+ }
+ putchar('\n');
+ }
+ }
+ }
+ }
+}
+
+struct iftot {
+ SLIST_ENTRY(iftot) chain;
+ char ift_name[IFNAMSIZ]; /* interface name */
+ u_long ift_ip; /* input packets */
+ u_long ift_ie; /* input errors */
+ u_long ift_op; /* output packets */
+ u_long ift_oe; /* output errors */
+ u_long ift_co; /* collisions */
+ u_int ift_dr; /* drops */
+ u_long ift_ib; /* input bytes */
+ u_long ift_ob; /* output bytes */
+};
+
+u_char signalled; /* set if alarm goes off "early" */
+
+/*
+ * Print a running summary of interface statistics.
+ * Repeat display every interval seconds, showing statistics
+ * collected over that interval. Assumes that interval is non-zero.
+ * First line printed at top of screen is always cumulative.
+ * XXX - should be rewritten to use ifmib(4).
+ */
+static void
+sidewaysintpr(unsigned interval1, u_long off)
+{
+ struct ifnet ifnet;
+ u_long firstifnet;
+ struct ifnethead ifnethead;
+ struct iftot *iftot, *ip, *ipn, *total, *sum, *interesting;
+ int line;
+ int oldmask, first;
+ u_long interesting_off;
+
+ if (kread(off, (char *)&ifnethead, sizeof ifnethead))
+ return;
+ firstifnet = (u_long)TAILQ_FIRST(&ifnethead);
+
+ if ((iftot = malloc(sizeof(struct iftot))) == NULL) {
+ printf("malloc failed\n");
+ exit(1);
+ }
+ memset(iftot, 0, sizeof(struct iftot));
+
+ interesting = NULL;
+ interesting_off = 0;
+ for (off = firstifnet, ip = iftot; off;) {
+ char name[IFNAMSIZ];
+
+ if (kread(off, (char *)&ifnet, sizeof ifnet))
+ break;
+ strlcpy(name, ifnet.if_xname, sizeof(name));
+ if (interface && strcmp(name, interface) == 0) {
+ interesting = ip;
+ interesting_off = off;
+ }
+ snprintf(ip->ift_name, sizeof(ip->ift_name), "(%s)", name);;
+ if ((ipn = malloc(sizeof(struct iftot))) == NULL) {
+ printf("malloc failed\n");
+ exit(1);
+ }
+ memset(ipn, 0, sizeof(struct iftot));
+ SLIST_NEXT(ip, chain) = ipn;
+ ip = ipn;
+ off = (u_long)TAILQ_NEXT(&ifnet, if_link);
+ }
+ if ((total = malloc(sizeof(struct iftot))) == NULL) {
+ printf("malloc failed\n");
+ exit(1);
+ }
+ memset(total, 0, sizeof(struct iftot));
+ if ((sum = malloc(sizeof(struct iftot))) == NULL) {
+ printf("malloc failed\n");
+ exit(1);
+ }
+ memset(sum, 0, sizeof(struct iftot));
+
+ (void)signal(SIGALRM, catchalarm);
+ signalled = NO;
+ (void)alarm(interval1);
+ first = 1;
+banner:
+ printf("%17s %14s %16s", "input",
+ interesting ? interesting->ift_name : "(Total)", "output");
+ putchar('\n');
+ printf("%10s %5s %10s %10s %5s %10s %5s",
+ "packets", "errs", "bytes", "packets", "errs", "bytes", "colls");
+ if (dflag)
+ printf(" %5.5s", "drops");
+ putchar('\n');
+ fflush(stdout);
+ line = 0;
+loop:
+ if (interesting != NULL) {
+ ip = interesting;
+ if (kread(interesting_off, (char *)&ifnet, sizeof ifnet)) {
+ printf("???\n");
+ exit(1);
+ };
+ if (!first) {
+ printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu",
+ ifnet.if_ipackets - ip->ift_ip,
+ ifnet.if_ierrors - ip->ift_ie,
+ ifnet.if_ibytes - ip->ift_ib,
+ ifnet.if_opackets - ip->ift_op,
+ ifnet.if_oerrors - ip->ift_oe,
+ ifnet.if_obytes - ip->ift_ob,
+ ifnet.if_collisions - ip->ift_co);
+ if (dflag)
+ printf(" %5u", ifnet.if_snd.ifq_drops - ip->ift_dr);
+ }
+ ip->ift_ip = ifnet.if_ipackets;
+ ip->ift_ie = ifnet.if_ierrors;
+ ip->ift_ib = ifnet.if_ibytes;
+ ip->ift_op = ifnet.if_opackets;
+ ip->ift_oe = ifnet.if_oerrors;
+ ip->ift_ob = ifnet.if_obytes;
+ ip->ift_co = ifnet.if_collisions;
+ ip->ift_dr = ifnet.if_snd.ifq_drops;
+ } else {
+ sum->ift_ip = 0;
+ sum->ift_ie = 0;
+ sum->ift_ib = 0;
+ sum->ift_op = 0;
+ sum->ift_oe = 0;
+ sum->ift_ob = 0;
+ sum->ift_co = 0;
+ sum->ift_dr = 0;
+ for (off = firstifnet, ip = iftot;
+ off && SLIST_NEXT(ip, chain) != NULL;
+ ip = SLIST_NEXT(ip, chain)) {
+ if (kread(off, (char *)&ifnet, sizeof ifnet)) {
+ off = 0;
+ continue;
+ }
+ sum->ift_ip += ifnet.if_ipackets;
+ sum->ift_ie += ifnet.if_ierrors;
+ sum->ift_ib += ifnet.if_ibytes;
+ sum->ift_op += ifnet.if_opackets;
+ sum->ift_oe += ifnet.if_oerrors;
+ sum->ift_ob += ifnet.if_obytes;
+ sum->ift_co += ifnet.if_collisions;
+ sum->ift_dr += ifnet.if_snd.ifq_drops;
+ off = (u_long)TAILQ_NEXT(&ifnet, if_link);
+ }
+ if (!first) {
+ printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu",
+ sum->ift_ip - total->ift_ip,
+ sum->ift_ie - total->ift_ie,
+ sum->ift_ib - total->ift_ib,
+ sum->ift_op - total->ift_op,
+ sum->ift_oe - total->ift_oe,
+ sum->ift_ob - total->ift_ob,
+ sum->ift_co - total->ift_co);
+ if (dflag)
+ printf(" %5u", sum->ift_dr - total->ift_dr);
+ }
+ *total = *sum;
+ }
+ if (!first)
+ putchar('\n');
+ fflush(stdout);
+ oldmask = sigblock(sigmask(SIGALRM));
+ if (! signalled) {
+ sigpause(0);
+ }
+ sigsetmask(oldmask);
+ signalled = NO;
+ (void)alarm(interval1);
+ line++;
+ first = 0;
+ if (line == 21)
+ goto banner;
+ else
+ goto loop;
+ /*NOTREACHED*/
+}
+
+/*
+ * Called if an interval expires before sidewaysintpr has completed a loop.
+ * Sets a flag to not wait for the alarm.
+ */
+static void
+catchalarm(int signo __unused)
+{
+ signalled = YES;
+}
diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c
new file mode 100644
index 000000000000..ea679f81af7a
--- /dev/null
+++ b/usr.bin/netstat/inet.c
@@ -0,0 +1,832 @@
+/*
+ * Copyright (c) 1983, 1988, 1993, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)inet.c 8.5 (Berkeley) 5/24/95";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+#include <sys/protosw.h>
+
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif /* INET6 */
+#include <netinet/in_pcb.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp_var.h>
+#include <netinet/igmp_var.h>
+#include <netinet/ip_var.h>
+#include <netinet/pim_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#include <netinet/tcp_seq.h>
+#define TCPSTATES
+#include <netinet/tcp_fsm.h>
+#include <netinet/tcp_timer.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcp_debug.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include <arpa/inet.h>
+#include <err.h>
+#include <errno.h>
+#include <libutil.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+
+char *inetname (struct in_addr *);
+void inetprint (struct in_addr *, int, const char *, int);
+#ifdef INET6
+static int udp_done, tcp_done;
+#endif /* INET6 */
+
+/*
+ * Print a summary of connections related to an Internet
+ * protocol. For TCP, also give state of connection.
+ * Listening processes (aflag) are suppressed unless the
+ * -a (all) flag is specified.
+ */
+void
+protopr(u_long proto, /* for sysctl version we pass proto # */
+ const char *name, int af1)
+{
+ int istcp;
+ static int first = 1;
+ char *buf;
+ const char *mibvar, *vchar;
+ struct tcpcb *tp = NULL;
+ struct inpcb *inp;
+ struct xinpgen *xig, *oxig;
+ struct xsocket *so;
+ size_t len;
+
+ istcp = 0;
+ switch (proto) {
+ case IPPROTO_TCP:
+#ifdef INET6
+ if (tcp_done != 0)
+ return;
+ else
+ tcp_done = 1;
+#endif
+ istcp = 1;
+ mibvar = "net.inet.tcp.pcblist";
+ break;
+ case IPPROTO_UDP:
+#ifdef INET6
+ if (udp_done != 0)
+ return;
+ else
+ udp_done = 1;
+#endif
+ mibvar = "net.inet.udp.pcblist";
+ break;
+ case IPPROTO_DIVERT:
+ mibvar = "net.inet.divert.pcblist";
+ break;
+ default:
+ mibvar = "net.inet.raw.pcblist";
+ break;
+ }
+ len = 0;
+ if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
+ if (errno != ENOENT)
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+ if ((buf = malloc(len)) == 0) {
+ warnx("malloc %lu bytes", (u_long)len);
+ return;
+ }
+ if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ free(buf);
+ return;
+ }
+
+ oxig = xig = (struct xinpgen *)buf;
+ for (xig = (struct xinpgen *)((char *)xig + xig->xig_len);
+ xig->xig_len > sizeof(struct xinpgen);
+ xig = (struct xinpgen *)((char *)xig + xig->xig_len)) {
+ if (istcp) {
+ tp = &((struct xtcpcb *)xig)->xt_tp;
+ inp = &((struct xtcpcb *)xig)->xt_inp;
+ so = &((struct xtcpcb *)xig)->xt_socket;
+ } else {
+ inp = &((struct xinpcb *)xig)->xi_inp;
+ so = &((struct xinpcb *)xig)->xi_socket;
+ }
+
+ /* Ignore sockets for protocols other than the desired one. */
+ if (so->xso_protocol != (int)proto)
+ continue;
+
+ /* Ignore PCBs which were freed during copyout. */
+ if (inp->inp_gencnt > oxig->xig_gen)
+ continue;
+
+ if ((af1 == AF_INET && (inp->inp_vflag & INP_IPV4) == 0)
+#ifdef INET6
+ || (af1 == AF_INET6 && (inp->inp_vflag & INP_IPV6) == 0)
+#endif /* INET6 */
+ || (af1 == AF_UNSPEC && ((inp->inp_vflag & INP_IPV4) == 0
+#ifdef INET6
+ && (inp->inp_vflag &
+ INP_IPV6) == 0
+#endif /* INET6 */
+ ))
+ )
+ continue;
+ if (!aflag &&
+ (
+ (istcp && tp->t_state == TCPS_LISTEN)
+ || (af1 == AF_INET &&
+ inet_lnaof(inp->inp_laddr) == INADDR_ANY)
+#ifdef INET6
+ || (af1 == AF_INET6 &&
+ IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
+#endif /* INET6 */
+ || (af1 == AF_UNSPEC &&
+ (((inp->inp_vflag & INP_IPV4) != 0 &&
+ inet_lnaof(inp->inp_laddr) == INADDR_ANY)
+#ifdef INET6
+ || ((inp->inp_vflag & INP_IPV6) != 0 &&
+ IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
+#endif
+ ))
+ ))
+ continue;
+
+ if (first) {
+ if (!Lflag) {
+ printf("Active Internet connections");
+ if (aflag)
+ printf(" (including servers)");
+ } else
+ printf(
+ "Current listen queue sizes (qlen/incqlen/maxqlen)");
+ putchar('\n');
+ if (Aflag)
+ printf("%-8.8s ", "Socket");
+ if (Lflag)
+ printf("%-5.5s %-14.14s %-22.22s\n",
+ "Proto", "Listen", "Local Address");
+ else
+ printf((Aflag && !Wflag) ?
+ "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" :
+ "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n",
+ "Proto", "Recv-Q", "Send-Q",
+ "Local Address", "Foreign Address",
+ "(state)");
+ first = 0;
+ }
+ if (Lflag && so->so_qlimit == 0)
+ continue;
+ if (Aflag) {
+ if (istcp)
+ printf("%8lx ", (u_long)inp->inp_ppcb);
+ else
+ printf("%8lx ", (u_long)so->so_pcb);
+ }
+#ifdef INET6
+ if ((inp->inp_vflag & INP_IPV6) != 0)
+ vchar = ((inp->inp_vflag & INP_IPV4) != 0)
+ ? "46" : "6 ";
+ else
+#endif
+ vchar = ((inp->inp_vflag & INP_IPV4) != 0)
+ ? "4 " : " ";
+ printf("%-3.3s%-2.2s ", name, vchar);
+ if (Lflag) {
+ char buf1[15];
+
+ snprintf(buf1, 15, "%d/%d/%d", so->so_qlen,
+ so->so_incqlen, so->so_qlimit);
+ printf("%-14.14s ", buf1);
+ } else {
+ printf("%6u %6u ",
+ so->so_rcv.sb_cc,
+ so->so_snd.sb_cc);
+ }
+ if (numeric_port) {
+ if (inp->inp_vflag & INP_IPV4) {
+ inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+ name, 1);
+ if (!Lflag)
+ inetprint(&inp->inp_faddr,
+ (int)inp->inp_fport, name, 1);
+ }
+#ifdef INET6
+ else if (inp->inp_vflag & INP_IPV6) {
+ inet6print(&inp->in6p_laddr,
+ (int)inp->inp_lport, name, 1);
+ if (!Lflag)
+ inet6print(&inp->in6p_faddr,
+ (int)inp->inp_fport, name, 1);
+ } /* else nothing printed now */
+#endif /* INET6 */
+ } else if (inp->inp_flags & INP_ANONPORT) {
+ if (inp->inp_vflag & INP_IPV4) {
+ inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+ name, 1);
+ if (!Lflag)
+ inetprint(&inp->inp_faddr,
+ (int)inp->inp_fport, name, 0);
+ }
+#ifdef INET6
+ else if (inp->inp_vflag & INP_IPV6) {
+ inet6print(&inp->in6p_laddr,
+ (int)inp->inp_lport, name, 1);
+ if (!Lflag)
+ inet6print(&inp->in6p_faddr,
+ (int)inp->inp_fport, name, 0);
+ } /* else nothing printed now */
+#endif /* INET6 */
+ } else {
+ if (inp->inp_vflag & INP_IPV4) {
+ inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+ name, 0);
+ if (!Lflag)
+ inetprint(&inp->inp_faddr,
+ (int)inp->inp_fport, name,
+ inp->inp_lport !=
+ inp->inp_fport);
+ }
+#ifdef INET6
+ else if (inp->inp_vflag & INP_IPV6) {
+ inet6print(&inp->in6p_laddr,
+ (int)inp->inp_lport, name, 0);
+ if (!Lflag)
+ inet6print(&inp->in6p_faddr,
+ (int)inp->inp_fport, name,
+ inp->inp_lport !=
+ inp->inp_fport);
+ } /* else nothing printed now */
+#endif /* INET6 */
+ }
+ if (istcp && !Lflag) {
+ if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES)
+ printf("%d", tp->t_state);
+ else {
+ printf("%s", tcpstates[tp->t_state]);
+#if defined(TF_NEEDSYN) && defined(TF_NEEDFIN)
+ /* Show T/TCP `hidden state' */
+ if (tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN))
+ putchar('*');
+#endif /* defined(TF_NEEDSYN) && defined(TF_NEEDFIN) */
+ }
+ }
+ putchar('\n');
+ }
+ if (xig != oxig && xig->xig_gen != oxig->xig_gen) {
+ if (oxig->xig_count > xig->xig_count) {
+ printf("Some %s sockets may have been deleted.\n",
+ name);
+ } else if (oxig->xig_count < xig->xig_count) {
+ printf("Some %s sockets may have been created.\n",
+ name);
+ } else {
+ printf("Some %s sockets may have been created or deleted.\n",
+ name);
+ }
+ }
+ free(buf);
+}
+
+/*
+ * Dump TCP statistics structure.
+ */
+void
+tcp_stats(u_long off __unused, const char *name, int af1 __unused)
+{
+ struct tcpstat tcpstat, zerostat;
+ size_t len = sizeof tcpstat;
+
+ if (zflag)
+ memset(&zerostat, 0, len);
+ if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len,
+ zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
+ warn("sysctl: net.inet.tcp.stats");
+ return;
+ }
+
+#ifdef INET6
+ if (tcp_done != 0)
+ return;
+ else
+ tcp_done = 1;
+#endif
+
+ printf ("%s:\n", name);
+
+#define p(f, m) if (tcpstat.f || sflag <= 1) \
+ printf(m, tcpstat.f, plural(tcpstat.f))
+#define p1a(f, m) if (tcpstat.f || sflag <= 1) \
+ printf(m, tcpstat.f)
+#define p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
+ printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2, plural(tcpstat.f2))
+#define p2a(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
+ printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2)
+#define p3(f, m) if (tcpstat.f || sflag <= 1) \
+ printf(m, tcpstat.f, plurales(tcpstat.f))
+
+ p(tcps_sndtotal, "\t%lu packet%s sent\n");
+ p2(tcps_sndpack,tcps_sndbyte,
+ "\t\t%lu data packet%s (%lu byte%s)\n");
+ p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
+ "\t\t%lu data packet%s (%lu byte%s) retransmitted\n");
+ p(tcps_sndrexmitbad,
+ "\t\t%lu data packet%s unnecessarily retransmitted\n");
+ p(tcps_mturesent, "\t\t%lu resend%s initiated by MTU discovery\n");
+ p2a(tcps_sndacks, tcps_delack,
+ "\t\t%lu ack-only packet%s (%lu delayed)\n");
+ p(tcps_sndurg, "\t\t%lu URG only packet%s\n");
+ p(tcps_sndprobe, "\t\t%lu window probe packet%s\n");
+ p(tcps_sndwinup, "\t\t%lu window update packet%s\n");
+ p(tcps_sndctrl, "\t\t%lu control packet%s\n");
+ p(tcps_rcvtotal, "\t%lu packet%s received\n");
+ p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%lu ack%s (for %lu byte%s)\n");
+ p(tcps_rcvdupack, "\t\t%lu duplicate ack%s\n");
+ p(tcps_rcvacktoomuch, "\t\t%lu ack%s for unsent data\n");
+ p2(tcps_rcvpack, tcps_rcvbyte,
+ "\t\t%lu packet%s (%lu byte%s) received in-sequence\n");
+ p2(tcps_rcvduppack, tcps_rcvdupbyte,
+ "\t\t%lu completely duplicate packet%s (%lu byte%s)\n");
+ p(tcps_pawsdrop, "\t\t%lu old duplicate packet%s\n");
+ p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
+ "\t\t%lu packet%s with some dup. data (%lu byte%s duped)\n");
+ p2(tcps_rcvoopack, tcps_rcvoobyte,
+ "\t\t%lu out-of-order packet%s (%lu byte%s)\n");
+ p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
+ "\t\t%lu packet%s (%lu byte%s) of data after window\n");
+ p(tcps_rcvwinprobe, "\t\t%lu window probe%s\n");
+ p(tcps_rcvwinupd, "\t\t%lu window update packet%s\n");
+ p(tcps_rcvafterclose, "\t\t%lu packet%s received after close\n");
+ p(tcps_rcvbadsum, "\t\t%lu discarded for bad checksum%s\n");
+ p(tcps_rcvbadoff, "\t\t%lu discarded for bad header offset field%s\n");
+ p1a(tcps_rcvshort, "\t\t%lu discarded because packet too short\n");
+ p(tcps_connattempt, "\t%lu connection request%s\n");
+ p(tcps_accepts, "\t%lu connection accept%s\n");
+ p(tcps_badsyn, "\t%lu bad connection attempt%s\n");
+ p(tcps_listendrop, "\t%lu listen queue overflow%s\n");
+ p(tcps_badrst, "\t%lu ignored RSTs in the window%s\n");
+ p(tcps_connects, "\t%lu connection%s established (including accepts)\n");
+ p2(tcps_closed, tcps_drops,
+ "\t%lu connection%s closed (including %lu drop%s)\n");
+ p(tcps_cachedrtt, "\t\t%lu connection%s updated cached RTT on close\n");
+ p(tcps_cachedrttvar,
+ "\t\t%lu connection%s updated cached RTT variance on close\n");
+ p(tcps_cachedssthresh,
+ "\t\t%lu connection%s updated cached ssthresh on close\n");
+ p(tcps_conndrops, "\t%lu embryonic connection%s dropped\n");
+ p2(tcps_rttupdated, tcps_segstimed,
+ "\t%lu segment%s updated rtt (of %lu attempt%s)\n");
+ p(tcps_rexmttimeo, "\t%lu retransmit timeout%s\n");
+ p(tcps_timeoutdrop, "\t\t%lu connection%s dropped by rexmit timeout\n");
+ p(tcps_persisttimeo, "\t%lu persist timeout%s\n");
+ p(tcps_persistdrop, "\t\t%lu connection%s dropped by persist timeout\n");
+ p(tcps_keeptimeo, "\t%lu keepalive timeout%s\n");
+ p(tcps_keepprobe, "\t\t%lu keepalive probe%s sent\n");
+ p(tcps_keepdrops, "\t\t%lu connection%s dropped by keepalive\n");
+ p(tcps_predack, "\t%lu correct ACK header prediction%s\n");
+ p(tcps_preddat, "\t%lu correct data packet header prediction%s\n");
+
+ p(tcps_sc_added, "\t%lu syncache entrie%s added\n");
+ p1a(tcps_sc_retransmitted, "\t\t%lu retransmitted\n");
+ p1a(tcps_sc_dupsyn, "\t\t%lu dupsyn\n");
+ p1a(tcps_sc_dropped, "\t\t%lu dropped\n");
+ p1a(tcps_sc_completed, "\t\t%lu completed\n");
+ p1a(tcps_sc_bucketoverflow, "\t\t%lu bucket overflow\n");
+ p1a(tcps_sc_cacheoverflow, "\t\t%lu cache overflow\n");
+ p1a(tcps_sc_reset, "\t\t%lu reset\n");
+ p1a(tcps_sc_stale, "\t\t%lu stale\n");
+ p1a(tcps_sc_aborted, "\t\t%lu aborted\n");
+ p1a(tcps_sc_badack, "\t\t%lu badack\n");
+ p1a(tcps_sc_unreach, "\t\t%lu unreach\n");
+ p(tcps_sc_zonefail, "\t\t%lu zone failure%s\n");
+ p(tcps_sc_sendcookie, "\t%lu cookie%s sent\n");
+ p(tcps_sc_recvcookie, "\t%lu cookie%s received\n");
+
+ p(tcps_sack_recovery_episode, "\t%lu SACK recovery episode%s\n");
+ p(tcps_sack_rexmits,
+ "\t%lu segment rexmit%s in SACK recovery episodes\n");
+ p(tcps_sack_rexmit_bytes,
+ "\t%lu byte rexmit%s in SACK recovery episodes\n");
+ p(tcps_sack_rcv_blocks,
+ "\t%lu SACK option%s (SACK blocks) received\n");
+ p(tcps_sack_send_blocks, "\t%lu SACK option%s (SACK blocks) sent\n");
+
+#undef p
+#undef p1a
+#undef p2
+#undef p2a
+#undef p3
+}
+
+/*
+ * Dump UDP statistics structure.
+ */
+void
+udp_stats(u_long off __unused, const char *name, int af1 __unused)
+{
+ struct udpstat udpstat, zerostat;
+ size_t len = sizeof udpstat;
+ u_long delivered;
+
+ if (zflag)
+ memset(&zerostat, 0, len);
+ if (sysctlbyname("net.inet.udp.stats", &udpstat, &len,
+ zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
+ warn("sysctl: net.inet.udp.stats");
+ return;
+ }
+
+#ifdef INET6
+ if (udp_done != 0)
+ return;
+ else
+ udp_done = 1;
+#endif
+
+ printf("%s:\n", name);
+#define p(f, m) if (udpstat.f || sflag <= 1) \
+ printf(m, udpstat.f, plural(udpstat.f))
+#define p1a(f, m) if (udpstat.f || sflag <= 1) \
+ printf(m, udpstat.f)
+ p(udps_ipackets, "\t%lu datagram%s received\n");
+ p1a(udps_hdrops, "\t%lu with incomplete header\n");
+ p1a(udps_badlen, "\t%lu with bad data length field\n");
+ p1a(udps_badsum, "\t%lu with bad checksum\n");
+ p1a(udps_nosum, "\t%lu with no checksum\n");
+ p1a(udps_noport, "\t%lu dropped due to no socket\n");
+ p(udps_noportbcast,
+ "\t%lu broadcast/multicast datagram%s dropped due to no socket\n");
+ p1a(udps_fullsock, "\t%lu dropped due to full socket buffers\n");
+ p1a(udpps_pcbhashmiss, "\t%lu not for hashed pcb\n");
+ delivered = udpstat.udps_ipackets -
+ udpstat.udps_hdrops -
+ udpstat.udps_badlen -
+ udpstat.udps_badsum -
+ udpstat.udps_noport -
+ udpstat.udps_noportbcast -
+ udpstat.udps_fullsock;
+ if (delivered || sflag <= 1)
+ printf("\t%lu delivered\n", delivered);
+ p(udps_opackets, "\t%lu datagram%s output\n");
+#undef p
+#undef p1a
+}
+
+/*
+ * Dump IP statistics structure.
+ */
+void
+ip_stats(u_long off __unused, const char *name, int af1 __unused)
+{
+ struct ipstat ipstat, zerostat;
+ size_t len = sizeof ipstat;
+
+ if (zflag)
+ memset(&zerostat, 0, len);
+ if (sysctlbyname("net.inet.ip.stats", &ipstat, &len,
+ zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
+ warn("sysctl: net.inet.ip.stats");
+ return;
+ }
+
+ printf("%s:\n", name);
+
+#define p(f, m) if (ipstat.f || sflag <= 1) \
+ printf(m, ipstat.f, plural(ipstat.f))
+#define p1a(f, m) if (ipstat.f || sflag <= 1) \
+ printf(m, ipstat.f)
+
+ p(ips_total, "\t%lu total packet%s received\n");
+ p(ips_badsum, "\t%lu bad header checksum%s\n");
+ p1a(ips_toosmall, "\t%lu with size smaller than minimum\n");
+ p1a(ips_tooshort, "\t%lu with data size < data length\n");
+ p1a(ips_toolong, "\t%lu with ip length > max ip packet size\n");
+ p1a(ips_badhlen, "\t%lu with header length < data size\n");
+ p1a(ips_badlen, "\t%lu with data length < header length\n");
+ p1a(ips_badoptions, "\t%lu with bad options\n");
+ p1a(ips_badvers, "\t%lu with incorrect version number\n");
+ p(ips_fragments, "\t%lu fragment%s received\n");
+ p(ips_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
+ p(ips_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
+ p(ips_reassembled, "\t%lu packet%s reassembled ok\n");
+ p(ips_delivered, "\t%lu packet%s for this host\n");
+ p(ips_noproto, "\t%lu packet%s for unknown/unsupported protocol\n");
+ p(ips_forward, "\t%lu packet%s forwarded");
+ p(ips_fastforward, " (%lu packet%s fast forwarded)");
+ if (ipstat.ips_forward || sflag <= 1)
+ putchar('\n');
+ p(ips_cantforward, "\t%lu packet%s not forwardable\n");
+ p(ips_notmember,
+ "\t%lu packet%s received for unknown multicast group\n");
+ p(ips_redirectsent, "\t%lu redirect%s sent\n");
+ p(ips_localout, "\t%lu packet%s sent from this host\n");
+ p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n");
+ p(ips_odropped,
+ "\t%lu output packet%s dropped due to no bufs, etc.\n");
+ p(ips_noroute, "\t%lu output packet%s discarded due to no route\n");
+ p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
+ p(ips_ofragments, "\t%lu fragment%s created\n");
+ p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
+ p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n");
+ p(ips_badaddr, "\t%lu datagram%s with bad address in header\n");
+#undef p
+#undef p1a
+}
+
+static const char *icmpnames[] = {
+ "echo reply",
+ "#1",
+ "#2",
+ "destination unreachable",
+ "source quench",
+ "routing redirect",
+ "#6",
+ "#7",
+ "echo",
+ "router advertisement",
+ "router solicitation",
+ "time exceeded",
+ "parameter problem",
+ "time stamp",
+ "time stamp reply",
+ "information request",
+ "information request reply",
+ "address mask request",
+ "address mask reply",
+};
+
+/*
+ * Dump ICMP statistics.
+ */
+void
+icmp_stats(u_long off __unused, const char *name, int af1 __unused)
+{
+ struct icmpstat icmpstat, zerostat;
+ int i, first;
+ int mib[4]; /* CTL_NET + PF_INET + IPPROTO_ICMP + req */
+ size_t len;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET;
+ mib[2] = IPPROTO_ICMP;
+ mib[3] = ICMPCTL_STATS;
+
+ len = sizeof icmpstat;
+ if (zflag)
+ memset(&zerostat, 0, len);
+ if (sysctl(mib, 4, &icmpstat, &len,
+ zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
+ warn("sysctl: net.inet.icmp.stats");
+ return;
+ }
+
+ printf("%s:\n", name);
+
+#define p(f, m) if (icmpstat.f || sflag <= 1) \
+ printf(m, icmpstat.f, plural(icmpstat.f))
+#define p1a(f, m) if (icmpstat.f || sflag <= 1) \
+ printf(m, icmpstat.f)
+#define p2(f, m) if (icmpstat.f || sflag <= 1) \
+ printf(m, icmpstat.f, plurales(icmpstat.f))
+
+ p(icps_error, "\t%lu call%s to icmp_error\n");
+ p(icps_oldicmp,
+ "\t%lu error%s not generated in response to an icmp message\n");
+ for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
+ if (icmpstat.icps_outhist[i] != 0) {
+ if (first) {
+ printf("\tOutput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %lu\n", icmpnames[i],
+ icmpstat.icps_outhist[i]);
+ }
+ p(icps_badcode, "\t%lu message%s with bad code fields\n");
+ p(icps_tooshort, "\t%lu message%s < minimum length\n");
+ p(icps_checksum, "\t%lu bad checksum%s\n");
+ p(icps_badlen, "\t%lu message%s with bad length\n");
+ p1a(icps_bmcastecho, "\t%lu multicast echo requests ignored\n");
+ p1a(icps_bmcasttstamp, "\t%lu multicast timestamp requests ignored\n");
+ for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
+ if (icmpstat.icps_inhist[i] != 0) {
+ if (first) {
+ printf("\tInput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %lu\n", icmpnames[i],
+ icmpstat.icps_inhist[i]);
+ }
+ p(icps_reflect, "\t%lu message response%s generated\n");
+ p2(icps_badaddr, "\t%lu invalid return address%s\n");
+ p(icps_noroute, "\t%lu no return route%s\n");
+#undef p
+#undef p1a
+#undef p2
+ mib[3] = ICMPCTL_MASKREPL;
+ len = sizeof i;
+ if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0)
+ return;
+ printf("\tICMP address mask responses are %sabled\n",
+ i ? "en" : "dis");
+}
+
+/*
+ * Dump IGMP statistics structure.
+ */
+void
+igmp_stats(u_long off __unused, const char *name, int af1 __unused)
+{
+ struct igmpstat igmpstat, zerostat;
+ size_t len = sizeof igmpstat;
+
+ if (zflag)
+ memset(&zerostat, 0, len);
+ if (sysctlbyname("net.inet.igmp.stats", &igmpstat, &len,
+ zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
+ warn("sysctl: net.inet.igmp.stats");
+ return;
+ }
+
+ printf("%s:\n", name);
+
+#define p(f, m) if (igmpstat.f || sflag <= 1) \
+ printf(m, igmpstat.f, plural(igmpstat.f))
+#define py(f, m) if (igmpstat.f || sflag <= 1) \
+ printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
+ p(igps_rcv_total, "\t%u message%s received\n");
+ p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n");
+ p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n");
+ py(igps_rcv_queries, "\t%u membership quer%s received\n");
+ py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n");
+ p(igps_rcv_reports, "\t%u membership report%s received\n");
+ p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n");
+ p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n");
+ p(igps_snd_reports, "\t%u membership report%s sent\n");
+#undef p
+#undef py
+}
+
+/*
+ * Dump PIM statistics structure.
+ */
+void
+pim_stats(u_long off __unused, const char *name, int af1 __unused)
+{
+ struct pimstat pimstat, zerostat;
+ size_t len = sizeof pimstat;
+
+ if (zflag)
+ memset(&zerostat, 0, len);
+ if (sysctlbyname("net.inet.pim.stats", &pimstat, &len,
+ zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
+ if (errno != ENOENT)
+ warn("sysctl: net.inet.pim.stats");
+ return;
+ }
+
+ printf("%s:\n", name);
+
+#define p(f, m) if (pimstat.f || sflag <= 1) \
+ printf(m, pimstat.f, plural(pimstat.f))
+#define py(f, m) if (pimstat.f || sflag <= 1) \
+ printf(m, pimstat.f, pimstat.f != 1 ? "ies" : "y")
+ p(pims_rcv_total_msgs, "\t%llu message%s received\n");
+ p(pims_rcv_total_bytes, "\t%llu byte%s received\n");
+ p(pims_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
+ p(pims_rcv_badsum, "\t%llu message%s received with bad checksum\n");
+ p(pims_rcv_badversion, "\t%llu message%s received with bad version\n");
+ p(pims_rcv_registers_msgs, "\t%llu data register message%s received\n");
+ p(pims_rcv_registers_bytes, "\t%llu data register byte%s received\n");
+ p(pims_rcv_registers_wrongiif, "\t%llu data register message%s received on wrong iif\n");
+ p(pims_rcv_badregisters, "\t%llu bad register%s received\n");
+ p(pims_snd_registers_msgs, "\t%llu data register message%s sent\n");
+ p(pims_snd_registers_bytes, "\t%llu data register byte%s sent\n");
+#undef p
+#undef py
+}
+
+/*
+ * Pretty print an Internet address (net address + port).
+ */
+void
+inetprint(struct in_addr *in, int port, const char *proto, int num_port)
+{
+ struct servent *sp = 0;
+ char line[80], *cp;
+ int width;
+
+ if (Wflag)
+ sprintf(line, "%s.", inetname(in));
+ else
+ sprintf(line, "%.*s.", (Aflag && !num_port) ? 12 : 16, inetname(in));
+ cp = index(line, '\0');
+ if (!num_port && port)
+ sp = getservbyport((int)port, proto);
+ if (sp || port == 0)
+ sprintf(cp, "%.15s ", sp ? sp->s_name : "*");
+ else
+ sprintf(cp, "%d ", ntohs((u_short)port));
+ width = (Aflag && !Wflag) ? 18 : 22;
+ if (Wflag)
+ printf("%-*s ", width, line);
+ else
+ printf("%-*.*s ", width, width, line);
+}
+
+/*
+ * Construct an Internet address representation.
+ * If numeric_addr has been supplied, give
+ * numeric value, otherwise try for symbolic name.
+ */
+char *
+inetname(struct in_addr *inp)
+{
+ char *cp;
+ static char line[MAXHOSTNAMELEN];
+ struct hostent *hp;
+ struct netent *np;
+
+ cp = 0;
+ if (!numeric_addr && inp->s_addr != INADDR_ANY) {
+ int net = inet_netof(*inp);
+ int lna = inet_lnaof(*inp);
+
+ if (lna == INADDR_ANY) {
+ np = getnetbyaddr(net, AF_INET);
+ if (np)
+ cp = np->n_name;
+ }
+ if (cp == 0) {
+ hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
+ if (hp) {
+ cp = hp->h_name;
+ trimdomain(cp, strlen(cp));
+ }
+ }
+ }
+ if (inp->s_addr == INADDR_ANY)
+ strcpy(line, "*");
+ else if (cp) {
+ strncpy(line, cp, sizeof(line) - 1);
+ line[sizeof(line) - 1] = '\0';
+ } else {
+ inp->s_addr = ntohl(inp->s_addr);
+#define C(x) ((u_int)((x) & 0xff))
+ sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24),
+ C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
+ }
+ return (line);
+}
diff --git a/usr.bin/netstat/inet6.c b/usr.bin/netstat/inet6.c
new file mode 100644
index 000000000000..984f525dd536
--- /dev/null
+++ b/usr.bin/netstat/inet6.c
@@ -0,0 +1,1137 @@
+/* BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp */
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)inet6.c 8.4 (Berkeley) 4/20/94";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef INET6
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/ioctl.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/sysctl.h>
+
+#include <net/route.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <netinet/in_systm.h>
+#include <netinet6/in6_pcb.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/pim6_var.h>
+#include <netinet6/raw_ip6.h>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+
+struct socket sockb;
+
+char *inet6name(struct in6_addr *);
+const char *pluralies(int);
+
+static char ntop_buf[INET6_ADDRSTRLEN];
+
+static const char *ip6nh[] = {
+ "hop by hop",
+ "ICMP",
+ "IGMP",
+ "#3",
+ "IP",
+ "#5",
+ "TCP",
+ "#7",
+ "#8",
+ "#9",
+ "#10",
+ "#11",
+ "#12",
+ "#13",
+ "#14",
+ "#15",
+ "#16",
+ "UDP",
+ "#18",
+ "#19",
+ "#20",
+ "#21",
+ "IDP",
+ "#23",
+ "#24",
+ "#25",
+ "#26",
+ "#27",
+ "#28",
+ "TP",
+ "#30",
+ "#31",
+ "#32",
+ "#33",
+ "#34",
+ "#35",
+ "#36",
+ "#37",
+ "#38",
+ "#39",
+ "#40",
+ "IP6",
+ "#42",
+ "routing",
+ "fragment",
+ "#45",
+ "#46",
+ "#47",
+ "#48",
+ "#49",
+ "ESP",
+ "AH",
+ "#52",
+ "#53",
+ "#54",
+ "#55",
+ "#56",
+ "#57",
+ "ICMP6",
+ "no next header",
+ "destination option",
+ "#61",
+ "mobility",
+ "#63",
+ "#64",
+ "#65",
+ "#66",
+ "#67",
+ "#68",
+ "#69",
+ "#70",
+ "#71",
+ "#72",
+ "#73",
+ "#74",
+ "#75",
+ "#76",
+ "#77",
+ "#78",
+ "#79",
+ "ISOIP",
+ "#81",
+ "#82",
+ "#83",
+ "#84",
+ "#85",
+ "#86",
+ "#87",
+ "#88",
+ "OSPF",
+ "#80",
+ "#91",
+ "#92",
+ "#93",
+ "#94",
+ "#95",
+ "#96",
+ "Ethernet",
+ "#98",
+ "#99",
+ "#100",
+ "#101",
+ "#102",
+ "PIM",
+ "#104",
+ "#105",
+ "#106",
+ "#107",
+ "#108",
+ "#109",
+ "#110",
+ "#111",
+ "#112",
+ "#113",
+ "#114",
+ "#115",
+ "#116",
+ "#117",
+ "#118",
+ "#119",
+ "#120",
+ "#121",
+ "#122",
+ "#123",
+ "#124",
+ "#125",
+ "#126",
+ "#127",
+ "#128",
+ "#129",
+ "#130",
+ "#131",
+ "#132",
+ "#133",
+ "#134",
+ "#135",
+ "#136",
+ "#137",
+ "#138",
+ "#139",
+ "#140",
+ "#141",
+ "#142",
+ "#143",
+ "#144",
+ "#145",
+ "#146",
+ "#147",
+ "#148",
+ "#149",
+ "#150",
+ "#151",
+ "#152",
+ "#153",
+ "#154",
+ "#155",
+ "#156",
+ "#157",
+ "#158",
+ "#159",
+ "#160",
+ "#161",
+ "#162",
+ "#163",
+ "#164",
+ "#165",
+ "#166",
+ "#167",
+ "#168",
+ "#169",
+ "#170",
+ "#171",
+ "#172",
+ "#173",
+ "#174",
+ "#175",
+ "#176",
+ "#177",
+ "#178",
+ "#179",
+ "#180",
+ "#181",
+ "#182",
+ "#183",
+ "#184",
+ "#185",
+ "#186",
+ "#187",
+ "#188",
+ "#189",
+ "#180",
+ "#191",
+ "#192",
+ "#193",
+ "#194",
+ "#195",
+ "#196",
+ "#197",
+ "#198",
+ "#199",
+ "#200",
+ "#201",
+ "#202",
+ "#203",
+ "#204",
+ "#205",
+ "#206",
+ "#207",
+ "#208",
+ "#209",
+ "#210",
+ "#211",
+ "#212",
+ "#213",
+ "#214",
+ "#215",
+ "#216",
+ "#217",
+ "#218",
+ "#219",
+ "#220",
+ "#221",
+ "#222",
+ "#223",
+ "#224",
+ "#225",
+ "#226",
+ "#227",
+ "#228",
+ "#229",
+ "#230",
+ "#231",
+ "#232",
+ "#233",
+ "#234",
+ "#235",
+ "#236",
+ "#237",
+ "#238",
+ "#239",
+ "#240",
+ "#241",
+ "#242",
+ "#243",
+ "#244",
+ "#245",
+ "#246",
+ "#247",
+ "#248",
+ "#249",
+ "#250",
+ "#251",
+ "#252",
+ "#253",
+ "#254",
+ "#255",
+};
+
+static char *srcrule_str[] = {
+ "first candidate",
+ "same address",
+ "appropriate scope",
+ "deprecated address",
+ "home address",
+ "outgoing interface",
+ "matching label",
+ "public/temporary address",
+ "alive interface",
+ "preferred interface",
+ "rule #10",
+ "rule #11",
+ "rule #12",
+ "rule #13",
+ "longest match",
+ "rule #15",
+};
+
+/*
+ * Dump IP6 statistics structure.
+ */
+void
+ip6_stats(u_long off __unused, const char *name, int af1 __unused)
+{
+ struct ip6stat ip6stat;
+ int first, i;
+ int mib[4];
+ size_t len;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET6;
+ mib[2] = IPPROTO_IPV6;
+ mib[3] = IPV6CTL_STATS;
+
+ len = sizeof ip6stat;
+ memset(&ip6stat, 0, len);
+ if (sysctl(mib, 4, &ip6stat, &len, (void *)0, 0) < 0)
+ return;
+ printf("%s:\n", name);
+
+#define p(f, m) if (ip6stat.f || sflag <= 1) \
+ printf(m, (unsigned long long)ip6stat.f, plural(ip6stat.f))
+#define p1a(f, m) if (ip6stat.f || sflag <= 1) \
+ printf(m, (unsigned long long)ip6stat.f)
+
+ p(ip6s_total, "\t%llu total packet%s received\n");
+ p1a(ip6s_toosmall, "\t%llu with size smaller than minimum\n");
+ p1a(ip6s_tooshort, "\t%llu with data size < data length\n");
+ p1a(ip6s_badoptions, "\t%llu with bad options\n");
+ p1a(ip6s_badvers, "\t%llu with incorrect version number\n");
+ p(ip6s_fragments, "\t%llu fragment%s received\n");
+ p(ip6s_fragdropped, "\t%llu fragment%s dropped (dup or out of space)\n");
+ p(ip6s_fragtimeout, "\t%llu fragment%s dropped after timeout\n");
+ p(ip6s_fragoverflow, "\t%llu fragment%s that exceeded limit\n");
+ p(ip6s_reassembled, "\t%llu packet%s reassembled ok\n");
+ p(ip6s_delivered, "\t%llu packet%s for this host\n");
+ p(ip6s_forward, "\t%llu packet%s forwarded\n");
+ p(ip6s_cantforward, "\t%llu packet%s not forwardable\n");
+ p(ip6s_redirectsent, "\t%llu redirect%s sent\n");
+ p(ip6s_localout, "\t%llu packet%s sent from this host\n");
+ p(ip6s_rawout, "\t%llu packet%s sent with fabricated ip header\n");
+ p(ip6s_odropped, "\t%llu output packet%s dropped due to no bufs, etc.\n");
+ p(ip6s_noroute, "\t%llu output packet%s discarded due to no route\n");
+ p(ip6s_fragmented, "\t%llu output datagram%s fragmented\n");
+ p(ip6s_ofragments, "\t%llu fragment%s created\n");
+ p(ip6s_cantfrag, "\t%llu datagram%s that can't be fragmented\n");
+ p(ip6s_badscope, "\t%llu packet%s that violated scope rules\n");
+ p(ip6s_notmember, "\t%llu multicast packet%s which we don't join\n");
+ for (first = 1, i = 0; i < 256; i++)
+ if (ip6stat.ip6s_nxthist[i] != 0) {
+ if (first) {
+ printf("\tInput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %llu\n", ip6nh[i],
+ (unsigned long long)ip6stat.ip6s_nxthist[i]);
+ }
+ printf("\tMbuf statistics:\n");
+ printf("\t\t%llu one mbuf\n", (unsigned long long)ip6stat.ip6s_m1);
+ for (first = 1, i = 0; i < 32; i++) {
+ char ifbuf[IFNAMSIZ];
+ if (ip6stat.ip6s_m2m[i] != 0) {
+ if (first) {
+ printf("\t\ttwo or more mbuf:\n");
+ first = 0;
+ }
+ printf("\t\t\t%s= %llu\n",
+ if_indextoname(i, ifbuf),
+ (unsigned long long)ip6stat.ip6s_m2m[i]);
+ }
+ }
+ printf("\t\t%llu one ext mbuf\n",
+ (unsigned long long)ip6stat.ip6s_mext1);
+ printf("\t\t%llu two or more ext mbuf\n",
+ (unsigned long long)ip6stat.ip6s_mext2m);
+ p(ip6s_exthdrtoolong,
+ "\t%llu packet%s whose headers are not continuous\n");
+ p(ip6s_nogif, "\t%llu tunneling packet%s that can't find gif\n");
+ p(ip6s_toomanyhdr,
+ "\t%llu packet%s discarded because of too many headers\n");
+
+ /* for debugging source address selection */
+#define PRINT_SCOPESTAT(s,i) do {\
+ switch(i) { /* XXX hardcoding in each case */\
+ case 1:\
+ p(s, "\t\t%llu node-local%s\n");\
+ break;\
+ case 2:\
+ p(s,"\t\t%llu link-local%s\n");\
+ break;\
+ case 5:\
+ p(s,"\t\t%llu site-local%s\n");\
+ break;\
+ case 14:\
+ p(s,"\t\t%llu global%s\n");\
+ break;\
+ default:\
+ printf("\t\t%llu addresses scope=%x\n",\
+ (unsigned long long)ip6stat.s, i);\
+ }\
+ } while (0);
+
+ p(ip6s_sources_none,
+ "\t%llu failure%s of source address selection\n");
+ for (first = 1, i = 0; i < 16; i++) {
+ if (ip6stat.ip6s_sources_sameif[i]) {
+ if (first) {
+ printf("\tsource addresses on an outgoing I/F\n");
+ first = 0;
+ }
+ PRINT_SCOPESTAT(ip6s_sources_sameif[i], i);
+ }
+ }
+ for (first = 1, i = 0; i < 16; i++) {
+ if (ip6stat.ip6s_sources_otherif[i]) {
+ if (first) {
+ printf("\tsource addresses on a non-outgoing I/F\n");
+ first = 0;
+ }
+ PRINT_SCOPESTAT(ip6s_sources_otherif[i], i);
+ }
+ }
+ for (first = 1, i = 0; i < 16; i++) {
+ if (ip6stat.ip6s_sources_samescope[i]) {
+ if (first) {
+ printf("\tsource addresses of same scope\n");
+ first = 0;
+ }
+ PRINT_SCOPESTAT(ip6s_sources_samescope[i], i);
+ }
+ }
+ for (first = 1, i = 0; i < 16; i++) {
+ if (ip6stat.ip6s_sources_otherscope[i]) {
+ if (first) {
+ printf("\tsource addresses of a different scope\n");
+ first = 0;
+ }
+ PRINT_SCOPESTAT(ip6s_sources_otherscope[i], i);
+ }
+ }
+ for (first = 1, i = 0; i < 16; i++) {
+ if (ip6stat.ip6s_sources_deprecated[i]) {
+ if (first) {
+ printf("\tdeprecated source addresses\n");
+ first = 0;
+ }
+ PRINT_SCOPESTAT(ip6s_sources_deprecated[i], i);
+ }
+ }
+
+ p1a(ip6s_forward_cachehit, "\t%llu forward cache hit\n");
+ p1a(ip6s_forward_cachemiss, "\t%llu forward cache miss\n");
+ printf("\tSource addresses selection rule applied:\n");
+ for (i = 0; i < 16; i++) {
+ if (ip6stat.ip6s_sources_rule[i])
+ printf("\t\t%llu %s\n", ip6stat.ip6s_sources_rule[i],
+ srcrule_str[i]);
+ }
+#undef p
+#undef p1a
+}
+
+/*
+ * Dump IPv6 per-interface statistics based on RFC 2465.
+ */
+void
+ip6_ifstats(char *ifname)
+{
+ struct in6_ifreq ifr;
+ int s;
+#define p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
+ printf(m, (unsigned long long)ifr.ifr_ifru.ifru_stat.f, plural(ifr.ifr_ifru.ifru_stat.f))
+#define p_5(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
+ printf(m, (unsigned long long)ip6stat.f)
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("Warning: socket(AF_INET6)");
+ return;
+ }
+
+ strcpy(ifr.ifr_name, ifname);
+ printf("ip6 on %s:\n", ifr.ifr_name);
+
+ if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) {
+ perror("Warning: ioctl(SIOCGIFSTAT_IN6)");
+ goto end;
+ }
+
+ p(ifs6_in_receive, "\t%llu total input datagram%s\n");
+ p(ifs6_in_hdrerr, "\t%llu datagram%s with invalid header received\n");
+ p(ifs6_in_toobig, "\t%llu datagram%s exceeded MTU received\n");
+ p(ifs6_in_noroute, "\t%llu datagram%s with no route received\n");
+ p(ifs6_in_addrerr, "\t%llu datagram%s with invalid dst received\n");
+ p(ifs6_in_protounknown, "\t%llu datagram%s with unknown proto received\n");
+ p(ifs6_in_truncated, "\t%llu truncated datagram%s received\n");
+ p(ifs6_in_discard, "\t%llu input datagram%s discarded\n");
+ p(ifs6_in_deliver,
+ "\t%llu datagram%s delivered to an upper layer protocol\n");
+ p(ifs6_out_forward, "\t%llu datagram%s forwarded to this interface\n");
+ p(ifs6_out_request,
+ "\t%llu datagram%s sent from an upper layer protocol\n");
+ p(ifs6_out_discard, "\t%llu total discarded output datagram%s\n");
+ p(ifs6_out_fragok, "\t%llu output datagram%s fragmented\n");
+ p(ifs6_out_fragfail, "\t%llu output datagram%s failed on fragment\n");
+ p(ifs6_out_fragcreat, "\t%llu output datagram%s succeeded on fragment\n");
+ p(ifs6_reass_reqd, "\t%llu incoming datagram%s fragmented\n");
+ p(ifs6_reass_ok, "\t%llu datagram%s reassembled\n");
+ p(ifs6_reass_fail, "\t%llu datagram%s failed on reassembly\n");
+ p(ifs6_in_mcast, "\t%llu multicast datagram%s received\n");
+ p(ifs6_out_mcast, "\t%llu multicast datagram%s sent\n");
+
+ end:
+ close(s);
+
+#undef p
+#undef p_5
+}
+
+static const char *icmp6names[] = {
+ "#0",
+ "unreach",
+ "packet too big",
+ "time exceed",
+ "parameter problem",
+ "#5",
+ "#6",
+ "#7",
+ "#8",
+ "#9",
+ "#10",
+ "#11",
+ "#12",
+ "#13",
+ "#14",
+ "#15",
+ "#16",
+ "#17",
+ "#18",
+ "#19",
+ "#20",
+ "#21",
+ "#22",
+ "#23",
+ "#24",
+ "#25",
+ "#26",
+ "#27",
+ "#28",
+ "#29",
+ "#30",
+ "#31",
+ "#32",
+ "#33",
+ "#34",
+ "#35",
+ "#36",
+ "#37",
+ "#38",
+ "#39",
+ "#40",
+ "#41",
+ "#42",
+ "#43",
+ "#44",
+ "#45",
+ "#46",
+ "#47",
+ "#48",
+ "#49",
+ "#50",
+ "#51",
+ "#52",
+ "#53",
+ "#54",
+ "#55",
+ "#56",
+ "#57",
+ "#58",
+ "#59",
+ "#60",
+ "#61",
+ "#62",
+ "#63",
+ "#64",
+ "#65",
+ "#66",
+ "#67",
+ "#68",
+ "#69",
+ "#70",
+ "#71",
+ "#72",
+ "#73",
+ "#74",
+ "#75",
+ "#76",
+ "#77",
+ "#78",
+ "#79",
+ "#80",
+ "#81",
+ "#82",
+ "#83",
+ "#84",
+ "#85",
+ "#86",
+ "#87",
+ "#88",
+ "#89",
+ "#80",
+ "#91",
+ "#92",
+ "#93",
+ "#94",
+ "#95",
+ "#96",
+ "#97",
+ "#98",
+ "#99",
+ "#100",
+ "#101",
+ "#102",
+ "#103",
+ "#104",
+ "#105",
+ "#106",
+ "#107",
+ "#108",
+ "#109",
+ "#110",
+ "#111",
+ "#112",
+ "#113",
+ "#114",
+ "#115",
+ "#116",
+ "#117",
+ "#118",
+ "#119",
+ "#120",
+ "#121",
+ "#122",
+ "#123",
+ "#124",
+ "#125",
+ "#126",
+ "#127",
+ "echo",
+ "echo reply",
+ "multicast listener query",
+ "multicast listener report",
+ "multicast listener done",
+ "router solicitation",
+ "router advertisement",
+ "neighbor solicitation",
+ "neighbor advertisement",
+ "redirect",
+ "router renumbering",
+ "node information request",
+ "node information reply",
+ "inverse neighbor solicitation",
+ "inverse neighbor advertisement",
+ "#143",
+ "#144",
+ "#145",
+ "#146",
+ "#147",
+ "#148",
+ "#149",
+ "#150",
+ "#151",
+ "#152",
+ "#153",
+ "#154",
+ "#155",
+ "#156",
+ "#157",
+ "#158",
+ "#159",
+ "#160",
+ "#161",
+ "#162",
+ "#163",
+ "#164",
+ "#165",
+ "#166",
+ "#167",
+ "#168",
+ "#169",
+ "#170",
+ "#171",
+ "#172",
+ "#173",
+ "#174",
+ "#175",
+ "#176",
+ "#177",
+ "#178",
+ "#179",
+ "#180",
+ "#181",
+ "#182",
+ "#183",
+ "#184",
+ "#185",
+ "#186",
+ "#187",
+ "#188",
+ "#189",
+ "#180",
+ "#191",
+ "#192",
+ "#193",
+ "#194",
+ "#195",
+ "#196",
+ "#197",
+ "#198",
+ "#199",
+ "#200",
+ "#201",
+ "#202",
+ "#203",
+ "#204",
+ "#205",
+ "#206",
+ "#207",
+ "#208",
+ "#209",
+ "#210",
+ "#211",
+ "#212",
+ "#213",
+ "#214",
+ "#215",
+ "#216",
+ "#217",
+ "#218",
+ "#219",
+ "#220",
+ "#221",
+ "#222",
+ "#223",
+ "#224",
+ "#225",
+ "#226",
+ "#227",
+ "#228",
+ "#229",
+ "#230",
+ "#231",
+ "#232",
+ "#233",
+ "#234",
+ "#235",
+ "#236",
+ "#237",
+ "#238",
+ "#239",
+ "#240",
+ "#241",
+ "#242",
+ "#243",
+ "#244",
+ "#245",
+ "#246",
+ "#247",
+ "#248",
+ "#249",
+ "#250",
+ "#251",
+ "#252",
+ "#253",
+ "#254",
+ "#255",
+};
+
+/*
+ * Dump ICMP6 statistics.
+ */
+void
+icmp6_stats(u_long off __unused, const char *name, int af1 __unused)
+{
+ struct icmp6stat icmp6stat;
+ int i, first;
+ int mib[4];
+ size_t len;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET6;
+ mib[2] = IPPROTO_ICMPV6;
+ mib[3] = ICMPV6CTL_STATS;
+
+ len = sizeof icmp6stat;
+ memset(&icmp6stat, 0, len);
+ if (sysctl(mib, 4, &icmp6stat, &len, (void *)0, 0) < 0)
+ return;
+ printf("%s:\n", name);
+
+#define p(f, m) if (icmp6stat.f || sflag <= 1) \
+ printf(m, (unsigned long long)icmp6stat.f, plural(icmp6stat.f))
+#define p_5(f, m) printf(m, (unsigned long long)icmp6stat.f)
+
+ p(icp6s_error, "\t%llu call%s to icmp6_error\n");
+ p(icp6s_canterror,
+ "\t%llu error%s not generated in response to an icmp6 message\n");
+ p(icp6s_toofreq,
+ "\t%llu error%s not generated because of rate limitation\n");
+#define NELEM (int)(sizeof(icmp6stat.icp6s_outhist)/sizeof(icmp6stat.icp6s_outhist[0]))
+ for (first = 1, i = 0; i < NELEM; i++)
+ if (icmp6stat.icp6s_outhist[i] != 0) {
+ if (first) {
+ printf("\tOutput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %llu\n", icmp6names[i],
+ (unsigned long long)icmp6stat.icp6s_outhist[i]);
+ }
+#undef NELEM
+ p(icp6s_badcode, "\t%llu message%s with bad code fields\n");
+ p(icp6s_tooshort, "\t%llu message%s < minimum length\n");
+ p(icp6s_checksum, "\t%llu bad checksum%s\n");
+ p(icp6s_badlen, "\t%llu message%s with bad length\n");
+#define NELEM (int)(sizeof(icmp6stat.icp6s_inhist)/sizeof(icmp6stat.icp6s_inhist[0]))
+ for (first = 1, i = 0; i < NELEM; i++)
+ if (icmp6stat.icp6s_inhist[i] != 0) {
+ if (first) {
+ printf("\tInput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %llu\n", icmp6names[i],
+ (unsigned long long)icmp6stat.icp6s_inhist[i]);
+ }
+#undef NELEM
+ printf("\tHistogram of error messages to be generated:\n");
+ p_5(icp6s_odst_unreach_noroute, "\t\t%llu no route\n");
+ p_5(icp6s_odst_unreach_admin, "\t\t%llu administratively prohibited\n");
+ p_5(icp6s_odst_unreach_beyondscope, "\t\t%llu beyond scope\n");
+ p_5(icp6s_odst_unreach_addr, "\t\t%llu address unreachable\n");
+ p_5(icp6s_odst_unreach_noport, "\t\t%llu port unreachable\n");
+ p_5(icp6s_opacket_too_big, "\t\t%llu packet too big\n");
+ p_5(icp6s_otime_exceed_transit, "\t\t%llu time exceed transit\n");
+ p_5(icp6s_otime_exceed_reassembly, "\t\t%llu time exceed reassembly\n");
+ p_5(icp6s_oparamprob_header, "\t\t%llu erroneous header field\n");
+ p_5(icp6s_oparamprob_nextheader, "\t\t%llu unrecognized next header\n");
+ p_5(icp6s_oparamprob_option, "\t\t%llu unrecognized option\n");
+ p_5(icp6s_oredirect, "\t\t%llu redirect\n");
+ p_5(icp6s_ounknown, "\t\t%llu unknown\n");
+
+ p(icp6s_reflect, "\t%llu message response%s generated\n");
+ p(icp6s_nd_toomanyopt, "\t%llu message%s with too many ND options\n");
+ p(icp6s_nd_badopt, "\t%llu message%s with bad ND options\n");
+ p(icp6s_badns, "\t%llu bad neighbor solicitation message%s\n");
+ p(icp6s_badna, "\t%llu bad neighbor advertisement message%s\n");
+ p(icp6s_badrs, "\t%llu bad router solicitation message%s\n");
+ p(icp6s_badra, "\t%llu bad router advertisement message%s\n");
+ p(icp6s_badredirect, "\t%llu bad redirect message%s\n");
+ p(icp6s_pmtuchg, "\t%llu path MTU change%s\n");
+#undef p
+#undef p_5
+}
+
+/*
+ * Dump ICMPv6 per-interface statistics based on RFC 2466.
+ */
+void
+icmp6_ifstats(char *ifname)
+{
+ struct in6_ifreq ifr;
+ int s;
+#define p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
+ printf(m, (unsigned long long)ifr.ifr_ifru.ifru_icmp6stat.f, plural(ifr.ifr_ifru.ifru_icmp6stat.f))
+#define p2(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
+ printf(m, (unsigned long long)ifr.ifr_ifru.ifru_icmp6stat.f, pluralies(ifr.ifr_ifru.ifru_icmp6stat.f))
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("Warning: socket(AF_INET6)");
+ return;
+ }
+
+ strcpy(ifr.ifr_name, ifname);
+ printf("icmp6 on %s:\n", ifr.ifr_name);
+
+ if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) {
+ perror("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
+ goto end;
+ }
+
+ p(ifs6_in_msg, "\t%llu total input message%s\n");
+ p(ifs6_in_error, "\t%llu total input error message%s\n");
+ p(ifs6_in_dstunreach, "\t%llu input destination unreachable error%s\n");
+ p(ifs6_in_adminprohib, "\t%llu input administratively prohibited error%s\n");
+ p(ifs6_in_timeexceed, "\t%llu input time exceeded error%s\n");
+ p(ifs6_in_paramprob, "\t%llu input parameter problem error%s\n");
+ p(ifs6_in_pkttoobig, "\t%llu input packet too big error%s\n");
+ p(ifs6_in_echo, "\t%llu input echo request%s\n");
+ p2(ifs6_in_echoreply, "\t%llu input echo repl%s\n");
+ p(ifs6_in_routersolicit, "\t%llu input router solicitation%s\n");
+ p(ifs6_in_routeradvert, "\t%llu input router advertisement%s\n");
+ p(ifs6_in_neighborsolicit, "\t%llu input neighbor solicitation%s\n");
+ p(ifs6_in_neighboradvert, "\t%llu input neighbor advertisement%s\n");
+ p(ifs6_in_redirect, "\t%llu input redirect%s\n");
+ p2(ifs6_in_mldquery, "\t%llu input MLD quer%s\n");
+ p(ifs6_in_mldreport, "\t%llu input MLD report%s\n");
+ p(ifs6_in_mlddone, "\t%llu input MLD done%s\n");
+
+ p(ifs6_out_msg, "\t%llu total output message%s\n");
+ p(ifs6_out_error, "\t%llu total output error message%s\n");
+ p(ifs6_out_dstunreach, "\t%llu output destination unreachable error%s\n");
+ p(ifs6_out_adminprohib, "\t%llu output administratively prohibited error%s\n");
+ p(ifs6_out_timeexceed, "\t%llu output time exceeded error%s\n");
+ p(ifs6_out_paramprob, "\t%llu output parameter problem error%s\n");
+ p(ifs6_out_pkttoobig, "\t%llu output packet too big error%s\n");
+ p(ifs6_out_echo, "\t%llu output echo request%s\n");
+ p2(ifs6_out_echoreply, "\t%llu output echo repl%s\n");
+ p(ifs6_out_routersolicit, "\t%llu output router solicitation%s\n");
+ p(ifs6_out_routeradvert, "\t%llu output router advertisement%s\n");
+ p(ifs6_out_neighborsolicit, "\t%llu output neighbor solicitation%s\n");
+ p(ifs6_out_neighboradvert, "\t%llu output neighbor advertisement%s\n");
+ p(ifs6_out_redirect, "\t%llu output redirect%s\n");
+ p2(ifs6_out_mldquery, "\t%llu output MLD quer%s\n");
+ p(ifs6_out_mldreport, "\t%llu output MLD report%s\n");
+ p(ifs6_out_mlddone, "\t%llu output MLD done%s\n");
+
+ end:
+ close(s);
+#undef p
+}
+
+/*
+ * Dump PIM statistics structure.
+ */
+void
+pim6_stats(u_long off __unused, const char *name, int af1 __unused)
+{
+ struct pim6stat pim6stat;
+
+ if (off == 0)
+ return;
+ if (kread(off, (char *)&pim6stat, sizeof(pim6stat)))
+ return;
+ printf("%s:\n", name);
+
+#define p(f, m) if (pim6stat.f || sflag <= 1) \
+ printf(m, (unsigned long long)pim6stat.f, plural(pim6stat.f))
+ p(pim6s_rcv_total, "\t%llu message%s received\n");
+ p(pim6s_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
+ p(pim6s_rcv_badsum, "\t%llu message%s received with bad checksum\n");
+ p(pim6s_rcv_badversion, "\t%llu message%s received with bad version\n");
+ p(pim6s_rcv_registers, "\t%llu register%s received\n");
+ p(pim6s_rcv_badregisters, "\t%llu bad register%s received\n");
+ p(pim6s_snd_registers, "\t%llu register%s sent\n");
+#undef p
+}
+
+/*
+ * Dump raw ip6 statistics structure.
+ */
+void
+rip6_stats(u_long off __unused, const char *name, int af1 __unused)
+{
+ struct rip6stat rip6stat;
+ u_quad_t delivered;
+ int mib[4];
+ size_t l;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET6;
+ mib[2] = IPPROTO_IPV6;
+ mib[3] = IPV6CTL_RIP6STATS;
+ l = sizeof(rip6stat);
+ if (sysctl(mib, 4, &rip6stat, &l, NULL, 0) < 0) {
+ perror("Warning: sysctl(net.inet6.ip6.rip6stats)");
+ return;
+ }
+
+ printf("%s:\n", name);
+
+#define p(f, m) if (rip6stat.f || sflag <= 1) \
+ printf(m, (unsigned long long)rip6stat.f, plural(rip6stat.f))
+ p(rip6s_ipackets, "\t%llu message%s received\n");
+ p(rip6s_isum, "\t%llu checksum calcuration%s on inbound\n");
+ p(rip6s_badsum, "\t%llu message%s with bad checksum\n");
+ p(rip6s_nosock, "\t%llu message%s dropped due to no socket\n");
+ p(rip6s_nosockmcast,
+ "\t%llu multicast message%s dropped due to no socket\n");
+ p(rip6s_fullsock,
+ "\t%llu message%s dropped due to full socket buffers\n");
+ delivered = rip6stat.rip6s_ipackets -
+ rip6stat.rip6s_badsum -
+ rip6stat.rip6s_nosock -
+ rip6stat.rip6s_nosockmcast -
+ rip6stat.rip6s_fullsock;
+ if (delivered || sflag <= 1)
+ printf("\t%llu delivered\n", (unsigned long long)delivered);
+ p(rip6s_opackets, "\t%llu datagram%s output\n");
+#undef p
+}
+
+/*
+ * Pretty print an Internet address (net address + port).
+ * Take numeric_addr and numeric_port into consideration.
+ */
+#define GETSERVBYPORT6(port, proto, ret)\
+{\
+ if (strcmp((proto), "tcp6") == 0)\
+ (ret) = getservbyport((int)(port), "tcp");\
+ else if (strcmp((proto), "udp6") == 0)\
+ (ret) = getservbyport((int)(port), "udp");\
+ else\
+ (ret) = getservbyport((int)(port), (proto));\
+};
+
+void
+inet6print(struct in6_addr *in6, int port, const char *proto, int numeric)
+{
+ struct servent *sp = 0;
+ char line[80], *cp;
+ int width;
+
+ sprintf(line, "%.*s.", Wflag ? 39 :
+ (Aflag && !numeric) ? 12 : 16, inet6name(in6));
+ cp = index(line, '\0');
+ if (!numeric && port)
+ GETSERVBYPORT6(port, proto, sp);
+ if (sp || port == 0)
+ sprintf(cp, "%.8s", sp ? sp->s_name : "*");
+ else
+ sprintf(cp, "%d", ntohs((u_short)port));
+ width = Wflag ? 45 : Aflag ? 18 : 22;
+ printf("%-*.*s ", width, width, line);
+}
+
+/*
+ * Construct an Internet address representation.
+ * If the numeric_addr has been supplied, give
+ * numeric value, otherwise try for symbolic name.
+ */
+
+char *
+inet6name(struct in6_addr *in6p)
+{
+ char *cp;
+ static char line[50];
+ struct hostent *hp;
+ static char domain[MAXHOSTNAMELEN];
+ static int first = 1;
+
+ if (first && !numeric_addr) {
+ first = 0;
+ if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
+ (cp = index(domain, '.')))
+ (void) strcpy(domain, cp + 1);
+ else
+ domain[0] = 0;
+ }
+ cp = 0;
+ if (!numeric_addr && !IN6_IS_ADDR_UNSPECIFIED(in6p)) {
+ hp = gethostbyaddr((char *)in6p, sizeof(*in6p), AF_INET6);
+ if (hp) {
+ if ((cp = index(hp->h_name, '.')) &&
+ !strcmp(cp + 1, domain))
+ *cp = 0;
+ cp = hp->h_name;
+ }
+ }
+ if (IN6_IS_ADDR_UNSPECIFIED(in6p))
+ strcpy(line, "*");
+ else if (cp)
+ strcpy(line, cp);
+ else
+ sprintf(line, "%s",
+ inet_ntop(AF_INET6, (void *)in6p, ntop_buf,
+ sizeof(ntop_buf)));
+ return (line);
+}
+#endif /*INET6*/
diff --git a/usr.bin/netstat/ipsec.c b/usr.bin/netstat/ipsec.c
new file mode 100644
index 000000000000..c99d27a2e988
--- /dev/null
+++ b/usr.bin/netstat/ipsec.c
@@ -0,0 +1,322 @@
+/* $NetBSD: inet.c,v 1.35.2.1 1999/04/29 14:57:08 perry Exp $ */
+/* $KAME: ipsec.c,v 1.33 2003/07/25 09:54:32 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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.
+ */
+
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)inet.c 8.5 (Berkeley) 5/24/95";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#include <netkey/keysock.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+
+#ifdef IPSEC
+struct val2str {
+ int val;
+ const char *str;
+};
+
+static struct val2str ipsec_ahnames[] = {
+ { SADB_AALG_NONE, "none", },
+ { SADB_AALG_MD5HMAC, "hmac-md5", },
+ { SADB_AALG_SHA1HMAC, "hmac-sha1", },
+ { SADB_X_AALG_MD5, "md5", },
+ { SADB_X_AALG_SHA, "sha", },
+ { SADB_X_AALG_NULL, "null", },
+#ifdef SADB_X_AALG_SHA2_256
+ { SADB_X_AALG_SHA2_256, "hmac-sha2-256", },
+#endif
+#ifdef SADB_X_AALG_SHA2_384
+ { SADB_X_AALG_SHA2_384, "hmac-sha2-384", },
+#endif
+#ifdef SADB_X_AALG_SHA2_512
+ { SADB_X_AALG_SHA2_512, "hmac-sha2-512", },
+#endif
+#ifdef SADB_X_AALG_RIPEMD160HMAC
+ { SADB_X_AALG_RIPEMD160HMAC, "hmac-ripemd160", },
+#endif
+#ifdef SADB_X_AALG_AES_XCBC_MAC
+ { SADB_X_AALG_AES_XCBC_MAC, "aes-xcbc-mac", },
+#endif
+ { -1, NULL },
+};
+
+static struct val2str ipsec_espnames[] = {
+ { SADB_EALG_NONE, "none", },
+ { SADB_EALG_DESCBC, "des-cbc", },
+ { SADB_EALG_3DESCBC, "3des-cbc", },
+ { SADB_EALG_NULL, "null", },
+ { SADB_X_EALG_CAST128CBC, "cast128-cbc", },
+ { SADB_X_EALG_BLOWFISHCBC, "blowfish-cbc", },
+#ifdef SADB_X_EALG_RIJNDAELCBC
+ { SADB_X_EALG_RIJNDAELCBC, "rijndael-cbc", },
+#endif
+#ifdef SADB_X_EALG_AESCTR
+ { SADB_X_EALG_AESCTR, "aes-ctr", },
+#endif
+ { -1, NULL },
+};
+
+static struct val2str ipsec_compnames[] = {
+ { SADB_X_CALG_NONE, "none", },
+ { SADB_X_CALG_OUI, "oui", },
+ { SADB_X_CALG_DEFLATE, "deflate", },
+ { SADB_X_CALG_LZS, "lzs", },
+ { -1, NULL },
+};
+
+static const char *pfkey_msgtypenames[] = {
+ "reserved", "getspi", "update", "add", "delete",
+ "get", "acquire", "register", "expire", "flush",
+ "dump", "x_promisc", "x_pchange", "x_spdupdate", "x_spdadd",
+ "x_spddelete", "x_spdget", "x_spdacquire", "x_spddump", "x_spdflush",
+ "x_spdsetidx", "x_spdexpire", "x_spddelete2"
+};
+
+static struct ipsecstat ipsecstat;
+
+static void print_ipsecstats (void);
+static const char *pfkey_msgtype_names (int);
+static void ipsec_hist (const u_quad_t *, size_t, const struct val2str *,
+ const char *);
+
+/*
+ * Dump IPSEC statistics structure.
+ */
+static void
+ipsec_hist(const u_quad_t *hist, size_t histmax, const struct val2str *name,
+ const char *title)
+{
+ int first;
+ size_t proto;
+ const struct val2str *p;
+
+ first = 1;
+ for (proto = 0; proto < histmax; proto++) {
+ if (hist[proto] <= 0)
+ continue;
+ if (first) {
+ printf("\t%s histogram:\n", title);
+ first = 0;
+ }
+ for (p = name; p && p->str; p++) {
+ if (p->val == (int)proto)
+ break;
+ }
+ if (p && p->str) {
+ printf("\t\t%s: %llu\n", p->str, (unsigned long long)hist[proto]);
+ } else {
+ printf("\t\t#%ld: %llu\n", (long)proto,
+ (unsigned long long)hist[proto]);
+ }
+ }
+}
+
+static void
+print_ipsecstats(void)
+{
+#define p(f, m) if (ipsecstat.f || sflag <= 1) \
+ printf(m, (unsigned long long)ipsecstat.f, plural(ipsecstat.f))
+#define pes(f, m) if (ipsecstat.f || sflag <= 1) \
+ printf(m, (unsigned long long)ipsecstat.f, plurales(ipsecstat.f))
+#define hist(f, n, t) \
+ ipsec_hist((f), sizeof(f)/sizeof(f[0]), (n), (t));
+
+ p(in_success, "\t%llu inbound packet%s processed successfully\n");
+ p(in_polvio, "\t%llu inbound packet%s violated process security "
+ "policy\n");
+ p(in_nosa, "\t%llu inbound packet%s with no SA available\n");
+ p(in_inval, "\t%llu invalid inbound packet%s\n");
+ p(in_nomem, "\t%llu inbound packet%s failed due to insufficient memory\n");
+ p(in_badspi, "\t%llu inbound packet%s failed getting SPI\n");
+ p(in_ahreplay, "\t%llu inbound packet%s failed on AH replay check\n");
+ p(in_espreplay, "\t%llu inbound packet%s failed on ESP replay check\n");
+ p(in_ahauthsucc, "\t%llu inbound packet%s considered authentic\n");
+ p(in_ahauthfail, "\t%llu inbound packet%s failed on authentication\n");
+ hist(ipsecstat.in_ahhist, ipsec_ahnames, "AH input");
+ hist(ipsecstat.in_esphist, ipsec_espnames, "ESP input");
+ hist(ipsecstat.in_comphist, ipsec_compnames, "IPComp input");
+
+ p(out_success, "\t%llu outbound packet%s processed successfully\n");
+ p(out_polvio, "\t%llu outbound packet%s violated process security "
+ "policy\n");
+ p(out_nosa, "\t%llu outbound packet%s with no SA available\n");
+ p(out_inval, "\t%llu invalid outbound packet%s\n");
+ p(out_nomem, "\t%llu outbound packet%s failed due to insufficient memory\n");
+ p(out_noroute, "\t%llu outbound packet%s with no route\n");
+ hist(ipsecstat.out_ahhist, ipsec_ahnames, "AH output");
+ hist(ipsecstat.out_esphist, ipsec_espnames, "ESP output");
+ hist(ipsecstat.out_comphist, ipsec_compnames, "IPComp output");
+ p(spdcachelookup, "\t%llu SPD cache lookup%s\n");
+ pes(spdcachemiss, "\t%llu SPD cache miss%s\n");
+#undef p
+#undef pes
+#undef hist
+}
+
+void
+ipsec_stats(u_long off __unused, const char *name, int af1 __unused)
+{
+ if (off == 0)
+ return;
+ printf ("%s:\n", name);
+ kread(off, (char *)&ipsecstat, sizeof (ipsecstat));
+
+ print_ipsecstats();
+}
+
+static const char *
+pfkey_msgtype_names(int x)
+{
+ const int max =
+ sizeof(pfkey_msgtypenames)/sizeof(pfkey_msgtypenames[0]);
+ static char buf[20];
+
+ if (x < max && pfkey_msgtypenames[x])
+ return pfkey_msgtypenames[x];
+ snprintf(buf, sizeof(buf), "#%d", x);
+ return buf;
+}
+
+void
+pfkey_stats(u_long off __unused, const char *name, int af1 __unused)
+{
+ struct pfkeystat pfkeystat;
+ unsigned first, type;
+
+ if (off == 0)
+ return;
+ printf ("%s:\n", name);
+ kread(off, (char *)&pfkeystat, sizeof(pfkeystat));
+
+#define p(f, m) if (pfkeystat.f || sflag <= 1) \
+ printf(m, (unsigned long long)pfkeystat.f, plural(pfkeystat.f))
+
+ /* userland -> kernel */
+ p(out_total, "\t%llu request%s sent from userland\n");
+ p(out_bytes, "\t%llu byte%s sent from userland\n");
+ for (first = 1, type = 0;
+ type < sizeof(pfkeystat.out_msgtype)/sizeof(pfkeystat.out_msgtype[0]);
+ type++) {
+ if (pfkeystat.out_msgtype[type] <= 0)
+ continue;
+ if (first) {
+ printf("\thistogram by message type:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %llu\n", pfkey_msgtype_names(type),
+ (unsigned long long)pfkeystat.out_msgtype[type]);
+ }
+ p(out_invlen, "\t%llu message%s with invalid length field\n");
+ p(out_invver, "\t%llu message%s with invalid version field\n");
+ p(out_invmsgtype, "\t%llu message%s with invalid message type field\n");
+ p(out_tooshort, "\t%llu message%s too short\n");
+ p(out_nomem, "\t%llu message%s with memory allocation failure\n");
+ p(out_dupext, "\t%llu message%s with duplicate extension\n");
+ p(out_invexttype, "\t%llu message%s with invalid extension type\n");
+ p(out_invsatype, "\t%llu message%s with invalid sa type\n");
+ p(out_invaddr, "\t%llu message%s with invalid address extension\n");
+
+ /* kernel -> userland */
+ p(in_total, "\t%llu request%s sent to userland\n");
+ p(in_bytes, "\t%llu byte%s sent to userland\n");
+ for (first = 1, type = 0;
+ type < sizeof(pfkeystat.in_msgtype)/sizeof(pfkeystat.in_msgtype[0]);
+ type++) {
+ if (pfkeystat.in_msgtype[type] <= 0)
+ continue;
+ if (first) {
+ printf("\thistogram by message type:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %llu\n", pfkey_msgtype_names(type),
+ (unsigned long long)pfkeystat.in_msgtype[type]);
+ }
+ p(in_msgtarget[KEY_SENDUP_ONE],
+ "\t%llu message%s toward single socket\n");
+ p(in_msgtarget[KEY_SENDUP_ALL],
+ "\t%llu message%s toward all sockets\n");
+ p(in_msgtarget[KEY_SENDUP_REGISTERED],
+ "\t%llu message%s toward registered sockets\n");
+ p(in_nomem, "\t%llu message%s with memory allocation failure\n");
+#undef p
+}
+#endif /*IPSEC*/
diff --git a/usr.bin/netstat/ipx.c b/usr.bin/netstat/ipx.c
new file mode 100644
index 000000000000..b4f294007436
--- /dev/null
+++ b/usr.bin/netstat/ipx.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)ns.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+
+#include <net/route.h>
+
+#include <netinet/tcp_fsm.h>
+
+#include <netipx/ipx.h>
+#include <netipx/ipx_pcb.h>
+#include <netipx/ipx_var.h>
+#ifdef IPXERRORMSGS
+#include <netipx/ipx_error.h>
+#endif
+#include <netipx/spx.h>
+#include <netipx/spx_timer.h>
+#include <netipx/spx_var.h>
+#define SANAMES
+#include <netipx/spx_debug.h>
+
+#include <nlist.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include "netstat.h"
+
+struct ipxpcb ipxpcb;
+struct spxpcb spxpcb;
+struct socket sockb;
+
+static char *ipx_prpr (struct ipx_addr *);
+
+static int first = 1;
+extern char *tcpstates[];
+
+/*
+ * Print a summary of connections related to a Network Systems
+ * protocol. For SPX, also give state of connection.
+ * Listening processes (aflag) are suppressed unless the
+ * -a (all) flag is specified.
+ */
+
+void
+ipxprotopr(u_long off, const char *name, int af1 __unused)
+{
+ struct ipxpcb cb;
+ struct ipxpcb *prev, *next;
+ int isspx;
+
+ if (off == 0)
+ return;
+ isspx = strcmp(name, "spx") == 0;
+ kread(off, (char *)&cb, sizeof (struct ipxpcb));
+ ipxpcb = cb;
+ prev = (struct ipxpcb *)off;
+ if (ipxpcb.ipxp_next == (struct ipxpcb *)off)
+ return;
+ for (;ipxpcb.ipxp_next != (struct ipxpcb *)off; prev = next) {
+ u_long ppcb;
+
+ next = ipxpcb.ipxp_next;
+ kread((u_long)next, (char *)&ipxpcb, sizeof (ipxpcb));
+ if (ipxpcb.ipxp_prev != prev) {
+ printf("???\n");
+ break;
+ }
+ if (!aflag && ipx_nullhost(ipxpcb.ipxp_faddr) ) {
+ continue;
+ }
+ kread((u_long)ipxpcb.ipxp_socket,
+ (char *)&sockb, sizeof (sockb));
+ ppcb = (u_long) ipxpcb.ipxp_pcb;
+ if (ppcb) {
+ if (isspx) {
+ kread(ppcb, (char *)&spxpcb, sizeof (spxpcb));
+ } else continue;
+ } else
+ if (isspx) continue;
+ if (first) {
+ printf("Active IPX connections");
+ if (aflag)
+ printf(" (including servers)");
+ putchar('\n');
+ if (Aflag)
+ printf("%-8.8s ", "PCB");
+ printf(Aflag ?
+ "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" :
+ "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n",
+ "Proto", "Recv-Q", "Send-Q",
+ "Local Address", "Foreign Address", "(state)");
+ first = 0;
+ }
+ if (Aflag)
+ printf("%8lx ", ppcb);
+ printf("%-5.5s %6u %6u ", name, sockb.so_rcv.sb_cc,
+ sockb.so_snd.sb_cc);
+ printf(Aflag?" %-18.18s":" %-22.22s", ipx_prpr(&ipxpcb.ipxp_laddr));
+ printf(Aflag?" %-18.18s":" %-22.22s", ipx_prpr(&ipxpcb.ipxp_faddr));
+ if (isspx) {
+ if (spxpcb.s_state >= TCP_NSTATES)
+ printf(" %d", spxpcb.s_state);
+ else
+ printf(" %s", tcpstates[spxpcb.s_state]);
+ }
+ putchar('\n');
+ prev = next;
+ }
+}
+
+#define ANY(x,y,z) \
+ if (x || sflag <= 1) printf("\t%u %s%s%s\n", x, y, plural(x), z)
+#define ANYl(x,y,z) \
+ if (x || sflag <= 1) printf("\t%lu %s%s%s\n", x, y, plural(x), z)
+
+/*
+ * Dump SPX statistics structure.
+ */
+void
+spx_stats(u_long off, const char *name, int af1 __unused)
+{
+ struct spx_istat spx_istat;
+#define spxstat spx_istat.newstats
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&spx_istat, sizeof (spx_istat));
+ printf("%s:\n", name);
+ ANY(spx_istat.nonucn, "connection", " dropped due to no new sockets ");
+ ANY(spx_istat.gonawy, "connection", " terminated due to our end dying");
+ ANY(spx_istat.nonucn, "connection",
+ " dropped due to inability to connect");
+ ANY(spx_istat.noconn, "connection",
+ " dropped due to inability to connect");
+ ANY(spx_istat.notme, "connection",
+ " incompleted due to mismatched id's");
+ ANY(spx_istat.wrncon, "connection", " dropped due to mismatched id's");
+ ANY(spx_istat.bdreas, "packet", " dropped out of sequence");
+ ANY(spx_istat.lstdup, "packet", " duplicating the highest packet");
+ ANY(spx_istat.notyet, "packet", " refused as exceeding allocation");
+ ANYl(spxstat.spxs_connattempt, "connection", " initiated");
+ ANYl(spxstat.spxs_accepts, "connection", " accepted");
+ ANYl(spxstat.spxs_connects, "connection", " established");
+ ANYl(spxstat.spxs_drops, "connection", " dropped");
+ ANYl(spxstat.spxs_conndrops, "embryonic connection", " dropped");
+ ANYl(spxstat.spxs_closed, "connection", " closed (includes drops)");
+ ANYl(spxstat.spxs_segstimed, "packet", " where we tried to get rtt");
+ ANYl(spxstat.spxs_rttupdated, "time", " we got rtt");
+ ANYl(spxstat.spxs_delack, "delayed ack", " sent");
+ ANYl(spxstat.spxs_timeoutdrop, "connection",
+ " dropped in rxmt timeout");
+ ANYl(spxstat.spxs_rexmttimeo, "retransmit timeout", "");
+ ANYl(spxstat.spxs_persisttimeo, "persist timeout", "");
+ ANYl(spxstat.spxs_keeptimeo, "keepalive timeout", "");
+ ANYl(spxstat.spxs_keepprobe, "keepalive probe", " sent");
+ ANYl(spxstat.spxs_keepdrops, "connection", " dropped in keepalive");
+ ANYl(spxstat.spxs_sndtotal, "total packet", " sent");
+ ANYl(spxstat.spxs_sndpack, "data packet", " sent");
+ ANYl(spxstat.spxs_sndbyte, "data byte", " sent");
+ ANYl(spxstat.spxs_sndrexmitpack, "data packet", " retransmitted");
+ ANYl(spxstat.spxs_sndrexmitbyte, "data byte", " retransmitted");
+ ANYl(spxstat.spxs_sndacks, "ack-only packet", " sent");
+ ANYl(spxstat.spxs_sndprobe, "window probe", " sent");
+ ANYl(spxstat.spxs_sndurg, "packet", " sent with URG only");
+ ANYl(spxstat.spxs_sndwinup, "window update-only packet", " sent");
+ ANYl(spxstat.spxs_sndctrl, "control (SYN|FIN|RST) packet", " sent");
+ ANYl(spxstat.spxs_sndvoid, "request", " to send a non-existant packet");
+ ANYl(spxstat.spxs_rcvtotal, "total packet", " received");
+ ANYl(spxstat.spxs_rcvpack, "packet", " received in sequence");
+ ANYl(spxstat.spxs_rcvbyte, "byte", " received in sequence");
+ ANYl(spxstat.spxs_rcvbadsum, "packet", " received with ccksum errs");
+ ANYl(spxstat.spxs_rcvbadoff, "packet", " received with bad offset");
+ ANYl(spxstat.spxs_rcvshort, "packet", " received too short");
+ ANYl(spxstat.spxs_rcvduppack, "duplicate-only packet", " received");
+ ANYl(spxstat.spxs_rcvdupbyte, "duplicate-only byte", " received");
+ ANYl(spxstat.spxs_rcvpartduppack, "packet",
+ " with some duplicate data");
+ ANYl(spxstat.spxs_rcvpartdupbyte, "dup. byte", " in part-dup. packet");
+ ANYl(spxstat.spxs_rcvoopack, "out-of-order packet", " received");
+ ANYl(spxstat.spxs_rcvoobyte, "out-of-order byte", " received");
+ ANYl(spxstat.spxs_rcvpackafterwin, "packet", " with data after window");
+ ANYl(spxstat.spxs_rcvbyteafterwin, "byte", " rcvd after window");
+ ANYl(spxstat.spxs_rcvafterclose, "packet", " rcvd after 'close'");
+ ANYl(spxstat.spxs_rcvwinprobe, "rcvd window probe packet", "");
+ ANYl(spxstat.spxs_rcvdupack, "rcvd duplicate ack", "");
+ ANYl(spxstat.spxs_rcvacktoomuch, "rcvd ack", " for unsent data");
+ ANYl(spxstat.spxs_rcvackpack, "rcvd ack packet", "");
+ ANYl(spxstat.spxs_rcvackbyte, "byte", " acked by rcvd acks");
+ ANYl(spxstat.spxs_rcvwinupd, "rcvd window update packet", "");
+}
+
+/*
+ * Dump IPX statistics structure.
+ */
+void
+ipx_stats(u_long off, const char *name, int af1 __unused)
+{
+ struct ipxstat ipxstat;
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&ipxstat, sizeof (ipxstat));
+ printf("%s:\n", name);
+ ANYl(ipxstat.ipxs_total, "total packet", " received");
+ ANYl(ipxstat.ipxs_badsum, "packet", " with bad checksums");
+ ANYl(ipxstat.ipxs_tooshort, "packet", " smaller than advertised");
+ ANYl(ipxstat.ipxs_toosmall, "packet", " smaller than a header");
+ ANYl(ipxstat.ipxs_forward, "packet", " forwarded");
+ ANYl(ipxstat.ipxs_cantforward, "packet", " not forwardable");
+ ANYl(ipxstat.ipxs_delivered, "packet", " for this host");
+ ANYl(ipxstat.ipxs_localout, "packet", " sent from this host");
+ ANYl(ipxstat.ipxs_odropped, "packet", " dropped due to no bufs, etc.");
+ ANYl(ipxstat.ipxs_noroute, "packet", " discarded due to no route");
+ ANYl(ipxstat.ipxs_mtutoosmall, "packet", " too big");
+}
+
+#ifdef IPXERRORMSGS
+static struct {
+ u_short code;
+ char *name;
+ char *where;
+} ipx_errnames[] = {
+ {0, "Unspecified Error", " at Destination"},
+ {1, "Bad Checksum", " at Destination"},
+ {2, "No Listener", " at Socket"},
+ {3, "Packet", " Refused due to lack of space at Destination"},
+ {01000, "Unspecified Error", " while gatewayed"},
+ {01001, "Bad Checksum", " while gatewayed"},
+ {01002, "Packet", " forwarded too many times"},
+ {01003, "Packet", " too large to be forwarded"},
+ {-1, 0, 0},
+};
+
+/*
+ * Dump IPX Error statistics structure.
+ */
+/*ARGSUSED*/
+void
+ipxerr_stats(u_long off, const char *name, int af __unused)
+{
+ struct ipx_errstat ipx_errstat;
+ int j;
+ int histoprint = 1;
+ int z;
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&ipx_errstat, sizeof (ipx_errstat));
+ printf("IPX error statistics:\n");
+ ANY(ipx_errstat.ipx_es_error, "call", " to ipx_error");
+ ANY(ipx_errstat.ipx_es_oldshort, "error",
+ " ignored due to insufficient addressing");
+ ANY(ipx_errstat.ipx_es_oldipx_err, "error request",
+ " in response to error packets");
+ ANY(ipx_errstat.ipx_es_tooshort, "error packet",
+ " received incomplete");
+ ANY(ipx_errstat.ipx_es_badcode, "error packet",
+ " received of unknown type");
+ for(j = 0; j < IPX_ERR_MAX; j ++) {
+ z = ipx_errstat.ipx_es_outhist[j];
+ if (z && histoprint) {
+ printf("Output Error Histogram:\n");
+ histoprint = 0;
+ }
+ ipx_erputil(z, ipx_errstat.ipx_es_codes[j]);
+ }
+ histoprint = 1;
+ for(j = 0; j < IPX_ERR_MAX; j ++) {
+ z = ipx_errstat.ipx_es_inhist[j];
+ if (z && histoprint) {
+ printf("Input Error Histogram:\n");
+ histoprint = 0;
+ }
+ ipx_erputil(z, ipx_errstat.ipx_es_codes[j]);
+ }
+}
+
+static void
+ipx_erputil(int z, int c)
+{
+ int j;
+ char codebuf[30];
+ char *name, *where;
+
+ for(j = 0;; j ++) {
+ if ((name = ipx_errnames[j].name) == 0)
+ break;
+ if (ipx_errnames[j].code == c)
+ break;
+ }
+ if (name == 0) {
+ if (c > 01000)
+ where = "in transit";
+ else
+ where = "at destination";
+ sprintf(codebuf, "Unknown IPX error code 0%o", c);
+ name = codebuf;
+ } else
+ where = ipx_errnames[j].where;
+ ANY(z, name, where);
+}
+#endif /* IPXERRORMSGS */
+
+static struct sockaddr_ipx ssipx = {AF_IPX};
+
+static
+char *ipx_prpr(struct ipx_addr *x)
+{
+ struct sockaddr_ipx *sipx = &ssipx;
+
+ sipx->sipx_addr = *x;
+ return(ipx_print((struct sockaddr *)sipx));
+}
diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c
new file mode 100644
index 000000000000..1474ba3750e3
--- /dev/null
+++ b/usr.bin/netstat/main.c
@@ -0,0 +1,698 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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.
+ */
+
+#ifndef lint
+char const copyright[] =
+"@(#) Copyright (c) 1983, 1988, 1993\n\
+ Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 3/1/94";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <netgraph/ng_socket.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <kvm.h>
+#include <limits.h>
+#include <netdb.h>
+#include <nlist.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+
+static struct nlist nl[] = {
+#define N_IFNET 0
+ { "_ifnet" },
+#define N_RTSTAT 1
+ { "_rtstat" },
+#define N_RTREE 2
+ { "_rt_tables"},
+#define N_MRTSTAT 3
+ { "_mrtstat" },
+#define N_MFCTABLE 4
+ { "_mfctable" },
+#define N_VIFTABLE 5
+ { "_viftable" },
+#define N_IPX 6
+ { "_ipxpcb"},
+#define N_IPXSTAT 7
+ { "_ipxstat"},
+#define N_SPXSTAT 8
+ { "_spx_istat"},
+#define N_DDPSTAT 9
+ { "_ddpstat"},
+#define N_DDPCB 10
+ { "_ddpcb"},
+#define N_NGSOCKS 11
+ { "_ngsocklist"},
+#define N_IP6STAT 12
+ { "_ip6stat" },
+#define N_ICMP6STAT 13
+ { "_icmp6stat" },
+#define N_IPSECSTAT 14
+ { "_ipsecstat" },
+#define N_IPSEC6STAT 15
+ { "_ipsec6stat" },
+#define N_PIM6STAT 16
+ { "_pim6stat" },
+#define N_MRT6STAT 17
+ { "_mrt6stat" },
+#define N_MF6CTABLE 18
+ { "_mf6ctable" },
+#define N_MIF6TABLE 19
+ { "_mif6table" },
+#define N_PFKEYSTAT 20
+ { "_pfkeystat" },
+#define N_MBSTAT 21
+ { "_mbstat" },
+#define N_MBTYPES 22
+ { "_mbtypes" },
+#define N_NMBCLUSTERS 23
+ { "_nmbclusters" },
+#define N_NMBUFS 24
+ { "_nmbufs" },
+#define N_MBHI 25
+ { "_mbuf_hiwm" },
+#define N_CLHI 26
+ { "_clust_hiwm" },
+#define N_NCPUS 27
+ { "_smp_cpus" },
+#define N_PAGESZ 28
+ { "_pagesize" },
+#define N_MBPSTAT 29
+ { "_mb_statpcpu" },
+#define N_RTTRASH 30
+ { "_rttrash" },
+#define N_MBLO 31
+ { "_mbuf_lowm" },
+#define N_CLLO 32
+ { "_clust_lowm" },
+ { "" },
+};
+
+struct protox {
+ u_char pr_index; /* index into nlist of cb head */
+ u_char pr_sindex; /* index into nlist of stat block */
+ u_char pr_wanted; /* 1 if wanted, 0 otherwise */
+ void (*pr_cblocks)(u_long, const char *, int);
+ /* control blocks printing routine */
+ void (*pr_stats)(u_long, const char *, int);
+ /* statistics printing routine */
+ void (*pr_istats)(char *); /* per/if statistics printing routine */
+ const char *pr_name; /* well-known name */
+ u_long pr_usesysctl; /* non-zero if we use sysctl, not kvm */
+} protox[] = {
+ { -1, -1, 1, protopr,
+ tcp_stats, NULL, "tcp", IPPROTO_TCP },
+ { -1, -1, 1, protopr,
+ udp_stats, NULL, "udp", IPPROTO_UDP },
+ { -1, -1, 1, protopr,
+ NULL, NULL, "divert",IPPROTO_DIVERT },
+ { -1, -1, 1, protopr,
+ ip_stats, NULL, "ip", IPPROTO_RAW },
+ { -1, -1, 1, protopr,
+ icmp_stats, NULL, "icmp", IPPROTO_ICMP },
+ { -1, -1, 1, protopr,
+ igmp_stats, NULL, "igmp", IPPROTO_IGMP },
+#ifdef IPSEC
+ { -1, N_IPSECSTAT, 1, NULL,
+ ipsec_stats, NULL, "ipsec", 0},
+#endif
+ { -1, -1, 1, NULL,
+ bdg_stats, NULL, "bdg", 1 /* bridging... */ },
+ { -1, -1, 1, protopr,
+ pim_stats, NULL, "pim", IPPROTO_PIM },
+ { -1, -1, 0, NULL,
+ NULL, NULL, NULL, 0 }
+};
+
+#ifdef INET6
+struct protox ip6protox[] = {
+ { -1, -1, 1, protopr,
+ tcp_stats, NULL, "tcp", IPPROTO_TCP },
+ { -1, -1, 1, protopr,
+ udp_stats, NULL, "udp", IPPROTO_UDP },
+ { -1, N_IP6STAT, 1, protopr,
+ ip6_stats, ip6_ifstats, "ip6", IPPROTO_RAW },
+ { -1, N_ICMP6STAT, 1, protopr,
+ icmp6_stats, icmp6_ifstats, "icmp6",IPPROTO_ICMPV6 },
+#ifdef IPSEC
+ { -1, N_IPSEC6STAT, 1, NULL,
+ ipsec_stats, NULL, "ipsec6",0 },
+#endif
+#ifdef notyet
+ { -1, N_PIM6STAT, 1, NULL,
+ pim6_stats, NULL, "pim6", 0 },
+#endif
+ { -1, -1, 1, NULL,
+ rip6_stats, NULL, "rip6", 0 },
+ { -1, -1, 1, NULL,
+ bdg_stats, NULL, "bdg", 1 /* bridging... */ },
+ { -1, -1, 0, NULL,
+ NULL, NULL, NULL, 0 }
+};
+#endif /*INET6*/
+
+#ifdef IPSEC
+struct protox pfkeyprotox[] = {
+ { -1, N_PFKEYSTAT, 1, NULL,
+ pfkey_stats, NULL, "pfkey", 0 },
+ { -1, -1, 0, NULL,
+ NULL, NULL, NULL, 0 }
+};
+#endif
+
+struct protox atalkprotox[] = {
+ { N_DDPCB, N_DDPSTAT, 1, atalkprotopr,
+ ddp_stats, NULL, "ddp", 0 },
+ { -1, -1, 0, NULL,
+ NULL, NULL, NULL, 0 }
+};
+
+struct protox netgraphprotox[] = {
+ { N_NGSOCKS, -1, 1, netgraphprotopr,
+ NULL, NULL, "ctrl", 0 },
+ { N_NGSOCKS, -1, 1, netgraphprotopr,
+ NULL, NULL, "data", 0 },
+ { -1, -1, 0, NULL,
+ NULL, NULL, NULL, 0 }
+};
+
+struct protox ipxprotox[] = {
+ { N_IPX, N_IPXSTAT, 1, ipxprotopr,
+ ipx_stats, NULL, "ipx", 0 },
+ { N_IPX, N_SPXSTAT, 1, ipxprotopr,
+ spx_stats, NULL, "spx", 0 },
+ { -1, -1, 0, NULL,
+ NULL, NULL, 0, 0 }
+};
+
+struct protox *protoprotox[] = {
+ protox,
+#ifdef INET6
+ ip6protox,
+#endif
+#ifdef IPSEC
+ pfkeyprotox,
+#endif
+ ipxprotox, atalkprotox, NULL };
+
+const char *pluralies(int);
+static void printproto(struct protox *, const char *);
+static void usage(void);
+static struct protox *name2protox(char *);
+static struct protox *knownname(char *);
+
+static kvm_t *kvmd;
+static char *nlistf = NULL, *memf = NULL;
+
+int Aflag; /* show addresses of protocol control block */
+int aflag; /* show all sockets (including servers) */
+int bflag; /* show i/f total bytes in/out */
+int dflag; /* show i/f dropped packets */
+int gflag; /* show group (multicast) routing or stats */
+int iflag; /* show interfaces */
+int Lflag; /* show size of listen queues */
+int mflag; /* show memory stats */
+int numeric_addr; /* show addresses numerically */
+int numeric_port; /* show ports numerically */
+static int pflag; /* show given protocol */
+int rflag; /* show routing tables (or routing stats) */
+int sflag; /* show protocol statistics */
+int tflag; /* show i/f watchdog timers */
+int Wflag; /* wide display */
+int zflag; /* zero stats */
+
+int interval; /* repeat interval for i/f stats */
+
+char *interface; /* desired i/f for stats, or NULL for all i/fs */
+int unit; /* unit number for above */
+
+int af; /* address family */
+
+int
+main(int argc, char *argv[])
+{
+ struct protox *tp = NULL; /* for printing cblocks & stats */
+ int ch;
+
+ af = AF_UNSPEC;
+
+ while ((ch = getopt(argc, argv, "Aabcdf:gI:iLlM:mN:np:rSstuWw:z")) != -1)
+ switch(ch) {
+ case 'A':
+ Aflag = 1;
+ break;
+ case 'a':
+ aflag = 1;
+ break;
+ case 'b':
+ bflag = 1;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'f':
+ if (strcmp(optarg, "ipx") == 0)
+ af = AF_IPX;
+ else if (strcmp(optarg, "inet") == 0)
+ af = AF_INET;
+#ifdef INET6
+ else if (strcmp(optarg, "inet6") == 0)
+ af = AF_INET6;
+#endif /*INET6*/
+#ifdef INET6
+ else if (strcmp(optarg, "pfkey") == 0)
+ af = PF_KEY;
+#endif /*INET6*/
+ else if (strcmp(optarg, "unix") == 0)
+ af = AF_UNIX;
+ else if (strcmp(optarg, "atalk") == 0)
+ af = AF_APPLETALK;
+ else if (strcmp(optarg, "ng") == 0
+ || strcmp(optarg, "netgraph") == 0)
+ af = AF_NETGRAPH;
+ else if (strcmp(optarg, "link") == 0)
+ af = AF_LINK;
+ else {
+ errx(1, "%s: unknown address family", optarg);
+ }
+ break;
+ case 'g':
+ gflag = 1;
+ break;
+ case 'I': {
+ char *cp;
+
+ iflag = 1;
+ for (cp = interface = optarg; isalpha(*cp); cp++)
+ continue;
+ unit = atoi(cp);
+ break;
+ }
+ case 'i':
+ iflag = 1;
+ break;
+ case 'L':
+ Lflag = 1;
+ break;
+ case 'M':
+ memf = optarg;
+ break;
+ case 'm':
+ mflag = 1;
+ break;
+ case 'N':
+ nlistf = optarg;
+ break;
+ case 'n':
+ numeric_addr = numeric_port = 1;
+ break;
+ case 'p':
+ if ((tp = name2protox(optarg)) == NULL) {
+ errx(1,
+ "%s: unknown or uninstrumented protocol",
+ optarg);
+ }
+ pflag = 1;
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case 's':
+ ++sflag;
+ break;
+ case 'S':
+ numeric_addr = 1;
+ break;
+ case 't':
+ tflag = 1;
+ break;
+ case 'u':
+ af = AF_UNIX;
+ break;
+ case 'W':
+ case 'l':
+ Wflag = 1;
+ break;
+ case 'w':
+ interval = atoi(optarg);
+ iflag = 1;
+ break;
+ case 'z':
+ zflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argv += optind;
+ argc -= optind;
+
+#define BACKWARD_COMPATIBILITY
+#ifdef BACKWARD_COMPATIBILITY
+ if (*argv) {
+ if (isdigit(**argv)) {
+ interval = atoi(*argv);
+ if (interval <= 0)
+ usage();
+ ++argv;
+ iflag = 1;
+ }
+ if (*argv) {
+ nlistf = *argv;
+ if (*++argv)
+ memf = *argv;
+ }
+ }
+#endif
+
+ /*
+ * Discard setgid privileges if not the running kernel so that bad
+ * guys can't print interesting stuff from kernel memory.
+ */
+ if (nlistf != NULL || memf != NULL)
+ setgid(getgid());
+
+ if (mflag) {
+ if (memf != NULL) {
+ if (kread(0, 0, 0) == 0)
+ mbpr(nl[N_MBSTAT].n_value,
+ nl[N_MBTYPES].n_value,
+ nl[N_NMBCLUSTERS].n_value,
+ nl[N_NMBUFS].n_value,
+ nl[N_MBHI].n_value,
+ nl[N_CLHI].n_value,
+ nl[N_MBLO].n_value,
+ nl[N_CLLO].n_value,
+ nl[N_NCPUS].n_value,
+ nl[N_PAGESZ].n_value,
+ nl[N_MBPSTAT].n_value);
+ } else
+ mbpr(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ exit(0);
+ }
+#if 0
+ /*
+ * Keep file descriptors open to avoid overhead
+ * of open/close on each call to get* routines.
+ */
+ sethostent(1);
+ setnetent(1);
+#else
+ /*
+ * This does not make sense any more with DNS being default over
+ * the files. Doing a setXXXXent(1) causes a tcp connection to be
+ * used for the queries, which is slower.
+ */
+#endif
+ if (iflag && !sflag) {
+ kread(0, 0, 0);
+ intpr(interval, nl[N_IFNET].n_value, NULL);
+ exit(0);
+ }
+ if (rflag) {
+ kread(0, 0, 0);
+ if (sflag)
+ rt_stats(nl[N_RTSTAT].n_value, nl[N_RTTRASH].n_value);
+ else
+ routepr(nl[N_RTREE].n_value);
+ exit(0);
+ }
+ if (gflag) {
+ kread(0, 0, 0);
+ if (sflag) {
+ if (af == AF_INET || af == AF_UNSPEC)
+ mrt_stats(nl[N_MRTSTAT].n_value);
+#ifdef INET6
+ if (af == AF_INET6 || af == AF_UNSPEC)
+ mrt6_stats(nl[N_MRT6STAT].n_value);
+#endif
+ } else {
+ if (af == AF_INET || af == AF_UNSPEC)
+ mroutepr(nl[N_MFCTABLE].n_value,
+ nl[N_VIFTABLE].n_value);
+#ifdef INET6
+ if (af == AF_INET6 || af == AF_UNSPEC)
+ mroute6pr(nl[N_MF6CTABLE].n_value,
+ nl[N_MIF6TABLE].n_value);
+#endif
+ }
+ ifmalist_dump();
+ exit(0);
+ }
+
+ kread(0, 0, 0);
+ if (tp) {
+ printproto(tp, tp->pr_name);
+ exit(0);
+ }
+ if (af == AF_INET || af == AF_UNSPEC)
+ for (tp = protox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#ifdef INET6
+ if (af == AF_INET6 || af == AF_UNSPEC)
+ for (tp = ip6protox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#endif /*INET6*/
+#ifdef IPSEC
+ if (af == PF_KEY || af == AF_UNSPEC)
+ for (tp = pfkeyprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#endif /*IPSEC*/
+ if (af == AF_IPX || af == AF_UNSPEC) {
+ kread(0, 0, 0);
+ for (tp = ipxprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+ }
+ if (af == AF_APPLETALK || af == AF_UNSPEC)
+ for (tp = atalkprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+ if (af == AF_NETGRAPH || af == AF_UNSPEC)
+ for (tp = netgraphprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+ if ((af == AF_UNIX || af == AF_UNSPEC) && !Lflag && !sflag)
+ unixpr();
+ exit(0);
+}
+
+/*
+ * Print out protocol statistics or control blocks (per sflag).
+ * If the interface was not specifically requested, and the symbol
+ * is not in the namelist, ignore this one.
+ */
+static void
+printproto(tp, name)
+ struct protox *tp;
+ const char *name;
+{
+ void (*pr)(u_long, const char *, int);
+ u_long off;
+
+ if (sflag) {
+ if (iflag) {
+ if (tp->pr_istats)
+ intpr(interval, nl[N_IFNET].n_value,
+ tp->pr_istats);
+ else if (pflag)
+ printf("%s: no per-interface stats routine\n",
+ tp->pr_name);
+ return;
+ }
+ else {
+ pr = tp->pr_stats;
+ if (!pr) {
+ if (pflag)
+ printf("%s: no stats routine\n",
+ tp->pr_name);
+ return;
+ }
+ off = tp->pr_usesysctl ? tp->pr_usesysctl
+ : nl[tp->pr_sindex].n_value;
+ }
+ } else {
+ pr = tp->pr_cblocks;
+ if (!pr) {
+ if (pflag)
+ printf("%s: no PCB routine\n", tp->pr_name);
+ return;
+ }
+ off = tp->pr_usesysctl ? tp->pr_usesysctl
+ : nl[tp->pr_index].n_value;
+ }
+ if (pr != NULL && (off || af != AF_UNSPEC))
+ (*pr)(off, name, af);
+}
+
+/*
+ * Read kernel memory, return 0 on success.
+ */
+int
+kread(u_long addr, char *buf, int size)
+{
+ if (kvmd == 0) {
+ /*
+ * XXX.
+ */
+ kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf);
+ setgid(getgid());
+ if (kvmd != NULL) {
+ if (kvm_nlist(kvmd, nl) < 0) {
+ if(nlistf)
+ errx(1, "%s: kvm_nlist: %s", nlistf,
+ kvm_geterr(kvmd));
+ else
+ errx(1, "kvm_nlist: %s", kvm_geterr(kvmd));
+ }
+
+ if (nl[0].n_type == 0) {
+ if(nlistf)
+ errx(1, "%s: no namelist", nlistf);
+ else
+ errx(1, "no namelist");
+ }
+ } else {
+ warnx("kvm not available");
+ return(-1);
+ }
+ }
+ if (!buf)
+ return (0);
+ if (kvm_read(kvmd, addr, buf, size) != size) {
+ warnx("%s", kvm_geterr(kvmd));
+ return (-1);
+ }
+ return (0);
+}
+
+const char *
+plural(int n)
+{
+ return (n != 1 ? "s" : "");
+}
+
+const char *
+plurales(int n)
+{
+ return (n != 1 ? "es" : "");
+}
+
+const char *
+pluralies(int n)
+{
+ return (n != 1 ? "ies" : "y");
+}
+
+/*
+ * Find the protox for the given "well-known" name.
+ */
+static struct protox *
+knownname(char *name)
+{
+ struct protox **tpp, *tp;
+
+ for (tpp = protoprotox; *tpp; tpp++)
+ for (tp = *tpp; tp->pr_name; tp++)
+ if (strcmp(tp->pr_name, name) == 0)
+ return (tp);
+ return (NULL);
+}
+
+/*
+ * Find the protox corresponding to name.
+ */
+static struct protox *
+name2protox(char *name)
+{
+ struct protox *tp;
+ char **alias; /* alias from p->aliases */
+ struct protoent *p;
+
+ /*
+ * Try to find the name in the list of "well-known" names. If that
+ * fails, check if name is an alias for an Internet protocol.
+ */
+ if ((tp = knownname(name)) != NULL)
+ return (tp);
+
+ setprotoent(1); /* make protocol lookup cheaper */
+ while ((p = getprotoent()) != NULL) {
+ /* assert: name not same as p->name */
+ for (alias = p->p_aliases; *alias; alias++)
+ if (strcmp(name, *alias) == 0) {
+ endprotoent();
+ return (knownname(p->p_name));
+ }
+ }
+ endprotoent();
+ return (NULL);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
+"usage: netstat [-AaLnSW] [-f protocol_family | -p protocol]\n"
+" [-M core] [-N system]",
+" netstat -i | -I interface [-abdnt] [-f address_family]\n"
+" [-M core] [-N system]",
+" netstat -w wait [-I interface] [-d] [-M core] [-N system]",
+" netstat -s [-s] [-z] [-f protocol_family | -p protocol] [-M core]",
+" netstat -i | -I interface -s [-f protocol_family | -p protocol]\n"
+" [-M core] [-N system]",
+" netstat -m [-c] [-M core] [-N system]",
+" netstat -r [-AenW] [-f address_family] [-M core] [-N system]",
+" netstat -rs [-s] [-M core] [-N system]",
+" netstat -g [-W] [-f address_family] [-M core] [-N system]",
+" netstat -gs [-s] [-f address_family] [-M core] [-N system]");
+ exit(1);
+}
diff --git a/usr.bin/netstat/mbuf.c b/usr.bin/netstat/mbuf.c
new file mode 100644
index 000000000000..feb4871d8f42
--- /dev/null
+++ b/usr.bin/netstat/mbuf.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)mbuf.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "netstat.h"
+
+#define YES 1
+typedef int bool;
+
+static struct mbtypenames {
+ short mt_type;
+ const char *mt_name;
+} mbtypenames[] = {
+ { MT_DATA, "data" },
+ { MT_OOBDATA, "oob data" },
+ { MT_CONTROL, "ancillary data" },
+ { MT_HEADER, "packet headers" },
+#ifdef MT_SOCKET
+ { MT_SOCKET, "socket structures" }, /* XXX */
+#endif
+#ifdef MT_PCB
+ { MT_PCB, "protocol control blocks" }, /* XXX */
+#endif
+#ifdef MT_RTABLE
+ { MT_RTABLE, "routing table entries" }, /* XXX */
+#endif
+#ifdef MT_HTABLE
+ { MT_HTABLE, "IMP host table entries" }, /* XXX */
+#endif
+#ifdef MT_ATABLE
+ { MT_ATABLE, "address resolution tables" },
+#endif
+ { MT_FTABLE, "fragment reassembly queue headers" }, /* XXX */
+ { MT_SONAME, "socket names and addresses" },
+#ifdef MT_SOOPTS
+ { MT_SOOPTS, "socket options" },
+#endif
+#ifdef MT_RIGHTS
+ { MT_RIGHTS, "access rights" },
+#endif
+#ifdef MT_IFADDR
+ { MT_IFADDR, "interface addresses" }, /* XXX */
+#endif
+ { 0, 0 }
+};
+
+/*
+ * Print mbuf statistics.
+ */
+void
+mbpr(u_long mbaddr, u_long mbtaddr __unused, u_long nmbcaddr, u_long nmbufaddr,
+ u_long mbhiaddr, u_long clhiaddr, u_long mbloaddr, u_long clloaddr,
+ u_long cpusaddr __unused, u_long pgsaddr, u_long mbpaddr)
+{
+ int i, nmbclusters;
+ int nsfbufs, nsfbufspeak, nsfbufsused;
+ short nmbtypes;
+ size_t mlen;
+ long *mbtypes = NULL;
+ struct mbstat *mbstat = NULL;
+ struct mbtypenames *mp;
+ bool *seen = NULL;
+
+ mlen = sizeof *mbstat;
+ if ((mbstat = malloc(mlen)) == NULL) {
+ warn("malloc: cannot allocate memory for mbstat");
+ goto err;
+ }
+
+ if (mbaddr) {
+ if (kread(mbaddr, (char *)mbstat, sizeof mbstat))
+ goto err;
+ if (kread(nmbcaddr, (char *)&nmbclusters, sizeof(int)))
+ goto err;
+ } else {
+ mlen = sizeof *mbstat;
+ if (sysctlbyname("kern.ipc.mbstat", mbstat, &mlen, NULL, 0)
+ < 0) {
+ warn("sysctl: retrieving mbstat");
+ goto err;
+ }
+ mlen = sizeof(int);
+ if (sysctlbyname("kern.ipc.nmbclusters", &nmbclusters, &mlen,
+ NULL, 0) < 0) {
+ warn("sysctl: retrieving nmbclusters");
+ goto err;
+ }
+ }
+ if (mbstat->m_mbufs < 0) mbstat->m_mbufs = 0; /* XXX */
+ if (mbstat->m_mclusts < 0) mbstat->m_mclusts = 0; /* XXX */
+
+ nmbtypes = mbstat->m_numtypes;
+ if ((seen = calloc(nmbtypes, sizeof(*seen))) == NULL) {
+ warn("calloc: cannot allocate memory for mbtypes seen flag");
+ goto err;
+ }
+ if ((mbtypes = calloc(nmbtypes, sizeof(long *))) == NULL) {
+ warn("calloc: cannot allocate memory for mbtypes");
+ goto err;
+ }
+
+#undef MSIZE
+#define MSIZE (mbstat->m_msize)
+#undef MCLBYTES
+#define MCLBYTES (mbstat->m_mclbytes)
+
+ printf("%lu mbufs in use\n", mbstat->m_mbufs);
+
+ for (mp = mbtypenames; mp->mt_name; mp++) {
+ if (mbtypes[mp->mt_type]) {
+ seen[mp->mt_type] = YES;
+ printf("\t %lu mbufs allocated to %s\n",
+ mbtypes[mp->mt_type], mp->mt_name);
+ }
+ }
+ for (i = 1; i < nmbtypes; i++) {
+ if (!seen[i] && mbtypes[i])
+ printf("\t %lu mbufs allocated to <mbuf type: %d>\n",
+ mbtypes[i], i);
+ }
+
+ printf("%lu/%d mbuf clusters in use (current/max)\n",
+ mbstat->m_mclusts, nmbclusters);
+
+ mlen = sizeof(nsfbufs);
+ if (!sysctlbyname("kern.ipc.nsfbufs", &nsfbufs, &mlen, NULL, 0) &&
+ !sysctlbyname("kern.ipc.nsfbufsused", &nsfbufsused, &mlen, NULL,
+ 0) &&
+ !sysctlbyname("kern.ipc.nsfbufspeak", &nsfbufspeak, &mlen, NULL,
+ 0)) {
+ printf("%d/%d/%d sfbufs in use (current/peak/max)\n",
+ nsfbufsused, nsfbufspeak, nsfbufs);
+ }
+ printf("%lu KBytes allocated to network\n", (mbstat->m_mbufs * MSIZE +
+ mbstat->m_mclusts * MCLBYTES) / 1024);
+ printf("%lu requests for sfbufs denied\n", mbstat->sf_allocfail);
+ printf("%lu requests for sfbufs delayed\n", mbstat->sf_allocwait);
+ printf("%lu requests for I/O initiated by sendfile\n",
+ mbstat->sf_iocnt);
+ printf("%lu calls to protocol drain routines\n", mbstat->m_drain);
+
+err:
+ if (mbtypes != NULL)
+ free(mbtypes);
+ if (seen != NULL)
+ free(seen);
+ if (mbstat != NULL)
+ free(mbstat);
+}
diff --git a/usr.bin/netstat/mcast.c b/usr.bin/netstat/mcast.c
new file mode 100644
index 000000000000..2b2a5cd1bb70
--- /dev/null
+++ b/usr.bin/netstat/mcast.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2004 Bruce M Simpson <bms@spc.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Print the system's current multicast group memberships.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_mib.h>
+#include <net/if_types.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <ifaddrs.h>
+#include <sysexits.h>
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "netstat.h"
+
+union sockunion {
+ struct sockaddr_storage ss;
+ struct sockaddr sa;
+ struct sockaddr_dl sdl;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+};
+typedef union sockunion sockunion_t;
+
+#define MYIFNAME_SIZE 128
+
+void
+ifmalist_dump(void)
+{
+ struct ifmaddrs *ifmap, *ifma;
+ sockunion_t *psa;
+ char myifname[MYIFNAME_SIZE];
+ char addrbuf[INET6_ADDRSTRLEN];
+ char *pcolon;
+ void *addr;
+ char *pifname, *plladdr, *pgroup;
+
+ if (getifmaddrs(&ifmap))
+ err(EX_OSERR, "getifmaddrs");
+
+ fputs("IPv4/IPv6 Multicast Group Memberships\n", stdout);
+ fprintf(stdout, "%-20s\t%-16s\t%s\n", "Group", "Gateway", "Netif");
+
+ for (ifma = ifmap; ifma; ifma = ifma->ifma_next) {
+
+ if (ifma->ifma_name == NULL || ifma->ifma_addr == NULL)
+ continue;
+
+ /* Group address */
+ psa = (sockunion_t *)ifma->ifma_addr;
+ switch (psa->sa.sa_family) {
+ case AF_INET:
+ pgroup = inet_ntoa(psa->sin.sin_addr);
+ break;
+ case AF_INET6:
+ addr = &psa->sin6.sin6_addr;
+ inet_ntop(psa->sa.sa_family, addr, addrbuf,
+ sizeof(addrbuf));
+ pgroup = addrbuf;
+ break;
+ default:
+ continue; /* XXX */
+ }
+
+ /* Link-layer mapping, if any */
+ psa = (sockunion_t *)ifma->ifma_lladdr;
+ if (psa != NULL) {
+ switch (psa->sa.sa_family) {
+ case AF_INET:
+ plladdr = inet_ntoa(psa->sin.sin_addr);
+ break;
+ case AF_LINK:
+ if (psa->sdl.sdl_type == IFT_ETHER)
+ plladdr = ether_ntoa((struct ether_addr *)&psa->sdl.sdl_data);
+ else
+ plladdr = link_ntoa(&psa->sdl);
+ break;
+ }
+ } else
+ plladdr = "<none>";
+
+ /* Interface upon which the membership exists */
+ psa = (sockunion_t *)ifma->ifma_name;
+ switch (psa->sa.sa_family) {
+ case AF_LINK:
+ strlcpy(myifname, link_ntoa(&psa->sdl),
+ MYIFNAME_SIZE);
+ pcolon = strchr(myifname, ':');
+ if (pcolon)
+ *pcolon = '\0';
+ pifname = myifname;
+ break;
+ default:
+ pifname = "";
+ break;
+ }
+
+ fprintf(stdout, "%-20s\t%-16s\t%s\n", pgroup, plladdr, pifname);
+ }
+
+ freeifmaddrs(ifmap);
+}
diff --git a/usr.bin/netstat/mroute.c b/usr.bin/netstat/mroute.c
new file mode 100644
index 000000000000..e81ca2bd3821
--- /dev/null
+++ b/usr.bin/netstat/mroute.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 1989 Stephen Deering
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Stephen Deering of Stanford University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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.
+ *
+ * @(#)mroute.c 8.2 (Berkeley) 4/28/95
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Print multicast routing structures and statistics.
+ *
+ * MROUTING 1.0
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+#include <sys/protosw.h>
+#include <sys/mbuf.h>
+#include <sys/time.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/igmp.h>
+#include <net/route.h>
+#include <netinet/ip_mroute.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "netstat.h"
+
+static void print_bw_meter(struct bw_meter *bw_meter, int *banner_printed);
+
+void
+mroutepr(u_long mfcaddr, u_long vifaddr)
+{
+ struct mfc *mfctable[MFCTBLSIZ];
+ struct vif viftable[MAXVIFS];
+ struct mfc mfc, *m;
+ struct vif *v;
+ vifi_t vifi;
+ int i;
+ int banner_printed;
+ int saved_numeric_addr;
+ vifi_t maxvif = 0;
+ size_t len;
+
+ len = sizeof(mfctable);
+ if (sysctlbyname("net.inet.ip.mfctable", mfctable, &len, NULL, 0) < 0) {
+ warn("sysctl: net.inet.ip.mfctable");
+ /* Compatability with older kernels - candidate for removal */
+ if (mfcaddr == 0) {
+ printf("No IPv4 multicast routing compiled into this system.\n");
+ return;
+ }
+
+ kread(mfcaddr, (char *)mfctable, sizeof(mfctable));
+ }
+
+ len = sizeof(viftable);
+ if (sysctlbyname("net.inet.ip.viftable", viftable, &len, NULL, 0) < 0) {
+ warn("sysctl: net.inet.ip.viftable");
+ /* Compatability with older kernels - candidate for removal */
+ if (vifaddr == 0) {
+ printf("No IPv4 multicast routing compiled into this system.\n");
+ return;
+ }
+
+ kread(vifaddr, (char *)viftable, sizeof(viftable));
+ }
+
+ saved_numeric_addr = numeric_addr;
+ numeric_addr = 1;
+
+ banner_printed = 0;
+ for (vifi = 0, v = viftable; vifi < MAXVIFS; ++vifi, ++v) {
+ if (v->v_lcl_addr.s_addr == 0)
+ continue;
+
+ maxvif = vifi;
+ if (!banner_printed) {
+ printf("\nVirtual Interface Table\n"
+ " Vif Thresh Rate Local-Address "
+ "Remote-Address Pkts-In Pkts-Out\n");
+ banner_printed = 1;
+ }
+
+ printf(" %2u %6u %4d %-15.15s",
+ /* opposite math of add_vif() */
+ vifi, v->v_threshold, v->v_rate_limit * 1000 / 1024,
+ routename(v->v_lcl_addr.s_addr));
+ printf(" %-15.15s", (v->v_flags & VIFF_TUNNEL) ?
+ routename(v->v_rmt_addr.s_addr) : "");
+
+ printf(" %9lu %9lu\n", v->v_pkt_in, v->v_pkt_out);
+ }
+ if (!banner_printed)
+ printf("\nVirtual Interface Table is empty\n");
+
+ banner_printed = 0;
+ for (i = 0; i < MFCTBLSIZ; ++i) {
+ m = mfctable[i];
+ while(m) {
+ kread((u_long)m, (char *)&mfc, sizeof mfc);
+
+ if (!banner_printed) {
+ printf("\nIPv4 Multicast Forwarding Cache\n"
+ " Origin Group "
+ " Packets In-Vif Out-Vifs:Ttls\n");
+ banner_printed = 1;
+ }
+
+ printf(" %-15.15s", routename(mfc.mfc_origin.s_addr));
+ printf(" %-15.15s", routename(mfc.mfc_mcastgrp.s_addr));
+ printf(" %9lu", mfc.mfc_pkt_cnt);
+ printf(" %3d ", mfc.mfc_parent);
+ for (vifi = 0; vifi <= maxvif; vifi++) {
+ if (mfc.mfc_ttls[vifi] > 0)
+ printf(" %u:%u", vifi,
+ mfc.mfc_ttls[vifi]);
+ }
+ printf("\n");
+
+ /* Print the bw meter information */
+ {
+ struct bw_meter bw_meter, *bwm;
+ int banner_printed2 = 0;
+
+ bwm = mfc.mfc_bw_meter;
+ while (bwm) {
+ kread((u_long)bwm, (char *)&bw_meter,
+ sizeof bw_meter);
+ print_bw_meter(&bw_meter,
+ &banner_printed2);
+ bwm = bw_meter.bm_mfc_next;
+ }
+#if 0 /* Don't ever print it? */
+ if (! banner_printed2)
+ printf("\n No Bandwidth Meters\n");
+#endif
+ }
+
+ m = mfc.mfc_next;
+ }
+ }
+ if (!banner_printed)
+ printf("\nMulticast Routing Table is empty\n");
+
+ printf("\n");
+ numeric_addr = saved_numeric_addr;
+}
+
+static void
+print_bw_meter(struct bw_meter *bw_meter, int *banner_printed)
+{
+ char s0[256], s1[256], s2[256], s3[256];
+ struct timeval now, end, delta;
+
+ gettimeofday(&now, NULL);
+
+ if (! *banner_printed) {
+ printf(" Bandwidth Meters\n");
+ printf(" %-30s", "Measured(Start|Packets|Bytes)");
+ printf(" %s", "Type");
+ printf(" %-30s", "Thresh(Interval|Packets|Bytes)");
+ printf(" Remain");
+ printf("\n");
+ *banner_printed = 1;
+ }
+
+ /* The measured values */
+ if (bw_meter->bm_flags & BW_METER_UNIT_PACKETS)
+ sprintf(s1, "%llu", bw_meter->bm_measured.b_packets);
+ else
+ sprintf(s1, "?");
+ if (bw_meter->bm_flags & BW_METER_UNIT_BYTES)
+ sprintf(s2, "%llu", bw_meter->bm_measured.b_bytes);
+ else
+ sprintf(s2, "?");
+ sprintf(s0, "%lu.%lu|%s|%s",
+ bw_meter->bm_start_time.tv_sec,
+ bw_meter->bm_start_time.tv_usec,
+ s1, s2);
+ printf(" %-30s", s0);
+
+ /* The type of entry */
+ sprintf(s0, "%s", "?");
+ if (bw_meter->bm_flags & BW_METER_GEQ)
+ sprintf(s0, "%s", ">=");
+ else if (bw_meter->bm_flags & BW_METER_LEQ)
+ sprintf(s0, "%s", "<=");
+ printf(" %-3s", s0);
+
+ /* The threshold values */
+ if (bw_meter->bm_flags & BW_METER_UNIT_PACKETS)
+ sprintf(s1, "%llu", bw_meter->bm_threshold.b_packets);
+ else
+ sprintf(s1, "?");
+ if (bw_meter->bm_flags & BW_METER_UNIT_BYTES)
+ sprintf(s2, "%llu", bw_meter->bm_threshold.b_bytes);
+ else
+ sprintf(s2, "?");
+ sprintf(s0, "%lu.%lu|%s|%s",
+ bw_meter->bm_threshold.b_time.tv_sec,
+ bw_meter->bm_threshold.b_time.tv_usec,
+ s1, s2);
+ printf(" %-30s", s0);
+
+ /* Remaining time */
+ timeradd(&bw_meter->bm_start_time,
+ &bw_meter->bm_threshold.b_time, &end);
+ if (timercmp(&now, &end, <=)) {
+ timersub(&end, &now, &delta);
+ sprintf(s3, "%lu.%lu", delta.tv_sec, delta.tv_usec);
+ } else {
+ /* Negative time */
+ timersub(&now, &end, &delta);
+ sprintf(s3, "-%lu.%lu", delta.tv_sec, delta.tv_usec);
+ }
+ printf(" %s", s3);
+
+ printf("\n");
+}
+
+void
+mrt_stats(u_long mstaddr)
+{
+ struct mrtstat mrtstat;
+ size_t len = sizeof mrtstat;
+
+ if (sysctlbyname("net.inet.ip.mrtstat", &mrtstat, &len,
+ NULL, 0) < 0) {
+ warn("sysctl: net.inet.ip.mrtstat");
+ /* Compatability with older kernels - candidate for removal */
+ if (mstaddr == 0) {
+ printf("No IPv4 multicast routing compiled into this system.\n");
+ return;
+ }
+
+ kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat));
+ }
+ printf("IPv4 multicast forwarding:\n");
+
+#define p(f, m) if (mrtstat.f || sflag <= 1) \
+ printf(m, mrtstat.f, plural(mrtstat.f))
+#define p2(f, m) if (mrtstat.f || sflag <= 1) \
+ printf(m, mrtstat.f, plurales(mrtstat.f))
+
+ p(mrts_mfc_lookups, "\t%lu multicast forwarding cache lookup%s\n");
+ p2(mrts_mfc_misses, "\t%lu multicast forwarding cache miss%s\n");
+ p(mrts_upcalls, "\t%lu upcall%s to mrouted\n");
+ p(mrts_upq_ovflw, "\t%lu upcall queue overflow%s\n");
+ p(mrts_upq_sockfull,
+ "\t%lu upcall%s dropped due to full socket buffer\n");
+ p(mrts_cache_cleanups, "\t%lu cache cleanup%s\n");
+ p(mrts_no_route, "\t%lu datagram%s with no route for origin\n");
+ p(mrts_bad_tunnel, "\t%lu datagram%s arrived with bad tunneling\n");
+ p(mrts_cant_tunnel, "\t%lu datagram%s could not be tunneled\n");
+ p(mrts_wrong_if, "\t%lu datagram%s arrived on wrong interface\n");
+ p(mrts_drop_sel, "\t%lu datagram%s selectively dropped\n");
+ p(mrts_q_overflow, "\t%lu datagram%s dropped due to queue overflow\n");
+ p(mrts_pkt2large, "\t%lu datagram%s dropped for being too large\n");
+
+#undef p2
+#undef p
+}
diff --git a/usr.bin/netstat/mroute6.c b/usr.bin/netstat/mroute6.c
new file mode 100644
index 000000000000..bc06a3d6c30d
--- /dev/null
+++ b/usr.bin/netstat/mroute6.c
@@ -0,0 +1,235 @@
+/*
+ * 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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.
+ */
+
+/*
+ * Copyright (c) 1989 Stephen Deering
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Stephen Deering of Stanford University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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.
+ *
+ * @(#)mroute.c 8.2 (Berkeley) 4/28/95
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef INET6
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+
+#include <stdio.h>
+
+#define KERNEL 1
+#include <netinet6/ip6_mroute.h>
+#undef KERNEL
+
+#include "netstat.h"
+
+#define WID_ORG (Wflag ? 39 : (numeric_addr ? 29 : 18)) /* width of origin column */
+#define WID_GRP (Wflag ? 18 : (numeric_addr ? 16 : 18)) /* width of group column */
+
+void
+mroute6pr(u_long mfcaddr, u_long mifaddr)
+{
+ struct mf6c *mf6ctable[MF6CTBLSIZ], *mfcp;
+ struct mif6 mif6table[MAXMIFS];
+ struct mf6c mfc;
+ struct rtdetq rte, *rtep;
+ struct mif6 *mifp;
+ mifi_t mifi;
+ int i;
+ int banner_printed;
+ int saved_numeric_addr;
+ mifi_t maxmif = 0;
+ long int waitings;
+
+ if (mfcaddr == 0 || mifaddr == 0) {
+ printf("No IPv6 multicast routing compiled into this"
+ " system.\n");
+ return;
+ }
+
+ saved_numeric_addr = numeric_addr;
+ numeric_addr = 1;
+
+ kread(mifaddr, (char *)&mif6table, sizeof(mif6table));
+ banner_printed = 0;
+ for (mifi = 0, mifp = mif6table; mifi < MAXMIFS; ++mifi, ++mifp) {
+ struct ifnet ifnet;
+ char ifname[IFNAMSIZ];
+
+ if (mifp->m6_ifp == NULL)
+ continue;
+
+ kread((u_long)mifp->m6_ifp, (char *)&ifnet, sizeof(ifnet));
+ maxmif = mifi;
+ if (!banner_printed) {
+ printf("\nIPv6 Multicast Interface Table\n"
+ " Mif Rate PhyIF "
+ "Pkts-In Pkts-Out\n");
+ banner_printed = 1;
+ }
+
+ printf(" %2u %4d",
+ mifi, mifp->m6_rate_limit);
+ printf(" %5s", (mifp->m6_flags & MIFF_REGISTER) ?
+ "reg0" : if_indextoname(ifnet.if_index, ifname));
+
+ printf(" %9llu %9llu\n", (unsigned long long)mifp->m6_pkt_in,
+ (unsigned long long)mifp->m6_pkt_out);
+ }
+ if (!banner_printed)
+ printf("\nIPv6 Multicast Interface Table is empty\n");
+
+ kread(mfcaddr, (char *)&mf6ctable, sizeof(mf6ctable));
+ banner_printed = 0;
+ for (i = 0; i < MF6CTBLSIZ; ++i) {
+ mfcp = mf6ctable[i];
+ while(mfcp) {
+ kread((u_long)mfcp, (char *)&mfc, sizeof(mfc));
+ if (!banner_printed) {
+ printf ("\nIPv6 Multicast Forwarding Cache\n");
+ printf(" %-*.*s %-*.*s %s",
+ WID_ORG, WID_ORG, "Origin",
+ WID_GRP, WID_GRP, "Group",
+ " Packets Waits In-Mif Out-Mifs\n");
+ banner_printed = 1;
+ }
+
+ printf(" %-*.*s", WID_ORG, WID_ORG,
+ routename6(&mfc.mf6c_origin));
+ printf(" %-*.*s", WID_GRP, WID_GRP,
+ routename6(&mfc.mf6c_mcastgrp));
+ printf(" %9llu", (unsigned long long)mfc.mf6c_pkt_cnt);
+
+ for (waitings = 0, rtep = mfc.mf6c_stall; rtep; ) {
+ waitings++;
+ kread((u_long)rtep, (char *)&rte, sizeof(rte));
+ rtep = rte.next;
+ }
+ printf(" %3ld", waitings);
+
+ if (mfc.mf6c_parent == MF6C_INCOMPLETE_PARENT)
+ printf(" --- ");
+ else
+ printf(" %3d ", mfc.mf6c_parent);
+ for (mifi = 0; mifi <= maxmif; mifi++) {
+ if (IF_ISSET(mifi, &mfc.mf6c_ifset))
+ printf(" %u", mifi);
+ }
+ printf("\n");
+
+ mfcp = mfc.mf6c_next;
+ }
+ }
+ if (!banner_printed)
+ printf("\nIPv6 Multicast Routing Table is empty\n");
+
+ printf("\n");
+ numeric_addr = saved_numeric_addr;
+}
+
+void
+mrt6_stats(u_long mstaddr)
+{
+ struct mrt6stat mrtstat;
+
+ if (mstaddr == 0) {
+ printf("No IPv6 multicast routing compiled into this"
+ " system.\n");
+ return;
+ }
+
+ kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat));
+ printf("IPv6 multicast forwarding:\n");
+
+#define p(f, m) if (mrtstat.f || sflag <= 1) \
+ printf(m, (unsigned long long)mrtstat.f, plural(mrtstat.f))
+#define p2(f, m) if (mrtstat.f || sflag <= 1) \
+ printf(m, (unsigned long long)mrtstat.f, plurales(mrtstat.f))
+
+ p(mrt6s_mfc_lookups, "\t%llu multicast forwarding cache lookup%s\n");
+ p2(mrt6s_mfc_misses, "\t%llu multicast forwarding cache miss%s\n");
+ p(mrt6s_upcalls, "\t%llu upcall%s to mrouted\n");
+ p(mrt6s_upq_ovflw, "\t%llu upcall queue overflow%s\n");
+ p(mrt6s_upq_sockfull,
+ "\t%llu upcall%s dropped due to full socket buffer\n");
+ p(mrt6s_cache_cleanups, "\t%llu cache cleanup%s\n");
+ p(mrt6s_no_route, "\t%llu datagram%s with no route for origin\n");
+ p(mrt6s_bad_tunnel, "\t%llu datagram%s arrived with bad tunneling\n");
+ p(mrt6s_cant_tunnel, "\t%llu datagram%s could not be tunneled\n");
+ p(mrt6s_wrong_if, "\t%llu datagram%s arrived on wrong interface\n");
+ p(mrt6s_drop_sel, "\t%llu datagram%s selectively dropped\n");
+ p(mrt6s_q_overflow,
+ "\t%llu datagram%s dropped due to queue overflow\n");
+ p(mrt6s_pkt2large, "\t%llu datagram%s dropped for being too large\n");
+
+#undef p2
+#undef p
+}
+#endif /*INET6*/
diff --git a/usr.bin/netstat/netgraph.c b/usr.bin/netstat/netgraph.c
new file mode 100644
index 000000000000..e156989155c5
--- /dev/null
+++ b/usr.bin/netstat/netgraph.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 1996-1999 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+#include <sys/linker.h>
+
+#include <net/route.h>
+
+#include <netgraph.h>
+#include <netgraph/ng_message.h>
+#include <netgraph/ng_socket.h>
+#include <netgraph/ng_socketvar.h>
+
+#include <nlist.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+#include "netstat.h"
+
+static int first = 1;
+static int csock = -1;
+
+void
+netgraphprotopr(u_long off, const char *name, int af1 __unused)
+{
+ struct ngpcb *this, *next;
+ struct ngpcb ngpcb;
+ struct ngsock info;
+ struct socket sockb;
+ int debug = 1;
+
+ /* If symbol not found, try looking in the KLD module */
+ if (off == 0) {
+ const char *const modname = "ng_socket.ko";
+/* XXX We should get "mpath" from "sysctl kern.module_path" */
+ const char *mpath[] = { "/", "/boot/", "/modules/", NULL };
+ struct nlist sym[] = { { "_ngsocklist" }, { NULL } };
+ const char **pre;
+ struct kld_file_stat ks;
+ int fileid;
+
+ /* See if module is loaded */
+ if ((fileid = kldfind(modname)) < 0) {
+ if (debug)
+ warn("kldfind(%s)", modname);
+ return;
+ }
+
+ /* Get module info */
+ memset(&ks, 0, sizeof(ks));
+ ks.version = sizeof(struct kld_file_stat);
+ if (kldstat(fileid, &ks) < 0) {
+ if (debug)
+ warn("kldstat(%d)", fileid);
+ return;
+ }
+
+ /* Get symbol table from module file */
+ for (pre = mpath; *pre; pre++) {
+ char path[MAXPATHLEN];
+
+ snprintf(path, sizeof(path), "%s%s", *pre, modname);
+ if (nlist(path, sym) == 0)
+ break;
+ }
+
+ /* Did we find it? */
+ if (sym[0].n_value == 0) {
+ if (debug)
+ warnx("%s not found", modname);
+ return;
+ }
+
+ /* Symbol found at load address plus symbol offset */
+ off = (u_long) ks.address + sym[0].n_value;
+ }
+
+ /* Get pointer to first socket */
+ kread(off, (char *)&this, sizeof(this));
+
+ /* Get my own socket node */
+ if (csock == -1)
+ NgMkSockNode(NULL, &csock, NULL);
+
+ for (; this != NULL; this = next) {
+ u_char rbuf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
+ struct ng_mesg *resp = (struct ng_mesg *) rbuf;
+ struct nodeinfo *ni = (struct nodeinfo *) resp->data;
+ char path[64];
+
+ /* Read in ngpcb structure */
+ kread((u_long)this, (char *)&ngpcb, sizeof(ngpcb));
+ next = LIST_NEXT(&ngpcb, socks);
+
+ /* Read in socket structure */
+ kread((u_long)ngpcb.ng_socket, (char *)&sockb, sizeof(sockb));
+
+ /* Check type of socket */
+ if (strcmp(name, "ctrl") == 0 && ngpcb.type != NG_CONTROL)
+ continue;
+ if (strcmp(name, "data") == 0 && ngpcb.type != NG_DATA)
+ continue;
+
+ /* Do headline */
+ if (first) {
+ printf("Netgraph sockets\n");
+ if (Aflag)
+ printf("%-8.8s ", "PCB");
+ printf("%-5.5s %-6.6s %-6.6s %-14.14s %s\n",
+ "Type", "Recv-Q", "Send-Q",
+ "Node Address", "#Hooks");
+ first = 0;
+ }
+
+ /* Show socket */
+ if (Aflag)
+ printf("%8lx ", (u_long) this);
+ printf("%-5.5s %6u %6u ",
+ name, sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc);
+
+ /* Get ngsock structure */
+ if (ngpcb.sockdata == 0) /* unconnected data socket */
+ goto finish;
+ kread((u_long)ngpcb.sockdata, (char *)&info, sizeof(info));
+
+ /* Get info on associated node */
+ if (info.node == 0 || csock == -1)
+ goto finish;
+ snprintf(path, sizeof(path), "[%lx]:", (u_long) info.node);
+ if (NgSendMsg(csock, path,
+ NGM_GENERIC_COOKIE, NGM_NODEINFO, NULL, 0) < 0)
+ goto finish;
+ if (NgRecvMsg(csock, resp, sizeof(rbuf), NULL) < 0)
+ goto finish;
+
+ /* Display associated node info */
+ if (*ni->name != '\0')
+ snprintf(path, sizeof(path), "%s:", ni->name);
+ printf("%-14.14s %4d", path, ni->hooks);
+finish:
+ putchar('\n');
+ }
+}
+
diff --git a/usr.bin/netstat/netstat.1 b/usr.bin/netstat/netstat.1
new file mode 100644
index 000000000000..32edfec3e537
--- /dev/null
+++ b/usr.bin/netstat/netstat.1
@@ -0,0 +1,441 @@
+.\" Copyright (c) 1983, 1990, 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University 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 REGENTS 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
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" 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.
+.\"
+.\" @(#)netstat.1 8.8 (Berkeley) 4/18/94
+.\" $FreeBSD$
+.\"
+.Dd March 25, 2004
+.Dt NETSTAT 1
+.Os
+.Sh NAME
+.Nm netstat
+.Nd show network status
+.Sh DESCRIPTION
+The
+.Nm
+command symbolically displays the contents of various network-related
+data structures.
+There are a number of output formats,
+depending on the options for the information presented.
+.Bl -tag -width indent
+.It Xo
+.Bk -words
+.Nm
+.Op Fl AaLnSW
+.Op Fl f Ar protocol_family | Fl p Ar protocol
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Ek
+.Xc
+Display a list of active sockets
+(protocol control blocks)
+for each network protocol,
+for a particular
+.Ar protocol_family ,
+or for a single
+.Ar protocol .
+If
+.Fl A
+is also present,
+show the address of a protocol control block (PCB)
+associated with a socket; used for debugging.
+If
+.Fl a
+is also present,
+show the state of all sockets;
+normally sockets used by server processes are not shown.
+If
+.Fl L
+is also present,
+show the size of the various listen queues.
+The first count shows the number of unaccepted connections,
+the second count shows the amount of unaccepted incomplete connections,
+and the third count is the maximum number of queued connections.
+If
+.Fl S
+is also present,
+show network addresses as numbers (as with
+.Fl n )
+but show ports symbolically.
+.It Xo
+.Bk -words
+.Nm
+.Fl i | I Ar interface
+.Op Fl abdnt
+.Op Fl f Ar address_family
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Ek
+.Xc
+Show the state of all network interfaces or a single
+.Ar interface
+which have been auto-configured
+(interfaces statically configured into a system, but not
+located at boot time are not shown).
+An asterisk
+.Pq Dq Li *
+after an interface name indicates that the interface is
+.Dq down .
+If
+.Fl a
+is also present, multicast addresses currently in use are shown
+for each Ethernet interface and for each IP interface address.
+Multicast addresses are shown on separate lines following the interface
+address with which they are associated.
+If
+.Fl b
+is also present, show the number of bytes in and out.
+If
+.Fl d
+is also present, show the number of dropped packets.
+If
+.Fl t
+is also present, show the contents of watchdog timers.
+If
+.Fl W
+is also present, print interface names using a wider field size.
+.It Xo
+.Bk -words
+.Nm
+.Fl w Ar wait
+.Op Fl I Ar interface
+.Op Fl d
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Ek
+.Xc
+At intervals of
+.Ar wait
+seconds,
+display the information regarding packet
+traffic on all configured network interfaces
+or a single
+.Ar interface .
+If
+.Fl d
+is also present, show the number of dropped packets.
+.It Xo
+.Bk -words
+.Nm
+.Fl s Op Fl s
+.Op Fl z
+.Op Fl f Ar protocol_family | Fl p Ar protocol
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Ek
+.Xc
+Display system-wide statistics for each network protocol,
+for a particular
+.Ar protocol_family ,
+or for a single
+.Ar protocol .
+If
+.Fl s
+is repeated, counters with a value of zero are suppressed.
+If
+.Fl z
+is also present, reset statistic counters after displaying them.
+.It Xo
+.Bk -words
+.Nm
+.Fl i | I Ar interface Fl s
+.Op Fl f Ar protocol_family | Fl p Ar protocol
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Ek
+.Xc
+Display per-interface statistics for each network protocol,
+for a particular
+.Ar protocol_family ,
+or for a single
+.Ar protocol .
+.It Xo
+.Bk -words
+.Nm
+.Fl m
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Ek
+.Xc
+Show statistics recorded by the memory management routines
+.Pq Xr mbuf 9 .
+The network manages a private pool of memory buffers.
+.It Xo
+.Bk -words
+.Nm
+.Fl r
+.Op Fl AanW
+.Op Fl f Ar address_family
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Ek
+.Xc
+Display the contents of all routing tables,
+or a routing table for a particular
+.Ar address_family .
+If
+.Fl A
+is also present,
+show the contents of the internal Patricia tree
+structures; used for debugging.
+If
+.Fl a
+is also present,
+show protocol-cloned routes
+(routes generated by an
+.Dv RTF_PRCLONING
+parent route);
+normally these routes are not shown.
+When
+.Fl W
+is also present,
+show the path MTU
+for each route,
+and print interface
+names with a wider
+field size.
+.It Xo
+.Bk -words
+.Nm
+.Fl rs
+.Op Fl s
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Ek
+.Xc
+Display routing statistics.
+If
+.Fl s
+is repeated, counters with a value of zero are suppressed.
+.It Xo
+.Bk -words
+.Nm
+.Fl g
+.Op Fl W
+.Op Fl f Ar address_family
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Ek
+.Xc
+Show information related to multicast (group address) routing.
+By default, show the IP Multicast virtual-interface and routing tables,
+and multicast group memberships.
+.It Xo
+.Bk -words
+.Nm
+.Fl gs
+.Op Fl s
+.Op Fl f Ar address_family
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Ek
+.Xc
+Show multicast routing statistics.
+If
+.Fl s
+is repeated, counters with a value of zero are suppressed.
+.El
+.Pp
+Some options have the general meaning:
+.Bl -tag -width flag
+.It Fl f Ar address_family , Fl p Ar protocol
+Limit display to those records
+of the specified
+.Ar address_family
+or a single
+.Ar protocol .
+The following address families and protocols are recognized:
+.Pp
+.Bl -tag -width ".Cm netgraph , ng Pq Dv AF_NETGRAPH" -compact
+.It Em Family
+.Em Protocols
+.It Cm inet Pq Dv AF_INET
+.Cm bdg , divert , icmp , igmp , ip , ipsec , pim, tcp , udp
+.It Cm inet6 Pq Dv AF_INET6
+.Cm bdg , icmp6 , ip6 , ipsec6 , rip6 , tcp , udp
+.It Cm pfkey Pq Dv PF_KEY
+.Cm pfkey
+.It Cm atalk Pq Dv AF_APPLETALK
+.Cm ddp
+.It Cm netgraph , ng Pq Dv AF_NETGRAPH
+.Cm ctrl , data
+.It Cm ipx Pq Dv AF_IPX
+.Cm ipx , spx
+.\".It Cm ns Pq Dv AF_NS
+.\".Cm idp , ns_err , spp
+.\".It Cm iso Pq Dv AF_ISO
+.\".Cm clnp , cltp , esis , tp
+.It Cm unix Pq Dv AF_UNIX
+.It Cm link Pq Dv AF_LINK
+.El
+.Pp
+The program will complain if
+.Ar protocol
+is unknown or if there is no statistics routine for it.
+.It Fl M
+Extract values associated with the name list from the specified core
+instead of the default
+.Pa /dev/kmem .
+.It Fl N
+Extract the name list from the specified system instead of the default,
+which is the kernel image the system has booted from.
+.It Fl n
+Show network addresses and ports as numbers.
+Normally
+.Nm
+attempts to resolve addresses and ports,
+and display them symbolically.
+.It Fl W
+In certain displays, avoid truncating addresses even if this causes
+some fields to overflow.
+.El
+.Pp
+The default display, for active sockets, shows the local
+and remote addresses, send and receive queue sizes (in bytes), protocol,
+and the internal state of the protocol.
+Address formats are of the form
+.Dq host.port
+or
+.Dq network.port
+if a socket's address specifies a network but no specific host address.
+When known, the host and network addresses are displayed symbolically
+according to the databases
+.Xr hosts 5
+and
+.Xr networks 5 ,
+respectively.
+If a symbolic name for an address is unknown, or if
+the
+.Fl n
+option is specified, the address is printed numerically, according
+to the address family.
+For more information regarding
+the Internet IPv4
+.Dq dot format ,
+refer to
+.Xr inet 3 .
+Unspecified,
+or
+.Dq wildcard ,
+addresses and ports appear as
+.Dq Li * .
+.Pp
+The interface display provides a table of cumulative
+statistics regarding packets transferred, errors, and collisions.
+The network addresses of the interface
+and the maximum transmission unit
+.Pq Dq mtu
+are also displayed.
+.Pp
+The routing table display indicates the available routes and their status.
+Each route consists of a destination host or network, and a gateway to use
+in forwarding packets.
+The flags field shows a collection of information about the route stored
+as binary choices.
+The individual flags are discussed in more detail in the
+.Xr route 8
+and
+.Xr route 4
+manual pages.
+The mapping between letters and flags is:
+.Bl -column ".Li W" ".Dv RTF_WASCLONED"
+.It Li 1 Ta Dv RTF_PROTO1 Ta "Protocol specific routing flag #1"
+.It Li 2 Ta Dv RTF_PROTO2 Ta "Protocol specific routing flag #2"
+.It Li 3 Ta Dv RTF_PROTO3 Ta "Protocol specific routing flag #3"
+.It Li B Ta Dv RTF_BLACKHOLE Ta "Just discard pkts (during updates)"
+.It Li b Ta Dv RTF_BROADCAST Ta "The route represents a broadcast address"
+.It Li C Ta Dv RTF_CLONING Ta "Generate new routes on use"
+.It Li c Ta Dv RTF_PRCLONING Ta "Protocol-specified generate new routes on use"
+.It Li D Ta Dv RTF_DYNAMIC Ta "Created dynamically (by redirect)"
+.It Li G Ta Dv RTF_GATEWAY Ta "Destination requires forwarding by intermediary"
+.It Li H Ta Dv RTF_HOST Ta "Host entry (net otherwise)"
+.It Li L Ta Dv RTF_LLINFO Ta "Valid protocol to link address translation"
+.It Li M Ta Dv RTF_MODIFIED Ta "Modified dynamically (by redirect)"
+.It Li R Ta Dv RTF_REJECT Ta "Host or net unreachable"
+.It Li S Ta Dv RTF_STATIC Ta "Manually added"
+.It Li U Ta Dv RTF_UP Ta "Route usable"
+.It Li W Ta Dv RTF_WASCLONED Ta "Route was generated as a result of cloning"
+.It Li X Ta Dv RTF_XRESOLVE Ta "External daemon translates proto to link address"
+.El
+.Pp
+Direct routes are created for each
+interface attached to the local host;
+the gateway field for such entries shows the address of the outgoing interface.
+The refcnt field gives the
+current number of active uses of the route.
+Connection oriented
+protocols normally hold on to a single route for the duration of
+a connection while connectionless protocols obtain a route while sending
+to the same destination.
+The use field provides a count of the number of packets
+sent using that route.
+The interface entry indicates the network interface utilized for the route.
+.Pp
+When
+.Nm
+is invoked with the
+.Fl w
+option and a
+.Ar wait
+interval argument, it displays a running count of statistics related to
+network interfaces.
+An obsolescent version of this option used a numeric parameter
+with no option, and is currently supported for backward compatibility.
+By default, this display summarizes information for all interfaces.
+Information for a specific interface may be displayed with the
+.Fl I
+option.
+.Sh SEE ALSO
+.Xr fstat 1 ,
+.Xr nfsstat 1 ,
+.Xr ps 1 ,
+.Xr sockstat 1 ,
+.Xr inet 4 ,
+.Xr route 4 ,
+.Xr unix 4 ,
+.Xr hosts 5 ,
+.Xr networks 5 ,
+.Xr protocols 5 ,
+.Xr services 5 ,
+.Xr iostat 8 ,
+.Xr route 8 ,
+.Xr trpt 8 ,
+.Xr vmstat 8 ,
+.Xr mbuf 9
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
+.Pp
+IPv6 support was added by WIDE/KAME project.
+.Sh BUGS
+The notion of errors is ill-defined.
diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h
new file mode 100644
index 000000000000..e2b3f291a6e5
--- /dev/null
+++ b/usr.bin/netstat/netstat.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 1992, 1993
+ * Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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.
+ *
+ * @(#)netstat.h 8.2 (Berkeley) 1/4/94
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+
+extern int Aflag; /* show addresses of protocol control block */
+extern int aflag; /* show all sockets (including servers) */
+extern int bflag; /* show i/f total bytes in/out */
+extern int dflag; /* show i/f dropped packets */
+extern int gflag; /* show group (multicast) routing or stats */
+extern int iflag; /* show interfaces */
+extern int Lflag; /* show size of listen queues */
+extern int mflag; /* show memory stats */
+extern int numeric_addr; /* show addresses numerically */
+extern int numeric_port; /* show ports numerically */
+extern int rflag; /* show routing tables (or routing stats) */
+extern int sflag; /* show protocol statistics */
+extern int tflag; /* show i/f watchdog timers */
+extern int Wflag; /* wide display */
+extern int zflag; /* zero stats */
+
+extern int interval; /* repeat interval for i/f stats */
+
+extern char *interface; /* desired i/f for stats, or NULL for all i/fs */
+extern int unit; /* unit number for above */
+
+extern int af; /* address family */
+
+int kread(u_long addr, char *buf, int size);
+const char *plural(int);
+const char *plurales(int);
+const char *pluralies(int);
+
+void protopr(u_long, const char *, int);
+void tcp_stats(u_long, const char *, int);
+void udp_stats(u_long, const char *, int);
+void ip_stats(u_long, const char *, int);
+void icmp_stats(u_long, const char *, int);
+void igmp_stats(u_long, const char *, int);
+void pim_stats(u_long, const char *, int);
+#ifdef IPSEC
+void ipsec_stats(u_long, const char *, int);
+#endif
+
+#ifdef INET6
+void ip6_stats(u_long, const char *, int);
+void ip6_ifstats(char *);
+void icmp6_stats(u_long, const char *, int);
+void icmp6_ifstats(char *);
+void pim6_stats(u_long, const char *, int);
+void rip6_stats(u_long, const char *, int);
+void mroute6pr(u_long, u_long);
+void mrt6_stats(u_long);
+
+struct sockaddr_in6;
+struct in6_addr;
+char *routename6(struct sockaddr_in6 *);
+const char *netname6(struct sockaddr_in6 *, struct in6_addr *);
+void inet6print(struct in6_addr *, int, const char *, int);
+#endif /*INET6*/
+
+#ifdef IPSEC
+void pfkey_stats(u_long, const char *, int);
+#endif
+
+void bdg_stats(u_long, const char *, int);
+
+void mbpr(u_long, u_long, u_long, u_long, u_long, u_long,
+ u_long, u_long, u_long, u_long, u_long);
+
+void hostpr(u_long, u_long);
+void impstats(u_long, u_long);
+
+void intpr(int, u_long, void (*)(char *));
+
+void pr_rthdr(int);
+void pr_family(int);
+void rt_stats(u_long, u_long);
+char *ipx_pnet(struct sockaddr *);
+char *ipx_phost(struct sockaddr *);
+char *ns_phost(struct sockaddr *);
+void upHex(char *);
+
+char *routename(u_long);
+char *netname(u_long, u_long);
+char *atalk_print(struct sockaddr *, int);
+char *atalk_print2(struct sockaddr *, struct sockaddr *, int);
+char *ipx_print(struct sockaddr *);
+char *ns_print(struct sockaddr *);
+void routepr(u_long);
+
+void ipxprotopr(u_long, const char *, int);
+void spx_stats(u_long, const char *, int);
+void ipx_stats(u_long, const char *, int);
+void ipxerr_stats(u_long, const char *, int);
+
+void nsprotopr(u_long, const char *, int);
+void spp_stats(u_long, const char *, int);
+void idp_stats(u_long, const char *, int);
+void nserr_stats(u_long, const char *, int);
+
+void atalkprotopr(u_long, const char *, int);
+void ddp_stats(u_long, const char *, int);
+
+void netgraphprotopr(u_long, const char *, int);
+
+void unixpr(void);
+
+void esis_stats(u_long, const char *, int);
+void clnp_stats(u_long, const char *, int);
+void cltp_stats(u_long, const char *, int);
+void iso_protopr(u_long, const char *, int);
+void iso_protopr1(u_long, int);
+void tp_protopr(u_long, const char *, int);
+void tp_inproto(u_long);
+void tp_stats(caddr_t, caddr_t);
+
+void ifmalist_dump(void);
+void mroutepr(u_long, u_long);
+void mrt_stats(u_long);
diff --git a/usr.bin/netstat/route.c b/usr.bin/netstat/route.c
new file mode 100644
index 000000000000..585fd7eecae3
--- /dev/null
+++ b/usr.bin/netstat/route.c
@@ -0,0 +1,1125 @@
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "From: @(#)route.c 8.6 (Berkeley) 4/28/95";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/radix.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netipx/ipx.h>
+#include <netatalk/at.h>
+#include <netgraph/ng_socket.h>
+
+#include <sys/sysctl.h>
+
+#include <arpa/inet.h>
+#include <libutil.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+#include <time.h>
+#include "netstat.h"
+
+#define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d)))
+
+/*
+ * Definitions for showing gateway flags.
+ */
+struct bits {
+ u_long b_mask;
+ char b_val;
+} bits[] = {
+ { RTF_UP, 'U' },
+ { RTF_GATEWAY, 'G' },
+ { RTF_HOST, 'H' },
+ { RTF_REJECT, 'R' },
+ { RTF_DYNAMIC, 'D' },
+ { RTF_MODIFIED, 'M' },
+ { RTF_DONE, 'd' }, /* Completed -- for routing messages only */
+ { RTF_CLONING, 'C' },
+ { RTF_XRESOLVE, 'X' },
+ { RTF_LLINFO, 'L' },
+ { RTF_STATIC, 'S' },
+ { RTF_PROTO1, '1' },
+ { RTF_PROTO2, '2' },
+ { RTF_WASCLONED,'W' },
+ { RTF_PRCLONING,'c' },
+ { RTF_PROTO3, '3' },
+ { RTF_BLACKHOLE,'B' },
+ { RTF_BROADCAST,'b' },
+ { 0 , 0 }
+};
+
+typedef union {
+ long dummy; /* Helps align structure. */
+ struct sockaddr u_sa;
+ u_short u_data[128];
+} sa_u;
+
+static sa_u pt_u;
+
+int do_rtent = 0;
+struct rtentry rtentry;
+struct radix_node rnode;
+struct radix_mask rmask;
+struct radix_node_head *rt_tables[AF_MAX+1];
+
+int NewTree = 0;
+
+static struct sockaddr *kgetsa (struct sockaddr *);
+static void size_cols (int ef, struct radix_node *rn);
+static void size_cols_tree (struct radix_node *rn);
+static void size_cols_rtentry (struct rtentry *rt);
+static void p_tree (struct radix_node *);
+static void p_rtnode (void);
+static void ntreestuff (void);
+static void np_rtentry (struct rt_msghdr *);
+static void p_sockaddr (struct sockaddr *, struct sockaddr *, int, int);
+static const char *fmt_sockaddr (struct sockaddr *sa, struct sockaddr *mask,
+ int flags);
+static void p_flags (int, const char *);
+static const char *fmt_flags(int f);
+static void p_rtentry (struct rtentry *);
+static u_long forgemask (u_long);
+static void domask (char *, u_long, u_long);
+
+/*
+ * Print routing tables.
+ */
+void
+routepr(u_long rtree)
+{
+ struct radix_node_head *rnh, head;
+ int i;
+
+ printf("Routing tables\n");
+
+ if (Aflag == 0 && NewTree)
+ ntreestuff();
+ else {
+ if (rtree == 0) {
+ printf("rt_tables: symbol not in namelist\n");
+ return;
+ }
+
+ kget(rtree, rt_tables);
+ for (i = 0; i <= AF_MAX; i++) {
+ if ((rnh = rt_tables[i]) == 0)
+ continue;
+ kget(rnh, head);
+ if (i == AF_UNSPEC) {
+ if (Aflag && af == 0) {
+ printf("Netmasks:\n");
+ p_tree(head.rnh_treetop);
+ }
+ } else if (af == AF_UNSPEC || af == i) {
+ size_cols(i, head.rnh_treetop);
+ pr_family(i);
+ do_rtent = 1;
+ pr_rthdr(i);
+ p_tree(head.rnh_treetop);
+ }
+ }
+ }
+}
+
+/*
+ * Print address family header before a section of the routing table.
+ */
+void
+pr_family(int af1)
+{
+ const char *afname;
+
+ switch (af1) {
+ case AF_INET:
+ afname = "Internet";
+ break;
+#ifdef INET6
+ case AF_INET6:
+ afname = "Internet6";
+ break;
+#endif /*INET6*/
+ case AF_IPX:
+ afname = "IPX";
+ break;
+ case AF_ISO:
+ afname = "ISO";
+ break;
+ case AF_APPLETALK:
+ afname = "AppleTalk";
+ break;
+ case AF_CCITT:
+ afname = "X.25";
+ break;
+ case AF_NETGRAPH:
+ afname = "Netgraph";
+ break;
+ default:
+ afname = NULL;
+ break;
+ }
+ if (afname)
+ printf("\n%s:\n", afname);
+ else
+ printf("\nProtocol Family %d:\n", af1);
+}
+
+/* column widths; each followed by one space */
+#ifndef INET6
+#define WID_DST_DEFAULT(af) 18 /* width of destination column */
+#define WID_GW_DEFAULT(af) 18 /* width of gateway column */
+#define WID_IF_DEFAULT(af) (Wflag ? 8 : 6) /* width of netif column */
+#else
+#define WID_DST_DEFAULT(af) \
+ ((af) == AF_INET6 ? (numeric_addr ? 33: 18) : 18)
+#define WID_GW_DEFAULT(af) \
+ ((af) == AF_INET6 ? (numeric_addr ? 29 : 18) : 18)
+#define WID_IF_DEFAULT(af) ((af) == AF_INET6 ? 8 : (Wflag ? 8 : 6))
+#endif /*INET6*/
+
+static int wid_dst;
+static int wid_gw;
+static int wid_flags;
+static int wid_refs;
+static int wid_use;
+static int wid_mtu;
+static int wid_if;
+static int wid_expire;
+
+static void
+size_cols(int ef, struct radix_node *rn)
+{
+ wid_dst = WID_DST_DEFAULT(ef);
+ wid_gw = WID_GW_DEFAULT(ef);
+ wid_flags = 6;
+ wid_refs = 6;
+ wid_use = 8;
+ wid_mtu = 6;
+ wid_if = WID_IF_DEFAULT(ef);
+ wid_expire = 6;
+
+ if (Wflag)
+ size_cols_tree(rn);
+}
+
+static void
+size_cols_tree(struct radix_node *rn)
+{
+again:
+ kget(rn, rnode);
+ if (rnode.rn_bit < 0) {
+ if ((rnode.rn_flags & RNF_ROOT) == 0) {
+ kget(rn, rtentry);
+ size_cols_rtentry(&rtentry);
+ }
+ if ((rn = rnode.rn_dupedkey))
+ goto again;
+ } else {
+ rn = rnode.rn_right;
+ size_cols_tree(rnode.rn_left);
+ size_cols_tree(rn);
+ }
+}
+
+static void
+size_cols_rtentry(struct rtentry *rt)
+{
+ static struct ifnet ifnet, *lastif;
+ struct rtentry parent;
+ static char buffer[100];
+ const char *bp;
+ struct sockaddr *sa;
+ sa_u addr, mask;
+ int len;
+
+ /*
+ * Don't print protocol-cloned routes unless -a.
+ */
+ if (rt->rt_flags & RTF_WASCLONED && !aflag) {
+ kget(rt->rt_parent, parent);
+ if (parent.rt_flags & RTF_PRCLONING)
+ return;
+ }
+
+ bzero(&addr, sizeof(addr));
+ if ((sa = kgetsa(rt_key(rt))))
+ bcopy(sa, &addr, sa->sa_len);
+ bzero(&mask, sizeof(mask));
+ if (rt_mask(rt) && (sa = kgetsa(rt_mask(rt))))
+ bcopy(sa, &mask, sa->sa_len);
+ bp = fmt_sockaddr(&addr.u_sa, &mask.u_sa, rt->rt_flags);
+ len = strlen(bp);
+ wid_dst = MAX(len, wid_dst);
+
+ bp = fmt_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST);
+ len = strlen(bp);
+ wid_gw = MAX(len, wid_gw);
+
+ bp = fmt_flags(rt->rt_flags);
+ len = strlen(bp);
+ wid_flags = MAX(len, wid_flags);
+
+ if (addr.u_sa.sa_family == AF_INET || Wflag) {
+ len = snprintf(buffer, sizeof(buffer), "%ld", rt->rt_refcnt);
+ wid_refs = MAX(len, wid_refs);
+ len = snprintf(buffer, sizeof(buffer), "%lu", rt->rt_use);
+ wid_use = MAX(len, wid_use);
+ if (Wflag && rt->rt_rmx.rmx_mtu != 0) {
+ len = snprintf(buffer, sizeof(buffer),
+ "%lu", rt->rt_rmx.rmx_mtu);
+ wid_mtu = MAX(len, wid_mtu);
+ }
+ }
+ if (rt->rt_ifp) {
+ if (rt->rt_ifp != lastif) {
+ kget(rt->rt_ifp, ifnet);
+ lastif = rt->rt_ifp;
+ len = strlen(ifnet.if_xname);
+ wid_if = MAX(len, wid_if);
+ }
+ if (rt->rt_rmx.rmx_expire) {
+ time_t expire_time;
+
+ if ((expire_time =
+ rt->rt_rmx.rmx_expire - time(NULL)) > 0) {
+ len = snprintf(buffer, sizeof(buffer), "%d",
+ (int)expire_time);
+ wid_expire = MAX(len, wid_expire);
+ }
+ }
+ }
+}
+
+
+/*
+ * Print header for routing table columns.
+ */
+void
+pr_rthdr(int af1)
+{
+
+ if (Aflag)
+ printf("%-8.8s ","Address");
+ if (af1 == AF_INET || Wflag) {
+ if (Wflag) {
+ printf("%-*.*s %-*.*s %-*.*s %*.*s %*.*s %*.*s %*.*s %*s\n",
+ wid_dst, wid_dst, "Destination",
+ wid_gw, wid_gw, "Gateway",
+ wid_flags, wid_flags, "Flags",
+ wid_refs, wid_refs, "Refs",
+ wid_use, wid_use, "Use",
+ wid_mtu, wid_mtu, "Mtu",
+ wid_if, wid_if, "Netif",
+ wid_expire, "Expire");
+ } else {
+ printf("%-*.*s %-*.*s %-*.*s %*.*s %*.*s %*.*s %*s\n",
+ wid_dst, wid_dst, "Destination",
+ wid_gw, wid_gw, "Gateway",
+ wid_flags, wid_flags, "Flags",
+ wid_refs, wid_refs, "Refs",
+ wid_use, wid_use, "Use",
+ wid_if, wid_if, "Netif",
+ wid_expire, "Expire");
+ }
+ } else {
+ printf("%-*.*s %-*.*s %-*.*s %*.*s %*s\n",
+ wid_dst, wid_dst, "Destination",
+ wid_gw, wid_gw, "Gateway",
+ wid_flags, wid_flags, "Flags",
+ wid_if, wid_if, "Netif",
+ wid_expire, "Expire");
+ }
+}
+
+static struct sockaddr *
+kgetsa(struct sockaddr *dst)
+{
+
+ kget(dst, pt_u.u_sa);
+ if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa))
+ kread((u_long)dst, (char *)pt_u.u_data, pt_u.u_sa.sa_len);
+ return (&pt_u.u_sa);
+}
+
+static void
+p_tree(struct radix_node *rn)
+{
+
+again:
+ kget(rn, rnode);
+ if (rnode.rn_bit < 0) {
+ if (Aflag)
+ printf("%-8.8lx ", (u_long)rn);
+ if (rnode.rn_flags & RNF_ROOT) {
+ if (Aflag)
+ printf("(root node)%s",
+ rnode.rn_dupedkey ? " =>\n" : "\n");
+ } else if (do_rtent) {
+ kget(rn, rtentry);
+ p_rtentry(&rtentry);
+ if (Aflag)
+ p_rtnode();
+ } else {
+ p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key),
+ NULL, 0, 44);
+ putchar('\n');
+ }
+ if ((rn = rnode.rn_dupedkey))
+ goto again;
+ } else {
+ if (Aflag && do_rtent) {
+ printf("%-8.8lx ", (u_long)rn);
+ p_rtnode();
+ }
+ rn = rnode.rn_right;
+ p_tree(rnode.rn_left);
+ p_tree(rn);
+ }
+}
+
+char nbuf[20];
+
+static void
+p_rtnode(void)
+{
+ struct radix_mask *rm = rnode.rn_mklist;
+
+ if (rnode.rn_bit < 0) {
+ if (rnode.rn_mask) {
+ printf("\t mask ");
+ p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask),
+ NULL, 0, -1);
+ } else if (rm == 0)
+ return;
+ } else {
+ sprintf(nbuf, "(%d)", rnode.rn_bit);
+ printf("%6.6s %8.8lx : %8.8lx", nbuf, (u_long)rnode.rn_left, (u_long)rnode.rn_right);
+ }
+ while (rm) {
+ kget(rm, rmask);
+ sprintf(nbuf, " %d refs, ", rmask.rm_refs);
+ printf(" mk = %8.8lx {(%d),%s",
+ (u_long)rm, -1 - rmask.rm_bit, rmask.rm_refs ? nbuf : " ");
+ if (rmask.rm_flags & RNF_NORMAL) {
+ struct radix_node rnode_aux;
+ printf(" <normal>, ");
+ kget(rmask.rm_leaf, rnode_aux);
+ p_sockaddr(kgetsa((struct sockaddr *)rnode_aux.rn_mask),
+ NULL, 0, -1);
+ } else
+ p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask),
+ NULL, 0, -1);
+ putchar('}');
+ if ((rm = rmask.rm_mklist))
+ printf(" ->");
+ }
+ putchar('\n');
+}
+
+static void
+ntreestuff(void)
+{
+ size_t needed;
+ int mib[6];
+ char *buf, *next, *lim;
+ struct rt_msghdr *rtm;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_DUMP;
+ mib[5] = 0;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
+ err(1, "sysctl: net.route.0.0.dump estimate");
+ }
+
+ if ((buf = malloc(needed)) == 0) {
+ errx(2, "malloc(%lu)", (unsigned long)needed);
+ }
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+ err(1, "sysctl: net.route.0.0.dump");
+ }
+ lim = buf + needed;
+ for (next = buf; next < lim; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)next;
+ np_rtentry(rtm);
+ }
+}
+
+static void
+np_rtentry(struct rt_msghdr *rtm)
+{
+ struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
+#ifdef notdef
+ static int masks_done, banner_printed;
+#endif
+ static int old_af;
+ int af1 = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST;
+
+#ifdef notdef
+ /* for the moment, netmasks are skipped over */
+ if (!banner_printed) {
+ printf("Netmasks:\n");
+ banner_printed = 1;
+ }
+ if (masks_done == 0) {
+ if (rtm->rtm_addrs != RTA_DST ) {
+ masks_done = 1;
+ af1 = sa->sa_family;
+ }
+ } else
+#endif
+ af1 = sa->sa_family;
+ if (af1 != old_af) {
+ pr_family(af1);
+ old_af = af1;
+ }
+ if (rtm->rtm_addrs == RTA_DST)
+ p_sockaddr(sa, NULL, 0, 36);
+ else {
+ p_sockaddr(sa, NULL, rtm->rtm_flags, 16);
+ sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa);
+ p_sockaddr(sa, NULL, 0, 18);
+ }
+ p_flags(rtm->rtm_flags & interesting, "%-6.6s ");
+ putchar('\n');
+}
+
+static void
+p_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags, int width)
+{
+ const char *cp;
+
+ cp = fmt_sockaddr(sa, mask, flags);
+
+ if (width < 0 )
+ printf("%s ", cp);
+ else {
+ if (numeric_addr)
+ printf("%-*s ", width, cp);
+ else
+ printf("%-*.*s ", width, width, cp);
+ }
+}
+
+static const char *
+fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags)
+{
+ static char workbuf[128];
+ const char *cp;
+
+ switch(sa->sa_family) {
+ case AF_INET:
+ {
+ struct sockaddr_in *sockin = (struct sockaddr_in *)sa;
+
+ if ((sockin->sin_addr.s_addr == INADDR_ANY) &&
+ mask &&
+ ntohl(((struct sockaddr_in *)mask)->sin_addr.s_addr)
+ ==0L)
+ cp = "default" ;
+ else if (flags & RTF_HOST)
+ cp = routename(sockin->sin_addr.s_addr);
+ else if (mask)
+ cp = netname(sockin->sin_addr.s_addr,
+ ntohl(((struct sockaddr_in *)mask)
+ ->sin_addr.s_addr));
+ else
+ cp = netname(sockin->sin_addr.s_addr, 0L);
+ break;
+ }
+
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
+ struct in6_addr *in6 = &sa6->sin6_addr;
+
+ /*
+ * XXX: This is a special workaround for KAME kernels.
+ * sin6_scope_id field of SA should be set in the future.
+ */
+ if (IN6_IS_ADDR_LINKLOCAL(in6) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(in6)) {
+ /* XXX: override is ok? */
+ sa6->sin6_scope_id = (u_int32_t)ntohs(*(u_short *)&in6->s6_addr[2]);
+ *(u_short *)&in6->s6_addr[2] = 0;
+ }
+
+ if (flags & RTF_HOST)
+ cp = routename6(sa6);
+ else if (mask)
+ cp = netname6(sa6,
+ &((struct sockaddr_in6 *)mask)->sin6_addr);
+ else {
+ cp = netname6(sa6, NULL);
+ }
+ break;
+ }
+#endif /*INET6*/
+
+ case AF_IPX:
+ {
+ struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr;
+ if (ipx_nullnet(satoipx_addr(work)))
+ cp = "default";
+ else
+ cp = ipx_print(sa);
+ break;
+ }
+ case AF_APPLETALK:
+ {
+ if (!(flags & RTF_HOST) && mask)
+ cp = atalk_print2(sa,mask,9);
+ else
+ cp = atalk_print(sa,11);
+ break;
+ }
+ case AF_NETGRAPH:
+ {
+ printf("%s", ((struct sockaddr_ng *)sa)->sg_data);
+ break;
+ }
+
+ case AF_LINK:
+ {
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
+
+ if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 &&
+ sdl->sdl_slen == 0) {
+ (void) sprintf(workbuf, "link#%d", sdl->sdl_index);
+ cp = workbuf;
+ } else
+ switch (sdl->sdl_type) {
+
+ case IFT_ETHER:
+ case IFT_L2VLAN:
+ if (sdl->sdl_alen == ETHER_ADDR_LEN) {
+ cp = ether_ntoa((struct ether_addr *)
+ (sdl->sdl_data + sdl->sdl_nlen));
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ cp = link_ntoa(sdl);
+ break;
+ }
+ break;
+ }
+
+ default:
+ {
+ u_char *s = (u_char *)sa->sa_data, *slim;
+ char *cq, *cqlim;
+
+ cq = workbuf;
+ slim = sa->sa_len + (u_char *) sa;
+ cqlim = cq + sizeof(workbuf) - 6;
+ cq += sprintf(cq, "(%d)", sa->sa_family);
+ while (s < slim && cq < cqlim) {
+ cq += sprintf(cq, " %02x", *s++);
+ if (s < slim)
+ cq += sprintf(cq, "%02x", *s++);
+ }
+ cp = workbuf;
+ }
+ }
+
+ return (cp);
+}
+
+static void
+p_flags(int f, const char *format)
+{
+ printf(format, fmt_flags(f));
+}
+
+static const char *
+fmt_flags(int f)
+{
+ static char name[33];
+ char *flags;
+ struct bits *p = bits;
+
+ for (flags = name; p->b_mask; p++)
+ if (p->b_mask & f)
+ *flags++ = p->b_val;
+ *flags = '\0';
+ return (name);
+}
+
+static void
+p_rtentry(struct rtentry *rt)
+{
+ static struct ifnet ifnet, *lastif;
+ struct rtentry parent;
+ static char buffer[128];
+ static char prettyname[128];
+ struct sockaddr *sa;
+ sa_u addr, mask;
+
+ /*
+ * Don't print protocol-cloned routes unless -a.
+ */
+ if (rt->rt_flags & RTF_WASCLONED && !aflag) {
+ kget(rt->rt_parent, parent);
+ if (parent.rt_flags & RTF_PRCLONING)
+ return;
+ }
+
+ bzero(&addr, sizeof(addr));
+ if ((sa = kgetsa(rt_key(rt))))
+ bcopy(sa, &addr, sa->sa_len);
+ bzero(&mask, sizeof(mask));
+ if (rt_mask(rt) && (sa = kgetsa(rt_mask(rt))))
+ bcopy(sa, &mask, sa->sa_len);
+ p_sockaddr(&addr.u_sa, &mask.u_sa, rt->rt_flags, wid_dst);
+ p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST, wid_gw);
+ snprintf(buffer, sizeof(buffer), "%%-%d.%ds ", wid_flags, wid_flags);
+ p_flags(rt->rt_flags, buffer);
+ if (addr.u_sa.sa_family == AF_INET || Wflag) {
+ printf("%*ld %*lu ", wid_refs, rt->rt_refcnt,
+ wid_use, rt->rt_use);
+ if (Wflag) {
+ if (rt->rt_rmx.rmx_mtu != 0)
+ printf("%*lu ", wid_mtu, rt->rt_rmx.rmx_mtu);
+ else
+ printf("%*s ", wid_mtu, "");
+ }
+ }
+ if (rt->rt_ifp) {
+ if (rt->rt_ifp != lastif) {
+ kget(rt->rt_ifp, ifnet);
+ lastif = rt->rt_ifp;
+ strlcpy(prettyname, ifnet.if_xname, sizeof(prettyname));
+ }
+ printf("%*.*s", wid_if, wid_if, prettyname);
+ if (rt->rt_rmx.rmx_expire) {
+ time_t expire_time;
+
+ if ((expire_time =
+ rt->rt_rmx.rmx_expire - time((time_t *)0)) > 0)
+ printf(" %*d", wid_expire, (int)expire_time);
+ }
+ if (rt->rt_nodes[0].rn_dupedkey)
+ printf(" =>");
+ }
+ putchar('\n');
+}
+
+char *
+routename(u_long in)
+{
+ char *cp;
+ static char line[MAXHOSTNAMELEN];
+ struct hostent *hp;
+
+ cp = 0;
+ if (!numeric_addr) {
+ hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
+ AF_INET);
+ if (hp) {
+ cp = hp->h_name;
+ trimdomain(cp, strlen(cp));
+ }
+ }
+ if (cp) {
+ strncpy(line, cp, sizeof(line) - 1);
+ line[sizeof(line) - 1] = '\0';
+ } else {
+#define C(x) ((x) & 0xff)
+ in = ntohl(in);
+ sprintf(line, "%lu.%lu.%lu.%lu",
+ C(in >> 24), C(in >> 16), C(in >> 8), C(in));
+ }
+ return (line);
+}
+
+static u_long
+forgemask(u_long a)
+{
+ u_long m;
+
+ if (IN_CLASSA(a))
+ m = IN_CLASSA_NET;
+ else if (IN_CLASSB(a))
+ m = IN_CLASSB_NET;
+ else
+ m = IN_CLASSC_NET;
+ return (m);
+}
+
+static void
+domask(char *dst, u_long addr, u_long mask)
+{
+ int b, i;
+
+ if (!mask || (forgemask(addr) == mask)) {
+ *dst = '\0';
+ return;
+ }
+ i = 0;
+ for (b = 0; b < 32; b++)
+ if (mask & (1 << b)) {
+ int bb;
+
+ i = b;
+ for (bb = b+1; bb < 32; bb++)
+ if (!(mask & (1 << bb))) {
+ i = -1; /* noncontig */
+ break;
+ }
+ break;
+ }
+ if (i == -1)
+ sprintf(dst, "&0x%lx", mask);
+ else
+ sprintf(dst, "/%d", 32-i);
+}
+
+/*
+ * Return the name of the network whose address is given.
+ * The address is assumed to be that of a net or subnet, not a host.
+ */
+char *
+netname(u_long in, u_long mask)
+{
+ char *cp = 0;
+ static char line[MAXHOSTNAMELEN];
+ struct netent *np = 0;
+ u_long dmask;
+ u_long i;
+
+#define NSHIFT(m) ( \
+ (m) == IN_CLASSA_NET ? IN_CLASSA_NSHIFT : \
+ (m) == IN_CLASSB_NET ? IN_CLASSB_NSHIFT : \
+ (m) == IN_CLASSC_NET ? IN_CLASSC_NSHIFT : \
+ 0)
+
+ i = ntohl(in);
+ dmask = forgemask(i);
+ if (!numeric_addr && i) {
+ np = getnetbyaddr(i >> NSHIFT(mask), AF_INET);
+ if (np == NULL && mask == 0)
+ np = getnetbyaddr(i >> NSHIFT(dmask), AF_INET);
+ if (np != NULL) {
+ cp = np->n_name;
+ trimdomain(cp, strlen(cp));
+ }
+ }
+#undef NSHIFT
+ if (cp != NULL) {
+ strncpy(line, cp, sizeof(line) - 1);
+ line[sizeof(line) - 1] = '\0';
+ } else {
+ switch (dmask) {
+ case IN_CLASSA_NET:
+ if ((i & IN_CLASSA_HOST) == 0) {
+ sprintf(line, "%lu", C(i >> 24));
+ break;
+ }
+ /* FALLTHROUGH */
+ case IN_CLASSB_NET:
+ if ((i & IN_CLASSB_HOST) == 0) {
+ sprintf(line, "%lu.%lu",
+ C(i >> 24), C(i >> 16));
+ break;
+ }
+ /* FALLTHROUGH */
+ case IN_CLASSC_NET:
+ if ((i & IN_CLASSC_HOST) == 0) {
+ sprintf(line, "%lu.%lu.%lu",
+ C(i >> 24), C(i >> 16), C(i >> 8));
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ sprintf(line, "%lu.%lu.%lu.%lu",
+ C(i >> 24), C(i >> 16), C(i >> 8), C(i));
+ break;
+ }
+ }
+ domask(line + strlen(line), i, mask);
+ return (line);
+}
+
+#ifdef INET6
+const char *
+netname6(struct sockaddr_in6 *sa6, struct in6_addr *mask)
+{
+ static char line[MAXHOSTNAMELEN];
+ u_char *p = (u_char *)mask;
+ u_char *lim;
+ int masklen, illegal = 0, flag = NI_WITHSCOPEID;
+
+ if (mask) {
+ for (masklen = 0, lim = p + 16; p < lim; p++) {
+ switch (*p) {
+ case 0xff:
+ masklen += 8;
+ break;
+ case 0xfe:
+ masklen += 7;
+ break;
+ case 0xfc:
+ masklen += 6;
+ break;
+ case 0xf8:
+ masklen += 5;
+ break;
+ case 0xf0:
+ masklen += 4;
+ break;
+ case 0xe0:
+ masklen += 3;
+ break;
+ case 0xc0:
+ masklen += 2;
+ break;
+ case 0x80:
+ masklen += 1;
+ break;
+ case 0x00:
+ break;
+ default:
+ illegal ++;
+ break;
+ }
+ }
+ if (illegal)
+ fprintf(stderr, "illegal prefixlen\n");
+ }
+ else
+ masklen = 128;
+
+ if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr))
+ return("default");
+
+ if (numeric_addr)
+ flag |= NI_NUMERICHOST;
+ getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line),
+ NULL, 0, flag);
+
+ if (numeric_addr)
+ sprintf(&line[strlen(line)], "/%d", masklen);
+
+ return line;
+}
+
+char *
+routename6(struct sockaddr_in6 *sa6)
+{
+ static char line[MAXHOSTNAMELEN];
+ int flag = NI_WITHSCOPEID;
+ /* use local variable for safety */
+ struct sockaddr_in6 sa6_local = {AF_INET6, sizeof(sa6_local),};
+
+ sa6_local.sin6_addr = sa6->sin6_addr;
+ sa6_local.sin6_scope_id = sa6->sin6_scope_id;
+
+ if (numeric_addr)
+ flag |= NI_NUMERICHOST;
+
+ getnameinfo((struct sockaddr *)&sa6_local, sa6_local.sin6_len,
+ line, sizeof(line), NULL, 0, flag);
+
+ return line;
+}
+#endif /*INET6*/
+
+/*
+ * Print routing statistics
+ */
+void
+rt_stats(u_long rtsaddr, u_long rttaddr)
+{
+ struct rtstat rtstat;
+ int rttrash;
+
+ if (rtsaddr == 0) {
+ printf("rtstat: symbol not in namelist\n");
+ return;
+ }
+ if (rttaddr == 0) {
+ printf("rttrash: symbol not in namelist\n");
+ return;
+ }
+ kread(rtsaddr, (char *)&rtstat, sizeof (rtstat));
+ kread(rttaddr, (char *)&rttrash, sizeof (rttrash));
+ printf("routing:\n");
+
+#define p(f, m) if (rtstat.f || sflag <= 1) \
+ printf(m, rtstat.f, plural(rtstat.f))
+
+ p(rts_badredirect, "\t%u bad routing redirect%s\n");
+ p(rts_dynamic, "\t%u dynamically created route%s\n");
+ p(rts_newgateway, "\t%u new gateway%s due to redirects\n");
+ p(rts_unreach, "\t%u destination%s found unreachable\n");
+ p(rts_wildcard, "\t%u use%s of a wildcard route\n");
+#undef p
+
+ if (rttrash || sflag <= 1)
+ printf("\t%u route%s not in table but not freed\n",
+ rttrash, plural(rttrash));
+}
+
+char *
+ipx_print(struct sockaddr *sa)
+{
+ u_short port;
+ struct servent *sp = 0;
+ const char *net = "", *host = "";
+ char *p;
+ u_char *q;
+ struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr;
+ static char mybuf[50];
+ char cport[10], chost[15], cnet[15];
+
+ port = ntohs(work.x_port);
+
+ if (ipx_nullnet(work) && ipx_nullhost(work)) {
+
+ if (port) {
+ if (sp)
+ sprintf(mybuf, "*.%s", sp->s_name);
+ else
+ sprintf(mybuf, "*.%x", port);
+ } else
+ sprintf(mybuf, "*.*");
+
+ return (mybuf);
+ }
+
+ if (ipx_wildnet(work))
+ net = "any";
+ else if (ipx_nullnet(work))
+ net = "*";
+ else {
+ q = work.x_net.c_net;
+ sprintf(cnet, "%02x%02x%02x%02x",
+ q[0], q[1], q[2], q[3]);
+ for (p = cnet; *p == '0' && p < cnet + 8; p++)
+ continue;
+ net = p;
+ }
+
+ if (ipx_wildhost(work))
+ host = "any";
+ else if (ipx_nullhost(work))
+ host = "*";
+ else {
+ q = work.x_host.c_host;
+ sprintf(chost, "%02x%02x%02x%02x%02x%02x",
+ q[0], q[1], q[2], q[3], q[4], q[5]);
+ for (p = chost; *p == '0' && p < chost + 12; p++)
+ continue;
+ host = p;
+ }
+
+ if (port) {
+ if (strcmp(host, "*") == 0)
+ host = "";
+ if (sp)
+ snprintf(cport, sizeof(cport),
+ "%s%s", *host ? "." : "", sp->s_name);
+ else
+ snprintf(cport, sizeof(cport),
+ "%s%x", *host ? "." : "", port);
+ } else
+ *cport = 0;
+
+ snprintf(mybuf, sizeof(mybuf), "%s.%s%s", net, host, cport);
+ return(mybuf);
+}
+
+char *
+ipx_phost(struct sockaddr *sa)
+{
+ struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)sa;
+ struct sockaddr_ipx work;
+ static union ipx_net ipx_zeronet;
+ char *p;
+ struct ipx_addr in;
+
+ work = *sipx;
+ in = work.sipx_addr;
+
+ work.sipx_addr.x_port = 0;
+ work.sipx_addr.x_net = ipx_zeronet;
+ p = ipx_print((struct sockaddr *)&work);
+ if (strncmp("*.", p, 2) == 0) p += 2;
+
+ return(p);
+}
+
+void
+upHex(char *p0)
+{
+ char *p = p0;
+
+ for (; *p; p++)
+ switch (*p) {
+
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ *p += ('A' - 'a');
+ break;
+ }
+}
diff --git a/usr.bin/netstat/unix.c b/usr.bin/netstat/unix.c
new file mode 100644
index 000000000000..d9256115382a
--- /dev/null
+++ b/usr.bin/netstat/unix.c
@@ -0,0 +1,160 @@
+/*-
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)unix.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Display protocol blocks in the unix domain.
+ */
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/mbuf.h>
+#include <sys/sysctl.h>
+#include <sys/un.h>
+#include <sys/unpcb.h>
+
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <err.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <kvm.h>
+#include "netstat.h"
+
+static void unixdomainpr (struct xunpcb *, struct xsocket *);
+
+static const char *const socktype[] =
+ { "#0", "stream", "dgram", "raw", "rdm", "seqpacket" };
+
+void
+unixpr(void)
+{
+ char *buf;
+ int type;
+ size_t len;
+ struct xsocket *so;
+ struct xunpgen *xug, *oxug;
+ struct xunpcb *xunp;
+ char mibvar[sizeof "net.local.seqpacket.pcblist"];
+
+ for (type = SOCK_STREAM; type <= SOCK_SEQPACKET; type++) {
+ sprintf(mibvar, "net.local.%s.pcblist", socktype[type]);
+
+ len = 0;
+ if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
+ if (errno != ENOENT)
+ warn("sysctl: %s", mibvar);
+ continue;
+ }
+ if ((buf = malloc(len)) == 0) {
+ warnx("malloc %lu bytes", (u_long)len);
+ return;
+ }
+ if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ free(buf);
+ return;
+ }
+
+ oxug = xug = (struct xunpgen *)buf;
+ for (xug = (struct xunpgen *)((char *)xug + xug->xug_len);
+ xug->xug_len > sizeof(struct xunpgen);
+ xug = (struct xunpgen *)((char *)xug + xug->xug_len)) {
+ xunp = (struct xunpcb *)xug;
+ so = &xunp->xu_socket;
+
+ /* Ignore PCBs which were freed during copyout. */
+ if (xunp->xu_unp.unp_gencnt > oxug->xug_gen)
+ continue;
+ unixdomainpr(xunp, so);
+ }
+ if (xug != oxug && xug->xug_gen != oxug->xug_gen) {
+ if (oxug->xug_count > xug->xug_count) {
+ printf("Some %s sockets may have been deleted.\n",
+ socktype[type]);
+ } else if (oxug->xug_count < xug->xug_count) {
+ printf("Some %s sockets may have been created.\n",
+ socktype[type]);
+ } else {
+ printf("Some %s sockets may have been created or deleted",
+ socktype[type]);
+ }
+ }
+ free(buf);
+ }
+}
+
+static void
+unixdomainpr(struct xunpcb *xunp, struct xsocket *so)
+{
+ struct unpcb *unp;
+ struct sockaddr_un *sa;
+ static int first = 1;
+
+ unp = &xunp->xu_unp;
+ if (unp->unp_addr)
+ sa = &xunp->xu_addr;
+ else
+ sa = (struct sockaddr_un *)0;
+
+ if (first) {
+ printf("Active UNIX domain sockets\n");
+ printf(
+"%-8.8s %-6.6s %-6.6s %-6.6s %8.8s %8.8s %8.8s %8.8s Addr\n",
+ "Address", "Type", "Recv-Q", "Send-Q",
+ "Inode", "Conn", "Refs", "Nextref");
+ first = 0;
+ }
+ printf("%8lx %-6.6s %6u %6u %8lx %8lx %8lx %8lx",
+ (long)so->so_pcb, socktype[so->so_type], so->so_rcv.sb_cc,
+ so->so_snd.sb_cc,
+ (long)unp->unp_vnode, (long)unp->unp_conn,
+ (long)LIST_FIRST(&unp->unp_refs), (long)LIST_NEXT(unp, unp_reflink));
+ if (sa)
+ printf(" %.*s",
+ (int)(sa->sun_len - offsetof(struct sockaddr_un, sun_path)),
+ sa->sun_path);
+ putchar('\n');
+}