|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.