diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
commit | d6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch) | |
tree | ece253b876159b39c620e62b6c9b1174642e070e /usr.bin/netstat |
initial import of NetBSD tree
Diffstat (limited to 'usr.bin/netstat')
-rw-r--r-- | usr.bin/netstat/Makefile | 13 | ||||
-rw-r--r-- | usr.bin/netstat/if.c | 395 | ||||
-rw-r--r-- | usr.bin/netstat/inet.c | 502 | ||||
-rw-r--r-- | usr.bin/netstat/iso.c | 845 | ||||
-rw-r--r-- | usr.bin/netstat/main.c | 517 | ||||
-rw-r--r-- | usr.bin/netstat/mbuf.c | 121 | ||||
-rw-r--r-- | usr.bin/netstat/mroute.c | 260 | ||||
-rw-r--r-- | usr.bin/netstat/netstat.1 | 296 | ||||
-rw-r--r-- | usr.bin/netstat/netstat.h | 111 | ||||
-rw-r--r-- | usr.bin/netstat/ns.c | 357 | ||||
-rw-r--r-- | usr.bin/netstat/route.c | 676 | ||||
-rw-r--r-- | usr.bin/netstat/unix.c | 140 |
12 files changed, 4233 insertions, 0 deletions
diff --git a/usr.bin/netstat/Makefile b/usr.bin/netstat/Makefile new file mode 100644 index 00000000000..b5fc9c34add --- /dev/null +++ b/usr.bin/netstat/Makefile @@ -0,0 +1,13 @@ +# $NetBSD: Makefile,v 1.11 1995/10/03 21:42:34 thorpej Exp $ +# from: @(#)Makefile 8.1 (Berkeley) 6/12/93 + +PROG= netstat +SRCS= if.c inet.c iso.c main.c mbuf.c mroute.c ns.c route.c \ + tp_astring.c unix.c +.PATH: ${.CURDIR}/../../sys/netiso +BINGRP= kmem +BINMODE=2555 +LDADD= -lkvm +DPADD= ${LIBKVM} + +.include <bsd.prog.mk> diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c new file mode 100644 index 00000000000..bb270fe734c --- /dev/null +++ b/usr.bin/netstat/if.c @@ -0,0 +1,395 @@ +/* $NetBSD: if.c,v 1.13 1995/10/03 21:42:36 thorpej 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. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "from: @(#)if.c 8.2 (Berkeley) 2/21/94"; +#else +static char *rcsid = "$NetBSD: if.c,v 1.13 1995/10/03 21:42:36 thorpej Exp $"; +#endif +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/protosw.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <netinet/in.h> +#include <netinet/in_var.h> +#include <netns/ns.h> +#include <netns/ns_if.h> +#include <netiso/iso.h> +#include <netiso/iso_var.h> +#include <arpa/inet.h> + +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "netstat.h" + +#define YES 1 +#define NO 0 + +static void sidewaysintpr __P((u_int, u_long)); +static void catchalarm __P((int)); + +/* + * Print a description of the network interfaces. + */ +void +intpr(interval, ifnetaddr) + int interval; + u_long ifnetaddr; +{ + struct ifnet ifnet; + union { + struct ifaddr ifa; + struct in_ifaddr in; + struct ns_ifaddr ns; + struct iso_ifaddr iso; + } ifaddr; + u_long ifaddraddr; + struct sockaddr *sa; + char name[16]; + + if (ifnetaddr == 0) { + printf("ifnet: symbol not defined\n"); + return; + } + if (interval) { + sidewaysintpr((unsigned)interval, ifnetaddr); + return; + } + if (kread(ifnetaddr, (char *)&ifnetaddr, sizeof ifnetaddr)) + return; + printf("%-5.5s %-5.5s %-11.11s %-15.15s %10.10s %5.5s %8.8s %5.5s", + "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs", + "Opkts", "Oerrs"); + printf(" %5s", "Coll"); + if (tflag) + printf(" %s", "Time"); + if (dflag) + printf(" %s", "Drop"); + putchar('\n'); + ifaddraddr = 0; + while (ifnetaddr || ifaddraddr) { + struct sockaddr_in *sin; + register char *cp; + int n, m; + + if (ifaddraddr == 0) { + if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet) || + kread((u_long)ifnet.if_name, name, 16)) + return; + name[15] = '\0'; + ifnetaddr = (u_long)ifnet.if_list.tqe_next; + if (interface != 0 && (strcmp(name, interface) != 0 || + unit != ifnet.if_unit)) + continue; + cp = index(name, '\0'); + cp += sprintf(cp, "%d", ifnet.if_unit); + if ((ifnet.if_flags & IFF_UP) == 0) + *cp++ = '*'; + *cp = '\0'; + ifaddraddr = (u_long)ifnet.if_addrlist.tqh_first; + } + printf("%-5.5s %-5d ", name, ifnet.if_mtu); + if (ifaddraddr == 0) { + printf("%-11.11s ", "none"); + printf("%-15.15s ", "none"); + } else { + if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) { + ifaddraddr = 0; + continue; + } +#define CP(x) ((char *)(x)) + cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + + CP(&ifaddr); sa = (struct sockaddr *)cp; + switch (sa->sa_family) { + case AF_UNSPEC: + printf("%-11.11s ", "none"); + printf("%-17.17s ", "none"); + break; + case AF_INET: + sin = (struct sockaddr_in *)sa; +#ifdef notdef + /* can't use inet_makeaddr because kernel + * keeps nets unshifted. + */ + in = inet_makeaddr(ifaddr.in.ia_subnet, + INADDR_ANY); + printf("%-11.11s ", netname(in.s_addr, + ifaddr.in.ia_subnetmask)); +#else + printf("%-11.11s ", + netname(ifaddr.in.ia_subnet, + ifaddr.in.ia_subnetmask)); +#endif + printf("%-17.17s ", + routename(sin->sin_addr.s_addr)); + + if (aflag) { + u_long multiaddr; + struct in_multi inm; + + multiaddr = (u_long)ifaddr.in.ia_multiaddrs.lh_first; + while (multiaddr != 0) { + kread(multiaddr, (char *)&inm, + sizeof inm); + printf("\n%23s %-15.15s ", "", + routename(inm.inm_addr.s_addr)); + multiaddr = (u_long)inm.inm_list.le_next; + } + } + break; + case AF_NS: + { + struct sockaddr_ns *sns = + (struct sockaddr_ns *)sa; + u_long net; + char netnum[8]; + + *(union ns_net *) &net = sns->sns_addr.x_net; + sprintf(netnum, "%lxH", ntohl(net)); + upHex(netnum); + printf("ns:%-8s ", netnum); + printf("%-17s ", + ns_phost((struct sockaddr *)sns)); + } + break; + case AF_LINK: + { + struct sockaddr_dl *sdl = + (struct sockaddr_dl *)sa; + cp = (char *)LLADDR(sdl); + n = sdl->sdl_alen; + } + m = printf("%-11.11s ", "<Link>"); + goto hexprint; + default: + m = printf("(%d)", sa->sa_family); + for (cp = sa->sa_len + (char *)sa; + --cp > sa->sa_data && (*cp == 0);) {} + n = cp - sa->sa_data + 1; + cp = sa->sa_data; + hexprint: + while (--n >= 0) + m += printf("%x%c", *cp++ & 0xff, + n > 0 ? '.' : ' '); + m = 30 - m; + while (m-- > 0) + putchar(' '); + break; + } + ifaddraddr = (u_long)ifaddr.ifa.ifa_list.tqe_next; + } + printf("%8d %5d %8d %5d %5d", + ifnet.if_ipackets, ifnet.if_ierrors, + ifnet.if_opackets, ifnet.if_oerrors, + ifnet.if_collisions); + if (tflag) + printf(" %3d", ifnet.if_timer); + if (dflag) + printf(" %3d", ifnet.if_snd.ifq_drops); + putchar('\n'); + } +} + +#define MAXIF 10 +struct iftot { + char ift_name[16]; /* interface name */ + int ift_ip; /* input packets */ + int ift_ie; /* input errors */ + int ift_op; /* output packets */ + int ift_oe; /* output errors */ + int ift_co; /* collisions */ + int ift_dr; /* drops */ +} iftot[MAXIF]; + +u_char signalled; /* set if alarm goes off "early" */ + +/* + * Print a running summary of interface statistics. + * Repeat display every interval seconds, showing statistics + * collected over that interval. Assumes that interval is non-zero. + * First line printed at top of screen is always cumulative. + */ +static void +sidewaysintpr(interval, off) + unsigned interval; + u_long off; +{ + struct ifnet ifnet; + u_long firstifnet; + register struct iftot *ip, *total; + register int line; + struct iftot *lastif, *sum, *interesting; + int oldmask; + + if (kread(off, (char *)&firstifnet, sizeof (u_long))) + return; + lastif = iftot; + sum = iftot + MAXIF - 1; + total = sum - 1; + interesting = iftot; + for (off = firstifnet, ip = iftot; off;) { + char *cp; + + if (kread(off, (char *)&ifnet, sizeof ifnet)) + break; + ip->ift_name[0] = '('; + if (kread((u_long)ifnet.if_name, ip->ift_name + 1, 15)) + break; + if (interface && strcmp(ip->ift_name + 1, interface) == 0 && + unit == ifnet.if_unit) + interesting = ip; + ip->ift_name[15] = '\0'; + cp = index(ip->ift_name, '\0'); + sprintf(cp, "%d)", ifnet.if_unit); + ip++; + if (ip >= iftot + MAXIF - 2) + break; + off = (u_long)ifnet.if_list.tqe_next; + } + lastif = ip; + + (void)signal(SIGALRM, catchalarm); + signalled = NO; + (void)alarm(interval); +banner: + printf(" input %-6.6s output ", interesting->ift_name); + if (lastif - iftot > 0) { + if (dflag) + printf(" "); + printf(" input (Total) output"); + } + for (ip = iftot; ip < iftot + MAXIF; ip++) { + ip->ift_ip = 0; + ip->ift_ie = 0; + ip->ift_op = 0; + ip->ift_oe = 0; + ip->ift_co = 0; + ip->ift_dr = 0; + } + putchar('\n'); + printf("%8.8s %5.5s %8.8s %5.5s %5.5s ", + "packets", "errs", "packets", "errs", "colls"); + if (dflag) + printf("%5.5s ", "drops"); + if (lastif - iftot > 0) + printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", + "packets", "errs", "packets", "errs", "colls"); + if (dflag) + printf(" %5.5s", "drops"); + putchar('\n'); + fflush(stdout); + line = 0; +loop: + sum->ift_ip = 0; + sum->ift_ie = 0; + sum->ift_op = 0; + sum->ift_oe = 0; + sum->ift_co = 0; + sum->ift_dr = 0; + for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) { + if (kread(off, (char *)&ifnet, sizeof ifnet)) { + off = 0; + continue; + } + if (ip == interesting) { + printf("%8d %5d %8d %5d %5d", + ifnet.if_ipackets - ip->ift_ip, + ifnet.if_ierrors - ip->ift_ie, + ifnet.if_opackets - ip->ift_op, + ifnet.if_oerrors - ip->ift_oe, + ifnet.if_collisions - ip->ift_co); + if (dflag) + printf(" %5d", + ifnet.if_snd.ifq_drops - ip->ift_dr); + } + ip->ift_ip = ifnet.if_ipackets; + ip->ift_ie = ifnet.if_ierrors; + ip->ift_op = ifnet.if_opackets; + ip->ift_oe = ifnet.if_oerrors; + ip->ift_co = ifnet.if_collisions; + ip->ift_dr = ifnet.if_snd.ifq_drops; + sum->ift_ip += ip->ift_ip; + sum->ift_ie += ip->ift_ie; + sum->ift_op += ip->ift_op; + sum->ift_oe += ip->ift_oe; + sum->ift_co += ip->ift_co; + sum->ift_dr += ip->ift_dr; + off = (u_long)ifnet.if_list.tqe_next; + } + if (lastif - iftot > 0) { + printf(" %8d %5d %8d %5d %5d", + sum->ift_ip - total->ift_ip, + sum->ift_ie - total->ift_ie, + sum->ift_op - total->ift_op, + sum->ift_oe - total->ift_oe, + sum->ift_co - total->ift_co); + if (dflag) + printf(" %5d", sum->ift_dr - total->ift_dr); + } + *total = *sum; + putchar('\n'); + fflush(stdout); + line++; + oldmask = sigblock(sigmask(SIGALRM)); + if (! signalled) { + sigpause(0); + } + sigsetmask(oldmask); + signalled = NO; + (void)alarm(interval); + if (line == 21) + goto banner; + goto loop; + /*NOTREACHED*/ +} + +/* + * Called if an interval expires before sidewaysintpr has completed a loop. + * Sets a flag to not wait for the alarm. + */ +static void +catchalarm(signo) + int signo; +{ + signalled = YES; +} diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c new file mode 100644 index 00000000000..e5ac793a228 --- /dev/null +++ b/usr.bin/netstat/inet.c @@ -0,0 +1,502 @@ +/* $NetBSD: inet.c,v 1.14 1995/10/03 21:42:37 thorpej 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. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "from: @(#)inet.c 8.4 (Berkeley) 4/20/94"; +#else +static char *rcsid = "$NetBSD: inet.c,v 1.14 1995/10/03 21:42:37 thorpej Exp $"; +#endif +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> + +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> +#include <netinet/ip_icmp.h> +#include <netinet/icmp_var.h> +#include <netinet/igmp_var.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> +#include <netinet/tcp_seq.h> +#define TCPSTATES +#include <netinet/tcp_fsm.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_var.h> +#include <netinet/tcp_debug.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> + +#include <arpa/inet.h> +#include <netdb.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include "netstat.h" + +struct inpcb inpcb; +struct tcpcb tcpcb; +struct socket sockb; + +char *inetname __P((struct in_addr *)); +void inetprint __P((struct in_addr *, int, char *)); + +/* + * Print a summary of connections related to an Internet + * protocol. For TCP, also give state of connection. + * Listening processes (aflag) are suppressed unless the + * -a (all) flag is specified. + */ +void +protopr(off, name) + u_long off; + char *name; +{ + struct inpcbtable table; + register struct inpcb *head, *next, *prev; + struct inpcb inpcb; + int istcp; + static int first = 1; + + if (off == 0) + return; + istcp = strcmp(name, "tcp") == 0; + kread(off, (char *)&table, sizeof table); + prev = head = + (struct inpcb *)&((struct inpcbtable *)off)->inpt_queue.cqh_first; + next = table.inpt_queue.cqh_first; + + while (next != head) { + kread((u_long)next, (char *)&inpcb, sizeof inpcb); + if (inpcb.inp_queue.cqe_prev != prev) { + printf("???\n"); + break; + } + prev = next; + next = inpcb.inp_queue.cqe_next; + + if (!aflag && + inet_lnaof(inpcb.inp_laddr) == INADDR_ANY) + continue; + kread((u_long)inpcb.inp_socket, (char *)&sockb, sizeof (sockb)); + if (istcp) { + kread((u_long)inpcb.inp_ppcb, + (char *)&tcpcb, sizeof (tcpcb)); + } + if (first) { + printf("Active Internet 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("%8x ", inpcb.inp_ppcb); + else + printf("%8x ", prev); + printf("%-5.5s %6d %6d ", name, sockb.so_rcv.sb_cc, + sockb.so_snd.sb_cc); + inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport, name); + inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport, name); + if (istcp) { + if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES) + printf(" %d", tcpcb.t_state); + else + printf(" %s", tcpstates[tcpcb.t_state]); + } + putchar('\n'); + } +} + +/* + * Dump TCP statistics structure. + */ +void +tcp_stats(off, name) + u_long off; + char *name; +{ + struct tcpstat tcpstat; + + if (off == 0) + return; + printf ("%s:\n", name); + kread(off, (char *)&tcpstat, sizeof (tcpstat)); + +#define p(f, m) if (tcpstat.f || sflag <= 1) \ + printf(m, tcpstat.f, plural(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 p3(f, m) if (tcpstat.f || sflag <= 1) \ + printf(m, tcpstat.f, plurales(tcpstat.f)) + + p(tcps_sndtotal, "\t%d packet%s sent\n"); + p2(tcps_sndpack,tcps_sndbyte, + "\t\t%d data packet%s (%d byte%s)\n"); + p2(tcps_sndrexmitpack, tcps_sndrexmitbyte, + "\t\t%d data packet%s (%d byte%s) retransmitted\n"); + p2(tcps_sndacks, tcps_delack, + "\t\t%d ack-only packet%s (%d delayed)\n"); + p(tcps_sndurg, "\t\t%d URG only packet%s\n"); + p(tcps_sndprobe, "\t\t%d window probe packet%s\n"); + p(tcps_sndwinup, "\t\t%d window update packet%s\n"); + p(tcps_sndctrl, "\t\t%d control packet%s\n"); + p(tcps_rcvtotal, "\t%d packet%s received\n"); + p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%d ack%s (for %d byte%s)\n"); + p(tcps_rcvdupack, "\t\t%d duplicate ack%s\n"); + p(tcps_rcvacktoomuch, "\t\t%d ack%s for unsent data\n"); + p2(tcps_rcvpack, tcps_rcvbyte, + "\t\t%d packet%s (%d byte%s) received in-sequence\n"); + p2(tcps_rcvduppack, tcps_rcvdupbyte, + "\t\t%d completely duplicate packet%s (%d byte%s)\n"); + p(tcps_pawsdrop, "\t\t%d old duplicate packet%s\n"); + p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte, + "\t\t%d packet%s with some dup. data (%d byte%s duped)\n"); + p2(tcps_rcvoopack, tcps_rcvoobyte, + "\t\t%d out-of-order packet%s (%d byte%s)\n"); + p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin, + "\t\t%d packet%s (%d byte%s) of data after window\n"); + p(tcps_rcvwinprobe, "\t\t%d window probe%s\n"); + p(tcps_rcvwinupd, "\t\t%d window update packet%s\n"); + p(tcps_rcvafterclose, "\t\t%d packet%s received after close\n"); + p(tcps_rcvbadsum, "\t\t%d discarded for bad checksum%s\n"); + p(tcps_rcvbadoff, "\t\t%d discarded for bad header offset field%s\n"); + p(tcps_rcvshort, "\t\t%d discarded because packet too short\n"); + p(tcps_connattempt, "\t%d connection request%s\n"); + p(tcps_accepts, "\t%d connection accept%s\n"); + p(tcps_connects, "\t%d connection%s established (including accepts)\n"); + p2(tcps_closed, tcps_drops, + "\t%d connection%s closed (including %d drop%s)\n"); + p(tcps_conndrops, "\t%d embryonic connection%s dropped\n"); + p2(tcps_rttupdated, tcps_segstimed, + "\t%d segment%s updated rtt (of %d attempt%s)\n"); + p(tcps_rexmttimeo, "\t%d retransmit timeout%s\n"); + p(tcps_timeoutdrop, "\t\t%d connection%s dropped by rexmit timeout\n"); + p(tcps_persisttimeo, "\t%d persist timeout%s\n"); + p(tcps_keeptimeo, "\t%d keepalive timeout%s\n"); + p(tcps_keepprobe, "\t\t%d keepalive probe%s sent\n"); + p(tcps_keepdrops, "\t\t%d connection%s dropped by keepalive\n"); + p(tcps_predack, "\t%d correct ACK header prediction%s\n"); + p(tcps_preddat, "\t%d correct data packet header prediction%s\n"); + p3(tcps_pcbcachemiss, "\t%d PCB cache miss%s\n"); +#undef p +#undef p2 +#undef p3 +} + +/* + * Dump UDP statistics structure. + */ +void +udp_stats(off, name) + u_long off; + char *name; +{ + struct udpstat udpstat; + u_long delivered; + + if (off == 0) + return; + kread(off, (char *)&udpstat, sizeof (udpstat)); + printf("%s:\n", name); +#define p(f, m) if (udpstat.f || sflag <= 1) \ + printf(m, udpstat.f, plural(udpstat.f)) + p(udps_ipackets, "\t%u datagram%s received\n"); + p(udps_hdrops, "\t%u with incomplete header\n"); + p(udps_badlen, "\t%u with bad data length field\n"); + p(udps_badsum, "\t%u with bad checksum\n"); + p(udps_noport, "\t%u dropped due to no socket\n"); + p(udps_noportbcast, "\t%u broadcast/multicast datagram%s dropped due to no socket\n"); + p(udps_fullsock, "\t%u dropped due to full socket buffers\n"); + delivered = udpstat.udps_ipackets - + udpstat.udps_hdrops - + udpstat.udps_badlen - + udpstat.udps_badsum - + udpstat.udps_noport - + udpstat.udps_noportbcast - + udpstat.udps_fullsock; + if (delivered || sflag <= 1) + printf("\t%u delivered\n", delivered); + p(udps_opackets, "\t%u datagram%s output\n"); +#undef p +} + +/* + * Dump IP statistics structure. + */ +void +ip_stats(off, name) + u_long off; + char *name; +{ + struct ipstat ipstat; + + if (off == 0) + return; + kread(off, (char *)&ipstat, sizeof (ipstat)); + printf("%s:\n", name); + +#define p(f, m) if (ipstat.f || sflag <= 1) \ + printf(m, ipstat.f, plural(ipstat.f)) + + p(ips_total, "\t%u total packet%s received\n"); + p(ips_badsum, "\t%u bad header checksum%s\n"); + p(ips_toosmall, "\t%u with size smaller than minimum\n"); + p(ips_tooshort, "\t%u with data size < data length\n"); + p(ips_badhlen, "\t%u with header length < data size\n"); + p(ips_badlen, "\t%u with data length < header length\n"); + p(ips_badoptions, "\t%u with bad options\n"); + p(ips_badvers, "\t%u with incorrect version number\n"); + p(ips_fragments, "\t%u fragment%s received\n"); + p(ips_fragdropped, "\t%u fragment%s dropped (dup or out of space)\n"); + p(ips_badfrags, "\t%u malformed fragment%s dropped\n"); + p(ips_fragtimeout, "\t%u fragment%s dropped after timeout\n"); + p(ips_reassembled, "\t%u packet%s reassembled ok\n"); + p(ips_delivered, "\t%u packet%s for this host\n"); + p(ips_noproto, "\t%u packet%s for unknown/unsupported protocol\n"); + p(ips_forward, "\t%u packet%s forwarded\n"); + p(ips_cantforward, "\t%u packet%s not forwardable\n"); + p(ips_redirectsent, "\t%u redirect%s sent\n"); + p(ips_localout, "\t%u packet%s sent from this host\n"); + p(ips_rawout, "\t%u packet%s sent with fabricated ip header\n"); + p(ips_odropped, "\t%u output packet%s dropped due to no bufs, etc.\n"); + p(ips_noroute, "\t%u output packet%s discarded due to no route\n"); + p(ips_fragmented, "\t%u output datagram%s fragmented\n"); + p(ips_ofragments, "\t%u fragment%s created\n"); + p(ips_cantfrag, "\t%u datagram%s that can't be fragmented\n"); +#undef p +} + +static char *icmpnames[] = { + "echo reply", + "#1", + "#2", + "destination unreachable", + "source quench", + "routing redirect", + "#6", + "#7", + "echo", + "#9", + "#10", + "time exceeded", + "parameter problem", + "time stamp", + "time stamp reply", + "information request", + "information request reply", + "address mask request", + "address mask reply", +}; + +/* + * Dump ICMP statistics. + */ +void +icmp_stats(off, name) + u_long off; + char *name; +{ + struct icmpstat icmpstat; + register int i, first; + + if (off == 0) + return; + kread(off, (char *)&icmpstat, sizeof (icmpstat)); + printf("%s:\n", name); + +#define p(f, m) if (icmpstat.f || sflag <= 1) \ + printf(m, icmpstat.f, plural(icmpstat.f)) + + p(icps_error, "\t%u call%s to icmp_error\n"); + p(icps_oldicmp, + "\t%u error%s not generated 'cuz old message was icmp\n"); + for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++) + if (icmpstat.icps_outhist[i] != 0) { + if (first) { + printf("\tOutput histogram:\n"); + first = 0; + } + printf("\t\t%s: %u\n", icmpnames[i], + icmpstat.icps_outhist[i]); + } + p(icps_badcode, "\t%u message%s with bad code fields\n"); + p(icps_tooshort, "\t%u message%s < minimum length\n"); + p(icps_checksum, "\t%u bad checksum%s\n"); + p(icps_badlen, "\t%u message%s with bad length\n"); + for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++) + if (icmpstat.icps_inhist[i] != 0) { + if (first) { + printf("\tInput histogram:\n"); + first = 0; + } + printf("\t\t%s: %u\n", icmpnames[i], + icmpstat.icps_inhist[i]); + } + p(icps_reflect, "\t%u message response%s generated\n"); +#undef p +} + +/* + * Dump IGMP statistics structure. + */ +void +igmp_stats(off, name) + u_long off; + char *name; +{ + struct igmpstat igmpstat; + + if (off == 0) + return; + kread(off, (char *)&igmpstat, sizeof (igmpstat)); + printf("%s:\n", name); + +#define p(f, m) if (igmpstat.f || sflag <= 1) \ + printf(m, igmpstat.f, plural(igmpstat.f)) +#define py(f, m) if (igmpstat.f || sflag <= 1) \ + printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y") + p(igps_rcv_total, "\t%u message%s received\n"); + p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n"); + p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n"); + py(igps_rcv_queries, "\t%u membership quer%s received\n"); + py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n"); + p(igps_rcv_reports, "\t%u membership report%s received\n"); + p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n"); + p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n"); + p(igps_snd_reports, "\t%u membership report%s sent\n"); +#undef p +#undef py +} + +/* + * Pretty print an Internet address (net address + port). + * If the nflag was specified, use numbers instead of names. + */ +void +inetprint(in, port, proto) + register struct in_addr *in; + int port; + char *proto; +{ + struct servent *sp = 0; + char line[80], *cp; + int width; + + sprintf(line, "%.*s.", (Aflag && !nflag) ? 12 : 16, inetname(in)); + cp = index(line, '\0'); + if (!nflag && port) + sp = getservbyport((int)port, proto); + 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 * +inetname(inp) + struct in_addr *inp; +{ + register char *cp; + static char line[50]; + struct hostent *hp; + struct netent *np; + 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 && inp->s_addr != INADDR_ANY) { + int net = inet_netof(*inp); + int lna = inet_lnaof(*inp); + + if (lna == INADDR_ANY) { + np = getnetbyaddr(net, AF_INET); + if (np) + cp = np->n_name; + } + if (cp == 0) { + hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET); + if (hp) { + if ((cp = index(hp->h_name, '.')) && + !strcmp(cp + 1, domain)) + *cp = 0; + cp = hp->h_name; + } + } + } + if (inp->s_addr == INADDR_ANY) + strcpy(line, "*"); + else if (cp) + strcpy(line, cp); + else { + inp->s_addr = ntohl(inp->s_addr); +#define C(x) ((x) & 0xff) + sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24), + C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr)); + } + return (line); +} diff --git a/usr.bin/netstat/iso.c b/usr.bin/netstat/iso.c new file mode 100644 index 00000000000..32fdce09fb3 --- /dev/null +++ b/usr.bin/netstat/iso.c @@ -0,0 +1,845 @@ +/* $NetBSD: iso.c,v 1.12 1995/10/03 21:42:38 thorpej 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. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "from: @(#)iso.c 8.1 (Berkeley) 6/6/93"; +#else +static char *rcsid = "$NetBSD: iso.c,v 1.12 1995/10/03 21:42:38 thorpej Exp $"; +#endif +#endif /* not lint */ + +/******************************************************************************* + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +*******************************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ + +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/mbuf.h> +#include <sys/time.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <errno.h> +#include <net/if.h> +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> +#include <netinet/ip_var.h> +#include <netiso/iso.h> +#include <netiso/iso_errno.h> +#include <netiso/clnp.h> +#include <netiso/esis.h> +#include <netiso/clnp_stat.h> +#include <netiso/argo_debug.h> +#undef satosiso +#include <netiso/tp_param.h> +#include <netiso/tp_states.h> +#include <netiso/tp_pcb.h> +#include <netiso/tp_stat.h> +#include <netiso/iso_pcb.h> +#include <netiso/cltp_var.h> +#include <netiso/cons.h> +#ifdef IncStat +#undef IncStat +#endif +#include <netiso/cons_pcb.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include "netstat.h" + +static void tprintstat __P((struct tp_stat *, int)); +static void isonetprint __P((struct sockaddr_iso *, int)); +static void hexprint __P((int, char *, char *)); +extern void inetprint __P((struct in_addr *, int, char *)); + +/* + * Dump esis stats + */ +void +esis_stats(off, name) + u_long off; + char *name; +{ + struct esis_stat esis_stat; + + if (off == 0 || + kread(off, (char *)&esis_stat, sizeof (struct esis_stat))) + return; + printf("%s:\n", name); + printf("\t%d esh sent, %d esh received\n", esis_stat.es_eshsent, + esis_stat.es_eshrcvd); + printf("\t%d ish sent, %d ish received\n", esis_stat.es_ishsent, + esis_stat.es_ishrcvd); + printf("\t%d rd sent, %d rd received\n", esis_stat.es_rdsent, + esis_stat.es_rdrcvd); + printf("\t%d pdus not sent due to insufficient memory\n", + esis_stat.es_nomem); + printf("\t%d pdus received with bad checksum\n", esis_stat.es_badcsum); + printf("\t%d pdus received with bad version number\n", + esis_stat.es_badvers); + printf("\t%d pdus received with bad type field\n", esis_stat.es_badtype); + printf("\t%d short pdus received\n", esis_stat.es_toosmall); +} + +/* + * Dump clnp statistics structure. + */ +void +clnp_stats(off, name) + u_long off; + char *name; +{ + struct clnp_stat clnp_stat; + + if (off == 0 || + kread(off, (char *)&clnp_stat, sizeof (clnp_stat))) + return; + + printf("%s:\n\t%d total packets sent\n", name, clnp_stat.cns_sent); + printf("\t%d total fragments sent\n", clnp_stat.cns_fragments); + printf("\t%d total packets received\n", clnp_stat.cns_total); + printf("\t%d with fixed part of header too small\n", + clnp_stat.cns_toosmall); + printf("\t%d with header length not reasonable\n", clnp_stat.cns_badhlen); + printf("\t%d incorrect checksum%s\n", + clnp_stat.cns_badcsum, plural(clnp_stat.cns_badcsum)); + printf("\t%d with unreasonable address lengths\n", clnp_stat.cns_badaddr); + printf("\t%d with forgotten segmentation information\n", + clnp_stat.cns_noseg); + printf("\t%d with an incorrect protocol identifier\n", clnp_stat.cns_noproto); + printf("\t%d with an incorrect version\n", clnp_stat.cns_badvers); + printf("\t%d dropped because the ttl has expired\n", + clnp_stat.cns_ttlexpired); + printf("\t%d clnp cache misses\n", clnp_stat.cns_cachemiss); + printf("\t%d clnp congestion experience bits set\n", + clnp_stat.cns_congest_set); + printf("\t%d clnp congestion experience bits received\n", + clnp_stat.cns_congest_rcvd); +} +/* + * Dump CLTP statistics structure. + */ +void +cltp_stats(off, name) + u_long off; + char *name; +{ + struct cltpstat cltpstat; + + if (off == 0 || + kread(off, (char *)&cltpstat, sizeof (cltpstat))) + return; + printf("%s:\n\t%u incomplete header%s\n", name, + cltpstat.cltps_hdrops, plural(cltpstat.cltps_hdrops)); + printf("\t%u bad data length field%s\n", + cltpstat.cltps_badlen, plural(cltpstat.cltps_badlen)); + printf("\t%u bad checksum%s\n", + cltpstat.cltps_badsum, plural(cltpstat.cltps_badsum)); +} + +struct tp_pcb tpcb; +struct isopcb isopcb; +struct socket sockb; +union { + struct sockaddr_iso siso; + char data[128]; +} laddr, faddr; +#define kget(o, p) \ + (kread((u_long)(o), (char *)&p, sizeof (p))) + +static int first = 1; + +/* + * Print a summary of connections related to an Internet + * protocol. For TP, also give state of connection. + * Listening processes (aflag) are suppressed unless the + * -a (all) flag is specified. + */ +void +iso_protopr(off, name) + u_long off; + char *name; +{ + struct isopcb cb; + register struct isopcb *prev, *next; + + if (off == 0) { + printf("%s control block: symbol not in namelist\n", name); + return; + } + if (strcmp(name, "tp") == 0) { + tp_protopr(off, name); + return; + } + if (kread(off, (char *)&cb, sizeof(cb))) + return; + isopcb = cb; + prev = (struct isopcb *)off; + if (isopcb.isop_next == (struct isopcb *)off) + return; + while (isopcb.isop_next != (struct isopcb *)off) { + next = isopcb.isop_next; + kget(next, isopcb); + if (isopcb.isop_prev != prev) { + printf("prev 0x%x next 0x%x isop_prev 0x%x isop_next 0x%x???\n", + prev, next, isopcb.isop_prev, isopcb.isop_next); + break; + } + kget(isopcb.isop_socket, sockb); + iso_protopr1((u_long)next, 0); + putchar('\n'); + prev = next; + } +} + +void +iso_protopr1(kern_addr, istp) + u_long kern_addr; + int istp; +{ + if (first) { + printf("Active ISO net connections"); + if (aflag) + printf(" (including servers)"); + putchar('\n'); + if (Aflag) + printf("%-8.8s ", "PCB"); + printf(Aflag ? + "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" : + "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n", + "Proto", "Recv-Q", "Send-Q", + "Local Address", "Foreign Address", "(state)"); + first = 0; + } + if (Aflag) + printf("%8x ", + (sockb.so_pcb ? (void *)sockb.so_pcb : (void *)kern_addr)); + printf("%-5.5s %6d %6d ", "tp", sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc); + if (istp && tpcb.tp_lsuffixlen) { + hexprint(tpcb.tp_lsuffixlen, tpcb.tp_lsuffix, "()"); + printf("\t"); + } else if (isopcb.isop_laddr == 0) + printf("*.*\t"); + else { + if ((char *)isopcb.isop_laddr == ((char *)kern_addr) + + _offsetof(struct isopcb, isop_sladdr)) + laddr.siso = isopcb.isop_sladdr; + else + kget(isopcb.isop_laddr, laddr); + isonetprint((struct sockaddr_iso *)&laddr, 1); + } + if (istp && tpcb.tp_fsuffixlen) { + hexprint(tpcb.tp_fsuffixlen, tpcb.tp_fsuffix, "()"); + printf("\t"); + } else if (isopcb.isop_faddr == 0) + printf("*.*\t"); + else { + if ((char *)isopcb.isop_faddr == ((char *)kern_addr) + + _offsetof(struct isopcb, isop_sfaddr)) + faddr.siso = isopcb.isop_sfaddr; + else + kget(isopcb.isop_faddr, faddr); + isonetprint((struct sockaddr_iso *)&faddr, 0); + } +} + +void +tp_protopr(off, name) + u_long off; + char *name; +{ + extern char *tp_sstring[]; + struct tp_ref *tpr, *tpr_base; + struct tp_refinfo tpkerninfo; + int size; + + kget(off, tpkerninfo); + size = tpkerninfo.tpr_size * sizeof (*tpr); + tpr_base = (struct tp_ref *)malloc(size); + if (tpr_base == 0) + return; + kread((u_long)(tpkerninfo.tpr_base), (char *)tpr_base, size); + for (tpr = tpr_base; tpr < tpr_base + tpkerninfo.tpr_size; tpr++) { + if (tpr->tpr_pcb == 0) + continue; + kget(tpr->tpr_pcb, tpcb); + if (tpcb.tp_state == ST_ERROR) + printf("undefined tpcb state: 0x%x\n", tpr->tpr_pcb); + if (!aflag && + (tpcb.tp_state == TP_LISTENING || + tpcb.tp_state == TP_CLOSED || + tpcb.tp_state == TP_REFWAIT)) { + continue; + } + kget(tpcb.tp_sock, sockb); + if (tpcb.tp_npcb) switch(tpcb.tp_netservice) { + case IN_CLNS: + tp_inproto((u_long)tpkerninfo.tpr_base); + break; + default: + kget(tpcb.tp_npcb, isopcb); + iso_protopr1((u_long)tpcb.tp_npcb, 1); + break; + } + if (tpcb.tp_state >= tp_NSTATES) + printf(" %d", tpcb.tp_state); + else + printf(" %-12.12s", tp_sstring[tpcb.tp_state]); + putchar('\n'); + } +} + +void +tp_inproto(pcb) + u_long pcb; +{ + struct inpcb inpcb; + kget(tpcb.tp_npcb, inpcb); + if (!aflag && inet_lnaof(inpcb.inp_laddr) == INADDR_ANY) + return; + if (Aflag) + printf("%8x ", pcb); + printf("%-5.5s %6d %6d ", "tpip", + sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc); + inetprint(&inpcb.inp_laddr, inpcb.inp_lport, "tp"); + inetprint(&inpcb.inp_faddr, inpcb.inp_fport, "tp"); +} + +/* + * Pretty print an iso address (net address + port). + * If the nflag was specified, use numbers instead of names. + */ + +#ifdef notdef +char * +isonetname(iso) + register struct iso_addr *iso; +{ + struct sockaddr_iso sa; + struct iso_hostent *ihe = 0; + struct iso_hostent *iso_gethostentrybyaddr(); + struct iso_hostent *iso_getserventrybytsel(); + struct iso_hostent Ihe; + static char line[80]; + + bzero(line, sizeof(line)); + if( iso->isoa_afi ) { + sa.siso_family = AF_ISO; + sa.siso_addr = *iso; + sa.siso_tsuffix = 0; + + if (!nflag ) + ihe = iso_gethostentrybyaddr( &sa, 0, 0 ); + if( ihe ) { + Ihe = *ihe; + ihe = &Ihe; + sprintf(line, "%s", ihe->isoh_hname); + } else { + sprintf(line, "%s", iso_ntoa(iso)); + } + } else { + sprintf(line, "*"); + } + return line; +} + +static void +isonetprint(iso, sufx, sufxlen, islocal) + register struct iso_addr *iso; + char *sufx; + u_short sufxlen; + int islocal; +{ + struct iso_hostent *iso_getserventrybytsel(), *ihe; + struct iso_hostent Ihe; + char *line, *cp; + int Alen = Aflag?18:22; + + line = isonetname(iso); + cp = index(line, '\0'); + ihe = (struct iso_hostent *)0; + + if( islocal ) + islocal = 20; + else + islocal = 22 + Alen; + + if(Aflag) + islocal += 10 ; + + if(!nflag) { + if( (cp -line)>10 ) { + cp = line+10; + bzero(cp, sizeof(line)-10); + } + } + + *cp++ = '.'; + if(sufxlen) { + if( !Aflag && !nflag && (ihe=iso_getserventrybytsel(sufx, sufxlen))) { + Ihe = *ihe; + ihe = &Ihe; + } + if( ihe && (strlen(ihe->isoh_aname)>0) ) { + sprintf(cp, "%s", ihe->isoh_aname); + } else { + iso_sprinttsel(cp, sufx, sufxlen); + } + } else + sprintf(cp, "*"); + /* + fprintf(stdout, Aflag?" %-18.18s":" %-22.22s", line); + */ + + if( strlen(line) > Alen ) { + fprintf(stdout, " %s", line); + fprintf(stdout, "\n %*.s", islocal+Alen," "); + } else { + fprintf(stdout, " %-*.*s", Alen, Alen,line); + } +} +#endif + +#ifdef notdef +static void +x25_protopr(off, name) + u_long off; + char *name; +{ + static char *xpcb_states[] = { + "CLOSED", + "LISTENING", + "CLOSING", + "CONNECTING", + "ACKWAIT", + "OPEN", + }; + register struct isopcb *prev, *next; + struct x25_pcb xpcb; + + if (off == 0) { + printf("%s control block: symbol not in namelist\n", name); + return; + } + kread(off, &xpcb, sizeof (struct x25_pcb)); + prev = (struct isopcb *)off; + if (xpcb.x_next == (struct isopcb *)off) + return; + while (xpcb.x_next != (struct isopcb *)off) { + next = isopcb.isop_next; + kread((u_long)next, &xpcb, sizeof (struct x25_pcb)); + if (xpcb.x_prev != prev) { + printf("???\n"); + break; + } + kread((u_long)xpcb.x_socket, &sockb, sizeof (sockb)); + + if (!aflag && + xpcb.x_state == LISTENING || + xpcb.x_state == TP_CLOSED ) { + prev = next; + continue; + } + if (first) { + printf("Active X25 net 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; + } + printf("%-5.5s %6d %6d ", name, sockb.so_rcv.sb_cc, + sockb.so_snd.sb_cc); + isonetprint(&xpcb.x_laddr.siso_addr, &xpcb.x_lport, + sizeof(xpcb.x_lport), 1); + isonetprint(&xpcb.x_faddr.siso_addr, &xpcb.x_fport, + sizeof(xpcb.x_lport), 0); + if (xpcb.x_state < 0 || xpcb.x_state >= x25_NSTATES) + printf(" 0x0x0x0x0x0x0x0x0x%x", xpcb.x_state); + else + printf(" %-12.12s", xpcb_states[xpcb.x_state]); + putchar('\n'); + prev = next; + } +} +#endif + +struct tp_stat tp_stat; + +void +tp_stats(off, name) + caddr_t off, name; +{ + if (off == 0) { + printf("TP not configured\n\n"); + return; + } + printf("%s:\n", name); + kget(off, tp_stat); + tprintstat(&tp_stat, 8); +} + +#define OUT stdout + +static void +tprintstat(s, indent) + register struct tp_stat *s; + int indent; +{ + fprintf(OUT, + "%*sReceiving:\n",indent," "); + fprintf(OUT, + "\t%*s%d variable parameter%s ignored\n", indent," ", + s->ts_param_ignored ,plural(s->ts_param_ignored)); + fprintf(OUT, + "\t%*s%d invalid parameter code%s\n", indent, " ", + s->ts_inv_pcode ,plural(s->ts_inv_pcode)); + fprintf(OUT, + "\t%*s%d invalid parameter value%s\n", indent, " ", + s->ts_inv_pval ,plural(s->ts_inv_pval)); + fprintf(OUT, + "\t%*s%d invalid dutype%s\n", indent, " ", + s->ts_inv_dutype ,plural(s->ts_inv_dutype)); + fprintf(OUT, + "\t%*s%d negotiation failure%s\n", indent, " ", + s->ts_negotfailed ,plural(s->ts_negotfailed)); + fprintf(OUT, + "\t%*s%d invalid destination reference%s\n", indent, " ", + s->ts_inv_dref ,plural(s->ts_inv_dref)); + fprintf(OUT, + "\t%*s%d invalid suffix parameter%s\n", indent, " ", + s->ts_inv_sufx ,plural(s->ts_inv_sufx)); + fprintf(OUT, + "\t%*s%d invalid length\n",indent, " ", s->ts_inv_length); + fprintf(OUT, + "\t%*s%d invalid checksum%s\n", indent, " ", + s->ts_bad_csum ,plural(s->ts_bad_csum)); + fprintf(OUT, + "\t%*s%d DT%s out of order\n", indent, " ", + s->ts_dt_ooo ,plural(s->ts_dt_ooo)); + fprintf(OUT, + "\t%*s%d DT%s not in window\n", indent, " ", + s->ts_dt_niw ,plural(s->ts_dt_niw)); + fprintf(OUT, + "\t%*s%d duplicate DT%s\n", indent, " ", + s->ts_dt_dup ,plural(s->ts_dt_dup)); + fprintf(OUT, + "\t%*s%d XPD%s not in window\n", indent, " ", + s->ts_xpd_niw ,plural(s->ts_xpd_niw)); + fprintf(OUT, + "\t%*s%d XPD%s w/o credit to stash\n", indent, " ", + s->ts_xpd_dup ,plural(s->ts_xpd_dup)); + fprintf(OUT, + "\t%*s%d time%s local credit reneged\n", indent, " ", + s->ts_lcdt_reduced ,plural(s->ts_lcdt_reduced)); + fprintf(OUT, + "\t%*s%d concatenated TPDU%s\n", indent, " ", + s->ts_concat_rcvd ,plural(s->ts_concat_rcvd)); + fprintf(OUT, + "%*sSending:\n", indent, " "); + fprintf(OUT, + "\t%*s%d XPD mark%s discarded\n", indent, " ", + s->ts_xpdmark_del ,plural(s->ts_xpdmark_del)); + fprintf(OUT, + "\t%*sXPD stopped data flow %d time%s\n", indent, " ", + s->ts_xpd_intheway ,plural(s->ts_xpd_intheway)); + fprintf(OUT, + "\t%*s%d time%s foreign window closed\n", indent, " ", + s->ts_zfcdt ,plural(s->ts_zfcdt)); + fprintf(OUT, + "%*sMiscellaneous:\n", indent, " "); + fprintf(OUT, + "\t%*s%d small mbuf%s\n", indent, " ", + s->ts_mb_small ,plural(s->ts_mb_small)); + fprintf(OUT, + "\t%*s%d cluster%s\n", indent, " ", + s->ts_mb_cluster, plural(s->ts_mb_cluster)); + fprintf(OUT, + "\t%*s%d source quench \n",indent, " ", + s->ts_quench); + fprintf(OUT, + "\t%*s%d dec bit%s\n", indent, " ", + s->ts_rcvdecbit, plural(s->ts_rcvdecbit)); + fprintf(OUT, + "\t%*sM:L ( M mbuf chains of length L)\n", indent, " "); + { + register int j; + + fprintf(OUT, "\t%*s%d: over 16\n", indent, " ", + s->ts_mb_len_distr[0]); + for( j=1; j<=8; j++) { + fprintf(OUT, + "\t%*s%d: %d\t\t%d: %d\n", indent, " ", + s->ts_mb_len_distr[j],j, + s->ts_mb_len_distr[j<<1],j<<1 + ); + } + } + fprintf(OUT, + "\t%*s%d EOT rcvd\n", indent, " ", s->ts_eot_input); + fprintf(OUT, + "\t%*s%d EOT sent\n", indent, " ", s->ts_EOT_sent); + fprintf(OUT, + "\t%*s%d EOT indication%s\n", indent, " ", + s->ts_eot_user ,plural(s->ts_eot_user)); + + fprintf(OUT, + "%*sConnections:\n", indent, " "); + fprintf(OUT, + "\t%*s%d connection%s used extended format\n", indent, " ", + s->ts_xtd_fmt ,plural(s->ts_xtd_fmt)); + fprintf(OUT, + "\t%*s%d connection%s allowed transport expedited data\n", indent, " ", + s->ts_use_txpd ,plural(s->ts_use_txpd)); + fprintf(OUT, + "\t%*s%d connection%s turned off checksumming\n", indent, " ", + s->ts_csum_off ,plural(s->ts_csum_off)); + fprintf(OUT, + "\t%*s%d connection%s dropped due to retrans limit\n", indent, " ", + s->ts_conn_gaveup ,plural(s->ts_conn_gaveup)); + fprintf(OUT, + "\t%*s%d tp 4 connection%s\n", indent, " ", + s->ts_tp4_conn ,plural(s->ts_tp4_conn)); + fprintf(OUT, + "\t%*s%d tp 0 connection%s\n", indent, " ", + s->ts_tp0_conn ,plural(s->ts_tp0_conn)); + { + register int j; + static char *name[]= { + "~LOCAL, PDN", + "~LOCAL,~PDN", + " LOCAL,~PDN", + " LOCAL, PDN" + }; + + fprintf(OUT, + "\n%*sRound trip times, listed in ticks:\n", indent, " "); + fprintf(OUT, + "\t%*s%11.11s %12.12s | %12.12s | %s\n", indent, " ", + "Category", + "Smoothed avg", "Deviation", "Deviation/Avg"); + for (j = 0; j <= 3; j++) { + fprintf(OUT, + "\t%*s%11.11s: %-11d | %-11d | %-11d | %-11d\n", indent, " ", + name[j], + s->ts_rtt[j], + s->ts_rtt[j], + s->ts_rtv[j], + s->ts_rtv[j]); + } + } + fprintf(OUT, +"\n%*sTpdus RECVD [%d valid, %3.6f %% of total (%d); %d dropped]\n",indent," ", + s->ts_tpdu_rcvd , + ((s->ts_pkt_rcvd > 0) ? + ((100 * (float)s->ts_tpdu_rcvd)/(float)s->ts_pkt_rcvd) + : 0), + s->ts_pkt_rcvd, + s->ts_recv_drop ); + + fprintf(OUT, + "\t%*sDT %6d AK %6d DR %4d CR %4d \n", indent, " ", + s->ts_DT_rcvd, s->ts_AK_rcvd, s->ts_DR_rcvd, s->ts_CR_rcvd); + fprintf(OUT, + "\t%*sXPD %6d XAK %6d DC %4d CC %4d ER %4d\n", indent, " ", + s->ts_XPD_rcvd, s->ts_XAK_rcvd, s->ts_DC_rcvd, s->ts_CC_rcvd, + s->ts_ER_rcvd); + fprintf(OUT, + "\n%*sTpdus SENT [%d total, %d dropped]\n", indent, " ", + s->ts_tpdu_sent, s->ts_send_drop); + + fprintf(OUT, + "\t%*sDT %6d AK %6d DR %4d CR %4d \n", indent, " ", + s->ts_DT_sent, s->ts_AK_sent, s->ts_DR_sent, s->ts_CR_sent); + fprintf(OUT, + "\t%*sXPD %6d XAK %6d DC %4d CC %4d ER %4d\n", indent, " ", + s->ts_XPD_sent, s->ts_XAK_sent, s->ts_DC_sent, s->ts_CC_sent, + s->ts_ER_sent); + + fprintf(OUT, + "\n%*sRetransmissions:\n", indent, " "); +#define PERCENT(X,Y) (((Y)>0)?((100 *(float)(X)) / (float) (Y)):0) + + fprintf(OUT, + "\t%*sCR %6d CC %6d DR %6d \n", indent, " ", + s->ts_retrans_cr, s->ts_retrans_cc, s->ts_retrans_dr); + fprintf(OUT, + "\t%*sDT %6d (%5.2f%%)\n", indent, " ", + s->ts_retrans_dt, + PERCENT(s->ts_retrans_dt, s->ts_DT_sent)); + fprintf(OUT, + "\t%*sXPD %6d (%5.2f%%)\n", indent, " ", + s->ts_retrans_xpd, + PERCENT(s->ts_retrans_xpd, s->ts_XPD_sent)); + + + fprintf(OUT, + "\n%*sE Timers: [%6d ticks]\n", indent, " ", s->ts_Eticks); + fprintf(OUT, + "%*s%6d timer%s set \t%6d timer%s expired \t%6d timer%s cancelled\n",indent, " ", + s->ts_Eset ,plural(s->ts_Eset), + s->ts_Eexpired ,plural(s->ts_Eexpired), + s->ts_Ecan_act ,plural(s->ts_Ecan_act)); + + fprintf(OUT, + "\n%*sC Timers: [%6d ticks]\n", indent, " ",s->ts_Cticks); + fprintf(OUT, + "%*s%6d timer%s set \t%6d timer%s expired \t%6d timer%s cancelled\n", + indent, " ", + s->ts_Cset ,plural(s->ts_Cset), + s->ts_Cexpired ,plural(s->ts_Cexpired), + s->ts_Ccan_act ,plural(s->ts_Ccan_act)); + fprintf(OUT, + "%*s%6d inactive timer%s cancelled\n", indent, " ", + s->ts_Ccan_inact ,plural(s->ts_Ccan_inact)); + + fprintf(OUT, + "\n%*sPathological debugging activity:\n", indent, " "); + fprintf(OUT, + "\t%*s%6d CC%s sent to zero dref\n", indent, " ", + s->ts_zdebug ,plural(s->ts_zdebug)); + /* SAME LINE AS ABOVE */ + fprintf(OUT, + "\t%*s%6d random DT%s dropped\n", indent, " ", + s->ts_ydebug ,plural(s->ts_ydebug)); + fprintf(OUT, + "\t%*s%6d illegally large XPD TPDU%s\n", indent, " ", + s->ts_vdebug ,plural(s->ts_vdebug)); + fprintf(OUT, + "\t%*s%6d faked reneging of cdt\n", indent, " ", + s->ts_ldebug ); + + fprintf(OUT, + "\n%*sACK reasons:\n", indent, " "); + fprintf(OUT, "\t%*s%6d not acked immediately\n", indent, " ", + s->ts_ackreason[_ACK_DONT_] ); + fprintf(OUT, "\t%*s%6d strategy==each\n", indent, " ", + s->ts_ackreason[_ACK_STRAT_EACH_] ); + fprintf(OUT, "\t%*s%6d strategy==fullwindow\n", indent, " ", + s->ts_ackreason[_ACK_STRAT_FULLWIN_] ); + fprintf(OUT, "\t%*s%6d duplicate DT\n", indent, " ", + s->ts_ackreason[_ACK_DUP_] ); + fprintf(OUT, "\t%*s%6d EOTSDU\n", indent, " ", + s->ts_ackreason[_ACK_EOT_] ); + fprintf(OUT, "\t%*s%6d reordered DT\n", indent, " ", + s->ts_ackreason[_ACK_REORDER_] ); + fprintf(OUT, "\t%*s%6d user rcvd\n", indent, " ", + s->ts_ackreason[_ACK_USRRCV_] ); + fprintf(OUT, "\t%*s%6d fcc reqd\n", indent, " ", + s->ts_ackreason[_ACK_FCC_] ); +} +#ifndef SSEL +#define SSEL(s) ((s)->siso_tlen + TSEL(s)) +#define PSEL(s) ((s)->siso_slen + SSEL(s)) +#endif + +static void +isonetprint(siso, islocal) + register struct sockaddr_iso *siso; + int islocal; +{ + hexprint(siso->siso_nlen, siso->siso_addr.isoa_genaddr, "{}"); + if (siso->siso_tlen || siso->siso_slen || siso->siso_plen) + hexprint(siso->siso_tlen, TSEL(siso), "()"); + if (siso->siso_slen || siso->siso_plen) + hexprint(siso->siso_slen, SSEL(siso), "[]"); + if (siso->siso_plen) + hexprint(siso->siso_plen, PSEL(siso), "<>"); + putchar(' '); +} + +static char hexlist[] = "0123456789abcdef", obuf[128]; + +static void +hexprint(n, buf, delim) + int n; + char *buf, *delim; +{ + register u_char *in = (u_char *)buf, *top = in + n; + register char *out = obuf; + register int i; + + if (n == 0) + return; + while (in < top) { + i = *in++; + *out++ = '.'; + if (i > 0xf) { + out[1] = hexlist[i & 0xf]; + i >>= 4; + out[0] = hexlist[i]; + out += 2; + } else + *out++ = hexlist[i]; + } + *obuf = *delim; *out++ = delim[1]; *out = 0; + printf("%s", obuf); +} diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c new file mode 100644 index 00000000000..bb66217ca51 --- /dev/null +++ b/usr.bin/netstat/main.c @@ -0,0 +1,517 @@ +/* $NetBSD: main.c,v 1.8 1995/10/03 21:42:40 thorpej Exp $ */ + +/* + * Copyright (c) 1983, 1988, 1993 + * Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1983, 1988, 1993\n\ + Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "from: @(#)main.c 8.4 (Berkeley) 3/1/94"; +#else +static char *rcsid = "$NetBSD: main.c,v 1.8 1995/10/03 21:42:40 thorpej Exp $"; +#endif +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/file.h> +#include <sys/protosw.h> +#include <sys/socket.h> + +#include <netinet/in.h> + +#include <ctype.h> +#include <errno.h> +#include <kvm.h> +#include <limits.h> +#include <netdb.h> +#include <nlist.h> +#include <paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "netstat.h" + +struct nlist nl[] = { +#define N_MBSTAT 0 + { "_mbstat" }, +#define N_IPSTAT 1 + { "_ipstat" }, +#define N_TCBTABLE 2 + { "_tcbtable" }, +#define N_TCPSTAT 3 + { "_tcpstat" }, +#define N_UDBTABLE 4 + { "_udbtable" }, +#define N_UDPSTAT 5 + { "_udpstat" }, +#define N_IFNET 6 + { "_ifnet" }, +#define N_IMP 7 + { "_imp_softc" }, +#define N_ICMPSTAT 8 + { "_icmpstat" }, +#define N_RTSTAT 9 + { "_rtstat" }, +#define N_UNIXSW 10 + { "_unixsw" }, +#define N_IDP 11 + { "_nspcb"}, +#define N_IDPSTAT 12 + { "_idpstat"}, +#define N_SPPSTAT 13 + { "_spp_istat"}, +#define N_NSERR 14 + { "_ns_errstat"}, +#define N_CLNPSTAT 15 + { "_clnp_stat"}, +#define IN_NOTUSED 16 + { "_tp_inpcb" }, +#define ISO_TP 17 + { "_tp_refinfo" }, +#define N_TPSTAT 18 + { "_tp_stat" }, +#define N_ESISSTAT 19 + { "_esis_stat"}, +#define N_NIMP 20 + { "_nimp"}, +#define N_RTREE 21 + { "_rt_tables"}, +#define N_CLTP 22 + { "_cltb"}, +#define N_CLTPSTAT 23 + { "_cltpstat"}, +#define N_NFILE 24 + { "_nfile" }, +#define N_FILE 25 + { "_file" }, +#define N_IGMPSTAT 26 + { "_igmpstat" }, +#define N_MRTPROTO 27 + { "_ip_mrtproto" }, +#define N_MRTSTAT 28 + { "_mrtstat" }, +#define N_MFCHASHTBL 29 + { "_mfchashtbl" }, +#define N_MFCHASH 30 + { "_mfchash" }, +#define N_VIFTABLE 31 + { "_viftable" }, + "", +}; + +struct protox { + u_char pr_index; /* index into nlist of cb head */ + u_char pr_sindex; /* index into nlist of stat block */ + u_char pr_wanted; /* 1 if wanted, 0 otherwise */ + void (*pr_cblocks)(); /* control blocks printing routine */ + void (*pr_stats)(); /* statistics printing routine */ + char *pr_name; /* well-known name */ +} protox[] = { + { N_TCBTABLE, N_TCPSTAT, 1, protopr, + tcp_stats, "tcp" }, + { N_UDBTABLE, N_UDPSTAT, 1, protopr, + udp_stats, "udp" }, + { -1, N_IPSTAT, 1, 0, + ip_stats, "ip" }, + { -1, N_ICMPSTAT, 1, 0, + icmp_stats, "icmp" }, + { -1, N_IGMPSTAT, 1, 0, + igmp_stats, "igmp" }, + { -1, -1, 0, 0, + 0, 0 } +}; + +struct protox nsprotox[] = { + { N_IDP, N_IDPSTAT, 1, nsprotopr, + idp_stats, "idp" }, + { N_IDP, N_SPPSTAT, 1, nsprotopr, + spp_stats, "spp" }, + { -1, N_NSERR, 1, 0, + nserr_stats, "ns_err" }, + { -1, -1, 0, 0, + 0, 0 } +}; + +struct protox isoprotox[] = { + { ISO_TP, N_TPSTAT, 1, iso_protopr, + tp_stats, "tp" }, + { N_CLTP, N_CLTPSTAT, 1, iso_protopr, + cltp_stats, "cltp" }, + { -1, N_CLNPSTAT, 1, 0, + clnp_stats, "clnp"}, + { -1, N_ESISSTAT, 1, 0, + esis_stats, "esis"}, + { -1, -1, 0, 0, + 0, 0 } +}; + +struct protox *protoprotox[] = { protox, nsprotox, isoprotox, NULL }; + +static void printproto __P((struct protox *, char *)); +static void usage __P((void)); +static struct protox *name2protox __P((char *)); +static struct protox *knownname __P((char *)); + +kvm_t *kvmd; + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + register struct protoent *p; + register struct protox *tp; /* for printing cblocks & stats */ + register char *cp; + int ch; + char *nlistf = NULL, *memf = NULL; + char buf[_POSIX2_LINE_MAX]; + + if (cp = rindex(argv[0], '/')) + prog = cp + 1; + else + prog = argv[0]; + af = AF_UNSPEC; + + while ((ch = getopt(argc, argv, "Aadf:ghI:iM:mN:np:rstuw:")) != EOF) + switch(ch) { + case 'A': + Aflag = 1; + break; + case 'a': + aflag = 1; + break; + case 'd': + dflag = 1; + break; + case 'f': + if (strcmp(optarg, "ns") == 0) + af = AF_NS; + else if (strcmp(optarg, "inet") == 0) + af = AF_INET; + else if (strcmp(optarg, "unix") == 0) + af = AF_UNIX; + else if (strcmp(optarg, "iso") == 0) + af = AF_ISO; + else { + (void)fprintf(stderr, + "%s: %s: unknown address family\n", + prog, optarg); + exit(1); + } + break; + case 'g': + gflag = 1; + break; + case 'I': { + char *cp; + + iflag = 1; + for (cp = interface = optarg; isalpha(*cp); cp++) + continue; + unit = atoi(cp); + *cp = '\0'; + break; + } + case 'i': + iflag = 1; + break; + case 'M': + memf = optarg; + break; + case 'm': + mflag = 1; + break; + case 'N': + nlistf = optarg; + break; + case 'n': + nflag = 1; + break; + case 'p': + if ((tp = name2protox(optarg)) == NULL) { + (void)fprintf(stderr, + "%s: %s: unknown or uninstrumented protocol\n", + prog, optarg); + exit(1); + } + pflag = 1; + break; + case 'r': + rflag = 1; + break; + case 's': + ++sflag; + break; + case 't': + tflag = 1; + break; + case 'u': + af = AF_UNIX; + break; + case 'w': + interval = atoi(optarg); + iflag = 1; + break; + case '?': + default: + usage(); + } + argv += optind; + argc -= optind; + +#define BACKWARD_COMPATIBILITY +#ifdef BACKWARD_COMPATIBILITY + if (*argv) { + if (isdigit(**argv)) { + interval = atoi(*argv); + if (interval <= 0) + usage(); + ++argv; + iflag = 1; + } + if (*argv) { + nlistf = *argv; + if (*++argv) + memf = *argv; + } + } +#endif + + /* + * Discard setgid privileges if not the running kernel so that bad + * guys can't print interesting stuff from kernel memory. + */ + if (nlistf != NULL || memf != NULL) + setgid(getgid()); + + if ((kvmd = kvm_open(nlistf, memf, NULL, O_RDONLY, prog)) == NULL) { + fprintf(stderr, "%s: kvm_open: %s\n", prog, buf); + exit(1); + } + if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) { + if (nlistf) + fprintf(stderr, "%s: %s: no namelist\n", prog, nlistf); + else + fprintf(stderr, "%s: no namelist\n", prog); + exit(1); + } + if (mflag) { + mbpr(nl[N_MBSTAT].n_value); + exit(0); + } + if (pflag) { + if (tp->pr_stats) + (*tp->pr_stats)(nl[tp->pr_sindex].n_value, + tp->pr_name); + else + printf("%s: no stats routine\n", tp->pr_name); + exit(0); + } + /* + * Keep file descriptors open to avoid overhead + * of open/close on each call to get* routines. + */ + sethostent(1); + setnetent(1); + if (iflag) { + intpr(interval, nl[N_IFNET].n_value); + exit(0); + } + if (rflag) { + if (sflag) + rt_stats(nl[N_RTSTAT].n_value); + else + routepr(nl[N_RTREE].n_value); + 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); + 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); + } + endprotoent(); + } + if (af == AF_NS || af == AF_UNSPEC) + for (tp = nsprotox; tp->pr_name; tp++) + printproto(tp, tp->pr_name); + if (af == AF_ISO || af == AF_UNSPEC) + for (tp = isoprotox; tp->pr_name; tp++) + printproto(tp, tp->pr_name); + if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag) + unixpr(nl[N_UNIXSW].n_value); + exit(0); +} + +/* + * Print out protocol statistics or control blocks (per sflag). + * If the interface was not specifically requested, and the symbol + * is not in the namelist, ignore this one. + */ +static void +printproto(tp, name) + register struct protox *tp; + char *name; +{ + void (*pr)(); + u_long off; + + if (sflag) { + pr = tp->pr_stats; + off = nl[tp->pr_sindex].n_value; + } else { + pr = tp->pr_cblocks; + off = nl[tp->pr_index].n_value; + } + if (pr != NULL && (off || af != AF_UNSPEC)) + (*pr)(off, name); +} + +/* + * Read kernel memory, return 0 on success. + */ +int +kread(addr, buf, size) + u_long addr; + char *buf; + int size; +{ + + if (kvm_read(kvmd, addr, buf, size) != size) { + /* XXX this duplicates kvm_read's error printout */ + (void)fprintf(stderr, "%s: kvm_read %s\n", prog, + kvm_geterr(kvmd)); + return (-1); + } + return (0); +} + +char * +plural(n) + int n; +{ + return (n != 1 ? "s" : ""); +} + +char * +plurales(n) + int n; +{ + return (n != 1 ? "es" : ""); +} + +/* + * Find the protox for the given "well-known" name. + */ +static struct protox * +knownname(name) + char *name; +{ + struct protox **tpp, *tp; + + for (tpp = protoprotox; *tpp; tpp++) + for (tp = *tpp; tp->pr_name; tp++) + if (strcmp(tp->pr_name, name) == 0) + return (tp); + return (NULL); +} + +/* + * Find the protox corresponding to name. + */ +static struct protox * +name2protox(name) + char *name; +{ + struct protox *tp; + char **alias; /* alias from p->aliases */ + struct protoent *p; + + /* + * Try to find the name in the list of "well-known" names. If that + * fails, check if name is an alias for an Internet protocol. + */ + if (tp = knownname(name)) + return (tp); + + setprotoent(1); /* make protocol lookup cheaper */ + while (p = getprotoent()) { + /* assert: name not same as p->name */ + for (alias = p->p_aliases; *alias; alias++) + if (strcmp(name, *alias) == 0) { + endprotoent(); + return (knownname(p->p_name)); + } + } + endprotoent(); + return (NULL); +} + +static void +usage() +{ + (void)fprintf(stderr, +"usage: %s [-Aan] [-f address_family] [-M core] [-N system]\n", prog); + (void)fprintf(stderr, +" %s [-ghimnrs] [-f address_family] [-M core] [-N system]\n", prog); + (void)fprintf(stderr, +" %s [-n] [-I interface] [-M core] [-N system] [-w wait]\n", prog); + (void)fprintf(stderr, +" %s [-M core] [-N system] [-p protocol]\n", prog); + exit(1); +} diff --git a/usr.bin/netstat/mbuf.c b/usr.bin/netstat/mbuf.c new file mode 100644 index 00000000000..cd521471e91 --- /dev/null +++ b/usr.bin/netstat/mbuf.c @@ -0,0 +1,121 @@ +/* $NetBSD: mbuf.c,v 1.8 1995/10/03 21:42:41 thorpej 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. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "from: @(#)mbuf.c 8.1 (Berkeley) 6/6/93"; +#else +static char *rcsid = "$NetBSD: mbuf.c,v 1.8 1995/10/03 21:42:41 thorpej Exp $"; +#endif +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/mbuf.h> + +#include <stdio.h> +#include "netstat.h" + +#define YES 1 +typedef int bool; + +struct mbstat mbstat; + +static struct mbtypes { + int mt_type; + char *mt_name; +} mbtypes[] = { + { MT_DATA, "data" }, + { MT_OOBDATA, "oob data" }, + { MT_CONTROL, "ancillary data" }, + { MT_HEADER, "packet headers" }, + { MT_FTABLE, "fragment reassembly queue headers" }, /* XXX */ + { MT_SONAME, "socket names and addresses" }, + { MT_SOOPTS, "socket options" }, + { 0, 0 } +}; + +int nmbtypes = sizeof(mbstat.m_mtypes) / sizeof(short); +bool seen[256]; /* "have we seen this type yet?" */ + +/* + * Print mbuf statistics. + */ +void +mbpr(mbaddr) + u_long mbaddr; +{ + register int totmem, totfree, totmbufs; + register int i; + register struct mbtypes *mp; + + if (nmbtypes != 256) { + fprintf(stderr, + "%s: unexpected change to mbstat; check source\n", prog); + return; + } + if (mbaddr == 0) { + fprintf(stderr, "%s: mbstat: symbol not in namelist\n", prog); + return; + } + if (kread(mbaddr, (char *)&mbstat, sizeof (mbstat))) + return; + totmbufs = 0; + for (mp = mbtypes; mp->mt_name; mp++) + totmbufs += mbstat.m_mtypes[mp->mt_type]; + printf("%u mbufs in use:\n", totmbufs); + for (mp = mbtypes; mp->mt_name; mp++) + if (mbstat.m_mtypes[mp->mt_type]) { + seen[mp->mt_type] = YES; + printf("\t%u mbufs allocated to %s\n", + mbstat.m_mtypes[mp->mt_type], mp->mt_name); + } + seen[MT_FREE] = YES; + for (i = 0; i < nmbtypes; i++) + if (!seen[i] && mbstat.m_mtypes[i]) { + printf("\t%u mbufs allocated to <mbuf type %d>\n", + mbstat.m_mtypes[i], i); + } + printf("%u/%u mapped pages in use\n", + mbstat.m_clusters - mbstat.m_clfree, mbstat.m_clusters); + totmem = totmbufs * MSIZE + mbstat.m_clusters * MCLBYTES; + totfree = mbstat.m_clfree * MCLBYTES; + printf("%u Kbytes allocated to network (%d%% in use)\n", + totmem / 1024, (totmem - totfree) * 100 / totmem); + printf("%u requests for memory denied\n", mbstat.m_drops); + printf("%u requests for memory delayed\n", mbstat.m_wait); + printf("%u calls to protocol drain routines\n", mbstat.m_drain); +} diff --git a/usr.bin/netstat/mroute.c b/usr.bin/netstat/mroute.c new file mode 100644 index 00000000000..a398f6858dd --- /dev/null +++ b/usr.bin/netstat/mroute.c @@ -0,0 +1,260 @@ +/* $NetBSD: mroute.c,v 1.9 1995/10/03 21:42:42 thorpej Exp $ */ + +/* + * 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. + * + * from: @(#)mroute.c 8.1 (Berkeley) 6/6/93 + */ + +/* + * Print DVMRP multicast routing structures and statistics. + * + * MROUTING 1.0 + */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> + +#include <net/if.h> +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/igmp.h> +#define _KERNEL +#include <netinet/ip_mroute.h> +#undef _KERNEL + +#include <stdio.h> +#include <stdlib.h> +#include "netstat.h" + +char * +pktscale(n) + u_long n; +{ + static char buf[8]; + char t; + + if (n < 1024) + t = ' '; + else if (n < 1024 * 1024) { + t = 'k'; + n /= 1024; + } else { + t = 'm'; + n /= 1048576; + } + + sprintf(buf, "%u%c", n, t); + return (buf); +} + +void +mroutepr(mrpaddr, mfchashtbladdr, mfchashaddr, vifaddr) + u_long mrpaddr, mfchashtbladdr, mfchashaddr, vifaddr; +{ + u_int mrtproto; + LIST_HEAD(, mfc) *mfchashtbl; + u_long mfchash; + struct vif viftable[MAXVIFS]; + struct mfc *mfcp, mfc; + register struct vif *v; + register vifi_t vifi; + struct in_addr *grp; + int i; + int banner_printed; + int saved_nflag; + int numvifs; + int nmfc; /* No. of cache entries */ + + if (mrpaddr == 0) { + printf("ip_mrtproto: symbol not in namelist\n"); + return; + } + + kread(mrpaddr, (char *)&mrtproto, sizeof(mrtproto)); + switch (mrtproto) { + case 0: + printf("no multicast routing compiled into this system\n"); + return; + + case IGMP_DVMRP: + break; + + default: + printf("multicast routing protocol %u, unknown\n", mrtproto); + return; + } + + if (mfchashtbladdr == 0) { + printf("mfchashtbl: symbol not in namelist\n"); + return; + } + if (mfchashaddr == 0) { + printf("mfchash: symbol not in namelist\n"); + return; + } + if (vifaddr == 0) { + printf("viftable: symbol not in namelist\n"); + return; + } + + saved_nflag = nflag; + nflag = 1; + + kread(vifaddr, (char *)&viftable, sizeof(viftable)); + banner_printed = 0; + numvifs = 0; + + for (vifi = 0, v = viftable; vifi < MAXVIFS; ++vifi, ++v) { + if (v->v_lcl_addr.s_addr == 0) + continue; + numvifs = vifi; + + if (!banner_printed) { + printf("\nVirtual Interface Table\n %s%s", + "Vif Thresh Limit Local-Address ", + "Remote-Address Pkt_in Pkt_out\n"); + banner_printed = 1; + } + + printf(" %3u %3u %5u %-15.15s", + vifi, v->v_threshold, v->v_rate_limit, + routename(v->v_lcl_addr.s_addr)); + printf(" %-15.15s %6u %7u\n", (v->v_flags & VIFF_TUNNEL) ? + routename(v->v_rmt_addr.s_addr) : "", + v->v_pkt_in, v->v_pkt_out); + } + if (!banner_printed) + printf("\nVirtual Interface Table is empty\n"); + + kread(mfchashtbladdr, (char *)&mfchashtbl, sizeof(mfchashtbl)); + kread(mfchashaddr, (char *)&mfchash, sizeof(mfchash)); + banner_printed = 0; + nmfc = 0; + + for (i = 0; i <= mfchash; ++i) { + kread((u_long)&mfchashtbl[i], (char *)&mfcp, sizeof(mfcp)); + + for (; mfcp != 0; mfcp = mfc.mfc_hash.le_next) { + if (!banner_printed) { + printf("\nMulticast Forwarding Cache\n %s%s", + "Hash Origin Mcastgroup ", + "Traffic In-Vif Out-Vifs/Forw-ttl\n"); + banner_printed = 1; + } + + kread((u_long)mfcp, (char *)&mfc, sizeof(mfc)); + printf(" %3u %-15.15s", + i, routename(mfc.mfc_origin.s_addr)); + printf(" %-15.15s %7s %3u ", + routename(mfc.mfc_mcastgrp.s_addr), + pktscale(mfc.mfc_pkt_cnt), mfc.mfc_parent); + for (vifi = 0; vifi <= numvifs; ++vifi) + if (mfc.mfc_ttls[vifi]) + printf(" %u/%u", vifi, mfc.mfc_ttls[vifi]); + + printf("\n"); + nmfc++; + } + } + if (!banner_printed) + printf("\nMulticast Forwarding Cache is empty\n"); + else + printf("\nTotal no. of entries in cache: %d\n", nmfc); + + printf("\n"); + nflag = saved_nflag; +} + + +void +mrt_stats(mrpaddr, mstaddr) + u_long mrpaddr, mstaddr; +{ + u_int mrtproto; + struct mrtstat mrtstat; + + if (mrpaddr == 0) { + printf("ip_mrtproto: symbol not in namelist\n"); + return; + } + + kread(mrpaddr, (char *)&mrtproto, sizeof(mrtproto)); + switch (mrtproto) { + case 0: + printf("no multicast routing compiled into this system\n"); + return; + + case IGMP_DVMRP: + break; + + default: + printf("multicast routing protocol %u, unknown\n", mrtproto); + return; + } + + if (mstaddr == 0) { + printf("mrtstat: symbol not in namelist\n"); + return; + } + + kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat)); + printf("multicast routing:\n"); + printf("\t%d datagram%s with no route for origin\n", + mrtstat.mrts_no_route, plural(mrtstat.mrts_no_route)); + printf("\t%d upcall%s made to mrouted\n", + mrtstat.mrts_upcalls, plural(mrtstat.mrts_upcalls)); + printf("\t%d datagram%s with malformed tunnel options\n", + mrtstat.mrts_bad_tunnel, plural(mrtstat.mrts_bad_tunnel)); + printf("\t%d datagram%s with no room for tunnel options\n", + mrtstat.mrts_cant_tunnel, plural(mrtstat.mrts_cant_tunnel)); + printf("\t%d datagram%s arrived on wrong interface\n", + mrtstat.mrts_wrong_if, plural(mrtstat.mrts_wrong_if)); + printf("\t%d datagram%s dropped due to upcall Q overflow\n", + mrtstat.mrts_upq_ovflw, plural(mrtstat.mrts_upq_ovflw)); + printf("\t%d datagram%s dropped due to upcall socket overflow\n", + mrtstat.mrts_upq_sockfull, plural(mrtstat.mrts_upq_sockfull)); + printf("\t%d datagram%s cleaned up by the cache\n", + mrtstat.mrts_cache_cleanups, plural(mrtstat.mrts_cache_cleanups)); + printf("\t%d datagram%s dropped selectively by ratelimiter\n", + mrtstat.mrts_drop_sel, plural(mrtstat.mrts_drop_sel)); + printf("\t%d datagram%s dropped - bucket Q overflow\n", + mrtstat.mrts_q_overflow, plural(mrtstat.mrts_q_overflow)); + printf("\t%d datagram%s dropped - larger than bkt size\n", + mrtstat.mrts_pkt2large, plural(mrtstat.mrts_pkt2large)); +} diff --git a/usr.bin/netstat/netstat.1 b/usr.bin/netstat/netstat.1 new file mode 100644 index 00000000000..9fd19213077 --- /dev/null +++ b/usr.bin/netstat/netstat.1 @@ -0,0 +1,296 @@ +.\" $NetBSD: netstat.1,v 1.11 1995/10/03 21:42:43 thorpej Exp $ +.\" +.\" Copyright (c) 1983, 1990, 1992, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" from: @(#)netstat.1 8.8 (Berkeley) 4/18/94 +.\" +.Dd April 18, 1994 +.Dt NETSTAT 1 +.Os BSD 4.2 +.Sh NAME +.Nm netstat +.Nd show network status +.Sh SYNOPSIS +.Nm netstat +.Op Fl Aan +.Op Fl f Ar address_family +.Op Fl M Ar core +.Op Fl N Ar system +.Nm netstat +.Op Fl dghimnrs +.Op Fl f Ar address_family +.Op Fl M Ar core +.Op Fl N Ar system +.Nm netstat +.Op Fl dn +.Op Fl I Ar interface +.Op Fl M Ar core +.Op Fl N Ar system +.Op Fl w Ar wait +.Nm netstat +.Op Fl p Ar protocol +.Op Fl M Ar core +.Op Fl N Ar system +.Sh DESCRIPTION +The +.Nm netstat +command symbolically displays the contents of various network-related +data structures. +There are a number of output formats, +depending on the options for the information presented. +The first form of the command displays a list of active sockets for +each protocol. +The second form presents the contents of one of the other network +data structures according to the option selected. +Using the third form, with a +.Ar wait +interval specified, +.Nm netstat +will continuously display the information regarding packet +traffic on the configured network interfaces. +The fourth form displays statistics about the named protocol. +.Pp +The options have the following meaning: +.Bl -tag -width flag +.It Fl A +With the default display, +show the address of any protocol control blocks associated with sockets; used +for debugging. +.It Fl a +With the default display, +show the state of all sockets; normally sockets used by +server processes are not shown. +.It Fl d +With either interface display (option +.Fl i +or an interval, as described below), +show the number of dropped packets. +.It Fl f Ar address_family +Limit statistics or address control block reports to those +of the specified +.Ar address family . +The following address families +are recognized: +.Ar inet , +for +.Dv AF_INET , +.Ar ns , +for +.Dv AF_NS , +.Ar iso , +for +.Dv AF_ISO , +and +.Ar unix , +for +.Dv AF_UNIX . +.It Fl g +Show information related to multicast (group address) routing. +By default, show the IP Multicast virtual-interface and routing tables. +If the +.Fl s +option is also present, show multicast routing statistics. +.It Fl h +Show the state of the +.Tn IMP +host table (obsolete). +.It Fl I Ar interface +Show information about the specified interface; +used with a +.Ar wait +interval as described below. +.It Fl i +Show the state of interfaces which have been auto-configured +(interfaces statically configured into a system, but not +located at boot time are not shown). +If the +.Fl a +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. +.It Fl M +Extract values associated with the name list from the specified core +instead of the default +.Pa /dev/kmem . +.It Fl m +Show statistics recorded by the memory management routines +(the network manages a private pool of memory buffers). +.It Fl N +Extract the name list from the specified system instead of the default +.Pa /netbsd . +.It Fl n +Show network addresses as numbers (normally +.Nm netstat +interprets addresses and attempts to display them +symbolically). +This option may be used with any of the display formats. +.It Fl p Ar protocol +Show statistics about +.Ar protocol , +which is either a well-known name for a protocol or an alias for it. Some +protocol names and aliases are listed in the file +.Pa /etc/protocols . +A null response typically means that there are no interesting numbers to +report. +The program will complain if +.Ar protocol +is unknown or if there is no statistics routine for it. +.It Fl s +Show per-protocol statistics. +If this option is repeated, counters with a value of zero are suppressed. +.It Fl r +Show the routing tables. +When +.Fl s +is also present, show routing statistics instead. +.It Fl w Ar wait +Show network interface statistics at intervals of +.Ar wait +seconds. +.El +.Pp +The default display, for active sockets, shows the local +and remote addresses, send and receive queue sizes (in bytes), protocol, +and the internal state of the protocol. +Address formats are of the form ``host.port'' or ``network.port'' +if a socket's address specifies a network but no specific host address. +When known the host and network addresses are displayed symbolically +according to the data bases +.Pa /etc/hosts +and +.Pa /etc/networks , +respectively. If a symbolic name for an address is unknown, or if +the +.Fl n +option is specified, the address is printed numerically, according +to the address family. +For more information regarding +the Internet ``dot format,'' +refer to +.Xr inet 3 ) . +Unspecified, +or ``wildcard'', addresses and ports appear as ``*''. +.Pp +The interface display provides a table of cumulative +statistics regarding packets transferred, errors, and collisions. +The network addresses of the interface +and the maximum transmission unit (``mtu'') are also displayed. +.Pp +The routing table display indicates the available routes and +their status. Each route consists of a destination host or network +and a gateway to use in forwarding packets. The flags field shows +a collection of information about the route stored as +binary choices. The individual flags are discussed in more +detail in the +.Xr route 8 +and +.Xr route 4 +manual pages. +The mapping between letters and flags is: +.Bl -column XXXX RTF_BLACKHOLE +1 RTF_PROTO2 Protocol specific routing flag #1 +2 RTF_PROTO1 Protocol specific routing flag #2 +B RTF_BLACKHOLE Just discard pkts (during updates) +C RTF_CLONING Generate new routes on use +D RTF_DYNAMIC Created dynamically (by redirect) +G RTF_GATEWAY Destination requires forwarding by intermediary +H RTF_HOST Host entry (net otherwise) +L RTF_LLINFO Valid protocol to link address translation. +M RTF_MODIFIED Modified dynamically (by redirect) +R RTF_REJECT Host or net unreachable +S RTF_STATIC Manually added +U RTF_UP Route usable +X RTF_XRESOLVE External daemon translates proto to link address +.El +.Pp +Direct routes are created for each +interface attached to the local host; +the gateway field for such entries shows the address of the outgoing interface. +The refcnt field gives the +current number of active uses of the route. Connection oriented +protocols normally hold on to a single route for the duration of +a connection while connectionless protocols obtain a route while sending +to the same destination. +The use field provides a count of the number of packets +sent using that route. The mtu entry shows the mtu associated with +that route. This mtu value is used as the basis for the TCP maximum +segment size. A +.Sq - +indicates that the mtu for this route has not been set, and a default +TCP maximum segment size will be used. The interface entry indicates +the network interface utilized for the route. +.Pp +When +.Nm netstat +is invoked with the +.Fl w +option and a +.Ar wait +interval argument, it displays a running count of statistics related to +network interfaces. +An obsolescent version of this option used a numeric parameter +with no option, and is currently supported for backward compatibility. +This display consists of a column for the primary interface (the first +interface found during autoconfiguration) and a column summarizing +information for all interfaces. +The primary interface may be replaced with another interface with the +.Fl I +option. +The first line of each screen of information contains a summary since the +system was last rebooted. Subsequent lines of output show values +accumulated over the preceding interval. +.Sh SEE ALSO +.Xr nfsstat 1 , +.Xr ps 1 , +.Xr hosts 5 , +.Xr networks 5 , +.Xr protocols 5 , +.Xr services 5 , +.Xr trpt 8 , +.Xr trsp 8 , +.Xr iostat 8 , +.Xr vmstat 8 +.Sh HISTORY +The +.Nm netstat +command appeared in +.Bx 4.2 . +.\" .Sh FILES +.\" .Bl -tag -width /dev/kmem -compact +.\" .It Pa /netbsd +.\" default kernel namelist +.\" .It Pa /dev/kmem +.\" default memory file +.\" .El +.Sh BUGS +The notion of errors is ill-defined. diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h new file mode 100644 index 00000000000..aaaae7b225a --- /dev/null +++ b/usr.bin/netstat/netstat.h @@ -0,0 +1,111 @@ +/* $NetBSD: netstat.h,v 1.5 1995/10/03 21:42:45 thorpej Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)netstat.h 8.2 (Berkeley) 1/4/94 + */ + +#include <sys/cdefs.h> + +int Aflag; /* show addresses of protocol control block */ +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 mflag; /* show memory stats */ +int nflag; /* show addresses numerically */ +int pflag; /* show given protocol */ +int rflag; /* show routing tables (or routing stats) */ +int sflag; /* show protocol statistics */ +int tflag; /* show i/f watchdog timers */ + +int interval; /* repeat interval for i/f stats */ + +char *interface; /* desired i/f for stats, or NULL for all i/fs */ +int unit; /* unit number for above */ + +int af; /* address family */ + +char *prog; /* program name */ + + +int kread __P((u_long addr, char *buf, int size)); +char *plural __P((int)); +char *plurales __P((int)); + +void protopr __P((u_long, char *)); +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 *)); +void protopr __P((u_long, char *)); + +void mbpr(u_long); + +void hostpr __P((u_long, u_long)); +void impstats __P((u_long, u_long)); + +void intpr __P((int, u_long)); + +void pr_rthdr __P(()); +void pr_family __P((int)); +void rt_stats __P((u_long)); +char *ns_phost __P((struct sockaddr *)); +void upHex __P((char *)); + +char *routename __P((u_int32_t)); +char *netname __P((u_int32_t, u_int32_t)); +char *ns_print __P((struct sockaddr *)); +void routepr __P((u_long)); + +void nsprotopr __P((u_long, char *)); +void spp_stats __P((u_long, char *)); +void idp_stats __P((u_long, char *)); +void nserr_stats __P((u_long, char *)); + +void intpr __P((int, u_long)); + +void unixpr __P((u_long)); + +void esis_stats __P((u_long, char *)); +void clnp_stats __P((u_long, char *)); +void cltp_stats __P((u_long, char *)); +void iso_protopr __P((u_long, char *)); +void iso_protopr1 __P((u_long, int)); +void tp_protopr __P((u_long, char *)); +void tp_inproto __P((u_long)); +void tp_stats __P((caddr_t, caddr_t)); + +void mroutepr __P((u_long, u_long, u_long, u_long)); +void mrt_stats __P((u_long, u_long)); diff --git a/usr.bin/netstat/ns.c b/usr.bin/netstat/ns.c new file mode 100644 index 00000000000..d9c8cf5a52d --- /dev/null +++ b/usr.bin/netstat/ns.c @@ -0,0 +1,357 @@ +/* $NetBSD: ns.c,v 1.8 1995/10/03 21:42:46 thorpej 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. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "from: @(#)ns.c 8.1 (Berkeley) 6/6/93"; +#else +static char *rcsid = "$NetBSD: ns.c,v 1.8 1995/10/03 21:42:46 thorpej Exp $"; +#endif +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> + +#include <net/route.h> +#include <net/if.h> + +#include <netinet/tcp_fsm.h> + +#include <netns/ns.h> +#include <netns/ns_pcb.h> +#include <netns/idp.h> +#include <netns/idp_var.h> +#include <netns/ns_error.h> +#include <netns/sp.h> +#include <netns/spidp.h> +#include <netns/spp_timer.h> +#include <netns/spp_var.h> +#define SANAMES +#include <netns/spp_debug.h> + +#include <nlist.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include "netstat.h" + +struct nspcb nspcb; +struct sppcb sppcb; +struct socket sockb; + +static char *ns_prpr __P((struct ns_addr *)); +static void ns_erputil __P((int, int)); + +static int first = 1; + +/* + * Print a summary of connections related to a Network Systems + * protocol. For SPP, also give state of connection. + * Listening processes (aflag) are suppressed unless the + * -a (all) flag is specified. + */ + +void +nsprotopr(off, name) + u_long off; + char *name; +{ + struct nspcb cb; + register struct nspcb *prev, *next; + int isspp; + + if (off == 0) + return; + isspp = strcmp(name, "spp") == 0; + kread(off, (char *)&cb, sizeof (struct nspcb)); + nspcb = cb; + prev = (struct nspcb *)off; + if (nspcb.nsp_next == (struct nspcb *)off) + return; + for (;nspcb.nsp_next != (struct nspcb *)off; prev = next) { + u_long ppcb; + + next = nspcb.nsp_next; + kread((u_long)next, (char *)&nspcb, sizeof (nspcb)); + if (nspcb.nsp_prev != prev) { + printf("???\n"); + break; + } + if (!aflag && ns_nullhost(nspcb.nsp_faddr) ) { + continue; + } + kread((u_long)nspcb.nsp_socket, + (char *)&sockb, sizeof (sockb)); + ppcb = (u_long) nspcb.nsp_pcb; + if (ppcb) { + if (isspp) { + kread(ppcb, (char *)&sppcb, sizeof (sppcb)); + } else continue; + } else + if (isspp) continue; + if (first) { + printf("Active NS connections"); + if (aflag) + printf(" (including servers)"); + putchar('\n'); + if (Aflag) + printf("%-8.8s ", "PCB"); + printf(Aflag ? + "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" : + "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n", + "Proto", "Recv-Q", "Send-Q", + "Local Address", "Foreign Address", "(state)"); + first = 0; + } + if (Aflag) + printf("%8x ", ppcb); + printf("%-5.5s %6d %6d ", name, sockb.so_rcv.sb_cc, + sockb.so_snd.sb_cc); + printf(" %-22.22s", ns_prpr(&nspcb.nsp_laddr)); + printf(" %-22.22s", ns_prpr(&nspcb.nsp_faddr)); + if (isspp) { + extern char *tcpstates[]; + if (sppcb.s_state >= TCP_NSTATES) + printf(" %d", sppcb.s_state); + else + printf(" %s", tcpstates[sppcb.s_state]); + } + putchar('\n'); + prev = next; + } +} +#define ANY(x,y,z) \ + ((x) ? printf("\t%d %s%s%s -- %s\n",x,y,plural(x),z,"x") : 0) + +/* + * Dump SPP statistics structure. + */ +void +spp_stats(off, name) + u_long off; + char *name; +{ + struct spp_istat spp_istat; +#define sppstat spp_istat.newstats + + if (off == 0) + return; + kread(off, (char *)&spp_istat, sizeof (spp_istat)); + printf("%s:\n", name); + ANY(spp_istat.nonucn, "connection", " dropped due to no new sockets "); + ANY(spp_istat.gonawy, "connection", " terminated due to our end dying"); + ANY(spp_istat.nonucn, "connection", + " dropped due to inability to connect"); + ANY(spp_istat.noconn, "connection", + " dropped due to inability to connect"); + ANY(spp_istat.notme, "connection", + " incompleted due to mismatched id's"); + ANY(spp_istat.wrncon, "connection", " dropped due to mismatched id's"); + ANY(spp_istat.bdreas, "packet", " dropped out of sequence"); + ANY(spp_istat.lstdup, "packet", " duplicating the highest packet"); + ANY(spp_istat.notyet, "packet", " refused as exceeding allocation"); + ANY(sppstat.spps_connattempt, "connection", " initiated"); + ANY(sppstat.spps_accepts, "connection", " accepted"); + ANY(sppstat.spps_connects, "connection", " established"); + ANY(sppstat.spps_drops, "connection", " dropped"); + ANY(sppstat.spps_conndrops, "embryonic connection", " dropped"); + ANY(sppstat.spps_closed, "connection", " closed (includes drops)"); + ANY(sppstat.spps_segstimed, "packet", " where we tried to get rtt"); + ANY(sppstat.spps_rttupdated, "time", " we got rtt"); + ANY(sppstat.spps_delack, "delayed ack", " sent"); + ANY(sppstat.spps_timeoutdrop, "connection", " dropped in rxmt timeout"); + ANY(sppstat.spps_rexmttimeo, "retransmit timeout", ""); + ANY(sppstat.spps_persisttimeo, "persist timeout", ""); + ANY(sppstat.spps_keeptimeo, "keepalive timeout", ""); + ANY(sppstat.spps_keepprobe, "keepalive probe", " sent"); + ANY(sppstat.spps_keepdrops, "connection", " dropped in keepalive"); + ANY(sppstat.spps_sndtotal, "total packet", " sent"); + ANY(sppstat.spps_sndpack, "data packet", " sent"); + ANY(sppstat.spps_sndbyte, "data byte", " sent"); + ANY(sppstat.spps_sndrexmitpack, "data packet", " retransmitted"); + ANY(sppstat.spps_sndrexmitbyte, "data byte", " retransmitted"); + ANY(sppstat.spps_sndacks, "ack-only packet", " sent"); + ANY(sppstat.spps_sndprobe, "window probe", " sent"); + ANY(sppstat.spps_sndurg, "packet", " sent with URG only"); + ANY(sppstat.spps_sndwinup, "window update-only packet", " sent"); + ANY(sppstat.spps_sndctrl, "control (SYN|FIN|RST) packet", " sent"); + ANY(sppstat.spps_sndvoid, "request", " to send a non-existant packet"); + ANY(sppstat.spps_rcvtotal, "total packet", " received"); + ANY(sppstat.spps_rcvpack, "packet", " received in sequence"); + ANY(sppstat.spps_rcvbyte, "byte", " received in sequence"); + ANY(sppstat.spps_rcvbadsum, "packet", " received with ccksum errs"); + ANY(sppstat.spps_rcvbadoff, "packet", " received with bad offset"); + ANY(sppstat.spps_rcvshort, "packet", " received too short"); + ANY(sppstat.spps_rcvduppack, "duplicate-only packet", " received"); + ANY(sppstat.spps_rcvdupbyte, "duplicate-only byte", " received"); + ANY(sppstat.spps_rcvpartduppack, "packet", " with some duplicate data"); + ANY(sppstat.spps_rcvpartdupbyte, "dup. byte", " in part-dup. packet"); + ANY(sppstat.spps_rcvoopack, "out-of-order packet", " received"); + ANY(sppstat.spps_rcvoobyte, "out-of-order byte", " received"); + ANY(sppstat.spps_rcvpackafterwin, "packet", " with data after window"); + ANY(sppstat.spps_rcvbyteafterwin, "byte", " rcvd after window"); + ANY(sppstat.spps_rcvafterclose, "packet", " rcvd after 'close'"); + ANY(sppstat.spps_rcvwinprobe, "rcvd window probe packet", ""); + ANY(sppstat.spps_rcvdupack, "rcvd duplicate ack", ""); + ANY(sppstat.spps_rcvacktoomuch, "rcvd ack", " for unsent data"); + ANY(sppstat.spps_rcvackpack, "rcvd ack packet", ""); + ANY(sppstat.spps_rcvackbyte, "byte", " acked by rcvd acks"); + ANY(sppstat.spps_rcvwinupd, "rcvd window update packet", ""); +} +#undef ANY +#define ANY(x,y,z) ((x) ? printf("\t%d %s%s%s\n",x,y,plural(x),z) : 0) + +/* + * Dump IDP statistics structure. + */ +void +idp_stats(off, name) + u_long off; + char *name; +{ + struct idpstat idpstat; + + if (off == 0) + return; + kread(off, (char *)&idpstat, sizeof (idpstat)); + printf("%s:\n", name); + ANY(idpstat.idps_toosmall, "packet", " smaller than a header"); + ANY(idpstat.idps_tooshort, "packet", " smaller than advertised"); + ANY(idpstat.idps_badsum, "packet", " with bad checksums"); +} + +static struct { + u_short code; + char *name; + char *where; +} ns_errnames[] = { + {0, "Unspecified Error", " at Destination"}, + {1, "Bad Checksum", " at Destination"}, + {2, "No Listener", " at Socket"}, + {3, "Packet", " Refused due to lack of space at Destination"}, + {01000, "Unspecified Error", " while gatewayed"}, + {01001, "Bad Checksum", " while gatewayed"}, + {01002, "Packet", " forwarded too many times"}, + {01003, "Packet", " too large to be forwarded"}, + {-1, 0, 0}, +}; + +/* + * Dump NS Error statistics structure. + */ +/*ARGSUSED*/ +void +nserr_stats(off, name) + u_long off; + char *name; +{ + struct ns_errstat ns_errstat; + register int j; + register int histoprint = 1; + int z; + + if (off == 0) + return; + kread(off, (char *)&ns_errstat, sizeof (ns_errstat)); + printf("NS error statistics:\n"); + ANY(ns_errstat.ns_es_error, "call", " to ns_error"); + ANY(ns_errstat.ns_es_oldshort, "error", + " ignored due to insufficient addressing"); + ANY(ns_errstat.ns_es_oldns_err, "error request", + " in response to error packets"); + ANY(ns_errstat.ns_es_tooshort, "error packet", + " received incomplete"); + ANY(ns_errstat.ns_es_badcode, "error packet", + " received of unknown type"); + for(j = 0; j < NS_ERR_MAX; j ++) { + z = ns_errstat.ns_es_outhist[j]; + if (z && histoprint) { + printf("Output Error Histogram:\n"); + histoprint = 0; + } + ns_erputil(z, ns_errstat.ns_es_codes[j]); + + } + histoprint = 1; + for(j = 0; j < NS_ERR_MAX; j ++) { + z = ns_errstat.ns_es_inhist[j]; + if (z && histoprint) { + printf("Input Error Histogram:\n"); + histoprint = 0; + } + ns_erputil(z, ns_errstat.ns_es_codes[j]); + } +} + +static void +ns_erputil(z, c) + int z, c; +{ + int j; + char codebuf[30]; + char *name, *where; + + for(j = 0;; j ++) { + if ((name = ns_errnames[j].name) == 0) + break; + if (ns_errnames[j].code == c) + break; + } + if (name == 0) { + if (c > 01000) + where = "in transit"; + else + where = "at destination"; + sprintf(codebuf, "Unknown XNS error code 0%o", c); + name = codebuf; + } else + where = ns_errnames[j].where; + ANY(z, name, where); +} + +static struct sockaddr_ns ssns = {AF_NS}; + +static +char *ns_prpr(x) + struct ns_addr *x; +{ + struct sockaddr_ns *sns = &ssns; + + sns->sns_addr = *x; + return(ns_print((struct sockaddr *)sns)); +} diff --git a/usr.bin/netstat/route.c b/usr.bin/netstat/route.c new file mode 100644 index 00000000000..fe8555aa5d7 --- /dev/null +++ b/usr.bin/netstat/route.c @@ -0,0 +1,676 @@ +/* $NetBSD: route.c,v 1.14 1995/10/03 21:42:47 thorpej 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. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "from: @(#)route.c 8.3 (Berkeley) 3/9/94"; +#else +static char *rcsid = "$NetBSD: route.c,v 1.14 1995/10/03 21:42:47 thorpej Exp $"; +#endif +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/mbuf.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_types.h> +#define _KERNEL +#include <net/route.h> +#undef _KERNEL +#include <netinet/in.h> + +#include <netns/ns.h> + +#include <sys/sysctl.h> + +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "netstat.h" + +#define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d))) + +/* + * Definitions for showing gateway flags. + */ +struct bits { + short b_mask; + char b_val; +} bits[] = { + { RTF_UP, 'U' }, + { RTF_GATEWAY, 'G' }, + { RTF_HOST, 'H' }, + { RTF_REJECT, 'R' }, + { RTF_DYNAMIC, 'D' }, + { RTF_MODIFIED, 'M' }, + { RTF_DONE, 'd' }, /* Completed -- for routing messages only */ + { RTF_MASK, 'm' }, /* Mask Present -- for routing messages only */ + { RTF_CLONING, 'C' }, + { RTF_XRESOLVE, 'X' }, + { RTF_LLINFO, 'L' }, + { RTF_STATIC, 'S' }, + { RTF_PROTO1, '1' }, + { RTF_PROTO2, '2' }, + { 0 } +}; + +static union { + struct sockaddr u_sa; + u_short u_data[128]; +} pt_u; + +int do_rtent = 0; +struct rtentry rtentry; +struct radix_node rnode; +struct radix_mask rmask; + +int NewTree = 0; + +static struct sockaddr *kgetsa __P((struct sockaddr *)); +static void p_tree __P((struct radix_node *)); +static void p_rtnode __P(()); +static void ntreestuff __P(()); +static void np_rtentry __P((struct rt_msghdr *)); +static void p_sockaddr __P((struct sockaddr *, int, int)); +static void p_flags __P((int, char *)); +static void p_rtentry __P((struct rtentry *)); + +/* + * Print routing tables. + */ +void +routepr(rtree) + u_long rtree; +{ + struct radix_node_head *rnh, head; + int i; + + printf("Routing tables\n"); + + if (Aflag == 0 && NewTree) + ntreestuff(); + else { + if (rtree == 0) { + printf("rt_tables: symbol not in namelist\n"); + return; + } + + kget(rtree, rt_tables); + for (i = 0; i <= AF_MAX; i++) { + if ((rnh = rt_tables[i]) == 0) + continue; + kget(rnh, head); + if (i == AF_UNSPEC) { + if (Aflag && af == 0) { + printf("Netmasks:\n"); + p_tree(head.rnh_treetop); + } + } else if (af == AF_UNSPEC || af == i) { + pr_family(i); + do_rtent = 1; + pr_rthdr(); + p_tree(head.rnh_treetop); + } + } + } +} + +/* + * Print address family header before a section of the routing table. + */ +void +pr_family(af) + int af; +{ + char *afname; + + switch (af) { + case AF_INET: + afname = "Internet"; + break; + case AF_NS: + afname = "XNS"; + break; + case AF_ISO: + afname = "ISO"; + break; + case AF_CCITT: + afname = "X.25"; + break; + default: + afname = NULL; + break; + } + if (afname) + printf("\n%s:\n", afname); + else + printf("\nProtocol Family %d:\n", af); +} + +/* column widths; each followed by one space */ +#define WID_DST 16 /* width of destination column */ +#define WID_GW 18 /* width of gateway column */ + +/* + * Print header for routing table columns. + */ +void +pr_rthdr() +{ + + if (Aflag) + printf("%-8.8s ","Address"); + printf("%-*.*s %-*.*s %-6.6s %6.6s%8.8s %6.6s %s\n", + WID_DST, WID_DST, "Destination", + WID_GW, WID_GW, "Gateway", + "Flags", "Refs", "Use", "Mtu", "Interface"); +} + +static struct sockaddr * +kgetsa(dst) + register struct sockaddr *dst; +{ + + kget(dst, pt_u.u_sa); + if (pt_u.u_sa.sa_len > sizeof (pt_u.u_sa)) + kread((u_long)dst, (char *)pt_u.u_data, pt_u.u_sa.sa_len); + return (&pt_u.u_sa); +} + +static void +p_tree(rn) + struct radix_node *rn; +{ + +again: + kget(rn, rnode); + if (rnode.rn_b < 0) { + if (Aflag) + printf("%-8.8x ", rn); + if (rnode.rn_flags & RNF_ROOT) { + if (Aflag) + printf("(root node)%s", + rnode.rn_dupedkey ? " =>\n" : "\n"); + } else if (do_rtent) { + kget(rn, rtentry); + p_rtentry(&rtentry); + if (Aflag) + p_rtnode(); + } else { + p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_key), + 0, 44); + putchar('\n'); + } + if (rn = rnode.rn_dupedkey) + goto again; + } else { + if (Aflag && do_rtent) { + printf("%-8.8x ", rn); + p_rtnode(); + } + rn = rnode.rn_r; + p_tree(rnode.rn_l); + p_tree(rn); + } +} + +char nbuf[20]; + +static void +p_rtnode() +{ + struct radix_mask *rm = rnode.rn_mklist; + + if (rnode.rn_b < 0) { + if (rnode.rn_mask) { + printf("\t mask "); + p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask), + 0, -1); + } else if (rm == 0) + return; + } else { + sprintf(nbuf, "(%d)", rnode.rn_b); + printf("%6.6s %8.8x : %8.8x", nbuf, rnode.rn_l, rnode.rn_r); + } + while (rm) { + kget(rm, rmask); + sprintf(nbuf, " %d refs, ", rmask.rm_refs); + printf(" mk = %8.8x {(%d),%s", + rm, -1 - rmask.rm_b, rmask.rm_refs ? nbuf : " "); + p_sockaddr(kgetsa((struct sockaddr *)rmask.rm_mask), 0, -1); + putchar('}'); + if (rm = rmask.rm_mklist) + printf(" ->"); + } + putchar('\n'); +} + +static void +ntreestuff() +{ + size_t needed; + int mib[6]; + char *buf, *next, *lim; + register struct rt_msghdr *rtm; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = 0; + mib[4] = NET_RT_DUMP; + mib[5] = 0; + if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) + { perror("route-sysctl-estimate"); exit(1);} + if ((buf = malloc(needed)) == 0) + { printf("out of space\n"); exit(1);} + if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) + { perror("sysctl of routing table"); exit(1);} + lim = buf + needed; + for (next = buf; next < lim; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)next; + np_rtentry(rtm); + } +} + +static void +np_rtentry(rtm) + register struct rt_msghdr *rtm; +{ + register struct sockaddr *sa = (struct sockaddr *)(rtm + 1); +#ifdef notdef + static int masks_done, banner_printed; +#endif + static int old_af; + int af = 0, interesting = RTF_UP | RTF_GATEWAY | RTF_HOST; + +#ifdef notdef + /* for the moment, netmasks are skipped over */ + if (!banner_printed) { + printf("Netmasks:\n"); + banner_printed = 1; + } + if (masks_done == 0) { + if (rtm->rtm_addrs != RTA_DST ) { + masks_done = 1; + af = sa->sa_family; + } + } else +#endif + af = sa->sa_family; + if (af != old_af) { + pr_family(af); + old_af = af; + } + if (rtm->rtm_addrs == RTA_DST) + p_sockaddr(sa, 0, 36); + else { + p_sockaddr(sa, 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, 0, 18); + } + p_flags(rtm->rtm_flags & interesting, "%-6.6s "); + putchar('\n'); +} + +static void +p_sockaddr(sa, flags, width) + struct sockaddr *sa; + int flags, width; +{ + char workbuf[128], *cplim; + register char *cp = workbuf; + + switch(sa->sa_family) { + case AF_INET: + { + register struct sockaddr_in *sin = (struct sockaddr_in *)sa; + + cp = (sin->sin_addr.s_addr == 0) ? "default" : + ((flags & RTF_HOST) ? + routename(sin->sin_addr.s_addr) : + netname(sin->sin_addr.s_addr, INADDR_ANY)); + break; + } + + case AF_NS: + cp = ns_print(sa); + break; + + case AF_LINK: + { + register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; + + if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && + sdl->sdl_slen == 0) + (void) sprintf(workbuf, "link#%d", sdl->sdl_index); + else switch (sdl->sdl_type) { + case IFT_ETHER: + { + register int i; + register u_char *lla = (u_char *)sdl->sdl_data + + sdl->sdl_nlen; + + cplim = ""; + for (i = 0; i < sdl->sdl_alen; i++, lla++) { + cp += sprintf(cp, "%s%x", cplim, *lla); + cplim = ":"; + } + cp = workbuf; + break; + } + default: + cp = link_ntoa(sdl); + break; + } + break; + } + + default: + { + register u_char *s = (u_char *)sa->sa_data, *slim; + + slim = sa->sa_len + (u_char *) sa; + cplim = cp + sizeof(workbuf) - 6; + cp += sprintf(cp, "(%d)", sa->sa_family); + while (s < slim && cp < cplim) { + cp += sprintf(cp, " %02x", *s++); + if (s < slim) + cp += sprintf(cp, "%02x", *s++); + } + cp = workbuf; + } + } + if (width < 0 ) + printf("%s ", cp); + else { + if (nflag) + printf("%-*s ", width, cp); + else + printf("%-*.*s ", width, width, cp); + } +} + +static void +p_flags(f, format) + register int f; + char *format; +{ + char name[33], *flags; + register struct bits *p = bits; + + for (flags = name; p->b_mask; p++) + if (p->b_mask & f) + *flags++ = p->b_val; + *flags = '\0'; + printf(format, name); +} + +static void +p_rtentry(rt) + register struct rtentry *rt; +{ + static struct ifnet ifnet, *lastif; + static char name[16]; + + p_sockaddr(kgetsa(rt_key(rt)), rt->rt_flags, WID_DST); + p_sockaddr(kgetsa(rt->rt_gateway), RTF_HOST, WID_GW); + p_flags(rt->rt_flags, "%-6.6s "); + printf("%6d %8d ", rt->rt_refcnt, rt->rt_use); + if (rt->rt_rmx.rmx_mtu) + printf("%6d ", rt->rt_rmx.rmx_mtu); + else + printf("%6s ", "-"); + 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; + } + printf(" %.15s%d%s", name, ifnet.if_unit, + rt->rt_nodes[0].rn_dupedkey ? " =>" : ""); + } + putchar('\n'); +} + +char * +routename(in) + u_int32_t in; +{ + register char *cp; + static char line[MAXHOSTNAMELEN + 1]; + struct hostent *hp; + static char domain[MAXHOSTNAMELEN + 1]; + static int first = 1; + + if (first) { + first = 0; + if (gethostname(domain, MAXHOSTNAMELEN) == 0 && + (cp = index(domain, '.'))) + (void) strcpy(domain, cp + 1); + else + domain[0] = 0; + } + cp = 0; + if (!nflag) { + hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), + AF_INET); + if (hp) { + if ((cp = index(hp->h_name, '.')) && + !strcmp(cp + 1, domain)) + *cp = 0; + cp = hp->h_name; + } + } + if (cp) + strncpy(line, cp, sizeof(line) - 1); + else { +#define C(x) ((x) & 0xff) + in = ntohl(in); + sprintf(line, "%u.%u.%u.%u", + C(in >> 24), C(in >> 16), C(in >> 8), C(in)); + } + return (line); +} + +/* + * Return the name of the network whose address is given. + * The address is assumed to be that of a net or subnet, not a host. + */ +char * +netname(in, mask) + u_int32_t in, mask; +{ + char *cp = 0; + static char line[MAXHOSTNAMELEN + 1]; + struct netent *np = 0; + u_int32_t net; + int subnetshift; + + in = ntohl(in); + mask = ntohl(mask); + if (!nflag && in != INADDR_ANY) { + if (mask == INADDR_ANY) { + if (IN_CLASSA(in)) { + mask = IN_CLASSA_NET; + subnetshift = 8; + } else if (IN_CLASSB(in)) { + mask = IN_CLASSB_NET; + subnetshift = 8; + } else { + mask = IN_CLASSC_NET; + subnetshift = 4; + } + /* + * If there are more bits than the standard mask + * would suggest, subnets must be in use. + * Guess at the subnet mask, assuming reasonable + * width subnet fields. + */ + while (in &~ mask) + mask = (long)mask >> subnetshift; + } + net = in & mask; + while ((mask & 1) == 0) + mask >>= 1, net >>= 1; + np = getnetbyaddr(net, AF_INET); + if (np) + cp = np->n_name; + } + if (cp) + strncpy(line, cp, sizeof(line) - 1); + else if ((in & 0xffffff) == 0) + sprintf(line, "%u", C(in >> 24)); + else if ((in & 0xffff) == 0) + sprintf(line, "%u.%u", C(in >> 24) , C(in >> 16)); + else if ((in & 0xff) == 0) + sprintf(line, "%u.%u.%u", C(in >> 24), C(in >> 16), C(in >> 8)); + else + sprintf(line, "%u.%u.%u.%u", C(in >> 24), + C(in >> 16), C(in >> 8), C(in)); + return (line); +} + +/* + * Print routing statistics + */ +void +rt_stats(off) + u_long off; +{ + struct rtstat rtstat; + + if (off == 0) { + printf("rtstat: symbol not in namelist\n"); + return; + } + kread(off, (char *)&rtstat, sizeof (rtstat)); + printf("routing:\n"); + printf("\t%u bad routing redirect%s\n", + rtstat.rts_badredirect, plural(rtstat.rts_badredirect)); + printf("\t%u dynamically created route%s\n", + rtstat.rts_dynamic, plural(rtstat.rts_dynamic)); + printf("\t%u new gateway%s due to redirects\n", + rtstat.rts_newgateway, plural(rtstat.rts_newgateway)); + printf("\t%u destination%s found unreachable\n", + rtstat.rts_unreach, plural(rtstat.rts_unreach)); + printf("\t%u use%s of a wildcard route\n", + rtstat.rts_wildcard, plural(rtstat.rts_wildcard)); +} +short ns_nullh[] = {0,0,0}; +short ns_bh[] = {-1,-1,-1}; + +char * +ns_print(sa) + register struct sockaddr *sa; +{ + register struct sockaddr_ns *sns = (struct sockaddr_ns*)sa; + struct ns_addr work; + union { union ns_net net_e; u_long long_e; } net; + u_short port; + static char mybuf[50], cport[10], chost[25]; + char *host = ""; + register char *p; register u_char *q; + + work = sns->sns_addr; + port = ntohs(work.x_port); + work.x_port = 0; + net.net_e = work.x_net; + if (ns_nullhost(work) && net.long_e == 0) { + if (port ) { + sprintf(mybuf, "*.%xH", port); + upHex(mybuf); + } else + sprintf(mybuf, "*.*"); + return (mybuf); + } + + if (bcmp(ns_bh, work.x_host.c_host, 6) == 0) { + host = "any"; + } else if (bcmp(ns_nullh, work.x_host.c_host, 6) == 0) { + host = "*"; + } else { + q = work.x_host.c_host; + sprintf(chost, "%02x%02x%02x%02x%02x%02xH", + q[0], q[1], q[2], q[3], q[4], q[5]); + for (p = chost; *p == '0' && p < chost + 12; p++) + continue; + host = p; + } + if (port) + sprintf(cport, ".%xH", htons(port)); + else + *cport = 0; + + sprintf(mybuf,"%xH.%s%s", ntohl(net.long_e), host, cport); + upHex(mybuf); + return(mybuf); +} + +char * +ns_phost(sa) + struct sockaddr *sa; +{ + register struct sockaddr_ns *sns = (struct sockaddr_ns *)sa; + struct sockaddr_ns work; + static union ns_net ns_zeronet; + char *p; + + work = *sns; + work.sns_addr.x_port = 0; + work.sns_addr.x_net = ns_zeronet; + + p = ns_print((struct sockaddr *)&work); + if (strncmp("0H.", p, 3) == 0) p += 3; + return(p); +} + +void +upHex(p0) + char *p0; +{ + register char *p = p0; + for (; *p; p++) switch (*p) { + + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + *p += ('A' - 'a'); + } +} diff --git a/usr.bin/netstat/unix.c b/usr.bin/netstat/unix.c new file mode 100644 index 00000000000..6b6388b5b4e --- /dev/null +++ b/usr.bin/netstat/unix.c @@ -0,0 +1,140 @@ +/* $NetBSD: unix.c,v 1.13 1995/10/03 21:42:48 thorpej 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. + */ + +#ifndef lint +#if 0 +static char sccsid[] = "from: @(#)unix.c 8.1 (Berkeley) 6/6/93"; +#else +static char *rcsid = "$NetBSD: unix.c,v 1.13 1995/10/03 21:42:48 thorpej Exp $"; +#endif +#endif /* not lint */ + +/* + * Display protocol blocks in the unix domain. + */ +#include <sys/param.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/mbuf.h> +#include <sys/sysctl.h> +#include <sys/un.h> +#include <sys/unpcb.h> +#define _KERNEL +struct uio; +struct proc; +#include <sys/file.h> + +#include <netinet/in.h> + +#include <stdio.h> +#include <stdlib.h> +#include <kvm.h> +#include "netstat.h" + +static void unixdomainpr __P((struct socket *, caddr_t)); + +static struct file *file, *fileNFILE; +static int nfiles; +extern kvm_t *kvmd; + +void +unixpr(off) + u_long off; +{ + register struct file *fp; + struct socket sock, *so = &sock; + char *filebuf; + struct protosw *unixsw = (struct protosw *)off; + + filebuf = (char *)kvm_getfiles(kvmd, KERN_FILE, 0, &nfiles); + if (filebuf == 0) { + printf("Out of memory (file table).\n"); + return; + } + file = (struct file *)(filebuf + sizeof(fp)); + fileNFILE = file + nfiles; + for (fp = file; fp < fileNFILE; fp++) { + if (fp->f_count == 0 || fp->f_type != DTYPE_SOCKET) + continue; + if (kread((u_long)fp->f_data, (char *)so, sizeof (*so))) + continue; + /* kludge */ + if (so->so_proto >= unixsw && so->so_proto <= unixsw + 2) + if (so->so_pcb) + unixdomainpr(so, fp->f_data); + } +} + +static char *socktype[] = + { "#0", "stream", "dgram", "raw", "rdm", "seqpacket" }; + +static void +unixdomainpr(so, soaddr) + register struct socket *so; + caddr_t soaddr; +{ + struct unpcb unpcb, *unp = &unpcb; + struct mbuf mbuf, *m; + struct sockaddr_un *sa; + static int first = 1; + + if (kread((u_long)so->so_pcb, (char *)unp, sizeof (*unp))) + return; + if (unp->unp_addr) { + m = &mbuf; + if (kread((u_long)unp->unp_addr, (char *)m, sizeof (*m))) + m = (struct mbuf *)0; + sa = (struct sockaddr_un *)(m->m_dat); + } else + m = (struct mbuf *)0; + if (first) { + printf("Active UNIX domain sockets\n"); + printf( +"%-8.8s %-6.6s %-6.6s %-6.6s %8.8s %8.8s %8.8s %8.8s Addr\n", + "Address", "Type", "Recv-Q", "Send-Q", + "Inode", "Conn", "Refs", "Nextref"); + first = 0; + } + printf("%8x %-6.6s %6d %6d %8x %8x %8x %8x", + soaddr, socktype[so->so_type], so->so_rcv.sb_cc, so->so_snd.sb_cc, + unp->unp_vnode, unp->unp_conn, + unp->unp_refs, unp->unp_nextref); + if (m) + printf(" %.*s", + m->m_len - (int)(sizeof(*sa) - sizeof(sa->sun_path)), + sa->sun_path); + putchar('\n'); +} |