1: /*
   2:  * Copyright (c) 1980 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #ifndef lint
   8: static char sccsid[] = "@(#)netstat.c	5.2 (Berkeley) 12/11/85";
   9: #endif not lint
  10: 
  11: /*
  12:  * netstat
  13:  */
  14: #include "systat.h"
  15: 
  16: #include <sys/socket.h>
  17: #include <sys/socketvar.h>
  18: #include <sys/mbuf.h>
  19: #include <sys/protosw.h>
  20: 
  21: #include <net/route.h>
  22: #include <netinet/in_systm.h>
  23: #include <netinet/in_pcb.h>
  24: #include <netinet/ip.h>
  25: #include <netinet/ip_icmp.h>
  26: #include <netinet/icmp_var.h>
  27: #include <netinet/ip_var.h>
  28: #include <netinet/tcp.h>
  29: #include <netinet/tcpip.h>
  30: #include <netinet/tcp_seq.h>
  31: #define TCPSTATES
  32: #include <netinet/tcp_fsm.h>
  33: #include <netinet/tcp_timer.h>
  34: #include <netinet/tcp_var.h>
  35: #include <netinet/tcp_debug.h>
  36: #include <netinet/udp.h>
  37: #include <netinet/udp_var.h>
  38: 
  39: #define streq(a,b)  (strcmp(a,b)==0)
  40: #define YMAX(w)     ((w)->_maxy-1)
  41: 
  42: WINDOW *
  43: opennetstat()
  44: {
  45: 
  46:     sethostent(1);
  47:     setnetent(1);
  48:     return (subwin(stdscr, LINES-5-1, 0, 5, 0));
  49: }
  50: 
  51: struct netinfo {
  52:     struct  netinfo *ni_forw, *ni_prev;
  53:     short   ni_line;        /* line on screen */
  54:     short   ni_seen;        /* 0 when not present in list */
  55:     short   ni_flags;
  56: #define NIF_LACHG   0x1     /* local address changed */
  57: #define NIF_FACHG   0x2     /* foreign address changed */
  58:     short   ni_state;       /* tcp state */
  59:     char    *ni_proto;      /* protocol */
  60:     struct  in_addr ni_laddr;   /* local address */
  61:     long    ni_lport;       /* local port */
  62:     struct  in_addr ni_faddr;   /* foreign address */
  63:     long    ni_fport;       /* foreign port */
  64:     long    ni_rcvcc;       /* rcv buffer character count */
  65:     long    ni_sndcc;       /* snd buffer character count */
  66: };
  67: 
  68: static struct {
  69:     struct  netinfo *ni_forw, *ni_prev;
  70: } netcb;
  71: 
  72: static  int aflag = 0;
  73: static  int nflag = 0;
  74: static  int lastrow = 1;
  75: static  char *inetname();
  76: 
  77: closenetstat(w)
  78:         WINDOW *w;
  79: {
  80:     register struct netinfo *p;
  81: 
  82:     endhostent();
  83:     endnetent();
  84:     p = netcb.ni_forw;
  85:     while (p != (struct netinfo *)&netcb) {
  86:         if (p->ni_line != -1)
  87:             lastrow--;
  88:         p->ni_line = -1;
  89:         p = p->ni_forw;
  90:     }
  91:         if (w != NULL) {
  92:         wclear(w);
  93:         wrefresh(w);
  94:         delwin(w);
  95:     }
  96: }
  97: 
  98: static struct nlist nlst[] = {
  99: #define X_TCB   0
 100:     { "_tcb" },
 101: #define X_UDB   1
 102:     { "_udb" },
 103:         { "" },
 104: };
 105: 
 106: initnetstat()
 107: {
 108: 
 109:     nlist("/vmunix", nlst);
 110:     if (nlst[X_TCB].n_value == 0) {
 111:         error("No symbols in namelist");
 112:         return(0);
 113:     }
 114:     netcb.ni_forw = netcb.ni_prev = (struct netinfo *)&netcb;
 115:     protos = TCP|UDP;
 116:     return(1);
 117: }
 118: 
 119: fetchnetstat()
 120: {
 121:     register struct inpcb *prev, *next;
 122:     register struct netinfo *p;
 123:     struct inpcb inpcb;
 124:     struct socket sockb;
 125:     struct tcpcb tcpcb;
 126:     off_t off;
 127:     int istcp;
 128: 
 129:     if (nlst[X_TCB].n_value == 0)
 130:         return;
 131:     for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw)
 132:         p->ni_seen = 0;
 133:     if (protos == 0)
 134:         error("No protocols to display");
 135:     if (protos&TCP)
 136:         off = nlst[X_TCB].n_value, istcp = 1;
 137:     else if (protos&UDP)
 138:         off = nlst[X_UDB].n_value, istcp = 0;
 139: again:
 140:     lseek(kmem, off, L_SET);
 141:     read(kmem, &inpcb, sizeof (struct inpcb));
 142:     prev = (struct inpcb *)off;
 143:     for (; inpcb.inp_next != (struct inpcb *)off; prev = next) {
 144:         next = inpcb.inp_next;
 145:         lseek(kmem, (off_t)next, L_SET);
 146:         read(kmem, &inpcb, sizeof (inpcb));
 147:         if (inpcb.inp_prev != prev) {
 148:             p = netcb.ni_forw;
 149:             for (; p != (struct netinfo *)&netcb; p = p->ni_forw)
 150:                 p->ni_seen = 1;
 151:             error("Kernel state in transition");
 152:             return;
 153:         }
 154:         if (!aflag && inet_lnaof(inpcb.inp_laddr) == INADDR_ANY)
 155:             continue;
 156:         if (nhosts && !checkhost(&inpcb))
 157:             continue;
 158:         if (nports && !checkport(&inpcb))
 159:             continue;
 160:         lseek(kmem, (off_t)inpcb.inp_socket, L_SET);
 161:         read(kmem, &sockb, sizeof (sockb));
 162:         lseek(kmem, (off_t)inpcb.inp_ppcb, L_SET);
 163:         if (istcp) {
 164:             read(kmem, &tcpcb, sizeof (tcpcb));
 165:             enter(&inpcb, &sockb, tcpcb.t_state, "tcp");
 166:         } else
 167:             enter(&inpcb, &sockb, 0, "udp");
 168:     }
 169:     if (istcp && (protos&UDP)) {
 170:         istcp = 0;
 171:         off = nlst[X_UDB].n_value;
 172:         goto again;
 173:     }
 174: }
 175: 
 176: static
 177: enter(inp, so, state, proto)
 178:     register struct inpcb *inp;
 179:     register struct socket *so;
 180:     int state;
 181:     char *proto;
 182: {
 183:     register struct netinfo *p;
 184: 
 185:     /*
 186: 	 * Only take exact matches, any sockets with
 187: 	 * previously unbound addresses will be deleted
 188: 	 * below in the display routine because they
 189: 	 * will appear as ``not seen'' in the kernel
 190: 	 * data structures.
 191: 	 */
 192:     for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) {
 193:         if (!streq(proto, p->ni_proto))
 194:             continue;
 195:         if (p->ni_lport != inp->inp_lport ||
 196:             p->ni_laddr.s_addr != inp->inp_laddr.s_addr)
 197:             continue;
 198:         if (p->ni_faddr.s_addr == inp->inp_faddr.s_addr &&
 199:             p->ni_fport == inp->inp_fport)
 200:             break;
 201:     }
 202:     if (p == (struct netinfo *)&netcb) {
 203:         p = (struct netinfo *)malloc(sizeof (*p));
 204:         if (p == 0) {
 205:             error("Out of memory");
 206:             return;
 207:         }
 208:         insque(p, &netcb);
 209:         p->ni_line = -1;
 210:         p->ni_laddr = inp->inp_laddr;
 211:         p->ni_lport = inp->inp_lport;
 212:         p->ni_faddr = inp->inp_faddr;
 213:         p->ni_fport = inp->inp_fport;
 214:         p->ni_proto = proto;
 215:         p->ni_flags = NIF_LACHG|NIF_FACHG;
 216:     }
 217:     p->ni_rcvcc = so->so_rcv.sb_cc;
 218:     p->ni_sndcc = so->so_snd.sb_cc;
 219:     p->ni_state = state;
 220:     p->ni_seen = 1;
 221: }
 222: 
 223: /* column locations */
 224: #define LADDR   0
 225: #define FADDR   LADDR+23
 226: #define PROTO   FADDR+23
 227: #define RCVCC   PROTO+6
 228: #define SNDCC   RCVCC+7
 229: #define STATE   SNDCC+7
 230: 
 231: labelnetstat()
 232: {
 233: 
 234:         if (nlst[X_TCB].n_type == 0)
 235:                 return;
 236:         wmove(wnd, 0, 0); wclrtobot(wnd);
 237:     mvwaddstr(wnd, 0, LADDR, "Local Address");
 238:     mvwaddstr(wnd, 0, FADDR, "Foreign Address");
 239:     mvwaddstr(wnd, 0, PROTO, "Proto");
 240:     mvwaddstr(wnd, 0, RCVCC, "Recv-Q");
 241:     mvwaddstr(wnd, 0, SNDCC, "Send-Q");
 242:     mvwaddstr(wnd, 0, STATE, "(state)");
 243: }
 244: 
 245: shownetstat()
 246: {
 247:     register struct netinfo *p, *q;
 248: 
 249:     /*
 250: 	 * First, delete any connections that have gone
 251: 	 * away and adjust the position of connections
 252: 	 * below to reflect the deleted line.
 253: 	 */
 254:     p = netcb.ni_forw;
 255:     while (p != (struct netinfo *)&netcb) {
 256:         if (p->ni_line == -1 || p->ni_seen) {
 257:             p = p->ni_forw;
 258:             continue;
 259:         }
 260:         wmove(wnd, p->ni_line, 0); wdeleteln(wnd);
 261:         q = netcb.ni_forw;
 262:         for (; q != (struct netinfo *)&netcb; q = q->ni_forw)
 263:             if (q != p && q->ni_line > p->ni_line) {
 264:                 q->ni_line--;
 265:                 /* this shouldn't be necessary */
 266:                 q->ni_flags |= NIF_LACHG|NIF_FACHG;
 267:             }
 268:         lastrow--;
 269:         q = p->ni_forw;
 270:         remque(p);
 271:         free((char *)p);
 272:         p = q;
 273:     }
 274:     /*
 275: 	 * Update existing connections and add new ones.
 276: 	 */
 277:     for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) {
 278:         if (p->ni_line == -1) {
 279:             /*
 280: 			 * Add a new entry if possible.
 281: 			 */
 282:             if (lastrow > YMAX(wnd))
 283:                 continue;
 284:             p->ni_line = lastrow++;
 285:             p->ni_flags |= NIF_LACHG|NIF_FACHG;
 286:         }
 287:         if (p->ni_flags & NIF_LACHG) {
 288:             wmove(wnd, p->ni_line, LADDR);
 289:             inetprint(&p->ni_laddr, p->ni_lport, p->ni_proto);
 290:             p->ni_flags &= ~NIF_LACHG;
 291:         }
 292:         if (p->ni_flags & NIF_FACHG) {
 293:             wmove(wnd, p->ni_line, FADDR);
 294:             inetprint(&p->ni_faddr, p->ni_fport, p->ni_proto);
 295:             p->ni_flags &= ~NIF_FACHG;
 296:         }
 297:         mvwaddstr(wnd, p->ni_line, PROTO, p->ni_proto);
 298:         mvwprintw(wnd, p->ni_line, RCVCC, "%6d", p->ni_rcvcc);
 299:         mvwprintw(wnd, p->ni_line, SNDCC, "%6d", p->ni_sndcc);
 300:         if (streq(p->ni_proto, "tcp"))
 301:             if (p->ni_state < 0 || p->ni_state >= TCP_NSTATES)
 302:                 mvwprintw(wnd, p->ni_line, STATE, "%d",
 303:                     p->ni_state);
 304:             else
 305:                 mvwaddstr(wnd, p->ni_line, STATE,
 306:                     tcpstates[p->ni_state]);
 307:         wclrtoeol(wnd);
 308:     }
 309:     if (lastrow < YMAX(wnd)) {
 310:         wmove(wnd, lastrow, 0); wclrtobot(wnd);
 311:         wmove(wnd, YMAX(wnd), 0); wdeleteln(wnd);   /* XXX */
 312:     }
 313: }
 314: 
 315: /*
 316:  * Pretty print an Internet address (net address + port).
 317:  * If the nflag was specified, use numbers instead of names.
 318:  */
 319: static
 320: inetprint(in, port, proto)
 321:     register struct in_addr *in;
 322:     int port;
 323:     char *proto;
 324: {
 325:     struct servent *sp = 0;
 326:     char line[80], *cp, *index();
 327: 
 328:     sprintf(line, "%.*s.", 16, inetname(*in));
 329:     cp = index(line, '\0');
 330:     if (!nflag && port)
 331:         sp = getservbyport(port, proto);
 332:     if (sp || port == 0)
 333:         sprintf(cp, "%.8s", sp ? sp->s_name : "*");
 334:     else
 335:         sprintf(cp, "%d", ntohs((u_short)port));
 336:     /* pad to full column to clear any garbage */
 337:     cp = index(line, '\0');
 338:     while (cp - line < 22)
 339:         *cp++ = ' ';
 340:     *cp = '\0';
 341:     waddstr(wnd, line);
 342: }
 343: 
 344: /*
 345:  * Construct an Internet address representation.
 346:  * If the nflag has been supplied, give
 347:  * numeric value, otherwise try for symbolic name.
 348:  */
 349: static char *
 350: inetname(in)
 351:     struct in_addr in;
 352: {
 353:     char *cp = 0;
 354:     static char line[50];
 355:     struct hostent *hp;
 356:     struct netent *np;
 357: 
 358:     if (!nflag && in.s_addr != INADDR_ANY) {
 359:         int net = inet_netof(in);
 360:         int lna = inet_lnaof(in);
 361: 
 362:         if (lna == INADDR_ANY) {
 363:             np = getnetbyaddr(net, AF_INET);
 364:             if (np)
 365:                 cp = np->n_name;
 366:         }
 367:         if (cp == 0) {
 368:             hp = gethostbyaddr(&in, sizeof (in), AF_INET);
 369:             if (hp)
 370:                 cp = hp->h_name;
 371:         }
 372:     }
 373:     if (in.s_addr == INADDR_ANY)
 374:         strcpy(line, "*");
 375:     else if (cp)
 376:         strcpy(line, cp);
 377:     else {
 378:         in.s_addr = ntohl(in.s_addr);
 379: #define C(x)    ((x) & 0xff)
 380:         sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
 381:             C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
 382:     }
 383:     return (line);
 384: }
 385: 
 386: cmdnetstat(cmd, args)
 387:         char *cmd, *args;
 388: {
 389:     register struct netinfo *p;
 390: 
 391:     if (prefix(cmd, "all")) {
 392:         aflag = !aflag;
 393:         goto fixup;
 394:     }
 395:     if  (prefix(cmd, "numbers") || prefix(cmd, "names")) {
 396:         int new;
 397: 
 398:         new = prefix(cmd, "numbers");
 399:         if (new == nflag)
 400:             return (1);
 401:         p = netcb.ni_forw;
 402:         for (; p != (struct netinfo *)&netcb; p = p->ni_forw) {
 403:             if (p->ni_line == -1)
 404:                 continue;
 405:             p->ni_flags |= NIF_LACHG|NIF_FACHG;
 406:         }
 407:         nflag = new;
 408:         goto redisplay;
 409:     }
 410:     if (!netcmd(cmd, args))
 411:         return (0);
 412: fixup:
 413:     fetchnetstat();
 414: redisplay:
 415:     shownetstat();
 416:     refresh();
 417:     return (1);
 418: }

