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