summaryrefslogtreecommitdiff
path: root/usr.bin/netstat
diff options
context:
space:
mode:
authorJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>1999-12-08 12:30:18 +0000
committerJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>1999-12-08 12:30:18 +0000
commit3fc9404f57dc2e084f8ed46c43c04334ed1c83dd (patch)
tree6f2de8a4d80bb7ab93530732b9978a0eec563d20 /usr.bin/netstat
parentdb919ef56dced82ec8bf8bb79296652463318f83 (diff)
add IPv6 support from KAME. cleanup type matches with printf() format.
KAME_SCOPEID should be enabled after KAME get{addr,name}info(3) merge.
Diffstat (limited to 'usr.bin/netstat')
-rw-r--r--usr.bin/netstat/Makefile7
-rw-r--r--usr.bin/netstat/if.c19
-rw-r--r--usr.bin/netstat/inet.c176
-rw-r--r--usr.bin/netstat/inet6.c1128
-rw-r--r--usr.bin/netstat/main.c84
-rw-r--r--usr.bin/netstat/mroute6.c280
-rw-r--r--usr.bin/netstat/netstat.145
-rw-r--r--usr.bin/netstat/netstat.h20
-rw-r--r--usr.bin/netstat/route.c193
-rw-r--r--usr.bin/netstat/unix.c8
10 files changed, 1852 insertions, 108 deletions
diff --git a/usr.bin/netstat/Makefile b/usr.bin/netstat/Makefile
index fa2b52ddd77..521acd59df2 100644
--- a/usr.bin/netstat/Makefile
+++ b/usr.bin/netstat/Makefile
@@ -1,12 +1,15 @@
-# $OpenBSD: Makefile,v 1.5 1997/09/21 11:50:15 deraadt Exp $
+# $OpenBSD: Makefile,v 1.6 1999/12/08 12:30:17 itojun Exp $
PROG= netstat
SRCS= if.c inet.c ipx.c iso.c main.c mbuf.c mroute.c ns.c route.c \
- tp_astring.c unix.c atalk.c
+ tp_astring.c unix.c atalk.c inet6.c mroute6.c
.PATH: ${.CURDIR}/../../sys/netiso
BINGRP= kmem
BINMODE=2555
LDADD= -lkvm
DPADD= ${LIBKVM}
+CPPFLAGS+= -DINET6
+#CPPFLAGS+= -DKAME_SCOPEID
+
.include <bsd.prog.mk>
diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c
index acea93bbf6d..8779f1bafed 100644
--- a/usr.bin/netstat/if.c
+++ b/usr.bin/netstat/if.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if.c,v 1.17 1998/02/27 12:07:32 deraadt Exp $ */
+/* $OpenBSD: if.c,v 1.18 1999/12/08 12:30:17 itojun Exp $ */
/* $NetBSD: if.c,v 1.16.4.2 1996/06/07 21:46:46 thorpej Exp $ */
/*
@@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "from: @(#)if.c 8.2 (Berkeley) 2/21/94";
#else
-static char *rcsid = "$OpenBSD: if.c,v 1.17 1998/02/27 12:07:32 deraadt Exp $";
+static char *rcsid = "$OpenBSD: if.c,v 1.18 1999/12/08 12:30:17 itojun Exp $";
#endif
#endif /* not lint */
@@ -88,6 +88,9 @@ intpr(interval, ifnetaddr)
union {
struct ifaddr ifa;
struct in_ifaddr in;
+#ifdef INET6
+ struct in6_ifaddr in6;
+#endif
struct ns_ifaddr ns;
struct ipx_ifaddr ipx;
struct iso_ifaddr iso;
@@ -127,6 +130,9 @@ intpr(interval, ifnetaddr)
ifaddraddr = 0;
while (ifnetaddr || ifaddraddr) {
struct sockaddr_in *sin;
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+#endif
register char *cp;
int n, m;
@@ -193,6 +199,15 @@ intpr(interval, ifnetaddr)
}
}
break;
+#ifdef INET6
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)sa;
+ printf("%-11.11s ",
+ netname6(&ifaddr.in6.ia_addr,
+ &ifaddr.in6.ia_prefixmask.sin6_addr));
+ printf("%-17.17s ", routename6(sin6));
+ break;
+#endif
case AF_IPX:
{
struct sockaddr_ipx *sipx =
diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c
index d27b551b2ff..88370045521 100644
--- a/usr.bin/netstat/inet.c
+++ b/usr.bin/netstat/inet.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: inet.c,v 1.37 1999/12/06 11:17:26 niklas Exp $ */
+/* $OpenBSD: inet.c,v 1.38 1999/12/08 12:30:17 itojun Exp $ */
/* $NetBSD: inet.c,v 1.14 1995/10/03 21:42:37 thorpej Exp $ */
/*
@@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "from: @(#)inet.c 8.4 (Berkeley) 4/20/94";
#else
-static char *rcsid = "$OpenBSD: inet.c,v 1.37 1999/12/06 11:17:26 niklas Exp $";
+static char *rcsid = "$OpenBSD: inet.c,v 1.38 1999/12/08 12:30:17 itojun Exp $";
#endif
#endif /* not lint */
@@ -93,6 +93,10 @@ struct socket sockb;
char *inetname __P((struct in_addr *));
void inetprint __P((struct in_addr *, int, char *, int));
+#ifdef INET6
+char *inet6name __P((struct in6_addr *));
+void inet6print __P((struct in6_addr *, int, char *, int));
+#endif
/*
* Print a summary of connections related to an Internet
@@ -110,7 +114,10 @@ protopr(off, name)
struct inpcb inpcb;
int istcp;
static int first = 1;
+ char *name0;
+ char namebuf[20];
+ name0 = name;
if (off == 0)
return;
istcp = strcmp(name, "tcp") == 0;
@@ -153,15 +160,36 @@ protopr(off, name)
"(state)");
first = 0;
}
- if (Aflag)
+ if (Aflag) {
if (istcp)
printf("%*p ", PLEN, inpcb.inp_ppcb);
else
printf("%*p ", PLEN, prev);
+ }
+#ifdef INET6
+ if (inpcb.inp_flags & INP_IPV6) {
+ strcpy(namebuf, name0);
+ strcat(namebuf, "6");
+ name = namebuf;
+ } else
+ name = name0;
+#endif
printf("%-5.5s %6ld %6ld ", name, sockb.so_rcv.sb_cc,
sockb.so_snd.sb_cc);
- inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport, name, 1);
- inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport, name, 0);
+#ifdef INET6
+ if (inpcb.inp_flags & INP_IPV6) {
+ inet6print(&inpcb.inp_laddr6, (int)inpcb.inp_lport,
+ name, 1);
+ inet6print(&inpcb.inp_faddr6, (int)inpcb.inp_fport,
+ name, 0);
+ } else
+#endif
+ {
+ inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport,
+ name, 1);
+ inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport,
+ name, 0);
+ }
if (istcp) {
if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
printf(" %d", tcpcb.t_state);
@@ -189,65 +217,71 @@ tcp_stats(off, name)
#define p(f, m) if (tcpstat.f || sflag <= 1) \
printf(m, tcpstat.f, plural(tcpstat.f))
+#define p1(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%ld packet%s sent\n");
+ p(tcps_sndtotal, "\t%u packet%s sent\n");
p2(tcps_sndpack,tcps_sndbyte,
- "\t\t%ld data packet%s (%qd byte%s)\n");
+ "\t\t%u data packet%s (%qd byte%s)\n");
p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
- "\t\t%ld data packet%s (%qd byte%s) retransmitted\n");
+ "\t\t%u data packet%s (%qd byte%s) retransmitted\n");
p(tcps_sndrexmitfast, "\t\t%qd fast retransmitted packet%s\n");
- p2(tcps_sndacks, tcps_delack,
- "\t\t%ld ack-only packet%s (%ld delayed)\n");
- p(tcps_sndurg, "\t\t%ld URG only packet%s\n");
- p(tcps_sndprobe, "\t\t%ld window probe packet%s\n");
- p(tcps_sndwinup, "\t\t%ld window update packet%s\n");
- p(tcps_sndctrl, "\t\t%ld control packet%s\n");
- p(tcps_rcvtotal, "\t%ld packet%s received\n");
- p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%ld ack%s (for %qd byte%s)\n");
- p(tcps_rcvdupack, "\t\t%ld duplicate ack%s\n");
- p(tcps_rcvacktoomuch, "\t\t%ld ack%s for unsent data\n");
+ p2a(tcps_sndacks, tcps_delack,
+ "\t\t%u ack-only packet%s (%u delayed)\n");
+ p(tcps_sndurg, "\t\t%u URG only packet%s\n");
+ p(tcps_sndprobe, "\t\t%u window probe packet%s\n");
+ p(tcps_sndwinup, "\t\t%u window update packet%s\n");
+ p(tcps_sndctrl, "\t\t%u control packet%s\n");
+ p(tcps_rcvtotal, "\t%u packet%s received\n");
+ p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%u ack%s (for %qd byte%s)\n");
+ p(tcps_rcvdupack, "\t\t%u duplicate ack%s\n");
+ p(tcps_rcvacktoomuch, "\t\t%u ack%s for unsent data\n");
p2(tcps_rcvpack, tcps_rcvbyte,
- "\t\t%ld packet%s (%qd byte%s) received in-sequence\n");
+ "\t\t%u packet%s (%qu byte%s) received in-sequence\n");
p2(tcps_rcvduppack, tcps_rcvdupbyte,
- "\t\t%ld completely duplicate packet%s (%qd byte%s)\n");
- p(tcps_pawsdrop, "\t\t%ld old duplicate packet%s\n");
+ "\t\t%u completely duplicate packet%s (%qd byte%s)\n");
+ p(tcps_pawsdrop, "\t\t%u old duplicate packet%s\n");
p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
- "\t\t%ld packet%s with some dup. data (%qd byte%s duped)\n");
+ "\t\t%u packet%s with some dup. data (%qd byte%s duped)\n");
p2(tcps_rcvoopack, tcps_rcvoobyte,
- "\t\t%ld out-of-order packet%s (%qd byte%s)\n");
+ "\t\t%u out-of-order packet%s (%qd byte%s)\n");
p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
- "\t\t%ld packet%s (%qd byte%s) of data after window\n");
- p(tcps_rcvwinprobe, "\t\t%ld window probe%s\n");
- p(tcps_rcvwinupd, "\t\t%ld window update packet%s\n");
- p(tcps_rcvafterclose, "\t\t%ld packet%s received after close\n");
- p(tcps_rcvbadsum, "\t\t%ld discarded for bad checksum%s\n");
- p(tcps_rcvbadoff, "\t\t%ld discarded for bad header offset field%s\n");
- p(tcps_rcvshort, "\t\t%ld discarded because packet too short\n");
- p(tcps_rcvnosec, "\t\t%ld discarded for missing IPSec protection\n");
- p(tcps_connattempt, "\t%ld connection request%s\n");
- p(tcps_accepts, "\t%ld connection accept%s\n");
- p(tcps_connects, "\t%ld connection%s established (including accepts)\n");
+ "\t\t%u packet%s (%qd byte%s) of data after window\n");
+ p(tcps_rcvwinprobe, "\t\t%u window probe%s\n");
+ p(tcps_rcvwinupd, "\t\t%u window update packet%s\n");
+ p(tcps_rcvafterclose, "\t\t%u packet%s received after close\n");
+ p(tcps_rcvbadsum, "\t\t%u discarded for bad checksum%s\n");
+ p(tcps_rcvbadoff, "\t\t%u discarded for bad header offset field%s\n");
+ p1(tcps_rcvshort, "\t\t%u discarded because packet too short\n");
+ p1(tcps_rcvnosec, "\t\t%u discarded for missing IPSec protection\n");
+ p(tcps_connattempt, "\t%u connection request%s\n");
+ p(tcps_accepts, "\t%u connection accept%s\n");
+ p(tcps_connects, "\t%u connection%s established (including accepts)\n");
p2(tcps_closed, tcps_drops,
- "\t%ld connection%s closed (including %ld drop%s)\n");
- p(tcps_conndrops, "\t%ld embryonic connection%s dropped\n");
+ "\t%u connection%s closed (including %u drop%s)\n");
+ p(tcps_conndrops, "\t%u embryonic connection%s dropped\n");
p2(tcps_rttupdated, tcps_segstimed,
- "\t%ld segment%s updated rtt (of %ld attempt%s)\n");
- p(tcps_rexmttimeo, "\t%ld retransmit timeout%s\n");
- p(tcps_timeoutdrop, "\t\t%ld connection%s dropped by rexmit timeout\n");
- p(tcps_persisttimeo, "\t%ld persist timeout%s\n");
- p(tcps_keeptimeo, "\t%ld keepalive timeout%s\n");
- p(tcps_keepprobe, "\t\t%ld keepalive probe%s sent\n");
- p(tcps_keepdrops, "\t\t%ld connection%s dropped by keepalive\n");
- p(tcps_predack, "\t%ld correct ACK header prediction%s\n");
- p(tcps_preddat, "\t%ld correct data packet header prediction%s\n");
- p3(tcps_pcbhashmiss, "\t%ld PCB cache miss%s\n");
- p(tcps_badsyn, "\t%ld SYN packet%s received with same src/dst address/port\n");
+ "\t%u segment%s updated rtt (of %u attempt%s)\n");
+ p(tcps_rexmttimeo, "\t%u retransmit timeout%s\n");
+ p(tcps_timeoutdrop, "\t\t%u connection%s dropped by rexmit timeout\n");
+ p(tcps_persisttimeo, "\t%u persist timeout%s\n");
+ p(tcps_keeptimeo, "\t%u keepalive timeout%s\n");
+ p(tcps_keepprobe, "\t\t%u keepalive probe%s sent\n");
+ p(tcps_keepdrops, "\t\t%u connection%s dropped by keepalive\n");
+ p(tcps_predack, "\t%u correct ACK header prediction%s\n");
+ p(tcps_preddat, "\t%u correct data packet header prediction%s\n");
+ p3(tcps_pcbhashmiss, "\t%u PCB cache miss%s\n");
+ p(tcps_badsyn, "\t%u SYN packet%s received with same src/dst address/port\n");
#undef p
+#undef p1
#undef p2
+#undef p2a
#undef p3
}
@@ -268,15 +302,17 @@ udp_stats(off, name)
printf("%s:\n", name);
#define p(f, m) if (udpstat.f || sflag <= 1) \
printf(m, udpstat.f, plural(udpstat.f))
+#define p1(f, m) if (udpstat.f || sflag <= 1) \
+ printf(m, udpstat.f)
p(udps_ipackets, "\t%lu datagram%s received\n");
- p(udps_hdrops, "\t%lu with incomplete header\n");
- p(udps_badlen, "\t%lu with bad data length field\n");
- p(udps_badsum, "\t%lu with bad checksum\n");
- p(udps_nosum, "\t%lu with no checksum\n");
- p(udps_noport, "\t%lu dropped due to no socket\n");
+ p1(udps_hdrops, "\t%lu with incomplete header\n");
+ p1(udps_badlen, "\t%lu with bad data length field\n");
+ p1(udps_badsum, "\t%lu with bad checksum\n");
+ p1(udps_nosum, "\t%lu with no checksum\n");
+ p1(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");
- p(udps_nosec, "\t%lu dropped due to missing IPSec protection\n");
- p(udps_fullsock, "\t%lu dropped due to full socket buffers\n");
+ p1(udps_nosec, "\t%lu dropped due to missing IPSec protection\n");
+ p1(udps_fullsock, "\t%lu dropped due to full socket buffers\n");
delivered = udpstat.udps_ipackets -
udpstat.udps_hdrops -
udpstat.udps_badlen -
@@ -287,8 +323,9 @@ udp_stats(off, name)
if (delivered || sflag <= 1)
printf("\t%lu delivered\n", delivered);
p(udps_opackets, "\t%lu datagram%s output\n");
- p(udps_pcbhashmiss, "\t%lu missed PCB cache\n");
+ p1(udps_pcbhashmiss, "\t%lu missed PCB cache\n");
#undef p
+#undef p1
}
/*
@@ -308,15 +345,17 @@ ip_stats(off, name)
#define p(f, m) if (ipstat.f || sflag <= 1) \
printf(m, ipstat.f, plural(ipstat.f))
+#define p1(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");
- p(ips_toosmall, "\t%lu with size smaller than minimum\n");
- p(ips_tooshort, "\t%lu with data size < data length\n");
- p(ips_badhlen, "\t%lu with header length < data size\n");
- p(ips_badlen, "\t%lu with data length < header length\n");
- p(ips_badoptions, "\t%lu with bad options\n");
- p(ips_badvers, "\t%lu with incorrect version number\n");
+ p1(ips_toosmall, "\t%lu with size smaller than minimum\n");
+ p1(ips_tooshort, "\t%lu with data size < data length\n");
+ p1(ips_badhlen, "\t%lu with header length < data size\n");
+ p1(ips_badlen, "\t%lu with data length < header length\n");
+ p1(ips_badoptions, "\t%lu with bad options\n");
+ p1(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_badfrags, "\t%lu malformed fragment%s dropped\n");
@@ -334,8 +373,9 @@ ip_stats(off, name)
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_rcvmemdrop, "\t%lu fragment floods\n");
+ p1(ips_rcvmemdrop, "\t%lu fragment floods\n");
#undef p
+#undef p1
}
static char *icmpnames[] = {
@@ -525,7 +565,6 @@ inetprint(in, port, proto, local)
{
struct servent *sp = 0;
char line[80], *cp, *nam;
- int proton;
int width;
snprintf(line, sizeof line, "%.*s.", (Aflag && !nflag) ? 12 : 16,
@@ -621,9 +660,11 @@ ah_stats(off, name)
#define p(f, m) if (ahstat.f || sflag <= 1) \
printf(m, ahstat.f, plural(ahstat.f))
+#define p1(f, m) if (ahstat.f || sflag <= 1) \
+ printf(m, ahstat.f)
- p(ahs_input, "\t%u input AH packets\n");
- p(ahs_output, "\t%u output AH packets\n");
+ p1(ahs_input, "\t%u input AH packets\n");
+ p1(ahs_output, "\t%u output AH packets\n");
p(ahs_hdrops, "\t%u packet%s shorter than header shows\n");
p(ahs_pdrops, "\t%u packet%s dropped due to policy\n");
p(ahs_notdb, "\t%u packet%s for which no TDB was found\n");
@@ -640,6 +681,7 @@ ah_stats(off, name)
p(ahs_obytes, "\t%qu output byte%s\n");
#undef p
+#undef p1
}
/*
@@ -693,8 +735,8 @@ esp_stats(off, name)
#define p(f, m) if (espstat.f || sflag <= 1) \
printf(m, espstat.f, plural(espstat.f))
- p(esps_input, "\t%u input ESP packets\n");
- p(esps_output, "\t%u output ESP packets\n");
+ p(esps_input, "\t%u input ESP packet%s\n");
+ p(esps_output, "\t%u output ESP packet%s\n");
p(esps_hdrops, "\t%u packet%s shorter than header shows\n");
p(esps_pdrops, "\t%u packet%s dropped due to policy\n");
p(esps_notdb, "\t%u packet%s for which no TDB was found\n");
diff --git a/usr.bin/netstat/inet6.c b/usr.bin/netstat/inet6.c
new file mode 100644
index 00000000000..3df1be54796
--- /dev/null
+++ b/usr.bin/netstat/inet6.c
@@ -0,0 +1,1128 @@
+/* $OpenBSD: inet6.c,v 1.1 1999/12/08 12:30:17 itojun Exp $ */
+/* 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)inet.c 8.4 (Berkeley) 4/20/94";
+#else
+/*__RCSID("$OpenBSD: inet6.c,v 1.1 1999/12/08 12:30:17 itojun Exp $");*/
+/*__RCSID("KAME Id: inet6.c,v 1.4 1999/12/02 04:47:27 itojun Exp");*/
+#endif
+#endif /* not lint */
+
+#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 <net/route.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <netinet/in_systm.h>
+#ifndef TCP6
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#endif
+#include <netinet6/in6_pcb.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/pim6_var.h>
+
+#include <arpa/inet.h>
+#if 0
+#include "gethostbyname2.h"
+#endif
+#include <netdb.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+
+#ifdef INET6
+
+struct in6pcb in6pcb;
+struct socket sockb;
+
+char *inet6name __P((struct in6_addr *));
+void inet6print __P((struct in6_addr *, int, char *));
+
+#if 0
+/*
+ * 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
+ip6protopr(off, name)
+ u_long off;
+ char *name;
+{
+ struct in6pcb cb;
+ register struct in6pcb *prev, *next;
+ int istcp;
+ static int first = 1;
+
+ if (off == 0)
+ return;
+ istcp = strcmp(name, "tcp6") == 0;
+ kread(off, (char *)&cb, sizeof (struct in6pcb));
+ in6pcb = cb;
+ prev = (struct in6pcb *)off;
+ if (in6pcb.in6p_next == (struct in6pcb *)off)
+ return;
+ while (in6pcb.in6p_next != (struct in6pcb *)off) {
+ next = in6pcb.in6p_next;
+ kread((u_long)next, (char *)&in6pcb, sizeof (in6pcb));
+ if (in6pcb.in6p_prev != prev) {
+ printf("???\n");
+ break;
+ }
+ if (!aflag && IN6_IS_ADDR_UNSPECIFIED(&in6pcb.in6p_laddr)) {
+ prev = next;
+ continue;
+ }
+ kread((u_long)in6pcb.in6p_socket, (char *)&sockb, sizeof (sockb));
+ if (istcp) {
+#ifdef TCP6
+ kread((u_long)in6pcb.in6p_ppcb,
+ (char *)&tcp6cb, sizeof (tcp6cb));
+#else
+ kread((u_long)in6pcb.in6p_ppcb,
+ (char *)&tcpcb, sizeof (tcpcb));
+#endif
+ }
+ if (first) {
+ printf("Active Internet6 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) {
+ if (istcp)
+ printf("%8p ", in6pcb.in6p_ppcb);
+ else
+ printf("%8p ", next);
+ }
+ printf("%-5.5s %6ld %6ld ", name, sockb.so_rcv.sb_cc,
+ sockb.so_snd.sb_cc);
+ /* xxx */
+ inet6print(&in6pcb.in6p_laddr, (int)in6pcb.in6p_lport, name);
+ inet6print(&in6pcb.in6p_faddr, (int)in6pcb.in6p_fport, name);
+ if (istcp) {
+#ifdef TCP6
+ if (tcp6cb.t_state < 0 || tcp6cb.t_state >= TCP6_NSTATES)
+ printf(" %d", tcp6cb.t_state);
+ else
+ printf(" %s", tcp6states[tcp6cb.t_state]);
+#else
+ if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
+ printf(" %d", tcpcb.t_state);
+ else
+ printf(" %s", tcpstates[tcpcb.t_state]);
+#endif
+ }
+ putchar('\n');
+ prev = next;
+ }
+}
+#endif
+
+static 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",
+ "#62",
+ "#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",
+ "#89",
+ "#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",
+};
+
+/*
+ * Dump IP6 statistics structure.
+ */
+void
+ip6_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct ip6stat ip6stat;
+ int first, i;
+
+ if (off == 0)
+ return;
+
+ kread(off, (char *)&ip6stat, sizeof (ip6stat));
+ printf("%s:\n", name);
+
+#define p(f, m) if (ip6stat.f || sflag <= 1) \
+ printf(m, ip6stat.f, plural(ip6stat.f))
+#define p1(f, m) if (ip6stat.f || sflag <= 1) \
+ printf(m, ip6stat.f)
+
+ p(ip6s_total, "\t%qu total packet%s received\n");
+ p1(ip6s_toosmall, "\t%qu with size smaller than minimum\n");
+ p1(ip6s_tooshort, "\t%qu with data size < data length\n");
+ p1(ip6s_badoptions, "\t%qu with bad options\n");
+ p1(ip6s_badvers, "\t%qu with incorrect version number\n");
+ p(ip6s_fragments, "\t%qu fragment%s received\n");
+ p(ip6s_fragdropped, "\t%qu fragment%s dropped (dup or out of space)\n");
+ p(ip6s_fragtimeout, "\t%qu fragment%s dropped after timeout\n");
+ p(ip6s_fragoverflow, "\t%qu fragment%s that exceeded limit\n");
+ p(ip6s_reassembled, "\t%qu packet%s reassembled ok\n");
+ p(ip6s_delivered, "\t%qu packet%s for this host\n");
+ p(ip6s_forward, "\t%qu packet%s forwarded\n");
+ p(ip6s_cantforward, "\t%qu packet%s not forwardable\n");
+ p(ip6s_redirectsent, "\t%qu redirect%s sent\n");
+ p(ip6s_localout, "\t%qu packet%s sent from this host\n");
+ p(ip6s_rawout, "\t%qu packet%s sent with fabricated ip header\n");
+ p(ip6s_odropped, "\t%qu output packet%s dropped due to no bufs, etc.\n");
+ p(ip6s_noroute, "\t%qu output packet%s discarded due to no route\n");
+ p(ip6s_fragmented, "\t%qu output datagram%s fragmented\n");
+ p(ip6s_ofragments, "\t%qu fragment%s created\n");
+ p(ip6s_cantfrag, "\t%qu datagram%s that can't be fragmented\n");
+ p(ip6s_badscope, "\t%qu packet%s that violated scope rules\n");
+ p(ip6s_notmember, "\t%qu 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: %qu\n", ip6nh[i],
+ ip6stat.ip6s_nxthist[i]);
+ }
+ printf("\tMbuf statics:\n");
+ printf("\t\t%qu one mbuf\n", 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 = %qu\n",
+ if_indextoname(i, ifbuf),
+ ip6stat.ip6s_m2m[i]);
+ }
+ }
+ printf("\t\t%qu one ext mbuf\n", ip6stat.ip6s_mext1);
+ printf("\t\t%qu two or more ext mbuf\n", ip6stat.ip6s_mext2m);
+ p(ip6s_exthdrtoolong, "\t%qu packet%s whose headers are not continuous\n");
+ p(ip6s_nogif, "\t%qu tunneling packet%s that can't find gif\n");
+#undef p
+#undef p1
+}
+
+/*
+ * Dump IPv6 per-interface statistics based on RFC 2465.
+ */
+void
+ip6_ifstats(ifname)
+ char *ifname;
+{
+ struct in6_ifreq ifr;
+ int s;
+#define p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
+ printf(m, 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, 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%qu total input datagram%s\n");
+ p(ifs6_in_hdrerr, "\t%qu datagram%s with invalid header received\n");
+ p(ifs6_in_toobig, "\t%qu datagram%s exceeded MTU received\n");
+ p(ifs6_in_noroute, "\t%qu datagram%s with no route received\n");
+ p(ifs6_in_addrerr, "\t%qu datagram%s with invalid dst received\n");
+ p(ifs6_in_protounknown, "\t%qu datagram%s with unknown proto received\n");
+ p(ifs6_in_discard, "\t%qu input datagram%s discarded\n");
+ p(ifs6_in_deliver,
+ "\t%qu datagram%s delivered to an upper layer protocol\n");
+ p(ifs6_out_forward, "\t%qu datagram%s forwarded to this interface\n");
+ p(ifs6_out_request,
+ "\t%qu datagram%s sent from an upper layer protocol\n");
+ p(ifs6_out_discard, "\t%qu total discarded output datagram%s\n");
+ p(ifs6_out_fragok, "\t%qu output datagram%s fragmented\n");
+ p(ifs6_out_fragfail, "\t%qu output datagram%s failed on fragment\n");
+ p(ifs6_out_fragcreat, "\t%qu output datagram%s succeeded on fragment\n");
+ p(ifs6_reass_reqd, "\t%qu incoming datagram%s fragmented\n");
+ p(ifs6_reass_ok, "\t%qu datagram%s reassembled\n");
+ p(ifs6_reass_fail, "\t%qu datagram%s failed on reassembling\n");
+ p(ifs6_in_mcast, "\t%qu multicast datagram%s received\n");
+ p(ifs6_out_mcast, "\t%qu multicast datagram%s sent\n");
+
+ end:
+ close(s);
+
+#undef p
+#undef p_5
+}
+
+static 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 advertisment",
+ "neighbor solicitation",
+ "neighbor advertisment",
+ "redirect",
+ "router renumbering",
+ "node information request",
+ "node information reply",
+ "#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",
+};
+
+/*
+ * Dump ICMPv6 statistics.
+ */
+void
+icmp6_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct icmp6stat icmp6stat;
+ register int i, first;
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&icmp6stat, sizeof (icmp6stat));
+ printf("%s:\n", name);
+
+#define p(f, m) if (icmp6stat.f || sflag <= 1) \
+ printf(m, icmp6stat.f, plural(icmp6stat.f))
+
+ p(icp6s_error, "\t%qu call%s to icmp_error\n");
+ p(icp6s_canterror,
+ "\t%qu error%s not generated because old message was icmp or so\n");
+ for (first = 1, i = 0; i < 256; i++)
+ if (icmp6stat.icp6s_outhist[i] != 0) {
+ if (first) {
+ printf("\tOutput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %qu\n", icmp6names[i],
+ icmp6stat.icp6s_outhist[i]);
+ }
+ p(icp6s_badcode, "\t%qu message%s with bad code fields\n");
+ p(icp6s_tooshort, "\t%qu message%s < minimum length\n");
+ p(icp6s_checksum, "\t%qu bad checksum%s\n");
+ p(icp6s_badlen, "\t%qu message%s with bad length\n");
+ for (first = 1, i = 0; i < ICMP6_MAXTYPE; i++)
+ if (icmp6stat.icp6s_inhist[i] != 0) {
+ if (first) {
+ printf("\tInput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %qu\n", icmp6names[i],
+ icmp6stat.icp6s_inhist[i]);
+ }
+ p(icp6s_reflect, "\t%qu message response%s generated\n");
+#undef p
+}
+
+/*
+ * Dump ICMPv6 per-interface statistics based on RFC 2466.
+ */
+void
+icmp6_ifstats(ifname)
+ char *ifname;
+{
+ struct in6_ifreq ifr;
+ int s;
+#define p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
+ printf(m, (u_quad_t)ifr.ifr_ifru.ifru_icmp6stat.f, plural(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%qu total input message%s\n");
+ p(ifs6_in_error, "\t%qu total input error message%s\n");
+ p(ifs6_in_dstunreach, "\t%qu input destination unreachable error%s\n");
+ p(ifs6_in_adminprohib, "\t%qu input administratively prohibited error%s\n");
+ p(ifs6_in_timeexceed, "\t%qu input time exceeded error%s\n");
+ p(ifs6_in_paramprob, "\t%qu input parameter problem error%s\n");
+ p(ifs6_in_pkttoobig, "\t%qu input packet too big error%s\n");
+ p(ifs6_in_echo, "\t%qu input echo request%s\n");
+ p(ifs6_in_echoreply, "\t%qu input echo reply%s\n");
+ p(ifs6_in_routersolicit, "\t%qu input router solicitation%s\n");
+ p(ifs6_in_routeradvert, "\t%qu input router advertisement%s\n");
+ p(ifs6_in_neighborsolicit, "\t%qu input neighbor solicitation%s\n");
+ p(ifs6_in_neighboradvert, "\t%qu input neighbor advertisement%s\n");
+ p(ifs6_in_redirect, "\t%qu input redirect%s\n");
+ p(ifs6_in_mldquery, "\t%qu input MLD query%s\n");
+ p(ifs6_in_mldreport, "\t%qu input MLD report%s\n");
+ p(ifs6_in_mlddone, "\t%qu input MLD done%s\n");
+
+ p(ifs6_out_msg, "\t%qu total output message%s\n");
+ p(ifs6_out_error, "\t%qu total output error message%s\n");
+ p(ifs6_out_dstunreach, "\t%qu output destination unreachable error%s\n");
+ p(ifs6_out_adminprohib, "\t%qu output administratively prohibited error%s\n");
+ p(ifs6_out_timeexceed, "\t%qu output time exceeded error%s\n");
+ p(ifs6_out_paramprob, "\t%qu output parameter problem error%s\n");
+ p(ifs6_out_pkttoobig, "\t%qu output packet too big error%s\n");
+ p(ifs6_out_echo, "\t%qu output echo request%s\n");
+ p(ifs6_out_echoreply, "\t%qu output echo reply%s\n");
+ p(ifs6_out_routersolicit, "\t%qu output router solicitation%s\n");
+ p(ifs6_out_routeradvert, "\t%qu output router advertisement%s\n");
+ p(ifs6_out_neighborsolicit, "\t%qu output neighbor solicitation%s\n");
+ p(ifs6_out_neighboradvert, "\t%qu output neighbor advertisement%s\n");
+ p(ifs6_out_redirect, "\t%qu output redirect%s\n");
+ p(ifs6_out_mldquery, "\t%qu output MLD query%s\n");
+ p(ifs6_out_mldreport, "\t%qu output MLD report%s\n");
+ p(ifs6_out_mlddone, "\t%qu output MLD done%s\n");
+
+ end:
+ close(s);
+#undef p
+}
+
+/*
+ * Dump PIM statistics structure.
+ */
+void
+pim6_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct pim6stat pim6stat;
+
+ if (off == 0)
+ return;
+ kread(off, (char *)&pim6stat, sizeof(pim6stat));
+ printf("%s:\n", name);
+
+#define p(f, m) if (pim6stat.f || sflag <= 1) \
+ printf(m, pim6stat.f, plural(pim6stat.f))
+ p(pim6s_rcv_total, "\t%qu message%s received\n");
+ p(pim6s_rcv_tooshort, "\t%qu message%s received with too few bytes\n");
+ p(pim6s_rcv_badsum, "\t%qu message%s received with bad checksum\n");
+ p(pim6s_rcv_badversion, "\t%qu message%s received with bad version\n");
+ p(pim6s_rcv_registers, "\t%qu register%s received\n");
+ p(pim6s_rcv_badregisters, "\t%qu bad register%s received\n");
+ p(pim6s_snd_registers, "\t%qu register%s sent\n");
+#undef p
+}
+
+/*
+ * Pretty print an Internet address (net address + port).
+ * If the nflag was specified, use numbers instead of names.
+ */
+
+void
+inet6print(in6, port, proto)
+ register struct in6_addr *in6;
+ int port;
+ char *proto;
+{
+#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));\
+};
+ struct servent *sp = 0;
+ char line[80], *cp;
+ int width;
+
+ sprintf(line, "%.*s.", (Aflag && !nflag) ? 12 : 16, inet6name(in6));
+ cp = index(line, '\0');
+ if (!nflag && 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 = Aflag ? 18 : 22;
+ printf(" %-*.*s", width, width, line);
+}
+
+/*
+ * Construct an Internet address representation.
+ * If the nflag has been supplied, give
+ * numeric value, otherwise try for symbolic name.
+ */
+
+char *
+inet6name(in6p)
+ struct in6_addr *in6p;
+{
+ register char *cp;
+ static char line[50];
+ struct hostent *hp;
+ static char domain[MAXHOSTNAMELEN + 1];
+ static int first = 1;
+ static char hbuf[NI_MAXHOST];
+ struct sockaddr_in6 sin6;
+#ifdef NI_WITHSCOPEID
+ const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID;
+#else
+ const int niflag = NI_NUMERICHOST;
+#endif
+
+ if (first && !nflag) {
+ first = 0;
+ if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
+ (cp = index(domain, '.')))
+ (void) strcpy(domain, cp + 1);
+ else
+ domain[0] = 0;
+ }
+ cp = 0;
+ if (!nflag && !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 {
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_len = sizeof(sin6);
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = *in6p;
+#ifdef KAME_SCOPEID
+ if (IN6_IS_ADDR_LINKLOCAL(in6p)) {
+ sin6.sin6_scope_id =
+ ntohs(*(u_int16_t *)&in6p->s6_addr[2]);
+ sin6.sin6_addr.s6_addr[2] = 0;
+ sin6.sin6_addr.s6_addr[3] = 0;
+ }
+#endif
+ if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
+ hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
+ strcpy(hbuf, "?");
+ strncpy(line, hbuf, sizeof(line));
+ }
+ return (line);
+}
+
+#ifdef TCP6
+/*
+ * Dump the contents of a TCP6 PCB.
+ */
+void
+tcp6_dump(pcbaddr)
+ u_long pcbaddr;
+{
+ struct tcp6cb tcp6cb;
+ int i;
+
+ kread(pcbaddr, (char *)&tcp6cb, sizeof(tcp6cb));
+
+ printf("TCP Protocol Control Block at 0x%08lx:\n\n", pcbaddr);
+
+ printf("Timers:\n");
+ for (i = 0; i < TCP6T_NTIMERS; i++)
+ printf("\t%s: %u", tcp6timers[i], tcp6cb.t_timer[i]);
+ printf("\n\n");
+
+ if (tcp6cb.t_state < 0 || tcp6cb.t_state >= TCP6_NSTATES)
+ printf("State: %d", tcp6cb.t_state);
+ else
+ printf("State: %s", tcp6states[tcp6cb.t_state]);
+ printf(", flags 0x%x, in6pcb 0x%lx\n\n", tcp6cb.t_flags,
+ (u_long)tcp6cb.t_in6pcb);
+
+ printf("rxtshift %d, rxtcur %d, dupacks %d\n", tcp6cb.t_rxtshift,
+ tcp6cb.t_rxtcur, tcp6cb.t_dupacks);
+ printf("peermaxseg %u, maxseg %u, force %d\n\n", tcp6cb.t_peermaxseg,
+ tcp6cb.t_maxseg, tcp6cb.t_force);
+
+ printf("snd_una %u, snd_nxt %u, snd_up %u\n",
+ tcp6cb.snd_una, tcp6cb.snd_nxt, tcp6cb.snd_up);
+ printf("snd_wl1 %u, snd_wl2 %u, iss %u, snd_wnd %lu\n\n",
+ tcp6cb.snd_wl1, tcp6cb.snd_wl2, tcp6cb.iss, tcp6cb.snd_wnd);
+
+ printf("rcv_wnd %lu, rcv_nxt %u, rcv_up %u, irs %u\n\n",
+ tcp6cb.rcv_wnd, tcp6cb.rcv_nxt, tcp6cb.rcv_up, tcp6cb.irs);
+
+ printf("rcv_adv %u, snd_max %u, snd_cwnd %lu, snd_ssthresh %lu\n",
+ tcp6cb.rcv_adv, tcp6cb.snd_max, tcp6cb.snd_cwnd, tcp6cb.snd_ssthresh);
+
+ printf("idle %d, rtt %d, rtseq %u, srtt %d, rttvar %d, rttmin %d, "
+ "max_sndwnd %lu\n\n", tcp6cb.t_idle, tcp6cb.t_rtt, tcp6cb.t_rtseq,
+ tcp6cb.t_srtt, tcp6cb.t_rttvar, tcp6cb.t_rttmin, tcp6cb.max_sndwnd);
+
+ printf("oobflags %d, iobc %d, softerror %d\n\n", tcp6cb.t_oobflags,
+ tcp6cb.t_iobc, tcp6cb.t_softerror);
+
+ printf("snd_scale %d, rcv_scale %d, req_r_scale %d, req_s_scale %d\n",
+ tcp6cb.snd_scale, tcp6cb.rcv_scale, tcp6cb.request_r_scale,
+ tcp6cb.requested_s_scale);
+ printf("ts_recent %u, ts_regent_age %d, last_ack_sent %u\n",
+ tcp6cb.ts_recent, tcp6cb.ts_recent_age, tcp6cb.last_ack_sent);
+}
+#endif
+
+#endif /*INET6*/
diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c
index 230290534c0..188de0b3907 100644
--- a/usr.bin/netstat/main.c
+++ b/usr.bin/netstat/main.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: main.c,v 1.18 1999/10/29 03:26:40 angelos Exp $ */
+/* $OpenBSD: main.c,v 1.19 1999/12/08 12:30:17 itojun Exp $ */
/* $NetBSD: main.c,v 1.9 1996/05/07 02:55:02 thorpej Exp $ */
/*
@@ -44,7 +44,7 @@ char copyright[] =
#if 0
static char sccsid[] = "from: @(#)main.c 8.4 (Berkeley) 3/1/94";
#else
-static char *rcsid = "$OpenBSD: main.c,v 1.18 1999/10/29 03:26:40 angelos Exp $";
+static char *rcsid = "$OpenBSD: main.c,v 1.19 1999/12/08 12:30:17 itojun Exp $";
#endif
#endif /* not lint */
@@ -153,6 +153,24 @@ struct nlist nl[] = {
{ "_ddpcb"},
#define N_ETHERIPSTAT 41
{ "_etheripstat"},
+#define N_IP6STAT 42
+ { "_ip6stat" },
+#define N_ICMP6STAT 43
+ { "_icmp6stat" },
+#define N_IPSECSTAT 44
+ { "_ipsecstat" },
+#define N_IPSEC6STAT 45
+ { "_ipsec6stat" },
+#define N_PIM6STAT 46
+ { "_pim6stat" },
+#define N_MRT6PROTO 47
+ { "_ip6_mrtproto" },
+#define N_MRT6STAT 48
+ { "_mrt6stat" },
+#define N_MF6CTABLE 49
+ { "_mf6ctable" },
+#define N_MIF6TABLE 50
+ { "_mif6table" },
{ ""},
};
@@ -186,6 +204,19 @@ struct protox {
0, 0 }
};
+#ifdef INET6
+struct protox ip6protox[] = {
+ { -1, N_IP6STAT, 1, 0,
+ ip6_stats, "ip6" },
+ { -1, N_ICMP6STAT, 1, 0,
+ icmp6_stats, "icmp6" },
+ { -1, N_PIM6STAT, 1, 0,
+ pim6_stats, "pim6" },
+ { -1, -1, 0, 0,
+ 0, 0 }
+};
+#endif
+
struct protox ipxprotox[] = {
{ N_IPX, N_IPXSTAT, 1, ipxprotopr,
ipx_stats, "ipx" },
@@ -228,7 +259,11 @@ struct protox atalkprotox[] = {
0, 0 }
};
+#ifndef INET6
struct protox *protoprotox[] = { protox, ipxprotox, nsprotox, isoprotox, atalkprotox, NULL };
+#else
+struct protox *protoprotox[] = { protox, ip6protox, ipxprotox, nsprotox, isoprotox, atalkprotox, NULL };
+#endif
static void printproto __P((struct protox *, char *));
static void usage __P((void));
@@ -245,14 +280,14 @@ main(argc, argv)
extern char *optarg;
extern int optind;
register struct protoent *p;
- register struct protox *tp; /* for printing cblocks & stats */
+ register struct protox *tp = NULL; /* for printing cblocks & stats */
int ch;
char *nlistf = NULL, *memf = NULL;
char buf[_POSIX2_LINE_MAX];
af = AF_UNSPEC;
- while ((ch = getopt(argc, argv, "Aadf:gI:iM:mN:np:rstuvw:")) != -1)
+ while ((ch = getopt(argc, argv, "Aadf:gI:ilM:mN:np:rstuvw:")) != -1)
switch(ch) {
case 'A':
Aflag = 1;
@@ -266,6 +301,8 @@ main(argc, argv)
case 'f':
if (strcmp(optarg, "inet") == 0)
af = AF_INET;
+ else if (strcmp(optarg, "inet6") == 0)
+ af = AF_INET6;
else if (strcmp(optarg, "local") == 0)
af = AF_LOCAL;
else if (strcmp(optarg, "unix") == 0)
@@ -297,6 +334,9 @@ main(argc, argv)
case 'i':
iflag = 1;
break;
+ case 'l':
+ lflag = 1;
+ break;
case 'M':
memf = optarg;
break;
@@ -417,14 +457,29 @@ main(argc, argv)
exit(0);
}
if (gflag) {
- if (sflag)
- mrt_stats(nl[N_MRTPROTO].n_value,
- nl[N_MRTSTAT].n_value);
- else
- mroutepr(nl[N_MRTPROTO].n_value,
- nl[N_MFCHASHTBL].n_value,
- nl[N_MFCHASH].n_value,
- nl[N_VIFTABLE].n_value);
+ if (sflag) {
+ if (af == AF_INET || af == AF_UNSPEC)
+ mrt_stats(nl[N_MRTPROTO].n_value,
+ nl[N_MRTSTAT].n_value);
+#ifdef INET6
+ if (af == AF_INET6 || af == AF_UNSPEC)
+ mrt6_stats(nl[N_MRT6PROTO].n_value,
+ nl[N_MRT6STAT].n_value);
+#endif
+ }
+ else {
+ if (af == AF_INET || af == AF_UNSPEC)
+ mroutepr(nl[N_MRTPROTO].n_value,
+ nl[N_MFCHASHTBL].n_value,
+ nl[N_MFCHASH].n_value,
+ nl[N_VIFTABLE].n_value);
+#ifdef INET6
+ if (af == AF_INET6 || af == AF_UNSPEC)
+ mroute6pr(nl[N_MRT6PROTO].n_value,
+ nl[N_MF6CTABLE].n_value,
+ nl[N_MIF6TABLE].n_value);
+#endif
+ }
exit(0);
}
if (af == AF_INET || af == AF_UNSPEC) {
@@ -441,6 +496,11 @@ main(argc, argv)
}
endprotoent();
}
+#ifdef INET6
+ if (af == AF_INET6 || af == AF_UNSPEC)
+ for (tp = ip6protox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#endif
if (af == AF_IPX || af == AF_UNSPEC)
for (tp = ipxprotox; tp->pr_name; tp++)
printproto(tp, tp->pr_name);
diff --git a/usr.bin/netstat/mroute6.c b/usr.bin/netstat/mroute6.c
new file mode 100644
index 00000000000..50ce7c2bd23
--- /dev/null
+++ b/usr.bin/netstat/mroute6.c
@@ -0,0 +1,280 @@
+/* $OpenBSD: mroute6.c,v 1.1 1999/12/08 12:30:17 itojun Exp $ */
+
+/*
+ * 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/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/protosw.h>
+
+#include <net/if.h>
+
+#include <netinet/in.h>
+
+#define _KERNEL 1
+#include <netinet6/ip6_mroute.h>
+#undef _KERNEL
+
+#include <stdio.h>
+#include "netstat.h"
+
+#ifdef INET6
+
+#define WID_ORG (lflag ? 39 : (nflag ? 29 : 18)) /* width of origin column */
+#define WID_GRP (lflag ? 18 : (nflag ? 16 : 18)) /* width of group column */
+
+void
+mroute6pr(mrpaddr, mfcaddr, mifaddr)
+ u_long mrpaddr, mfcaddr, mifaddr;
+{
+ u_int mrtproto;
+ struct mf6c *mf6ctable[MF6CTBLSIZ], *mfcp;
+ struct mif6 mif6table[MAXMIFS];
+ struct mf6c mfc;
+ struct rtdetq rte, *rtep;
+ register struct mif6 *mifp;
+ register mifi_t mifi;
+ register int i;
+ register int banner_printed;
+ register int saved_nflag;
+ mifi_t maxmif = 0;
+ int waitings;
+
+ if (mrpaddr == 0) {
+ printf("mroute6pr: symbol not in namelist\n");
+ return;
+ }
+
+ kread(mrpaddr, (char *)&mrtproto, sizeof(mrtproto));
+ switch (mrtproto) {
+
+ case 0:
+ printf("no IPv6 multicast routing compiled into this system\n");
+ return;
+
+ case IPPROTO_PIM:
+ break;
+
+ default:
+ printf("IPv6 multicast routing protocol %u, unknown\n",
+ mrtproto);
+ return;
+ }
+
+ if (mfcaddr == 0) {
+ printf("mf6ctable: symbol not in namelist\n");
+ return;
+ }
+ if (mifaddr == 0) {
+ printf("miftable: symbol not in namelist\n");
+ return;
+ }
+
+ saved_nflag = nflag;
+ nflag = 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(" %9qu %9qu\n", mifp->m6_pkt_in, 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(" %9qu", 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(" %3d", waitings);
+
+ if (mfc.mf6c_parent == MF6C_INCOMPLETE_PARENT)
+ printf(" --- ");
+ else
+ printf(" %3d ", mfc.mf6c_parent);
+ for (mifi = 0; mifi <= MAXMIFS; 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");
+ nflag = saved_nflag;
+}
+
+void
+mrt6_stats(mrpaddr, mstaddr)
+ u_long mrpaddr, mstaddr;
+{
+ u_int mrtproto;
+ struct mrt6stat mrtstat;
+
+ if(mrpaddr == 0) {
+ printf("mrt6_stats: symbol not in namelist\n");
+ return;
+ }
+
+ kread(mrpaddr, (char *)&mrtproto, sizeof(mrtproto));
+ switch (mrtproto) {
+ case 0:
+ printf("no IPv6 multicast routing compiled into this system\n");
+ return;
+
+ case IPPROTO_PIM:
+ break;
+
+ default:
+ printf("IPv6 multicast routing protocol %u, unknown\n",
+ mrtproto);
+ return;
+ }
+
+ if (mstaddr == 0) {
+ printf("mrt6_stats: symbol not in namelist\n");
+ return;
+ }
+
+ kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat));
+ printf("multicast forwarding:\n");
+ printf(" %10qu multicast forwarding cache lookup%s\n",
+ mrtstat.mrt6s_mfc_lookups, plural(mrtstat.mrt6s_mfc_lookups));
+ printf(" %10qu multicast forwarding cache miss%s\n",
+ mrtstat.mrt6s_mfc_misses, plurales(mrtstat.mrt6s_mfc_misses));
+ printf(" %10qu upcall%s to mrouted\n",
+ mrtstat.mrt6s_upcalls, plural(mrtstat.mrt6s_upcalls));
+ printf(" %10qu upcall queue overflow%s\n",
+ mrtstat.mrt6s_upq_ovflw, plural(mrtstat.mrt6s_upq_ovflw));
+ printf(" %10qu upcall%s dropped due to full socket buffer\n",
+ mrtstat.mrt6s_upq_sockfull, plural(mrtstat.mrt6s_upq_sockfull));
+ printf(" %10qu cache cleanup%s\n",
+ mrtstat.mrt6s_cache_cleanups, plural(mrtstat.mrt6s_cache_cleanups));
+ printf(" %10qu datagram%s with no route for origin\n",
+ mrtstat.mrt6s_no_route, plural(mrtstat.mrt6s_no_route));
+ printf(" %10qu datagram%s arrived with bad tunneling\n",
+ mrtstat.mrt6s_bad_tunnel, plural(mrtstat.mrt6s_bad_tunnel));
+ printf(" %10qu datagram%s could not be tunneled\n",
+ mrtstat.mrt6s_cant_tunnel, plural(mrtstat.mrt6s_cant_tunnel));
+ printf(" %10qu datagram%s arrived on wrong interface\n",
+ mrtstat.mrt6s_wrong_if, plural(mrtstat.mrt6s_wrong_if));
+ printf(" %10qu datagram%s selectively dropped\n",
+ mrtstat.mrt6s_drop_sel, plural(mrtstat.mrt6s_drop_sel));
+ printf(" %10qu datagram%s dropped due to queue overflow\n",
+ mrtstat.mrt6s_q_overflow, plural(mrtstat.mrt6s_q_overflow));
+ printf(" %10qu datagram%s dropped for being too large\n",
+ mrtstat.mrt6s_pkt2large, plural(mrtstat.mrt6s_pkt2large));
+}
+#endif /*INET6*/
diff --git a/usr.bin/netstat/netstat.1 b/usr.bin/netstat/netstat.1
index 94d8f6070b9..22b4a292acb 100644
--- a/usr.bin/netstat/netstat.1
+++ b/usr.bin/netstat/netstat.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: netstat.1,v 1.18 1999/09/01 17:22:03 aaron Exp $
+.\" $OpenBSD: netstat.1,v 1.19 1999/12/08 12:30:17 itojun Exp $
.\" $NetBSD: netstat.1,v 1.11 1995/10/03 21:42:43 thorpej Exp $
.\"
.\" Copyright (c) 1983, 1990, 1992, 1993
@@ -61,6 +61,15 @@
.Op Fl p Ar protocol
.Op Fl M Ar core
.Op Fl N Ar system
+.Nm netstat
+.Op Fl p Ar protocol
+.Op Fl i
+.Op Fl I Ar Interface
+.Nm netstat
+.Op Fl s
+.Op Fl f Ar address_family
+.Op Fl i
+.Op Fl I Ar Interface
.Sh DESCRIPTION
The
.Nm netstat
@@ -79,6 +88,8 @@ interval specified,
will continuously display the information regarding packet
traffic on the configured network interfaces.
The fourth form displays statistics about the named protocol.
+The fifth and sixth forms display per interface statistics for
+the specified protocol or address family.
.Pp
The options are as follows:
.Bl -tag -width flag
@@ -104,6 +115,9 @@ are recognized:
.Ar inet ,
for
.Dv AF_INET ,
+.Ar inet6 ,
+for
+.Dv AF_INET6 ,
.Ar ipx ,
for
.Dv AF_IPX ,
@@ -137,6 +151,19 @@ Show information about the specified interface;
used with a
.Ar wait
interval as described below.
+If the
+.Fl f Ar address_family
+option (with the
+.Fl s
+option) or the
+.Fl p Ar protocol
+option is present, show per-interface statistics on the
+.Ar interface
+for the specfied
+.Ar address_family
+or
+.Ar protocol,
+respectively.
.It Fl i
Show the state of interfaces which have been auto-configured
(interfaces statically configured into a system, but not
@@ -147,6 +174,18 @@ options 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 the
+.Fl f Ar address_family
+option (with the
+.Fl s
+option) or the
+.Fl p Ar protocol
+option is present, show per-interface statistics on all interfaces
+for the specfied
+.Ar address_family
+or
+.Ar protocol,
+respectively.
.It Fl M Ar core
Extract values associated with the name list from the specified core
instead of the default
@@ -183,7 +222,8 @@ When
.Fl s
is also present, show routing statistics instead.
.It Fl v
-Be verbose. This currently has no effect.
+Be verbose.
+Avoids truncation of long addresses.
.It Fl w Ar wait
Show network interface statistics at intervals of
.Ar wait
@@ -301,6 +341,7 @@ The
.Nm netstat
command appeared in
.Bx 4.2 .
+IPv6 support was added by WIDE/KAME project.
.\" .Sh FILES
.\" .Bl -tag -width /dev/kmem -compact
.\" .It Pa /bsd
diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h
index 4b6b18779ae..71797c3c98a 100644
--- a/usr.bin/netstat/netstat.h
+++ b/usr.bin/netstat/netstat.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: netstat.h,v 1.12 1999/10/29 03:26:40 angelos Exp $ */
+/* $OpenBSD: netstat.h,v 1.13 1999/12/08 12:30:17 itojun Exp $ */
/* $NetBSD: netstat.h,v 1.6 1996/05/07 02:55:05 thorpej Exp $ */
/*
@@ -46,6 +46,7 @@ int aflag; /* show all sockets (including servers) */
int dflag; /* show i/f dropped packets */
int gflag; /* show group (multicast) routing or stats */
int iflag; /* show interfaces */
+int lflag; /* show routing table with use and ref */
int mflag; /* show memory stats */
int nflag; /* show addresses numerically */
int pflag; /* show given protocol */
@@ -86,7 +87,7 @@ void impstats __P((u_long, u_long));
void intpr __P((int, u_long));
-void pr_rthdr __P(());
+void pr_rthdr __P((int));
void pr_encaphdr __P(());
void pr_family __P((int));
void rt_stats __P((u_long));
@@ -94,6 +95,21 @@ char *ns_phost __P((struct sockaddr *));
char *ipx_phost __P((struct sockaddr *));
void upHex __P((char *));
+#ifdef INET6
+struct in6_addr;
+struct sockaddr_in6;
+void ip6protopr __P((u_long, char *));
+void ip6_stats __P((u_long, char *));
+void ip6_ifstats __P((char *));
+void icmp6_stats __P((u_long, char *));
+void icmp6_ifstats __P((char *));
+void pim6_stats __P((u_long, char *));
+void mroute6pr __P((u_long, u_long, u_long));
+void mrt6_stats __P((u_long, u_long));
+char *routename6 __P((struct sockaddr_in6 *));
+char *netname6 __P((struct sockaddr_in6 *, struct in6_addr *));
+#endif /*INET6*/
+
char *routename __P((in_addr_t));
char *netname __P((in_addr_t, in_addr_t));
char *ns_print __P((struct sockaddr *));
diff --git a/usr.bin/netstat/route.c b/usr.bin/netstat/route.c
index 9b747220843..ce1643fc846 100644
--- a/usr.bin/netstat/route.c
+++ b/usr.bin/netstat/route.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: route.c,v 1.29 1999/09/22 05:10:04 deraadt Exp $ */
+/* $OpenBSD: route.c,v 1.30 1999/12/08 12:30:17 itojun Exp $ */
/* $NetBSD: route.c,v 1.15 1996/05/07 02:55:06 thorpej Exp $ */
/*
@@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "from: @(#)route.c 8.3 (Berkeley) 3/9/94";
#else
-static char *rcsid = "$OpenBSD: route.c,v 1.29 1999/09/22 05:10:04 deraadt Exp $";
+static char *rcsid = "$OpenBSD: route.c,v 1.30 1999/12/08 12:30:17 itojun Exp $";
#endif
#endif /* not lint */
@@ -64,6 +64,8 @@ static char *rcsid = "$OpenBSD: route.c,v 1.29 1999/09/22 05:10:04 deraadt Exp $
#include <sys/sysctl.h>
+#include <arpa/inet.h>
+
#include <limits.h>
#include <netdb.h>
#include <stdio.h>
@@ -167,7 +169,7 @@ routepr(rtree)
pr_family(i);
do_rtent = 1;
if (i != PF_KEY)
- pr_rthdr();
+ pr_rthdr(i);
else
pr_encaphdr();
p_tree(head.rnh_treetop);
@@ -189,6 +191,11 @@ pr_family(af)
case AF_INET:
afname = "Internet";
break;
+#ifdef INET6
+ case AF_INET6:
+ afname = "Internet6";
+ break;
+#endif
case AF_NS:
afname = "XNS";
break;
@@ -218,21 +225,35 @@ pr_family(af)
}
/* column widths; each followed by one space */
-#define WID_DST 18 /* width of destination column */
-#define WID_GW 18 /* width of gateway column */
+#ifndef INET6
+#define WID_DST(af) 18 /* width of destination column */
+#define WID_GW(af) 18 /* width of gateway column */
+#else
+/* width of destination/gateway column */
+#ifdef KAME_SCOPEID
+/* strlen("fe80::aaaa:bbbb:cccc:dddd@gif0") == 30, strlen("/128") == 4 */
+#define WID_DST(af) ((af) == AF_INET6 ? (nflag ? 34 : 18) : 18)
+#define WID_GW(af) ((af) == AF_INET6 ? (nflag ? 30 : 18) : 18)
+#else
+/* strlen("fe80::aaaa:bbbb:cccc:dddd") == 25, strlen("/128") == 4 */
+#define WID_DST(af) ((af) == AF_INET6 ? (nflag ? 29 : 18) : 18)
+#define WID_GW(af) ((af) == AF_INET6 ? (nflag ? 25 : 18) : 18)
+#endif
+#endif /* INET6 */
/*
* Print header for routing table columns.
*/
void
-pr_rthdr()
+pr_rthdr(af)
+ int af;
{
if (Aflag)
printf("%-*.*s ", PLEN, PLEN, "Address");
printf("%-*.*s %-*.*s %-6.6s %6.6s %6.6s %6.6s %s\n",
- WID_DST, WID_DST, "Destination",
- WID_GW, WID_GW, "Gateway",
+ WID_DST(af), WID_DST(af), "Destination",
+ WID_GW(af), WID_GW(af), "Gateway",
"Flags", "Refs", "Use", "Mtu", "Interface");
}
@@ -425,6 +446,36 @@ p_sockaddr(sa, mask, flags, width)
break;
}
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
+#ifdef KAME_SCOPEID
+ 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;
+ }
+#endif
+
+ 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
+
case AF_NS:
cp = ns_print(sa);
break;
@@ -532,23 +583,28 @@ p_rtentry(rt)
register struct rtentry *rt;
{
static struct ifnet ifnet, *lastif;
- struct sockaddr sock1, sock2;
- struct sockaddr *sa = &sock1, *mask = &sock2;
+ struct sockaddr_storage sock1, sock2;
+ struct sockaddr *sa = (struct sockaddr *)&sock1;
+ struct sockaddr *mask = (struct sockaddr *)&sock2;
bcopy(kgetsa(rt_key(rt)), sa, sizeof(struct sockaddr));
+ if (sa->sa_len > sizeof(struct sockaddr))
+ bcopy(kgetsa(rt_key(rt)), sa, sa->sa_len);
if (sa->sa_family == PF_KEY) {
encap_print(rt);
return;
}
- if (rt_mask(rt))
+ if (rt_mask(rt)) {
bcopy(kgetsa(rt_mask(rt)), mask, sizeof(struct sockaddr));
- else
+ if (sa->sa_len > sizeof(struct sockaddr))
+ bcopy(kgetsa(rt_mask(rt)), mask, sa->sa_len);
+ } else
mask = 0;
- p_sockaddr(sa, mask, rt->rt_flags, WID_DST);
- p_sockaddr(kgetsa(rt->rt_gateway), 0, RTF_HOST, WID_GW);
+ p_sockaddr(sa, mask, rt->rt_flags, WID_DST(sa->sa_family));
+ p_sockaddr(kgetsa(rt->rt_gateway), 0, RTF_HOST, WID_GW(sa->sa_family));
p_flags(rt->rt_flags, "%-6.6s ");
printf("%6d %8ld ", rt->rt_refcnt, rt->rt_use);
if (rt->rt_rmx.rmx_mtu)
@@ -618,13 +674,12 @@ netname(in, mask)
char *cp = 0;
static char line[MAXHOSTNAMELEN];
struct netent *np = 0;
- in_addr_t net, subnetshift;
int mbits;
in = ntohl(in);
mask = ntohl(mask);
if (!nflag && in != INADDR_ANY) {
- if (np = getnetbyaddr(in, AF_INET))
+ if ((np = getnetbyaddr(in, AF_INET)) != NULL)
cp = np->n_name;
}
mbits = mask ? 33 - ffs(mask) : 0;
@@ -645,6 +700,110 @@ netname(in, mask)
return (line);
}
+#ifdef INET6
+char *
+netname6(sa6, mask)
+ struct sockaddr_in6 *sa6;
+ struct in6_addr *mask;
+{
+ static char line[MAXHOSTNAMELEN + 1];
+ struct in6_addr net6;
+ u_char *p;
+ u_char *lim;
+ int masklen, final = 0, illegal = 0;
+ int i;
+ char hbuf[NI_MAXHOST];
+#ifdef NI_WITHSCOPEID
+ int flag = NI_WITHSCOPEID;
+#else
+ int flag = 0;
+#endif
+
+ net6 = sa6->sin6_addr;
+ for (i = 0; i < sizeof(net6); i++)
+ net6.s6_addr[i] &= mask->s6_addr[i];
+
+ masklen = 0;
+ lim = (u_char *)mask + 16;
+ for (p = (u_char *)mask; p < lim; p++) {
+ if (final && *p) {
+ illegal++;
+ continue;
+ }
+
+ switch (*p & 0xff) {
+ case 0xff:
+ masklen += 8;
+ break;
+ case 0xfe:
+ masklen += 7;
+ final++;
+ break;
+ case 0xfc:
+ masklen += 6;
+ final++;
+ break;
+ case 0xf8:
+ masklen += 5;
+ final++;
+ break;
+ case 0xf0:
+ masklen += 4;
+ final++;
+ break;
+ case 0xe0:
+ masklen += 3;
+ final++;
+ break;
+ case 0xc0:
+ masklen += 2;
+ final++;
+ break;
+ case 0x80:
+ masklen += 1;
+ final++;
+ break;
+ case 0x00:
+ final++;
+ break;
+ default:
+ final++;
+ illegal++;
+ break;
+ }
+ }
+
+ if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr))
+ return("default");
+
+ if (illegal)
+ fprintf(stderr, "illegal prefixlen\n");
+
+ if (nflag)
+ flag |= NI_NUMERICHOST;
+ getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, hbuf, sizeof(hbuf),
+ NULL, 0, flag);
+ snprintf(line, sizeof(line), "%s/%d", hbuf, masklen);
+ return line;
+}
+
+char *
+routename6(sa6)
+ struct sockaddr_in6 *sa6;
+{
+ static char line[NI_MAXHOST];
+#ifdef NI_WITHSCOPEID
+ const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID;
+#else
+ const int niflag = NI_NUMERICHOST;
+#endif
+ if (getnameinfo((struct sockaddr *)sa6, sa6->sin6_len,
+ line, sizeof(line), NULL, 0, niflag) != 0)
+ strcpy(line, "");
+ return line;
+}
+#endif /*INET6*/
+
/*
* Print routing statistics
*/
@@ -826,7 +985,7 @@ encap_print(rt)
sen2.sen_ip_dst.s_addr),
sen1.sen_dport, sen1.sen_proto);
- printf("%s/%08x/%-lu\n", inet_ntoa(sen3.sen_ipsp_dst),
+ printf("%s/%08x/%-u\n", inet_ntoa(sen3.sen_ipsp_dst),
ntohl(sen3.sen_ipsp_spi), sen3.sen_ipsp_sproto);
}
diff --git a/usr.bin/netstat/unix.c b/usr.bin/netstat/unix.c
index 0f8846c4d22..2547eb0ba11 100644
--- a/usr.bin/netstat/unix.c
+++ b/usr.bin/netstat/unix.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: unix.c,v 1.5 1997/06/29 21:46:06 millert Exp $ */
+/* $OpenBSD: unix.c,v 1.6 1999/12/08 12:30:17 itojun Exp $ */
/* $NetBSD: unix.c,v 1.13 1995/10/03 21:42:48 thorpej Exp $ */
/*-
@@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "from: @(#)unix.c 8.1 (Berkeley) 6/6/93";
#else
-static char *rcsid = "$OpenBSD: unix.c,v 1.5 1997/06/29 21:46:06 millert Exp $";
+static char *rcsid = "$OpenBSD: unix.c,v 1.6 1999/12/08 12:30:17 itojun Exp $";
#endif
#endif /* not lint */
@@ -110,7 +110,7 @@ unixdomainpr(so, soaddr)
{
struct unpcb unpcb, *unp = &unpcb;
struct mbuf mbuf, *m;
- struct sockaddr_un *sa;
+ struct sockaddr_un *sa = NULL;
static int first = 1;
if (kread((u_long)so->so_pcb, (char *)unp, sizeof (*unp)))
@@ -137,7 +137,7 @@ unixdomainpr(so, soaddr)
PLEN, unp->unp_refs, PLEN, unp->unp_nextref);
if (m)
printf(" %.*s",
- m->m_len - (int)(sizeof(*sa) - sizeof(sa->sun_path)),
+ (int)(m->m_len - (int)(sizeof(*sa) - sizeof(sa->sun_path))),
sa->sun_path);
putchar('\n');
}