V10/ipc/internet/netstat.c

Compare this file to the similar file:
Show the results in this format:

#include <values.h>
#include <stdio.h>
#include <sys/param.h>
#include <sys/stream.h>
#include <sys/inet/in.h>
#define KERNEL	1	/* get kernel definitions */
#include <sys/inet/tcp.h>
#include <sys/inet/udp.h>
#include <sys/inet/ip_var.h>
#include <sys/inet/tcp_timer.h>
#define TCPSTATES 1
#include <sys/inet/tcp_fsm.h>
#include <sys/inet/tcp_var.h>
#include <sys/inet/tcpip.h>
#include <sys/inet/tcpdebug.h>
#include <sys/ethernet.h>
#include <sys/inet/udp_var.h>

static int strip = 0; /* true if we're stripping the high bit from kernel addrs */
static int numeric = 0;

/* predeclared */
doseek();
void doseekoff();
void doread();
char *inettoascii();

main(argc, argv)
char *argv[];
{
	char *xinu, *kmem;
	int c;
	int action;
	char *operand;
	extern char *optarg;
	extern int optind;

	xinu = "/unix";
	kmem = "/dev/kmem";

	action = 'c';
	while((c = getopt(argc, argv, "CRacinrst:")) != -1) {
		switch(c){
		case 'C':
		case 'R':
		case 'a':
		case 'c':
		case 'i':
		case 'r':
		case 's':
			action = c;
			break;
		case 'n':
			numeric = 1;
			break;
		case 't':
			action = c;
			operand = optarg;
			break;
		default:
			fprintf(stderr, "Usage: %s -CRacinrst [unix [vmcore]]\n", argv[0]);
			break;
		}
	}
	if (argc > optind+1)
		xinu = argv[optind++];
	if (argc > optind)
		kmem = argv[optind];
	kern_init(xinu, kmem);

	switch(action) {
	case '\0':
	case 'c':
		tcps(0);
		udps();
		break;
	case 'n':
		numeric = 1;
		break;
	case 'i':
		interfaces();
		break;
	case 's':
		statistics();
		break;
	case 'r':
		routes(0);
		break;
	case 'R':
		routes(1);
		break;
	case 'a':
		arps();
		break;
	case 'C':
		tcps(1);
		break;
	case 't':
		if (*operand == '\0' || strcmp(operand, "tcp")==0)
			debugtcp();
		else if (strcmp(operand, "il")==0)
			debugil();
		else if (strcmp(operand, "qe")==0)
			debugqe();
		break;
	default:
		fprintf(stderr, "Usage: %s -icCrat [unix [vmcore]]\n", argv[0]);
		break;
	}
}

/*
 *  truncate name to rightmost n chars
 */
trunc(name, n)
	char *name;
	int n;
{
	register int i=strlen(name);

	return ((i<=n) ? name : name+(i-n));
}


#include "nlist.h"
struct nlist nl[] = {
	{"_ipif", 0},
#define NL_INET 0
	{"_ipstat", 0},
#define NL_IPSTAT 1
	{"_tcpstat", 0},
#define NL_TCPSTAT 2
	{"_tcpcnt", 0},
#define NL_NTCP 3
	{"_tcpcb", 0},
#define NL_TCP 4
	{"_ip_routes", 0},
#define NL_ROUTE 5
	{"_ip_arps", 0},
#define NL_ARP 6
	{"_ipcnt", 0},
#define NL_NINET 7
	{"_Nip_route", 0},
#define NL_NROUTE 8
	{"_arpcnt", 0},
#define NL_NARP 9
	{"_ip_default_route", 0},
#define NL_DR 10
	{"_bugarr", 0},
#define NL_TCPDEB 11
	{"_Nbugarr", 0},
#define NL_NBUGARR 12
	{"_udpcnt", 0},
#define NL_NUDP 13
	{"_udpconn", 0},
#define NL_UDP 14
	{"_ild", 0},
#define NL_ILDEB 15
	{"_qed", 0},
#define NL_QEDEB 16
	{"_udpstat", 0},
#define NL_UDPSTAT 17
	{0, 0}
};
int kern_fd;

