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