summaryrefslogtreecommitdiffstats
path: root/usr.bin/netstat
diff options
context:
space:
mode:
authorshin <shin@FreeBSD.org>1999-12-07 17:39:16 +0000
committershin <shin@FreeBSD.org>1999-12-07 17:39:16 +0000
commit70f0bdf6818a73c858bc47a23afc1e9d7c56d716 (patch)
tree446280db4239de7d7d9030c47d2c30515a265a54 /usr.bin/netstat
parent7bdf4b7db0db632bec3b1040d83cdfbdb35e59cd (diff)
downloadFreeBSD-src-70f0bdf6818a73c858bc47a23afc1e9d7c56d716.zip
FreeBSD-src-70f0bdf6818a73c858bc47a23afc1e9d7c56d716.tar.gz
udp IPv6 support, IPv6/IPv4 tunneling support in kernel,
packet divert at kernel for IPv6/IPv4 translater daemon This includes queue related patch submitted by jburkhol@home.com. Submitted by: queue related patch from jburkhol@home.com Reviewed by: freebsd-arch, cvs-committers Obtained from: KAME project
Diffstat (limited to 'usr.bin/netstat')
-rw-r--r--usr.bin/netstat/Makefile3
-rw-r--r--usr.bin/netstat/if.c88
-rw-r--r--usr.bin/netstat/inet.c248
-rw-r--r--usr.bin/netstat/inet6.c962
-rw-r--r--usr.bin/netstat/main.c200
-rw-r--r--usr.bin/netstat/netstat.148
-rw-r--r--usr.bin/netstat/netstat.h24
-rw-r--r--usr.bin/netstat/route.c183
8 files changed, 1649 insertions, 107 deletions
diff --git a/usr.bin/netstat/Makefile b/usr.bin/netstat/Makefile
index 3c8092a..78e80c7 100644
--- a/usr.bin/netstat/Makefile
+++ b/usr.bin/netstat/Makefile
@@ -2,7 +2,7 @@
# @(#)Makefile 8.1 (Berkeley) 6/12/93
PROG= netstat
-SRCS= if.c inet.c main.c mbuf.c mroute.c ipx.c route.c \
+SRCS= if.c inet.c inet6.c main.c mbuf.c mroute.c ipx.c route.c \
unix.c atalk.c netgraph.c # iso.c ns.c tp_astring.c
CFLAGS+=-Wall
@@ -12,5 +12,6 @@ BINGRP= kmem
BINMODE=2555
DPADD= ${LIBKVM} ${LIBIPX} ${LIBNETGRAPH}
LDADD= -lkvm -lipx -lnetgraph
+#CFLAGS+= -DINET6
.include <bsd.prog.mk>
diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c
index 8343363..4366163 100644
--- a/usr.bin/netstat/if.c
+++ b/usr.bin/netstat/if.c
@@ -78,6 +78,12 @@ static const char rcsid[] =
static void sidewaysintpr __P((u_int, u_long));
static void catchalarm __P((int));
+#ifdef INET6
+char *netname6 __P((struct sockaddr_in6 *, struct in6_addr *));
+static char ntop_buf[INET6_ADDRSTRLEN]; /* for inet_ntop() */
+static int bdg_done;
+#endif
+
void
bdg_stats(u_long dummy, char *name) /* print bridge statistics */
{
@@ -94,6 +100,12 @@ bdg_stats(u_long dummy, char *name) /* print bridge statistics */
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");
@@ -116,15 +128,19 @@ bdg_stats(u_long dummy, char *name) /* print bridge statistics */
* Print a description of the network interfaces.
*/
void
-intpr(interval, ifnetaddr)
+intpr(interval, ifnetaddr, pfunc)
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;
#ifdef NS
struct ns_ifaddr ns;
@@ -153,22 +169,27 @@ intpr(interval, ifnetaddr)
if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet))
return;
- printf("%-5.5s %-5.5s %-13.13s %-15.15s %8.8s %5.5s",
- "Name", "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');
+ if (!sflag && !pflag) {
+ printf("%-5.5s %-5.5s %-13.13s %-15.15s %8.8s %5.5s",
+ "Name", "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 *sin;
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+#endif
register char *cp;
int n, m;
@@ -183,6 +204,12 @@ intpr(interval, ifnetaddr)
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';
@@ -225,6 +252,18 @@ intpr(interval, ifnetaddr)
printf("%-15.15s ",
routename(sin->sin_addr.s_addr));
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 ",
+ (char *)inet_ntop(AF_INET6,
+ &sin6->sin6_addr,
+ ntop_buf, sizeof(ntop_buf)));
+ break;
+#endif /*INET6*/
case AF_IPX:
{
struct sockaddr_ipx *sipx =
@@ -266,10 +305,12 @@ intpr(interval, ifnetaddr)
{
struct sockaddr_dl *sdl =
(struct sockaddr_dl *)sa;
- cp = (char *)LLADDR(sdl);
- n = sdl->sdl_alen;
+ char linknum[10];
+ cp = (char *)LLADDR(sdl);
+ n = sdl->sdl_alen;
+ sprintf(linknum, "<Link#%d>", sdl->sdl_index);
+ m = printf("%-11.11s ", linknum);
}
- m = printf("%-11.11s ", "<Link>");
goto hexprint;
default:
m = printf("(%d)", sa->sa_family);
@@ -311,6 +352,9 @@ intpr(interval, ifnetaddr)
union {
struct sockaddr sa;
struct sockaddr_in in;
+#ifdef INET6
+ struct sockaddr_in6 in6;
+#endif /* INET6 */
struct sockaddr_dl dl;
} msa;
const char *fmt;
@@ -332,7 +376,15 @@ intpr(interval, ifnetaddr)
case AF_INET:
fmt = routename(msa.in.sin_addr.s_addr);
break;
-
+#ifdef INET6
+ case AF_INET6:
+ printf("%23s %-19.19s(refs: %d)\n", "",
+ inet_ntop(AF_INET6,
+ &msa.in6.sin6_addr,
+ ntop_buf,
+ sizeof(ntop_buf)),
+ ifma.ifma_refcount);
+#endif /* INET6 */
case AF_LINK:
switch (ifnet.if_type) {
case IFT_ETHER:
diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c
index 783cbc7..4a8cda1 100644
--- a/usr.bin/netstat/inet.c
+++ b/usr.bin/netstat/inet.c
@@ -50,6 +50,9 @@ static const char rcsid[] =
#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>
@@ -65,6 +68,9 @@ static const char rcsid[] =
#include <netinet/tcp_debug.h>
#include <netinet/udp.h>
#include <netinet/udp_var.h>
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#endif
#include <arpa/inet.h>
#include <err.h>
@@ -78,6 +84,10 @@ static const char rcsid[] =
char *inetname __P((struct in_addr *));
void inetprint __P((struct in_addr *, int, char *, int));
+#ifdef INET6
+extern void inet6print __P((struct in6_addr *, int, char *, int));
+static int udp_done, tcp_done;
+#endif /* INET6 */
/*
* Print a summary of connections related to an Internet
@@ -86,9 +96,10 @@ void inetprint __P((struct in_addr *, int, char *, int));
* -a (all) flag is specified.
*/
void
-protopr(proto, name)
+protopr(proto, name, af)
u_long proto; /* for sysctl version we pass proto # */
char *name;
+ int af;
{
int istcp;
static int first = 1;
@@ -103,10 +114,22 @@ protopr(proto, name)
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:
@@ -153,7 +176,35 @@ protopr(proto, name)
if (inp->inp_gencnt > oxig->xig_gen)
continue;
- if (!aflag && inet_lnaof(inp->inp_laddr) == INADDR_ANY)
+ if ((af == AF_INET && (inp->inp_vflag & INP_IPV4) == 0)
+#ifdef INET6
+ || (af == AF_INET6 && (inp->inp_vflag & INP_IPV6) == 0)
+#endif /* INET6 */
+ || (af == AF_UNSPEC && ((inp->inp_vflag & INP_IPV4) == 0
+#ifdef INET6
+ && (inp->inp_vflag &
+ INP_IPV6) == 0
+#endif /* INET6 */
+ ))
+ )
+ continue;
+ if (!aflag &&
+ (
+ (af == AF_INET &&
+ inet_lnaof(inp->inp_laddr) == INADDR_ANY)
+#ifdef INET6
+ || (af == AF_INET6 &&
+ IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
+#endif /* INET6 */
+ || (af == 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) {
@@ -163,7 +214,9 @@ protopr(proto, name)
putchar('\n');
if (Aflag)
printf("%-8.8s ", "Socket");
- printf("%-5.5s %-6.6s %-6.6s %-21.21s %-21.21s %s\n",
+ 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;
@@ -174,23 +227,61 @@ protopr(proto, name)
else
printf("%8lx ", (u_long)so->so_pcb);
}
- printf("%-5.5s %6ld %6ld ", name, so->so_rcv.sb_cc,
- so->so_snd.sb_cc);
+ printf("%-3.3s%s%s %6ld %6ld ", name,
+ (inp->inp_vflag & INP_IPV4) ? "4" : "",
+#ifdef INET6
+ (inp->inp_vflag & INP_IPV6) ? "6" :
+#endif
+ "",
+ so->so_rcv.sb_cc,
+ so->so_snd.sb_cc);
if (nflag) {
- inetprint(&inp->inp_laddr, (int)inp->inp_lport,
- name, 1);
- inetprint(&inp->inp_faddr, (int)inp->inp_fport,
- name, 1);
+ if (inp->inp_vflag & INP_IPV4) {
+ inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+ name, 1);
+ 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);
+ inet6print(&inp->in6p_faddr,
+ (int)inp->inp_fport, name, 1);
+ } /* else nothing printed now */
+#endif /* INET6 */
} else if (inp->inp_flags & INP_ANONPORT) {
- inetprint(&inp->inp_laddr, (int)inp->inp_lport,
- name, 1);
- inetprint(&inp->inp_faddr, (int)inp->inp_fport,
- name, 0);
+ if (inp->inp_vflag & INP_IPV4) {
+ inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+ name, 1);
+ 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);
+ inet6print(&inp->in6p_faddr,
+ (int)inp->inp_fport, name, 0);
+ } /* else nothing printed now */
+#endif /* INET6 */
} else {
- inetprint(&inp->inp_laddr, (int)inp->inp_lport,
- name, 0);
- inetprint(&inp->inp_faddr, (int)inp->inp_fport,
- name, inp->inp_lport != inp->inp_fport);
+ if (inp->inp_vflag & INP_IPV4) {
+ inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+ name, 0);
+ 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);
+ inet6print(&inp->in6p_faddr,
+ (int)inp->inp_fport, name,
+ inp->inp_lport != inp->inp_fport);
+ } /* else nothing printed now */
+#endif /* INET6 */
}
if (istcp) {
if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES)
@@ -237,6 +328,13 @@ tcp_stats(off, name)
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) \
@@ -331,6 +429,13 @@ udp_stats(off, name)
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))
@@ -386,6 +491,7 @@ ip_stats(off, name)
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");
@@ -412,6 +518,7 @@ 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_nogif, "\t%lu tunneling packet%s that can't find gif\n");
#undef p
#undef p1a
}
@@ -541,6 +648,109 @@ igmp_stats(off, name)
#undef py
}
+#ifdef IPSEC
+static char *ipsec_ahnames[] = {
+ "none",
+ "hmac MD5",
+ "hmac SHA1",
+ "keyed MD5",
+ "keyed SHA1",
+ "null",
+};
+
+static char *ipsec_espnames[] = {
+ "none",
+ "DES CBC",
+ "3DES CBC",
+ "simple",
+ "blowfish CBC",
+ "CAST128 CBC",
+ "RC5 CBC",
+};
+
+/*
+ * Dump IPSEC statistics structure.
+ */
+void
+ipsec_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct ipsecstat ipsecstat;
+ int first, proto;
+
+ if (off == 0)
+ return;
+ printf ("%s:\n", name);
+ kread(off, (char *)&ipsecstat, sizeof (ipsecstat));
+
+#define p(f, m) if (ipsecstat.f || sflag <= 1) \
+ printf(m, ipsecstat.f, plural(ipsecstat.f))
+
+ p(in_success, "\t%lu inbound packet%s processed successfully\n");
+ p(in_polvio, "\t%lu inbound packet%s violated process security "
+ "policy\n");
+ p(in_nosa, "\t%lu inbound packet%s with no SA available\n");
+ p(in_inval, "\t%lu inbound packet%s failed processing due to EINVAL\n");
+ p(in_badspi, "\t%lu inbound packet%s failed getting SPI\n");
+ p(in_ahreplay, "\t%lu inbound packet%s failed on AH replay check\n");
+ p(in_espreplay, "\t%lu inbound packet%s failed on ESP replay check\n");
+ p(in_ahauthsucc, "\t%lu inbound AH packet%s considered authentic\n");
+ p(in_ahauthfail, "\t%lu inbound AH packet%s failed on authentication\n");
+ p(in_espauthsucc, "\t%lu inbound ESP packet%s considered authentic\n");
+ p(in_espauthfail, "\t%lu inbound ESP packet%s failed on authentication\n");
+ for (first = 1, proto = 0; proto < SADB_AALG_MAX; proto++) {
+ if (ipsecstat.in_ahhist[proto] <= 0)
+ continue;
+ if (first) {
+ printf("\tAH input histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %lu\n", ipsec_ahnames[proto],
+ ipsecstat.in_ahhist[proto]);
+ }
+ for (first = 1, proto = 0; proto < SADB_EALG_MAX; proto++) {
+ if (ipsecstat.in_esphist[proto] <= 0)
+ continue;
+ if (first) {
+ printf("\tESP input histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %lu\n", ipsec_espnames[proto],
+ ipsecstat.in_esphist[proto]);
+ }
+
+ p(out_success, "\t%lu outbound packet%s processed successfully\n");
+ p(out_polvio, "\t%lu outbound packet%s violated process security "
+ "policy\n");
+ p(out_nosa, "\t%lu outbound packet%s with no SA available\n");
+ p(out_inval, "\t%lu outbound packet%s failed processing due to "
+ "EINVAL\n");
+ p(out_noroute, "\t%lu outbound packet%s with no route\n");
+ for (first = 1, proto = 0; proto < SADB_AALG_MAX; proto++) {
+ if (ipsecstat.out_ahhist[proto] <= 0)
+ continue;
+ if (first) {
+ printf("\tAH output histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %lu\n", ipsec_ahnames[proto],
+ ipsecstat.out_ahhist[proto]);
+ }
+ for (first = 1, proto = 0; proto < SADB_EALG_MAX; proto++) {
+ if (ipsecstat.out_esphist[proto] <= 0)
+ continue;
+ if (first) {
+ printf("\tESP output histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %lu\n", ipsec_espnames[proto],
+ ipsecstat.out_esphist[proto]);
+ }
+#undef p
+}
+#endif /*IPSEC*/
+
/*
* Pretty print an Internet address (net address + port).
*/
@@ -553,6 +763,7 @@ inetprint(in, port, proto,numeric)
{
struct servent *sp = 0;
char line[80], *cp;
+ int width;
sprintf(line, "%.*s.", (Aflag && !numeric) ? 12 : 16, inetname(in));
cp = index(line, '\0');
@@ -562,7 +773,8 @@ inetprint(in, port, proto,numeric)
sprintf(cp, "%.15s", sp ? sp->s_name : "*");
else
sprintf(cp, "%d", ntohs((u_short)port));
- printf("%-21.21s ", line);
+ width = Aflag ? 18 : 22;
+ printf(" %-*.*s", width, width, line);
}
/*
diff --git a/usr.bin/netstat/inet6.c b/usr.bin/netstat/inet6.c
new file mode 100644
index 0000000..154ee32
--- /dev/null
+++ b/usr.bin/netstat/inet6.c
@@ -0,0 +1,962 @@
+/* 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef lint
+/*
+static char sccsid[] = "@(#)inet6.c 8.4 (Berkeley) 4/20/94";
+*/
+#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 <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 <arpa/inet.h>
+#include <netdb.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+
+struct socket sockb;
+
+char *inet6name __P((struct in6_addr *));
+void inet6print __P((struct in6_addr *, int, char *, int));
+
+static char ntop_buf[INET6_ADDRSTRLEN];
+
+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 p1a(f, m) if (ip6stat.f || sflag <= 1) \
+ printf(m, ip6stat.f)
+
+ p(ip6s_total, "\t%lu total packet%s received\n");
+ p1a(ip6s_toosmall, "\t%lu with size smaller than minimum\n");
+ p1a(ip6s_tooshort, "\t%lu with data size < data length\n");
+ p1a(ip6s_badoptions, "\t%lu with bad options\n");
+ p1a(ip6s_badvers, "\t%lu with incorrect version number\n");
+ p(ip6s_fragments, "\t%lu fragment%s received\n");
+ p(ip6s_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
+ p(ip6s_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
+ p(ip6s_fragoverflow, "\t%lu fragment%s that exceeded limit\n");
+ p(ip6s_reassembled, "\t%lu packet%s reassembled ok\n");
+ p(ip6s_delivered, "\t%lu packet%s for this host\n");
+ p(ip6s_forward, "\t%lu packet%s forwarded\n");
+ p(ip6s_cantforward, "\t%lu packet%s not forwardable\n");
+ p(ip6s_redirectsent, "\t%lu redirect%s sent\n");
+ p(ip6s_localout, "\t%lu packet%s sent from this host\n");
+ p(ip6s_rawout, "\t%lu packet%s sent with fabricated ip header\n");
+ p(ip6s_odropped, "\t%lu output packet%s dropped due to no bufs, etc.\n");
+ p(ip6s_noroute, "\t%lu output packet%s discarded due to no route\n");
+ p(ip6s_fragmented, "\t%lu output datagram%s fragmented\n");
+ p(ip6s_ofragments, "\t%lu fragment%s created\n");
+ p(ip6s_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
+ p(ip6s_badscope, "\t%lu packet%s that violated scope rules\n");
+ p(ip6s_notmember, "\t%lu 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: %lu\n", ip6nh[i],
+ ip6stat.ip6s_nxthist[i]);
+ }
+ printf("\tMbuf statistics:\n");
+ printf("\t\t%lu one mbuf\n", ip6stat.ip6s_m1);
+ for (first = 1, i = 0; i < 32; i++) {
+ if (ip6stat.ip6s_m2m[i] != 0) {
+ if (first) {
+ printf("\t\ttwo or more mbuf:\n");
+ first = 0;
+ }
+ printf("\t\t\t"
+#ifdef notyet
+ "%s"
+#else
+ "if%d"
+#endif
+ "= %ld\n",
+#ifdef notyet
+ if_indextoname(i, ifbuf),
+#else
+ i,
+#endif
+ ip6stat.ip6s_m2m[i]);
+ }
+ }
+ printf("\t\t%lu one ext mbuf\n", ip6stat.ip6s_mext1);
+ printf("\t\t%lu two or more ext mbuf\n", ip6stat.ip6s_mext2m);
+ p(ip6s_exthdrtoolong, "\t%lu packet%s whose headers are not continuous\n");
+ p(ip6s_nogif, "\t%lu tunneling packet%s that can't find gif\n");
+ p(ip6s_toomanyhdr, "\t%lu packet%s discarded due to too may headers\n");
+#undef p
+}
+
+/*
+ * 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_truncated, "\t%qu truncated datagram%s 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 ICMP6 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%lu call%s to icmp_error\n");
+ p(icp6s_canterror,
+ "\t%lu error%s not generated because old message was icmp error or so\n");
+ p(icp6s_toofreq,
+ "\t%lu error%s not generated because rate limitation\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: %lu\n", icmp6names[i],
+ icmp6stat.icp6s_outhist[i]);
+ }
+ p(icp6s_badcode, "\t%lu message%s with bad code fields\n");
+ p(icp6s_tooshort, "\t%lu message%s < minimum length\n");
+ p(icp6s_checksum, "\t%lu bad checksum%s\n");
+ p(icp6s_badlen, "\t%lu 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: %lu\n", icmp6names[i],
+ icmp6stat.icp6s_inhist[i]);
+ }
+ p(icp6s_reflect, "\t%lu message response%s generated\n");
+#undef p
+#undef p_5
+}
+
+/*
+ * 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%u message%s received\n");
+ p(pim6s_rcv_tooshort, "\t%u message%s received with too few bytes\n");
+ p(pim6s_rcv_badsum, "\t%u message%s received with bad checksum\n");
+ p(pim6s_rcv_badversion, "\t%u message%s received with bad version\n");
+ p(pim6s_rcv_registers, "\t%u register%s received\n");
+ p(pim6s_rcv_badregisters, "\t%u bad register%s received\n");
+ p(pim6s_snd_registers, "\t%u register%s sent\n");
+#undef p
+}
+
+/*
+ * Pretty print an Internet address (net address + port).
+ * If the nflag was specified, use numbers instead of names.
+ */
+#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(in6, port, proto, numeric)
+ register struct in6_addr *in6;
+ int port;
+ char *proto;
+ int numeric;
+{
+ struct servent *sp = 0;
+ char line[80], *cp;
+ int width;
+
+ sprintf(line, "%.*s.", lflag ? 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 = lflag ? 45 : 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;
+
+ 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
+ sprintf(line, "%s",
+ inet_ntop(AF_INET6, (void *)in6p, ntop_buf,
+ sizeof(ntop_buf)));
+ return (line);
+}
diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c
index 1a5bc14..034ffbd 100644
--- a/usr.bin/netstat/main.c
+++ b/usr.bin/netstat/main.c
@@ -125,6 +125,26 @@ static struct nlist nl[] = {
{ "_ddpcb"},
#define N_NGSOCKS 27
{ "_ngsocklist"},
+#define N_IP6STAT 28
+ { "_ip6stat" },
+#define N_ICMP6STAT 29
+ { "_icmp6stat" },
+#ifdef notyet
+#define N_IPSECSTAT 30
+ { "_ipsecstat" },
+#define N_IPSEC6STAT 31
+ { "_ipsec6stat" },
+#define N_PIM6STAT 32
+ { "_pim6stat" },
+#define N_MRT6PROTO 33
+ { "_ip6_mrtproto" },
+#define N_MRT6STAT 34
+ { "_mrt6stat" },
+#define N_MF6CTABLE 35
+ { "_mf6ctable" },
+#define N_MIF6TABLE 36
+ { "_mif6table" },
+#endif
{ "" },
};
@@ -134,81 +154,116 @@ struct protox {
u_char pr_wanted; /* 1 if wanted, 0 otherwise */
void (*pr_cblocks)(); /* control blocks printing routine */
void (*pr_stats)(); /* statistics printing routine */
+ void (*pr_istats)(); /* per/if statistics printing routine */
char *pr_name; /* well-known name */
int pr_usesysctl; /* true if we use sysctl, not kvm */
} protox[] = {
{ -1, -1, 1, protopr,
- tcp_stats, "tcp", IPPROTO_TCP },
+ tcp_stats, NULL, "tcp", IPPROTO_TCP },
{ -1, -1, 1, protopr,
- udp_stats, "udp", IPPROTO_UDP },
+ udp_stats, NULL, "udp", IPPROTO_UDP },
{ -1, -1, 1, protopr,
- NULL, "divert", IPPROTO_DIVERT },
+ NULL, NULL, "divert",IPPROTO_DIVERT },
{ -1, -1, 1, protopr,
- ip_stats, "ip", IPPROTO_RAW },
+ ip_stats, NULL, "ip", IPPROTO_RAW },
{ -1, -1, 1, protopr,
- icmp_stats, "icmp", IPPROTO_ICMP },
+ icmp_stats, NULL, "icmp", IPPROTO_ICMP },
{ -1, -1, 1, protopr,
- igmp_stats, "igmp", IPPROTO_IGMP },
+ igmp_stats, NULL, "igmp", IPPROTO_IGMP },
+#ifdef IPSEC
+ { -1, N_IPSECSTAT, 1, 0,
+ ipsec_stats, NULL, "ipsec", 0},
+#endif
{ -1, -1, 1, protopr,
- bdg_stats, "bdg", 1 /* bridging... */ },
+ bdg_stats, NULL, "bdg", 1 /* bridging... */ },
{ -1, -1, 0, 0,
- 0, 0 }
+ 0, 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, 0,
+ ip6_stats, ip6_ifstats, "ip6", 0 },
+ { -1, N_ICMP6STAT, 1, 0,
+ icmp6_stats, icmp6_ifstats, "icmp6",0 },
+#ifdef IPSEC
+ { -1, N_IPSEC6STAT, 1, 0,
+ ipsec_stats, NULL, "ipsec6",0 },
+#endif
+#ifdef notyet
+ { -1, N_PIM6STAT, 1, 0,
+ pim6_stats, NULL, "pim6", 0 },
+#endif
+ { -1, -1, 1, protopr,
+ bdg_stats, NULL, "bdg", 1 /* bridging... */ },
+ { -1, -1, 0, 0,
+ 0, NULL, 0, 0 }
+};
+#endif /*INET6*/
+
struct protox atalkprotox[] = {
{ N_DDPCB, N_DDPSTAT, 1, atalkprotopr,
- ddp_stats, "ddp" },
+ ddp_stats, NULL, "ddp" },
{ -1, -1, 0, 0,
- 0, 0 }
+ 0, NULL, 0 }
};
struct protox netgraphprotox[] = {
{ N_NGSOCKS, -1, 1, netgraphprotopr,
- NULL, "ctrl" },
+ NULL, NULL, "ctrl" },
{ N_NGSOCKS, -1, 1, netgraphprotopr,
- NULL, "data" },
- { -1, -1, 0, 0,
- 0, 0 }
+ NULL, NULL, "data" },
+ { -1, NULL, 0, 0,
+ 0, NULL, 0 }
};
struct protox ipxprotox[] = {
{ N_IPX, N_IPXSTAT, 1, ipxprotopr,
- ipx_stats, "ipx", 0 },
+ ipx_stats, NULL, "ipx", 0 },
{ N_IPX, N_SPXSTAT, 1, ipxprotopr,
- spx_stats, "spx", 0 },
+ spx_stats, NULL, "spx", 0 },
{ -1, -1, 0, 0,
- 0, 0, 0 }
+ 0, NULL, 0, 0 }
};
#ifdef NS
struct protox nsprotox[] = {
{ N_IDP, N_IDPSTAT, 1, nsprotopr,
- idp_stats, "idp" },
+ idp_stats, NULL, "idp" },
{ N_IDP, N_SPPSTAT, 1, nsprotopr,
- spp_stats, "spp" },
+ spp_stats, NULL, "spp" },
{ -1, N_NSERR, 1, 0,
- nserr_stats, "ns_err" },
+ nserr_stats, NULL, "ns_err" },
{ -1, -1, 0, 0,
- 0, 0 }
+ 0, NULL, 0 }
};
#endif
#ifdef ISO
struct protox isoprotox[] = {
{ ISO_TP, N_TPSTAT, 1, iso_protopr,
- tp_stats, "tp" },
+ tp_stats, NULL, "tp" },
{ N_CLTP, N_CLTPSTAT, 1, iso_protopr,
- cltp_stats, "cltp" },
+ cltp_stats, NULL, "cltp" },
{ -1, N_CLNPSTAT, 1, 0,
- clnp_stats, "clnp"},
+ clnp_stats, NULL, "clnp"},
{ -1, N_ESISSTAT, 1, 0,
- esis_stats, "esis"},
+ esis_stats, NULL, "esis"},
{ -1, -1, 0, 0,
- 0, 0 }
+ 0, NULL, 0 }
};
#endif
-struct protox *protoprotox[] = { protox, ipxprotox, atalkprotox,
+struct protox *protoprotox[] = {
+ protox,
+#ifdef INET6
+ ip6protox,
+#endif
+ ipxprotox, atalkprotox,
#ifdef NS
nsprotox,
#endif
@@ -230,13 +285,12 @@ main(argc, argv)
int argc;
char *argv[];
{
- register struct protoent *p;
register struct protox *tp = NULL; /* for printing cblocks & stats */
int ch;
af = AF_UNSPEC;
- while ((ch = getopt(argc, argv, "Aabdf:ghI:iM:mN:np:rstuw:")) != -1)
+ while ((ch = getopt(argc, argv, "Aabdf:ghI:liM:mN:np:rstuw:")) != -1)
switch(ch) {
case 'A':
Aflag = 1;
@@ -260,6 +314,10 @@ main(argc, argv)
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*/
else if (strcmp(optarg, "unix") == 0)
af = AF_UNIX;
else if (strcmp(optarg, "atalk") == 0)
@@ -290,6 +348,9 @@ main(argc, argv)
case 'i':
iflag = 1;
break;
+ case 'l':
+ lflag = 1;
+ break;
case 'M':
memf = optarg;
break;
@@ -363,6 +424,11 @@ main(argc, argv)
exit(0);
}
if (pflag) {
+ if (iflag && tp->pr_istats) {
+ kread(0, 0, 0);
+ intpr(interval, nl[N_IFNET].n_value, tp->pr_istats);
+ exit(0);
+ }
if (!tp->pr_stats) {
printf("%s: no stats routine\n", tp->pr_name);
exit(0);
@@ -391,8 +457,11 @@ main(argc, argv)
*/
#endif
if (iflag) {
+ if (af != AF_UNSPEC)
+ goto protostat;
+
kread(0, 0, 0);
- intpr(interval, nl[N_IFNET].n_value);
+ intpr(interval, nl[N_IFNET].n_value, NULL);
exit(0);
}
if (rflag) {
@@ -405,27 +474,40 @@ main(argc, argv)
}
if (gflag) {
kread(0, 0, 0);
- if (sflag)
- mrt_stats(nl[N_MRTSTAT].n_value);
- else
- mroutepr(nl[N_MFCTABLE].n_value,
- nl[N_VIFTABLE].n_value);
- exit(0);
- }
- if (af == AF_INET || af == AF_UNSPEC) {
- setprotoent(1);
- setservent(1);
- /* ugh, this is O(MN) ... why do we do this? */
- while ((p = getprotoent())) {
- for (tp = protox; tp->pr_name; tp++)
- if (strcmp(tp->pr_name, p->p_name) == 0)
- break;
- if (tp->pr_name == 0 || tp->pr_wanted == 0)
- continue;
- printproto(tp, p->p_name);
+ if (sflag) {
+ if (af == AF_INET || af == AF_UNSPEC)
+ mrt_stats(nl[N_MRTSTAT].n_value);
+#ifdef INET6
+#ifdef notyet
+ if (af == AF_INET6 || af == AF_UNSPEC)
+ mrt6_stats(nl[N_MRT6STAT].n_value);
+#endif
+#endif
+ } else {
+ if (af == AF_INET || af == AF_UNSPEC)
+ mroutepr(nl[N_MFCTABLE].n_value,
+ nl[N_VIFTABLE].n_value);
+#ifdef INET6
+#ifdef notyet
+ if (af == AF_INET6 || af == AF_UNSPEC)
+ mroute6pr(nl[N_MF6CTABLE].n_value,
+ nl[N_MIF6TABLE].n_value);
+#endif
+#endif
}
- endprotoent();
+ exit(0);
}
+
+ protostat:
+ kread(0, 0, 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*/
if (af == AF_IPX || af == AF_UNSPEC) {
kread(0, 0, 0);
for (tp = ipxprotox; tp->pr_name; tp++)
@@ -466,16 +548,24 @@ printproto(tp, name)
u_long off;
if (sflag) {
- pr = tp->pr_stats;
- off = tp->pr_usesysctl ? tp->pr_usesysctl
- : nl[tp->pr_sindex].n_value;
+ if (iflag) {
+ if (tp->pr_istats)
+ intpr(interval, nl[N_IFNET].n_value,
+ tp->pr_istats);
+ return;
+ }
+ else {
+ pr = tp->pr_stats;
+ off = tp->pr_usesysctl ? tp->pr_usesysctl
+ : nl[tp->pr_sindex].n_value;
+ }
} else {
pr = tp->pr_cblocks;
off = tp->pr_usesysctl ? tp->pr_usesysctl
: nl[tp->pr_index].n_value;
}
if (pr != NULL && (off || af != AF_UNSPEC))
- (*pr)(off, name);
+ (*pr)(off, name, af);
}
/*
@@ -566,11 +656,11 @@ name2protox(name)
* 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)))
+ if ((tp = knownname(name)) != NULL)
return (tp);
setprotoent(1); /* make protocol lookup cheaper */
- while ((p = getprotoent())) {
+ while ((p = getprotoent()) != NULL) {
/* assert: name not same as p->name */
for (alias = p->p_aliases; *alias; alias++)
if (strcmp(name, *alias) == 0) {
diff --git a/usr.bin/netstat/netstat.1 b/usr.bin/netstat/netstat.1
index 4eb0b5e..30a8249 100644
--- a/usr.bin/netstat/netstat.1
+++ b/usr.bin/netstat/netstat.1
@@ -45,7 +45,7 @@
.Op Fl M Ar core
.Op Fl N Ar system
.Nm netstat
-.Op Fl bdghimnrs
+.Op Fl bdghilmnrs
.Op Fl f Ar address_family
.Op Fl M Ar core
.Op Fl N Ar system
@@ -59,6 +59,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
@@ -77,6 +86,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 have the following meaning:
.Bl -tag -width flag
@@ -112,6 +123,9 @@ are recognized:
.Ar inet ,
for
.Dv AF_INET ,
+.Ar inet6 ,
+for
+.Dv AF_INET6 ,
.Ar ipx ,
for
.Dv AF_IPX ,
@@ -148,6 +162,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
@@ -158,6 +185,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
Extract values associated with the name list from the specified core
instead of the default
@@ -199,6 +238,11 @@ to show protocol-cloned routes.
When
.Fl s
is also present, show routing statistics instead.
+When
+.Fl l
+is also present,
+.Nm
+assumes more columns are there.
.It Fl w Ar wait
Show network interface statistics at intervals of
.Ar wait
@@ -317,6 +361,8 @@ The
.Nm netstat
command appeared in
.Bx 4.2 .
+.Pp
+IPv6 support was added by WIDE/KAME project.
.Sh FILES
.Bl -tag -width /dev/kmem -compact
.It Pa /kernel
diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h
index 1e67517..fc46dee 100644
--- a/usr.bin/netstat/netstat.h
+++ b/usr.bin/netstat/netstat.h
@@ -42,6 +42,7 @@ 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 routing table with use and ref */
int mflag; /* show memory stats */
int nflag; /* show addresses numerically */
int pflag; /* show given protocol */
@@ -61,21 +62,36 @@ char *plural __P((int));
char *plurales __P((int));
void trimdomain __P((char *));
-void protopr __P((u_long, char *));
+void protopr __P((u_long, char *, int));
void tcp_stats __P((u_long, char *));
void udp_stats __P((u_long, char *));
void ip_stats __P((u_long, char *));
void icmp_stats __P((u_long, char *));
void igmp_stats __P((u_long, char *));
+#ifdef IPSEC
+void ipsec_stats __P((u_long, char *));
+#endif
+
+#ifdef INET6
+void ip6_stats __P((u_long, char *));
+void ip6_ifstats __P((char *));
+void icmp6_stats __P((u_long, char *));
+void icmp6_ifstats __P((char *));
+#ifdef notyet
+void pim6_stats __P((u_long, char *));
+void mroute6pr __P((u_long, u_long));
+void mrt6_stats __P((u_long));
+#endif
+#endif /*INET6*/
+
void bdg_stats __P((u_long, char *));
-void protopr __P((u_long, char *));
void mbpr __P((void));
void hostpr __P((u_long, u_long));
void impstats __P((u_long, u_long));
-void intpr __P((int, u_long));
+void intpr __P((int, u_long, void (*) __P((char *))));
void pr_rthdr __P(());
void pr_family __P((int));
@@ -108,8 +124,6 @@ void ddp_stats __P((u_long, char *));
void netgraphprotopr __P((u_long, char *));
-void intpr __P((int, u_long));
-
void unixpr __P((void));
void esis_stats __P((u_long, char *));
diff --git a/usr.bin/netstat/route.c b/usr.bin/netstat/route.c
index 0cdbdf8..e41eec6 100644
--- a/usr.bin/netstat/route.c
+++ b/usr.bin/netstat/route.c
@@ -61,6 +61,7 @@ static const char rcsid[] =
#include <sys/sysctl.h>
+#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
@@ -127,6 +128,11 @@ static void p_rtentry __P((struct rtentry *));
static u_long forgemask __P((u_long));
static void domask __P((char *, u_long, u_long));
+#ifdef INET6
+char *routename6 __P((struct sockaddr_in6 *));
+char *netname6 __P((struct sockaddr_in6 *, struct in6_addr *));
+#endif /*INET6*/
+
/*
* Print routing tables.
*/
@@ -180,6 +186,11 @@ pr_family(af)
case AF_INET:
afname = "Internet";
break;
+#ifdef INET6
+ case AF_INET6:
+ afname = "Internet6";
+ break;
+#endif /*INET6*/
case AF_IPX:
afname = "IPX";
break;
@@ -211,8 +222,13 @@ pr_family(af)
}
/* column widths; each followed by one space */
-#define WID_DST 18 /* width of destination column */
+#ifndef INET6
+#define WID_DST 18 /* width of destination column */
#define WID_GW 18 /* width of gateway column */
+#else
+#define WID_DST (lflag ? 39 : (nflag ? 33: 18)) /* width of dest column */
+#define WID_GW (lflag ? 31 : (nflag ? 29 : 18)) /* width of gateway column */
+#endif /*INET6*/
/*
* Print header for routing table columns.
@@ -222,10 +238,16 @@ pr_rthdr()
{
if (Aflag)
printf("%-8.8s ","Address");
- printf("%-*.*s %-*.*s %-6.6s %6.6s%8.8s %8.8s %6s\n",
- WID_DST, WID_DST, "Destination",
- WID_GW, WID_GW, "Gateway",
- "Flags", "Refs", "Use", "Netif", "Expire");
+ if (lflag)
+ printf("%-*.*s %-*.*s %-6.6s %6.6s%8.8s %8.8s %6s\n",
+ WID_DST, WID_DST, "Destination",
+ WID_GW, WID_GW, "Gateway",
+ "Flags", "Refs", "Use", "Netif", "Expire");
+ else
+ printf("%-*.*s %-*.*s %-6.6s %8.8s %6s\n",
+ WID_DST, WID_DST, "Destination",
+ WID_GW, WID_GW, "Gateway",
+ "Flags", "Netif", "Expire");
}
static struct sockaddr *
@@ -379,8 +401,6 @@ np_rtentry(rtm)
p_sockaddr(sa, NULL, 0, 36);
else {
p_sockaddr(sa, NULL, rtm->rtm_flags, 16);
- if (sa->sa_len == 0)
- sa->sa_len = sizeof(long);
sa = (struct sockaddr *)(sa->sa_len + (char *)sa);
p_sockaddr(sa, NULL, 0, 18);
}
@@ -414,6 +434,35 @@ p_sockaddr(sa, mask, flags, width)
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;
@@ -539,14 +588,15 @@ p_rtentry(rt)
p_sockaddr(&addr.u_sa, &mask.u_sa, rt->rt_flags, WID_DST);
p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST, WID_GW);
p_flags(rt->rt_flags, "%-6.6s ");
- printf("%6ld %8ld ", rt->rt_refcnt, rt->rt_use);
+ if (lflag)
+ printf("%6ld %8ld ", rt->rt_refcnt, rt->rt_use);
if (rt->rt_ifp) {
if (rt->rt_ifp != lastif) {
kget(rt->rt_ifp, ifnet);
kread((u_long)ifnet.if_name, name, 16);
lastif = rt->rt_ifp;
snprintf(prettyname, sizeof prettyname,
- "%.6s%d", name, ifnet.if_unit);
+ "%s%d", name, ifnet.if_unit);
}
printf("%8.8s", prettyname);
if (rt->rt_rmx.rmx_expire) {
@@ -556,7 +606,10 @@ p_rtentry(rt)
rt->rt_rmx.rmx_expire - time((time_t *)0)) > 0)
printf(" %6d%s", (int)expire_time,
rt->rt_nodes[0].rn_dupedkey ? " =>" : "");
+ else
+ goto ifandkey;
} else if (rt->rt_nodes[0].rn_dupedkey) {
+ifandkey:;
printf(" =>");
}
@@ -679,6 +732,118 @@ netname(in, mask)
return (line);
}
+#ifdef INET6
+char *
+netname6(sa6, mask)
+ struct sockaddr_in6 *sa6;
+ struct in6_addr *mask;
+{
+ static char line[MAXHOSTNAMELEN + 1];
+ u_char *p = (u_char *)mask;
+ u_char *lim;
+ int masklen, illegal = 0;
+#ifdef notyet
+ int flag = NI_WITHSCOPEID;
+#endif
+
+ 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");
+
+#ifdef notyet
+ if (nflag)
+ flag |= NI_NUMERICHOST;
+ getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line),
+ NULL, 0, flag);
+#else
+ inet_ntop(AF_INET6, (void *)&sa6->sin6_addr, line, sizeof(line));
+#endif
+
+ if (nflag)
+ sprintf(&line[strlen(line)], "/%d", masklen);
+
+ return line;
+}
+
+char *
+routename6(sa6)
+ struct sockaddr_in6 *sa6;
+{
+#ifdef notyet
+ int flag = NI_WITHSCOPEID;
+
+ if (nflag)
+ flag |= NI_NUMERICHOST;
+#else
+ register char *cp;
+#endif
+ static char line[MAXHOSTNAMELEN + 1];
+ struct hostent *hp;
+
+#ifdef notyet
+ getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line),
+ NULL, 0, flag);
+#else
+ cp = 0;
+ if (!nflag) {
+ hp = gethostbyaddr((char *)&sa6->sin6_addr,
+ sizeof(sa6->sin6_addr), AF_INET6);
+ if (hp) {
+ cp = hp->h_name;
+ trimdomain(cp);
+ }
+ }
+ if (cp) {
+ strncpy(line, cp, sizeof(line) - 1);
+ line[sizeof(line) - 1] = '\0';
+ } else
+ inet_ntop(AF_INET6, (void *)&sa6->sin6_addr, line,
+ sizeof(line));
+#endif
+
+ return line;
+}
+#endif /*INET6*/
+
/*
* Print routing statistics
*/
OpenPOWER on IntegriCloud