|
|
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.4 (Berkeley) 4/11/90"; ! 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/ip.h> ! 24: #include <netinet/in_pcb.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: #include <paths.h> ! 39: ! 40: #define streq(a,b) (strcmp(a,b)==0) ! 41: #define YMAX(w) ((w)->_maxy-1) ! 42: ! 43: WINDOW * ! 44: opennetstat() ! 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: nlist(_PATH_UNIX, nlst); ! 109: if (nlst[X_TCB].n_value == 0) { ! 110: error("No symbols in namelist"); ! 111: return(0); ! 112: } ! 113: netcb.ni_forw = netcb.ni_prev = (struct netinfo *)&netcb; ! 114: protos = TCP|UDP; ! 115: return(1); ! 116: } ! 117: ! 118: fetchnetstat() ! 119: { ! 120: register struct inpcb *prev, *next; ! 121: register struct netinfo *p; ! 122: struct inpcb inpcb; ! 123: struct socket sockb; ! 124: struct tcpcb tcpcb; ! 125: off_t off; ! 126: int istcp; ! 127: ! 128: if (nlst[X_TCB].n_value == 0) ! 129: return; ! 130: for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) ! 131: p->ni_seen = 0; ! 132: if (protos == 0) ! 133: error("No protocols to display"); ! 134: if (protos&TCP) ! 135: off = nlst[X_TCB].n_value, istcp = 1; ! 136: else if (protos&UDP) ! 137: off = nlst[X_UDB].n_value, istcp = 0; ! 138: again: ! 139: lseek(kmem, off, L_SET); ! 140: read(kmem, &inpcb, sizeof (struct inpcb)); ! 141: prev = (struct inpcb *)off; ! 142: for (; inpcb.inp_next != (struct inpcb *)off; prev = next) { ! 143: next = inpcb.inp_next; ! 144: lseek(kmem, (off_t)next, L_SET); ! 145: read(kmem, &inpcb, sizeof (inpcb)); ! 146: if (inpcb.inp_prev != prev) { ! 147: p = netcb.ni_forw; ! 148: for (; p != (struct netinfo *)&netcb; p = p->ni_forw) ! 149: p->ni_seen = 1; ! 150: error("Kernel state in transition"); ! 151: return; ! 152: } ! 153: if (!aflag && inet_lnaof(inpcb.inp_laddr) == INADDR_ANY) ! 154: continue; ! 155: if (nhosts && !checkhost(&inpcb)) ! 156: continue; ! 157: if (nports && !checkport(&inpcb)) ! 158: continue; ! 159: lseek(kmem, (off_t)inpcb.inp_socket, L_SET); ! 160: read(kmem, &sockb, sizeof (sockb)); ! 161: lseek(kmem, (off_t)inpcb.inp_ppcb, L_SET); ! 162: if (istcp) { ! 163: read(kmem, &tcpcb, sizeof (tcpcb)); ! 164: enter(&inpcb, &sockb, tcpcb.t_state, "tcp"); ! 165: } else ! 166: enter(&inpcb, &sockb, 0, "udp"); ! 167: } ! 168: if (istcp && (protos&UDP)) { ! 169: istcp = 0; ! 170: off = nlst[X_UDB].n_value; ! 171: goto again; ! 172: } ! 173: } ! 174: ! 175: static ! 176: enter(inp, so, state, proto) ! 177: register struct inpcb *inp; ! 178: register struct socket *so; ! 179: int state; ! 180: char *proto; ! 181: { ! 182: register struct netinfo *p; ! 183: ! 184: /* ! 185: * Only take exact matches, any sockets with ! 186: * previously unbound addresses will be deleted ! 187: * below in the display routine because they ! 188: * will appear as ``not seen'' in the kernel ! 189: * data structures. ! 190: */ ! 191: for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) { ! 192: if (!streq(proto, p->ni_proto)) ! 193: continue; ! 194: if (p->ni_lport != inp->inp_lport || ! 195: p->ni_laddr.s_addr != inp->inp_laddr.s_addr) ! 196: continue; ! 197: if (p->ni_faddr.s_addr == inp->inp_faddr.s_addr && ! 198: p->ni_fport == inp->inp_fport) ! 199: break; ! 200: } ! 201: if (p == (struct netinfo *)&netcb) { ! 202: p = (struct netinfo *)malloc(sizeof (*p)); ! 203: if (p == 0) { ! 204: error("Out of memory"); ! 205: return; ! 206: } ! 207: insque(p, &netcb); ! 208: p->ni_line = -1; ! 209: p->ni_laddr = inp->inp_laddr; ! 210: p->ni_lport = inp->inp_lport; ! 211: p->ni_faddr = inp->inp_faddr; ! 212: p->ni_fport = inp->inp_fport; ! 213: p->ni_proto = proto; ! 214: p->ni_flags = NIF_LACHG|NIF_FACHG; ! 215: } ! 216: p->ni_rcvcc = so->so_rcv.sb_cc; ! 217: p->ni_sndcc = so->so_snd.sb_cc; ! 218: p->ni_state = state; ! 219: p->ni_seen = 1; ! 220: } ! 221: ! 222: /* column locations */ ! 223: #define LADDR 0 ! 224: #define FADDR LADDR+23 ! 225: #define PROTO FADDR+23 ! 226: #define RCVCC PROTO+6 ! 227: #define SNDCC RCVCC+7 ! 228: #define STATE SNDCC+7 ! 229: ! 230: labelnetstat() ! 231: { ! 232: if (nlst[X_TCB].n_type == 0) ! 233: return; ! 234: wmove(wnd, 0, 0); wclrtobot(wnd); ! 235: mvwaddstr(wnd, 0, LADDR, "Local Address"); ! 236: mvwaddstr(wnd, 0, FADDR, "Foreign Address"); ! 237: mvwaddstr(wnd, 0, PROTO, "Proto"); ! 238: mvwaddstr(wnd, 0, RCVCC, "Recv-Q"); ! 239: mvwaddstr(wnd, 0, SNDCC, "Send-Q"); ! 240: mvwaddstr(wnd, 0, STATE, "(state)"); ! 241: } ! 242: ! 243: shownetstat() ! 244: { ! 245: register struct netinfo *p, *q; ! 246: ! 247: /* ! 248: * First, delete any connections that have gone ! 249: * away and adjust the position of connections ! 250: * below to reflect the deleted line. ! 251: */ ! 252: p = netcb.ni_forw; ! 253: while (p != (struct netinfo *)&netcb) { ! 254: if (p->ni_line == -1 || p->ni_seen) { ! 255: p = p->ni_forw; ! 256: continue; ! 257: } ! 258: wmove(wnd, p->ni_line, 0); wdeleteln(wnd); ! 259: q = netcb.ni_forw; ! 260: for (; q != (struct netinfo *)&netcb; q = q->ni_forw) ! 261: if (q != p && q->ni_line > p->ni_line) { ! 262: q->ni_line--; ! 263: /* this shouldn't be necessary */ ! 264: q->ni_flags |= NIF_LACHG|NIF_FACHG; ! 265: } ! 266: lastrow--; ! 267: q = p->ni_forw; ! 268: remque(p); ! 269: free((char *)p); ! 270: p = q; ! 271: } ! 272: /* ! 273: * Update existing connections and add new ones. ! 274: */ ! 275: for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) { ! 276: if (p->ni_line == -1) { ! 277: /* ! 278: * Add a new entry if possible. ! 279: */ ! 280: if (lastrow > YMAX(wnd)) ! 281: continue; ! 282: p->ni_line = lastrow++; ! 283: p->ni_flags |= NIF_LACHG|NIF_FACHG; ! 284: } ! 285: if (p->ni_flags & NIF_LACHG) { ! 286: wmove(wnd, p->ni_line, LADDR); ! 287: inetprint(&p->ni_laddr, p->ni_lport, p->ni_proto); ! 288: p->ni_flags &= ~NIF_LACHG; ! 289: } ! 290: if (p->ni_flags & NIF_FACHG) { ! 291: wmove(wnd, p->ni_line, FADDR); ! 292: inetprint(&p->ni_faddr, p->ni_fport, p->ni_proto); ! 293: p->ni_flags &= ~NIF_FACHG; ! 294: } ! 295: mvwaddstr(wnd, p->ni_line, PROTO, p->ni_proto); ! 296: mvwprintw(wnd, p->ni_line, RCVCC, "%6d", p->ni_rcvcc); ! 297: mvwprintw(wnd, p->ni_line, SNDCC, "%6d", p->ni_sndcc); ! 298: if (streq(p->ni_proto, "tcp")) ! 299: if (p->ni_state < 0 || p->ni_state >= TCP_NSTATES) ! 300: mvwprintw(wnd, p->ni_line, STATE, "%d", ! 301: p->ni_state); ! 302: else ! 303: mvwaddstr(wnd, p->ni_line, STATE, ! 304: tcpstates[p->ni_state]); ! 305: wclrtoeol(wnd); ! 306: } ! 307: if (lastrow < YMAX(wnd)) { ! 308: wmove(wnd, lastrow, 0); wclrtobot(wnd); ! 309: wmove(wnd, YMAX(wnd), 0); wdeleteln(wnd); /* XXX */ ! 310: } ! 311: } ! 312: ! 313: /* ! 314: * Pretty print an Internet address (net address + port). ! 315: * If the nflag was specified, use numbers instead of names. ! 316: */ ! 317: static ! 318: inetprint(in, port, proto) ! 319: register struct in_addr *in; ! 320: int port; ! 321: char *proto; ! 322: { ! 323: struct servent *sp = 0; ! 324: char line[80], *cp, *index(); ! 325: ! 326: sprintf(line, "%.*s.", 16, inetname(*in)); ! 327: cp = index(line, '\0'); ! 328: if (!nflag && port) ! 329: sp = getservbyport(port, proto); ! 330: if (sp || port == 0) ! 331: sprintf(cp, "%.8s", sp ? sp->s_name : "*"); ! 332: else ! 333: sprintf(cp, "%d", ntohs((u_short)port)); ! 334: /* pad to full column to clear any garbage */ ! 335: cp = index(line, '\0'); ! 336: while (cp - line < 22) ! 337: *cp++ = ' '; ! 338: *cp = '\0'; ! 339: waddstr(wnd, line); ! 340: } ! 341: ! 342: /* ! 343: * Construct an Internet address representation. ! 344: * If the nflag has been supplied, give ! 345: * numeric value, otherwise try for symbolic name. ! 346: */ ! 347: static char * ! 348: inetname(in) ! 349: struct in_addr in; ! 350: { ! 351: char *cp = 0; ! 352: static char line[50]; ! 353: struct hostent *hp; ! 354: struct netent *np; ! 355: ! 356: if (!nflag && in.s_addr != INADDR_ANY) { ! 357: int net = inet_netof(in); ! 358: int lna = inet_lnaof(in); ! 359: ! 360: if (lna == INADDR_ANY) { ! 361: np = getnetbyaddr(net, AF_INET); ! 362: if (np) ! 363: cp = np->n_name; ! 364: } ! 365: if (cp == 0) { ! 366: hp = gethostbyaddr(&in, sizeof (in), AF_INET); ! 367: if (hp) ! 368: cp = hp->h_name; ! 369: } ! 370: } ! 371: if (in.s_addr == INADDR_ANY) ! 372: strcpy(line, "*"); ! 373: else if (cp) ! 374: strcpy(line, cp); ! 375: else { ! 376: in.s_addr = ntohl(in.s_addr); ! 377: #define C(x) ((x) & 0xff) ! 378: sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), ! 379: C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr)); ! 380: } ! 381: return (line); ! 382: } ! 383: ! 384: cmdnetstat(cmd, args) ! 385: char *cmd, *args; ! 386: { ! 387: register struct netinfo *p; ! 388: ! 389: if (prefix(cmd, "all")) { ! 390: aflag = !aflag; ! 391: goto fixup; ! 392: } ! 393: if (prefix(cmd, "numbers") || prefix(cmd, "names")) { ! 394: int new; ! 395: ! 396: new = prefix(cmd, "numbers"); ! 397: if (new == nflag) ! 398: return (1); ! 399: p = netcb.ni_forw; ! 400: for (; p != (struct netinfo *)&netcb; p = p->ni_forw) { ! 401: if (p->ni_line == -1) ! 402: continue; ! 403: p->ni_flags |= NIF_LACHG|NIF_FACHG; ! 404: } ! 405: nflag = new; ! 406: goto redisplay; ! 407: } ! 408: if (!netcmd(cmd, args)) ! 409: return (0); ! 410: fixup: ! 411: fetchnetstat(); ! 412: redisplay: ! 413: shownetstat(); ! 414: refresh(); ! 415: return (1); ! 416: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.