kern_init(xinu, kmem)
char *xinu, *kmem;
{
	int i;
	nlist(xinu, nl);
	if((long)nl[0].n_value == 0){
		fprintf(stderr, "nlist %s failed\n", xinu);
		exit(1);
	}
	if(strcmp(kmem, "/dev/kmem") != 0){
		for(i = 0; nl[i].n_name; i++){
			nl[i].n_value &= 0xffffff;
		}
		strip = 1;
	}
	kern_fd = open(kmem, 0);
	if(kern_fd < 0){
		perror(kmem);
		exit(1);
	}
}

interfaces()
{
	extern char *xflags();
	struct ipif ipif[128];
	int i, ninet;

	if (doseek(NL_NINET) < 0) {
		printf("Internet not compiled into this kernel\n");
		return;
	}
	doread((char *)&ninet, sizeof ninet);
	if (ninet > (sizeof(ipif)/sizeof(struct ipif)))
		ninet = sizeof(ipif)/sizeof(struct ipif);
	printf("%-4s %-24s %-15s  %5s %6s %6s %6s %6s\n",
		"Mtu", "Network&Mask", "Address", "Flags",
		"Ipkts", "Ierrs", "Opkts", "Oerrs");
	doseek(NL_INET);
	doread((char *)ipif, ninet*sizeof(struct ipif));
	for(i = 0; i < ninet; i++){
		if((ipif[i].flags&IFF_UP) == 0)
			continue;
		printf("%-4d %-15.15s&%x ", ipif[i].mtu, inettoascii(ipif[i].that), ipif[i].mask);
		printf("%-15.15s  %5s %6d %6d %6d %6d\n",
			inettoascii(ipif[i].thishost),
			xflags(ipif[i].flags, "UHA?", "   "),
			ipif[i].ipackets, ipif[i].ierrors,
			ipif[i].opackets, ipif[i].oerrors);
	}
}


statistics()
{
	struct ipstat stats;
	struct tcpstat tcpstat;

	if (doseek(NL_IPSTAT) < 0) {
		printf("Internet not compiled into this kernel\n");
		return;
	}
	doread((char *)&stats, sizeof(stats));
	printf("IP:\n");
	printf("%6d bad sums\n", stats.ips_badsum);
	printf("%6d short packets\n", stats.ips_tooshort);
	printf("%6d short data\n", stats.ips_toosmall);
	printf("%6d bad header lengths\n", stats.ips_badhlen);
	printf("%6d real bad header lengths\n", stats.ips_badlen);
	printf("%6d queue overflows\n", stats.ips_qfull);
	printf("%6d output routing errors\n", stats.ips_route);
	printf("%6d fragmented packets\n", stats.ips_fragout);
	if (doseek(NL_TCPSTAT) < 0) {
		printf("Tcp not compiled into this kernel\n");
		return;
	}
	doread((char *)&tcpstat, sizeof(tcpstat));
	printf("TCP:\n");
	printf("%6d bad sums\n", tcpstat.tcps_badsum);
	printf("%6d bad offsets\n", tcpstat.tcps_badoff);
	printf("%6d header drops\n", tcpstat.tcps_hdrops);
	printf("%6d bad segments\n", tcpstat.tcps_badsegs);
	printf("%6d retransmit timeouts\n", tcpstat.tcps_timeouts[0]);
	printf("%6d persist timeouts\n", tcpstat.tcps_timeouts[1]);
	printf("%6d keep-alive timeouts\n", tcpstat.tcps_timeouts[2]);
	printf("%6d quiet time timeouts\n", tcpstat.tcps_timeouts[3]);
	printf("%6d duplicate packets received\n", tcpstat.tcps_duplicates);
	printf("%6d possibly late packets received\n", tcpstat.tcps_delayed);
	if (doseek(NL_UDPSTAT) < 0) {
		printf("Udp not compiled into this kernel\n");
		return;
	}
	doread((char *)&udpstat, sizeof(udpstat));
	printf("UDP:\n");
	printf("%6d bad sums\n", udpstat.udps_badsum);
	printf("%6d bad length\n", udpstat.udps_badlen);
	printf("%6d bad port\n", udpstat.udps_badport);
	printf("%6d q overflows\n", udpstat.udps_inqfull);
	printf("%6d input packets\n", udpstat.udps_ipackets);
}

