netstat.c revision 164678
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
3487715Smarkm#include <sys/cdefs.h>
351590Srgrimes
3687715Smarkm__FBSDID("$FreeBSD: head/usr.bin/systat/netstat.c 164678 2006-11-27 17:01:31Z yar $");
3787715Smarkm
3887715Smarkm#ifdef lint
3987715Smarkmstatic const char sccsid[] = "@(#)netstat.c	8.1 (Berkeley) 6/6/93";
4087715Smarkm#endif
4187715Smarkm
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>
56118318Sdwmalone#ifdef INET6
57118318Sdwmalone#include <netinet/ip6.h>
58118318Sdwmalone#endif
591590Srgrimes#include <netinet/in_pcb.h>
601590Srgrimes#include <netinet/ip_icmp.h>
611590Srgrimes#include <netinet/icmp_var.h>
621590Srgrimes#include <netinet/ip_var.h>
631590Srgrimes#include <netinet/tcp.h>
641590Srgrimes#include <netinet/tcpip.h>
651590Srgrimes#include <netinet/tcp_seq.h>
6674671Stmm#include <netinet/tcp_var.h>
671590Srgrimes#define TCPSTATES
681590Srgrimes#include <netinet/tcp_fsm.h>
691590Srgrimes#include <netinet/tcp_timer.h>
701590Srgrimes#include <netinet/tcp_var.h>
711590Srgrimes#include <netinet/tcp_debug.h>
721590Srgrimes#include <netinet/udp.h>
731590Srgrimes#include <netinet/udp_var.h>
741590Srgrimes
751590Srgrimes#include <netdb.h>
7687715Smarkm#include <nlist.h>
7787715Smarkm#include <paths.h>
781590Srgrimes#include <stdlib.h>
791590Srgrimes#include <string.h>
8087715Smarkm
811590Srgrimes#include "systat.h"
821590Srgrimes#include "extern.h"
831590Srgrimes
8492922Simpstatic struct netinfo *enter(struct inpcb *, int, const char *);
8592922Simpstatic void enter_kvm(struct inpcb *, struct socket *, int, const char *);
8692922Simpstatic void enter_sysctl(struct inpcb *, struct xsocket *, int, const char *);
8792922Simpstatic void fetchnetstat_kvm(void);
8892922Simpstatic void fetchnetstat_sysctl(void);
89142093Sumestatic char *inetname(struct sockaddr *);
90142093Sumestatic void inetprint(struct sockaddr *, const char *);
911590Srgrimes
921590Srgrimes#define	streq(a,b)	(strcmp(a,b)==0)
9350635Speter#define	YMAX(w)		((w)->_maxy-1)
941590Srgrimes
951590SrgrimesWINDOW *
961590Srgrimesopennetstat()
971590Srgrimes{
981590Srgrimes	sethostent(1);
991590Srgrimes	setnetent(1);
100158160Sbde	return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0));
1011590Srgrimes}
1021590Srgrimes
1031590Srgrimesstruct netinfo {
10470523Sphk	TAILQ_ENTRY(netinfo) chain;
1051590Srgrimes	short	ni_line;		/* line on screen */
1061590Srgrimes	short	ni_seen;		/* 0 when not present in list */
1071590Srgrimes	short	ni_flags;
1081590Srgrimes#define	NIF_LACHG	0x1		/* local address changed */
1091590Srgrimes#define	NIF_FACHG	0x2		/* foreign address changed */
1101590Srgrimes	short	ni_state;		/* tcp state */
11187715Smarkm	const char	*ni_proto;		/* protocol */
112142093Sume	struct sockaddr_storage ni_lsa;	/* local address */
113142093Sume	struct sockaddr_storage	ni_fsa;	/* foreign address */
114100591Sjdp	u_int	ni_rcvcc;		/* rcv buffer character count */
115100591Sjdp	u_int	ni_sndcc;		/* snd buffer character count */
1161590Srgrimes};
1171590Srgrimes
11870523SphkTAILQ_HEAD(netinfohead, netinfo) netcb = TAILQ_HEAD_INITIALIZER(netcb);
1191590Srgrimes
1201590Srgrimesstatic	int aflag = 0;
1211590Srgrimesstatic	int nflag = 0;
1221590Srgrimesstatic	int lastrow = 1;
1231590Srgrimes
1241590Srgrimesvoid
1251590Srgrimesclosenetstat(w)
1261590Srgrimes        WINDOW *w;
1271590Srgrimes{
12887715Smarkm	struct netinfo *p;
1291590Srgrimes
1301590Srgrimes	endhostent();
1311590Srgrimes	endnetent();
13270526Sphk	TAILQ_FOREACH(p, &netcb, chain) {
1331590Srgrimes		if (p->ni_line != -1)
1341590Srgrimes			lastrow--;
1351590Srgrimes		p->ni_line = -1;
1361590Srgrimes	}
1371590Srgrimes        if (w != NULL) {
1381590Srgrimes		wclear(w);
1391590Srgrimes		wrefresh(w);
1401590Srgrimes		delwin(w);
1411590Srgrimes	}
1421590Srgrimes}
1431590Srgrimes
14487715Smarkmstatic const char *miblist[] = {
14574671Stmm	"net.inet.tcp.pcblist",
146158161Sbde	"net.inet.udp.pcblist"
14774671Stmm};
14874671Stmm
14974671Stmmstruct nlist namelist[] = {
1501590Srgrimes#define	X_TCB	0
15174671Stmm	{ "tcb" },
1521590Srgrimes#define	X_UDB	1
15374671Stmm	{ "udb" },
1541590Srgrimes	{ "" },
1551590Srgrimes};
1561590Srgrimes
1571590Srgrimesint
1581590Srgrimesinitnetstat()
1591590Srgrimes{
1601590Srgrimes	protos = TCP|UDP;
1611590Srgrimes	return(1);
1621590Srgrimes}
1631590Srgrimes
1641590Srgrimesvoid
1651590Srgrimesfetchnetstat()
1661590Srgrimes{
16774671Stmm	if (use_kvm)
16874671Stmm		fetchnetstat_kvm();
16974671Stmm	else
17074671Stmm		fetchnetstat_sysctl();
17174671Stmm}
17274671Stmm
17374671Stmmstatic void
17474671Stmmfetchnetstat_kvm()
17574671Stmm{
17687715Smarkm	struct inpcb *next;
17787715Smarkm	struct netinfo *p;
1787715Sdg	struct inpcbhead head;
1791590Srgrimes	struct inpcb inpcb;
1801590Srgrimes	struct socket sockb;
1811590Srgrimes	struct tcpcb tcpcb;
1821590Srgrimes	void *off;
1831590Srgrimes	int istcp;
1841590Srgrimes
1851590Srgrimes	if (namelist[X_TCB].n_value == 0)
1861590Srgrimes		return;
18770523Sphk	TAILQ_FOREACH(p, &netcb, chain)
1881590Srgrimes		p->ni_seen = 0;
1891590Srgrimes	if (protos&TCP) {
1908874Srgrimes		off = NPTR(X_TCB);
1911590Srgrimes		istcp = 1;
1921590Srgrimes	}
1931590Srgrimes	else if (protos&UDP) {
1948874Srgrimes		off = NPTR(X_UDB);
1951590Srgrimes		istcp = 0;
1961590Srgrimes	}
1971590Srgrimes	else {
1981590Srgrimes		error("No protocols to display");
1991590Srgrimes		return;
2001590Srgrimes	}
2011590Srgrimesagain:
2027715Sdg	KREAD(off, &head, sizeof (struct inpcbhead));
20370523Sphk	LIST_FOREACH(next, &head, inp_list) {
2041590Srgrimes		KREAD(next, &inpcb, sizeof (inpcb));
20570526Sphk		next = &inpcb;
206142093Sume		if (!aflag) {
207142093Sume			if (inpcb.inp_vflag & INP_IPV4) {
208142093Sume				if (inet_lnaof(inpcb.inp_laddr) == INADDR_ANY)
209142093Sume					continue;
210142093Sume			}
211142093Sume#ifdef INET6
212142093Sume			else if (inpcb.inp_vflag & INP_IPV6) {
213142093Sume				if (memcmp(&inpcb.in6p_laddr,
214142093Sume				    &in6addr_any, sizeof(in6addr_any)) == 0)
215142093Sume					continue;
216142093Sume			}
217142093Sume#endif
218142093Sume		}
2191590Srgrimes		if (nhosts && !checkhost(&inpcb))
2201590Srgrimes			continue;
2211590Srgrimes		if (nports && !checkport(&inpcb))
2221590Srgrimes			continue;
2231590Srgrimes		if (istcp) {
224123800Ssilby			if (inpcb.inp_vflag & INP_TIMEWAIT) {
225123800Ssilby				bzero(&sockb, sizeof(sockb));
226123800Ssilby				enter_kvm(&inpcb, &sockb, TCPS_TIME_WAIT,
227123800Ssilby					 "tcp");
228123800Ssilby			} else {
229123800Ssilby				KREAD(inpcb.inp_socket, &sockb,
230123800Ssilby					sizeof (sockb));
231123800Ssilby				KREAD(inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb));
232123800Ssilby				enter_kvm(&inpcb, &sockb, tcpcb.t_state,
233123800Ssilby					"tcp");
234123800Ssilby			}
2351590Srgrimes		} else
23674671Stmm			enter_kvm(&inpcb, &sockb, 0, "udp");
2371590Srgrimes	}
2381590Srgrimes	if (istcp && (protos&UDP)) {
2391590Srgrimes		istcp = 0;
2401590Srgrimes		off = NPTR(X_UDB);
2411590Srgrimes		goto again;
2421590Srgrimes	}
2431590Srgrimes}
2441590Srgrimes
2451590Srgrimesstatic void
24674671Stmmfetchnetstat_sysctl()
24774671Stmm{
24887715Smarkm	struct netinfo *p;
24974671Stmm	int idx;
25074671Stmm	struct xinpgen *inpg;
25174671Stmm	char *cur, *end;
25274671Stmm	struct inpcb *inpcb;
25374671Stmm	struct xinpcb *xip;
25474671Stmm	struct xtcpcb *xtp;
25574671Stmm	int plen;
25674671Stmm	size_t lsz;
25774671Stmm
25874671Stmm	TAILQ_FOREACH(p, &netcb, chain)
25974671Stmm		p->ni_seen = 0;
26074671Stmm	if (protos&TCP) {
26174671Stmm		idx = 0;
26274671Stmm	} else if (protos&UDP) {
26374671Stmm		idx = 1;
26474671Stmm	} else {
26574671Stmm		error("No protocols to display");
26674671Stmm		return;
26774671Stmm	}
26874671Stmm
26974671Stmm	for (;idx < 2; idx++) {
27074671Stmm		if (idx == 1 && !(protos&UDP))
27174671Stmm			break;
27274671Stmm		inpg = (struct xinpgen *)sysctl_dynread(miblist[idx], &lsz);
27374671Stmm		if (inpg == NULL) {
27474671Stmm			error("sysctl(%s...) failed", miblist[idx]);
27574671Stmm			continue;
27674671Stmm		}
277158161Sbde		/*
27874671Stmm		 * We currently do no require a consistent pcb list.
279158161Sbde		 * Try to be robust in case of struct size changes
28074671Stmm		 */
28174671Stmm		cur = ((char *)inpg) + inpg->xig_len;
28274671Stmm		/* There is also a trailing struct xinpgen */
28374671Stmm		end = ((char *)inpg) + lsz - inpg->xig_len;
28474671Stmm		if (end <= cur) {
28574671Stmm			free(inpg);
28674671Stmm			continue;
28774671Stmm		}
28874671Stmm		if (idx == 0) { /* TCP */
28974671Stmm			xtp = (struct xtcpcb *)cur;
29074671Stmm			plen = xtp->xt_len;
29174671Stmm		} else {
29274671Stmm			xip = (struct xinpcb *)cur;
29374671Stmm			plen = xip->xi_len;
29474671Stmm		}
29574671Stmm		while (cur + plen <= end) {
29674671Stmm			if (idx == 0) { /* TCP */
29774671Stmm				xtp = (struct xtcpcb *)cur;
29874671Stmm				inpcb = &xtp->xt_inp;
29974671Stmm			} else {
30074671Stmm				xip = (struct xinpcb *)cur;
30174671Stmm				inpcb = &xip->xi_inp;
30274671Stmm			}
30374671Stmm			cur += plen;
30474671Stmm
305142093Sume			if (!aflag) {
306142093Sume				if (inpcb->inp_vflag & INP_IPV4) {
307142093Sume					if (inet_lnaof(inpcb->inp_laddr) ==
308142093Sume					    INADDR_ANY)
309142093Sume						continue;
310142093Sume				}
311142093Sume#ifdef INET6
312142093Sume				else if (inpcb->inp_vflag & INP_IPV6) {
313142093Sume					if (memcmp(&inpcb->in6p_laddr,
314142093Sume					    &in6addr_any, sizeof(in6addr_any))
315142093Sume					    == 0)
316142093Sume						continue;
317142093Sume				}
318142093Sume#endif
319142093Sume			}
32074671Stmm			if (nhosts && !checkhost(inpcb))
32174671Stmm				continue;
32274671Stmm			if (nports && !checkport(inpcb))
32374671Stmm				continue;
32474671Stmm			if (idx == 0)	/* TCP */
325158161Sbde				enter_sysctl(inpcb, &xtp->xt_socket,
32674671Stmm				    xtp->xt_tp.t_state, "tcp");
32774671Stmm			else		/* UDP */
32874671Stmm				enter_sysctl(inpcb, &xip->xi_socket, 0, "udp");
32974671Stmm		}
33074671Stmm		free(inpg);
33174671Stmm	}
33274671Stmm}
33374671Stmm
33474671Stmmstatic void
33574671Stmmenter_kvm(inp, so, state, proto)
33687715Smarkm	struct inpcb *inp;
33787715Smarkm	struct socket *so;
3381590Srgrimes	int state;
33987715Smarkm	const char *proto;
3401590Srgrimes{
34187715Smarkm	struct netinfo *p;
3421590Srgrimes
34374671Stmm	if ((p = enter(inp, state, proto)) != NULL) {
34474671Stmm		p->ni_rcvcc = so->so_rcv.sb_cc;
34574671Stmm		p->ni_sndcc = so->so_snd.sb_cc;
34674671Stmm	}
34774671Stmm}
34874671Stmm
34974671Stmmstatic void
35074671Stmmenter_sysctl(inp, so, state, proto)
35187715Smarkm	struct inpcb *inp;
35287715Smarkm	struct xsocket *so;
35374671Stmm	int state;
35487715Smarkm	const char *proto;
35574671Stmm{
35687715Smarkm	struct netinfo *p;
35774671Stmm
35874671Stmm	if ((p = enter(inp, state, proto)) != NULL) {
35974671Stmm		p->ni_rcvcc = so->so_rcv.sb_cc;
36074671Stmm		p->ni_sndcc = so->so_snd.sb_cc;
36174671Stmm	}
36274671Stmm}
36374671Stmm
36474671Stmm
36574671Stmmstatic struct netinfo *
36674671Stmmenter(inp, state, proto)
36787715Smarkm	struct inpcb *inp;
36874671Stmm	int state;
36987715Smarkm	const char *proto;
37074671Stmm{
37187715Smarkm	struct netinfo *p;
372142093Sume	struct sockaddr_storage lsa, fsa;
373142093Sume	struct sockaddr_in *sa4;
374142093Sume#ifdef INET6
375142093Sume	struct sockaddr_in6 *sa6;
376142093Sume#endif
37774671Stmm
378142093Sume	memset(&lsa, 0, sizeof(lsa));
379142093Sume	memset(&fsa, 0, sizeof(fsa));
380142093Sume	if (inp->inp_vflag & INP_IPV4) {
381142093Sume		sa4 = (struct sockaddr_in *)&lsa;
382142093Sume		sa4->sin_addr = inp->inp_laddr;
383142093Sume		sa4->sin_port = inp->inp_lport;
384142093Sume		sa4->sin_family = AF_INET;
385142093Sume		sa4->sin_len = sizeof(struct sockaddr_in);
386142093Sume
387142093Sume		sa4 = (struct sockaddr_in *)&fsa;
388142093Sume		sa4->sin_addr = inp->inp_faddr;
389142093Sume		sa4->sin_port = inp->inp_fport;
390142093Sume		sa4->sin_family = AF_INET;
391142093Sume		sa4->sin_len = sizeof(struct sockaddr_in);
392142093Sume	}
393142093Sume#ifdef INET6
394142093Sume	else if (inp->inp_vflag & INP_IPV6) {
395142093Sume		sa6 = (struct sockaddr_in6 *)&lsa;
396142093Sume		memcpy(&sa6->sin6_addr, &inp->in6p_laddr,
397142093Sume		    sizeof(struct in6_addr));
398142093Sume		sa6->sin6_port = inp->inp_lport;
399142093Sume		sa6->sin6_family = AF_INET6;
400142093Sume		sa6->sin6_len = sizeof(struct sockaddr_in6);
401142093Sume
402142093Sume		sa6 = (struct sockaddr_in6 *)&fsa;
403142093Sume		memcpy(&sa6->sin6_addr, &inp->in6p_faddr,
404142093Sume		    sizeof(struct in6_addr));
405142093Sume		sa6->sin6_port = inp->inp_fport;
406142093Sume		sa6->sin6_family = AF_INET6;
407142093Sume		sa6->sin6_len = sizeof(struct sockaddr_in6);
408142093Sume	}
409142093Sume#endif
410142095Sume	else
411142093Sume		return NULL;
412142093Sume
4131590Srgrimes	/*
4141590Srgrimes	 * Only take exact matches, any sockets with
4151590Srgrimes	 * previously unbound addresses will be deleted
4161590Srgrimes	 * below in the display routine because they
4171590Srgrimes	 * will appear as ``not seen'' in the kernel
4181590Srgrimes	 * data structures.
4191590Srgrimes	 */
42070523Sphk	TAILQ_FOREACH(p, &netcb, chain) {
4211590Srgrimes		if (!streq(proto, p->ni_proto))
4221590Srgrimes			continue;
423142093Sume		if (p->ni_lsa.ss_family != lsa.ss_family ||
424142093Sume		    memcmp(&p->ni_lsa, &lsa, lsa.ss_len) != 0)
4251590Srgrimes			continue;
426142093Sume		if (p->ni_fsa.ss_family == fsa.ss_family &&
427142093Sume		    memcmp(&p->ni_fsa, &fsa, fsa.ss_len) == 0)
4281590Srgrimes			break;
4291590Srgrimes	}
43070523Sphk	if (p == NULL) {
4311590Srgrimes		if ((p = malloc(sizeof(*p))) == NULL) {
4321590Srgrimes			error("Out of memory");
43374671Stmm			return NULL;
4341590Srgrimes		}
43570523Sphk		TAILQ_INSERT_HEAD(&netcb, p, chain);
4361590Srgrimes		p->ni_line = -1;
437142093Sume		memcpy(&p->ni_lsa, &lsa, lsa.ss_len);
438142093Sume		memcpy(&p->ni_fsa, &fsa, fsa.ss_len);
43987715Smarkm		p->ni_proto = strdup(proto);
4401590Srgrimes		p->ni_flags = NIF_LACHG|NIF_FACHG;
4411590Srgrimes	}
4421590Srgrimes	p->ni_state = state;
4431590Srgrimes	p->ni_seen = 1;
44474671Stmm	return p;
4451590Srgrimes}
4461590Srgrimes
4471590Srgrimes/* column locations */
4481590Srgrimes#define	LADDR	0
4491590Srgrimes#define	FADDR	LADDR+23
4501590Srgrimes#define	PROTO	FADDR+23
4511590Srgrimes#define	RCVCC	PROTO+6
4521590Srgrimes#define	SNDCC	RCVCC+7
4531590Srgrimes#define	STATE	SNDCC+7
4541590Srgrimes
4551590Srgrimes
4561590Srgrimesvoid
4571590Srgrimeslabelnetstat()
4581590Srgrimes{
45974671Stmm	if (use_kvm && namelist[X_TCB].n_type == 0)
4601590Srgrimes		return;
4611590Srgrimes	wmove(wnd, 0, 0); wclrtobot(wnd);
4621590Srgrimes	mvwaddstr(wnd, 0, LADDR, "Local Address");
4631590Srgrimes	mvwaddstr(wnd, 0, FADDR, "Foreign Address");
4641590Srgrimes	mvwaddstr(wnd, 0, PROTO, "Proto");
4651590Srgrimes	mvwaddstr(wnd, 0, RCVCC, "Recv-Q");
4661590Srgrimes	mvwaddstr(wnd, 0, SNDCC, "Send-Q");
4678874Srgrimes	mvwaddstr(wnd, 0, STATE, "(state)");
4681590Srgrimes}
4691590Srgrimes
4701590Srgrimesvoid
4711590Srgrimesshownetstat()
4721590Srgrimes{
47387715Smarkm	struct netinfo *p, *q;
474164678Syar	char proto[6];
475164678Syar	const char *family = "";
4761590Srgrimes
4771590Srgrimes	/*
4781590Srgrimes	 * First, delete any connections that have gone
4791590Srgrimes	 * away and adjust the position of connections
4801590Srgrimes	 * below to reflect the deleted line.
4811590Srgrimes	 */
48274671Stmm	p = TAILQ_FIRST(&netcb);
48374671Stmm	while (p != NULL) {
48474671Stmm		if (p->ni_line == -1 || p->ni_seen) {
48574671Stmm			p = TAILQ_NEXT(p, chain);
4861590Srgrimes			continue;
48774671Stmm		}
4881590Srgrimes		wmove(wnd, p->ni_line, 0); wdeleteln(wnd);
48970523Sphk		TAILQ_FOREACH(q, &netcb, chain)
4901590Srgrimes			if (q != p && q->ni_line > p->ni_line) {
4911590Srgrimes				q->ni_line--;
4921590Srgrimes				/* this shouldn't be necessary */
4931590Srgrimes				q->ni_flags |= NIF_LACHG|NIF_FACHG;
4941590Srgrimes			}
4951590Srgrimes		lastrow--;
49674671Stmm		q = TAILQ_NEXT(p, chain);
49770523Sphk		TAILQ_REMOVE(&netcb, p, chain);
4981590Srgrimes		free(p);
4991590Srgrimes		p = q;
5001590Srgrimes	}
5011590Srgrimes	/*
5021590Srgrimes	 * Update existing connections and add new ones.
5031590Srgrimes	 */
50470523Sphk	TAILQ_FOREACH(p, &netcb, chain) {
5051590Srgrimes		if (p->ni_line == -1) {
5061590Srgrimes			/*
5071590Srgrimes			 * Add a new entry if possible.
5081590Srgrimes			 */
5091590Srgrimes			if (lastrow > YMAX(wnd))
5101590Srgrimes				continue;
5111590Srgrimes			p->ni_line = lastrow++;
5121590Srgrimes			p->ni_flags |= NIF_LACHG|NIF_FACHG;
5131590Srgrimes		}
5141590Srgrimes		if (p->ni_flags & NIF_LACHG) {
5151590Srgrimes			wmove(wnd, p->ni_line, LADDR);
516142093Sume			inetprint((struct sockaddr *)&p->ni_lsa, p->ni_proto);
5171590Srgrimes			p->ni_flags &= ~NIF_LACHG;
5181590Srgrimes		}
5191590Srgrimes		if (p->ni_flags & NIF_FACHG) {
5201590Srgrimes			wmove(wnd, p->ni_line, FADDR);
521142093Sume			inetprint((struct sockaddr *)&p->ni_fsa, p->ni_proto);
5221590Srgrimes			p->ni_flags &= ~NIF_FACHG;
5231590Srgrimes		}
524142093Sume#ifdef INET6
525142093Sume		family = (p->ni_lsa.ss_family == AF_INET) ? "4" : "6";
526142093Sume#endif
527142093Sume		snprintf(proto, sizeof(proto), "%s%s", p->ni_proto, family);
528142093Sume		mvwaddstr(wnd, p->ni_line, PROTO, proto);
529100591Sjdp		mvwprintw(wnd, p->ni_line, RCVCC, "%6u", p->ni_rcvcc);
530100591Sjdp		mvwprintw(wnd, p->ni_line, SNDCC, "%6u", p->ni_sndcc);
53187715Smarkm		if (streq(p->ni_proto, "tcp")) {
5321590Srgrimes			if (p->ni_state < 0 || p->ni_state >= TCP_NSTATES)
5331590Srgrimes				mvwprintw(wnd, p->ni_line, STATE, "%d",
5341590Srgrimes				    p->ni_state);
5351590Srgrimes			else
5361590Srgrimes				mvwaddstr(wnd, p->ni_line, STATE,
5371590Srgrimes				    tcpstates[p->ni_state]);
53887715Smarkm		}
5391590Srgrimes		wclrtoeol(wnd);
5401590Srgrimes	}
5411590Srgrimes	if (lastrow < YMAX(wnd)) {
5421590Srgrimes		wmove(wnd, lastrow, 0); wclrtobot(wnd);
5431590Srgrimes		wmove(wnd, YMAX(wnd), 0); wdeleteln(wnd);	/* XXX */
5441590Srgrimes	}
5451590Srgrimes}
5461590Srgrimes
5471590Srgrimes/*
5481590Srgrimes * Pretty print an Internet address (net address + port).
5491590Srgrimes * If the nflag was specified, use numbers instead of names.
5501590Srgrimes */
5511590Srgrimesstatic void
552142093Sumeinetprint(sa, proto)
553142093Sume	struct sockaddr *sa;
55487715Smarkm	const char *proto;
5551590Srgrimes{
5561590Srgrimes	struct servent *sp = 0;
55787715Smarkm	char line[80], *cp;
558142093Sume	int port;
5591590Srgrimes
560142093Sume	switch (sa->sa_family) {
561142093Sume	case AF_INET:
562142093Sume		port = ((struct sockaddr_in *)sa)->sin_port;
563142093Sume		break;
564142093Sume#ifdef INET6
565142093Sume	case AF_INET6:
566142093Sume		port = ((struct sockaddr_in6 *)sa)->sin6_port;
567142093Sume		break;
568142093Sume#endif
569142093Sume	default:
570142093Sume		port = 0;
571142093Sume		break;
572142093Sume	}
573142093Sume	snprintf(line, sizeof(line), "%.*s.", 16, inetname(sa));
5741590Srgrimes	cp = index(line, '\0');
5751590Srgrimes	if (!nflag && port)
5761590Srgrimes		sp = getservbyport(port, proto);
5771590Srgrimes	if (sp || port == 0)
578158161Sbde		snprintf(cp, sizeof(line) - (cp - line), "%.8s",
57936789Simp		    sp ? sp->s_name : "*");
5801590Srgrimes	else
581158161Sbde		snprintf(cp, sizeof(line) - (cp - line), "%d",
58236789Simp		    ntohs((u_short)port));
5831590Srgrimes	/* pad to full column to clear any garbage */
5841590Srgrimes	cp = index(line, '\0');
5851590Srgrimes	while (cp - line < 22)
5861590Srgrimes		*cp++ = ' ';
58719330Sphk	line[22] = '\0';
5881590Srgrimes	waddstr(wnd, line);
5891590Srgrimes}
5901590Srgrimes
5911590Srgrimes/*
5921590Srgrimes * Construct an Internet address representation.
5938874Srgrimes * If the nflag has been supplied, give
5941590Srgrimes * numeric value, otherwise try for symbolic name.
5951590Srgrimes */
5961590Srgrimesstatic char *
597142093Sumeinetname(sa)
598142093Sume	struct sockaddr *sa;
5991590Srgrimes{
6001590Srgrimes	char *cp = 0;
601142093Sume	static char line[NI_MAXHOST];
6021590Srgrimes	struct hostent *hp;
6031590Srgrimes	struct netent *np;
604142093Sume	struct in_addr in;
6051590Srgrimes
606142093Sume#ifdef INET6
607142093Sume	if (sa->sa_family == AF_INET6) {
608142093Sume		if (memcmp(&((struct sockaddr_in6 *)sa)->sin6_addr,
609142093Sume		    &in6addr_any, sizeof(in6addr_any)) == 0)
610142093Sume			strcpy(line, "*");
611142093Sume		else
612142093Sume			getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0,
613142093Sume			    nflag ? NI_NUMERICHOST : 0);
614142093Sume		return (line);
615142093Sume	}
616142093Sume#endif
617142093Sume
618142093Sume	in = ((struct sockaddr_in *)sa)->sin_addr;
6191590Srgrimes	if (!nflag && in.s_addr != INADDR_ANY) {
6201590Srgrimes		int net = inet_netof(in);
6211590Srgrimes		int lna = inet_lnaof(in);
6221590Srgrimes
6231590Srgrimes		if (lna == INADDR_ANY) {
6241590Srgrimes			np = getnetbyaddr(net, AF_INET);
6251590Srgrimes			if (np)
6261590Srgrimes				cp = np->n_name;
6271590Srgrimes		}
6281590Srgrimes		if (cp == 0) {
6291590Srgrimes			hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
6301590Srgrimes			if (hp)
6311590Srgrimes				cp = hp->h_name;
6321590Srgrimes		}
6331590Srgrimes	}
6341590Srgrimes	if (in.s_addr == INADDR_ANY)
6351590Srgrimes		strcpy(line, "*");
6361590Srgrimes	else if (cp)
63736789Simp		snprintf(line, sizeof(line), "%s", cp);
6381590Srgrimes	else {
6391590Srgrimes		in.s_addr = ntohl(in.s_addr);
6401590Srgrimes#define C(x)	((x) & 0xff)
64136789Simp		snprintf(line, sizeof(line), "%u.%u.%u.%u", C(in.s_addr >> 24),
6421590Srgrimes			C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
6431590Srgrimes	}
6441590Srgrimes	return (line);
6451590Srgrimes}
6461590Srgrimes
6471590Srgrimesint
6481590Srgrimescmdnetstat(cmd, args)
64987715Smarkm	const char *cmd, *args;
6501590Srgrimes{
6511590Srgrimes	if (prefix(cmd, "all")) {
6521590Srgrimes		aflag = !aflag;
6531590Srgrimes		goto fixup;
6541590Srgrimes	}
6551590Srgrimes	if  (prefix(cmd, "numbers") || prefix(cmd, "names")) {
65670523Sphk		struct netinfo *p;
6571590Srgrimes		int new;
6581590Srgrimes
6591590Srgrimes		new = prefix(cmd, "numbers");
6601590Srgrimes		if (new == nflag)
6611590Srgrimes			return (1);
66270523Sphk		TAILQ_FOREACH(p, &netcb, chain) {
6631590Srgrimes			if (p->ni_line == -1)
6641590Srgrimes				continue;
6651590Srgrimes			p->ni_flags |= NIF_LACHG|NIF_FACHG;
6661590Srgrimes		}
6671590Srgrimes		nflag = new;
6681590Srgrimes		goto redisplay;
6691590Srgrimes	}
6701590Srgrimes	if (!netcmd(cmd, args))
6711590Srgrimes		return (0);
6721590Srgrimesfixup:
6731590Srgrimes	fetchnetstat();
6741590Srgrimesredisplay:
6751590Srgrimes	shownetstat();
6761590Srgrimes	refresh();
6771590Srgrimes	return (1);
6781590Srgrimes}
679