Defined functions

closenetstat defined in line 77; used 2 times
cmdnetstat defined in line 386; used 2 times
enter defined in line 176; used 2 times
fetchnetstat defined in line 119; used 3 times
inetname defined in line 349; used 2 times
inetprint defined in line 319; used 2 times
initnetstat defined in line 106; used 2 times
labelnetstat defined in line 231; used 2 times
opennetstat defined in line 42; used 2 times
shownetstat defined in line 245; used 3 times

Defined variables

aflag defined in line 72; used 3 times
lastrow defined in line 74; used 6 times
nflag defined in line 73; used 4 times
nlst defined in line 98; used 7 times
sccsid defined in line 8; never used

Defined struct's

netinfo defined in line 51; used 36 times

Defined macros

C defined in line 379; used 4 times
FADDR defined in line 225; used 3 times
LADDR defined in line 224; used 3 times
NIF_FACHG defined in line 57; used 6 times
NIF_LACHG defined in line 56; used 6 times
PROTO defined in line 226; used 3 times
RCVCC defined in line 227; used 3 times
SNDCC defined in line 228; used 3 times
STATE defined in line 229; used 3 times
TCPSTATES defined in line 31; never used
X_TCB defined in line 99; used 4 times
X_UDB defined in line 101; used 2 times
YMAX defined in line 40; used 3 times
streq defined in line 39; used 2 times
Last modified: 1986-01-11
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2128
Valid CSS Valid XHTML 1.0 Strict