tcps(flag)
{
	int i, ntcp;
	struct tcpcb tcpcb;
	extern char *xflags();
	char b1[100], b2[100];
	struct in_service *sp;

	if (doseek(NL_NTCP) < 0) {
		printf("Tcp not compiled into this kernel\n");
		return;
	}
	doread((char *)&ntcp, sizeof ntcp);
	printf("Dev   Wque Rque State %-22s %-22s %11s\n",
		"Remote Addr", "Local Addr", "Cstate");
	for(i = 0; i < ntcp; i++){
		doseekoff(NL_TCP, sizeof(tcpcb)*i);
		doread((char *)&tcpcb, sizeof(tcpcb));
		if(tcpcb.t_state == TCPS_CLOSED)
			continue;
		sp = in_service(0, "tcp", tcpcb.so_fport);
		sprintf(b1, "%.17s-%s", inettoascii(tcpcb.so_faddr), sp->name);
		sp = in_service(0, "tcp", tcpcb.so_lport);
		sprintf(b2, "%.17s-%s", inettoascii(tcpcb.so_laddr), sp->name);
		if(!flag || tcpcb.t_state != TCPS_LISTEN)
		printf("tcp%02d %4d %4d %5s %-22.22s %-22.22s %11s\n",
			tcpcb.so_dev,
			tcpcb.so_wcount, tcpcb.so_rcount,
			xflags(tcpcb.so_state, "OPRWAHU?", "        "),
			b1, b2,
			tcpstates[tcpcb.t_state]);
#ifdef ALL
		if(!flag || tcpcb.t_state != TCPS_LISTEN)
			printf("template %x\n", tcpcb.t_template);
#endif
		if(flag && tcpcb.t_state != TCPS_LISTEN){
			printf("  Timers:\n");
			printf("\tretransmit %d\n\tpersist %d\n\tkeepalive %d\n\t2msl %d\n",
				tcpcb.t_timer[0], tcpcb.t_timer[1],
				tcpcb.t_timer[2], tcpcb.t_timer[3]);
			printf("  Send sequence variables:");
			printf("\n\tunacked %d\n\tnext %d\n\turgent ptr %d",
				tcpcb.snd_una, tcpcb.snd_nxt, tcpcb.snd_up);
			printf("\n\tinitial number %d\n\twindow %d\n\thighest sent %d\n",
				tcpcb.iss, tcpcb.snd_wnd, tcpcb.snd_max);
			printf("  Receive sequence variables:");
			printf("\n\tnext %d\n\turgent ptr %d",
				tcpcb.rcv_nxt, tcpcb.rcv_up);
			printf("\n\tinitial number %d\n\twindow %d\n\tadvertised %d\n",
				tcpcb.irs, tcpcb.rcv_wnd, tcpcb.rcv_adv);
			printf("  Transmit timing:");
			printf("\n\tinactive %d\n\tround trip %d\n\tseq # timed %d\n\tsmoothed round trip %f\n",
				tcpcb.t_idle, tcpcb.t_rtt, tcpcb.t_rtseq,
				tcpcb.t_srtt);
			printf("  Status:");
			printf("\n\tmax segment size %d", tcpcb.t_maxseg);
			printf("\n\tforcing out byte %d", tcpcb.t_force);
			printf("\n\tflags 0x%x\n", tcpcb.t_flags);
			printf("\n");
		}
	}
}

