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