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 * 4. Neither the name of the University nor the names of its contributors
141590Srgrimes *    may be used to endorse or promote products derived from this software
151590Srgrimes *    without specific prior written permission.
161590Srgrimes *
171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271590Srgrimes * SUCH DAMAGE.
281590Srgrimes */
291590Srgrimes
3087715Smarkm#include <sys/cdefs.h>
311590Srgrimes
3287715Smarkm__FBSDID("$FreeBSD: releng/10.2/usr.bin/systat/netstat.c 231011 2012-02-05 09:17:49Z ed $");
3387715Smarkm
3487715Smarkm#ifdef lint
3587715Smarkmstatic const char sccsid[] = "@(#)netstat.c	8.1 (Berkeley) 6/6/93";
3687715Smarkm#endif
3787715Smarkm
381590Srgrimes/*
391590Srgrimes * netstat
401590Srgrimes */
411590Srgrimes#include <sys/param.h>
4214543Sdg#include <sys/queue.h>
431590Srgrimes#include <sys/socket.h>
441590Srgrimes#include <sys/socketvar.h>
451590Srgrimes#include <sys/protosw.h>
461590Srgrimes
471590Srgrimes#include <netinet/in.h>
4836916Speter#include <arpa/inet.h>
491590Srgrimes#include <net/route.h>
501590Srgrimes#include <netinet/in_systm.h>
511590Srgrimes#include <netinet/ip.h>
52118318Sdwmalone#ifdef INET6
53118318Sdwmalone#include <netinet/ip6.h>
54118318Sdwmalone#endif
551590Srgrimes#include <netinet/in_pcb.h>
561590Srgrimes#include <netinet/ip_icmp.h>
571590Srgrimes#include <netinet/icmp_var.h>
581590Srgrimes#include <netinet/ip_var.h>
591590Srgrimes#include <netinet/tcp.h>
601590Srgrimes#include <netinet/tcpip.h>
611590Srgrimes#include <netinet/tcp_seq.h>
6274671Stmm#include <netinet/tcp_var.h>
631590Srgrimes#define TCPSTATES
641590Srgrimes#include <netinet/tcp_fsm.h>
651590Srgrimes#include <netinet/tcp_timer.h>
661590Srgrimes#include <netinet/tcp_debug.h>
671590Srgrimes#include <netinet/udp.h>
681590Srgrimes#include <netinet/udp_var.h>
691590Srgrimes
701590Srgrimes#include <netdb.h>
7187715Smarkm#include <nlist.h>
72200462Sdelphij#include <paths.h>
731590Srgrimes#include <stdlib.h>
741590Srgrimes#include <string.h>
7587715Smarkm
761590Srgrimes#include "systat.h"
771590Srgrimes#include "extern.h"
781590Srgrimes
7992922Simpstatic struct netinfo *enter(struct inpcb *, int, const char *);
8092922Simpstatic void enter_kvm(struct inpcb *, struct socket *, int, const char *);
8192922Simpstatic void enter_sysctl(struct inpcb *, struct xsocket *, int, const char *);
8292922Simpstatic void fetchnetstat_kvm(void);
8392922Simpstatic void fetchnetstat_sysctl(void);
84142093Sumestatic char *inetname(struct sockaddr *);
85142093Sumestatic void inetprint(struct sockaddr *, const char *);
861590Srgrimes
871590Srgrimes#define	streq(a,b)	(strcmp(a,b)==0)
8850635Speter#define	YMAX(w)		((w)->_maxy-1)
891590Srgrimes
901590SrgrimesWINDOW *
91175387Sdelphijopennetstat(void)
921590Srgrimes{
931590Srgrimes	sethostent(1);
941590Srgrimes	setnetent(1);
95158160Sbde	return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0));
961590Srgrimes}
971590Srgrimes
981590Srgrimesstruct netinfo {
9970523Sphk	TAILQ_ENTRY(netinfo) chain;
1001590Srgrimes	short	ni_line;		/* line on screen */
1011590Srgrimes	short	ni_seen;		/* 0 when not present in list */
1021590Srgrimes	short	ni_flags;
1031590Srgrimes#define	NIF_LACHG	0x1		/* local address changed */
1041590Srgrimes#define	NIF_FACHG	0x2		/* foreign address changed */
1051590Srgrimes	short	ni_state;		/* tcp state */
10687715Smarkm	const char	*ni_proto;		/* protocol */
107142093Sume	struct sockaddr_storage ni_lsa;	/* local address */
108142093Sume	struct sockaddr_storage	ni_fsa;	/* foreign address */
109100591Sjdp	u_int	ni_rcvcc;		/* rcv buffer character count */
110100591Sjdp	u_int	ni_sndcc;		/* snd buffer character count */
1111590Srgrimes};
1121590Srgrimes
11370523SphkTAILQ_HEAD(netinfohead, netinfo) netcb = TAILQ_HEAD_INITIALIZER(netcb);
1141590Srgrimes
1151590Srgrimesstatic	int aflag = 0;
1161590Srgrimesstatic	int nflag = 0;
1171590Srgrimesstatic	int lastrow = 1;
1181590Srgrimes
1191590Srgrimesvoid
120175387Sdelphijclosenetstat(WINDOW *w)
1211590Srgrimes{
12287715Smarkm	struct netinfo *p;
1231590Srgrimes
1241590Srgrimes	endhostent();
1251590Srgrimes	endnetent();
12670526Sphk	TAILQ_FOREACH(p, &netcb, chain) {
1271590Srgrimes		if (p->ni_line != -1)
1281590Srgrimes			lastrow--;
1291590Srgrimes		p->ni_line = -1;
1301590Srgrimes	}
131226396Sed	if (w != NULL) {
1321590Srgrimes		wclear(w);
1331590Srgrimes		wrefresh(w);
1341590Srgrimes		delwin(w);
1351590Srgrimes	}
1361590Srgrimes}
1371590Srgrimes
13887715Smarkmstatic const char *miblist[] = {
13974671Stmm	"net.inet.tcp.pcblist",
140158161Sbde	"net.inet.udp.pcblist"
14174671Stmm};
14274671Stmm
143164679Syarstatic char tcb[] = "tcb", udb[] = "udb";
144164679Syar
14574671Stmmstruct nlist namelist[] = {
1461590Srgrimes#define	X_TCB	0
147164679Syar	{ .n_name = tcb },
1481590Srgrimes#define	X_UDB	1
149164679Syar	{ .n_name = udb },
150164679Syar	{ .n_name = NULL },
1511590Srgrimes};
1521590Srgrimes
1531590Srgrimesint
154175387Sdelphijinitnetstat(void)
1551590Srgrimes{
1561590Srgrimes	protos = TCP|UDP;
1571590Srgrimes	return(1);
1581590Srgrimes}
1591590Srgrimes
1601590Srgrimesvoid
161175387Sdelphijfetchnetstat(void)
1621590Srgrimes{
16374671Stmm	if (use_kvm)
16474671Stmm		fetchnetstat_kvm();
16574671Stmm	else
16674671Stmm		fetchnetstat_sysctl();
16774671Stmm}
16874671Stmm
16974671Stmmstatic void
170175387Sdelphijfetchnetstat_kvm(void)
17174671Stmm{
17287715Smarkm	struct inpcb *next;
17387715Smarkm	struct netinfo *p;
1747715Sdg	struct inpcbhead head;
1751590Srgrimes	struct inpcb inpcb;
1761590Srgrimes	struct socket sockb;
1771590Srgrimes	struct tcpcb tcpcb;
1781590Srgrimes	void *off;
1791590Srgrimes	int istcp;
1801590Srgrimes
1811590Srgrimes	if (namelist[X_TCB].n_value == 0)
1821590Srgrimes		return;
18370523Sphk	TAILQ_FOREACH(p, &netcb, chain)
1841590Srgrimes		p->ni_seen = 0;
1851590Srgrimes	if (protos&TCP) {
1868874Srgrimes		off = NPTR(X_TCB);
1871590Srgrimes		istcp = 1;
1881590Srgrimes	}
1891590Srgrimes	else if (protos&UDP) {
1908874Srgrimes		off = NPTR(X_UDB);
1911590Srgrimes		istcp = 0;
1921590Srgrimes	}
1931590Srgrimes	else {
1941590Srgrimes		error("No protocols to display");
1951590Srgrimes		return;
1961590Srgrimes	}
1971590Srgrimesagain:
1987715Sdg	KREAD(off, &head, sizeof (struct inpcbhead));
19970523Sphk	LIST_FOREACH(next, &head, inp_list) {
2001590Srgrimes		KREAD(next, &inpcb, sizeof (inpcb));
20170526Sphk		next = &inpcb;
202142093Sume		if (!aflag) {
203142093Sume			if (inpcb.inp_vflag & INP_IPV4) {
204142093Sume				if (inet_lnaof(inpcb.inp_laddr) == INADDR_ANY)
205142093Sume					continue;
206142093Sume			}
207142093Sume#ifdef INET6
208142093Sume			else if (inpcb.inp_vflag & INP_IPV6) {
209142093Sume				if (memcmp(&inpcb.in6p_laddr,
210142093Sume				    &in6addr_any, sizeof(in6addr_any)) == 0)
211142093Sume					continue;
212142093Sume			}
213142093Sume#endif
214142093Sume		}
2151590Srgrimes		if (nhosts && !checkhost(&inpcb))
2161590Srgrimes			continue;
2171590Srgrimes		if (nports && !checkport(&inpcb))
2181590Srgrimes			continue;
2191590Srgrimes		if (istcp) {
220189848Srwatson			if (inpcb.inp_flags & INP_TIMEWAIT) {
221123800Ssilby				bzero(&sockb, sizeof(sockb));
222123800Ssilby				enter_kvm(&inpcb, &sockb, TCPS_TIME_WAIT,
223123800Ssilby					 "tcp");
224123800Ssilby			} else {
225123800Ssilby				KREAD(inpcb.inp_socket, &sockb,
226123800Ssilby					sizeof (sockb));
227123800Ssilby				KREAD(inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb));
228123800Ssilby				enter_kvm(&inpcb, &sockb, tcpcb.t_state,
229123800Ssilby					"tcp");
230123800Ssilby			}
2311590Srgrimes		} else
23274671Stmm			enter_kvm(&inpcb, &sockb, 0, "udp");
2331590Srgrimes	}
2341590Srgrimes	if (istcp && (protos&UDP)) {
2351590Srgrimes		istcp = 0;
2361590Srgrimes		off = NPTR(X_UDB);
2371590Srgrimes		goto again;
2381590Srgrimes	}
2391590Srgrimes}
2401590Srgrimes
2411590Srgrimesstatic void
242175387Sdelphijfetchnetstat_sysctl(void)
24374671Stmm{
24487715Smarkm	struct netinfo *p;
24574671Stmm	int idx;
24674671Stmm	struct xinpgen *inpg;
24774671Stmm	char *cur, *end;
24874671Stmm	struct inpcb *inpcb;
249164680Syar	struct xinpcb *xip = NULL;
250164680Syar	struct xtcpcb *xtp = NULL;
25174671Stmm	int plen;
25274671Stmm	size_t lsz;
25374671Stmm
25474671Stmm	TAILQ_FOREACH(p, &netcb, chain)
25574671Stmm		p->ni_seen = 0;
25674671Stmm	if (protos&TCP) {
25774671Stmm		idx = 0;
25874671Stmm	} else if (protos&UDP) {
25974671Stmm		idx = 1;
26074671Stmm	} else {
26174671Stmm		error("No protocols to display");
26274671Stmm		return;
26374671Stmm	}
26474671Stmm
26574671Stmm	for (;idx < 2; idx++) {
26674671Stmm		if (idx == 1 && !(protos&UDP))
26774671Stmm			break;
26874671Stmm		inpg = (struct xinpgen *)sysctl_dynread(miblist[idx], &lsz);
26974671Stmm		if (inpg == NULL) {
27074671Stmm			error("sysctl(%s...) failed", miblist[idx]);
27174671Stmm			continue;
27274671Stmm		}
273158161Sbde		/*
27474671Stmm		 * We currently do no require a consistent pcb list.
275158161Sbde		 * Try to be robust in case of struct size changes
27674671Stmm		 */
27774671Stmm		cur = ((char *)inpg) + inpg->xig_len;
27874671Stmm		/* There is also a trailing struct xinpgen */
27974671Stmm		end = ((char *)inpg) + lsz - inpg->xig_len;
28074671Stmm		if (end <= cur) {
28174671Stmm			free(inpg);
28274671Stmm			continue;
28374671Stmm		}
28474671Stmm		if (idx == 0) { /* TCP */
28574671Stmm			xtp = (struct xtcpcb *)cur;
28674671Stmm			plen = xtp->xt_len;
28774671Stmm		} else {
28874671Stmm			xip = (struct xinpcb *)cur;
28974671Stmm			plen = xip->xi_len;
29074671Stmm		}
29174671Stmm		while (cur + plen <= end) {
29274671Stmm			if (idx == 0) { /* TCP */
29374671Stmm				xtp = (struct xtcpcb *)cur;
29474671Stmm				inpcb = &xtp->xt_inp;
29574671Stmm			} else {
29674671Stmm				xip = (struct xinpcb *)cur;
29774671Stmm				inpcb = &xip->xi_inp;
29874671Stmm			}
29974671Stmm			cur += plen;
30074671Stmm
301142093Sume			if (!aflag) {
302142093Sume				if (inpcb->inp_vflag & INP_IPV4) {
303142093Sume					if (inet_lnaof(inpcb->inp_laddr) ==
304142093Sume					    INADDR_ANY)
305142093Sume						continue;
306142093Sume				}
307142093Sume#ifdef INET6
308142093Sume				else if (inpcb->inp_vflag & INP_IPV6) {
309142093Sume					if (memcmp(&inpcb->in6p_laddr,
310142093Sume					    &in6addr_any, sizeof(in6addr_any))
311142093Sume					    == 0)
312142093Sume						continue;
313142093Sume				}
314142093Sume#endif
315142093Sume			}
31674671Stmm			if (nhosts && !checkhost(inpcb))
31774671Stmm				continue;
31874671Stmm			if (nports && !checkport(inpcb))
31974671Stmm				continue;
32074671Stmm			if (idx == 0)	/* TCP */
321158161Sbde				enter_sysctl(inpcb, &xtp->xt_socket,
32274671Stmm				    xtp->xt_tp.t_state, "tcp");
32374671Stmm			else		/* UDP */
32474671Stmm				enter_sysctl(inpcb, &xip->xi_socket, 0, "udp");
32574671Stmm		}
32674671Stmm		free(inpg);
32774671Stmm	}
32874671Stmm}
32974671Stmm
33074671Stmmstatic void
331175387Sdelphijenter_kvm(struct inpcb *inp, struct socket *so, int state, const char *proto)
3321590Srgrimes{
33387715Smarkm	struct netinfo *p;
3341590Srgrimes
33574671Stmm	if ((p = enter(inp, state, proto)) != NULL) {
33674671Stmm		p->ni_rcvcc = so->so_rcv.sb_cc;
33774671Stmm		p->ni_sndcc = so->so_snd.sb_cc;
33874671Stmm	}
33974671Stmm}
34074671Stmm
34174671Stmmstatic void
342175387Sdelphijenter_sysctl(struct inpcb *inp, struct xsocket *so, int state, const char *proto)
34374671Stmm{
34487715Smarkm	struct netinfo *p;
34574671Stmm
34674671Stmm	if ((p = enter(inp, state, proto)) != NULL) {
34774671Stmm		p->ni_rcvcc = so->so_rcv.sb_cc;
34874671Stmm		p->ni_sndcc = so->so_snd.sb_cc;
34974671Stmm	}
35074671Stmm}
35174671Stmm
35274671Stmmstatic struct netinfo *
353175387Sdelphijenter(struct inpcb *inp, int state, const char *proto)
35474671Stmm{
35587715Smarkm	struct netinfo *p;
356142093Sume	struct sockaddr_storage lsa, fsa;
357142093Sume	struct sockaddr_in *sa4;
358142093Sume#ifdef INET6
359142093Sume	struct sockaddr_in6 *sa6;
360142093Sume#endif
36174671Stmm
362142093Sume	memset(&lsa, 0, sizeof(lsa));
363142093Sume	memset(&fsa, 0, sizeof(fsa));
364142093Sume	if (inp->inp_vflag & INP_IPV4) {
365142093Sume		sa4 = (struct sockaddr_in *)&lsa;
366142093Sume		sa4->sin_addr = inp->inp_laddr;
367142093Sume		sa4->sin_port = inp->inp_lport;
368142093Sume		sa4->sin_family = AF_INET;
369142093Sume		sa4->sin_len = sizeof(struct sockaddr_in);
370142093Sume
371142093Sume		sa4 = (struct sockaddr_in *)&fsa;
372142093Sume		sa4->sin_addr = inp->inp_faddr;
373142093Sume		sa4->sin_port = inp->inp_fport;
374142093Sume		sa4->sin_family = AF_INET;
375142093Sume		sa4->sin_len = sizeof(struct sockaddr_in);
376142093Sume	}
377142093Sume#ifdef INET6
378142093Sume	else if (inp->inp_vflag & INP_IPV6) {
379142093Sume		sa6 = (struct sockaddr_in6 *)&lsa;
380142093Sume		memcpy(&sa6->sin6_addr, &inp->in6p_laddr,
381142093Sume		    sizeof(struct in6_addr));
382142093Sume		sa6->sin6_port = inp->inp_lport;
383142093Sume		sa6->sin6_family = AF_INET6;
384142093Sume		sa6->sin6_len = sizeof(struct sockaddr_in6);
385142093Sume
386142093Sume		sa6 = (struct sockaddr_in6 *)&fsa;
387142093Sume		memcpy(&sa6->sin6_addr, &inp->in6p_faddr,
388142093Sume		    sizeof(struct in6_addr));
389142093Sume		sa6->sin6_port = inp->inp_fport;
390142093Sume		sa6->sin6_family = AF_INET6;
391142093Sume		sa6->sin6_len = sizeof(struct sockaddr_in6);
392142093Sume	}
393142093Sume#endif
394142095Sume	else
395142093Sume		return NULL;
396142093Sume
3971590Srgrimes	/*
3981590Srgrimes	 * Only take exact matches, any sockets with
3991590Srgrimes	 * previously unbound addresses will be deleted
4001590Srgrimes	 * below in the display routine because they
4011590Srgrimes	 * will appear as ``not seen'' in the kernel
4021590Srgrimes	 * data structures.
4031590Srgrimes	 */
40470523Sphk	TAILQ_FOREACH(p, &netcb, chain) {
4051590Srgrimes		if (!streq(proto, p->ni_proto))
4061590Srgrimes			continue;
407142093Sume		if (p->ni_lsa.ss_family != lsa.ss_family ||
408142093Sume		    memcmp(&p->ni_lsa, &lsa, lsa.ss_len) != 0)
4091590Srgrimes			continue;
410142093Sume		if (p->ni_fsa.ss_family == fsa.ss_family &&
411142093Sume		    memcmp(&p->ni_fsa, &fsa, fsa.ss_len) == 0)
4121590Srgrimes			break;
4131590Srgrimes	}
41470523Sphk	if (p == NULL) {
4151590Srgrimes		if ((p = malloc(sizeof(*p))) == NULL) {
4161590Srgrimes			error("Out of memory");
41774671Stmm			return NULL;
4181590Srgrimes		}
41970523Sphk		TAILQ_INSERT_HEAD(&netcb, p, chain);
4201590Srgrimes		p->ni_line = -1;
421142093Sume		memcpy(&p->ni_lsa, &lsa, lsa.ss_len);
422142093Sume		memcpy(&p->ni_fsa, &fsa, fsa.ss_len);
42387715Smarkm		p->ni_proto = strdup(proto);
4241590Srgrimes		p->ni_flags = NIF_LACHG|NIF_FACHG;
4251590Srgrimes	}
4261590Srgrimes	p->ni_state = state;
4271590Srgrimes	p->ni_seen = 1;
42874671Stmm	return p;
4291590Srgrimes}
4301590Srgrimes
4311590Srgrimes/* column locations */
4321590Srgrimes#define	LADDR	0
4331590Srgrimes#define	FADDR	LADDR+23
4341590Srgrimes#define	PROTO	FADDR+23
4351590Srgrimes#define	RCVCC	PROTO+6
4361590Srgrimes#define	SNDCC	RCVCC+7
4371590Srgrimes#define	STATE	SNDCC+7
4381590Srgrimes
4391590Srgrimesvoid
440175387Sdelphijlabelnetstat(void)
4411590Srgrimes{
44274671Stmm	if (use_kvm && namelist[X_TCB].n_type == 0)
4431590Srgrimes		return;
4441590Srgrimes	wmove(wnd, 0, 0); wclrtobot(wnd);
4451590Srgrimes	mvwaddstr(wnd, 0, LADDR, "Local Address");
4461590Srgrimes	mvwaddstr(wnd, 0, FADDR, "Foreign Address");
4471590Srgrimes	mvwaddstr(wnd, 0, PROTO, "Proto");
4481590Srgrimes	mvwaddstr(wnd, 0, RCVCC, "Recv-Q");
4491590Srgrimes	mvwaddstr(wnd, 0, SNDCC, "Send-Q");
4508874Srgrimes	mvwaddstr(wnd, 0, STATE, "(state)");
4511590Srgrimes}
4521590Srgrimes
4531590Srgrimesvoid
454175387Sdelphijshownetstat(void)
4551590Srgrimes{
45687715Smarkm	struct netinfo *p, *q;
457164678Syar	char proto[6];
458164678Syar	const char *family = "";
4591590Srgrimes
4601590Srgrimes	/*
4611590Srgrimes	 * First, delete any connections that have gone
4621590Srgrimes	 * away and adjust the position of connections
4631590Srgrimes	 * below to reflect the deleted line.
4641590Srgrimes	 */
46574671Stmm	p = TAILQ_FIRST(&netcb);
46674671Stmm	while (p != NULL) {
46774671Stmm		if (p->ni_line == -1 || p->ni_seen) {
46874671Stmm			p = TAILQ_NEXT(p, chain);
4691590Srgrimes			continue;
47074671Stmm		}
4711590Srgrimes		wmove(wnd, p->ni_line, 0); wdeleteln(wnd);
47270523Sphk		TAILQ_FOREACH(q, &netcb, chain)
4731590Srgrimes			if (q != p && q->ni_line > p->ni_line) {
4741590Srgrimes				q->ni_line--;
4751590Srgrimes				/* this shouldn't be necessary */
4761590Srgrimes				q->ni_flags |= NIF_LACHG|NIF_FACHG;
4771590Srgrimes			}
4781590Srgrimes		lastrow--;
47974671Stmm		q = TAILQ_NEXT(p, chain);
48070523Sphk		TAILQ_REMOVE(&netcb, p, chain);
4811590Srgrimes		free(p);
4821590Srgrimes		p = q;
4831590Srgrimes	}
4841590Srgrimes	/*
4851590Srgrimes	 * Update existing connections and add new ones.
4861590Srgrimes	 */
48770523Sphk	TAILQ_FOREACH(p, &netcb, chain) {
4881590Srgrimes		if (p->ni_line == -1) {
4891590Srgrimes			/*
4901590Srgrimes			 * Add a new entry if possible.
4911590Srgrimes			 */
4921590Srgrimes			if (lastrow > YMAX(wnd))
4931590Srgrimes				continue;
4941590Srgrimes			p->ni_line = lastrow++;
4951590Srgrimes			p->ni_flags |= NIF_LACHG|NIF_FACHG;
4961590Srgrimes		}
4971590Srgrimes		if (p->ni_flags & NIF_LACHG) {
4981590Srgrimes			wmove(wnd, p->ni_line, LADDR);
499142093Sume			inetprint((struct sockaddr *)&p->ni_lsa, p->ni_proto);
5001590Srgrimes			p->ni_flags &= ~NIF_LACHG;
5011590Srgrimes		}
5021590Srgrimes		if (p->ni_flags & NIF_FACHG) {
5031590Srgrimes			wmove(wnd, p->ni_line, FADDR);
504142093Sume			inetprint((struct sockaddr *)&p->ni_fsa, p->ni_proto);
5051590Srgrimes			p->ni_flags &= ~NIF_FACHG;
5061590Srgrimes		}
507142093Sume#ifdef INET6
508142093Sume		family = (p->ni_lsa.ss_family == AF_INET) ? "4" : "6";
509142093Sume#endif
510142093Sume		snprintf(proto, sizeof(proto), "%s%s", p->ni_proto, family);
511142093Sume		mvwaddstr(wnd, p->ni_line, PROTO, proto);
512100591Sjdp		mvwprintw(wnd, p->ni_line, RCVCC, "%6u", p->ni_rcvcc);
513100591Sjdp		mvwprintw(wnd, p->ni_line, SNDCC, "%6u", p->ni_sndcc);
51487715Smarkm		if (streq(p->ni_proto, "tcp")) {
5151590Srgrimes			if (p->ni_state < 0 || p->ni_state >= TCP_NSTATES)
5161590Srgrimes				mvwprintw(wnd, p->ni_line, STATE, "%d",
5171590Srgrimes				    p->ni_state);
5181590Srgrimes			else
5191590Srgrimes				mvwaddstr(wnd, p->ni_line, STATE,
5201590Srgrimes				    tcpstates[p->ni_state]);
52187715Smarkm		}
5221590Srgrimes		wclrtoeol(wnd);
5231590Srgrimes	}
5241590Srgrimes	if (lastrow < YMAX(wnd)) {
5251590Srgrimes		wmove(wnd, lastrow, 0); wclrtobot(wnd);
5261590Srgrimes		wmove(wnd, YMAX(wnd), 0); wdeleteln(wnd);	/* XXX */
5271590Srgrimes	}
5281590Srgrimes}
5291590Srgrimes
5301590Srgrimes/*
5311590Srgrimes * Pretty print an Internet address (net address + port).
5321590Srgrimes * If the nflag was specified, use numbers instead of names.
5331590Srgrimes */
5341590Srgrimesstatic void
535175387Sdelphijinetprint(struct sockaddr *sa, const char *proto)
5361590Srgrimes{
5371590Srgrimes	struct servent *sp = 0;
53887715Smarkm	char line[80], *cp;
539142093Sume	int port;
5401590Srgrimes
541142093Sume	switch (sa->sa_family) {
542142093Sume	case AF_INET:
543142093Sume		port = ((struct sockaddr_in *)sa)->sin_port;
544142093Sume		break;
545142093Sume#ifdef INET6
546142093Sume	case AF_INET6:
547142093Sume		port = ((struct sockaddr_in6 *)sa)->sin6_port;
548142093Sume		break;
549142093Sume#endif
550142093Sume	default:
551142093Sume		port = 0;
552142093Sume		break;
553142093Sume	}
554142093Sume	snprintf(line, sizeof(line), "%.*s.", 16, inetname(sa));
555229403Sed	cp = strchr(line, '\0');
5561590Srgrimes	if (!nflag && port)
5571590Srgrimes		sp = getservbyport(port, proto);
5581590Srgrimes	if (sp || port == 0)
559158161Sbde		snprintf(cp, sizeof(line) - (cp - line), "%.8s",
56036789Simp		    sp ? sp->s_name : "*");
5611590Srgrimes	else
562158161Sbde		snprintf(cp, sizeof(line) - (cp - line), "%d",
56336789Simp		    ntohs((u_short)port));
5641590Srgrimes	/* pad to full column to clear any garbage */
565229403Sed	cp = strchr(line, '\0');
5661590Srgrimes	while (cp - line < 22)
5671590Srgrimes		*cp++ = ' ';
56819330Sphk	line[22] = '\0';
5691590Srgrimes	waddstr(wnd, line);
5701590Srgrimes}
5711590Srgrimes
5721590Srgrimes/*
5731590Srgrimes * Construct an Internet address representation.
5748874Srgrimes * If the nflag has been supplied, give
5751590Srgrimes * numeric value, otherwise try for symbolic name.
5761590Srgrimes */
5771590Srgrimesstatic char *
578175387Sdelphijinetname(struct sockaddr *sa)
5791590Srgrimes{
5801590Srgrimes	char *cp = 0;
581142093Sume	static char line[NI_MAXHOST];
5821590Srgrimes	struct hostent *hp;
5831590Srgrimes	struct netent *np;
584142093Sume	struct in_addr in;
5851590Srgrimes
586142093Sume#ifdef INET6
587142093Sume	if (sa->sa_family == AF_INET6) {
588142093Sume		if (memcmp(&((struct sockaddr_in6 *)sa)->sin6_addr,
589142093Sume		    &in6addr_any, sizeof(in6addr_any)) == 0)
590142093Sume			strcpy(line, "*");
591142093Sume		else
592142093Sume			getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0,
593142093Sume			    nflag ? NI_NUMERICHOST : 0);
594142093Sume		return (line);
595142093Sume	}
596142093Sume#endif
597142093Sume
598142093Sume	in = ((struct sockaddr_in *)sa)->sin_addr;
5991590Srgrimes	if (!nflag && in.s_addr != INADDR_ANY) {
6001590Srgrimes		int net = inet_netof(in);
6011590Srgrimes		int lna = inet_lnaof(in);
6021590Srgrimes
6031590Srgrimes		if (lna == INADDR_ANY) {
6041590Srgrimes			np = getnetbyaddr(net, AF_INET);
6051590Srgrimes			if (np)
6061590Srgrimes				cp = np->n_name;
6071590Srgrimes		}
6081590Srgrimes		if (cp == 0) {
6091590Srgrimes			hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
6101590Srgrimes			if (hp)
6111590Srgrimes				cp = hp->h_name;
6121590Srgrimes		}
6131590Srgrimes	}
6141590Srgrimes	if (in.s_addr == INADDR_ANY)
6151590Srgrimes		strcpy(line, "*");
6161590Srgrimes	else if (cp)
61736789Simp		snprintf(line, sizeof(line), "%s", cp);
6181590Srgrimes	else {
6191590Srgrimes		in.s_addr = ntohl(in.s_addr);
6201590Srgrimes#define C(x)	((x) & 0xff)
62136789Simp		snprintf(line, sizeof(line), "%u.%u.%u.%u", C(in.s_addr >> 24),
6221590Srgrimes			C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
6231590Srgrimes	}
6241590Srgrimes	return (line);
6251590Srgrimes}
6261590Srgrimes
6271590Srgrimesint
628175387Sdelphijcmdnetstat(const char *cmd, const char *args)
6291590Srgrimes{
6301590Srgrimes	if (prefix(cmd, "all")) {
6311590Srgrimes		aflag = !aflag;
6321590Srgrimes		goto fixup;
6331590Srgrimes	}
6341590Srgrimes	if  (prefix(cmd, "numbers") || prefix(cmd, "names")) {
63570523Sphk		struct netinfo *p;
6361590Srgrimes		int new;
6371590Srgrimes
6381590Srgrimes		new = prefix(cmd, "numbers");
6391590Srgrimes		if (new == nflag)
6401590Srgrimes			return (1);
64170523Sphk		TAILQ_FOREACH(p, &netcb, chain) {
6421590Srgrimes			if (p->ni_line == -1)
6431590Srgrimes				continue;
6441590Srgrimes			p->ni_flags |= NIF_LACHG|NIF_FACHG;
6451590Srgrimes		}
6461590Srgrimes		nflag = new;
6471590Srgrimes		goto redisplay;
6481590Srgrimes	}
6491590Srgrimes	if (!netcmd(cmd, args))
6501590Srgrimes		return (0);
6511590Srgrimesfixup:
6521590Srgrimes	fetchnetstat();
6531590Srgrimesredisplay:
6541590Srgrimes	shownetstat();
6551590Srgrimes	refresh();
6561590Srgrimes	return (1);
6571590Srgrimes}
658