udps()
{
	int i, nudp;
	struct udp udp[132];
	extern char *xflags();
	char b1[100], b2[100];
	struct in_service *sp;

	if (doseek(NL_NUDP) < 0) {
		printf("Udp not compiled into this kernel\n");
		return;
	}
	doread((char *)&nudp, sizeof nudp);
	printf("\nDev   State %-30s %-30s\n",
		"Remote Addr", "Local Addr");
	doseek(NL_UDP);
	doread((char *)udp, nudp*sizeof(struct udp));
	for (i = 0; i < nudp; i++) {
		if(udp[i].rq == 0)
			continue;
		sp = in_service(0, "udp", udp[i].sport);
		sprintf(b1, "%s-%.6s", inettoascii(udp[i].src), sp->name);
		sp = in_service(0, "udp", udp[i].dport);
		sprintf(b2, "%s-%.6s", inettoascii(udp[i].dst), sp->name);
		printf("udp%02d %5s %-30.30s %-30.30s\n",
			i, xflags(udp[i].flags, "ILC?", "      "),
			b2, b1);
	}
}

char *
xflags(fl, fs, buf)
char *fs, *buf;
{
	int i, len;
	char *os;

	os = buf;
	len = strlen(fs);
	for(i = 0; i < len; i++){
		if(fl & (1<<i))
			*buf++ = fs[i];
	}
	*buf++ = '\0';
	return(os);
}

routes(all)
	int all;
{
	struct ip_route r[256];
	int i;
	int nroute;

	doseek(NL_DR);
	doread((char *)r, sizeof(struct ip_route));
	if (r[0].gate != 0)
		printf("Default route is %s\n\n", inettoascii(r[0].gate));
	doseek(NL_NROUTE);
	doread((char *)&nroute, sizeof nroute);
	if (nroute > (sizeof(r)/sizeof(struct ip_route)))
		nroute = sizeof(r)/sizeof(struct ip_route);
	doseek(NL_ROUTE);
	doread((char *)r, nroute*sizeof(struct ip_route));
	printf("%-14s %-14s\n", "Destination", "Gateway");
	for(i = 0; i < nroute; i++){
		if(all || r[i].dst!=r[i].gate){
			printf("%-14s ", inettoascii(r[i].dst));
			printf("%-14s\n", inettoascii(r[i].gate));
		}
	}
}

arps()
{
	struct ip_arp a[256];
	int i, j, narp;

	if (doseek(NL_NARP) < 0) {
		printf("Arp not compiled into this kernel\n");
		return;
	}
	doread((char *)&narp, sizeof narp);
	if (narp > (sizeof(a)/sizeof(struct ip_arp)))
		narp = sizeof(a)/sizeof(struct ip_arp);
	doseek(NL_ARP);
	doread((char *)a, narp*sizeof(struct ip_arp));
	printf("%-11s Ether-Address\n", "Host");
	for(i = 0; i < narp; i++){
		if(a[i].inaddr){
			printf("%-11s ", inettoascii(a[i].inaddr));
			for(j = 0; j < 6; j++){
				printf("%02x ", a[i].enaddr[j]);
			}
			printf("\n");
		}
	}
}

#define NEXT(i) ((i+1)%SIZDEBUG)
#define PREV(i) ((i+SIZDEBUG-1)%SIZDEBUG)
#define HEADER\
"\ntime   src           dst                seq bytes      ack wind cksm      urg flags\n"
#define FORMAT "%4d %c %8x.%-4d %8x.%-4d %8x   %3x %8x %4x %04x %8x %s\n"

