|
|
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.