netstat.c revision 74671
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 1980, 1992, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 3. All advertising materials mentioning features or use of this software
141590Srgrimes *    must display the following acknowledgement:
151590Srgrimes *	This product includes software developed by the University of
161590Srgrimes *	California, Berkeley and its contributors.
171590Srgrimes * 4. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes
341590Srgrimes#ifndef lint
3519234Swollman/*
361590Srgrimesstatic char sccsid[] = "@(#)netstat.c	8.1 (Berkeley) 6/6/93";
3719234Swollman*/
3819234Swollmanstatic const char rcsid[] =
3950477Speter  "$FreeBSD: head/usr.bin/systat/netstat.c 74671 2001-03-23 03:58:25Z tmm $";
401590Srgrimes#endif /* not lint */
411590Srgrimes
421590Srgrimes/*
431590Srgrimes * netstat
441590Srgrimes */
451590Srgrimes#include <sys/param.h>
4614543Sdg#include <sys/queue.h>
471590Srgrimes#include <sys/socket.h>
481590Srgrimes#include <sys/socketvar.h>
491590Srgrimes#include <sys/protosw.h>
501590Srgrimes
511590Srgrimes#include <netinet/in.h>
5236916Speter#include <arpa/inet.h>
531590Srgrimes#include <net/route.h>
541590Srgrimes#include <netinet/in_systm.h>
551590Srgrimes#include <netinet/ip.h>
561590Srgrimes#include <netinet/in_pcb.h>
571590Srgrimes#include <netinet/ip_icmp.h>
581590Srgrimes#include <netinet/icmp_var.h>
591590Srgrimes#include <netinet/ip_var.h>
601590Srgrimes#include <netinet/tcp.h>
611590Srgrimes#include <netinet/tcpip.h>
621590Srgrimes#include <netinet/tcp_seq.h>
6374671Stmm#include <netinet/tcp_var.h>
641590Srgrimes#define TCPSTATES
651590Srgrimes#include <netinet/tcp_fsm.h>
661590Srgrimes#include <netinet/tcp_timer.h>
671590Srgrimes#include <netinet/tcp_var.h>
681590Srgrimes#include <netinet/tcp_debug.h>
691590Srgrimes#include <netinet/udp.h>
701590Srgrimes#include <netinet/udp_var.h>
711590Srgrimes
721590Srgrimes#include <netdb.h>
731590Srgrimes#include <stdlib.h>
741590Srgrimes#include <string.h>
751590Srgrimes#include <nlist.h>
761590Srgrimes#include <paths.h>
771590Srgrimes#include "systat.h"
781590Srgrimes#include "extern.h"
791590Srgrimes
8074671Stmmstatic struct netinfo *enter __P((struct inpcb *, int, char *));
8174671Stmmstatic void enter_kvm __P((struct inpcb *, struct socket *, int, char *));
8274671Stmmstatic void enter_sysctl __P((struct inpcb *, struct xsocket *, int, char *));
8374671Stmmstatic void fetchnetstat_kvm __P((void));
8474671Stmmstatic void fetchnetstat_sysctl __P((void));
851590Srgrimesstatic char *inetname __P((struct in_addr));
861590Srgrimesstatic void inetprint __P((struct in_addr *, int, char *));
871590Srgrimes
881590Srgrimes#define	streq(a,b)	(strcmp(a,b)==0)
8950635Speter#define	YMAX(w)		((w)->_maxy-1)
901590Srgrimes
911590SrgrimesWINDOW *
921590Srgrimesopennetstat()
931590Srgrimes{
941590Srgrimes	sethostent(1);
951590Srgrimes	setnetent(1);
961590Srgrimes	return (subwin(stdscr, LINES-5-1, 0, 5, 0));
971590Srgrimes}
981590Srgrimes
991590Srgrimesstruct netinfo {
10070523Sphk	TAILQ_ENTRY(netinfo) chain;
1011590Srgrimes	short	ni_line;		/* line on screen */
1021590Srgrimes	short	ni_seen;		/* 0 when not present in list */
1031590Srgrimes	short	ni_flags;
1041590Srgrimes#define	NIF_LACHG	0x1		/* local address changed */
1051590Srgrimes#define	NIF_FACHG	0x2		/* foreign address changed */
1061590Srgrimes	short	ni_state;		/* tcp state */
1071590Srgrimes	char	*ni_proto;		/* protocol */
1081590Srgrimes	struct	in_addr ni_laddr;	/* local address */
1091590Srgrimes	long	ni_lport;		/* local port */
1101590Srgrimes	struct	in_addr	ni_faddr;	/* foreign address */
1111590Srgrimes	long	ni_fport;		/* foreign port */
1121590Srgrimes	long	ni_rcvcc;		/* rcv buffer character count */
1131590Srgrimes	long	ni_sndcc;		/* snd buffer character count */
1141590Srgrimes};
1151590Srgrimes
11670523SphkTAILQ_HEAD(netinfohead, netinfo) netcb = TAILQ_HEAD_INITIALIZER(netcb);
1171590Srgrimes
1181590Srgrimesstatic	int aflag = 0;
1191590Srgrimesstatic	int nflag = 0;
1201590Srgrimesstatic	int lastrow = 1;
1211590Srgrimesstatic	char *inetname();
1221590Srgrimes
1231590Srgrimesvoid
1241590Srgrimesclosenetstat(w)
1251590Srgrimes        WINDOW *w;
1261590Srgrimes{
1271590Srgrimes	register struct netinfo *p;
1281590Srgrimes
1291590Srgrimes	endhostent();
1301590Srgrimes	endnetent();
13170526Sphk	TAILQ_FOREACH(p, &netcb, chain) {
1321590Srgrimes		if (p->ni_line != -1)
1331590Srgrimes			lastrow--;
1341590Srgrimes		p->ni_line = -1;
1351590Srgrimes	}
1361590Srgrimes        if (w != NULL) {
1371590Srgrimes		wclear(w);
1381590Srgrimes		wrefresh(w);
1391590Srgrimes		delwin(w);
1401590Srgrimes	}
1411590Srgrimes}
1421590Srgrimes
14374671Stmmstatic char *miblist[] = {
14474671Stmm	"net.inet.tcp.pcblist",
14574671Stmm	"net.inet.udp.pcblist"
14674671Stmm};
14774671Stmm
14874671Stmmstruct nlist namelist[] = {
1491590Srgrimes#define	X_TCB	0
15074671Stmm	{ "tcb" },
1511590Srgrimes#define	X_UDB	1
15274671Stmm	{ "udb" },
1531590Srgrimes	{ "" },
1541590Srgrimes};
1551590Srgrimes
1561590Srgrimesint
1571590Srgrimesinitnetstat()
1581590Srgrimes{
1591590Srgrimes	protos = TCP|UDP;
1601590Srgrimes	return(1);
1611590Srgrimes}
1621590Srgrimes
1631590Srgrimesvoid
1641590Srgrimesfetchnetstat()
1651590Srgrimes{
16674671Stmm	if (use_kvm)
16774671Stmm		fetchnetstat_kvm();
16874671Stmm	else
16974671Stmm		fetchnetstat_sysctl();
17074671Stmm}
17174671Stmm
17274671Stmmstatic void
17374671Stmmfetchnetstat_kvm()
17474671Stmm{
17540060Sobrien	register struct inpcb *next;
1761590Srgrimes	register struct netinfo *p;
1777715Sdg	struct inpcbhead head;
1781590Srgrimes	struct inpcb inpcb;
1791590Srgrimes	struct socket sockb;
1801590Srgrimes	struct tcpcb tcpcb;
1811590Srgrimes	void *off;
1821590Srgrimes	int istcp;
1831590Srgrimes
1841590Srgrimes	if (namelist[X_TCB].n_value == 0)
1851590Srgrimes		return;
18670523Sphk	TAILQ_FOREACH(p, &netcb, chain)
1871590Srgrimes		p->ni_seen = 0;
1881590Srgrimes	if (protos&TCP) {
1898874Srgrimes		off = NPTR(X_TCB);
1901590Srgrimes		istcp = 1;
1911590Srgrimes	}
1921590Srgrimes	else if (protos&UDP) {
1938874Srgrimes		off = NPTR(X_UDB);
1941590Srgrimes		istcp = 0;
1951590Srgrimes	}
1961590Srgrimes	else {
1971590Srgrimes		error("No protocols to display");
1981590Srgrimes		return;
1991590Srgrimes	}
2001590Srgrimesagain:
2017715Sdg	KREAD(off, &head, sizeof (struct inpcbhead));
20270523Sphk	LIST_FOREACH(next, &head, inp_list) {
2031590Srgrimes		KREAD(next, &inpcb, sizeof (inpcb));
20470526Sphk		next = &inpcb;
2051590Srgrimes		if (!aflag && inet_lnaof(inpcb.inp_laddr) == INADDR_ANY)
2061590Srgrimes			continue;
2071590Srgrimes		if (nhosts && !checkhost(&inpcb))
2081590Srgrimes			continue;
2091590Srgrimes		if (nports && !checkport(&inpcb))
2101590Srgrimes			continue;
2111590Srgrimes		KREAD(inpcb.inp_socket, &sockb, sizeof (sockb));
2121590Srgrimes		if (istcp) {
2131590Srgrimes			KREAD(inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb));
21474671Stmm			enter_kvm(&inpcb, &sockb, tcpcb.t_state, "tcp");
2151590Srgrimes		} else
21674671Stmm			enter_kvm(&inpcb, &sockb, 0, "udp");
2171590Srgrimes	}
2181590Srgrimes	if (istcp && (protos&UDP)) {
2191590Srgrimes		istcp = 0;
2201590Srgrimes		off = NPTR(X_UDB);
2211590Srgrimes		goto again;
2221590Srgrimes	}
2231590Srgrimes}
2241590Srgrimes
2251590Srgrimesstatic void
22674671Stmmfetchnetstat_sysctl()
22774671Stmm{
22874671Stmm	register struct netinfo *p;
22974671Stmm	int idx;
23074671Stmm	struct xinpgen *inpg;
23174671Stmm	char *cur, *end;
23274671Stmm	struct inpcb *inpcb;
23374671Stmm	struct xinpcb *xip;
23474671Stmm	struct xtcpcb *xtp;
23574671Stmm	int plen;
23674671Stmm	size_t lsz;
23774671Stmm
23874671Stmm	TAILQ_FOREACH(p, &netcb, chain)
23974671Stmm		p->ni_seen = 0;
24074671Stmm	if (protos&TCP) {
24174671Stmm		idx = 0;
24274671Stmm	} else if (protos&UDP) {
24374671Stmm		idx = 1;
24474671Stmm	} else {
24574671Stmm		error("No protocols to display");
24674671Stmm		return;
24774671Stmm	}
24874671Stmm
24974671Stmm	for (;idx < 2; idx++) {
25074671Stmm		if (idx == 1 && !(protos&UDP))
25174671Stmm			break;
25274671Stmm		inpg = (struct xinpgen *)sysctl_dynread(miblist[idx], &lsz);
25374671Stmm		if (inpg == NULL) {
25474671Stmm			error("sysctl(%s...) failed", miblist[idx]);
25574671Stmm			continue;
25674671Stmm		}
25774671Stmm		/*
25874671Stmm		 * We currently do no require a consistent pcb list.
25974671Stmm		 * Try to be robust in case of struct size changes
26074671Stmm		 */
26174671Stmm		cur = ((char *)inpg) + inpg->xig_len;
26274671Stmm		/* There is also a trailing struct xinpgen */
26374671Stmm		end = ((char *)inpg) + lsz - inpg->xig_len;
26474671Stmm		if (end <= cur) {
26574671Stmm			free(inpg);
26674671Stmm			continue;
26774671Stmm		}
26874671Stmm		if (idx == 0) { /* TCP */
26974671Stmm			xtp = (struct xtcpcb *)cur;
27074671Stmm			plen = xtp->xt_len;
27174671Stmm		} else {
27274671Stmm			xip = (struct xinpcb *)cur;
27374671Stmm			plen = xip->xi_len;
27474671Stmm		}
27574671Stmm		while (cur + plen <= end) {
27674671Stmm			if (idx == 0) { /* TCP */
27774671Stmm				xtp = (struct xtcpcb *)cur;
27874671Stmm				inpcb = &xtp->xt_inp;
27974671Stmm			} else {
28074671Stmm				xip = (struct xinpcb *)cur;
28174671Stmm				inpcb = &xip->xi_inp;
28274671Stmm			}
28374671Stmm			cur += plen;
28474671Stmm
28574671Stmm			if (!aflag && inet_lnaof(inpcb->inp_laddr) ==
28674671Stmm			    INADDR_ANY)
28774671Stmm				continue;
28874671Stmm			if (nhosts && !checkhost(inpcb))
28974671Stmm				continue;
29074671Stmm			if (nports && !checkport(inpcb))
29174671Stmm				continue;
29274671Stmm			if (idx == 0)	/* TCP */
29374671Stmm				enter_sysctl(inpcb, &xtp->xt_socket,
29474671Stmm				    xtp->xt_tp.t_state, "tcp");
29574671Stmm			else		/* UDP */
29674671Stmm				enter_sysctl(inpcb, &xip->xi_socket, 0, "udp");
29774671Stmm		}
29874671Stmm		free(inpg);
29974671Stmm	}
30074671Stmm}
30174671Stmm
30274671Stmmstatic void
30374671Stmmenter_kvm(inp, so, state, proto)
3041590Srgrimes	register struct inpcb *inp;
3051590Srgrimes	register struct socket *so;
3061590Srgrimes	int state;
3071590Srgrimes	char *proto;
3081590Srgrimes{
3091590Srgrimes	register struct netinfo *p;
3101590Srgrimes
31174671Stmm	if ((p = enter(inp, state, proto)) != NULL) {
31274671Stmm		p->ni_rcvcc = so->so_rcv.sb_cc;
31374671Stmm		p->ni_sndcc = so->so_snd.sb_cc;
31474671Stmm	}
31574671Stmm}
31674671Stmm
31774671Stmmstatic void
31874671Stmmenter_sysctl(inp, so, state, proto)
31974671Stmm	register struct inpcb *inp;
32074671Stmm	register struct xsocket *so;
32174671Stmm	int state;
32274671Stmm	char *proto;
32374671Stmm{
32474671Stmm	register struct netinfo *p;
32574671Stmm
32674671Stmm	if ((p = enter(inp, state, proto)) != NULL) {
32774671Stmm		p->ni_rcvcc = so->so_rcv.sb_cc;
32874671Stmm		p->ni_sndcc = so->so_snd.sb_cc;
32974671Stmm	}
33074671Stmm}
33174671Stmm
33274671Stmm
33374671Stmmstatic struct netinfo *
33474671Stmmenter(inp, state, proto)
33574671Stmm	register struct inpcb *inp;
33674671Stmm	int state;
33774671Stmm	char *proto;
33874671Stmm{
33974671Stmm	register struct netinfo *p;
34074671Stmm
3411590Srgrimes	/*
3421590Srgrimes	 * Only take exact matches, any sockets with
3431590Srgrimes	 * previously unbound addresses will be deleted
3441590Srgrimes	 * below in the display routine because they
3451590Srgrimes	 * will appear as ``not seen'' in the kernel
3461590Srgrimes	 * data structures.
3471590Srgrimes	 */
34870523Sphk	TAILQ_FOREACH(p, &netcb, chain) {
3491590Srgrimes		if (!streq(proto, p->ni_proto))
3501590Srgrimes			continue;
3511590Srgrimes		if (p->ni_lport != inp->inp_lport ||
3521590Srgrimes		    p->ni_laddr.s_addr != inp->inp_laddr.s_addr)
3531590Srgrimes			continue;
3541590Srgrimes		if (p->ni_faddr.s_addr == inp->inp_faddr.s_addr &&
3551590Srgrimes		    p->ni_fport == inp->inp_fport)
3561590Srgrimes			break;
3571590Srgrimes	}
35870523Sphk	if (p == NULL) {
3591590Srgrimes		if ((p = malloc(sizeof(*p))) == NULL) {
3601590Srgrimes			error("Out of memory");
36174671Stmm			return NULL;
3621590Srgrimes		}
36370523Sphk		TAILQ_INSERT_HEAD(&netcb, p, chain);
3641590Srgrimes		p->ni_line = -1;
3651590Srgrimes		p->ni_laddr = inp->inp_laddr;
3661590Srgrimes		p->ni_lport = inp->inp_lport;
3671590Srgrimes		p->ni_faddr = inp->inp_faddr;
3681590Srgrimes		p->ni_fport = inp->inp_fport;
3691590Srgrimes		p->ni_proto = proto;
3701590Srgrimes		p->ni_flags = NIF_LACHG|NIF_FACHG;
3711590Srgrimes	}
3721590Srgrimes	p->ni_state = state;
3731590Srgrimes	p->ni_seen = 1;
37474671Stmm	return p;
3751590Srgrimes}
3761590Srgrimes
3771590Srgrimes/* column locations */
3781590Srgrimes#define	LADDR	0
3791590Srgrimes#define	FADDR	LADDR+23
3801590Srgrimes#define	PROTO	FADDR+23
3811590Srgrimes#define	RCVCC	PROTO+6
3821590Srgrimes#define	SNDCC	RCVCC+7
3831590Srgrimes#define	STATE	SNDCC+7
3841590Srgrimes
3851590Srgrimes
3861590Srgrimesvoid
3871590Srgrimeslabelnetstat()
3881590Srgrimes{
38974671Stmm	if (use_kvm && namelist[X_TCB].n_type == 0)
3901590Srgrimes		return;
3911590Srgrimes	wmove(wnd, 0, 0); wclrtobot(wnd);
3921590Srgrimes	mvwaddstr(wnd, 0, LADDR, "Local Address");
3931590Srgrimes	mvwaddstr(wnd, 0, FADDR, "Foreign Address");
3941590Srgrimes	mvwaddstr(wnd, 0, PROTO, "Proto");
3951590Srgrimes	mvwaddstr(wnd, 0, RCVCC, "Recv-Q");
3961590Srgrimes	mvwaddstr(wnd, 0, SNDCC, "Send-Q");
3978874Srgrimes	mvwaddstr(wnd, 0, STATE, "(state)");
3981590Srgrimes}
3991590Srgrimes
4001590Srgrimesvoid
4011590Srgrimesshownetstat()
4021590Srgrimes{
4031590Srgrimes	register struct netinfo *p, *q;
4041590Srgrimes
4051590Srgrimes	/*
4061590Srgrimes	 * First, delete any connections that have gone
4071590Srgrimes	 * away and adjust the position of connections
4081590Srgrimes	 * below to reflect the deleted line.
4091590Srgrimes	 */
41074671Stmm	p = TAILQ_FIRST(&netcb);
41174671Stmm	while (p != NULL) {
41274671Stmm		if (p->ni_line == -1 || p->ni_seen) {
41374671Stmm			p = TAILQ_NEXT(p, chain);
4141590Srgrimes			continue;
41574671Stmm		}
4161590Srgrimes		wmove(wnd, p->ni_line, 0); wdeleteln(wnd);
41770523Sphk		TAILQ_FOREACH(q, &netcb, chain)
4181590Srgrimes			if (q != p && q->ni_line > p->ni_line) {
4191590Srgrimes				q->ni_line--;
4201590Srgrimes				/* this shouldn't be necessary */
4211590Srgrimes				q->ni_flags |= NIF_LACHG|NIF_FACHG;
4221590Srgrimes			}
4231590Srgrimes		lastrow--;
42474671Stmm		q = TAILQ_NEXT(p, chain);
42570523Sphk		TAILQ_REMOVE(&netcb, p, chain);
4261590Srgrimes		free(p);
4271590Srgrimes		p = q;
4281590Srgrimes	}
4291590Srgrimes	/*
4301590Srgrimes	 * Update existing connections and add new ones.
4311590Srgrimes	 */
43270523Sphk	TAILQ_FOREACH(p, &netcb, chain) {
4331590Srgrimes		if (p->ni_line == -1) {
4341590Srgrimes			/*
4351590Srgrimes			 * Add a new entry if possible.
4361590Srgrimes			 */
4371590Srgrimes			if (lastrow > YMAX(wnd))
4381590Srgrimes				continue;
4391590Srgrimes			p->ni_line = lastrow++;
4401590Srgrimes			p->ni_flags |= NIF_LACHG|NIF_FACHG;
4411590Srgrimes		}
4421590Srgrimes		if (p->ni_flags & NIF_LACHG) {
4431590Srgrimes			wmove(wnd, p->ni_line, LADDR);
4441590Srgrimes			inetprint(&p->ni_laddr, p->ni_lport, p->ni_proto);
4451590Srgrimes			p->ni_flags &= ~NIF_LACHG;
4461590Srgrimes		}
4471590Srgrimes		if (p->ni_flags & NIF_FACHG) {
4481590Srgrimes			wmove(wnd, p->ni_line, FADDR);
4491590Srgrimes			inetprint(&p->ni_faddr, p->ni_fport, p->ni_proto);
4501590Srgrimes			p->ni_flags &= ~NIF_FACHG;
4511590Srgrimes		}
4521590Srgrimes		mvwaddstr(wnd, p->ni_line, PROTO, p->ni_proto);
4531590Srgrimes		mvwprintw(wnd, p->ni_line, RCVCC, "%6d", p->ni_rcvcc);
4541590Srgrimes		mvwprintw(wnd, p->ni_line, SNDCC, "%6d", p->ni_sndcc);
4551590Srgrimes		if (streq(p->ni_proto, "tcp"))
4561590Srgrimes			if (p->ni_state < 0 || p->ni_state >= TCP_NSTATES)
4571590Srgrimes				mvwprintw(wnd, p->ni_line, STATE, "%d",
4581590Srgrimes				    p->ni_state);
4591590Srgrimes			else
4601590Srgrimes				mvwaddstr(wnd, p->ni_line, STATE,
4611590Srgrimes				    tcpstates[p->ni_state]);
4621590Srgrimes		wclrtoeol(wnd);
4631590Srgrimes	}
4641590Srgrimes	if (lastrow < YMAX(wnd)) {
4651590Srgrimes		wmove(wnd, lastrow, 0); wclrtobot(wnd);
4661590Srgrimes		wmove(wnd, YMAX(wnd), 0); wdeleteln(wnd);	/* XXX */
4671590Srgrimes	}
4681590Srgrimes}
4691590Srgrimes
4701590Srgrimes/*
4711590Srgrimes * Pretty print an Internet address (net address + port).
4721590Srgrimes * If the nflag was specified, use numbers instead of names.
4731590Srgrimes */
4741590Srgrimesstatic void
4751590Srgrimesinetprint(in, port, proto)
4761590Srgrimes	register struct in_addr *in;
4771590Srgrimes	int port;
4781590Srgrimes	char *proto;
4791590Srgrimes{
4801590Srgrimes	struct servent *sp = 0;
4811590Srgrimes	char line[80], *cp, *index();
4821590Srgrimes
48336789Simp	snprintf(line, sizeof(line), "%.*s.", 16, inetname(*in));
4841590Srgrimes	cp = index(line, '\0');
4851590Srgrimes	if (!nflag && port)
4861590Srgrimes		sp = getservbyport(port, proto);
4871590Srgrimes	if (sp || port == 0)
48836789Simp		snprintf(cp, sizeof(line) - (cp - line), "%.8s",
48936789Simp		    sp ? sp->s_name : "*");
4901590Srgrimes	else
49136789Simp		snprintf(cp, sizeof(line) - (cp - line), "%d",
49236789Simp		    ntohs((u_short)port));
4931590Srgrimes	/* pad to full column to clear any garbage */
4941590Srgrimes	cp = index(line, '\0');
4951590Srgrimes	while (cp - line < 22)
4961590Srgrimes		*cp++ = ' ';
49719330Sphk	line[22] = '\0';
4981590Srgrimes	waddstr(wnd, line);
4991590Srgrimes}
5001590Srgrimes
5011590Srgrimes/*
5021590Srgrimes * Construct an Internet address representation.
5038874Srgrimes * If the nflag has been supplied, give
5041590Srgrimes * numeric value, otherwise try for symbolic name.
5051590Srgrimes */
5061590Srgrimesstatic char *
5071590Srgrimesinetname(in)
5081590Srgrimes	struct in_addr in;
5091590Srgrimes{
5101590Srgrimes	char *cp = 0;
5111590Srgrimes	static char line[50];
5121590Srgrimes	struct hostent *hp;
5131590Srgrimes	struct netent *np;
5141590Srgrimes
5151590Srgrimes	if (!nflag && in.s_addr != INADDR_ANY) {
5161590Srgrimes		int net = inet_netof(in);
5171590Srgrimes		int lna = inet_lnaof(in);
5181590Srgrimes
5191590Srgrimes		if (lna == INADDR_ANY) {
5201590Srgrimes			np = getnetbyaddr(net, AF_INET);
5211590Srgrimes			if (np)
5221590Srgrimes				cp = np->n_name;
5231590Srgrimes		}
5241590Srgrimes		if (cp == 0) {
5251590Srgrimes			hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
5261590Srgrimes			if (hp)
5271590Srgrimes				cp = hp->h_name;
5281590Srgrimes		}
5291590Srgrimes	}
5301590Srgrimes	if (in.s_addr == INADDR_ANY)
5311590Srgrimes		strcpy(line, "*");
5321590Srgrimes	else if (cp)
53336789Simp		snprintf(line, sizeof(line), "%s", cp);
5341590Srgrimes	else {
5351590Srgrimes		in.s_addr = ntohl(in.s_addr);
5361590Srgrimes#define C(x)	((x) & 0xff)
53736789Simp		snprintf(line, sizeof(line), "%u.%u.%u.%u", C(in.s_addr >> 24),
5381590Srgrimes			C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
5391590Srgrimes	}
5401590Srgrimes	return (line);
5411590Srgrimes}
5421590Srgrimes
5431590Srgrimesint
5441590Srgrimescmdnetstat(cmd, args)
5451590Srgrimes	char *cmd, *args;
5461590Srgrimes{
5471590Srgrimes	if (prefix(cmd, "all")) {
5481590Srgrimes		aflag = !aflag;
5491590Srgrimes		goto fixup;
5501590Srgrimes	}
5511590Srgrimes	if  (prefix(cmd, "numbers") || prefix(cmd, "names")) {
55270523Sphk		struct netinfo *p;
5531590Srgrimes		int new;
5541590Srgrimes
5551590Srgrimes		new = prefix(cmd, "numbers");
5561590Srgrimes		if (new == nflag)
5571590Srgrimes			return (1);
55870523Sphk		TAILQ_FOREACH(p, &netcb, chain) {
5591590Srgrimes			if (p->ni_line == -1)
5601590Srgrimes				continue;
5611590Srgrimes			p->ni_flags |= NIF_LACHG|NIF_FACHG;
5621590Srgrimes		}
5631590Srgrimes		nflag = new;
5641590Srgrimes		goto redisplay;
5651590Srgrimes	}
5661590Srgrimes	if (!netcmd(cmd, args))
5671590Srgrimes		return (0);
5681590Srgrimesfixup:
5691590Srgrimes	fetchnetstat();
5701590Srgrimesredisplay:
5711590Srgrimes	shownetstat();
5721590Srgrimes	refresh();
5731590Srgrimes	return (1);
5741590Srgrimes}
575