netstat.c revision 7715
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 351590Srgrimesstatic char sccsid[] = "@(#)netstat.c 8.1 (Berkeley) 6/6/93"; 361590Srgrimes#endif /* not lint */ 371590Srgrimes 381590Srgrimes/* 391590Srgrimes * netstat 401590Srgrimes */ 411590Srgrimes#include <sys/param.h> 421590Srgrimes#include <sys/socket.h> 431590Srgrimes#include <sys/socketvar.h> 441590Srgrimes#include <sys/mbuf.h> 451590Srgrimes#include <sys/protosw.h> 467715Sdg#include <sys/queue.h> 471590Srgrimes 481590Srgrimes#include <netinet/in.h> 491590Srgrimes#include <net/route.h> 501590Srgrimes#include <netinet/in_systm.h> 511590Srgrimes#include <netinet/ip.h> 521590Srgrimes#include <netinet/in_pcb.h> 531590Srgrimes#include <netinet/ip_icmp.h> 541590Srgrimes#include <netinet/icmp_var.h> 551590Srgrimes#include <netinet/ip_var.h> 561590Srgrimes#include <netinet/tcp.h> 571590Srgrimes#include <netinet/tcpip.h> 581590Srgrimes#include <netinet/tcp_seq.h> 591590Srgrimes#define TCPSTATES 601590Srgrimes#include <netinet/tcp_fsm.h> 611590Srgrimes#include <netinet/tcp_timer.h> 621590Srgrimes#include <netinet/tcp_var.h> 631590Srgrimes#include <netinet/tcp_debug.h> 641590Srgrimes#include <netinet/udp.h> 651590Srgrimes#include <netinet/udp_var.h> 661590Srgrimes 671590Srgrimes#include <netdb.h> 681590Srgrimes#include <stdlib.h> 691590Srgrimes#include <string.h> 701590Srgrimes#include <nlist.h> 711590Srgrimes#include <paths.h> 721590Srgrimes#include "systat.h" 731590Srgrimes#include "extern.h" 741590Srgrimes 751590Srgrimesstatic void enter __P((struct inpcb *, struct socket *, int, char *)); 761590Srgrimesstatic char *inetname __P((struct in_addr)); 771590Srgrimesstatic void inetprint __P((struct in_addr *, int, char *)); 781590Srgrimes 791590Srgrimes#define streq(a,b) (strcmp(a,b)==0) 801590Srgrimes#define YMAX(w) ((w)->maxy-1) 811590Srgrimes 821590SrgrimesWINDOW * 831590Srgrimesopennetstat() 841590Srgrimes{ 851590Srgrimes sethostent(1); 861590Srgrimes setnetent(1); 871590Srgrimes return (subwin(stdscr, LINES-5-1, 0, 5, 0)); 881590Srgrimes} 891590Srgrimes 901590Srgrimesstruct netinfo { 911590Srgrimes struct netinfo *ni_forw, *ni_prev; 921590Srgrimes short ni_line; /* line on screen */ 931590Srgrimes short ni_seen; /* 0 when not present in list */ 941590Srgrimes short ni_flags; 951590Srgrimes#define NIF_LACHG 0x1 /* local address changed */ 961590Srgrimes#define NIF_FACHG 0x2 /* foreign address changed */ 971590Srgrimes short ni_state; /* tcp state */ 981590Srgrimes char *ni_proto; /* protocol */ 991590Srgrimes struct in_addr ni_laddr; /* local address */ 1001590Srgrimes long ni_lport; /* local port */ 1011590Srgrimes struct in_addr ni_faddr; /* foreign address */ 1021590Srgrimes long ni_fport; /* foreign port */ 1031590Srgrimes long ni_rcvcc; /* rcv buffer character count */ 1041590Srgrimes long ni_sndcc; /* snd buffer character count */ 1051590Srgrimes}; 1061590Srgrimes 1071590Srgrimesstatic struct { 1081590Srgrimes struct netinfo *ni_forw, *ni_prev; 1091590Srgrimes} netcb; 1101590Srgrimes 1111590Srgrimesstatic int aflag = 0; 1121590Srgrimesstatic int nflag = 0; 1131590Srgrimesstatic int lastrow = 1; 1141590Srgrimesstatic void enter(), inetprint(); 1151590Srgrimesstatic char *inetname(); 1161590Srgrimes 1171590Srgrimesvoid 1181590Srgrimesclosenetstat(w) 1191590Srgrimes WINDOW *w; 1201590Srgrimes{ 1211590Srgrimes register struct netinfo *p; 1221590Srgrimes 1231590Srgrimes endhostent(); 1241590Srgrimes endnetent(); 1251590Srgrimes p = (struct netinfo *)netcb.ni_forw; 1261590Srgrimes while (p != (struct netinfo *)&netcb) { 1271590Srgrimes if (p->ni_line != -1) 1281590Srgrimes lastrow--; 1291590Srgrimes p->ni_line = -1; 1301590Srgrimes p = p->ni_forw; 1311590Srgrimes } 1321590Srgrimes if (w != NULL) { 1331590Srgrimes wclear(w); 1341590Srgrimes wrefresh(w); 1351590Srgrimes delwin(w); 1361590Srgrimes } 1371590Srgrimes} 1381590Srgrimes 1391590Srgrimesstatic struct nlist namelist[] = { 1401590Srgrimes#define X_TCB 0 1411590Srgrimes { "_tcb" }, 1421590Srgrimes#define X_UDB 1 1431590Srgrimes { "_udb" }, 1441590Srgrimes { "" }, 1451590Srgrimes}; 1461590Srgrimes 1471590Srgrimesint 1481590Srgrimesinitnetstat() 1491590Srgrimes{ 1501590Srgrimes if (kvm_nlist(kd, namelist)) { 1511590Srgrimes nlisterr(namelist); 1521590Srgrimes return(0); 1531590Srgrimes } 1541590Srgrimes if (namelist[X_TCB].n_value == 0) { 1551590Srgrimes error("No symbols in namelist"); 1561590Srgrimes return(0); 1571590Srgrimes } 1581590Srgrimes netcb.ni_forw = netcb.ni_prev = (struct netinfo *)&netcb; 1591590Srgrimes protos = TCP|UDP; 1601590Srgrimes return(1); 1611590Srgrimes} 1621590Srgrimes 1631590Srgrimesvoid 1641590Srgrimesfetchnetstat() 1651590Srgrimes{ 1661590Srgrimes register struct inpcb *prev, *next; 1671590Srgrimes register struct netinfo *p; 1687715Sdg struct inpcbhead head; 1691590Srgrimes struct inpcb inpcb; 1701590Srgrimes struct socket sockb; 1711590Srgrimes struct tcpcb tcpcb; 1721590Srgrimes void *off; 1731590Srgrimes int istcp; 1741590Srgrimes 1751590Srgrimes if (namelist[X_TCB].n_value == 0) 1761590Srgrimes return; 1771590Srgrimes for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) 1781590Srgrimes p->ni_seen = 0; 1791590Srgrimes if (protos&TCP) { 1801590Srgrimes off = NPTR(X_TCB); 1811590Srgrimes istcp = 1; 1821590Srgrimes } 1831590Srgrimes else if (protos&UDP) { 1841590Srgrimes off = NPTR(X_UDB); 1851590Srgrimes istcp = 0; 1861590Srgrimes } 1871590Srgrimes else { 1881590Srgrimes error("No protocols to display"); 1891590Srgrimes return; 1901590Srgrimes } 1911590Srgrimesagain: 1927715Sdg KREAD(off, &head, sizeof (struct inpcbhead)); 1937715Sdg for (next = head.lh_first; next != NULL; next = inpcb.inp_list.le_next) { 1941590Srgrimes KREAD(next, &inpcb, sizeof (inpcb)); 1951590Srgrimes if (!aflag && inet_lnaof(inpcb.inp_laddr) == INADDR_ANY) 1961590Srgrimes continue; 1971590Srgrimes if (nhosts && !checkhost(&inpcb)) 1981590Srgrimes continue; 1991590Srgrimes if (nports && !checkport(&inpcb)) 2001590Srgrimes continue; 2011590Srgrimes KREAD(inpcb.inp_socket, &sockb, sizeof (sockb)); 2021590Srgrimes if (istcp) { 2031590Srgrimes KREAD(inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb)); 2041590Srgrimes enter(&inpcb, &sockb, tcpcb.t_state, "tcp"); 2051590Srgrimes } else 2061590Srgrimes enter(&inpcb, &sockb, 0, "udp"); 2071590Srgrimes } 2081590Srgrimes if (istcp && (protos&UDP)) { 2091590Srgrimes istcp = 0; 2101590Srgrimes off = NPTR(X_UDB); 2111590Srgrimes goto again; 2121590Srgrimes } 2131590Srgrimes} 2141590Srgrimes 2151590Srgrimesstatic void 2161590Srgrimesenter(inp, so, state, proto) 2171590Srgrimes register struct inpcb *inp; 2181590Srgrimes register struct socket *so; 2191590Srgrimes int state; 2201590Srgrimes char *proto; 2211590Srgrimes{ 2221590Srgrimes register struct netinfo *p; 2231590Srgrimes 2241590Srgrimes /* 2251590Srgrimes * Only take exact matches, any sockets with 2261590Srgrimes * previously unbound addresses will be deleted 2271590Srgrimes * below in the display routine because they 2281590Srgrimes * will appear as ``not seen'' in the kernel 2291590Srgrimes * data structures. 2301590Srgrimes */ 2311590Srgrimes for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) { 2321590Srgrimes if (!streq(proto, p->ni_proto)) 2331590Srgrimes continue; 2341590Srgrimes if (p->ni_lport != inp->inp_lport || 2351590Srgrimes p->ni_laddr.s_addr != inp->inp_laddr.s_addr) 2361590Srgrimes continue; 2371590Srgrimes if (p->ni_faddr.s_addr == inp->inp_faddr.s_addr && 2381590Srgrimes p->ni_fport == inp->inp_fport) 2391590Srgrimes break; 2401590Srgrimes } 2411590Srgrimes if (p == (struct netinfo *)&netcb) { 2421590Srgrimes if ((p = malloc(sizeof(*p))) == NULL) { 2431590Srgrimes error("Out of memory"); 2441590Srgrimes return; 2451590Srgrimes } 2461590Srgrimes p->ni_prev = (struct netinfo *)&netcb; 2471590Srgrimes p->ni_forw = netcb.ni_forw; 2481590Srgrimes netcb.ni_forw->ni_prev = p; 2491590Srgrimes netcb.ni_forw = p; 2501590Srgrimes p->ni_line = -1; 2511590Srgrimes p->ni_laddr = inp->inp_laddr; 2521590Srgrimes p->ni_lport = inp->inp_lport; 2531590Srgrimes p->ni_faddr = inp->inp_faddr; 2541590Srgrimes p->ni_fport = inp->inp_fport; 2551590Srgrimes p->ni_proto = proto; 2561590Srgrimes p->ni_flags = NIF_LACHG|NIF_FACHG; 2571590Srgrimes } 2581590Srgrimes p->ni_rcvcc = so->so_rcv.sb_cc; 2591590Srgrimes p->ni_sndcc = so->so_snd.sb_cc; 2601590Srgrimes p->ni_state = state; 2611590Srgrimes p->ni_seen = 1; 2621590Srgrimes} 2631590Srgrimes 2641590Srgrimes/* column locations */ 2651590Srgrimes#define LADDR 0 2661590Srgrimes#define FADDR LADDR+23 2671590Srgrimes#define PROTO FADDR+23 2681590Srgrimes#define RCVCC PROTO+6 2691590Srgrimes#define SNDCC RCVCC+7 2701590Srgrimes#define STATE SNDCC+7 2711590Srgrimes 2721590Srgrimes 2731590Srgrimesvoid 2741590Srgrimeslabelnetstat() 2751590Srgrimes{ 2761590Srgrimes if (namelist[X_TCB].n_type == 0) 2771590Srgrimes return; 2781590Srgrimes wmove(wnd, 0, 0); wclrtobot(wnd); 2791590Srgrimes mvwaddstr(wnd, 0, LADDR, "Local Address"); 2801590Srgrimes mvwaddstr(wnd, 0, FADDR, "Foreign Address"); 2811590Srgrimes mvwaddstr(wnd, 0, PROTO, "Proto"); 2821590Srgrimes mvwaddstr(wnd, 0, RCVCC, "Recv-Q"); 2831590Srgrimes mvwaddstr(wnd, 0, SNDCC, "Send-Q"); 2841590Srgrimes mvwaddstr(wnd, 0, STATE, "(state)"); 2851590Srgrimes} 2861590Srgrimes 2871590Srgrimesvoid 2881590Srgrimesshownetstat() 2891590Srgrimes{ 2901590Srgrimes register struct netinfo *p, *q; 2911590Srgrimes 2921590Srgrimes /* 2931590Srgrimes * First, delete any connections that have gone 2941590Srgrimes * away and adjust the position of connections 2951590Srgrimes * below to reflect the deleted line. 2961590Srgrimes */ 2971590Srgrimes p = netcb.ni_forw; 2981590Srgrimes while (p != (struct netinfo *)&netcb) { 2991590Srgrimes if (p->ni_line == -1 || p->ni_seen) { 3001590Srgrimes p = p->ni_forw; 3011590Srgrimes continue; 3021590Srgrimes } 3031590Srgrimes wmove(wnd, p->ni_line, 0); wdeleteln(wnd); 3041590Srgrimes q = netcb.ni_forw; 3051590Srgrimes for (; q != (struct netinfo *)&netcb; q = q->ni_forw) 3061590Srgrimes if (q != p && q->ni_line > p->ni_line) { 3071590Srgrimes q->ni_line--; 3081590Srgrimes /* this shouldn't be necessary */ 3091590Srgrimes q->ni_flags |= NIF_LACHG|NIF_FACHG; 3101590Srgrimes } 3111590Srgrimes lastrow--; 3121590Srgrimes q = p->ni_forw; 3131590Srgrimes p->ni_prev->ni_forw = p->ni_forw; 3141590Srgrimes p->ni_forw->ni_prev = p->ni_prev; 3151590Srgrimes free(p); 3161590Srgrimes p = q; 3171590Srgrimes } 3181590Srgrimes /* 3191590Srgrimes * Update existing connections and add new ones. 3201590Srgrimes */ 3211590Srgrimes for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) { 3221590Srgrimes if (p->ni_line == -1) { 3231590Srgrimes /* 3241590Srgrimes * Add a new entry if possible. 3251590Srgrimes */ 3261590Srgrimes if (lastrow > YMAX(wnd)) 3271590Srgrimes continue; 3281590Srgrimes p->ni_line = lastrow++; 3291590Srgrimes p->ni_flags |= NIF_LACHG|NIF_FACHG; 3301590Srgrimes } 3311590Srgrimes if (p->ni_flags & NIF_LACHG) { 3321590Srgrimes wmove(wnd, p->ni_line, LADDR); 3331590Srgrimes inetprint(&p->ni_laddr, p->ni_lport, p->ni_proto); 3341590Srgrimes p->ni_flags &= ~NIF_LACHG; 3351590Srgrimes } 3361590Srgrimes if (p->ni_flags & NIF_FACHG) { 3371590Srgrimes wmove(wnd, p->ni_line, FADDR); 3381590Srgrimes inetprint(&p->ni_faddr, p->ni_fport, p->ni_proto); 3391590Srgrimes p->ni_flags &= ~NIF_FACHG; 3401590Srgrimes } 3411590Srgrimes mvwaddstr(wnd, p->ni_line, PROTO, p->ni_proto); 3421590Srgrimes mvwprintw(wnd, p->ni_line, RCVCC, "%6d", p->ni_rcvcc); 3431590Srgrimes mvwprintw(wnd, p->ni_line, SNDCC, "%6d", p->ni_sndcc); 3441590Srgrimes if (streq(p->ni_proto, "tcp")) 3451590Srgrimes if (p->ni_state < 0 || p->ni_state >= TCP_NSTATES) 3461590Srgrimes mvwprintw(wnd, p->ni_line, STATE, "%d", 3471590Srgrimes p->ni_state); 3481590Srgrimes else 3491590Srgrimes mvwaddstr(wnd, p->ni_line, STATE, 3501590Srgrimes tcpstates[p->ni_state]); 3511590Srgrimes wclrtoeol(wnd); 3521590Srgrimes } 3531590Srgrimes if (lastrow < YMAX(wnd)) { 3541590Srgrimes wmove(wnd, lastrow, 0); wclrtobot(wnd); 3551590Srgrimes wmove(wnd, YMAX(wnd), 0); wdeleteln(wnd); /* XXX */ 3561590Srgrimes } 3571590Srgrimes} 3581590Srgrimes 3591590Srgrimes/* 3601590Srgrimes * Pretty print an Internet address (net address + port). 3611590Srgrimes * If the nflag was specified, use numbers instead of names. 3621590Srgrimes */ 3631590Srgrimesstatic void 3641590Srgrimesinetprint(in, port, proto) 3651590Srgrimes register struct in_addr *in; 3661590Srgrimes int port; 3671590Srgrimes char *proto; 3681590Srgrimes{ 3691590Srgrimes struct servent *sp = 0; 3701590Srgrimes char line[80], *cp, *index(); 3711590Srgrimes 3721590Srgrimes sprintf(line, "%.*s.", 16, inetname(*in)); 3731590Srgrimes cp = index(line, '\0'); 3741590Srgrimes if (!nflag && port) 3751590Srgrimes sp = getservbyport(port, proto); 3761590Srgrimes if (sp || port == 0) 3771590Srgrimes sprintf(cp, "%.8s", sp ? sp->s_name : "*"); 3781590Srgrimes else 3791590Srgrimes sprintf(cp, "%d", ntohs((u_short)port)); 3801590Srgrimes /* pad to full column to clear any garbage */ 3811590Srgrimes cp = index(line, '\0'); 3821590Srgrimes while (cp - line < 22) 3831590Srgrimes *cp++ = ' '; 3841590Srgrimes *cp = '\0'; 3851590Srgrimes waddstr(wnd, line); 3861590Srgrimes} 3871590Srgrimes 3881590Srgrimes/* 3891590Srgrimes * Construct an Internet address representation. 3901590Srgrimes * If the nflag has been supplied, give 3911590Srgrimes * numeric value, otherwise try for symbolic name. 3921590Srgrimes */ 3931590Srgrimesstatic char * 3941590Srgrimesinetname(in) 3951590Srgrimes struct in_addr in; 3961590Srgrimes{ 3971590Srgrimes char *cp = 0; 3981590Srgrimes static char line[50]; 3991590Srgrimes struct hostent *hp; 4001590Srgrimes struct netent *np; 4011590Srgrimes 4021590Srgrimes if (!nflag && in.s_addr != INADDR_ANY) { 4031590Srgrimes int net = inet_netof(in); 4041590Srgrimes int lna = inet_lnaof(in); 4051590Srgrimes 4061590Srgrimes if (lna == INADDR_ANY) { 4071590Srgrimes np = getnetbyaddr(net, AF_INET); 4081590Srgrimes if (np) 4091590Srgrimes cp = np->n_name; 4101590Srgrimes } 4111590Srgrimes if (cp == 0) { 4121590Srgrimes hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET); 4131590Srgrimes if (hp) 4141590Srgrimes cp = hp->h_name; 4151590Srgrimes } 4161590Srgrimes } 4171590Srgrimes if (in.s_addr == INADDR_ANY) 4181590Srgrimes strcpy(line, "*"); 4191590Srgrimes else if (cp) 4201590Srgrimes strcpy(line, cp); 4211590Srgrimes else { 4221590Srgrimes in.s_addr = ntohl(in.s_addr); 4231590Srgrimes#define C(x) ((x) & 0xff) 4241590Srgrimes sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 4251590Srgrimes C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr)); 4261590Srgrimes } 4271590Srgrimes return (line); 4281590Srgrimes} 4291590Srgrimes 4301590Srgrimesint 4311590Srgrimescmdnetstat(cmd, args) 4321590Srgrimes char *cmd, *args; 4331590Srgrimes{ 4341590Srgrimes register struct netinfo *p; 4351590Srgrimes 4361590Srgrimes if (prefix(cmd, "all")) { 4371590Srgrimes aflag = !aflag; 4381590Srgrimes goto fixup; 4391590Srgrimes } 4401590Srgrimes if (prefix(cmd, "numbers") || prefix(cmd, "names")) { 4411590Srgrimes int new; 4421590Srgrimes 4431590Srgrimes new = prefix(cmd, "numbers"); 4441590Srgrimes if (new == nflag) 4451590Srgrimes return (1); 4461590Srgrimes p = netcb.ni_forw; 4471590Srgrimes for (; p != (struct netinfo *)&netcb; p = p->ni_forw) { 4481590Srgrimes if (p->ni_line == -1) 4491590Srgrimes continue; 4501590Srgrimes p->ni_flags |= NIF_LACHG|NIF_FACHG; 4511590Srgrimes } 4521590Srgrimes nflag = new; 4531590Srgrimes goto redisplay; 4541590Srgrimes } 4551590Srgrimes if (!netcmd(cmd, args)) 4561590Srgrimes return (0); 4571590Srgrimesfixup: 4581590Srgrimes fetchnetstat(); 4591590Srgrimesredisplay: 4601590Srgrimes shownetstat(); 4611590Srgrimes refresh(); 4621590Srgrimes return (1); 4631590Srgrimes} 464