debugtcp()
{
	struct tcpdebug d[SIZDEBUG];
	int i, lowi;
	unsigned long low, high;
	unsigned long lastlow = 0, lasthigh = 0;
	time_t t, lastt = 0;
	time_t base = 0;
	int line = 0;
	char *xflags();
	char xbuf[9];

	for(;;) {
		/* get array */
		if (doseek(NL_TCPDEB) < 0) {
			printf("Tcp debugging not compiled into this kernel\n");
			return;
		}
		doread((char *)d, sizeof(d));

		/* find lowest sequence entry */
		lowi = 0;
		low = d[0].seq;
		for (i = 1; i < SIZDEBUG; i++) {
			if (d[i].seq < low) {
				lowi = i;
				low = d[i].seq;
			}
		}
		if(low > lasthigh+1)
			printf("** missing messages **\n");

		if (base == 0)
			base = d[lowi].stamp;

		/* print all new entries */
		i = lowi;
		high = low;
		for(;;) {
			if(d[i].seq < lastlow || d[i].seq > lasthigh){
				if ((line++ % 22) == 0)
					printf(HEADER);
				printf(FORMAT, d[i].stamp-base,
					d[i].inout ? 'o' : 'i',
					ntohl(d[i].hdr.ti_src),
					ntohs(d[i].hdr.ti_sport),
					ntohl(d[i].hdr.ti_dst),
					ntohs(d[i].hdr.ti_dport),
					ntohl(d[i].hdr.ti_seq), 
					ntohs(d[i].hdr.ti_len) - sizeof(struct tcphdr),
					ntohl(d[i].hdr.ti_ack),
					ntohs(d[i].hdr.ti_win),
					ntohs(d[i].hdr.ti_sum),
					ntohs(d[i].hdr.ti_urp),
					xflags(d[i].hdr.ti_flags&0xff, "FSRPAU??",
						xbuf)
				);
			}
			if(d[i].seq > high)
				high = d[i].seq;
			i = NEXT(i);
			if(i==lowi)
				break;
		}
		lasthigh = high;
		lastlow = low;
		fflush(stdout);
		sleep(1);
	}
}

#define	QENRCV	30
#define QEDEBSIZE 64
#define QENEXT(i) ((i+1)%QEDEBSIZE)
#define QEPREV(i) ((i+QEDEBSIZE-1)%QEDEBSIZE)
#define QEHEADER\
"\n   time            src          dst type  sizes\n"
#define QEFORMAT "%7d %c %02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x %4x %x\n"

#define ILDEBSIZE 64
#define ILNEXT(i) ((i+1)%ILDEBSIZE)
#define ILPREV(i) ((i+ILDEBSIZE-1)%ILDEBSIZE)
#define ILHEADER\
"\n   time            src          dst     type\n"
#define ILFORMAT "%7d %c %02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x %4x\n"

debugil()
{
	struct {
		time_t	time;
		unsigned short code;
		struct etherpup pup;
		short len;
	} d[ILDEBSIZE];
	int i, lasti= 0;
	time_t t, lastt = 0;
	time_t base = 0;
	int line = 0;
	char *xflags();
	char xbuf[9];

	for(;;) {
		/* get array */
		if (doseek(NL_ILDEB) < 0) {
			printf("Interlan debugging not compiled into this kernel\n");
			return;
		}
		doread((char *)d, sizeof(d));

		/* see if we've overflowed the buffer (or first time around) */
		if (d[lasti].time != lastt) {
			if (lastt != 0)
				printf("** missing messages **\n");
			/* find last(highest) timestamped entry */
			for (i = ILNEXT(lasti); i != lasti; i = ILNEXT(i)) {
				if (d[i].time < lastt) {
					if (base == 0 || d[i].time < base)
						base = d[i].time;
					lasti = ILPREV(i);
					lastt = 0; /* for start of next loop */
					break;
				}
				lastt = d[i].time;
			}
		}

		/* print all new entries */
		for (i = ILNEXT(lasti); i != lasti; i = ILNEXT(i)) {
			if (d[i].time < lastt)
				break;
			if (d[i].time == 0)
				continue;
			if ((line++ % 22) == 0)
				printf(ILHEADER);
			if(d[i].code) {
				printf(ILFORMAT, d[i].time-base, 'o',
					 0, 0,
					 0, 0,
					 0, 0,
					 d[i].pup.dhost[0], d[i].pup.dhost[1],
					 d[i].pup.dhost[2], d[i].pup.dhost[3],
					 d[i].pup.dhost[4], d[i].pup.dhost[5],
					 (d[i].pup.shost[1]<<8) | d[i].pup.shost[0]
				);
			} else {
				printf(ILFORMAT, d[i].time-base, 'i',
					 d[i].pup.shost[0], d[i].pup.shost[1],
					 d[i].pup.shost[2], d[i].pup.shost[3],
					 d[i].pup.shost[4], d[i].pup.shost[5],
					 d[i].pup.dhost[0], d[i].pup.dhost[1],
					 d[i].pup.dhost[2], d[i].pup.dhost[3],
					 d[i].pup.dhost[4], d[i].pup.dhost[5],
					 d[i].pup.type
				);
			}
			lastt = d[i].time;
			lasti = i;
		}
		fflush(stdout);
		sleep(1);
	}
}

debugqe()
{
	struct {
		time_t	time;
		unsigned short code;
		struct etherpup pup;
		short len;
	} d[QEDEBSIZE];
	int i, j, lasti= 0;
	time_t t, lastt = 0;
	time_t base = 0;
	int line = 0;
	char *xflags();
	char xbuf[9];

	for(;;) {
		/* get array */
		if (doseek(NL_QEDEB) < 0) {
			printf("deqna/delqa debugging not compiled into this kernel\n");
			return;
		}
		doread((char *)d, sizeof(d));

		/* see if we've overflowed the buffer (or first time around) */
		if (d[lasti].time != lastt) {
			if (lastt != 0)
				printf("** missing messages **\n");
			/* find last(highest) timestamped entry */
			for (i = QENEXT(lasti); i != lasti; i = QENEXT(i)) {
				if (base == 0 || d[i].time < base)
					base = d[i].time;
				if (d[i].time < lastt) {
					lasti = QEPREV(i);
					lastt = 0; /* for start of next loop */
					break;
				}
				lastt = d[i].time;
			}
		}

		/* print all new entries */
		for (i = QENEXT(lasti); i != lasti; i = QENEXT(i)) {
			if (d[i].time < lastt)
				break;
			if (d[i].time == 0)
				continue;
			if ((line++ % 22) == 0)
				printf(QEHEADER);
			printf(QEFORMAT, d[i].time-base, d[i].code?'o':'i',
				 d[i].pup.shost[0], d[i].pup.shost[1],
				 d[i].pup.shost[2], d[i].pup.shost[3],
				 d[i].pup.shost[4], d[i].pup.shost[5],
				 d[i].pup.dhost[0], d[i].pup.dhost[1],
				 d[i].pup.dhost[2], d[i].pup.dhost[3],
				 d[i].pup.dhost[4], d[i].pup.dhost[5],
				 d[i].pup.type, d[i].len
			);
			lastt = d[i].time;
			lasti = i;
		}
		fflush(stdout);
		sleep(1);
	}
}

doseek(nlitem)
	unsigned int nlitem;
{
	if (nl[nlitem].n_value == 0)
		return -1;
	if(lseek(kern_fd, (long)nl[nlitem].n_value, 0) == -1){
		perror("seek");
		exit(1);
	}
	return 0;
}

void
doseekoff(nlitem, offset)
	unsigned int nlitem;
	unsigned int offset;
{
	if(lseek(kern_fd, (long)(nl[nlitem].n_value+offset), 0) == -1){
		perror("seek");
		exit(1);
	}
}

void
doread(addr, size)
	char *addr;
	unsigned int size;
{
	if(read(kern_fd, addr, size) < 0){
		perror("read");
		exit(1);
	}
}

char *
inettoascii(inaddr)
	long inaddr;
{
	return numeric ? in_ntoa(inaddr) : in_host(inaddr);
}