Annotation of src/usr.bin/systat/netstat.c, Revision 1.38
1.38 ! tedu 1: /* $OpenBSD: netstat.c,v 1.37 2013/12/20 02:04:09 krw Exp $ */
1.1 deraadt 2: /* $NetBSD: netstat.c,v 1.3 1995/06/18 23:53:07 cgd Exp $ */
3:
4: /*-
5: * Copyright (c) 1980, 1992, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
1.24 millert 16: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: /*
34: * netstat
35: */
36: #include <sys/param.h>
37: #include <sys/socket.h>
38: #include <sys/socketvar.h>
39: #include <sys/mbuf.h>
40: #include <sys/protosw.h>
41:
42: #include <netinet/in.h>
43: #include <net/route.h>
44: #include <netinet/in_systm.h>
45: #include <netinet/ip.h>
46: #include <netinet/in_pcb.h>
47: #include <netinet/ip_icmp.h>
48: #include <netinet/icmp_var.h>
49: #include <netinet/ip_var.h>
50: #include <netinet/tcp.h>
51: #include <netinet/tcpip.h>
52: #include <netinet/tcp_seq.h>
53: #define TCPSTATES
54: #include <netinet/tcp_fsm.h>
55: #include <netinet/tcp_timer.h>
56: #include <netinet/tcp_var.h>
57: #include <netinet/tcp_debug.h>
58: #include <netinet/udp.h>
59: #include <netinet/udp_var.h>
1.7 millert 60: #include <arpa/inet.h>
1.1 deraadt 61:
62: #include <netdb.h>
63: #include <stdlib.h>
64: #include <string.h>
1.16 pvalchev 65: #include <err.h>
1.1 deraadt 66: #include <nlist.h>
67: #include <paths.h>
68: #include "systat.h"
1.31 canacar 69: #include "engine.h"
70:
71: struct netinfo {
72: union {
73: struct in_addr nif_laddr; /* local address */
74: struct in6_addr nif_laddr6; /* local address */
75: } l;
76: union {
77: struct in_addr nif_faddr; /* foreign address */
78: struct in6_addr nif_faddr6; /* foreign address */
79: } f;
80: char *nif_proto; /* protocol */
81: long nif_rcvcc; /* rcv buffer character count */
82: long nif_sndcc; /* snd buffer character count */
83: short nif_lport; /* local port */
84: short nif_fport; /* foreign port */
85: short nif_state; /* tcp state */
86: short nif_family;
87: };
88:
89: #define nif_laddr l.nif_laddr
90: #define nif_laddr6 l.nif_laddr6
91: #define nif_faddr f.nif_faddr
92: #define nif_faddr6 f.nif_faddr6
1.1 deraadt 93:
1.21 millert 94: static void enter(struct inpcb *, struct socket *, int, char *);
1.31 canacar 95: static void inetprint(struct in_addr *, int, char *, field_def *);
96: static void inet6print(struct in6_addr *, int, char *, field_def *);
97: static void shownetstat(struct netinfo *p);
98:
99: void print_ns(void);
100: int read_ns(void);
101: int select_ns(void);
102: int ns_keyboard_callback(int);
1.1 deraadt 103:
104: #define streq(a,b) (strcmp(a,b)==0)
105:
1.31 canacar 106: static int aflag = 0;
107:
108: static struct nlist namelist[] = {
109: #define X_TCBTABLE 0 /* no sysctl */
110: { "_tcbtable" },
111: #define X_UDBTABLE 1 /* no sysctl */
112: { "_udbtable" },
113: { "" },
114: };
115: #define ADD_ALLOC 1000
116:
117:
118: int protos;
119:
120: struct netinfo *netinfos = NULL;
121: size_t num_ns = 0;
122: static size_t num_alloc = 0;
123:
124:
125: field_def fields_ns[] = {
126: {"LOCAL ADDRESS", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
127: {"FOREIGN ADDRESS", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
128: {"PROTO", 4, 9, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
129: {"RECV-Q", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
130: {"SEND-Q", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
131: {"STATE", 5, 11, 6, FLD_ALIGN_LEFT, -1, 0, 0, 0},
132: };
133:
1.34 jasper 134: #define FLD_NS_LOCAL FIELD_ADDR(fields_ns,0)
135: #define FLD_NS_FOREIGN FIELD_ADDR(fields_ns,1)
136: #define FLD_NS_PROTO FIELD_ADDR(fields_ns,2)
137: #define FLD_NS_RECV_Q FIELD_ADDR(fields_ns,3)
138: #define FLD_NS_SEND_Q FIELD_ADDR(fields_ns,4)
139: #define FLD_NS_STATE FIELD_ADDR(fields_ns,5)
1.31 canacar 140:
141: /* Define views */
142: field_def *view_ns_0[] = {
143: FLD_NS_LOCAL, FLD_NS_FOREIGN, FLD_NS_PROTO,
144: FLD_NS_RECV_Q, FLD_NS_SEND_Q, FLD_NS_STATE, NULL
145: };
146:
147: /* Define view managers */
148: struct view_manager netstat_mgr = {
149: "Netstat", select_ns, read_ns, NULL, print_header,
150: print_ns, ns_keyboard_callback, NULL, NULL
151: };
1.1 deraadt 152:
1.31 canacar 153: field_view views_ns[] = {
154: {view_ns_0, "netstat", '0', &netstat_mgr},
155: {NULL, NULL, 0, NULL}
1.1 deraadt 156: };
157:
158:
159:
1.31 canacar 160:
161: struct netinfo *
162: next_ns(void)
163: {
164: if (num_alloc <= num_ns) {
165: struct netinfo *ni;
166: size_t a = num_alloc + ADD_ALLOC;
167: if (a < num_alloc)
168: return NULL;
169: ni = realloc(netinfos, a * sizeof(*ni));
170: if (ni == NULL)
171: return NULL;
172: netinfos = ni;
173: num_alloc = a;
174: }
175:
176: return &netinfos[num_ns++];
177: }
178:
179: static void
180: enter(struct inpcb *inp, struct socket *so, int state, char *proto)
1.1 deraadt 181: {
1.17 mpech 182: struct netinfo *p;
1.1 deraadt 183:
1.31 canacar 184: p = next_ns();
185: if (p == NULL) {
186: error("Out of Memory!");
187: return;
1.1 deraadt 188: }
1.31 canacar 189:
190: p->nif_lport = inp->inp_lport;
191: p->nif_fport = inp->inp_fport;
192: p->nif_proto = proto;
193:
194: if (inp->inp_flags & INP_IPV6) {
195: p->nif_laddr6 = inp->inp_laddr6;
196: p->nif_faddr6 = inp->inp_faddr6;
197: p->nif_family = AF_INET6;
198: } else {
199: p->nif_laddr = inp->inp_laddr;
200: p->nif_faddr = inp->inp_faddr;
201: p->nif_family = AF_INET;
202: }
203:
204: p->nif_rcvcc = so->so_rcv.sb_cc;
205: p->nif_sndcc = so->so_snd.sb_cc;
206: p->nif_state = state;
1.1 deraadt 207: }
208:
1.31 canacar 209:
210: /* netstat callback functions */
1.1 deraadt 211:
212: int
1.31 canacar 213: select_ns(void)
1.1 deraadt 214: {
1.31 canacar 215: static int init = 0;
216: if (kd == NULL) {
217: num_disp = 1;
218: return (0);
219: }
1.14 ericj 220:
1.31 canacar 221: if (!init) {
222: sethostent(1);
223: setnetent(1);
224: init = 1;
1.1 deraadt 225: }
1.31 canacar 226:
227: num_disp = num_ns;
228: return (0);
1.1 deraadt 229: }
230:
1.31 canacar 231: int
232: read_ns(void)
1.1 deraadt 233: {
234: struct inpcbtable pcbtable;
1.38 ! tedu 235: struct inpcb *next;
1.1 deraadt 236: struct inpcb inpcb;
237: struct socket sockb;
238: struct tcpcb tcpcb;
239: void *off;
240: int istcp;
241:
1.31 canacar 242: if (kd == NULL) {
243: return (0);
244: }
245:
246: num_ns = 0;
247:
1.1 deraadt 248: if (namelist[X_TCBTABLE].n_value == 0)
1.31 canacar 249: return 0;
250:
251: if (protos & TCP) {
1.20 deraadt 252: off = NPTR(X_TCBTABLE);
1.1 deraadt 253: istcp = 1;
1.31 canacar 254: } else if (protos & UDP) {
1.20 deraadt 255: off = NPTR(X_UDBTABLE);
1.1 deraadt 256: istcp = 0;
1.20 deraadt 257: } else {
1.1 deraadt 258: error("No protocols to display");
1.31 canacar 259: return 0;
1.1 deraadt 260: }
1.31 canacar 261:
1.1 deraadt 262: again:
263: KREAD(off, &pcbtable, sizeof (struct inpcbtable));
1.31 canacar 264:
1.37 krw 265: next = TAILQ_FIRST(&pcbtable.inpt_queue);
1.31 canacar 266:
1.38 ! tedu 267: while (next != NULL) {
1.1 deraadt 268: KREAD(next, &inpcb, sizeof (inpcb));
1.37 krw 269: next = TAILQ_NEXT(&inpcb, inp_queue);
1.12 itojun 270:
271: if (!aflag) {
1.20 deraadt 272: if (!(inpcb.inp_flags & INP_IPV6) &&
1.35 okan 273: inet_lnaof(inpcb.inp_faddr) == INADDR_ANY)
1.12 itojun 274: continue;
1.20 deraadt 275: if ((inpcb.inp_flags & INP_IPV6) &&
1.35 okan 276: IN6_IS_ADDR_UNSPECIFIED(&inpcb.inp_faddr6))
1.12 itojun 277: continue;
278: }
1.1 deraadt 279: KREAD(inpcb.inp_socket, &sockb, sizeof (sockb));
280: if (istcp) {
281: KREAD(inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb));
1.35 okan 282: if (!aflag && tcpcb.t_state <= TCPS_LISTEN)
283: continue;
1.1 deraadt 284: enter(&inpcb, &sockb, tcpcb.t_state, "tcp");
285: } else
286: enter(&inpcb, &sockb, 0, "udp");
287: }
1.31 canacar 288: if (istcp && (protos & UDP)) {
1.1 deraadt 289: istcp = 0;
290: off = NPTR(X_UDBTABLE);
291: goto again;
292: }
1.31 canacar 293:
294: num_disp = num_ns;
295: return 0;
1.1 deraadt 296: }
297:
1.31 canacar 298: void
299: print_ns(void)
1.1 deraadt 300: {
1.31 canacar 301: int n, count = 0;
1.1 deraadt 302:
1.31 canacar 303: if (kd == NULL) {
304: print_fld_str(FLD_NS_LOCAL, "Failed to initialize KVM!");
305: print_fld_str(FLD_NS_FOREIGN, "Failed to initialize KVM!");
306: end_line();
307: return;
1.1 deraadt 308: }
1.31 canacar 309:
310: for (n = dispstart; n < num_disp; n++) {
311: shownetstat(netinfos + n);
312: count++;
313: if (maxprint > 0 && count >= maxprint)
314: break;
1.11 angelos 315: }
1.1 deraadt 316: }
317:
318:
1.31 canacar 319: int
320: initnetstat(void)
321: {
322: field_view *v;
323: int ret;
1.1 deraadt 324:
1.31 canacar 325: if (kd) {
326: if ((ret = kvm_nlist(kd, namelist)) == -1)
327: errx(1, "%s", kvm_geterr(kd));
328: else if (ret)
329: nlisterr(namelist);
330:
331: if (namelist[X_TCBTABLE].n_value == 0) {
332: error("No symbols in namelist");
333: return(0);
334: }
335: }
336: protos = TCP|UDP;
337:
338: for (v = views_ns; v->name != NULL; v++)
339: add_view(v);
340:
341: return(1);
1.1 deraadt 342: }
343:
1.31 canacar 344: static void
345: shownetstat(struct netinfo *p)
1.1 deraadt 346: {
1.31 canacar 347: switch (p->nif_family) {
348: case AF_INET:
349: inetprint(&p->nif_laddr, p->nif_lport,
350: p->nif_proto, FLD_NS_LOCAL);
351: inetprint(&p->nif_faddr, p->nif_fport,
352: p->nif_proto, FLD_NS_FOREIGN);
353: break;
354: case AF_INET6:
355: inet6print(&p->nif_laddr6, p->nif_lport,
356: p->nif_proto, FLD_NS_LOCAL);
357: inet6print(&p->nif_faddr6, p->nif_fport,
358: p->nif_proto, FLD_NS_FOREIGN);
359: break;
360: }
361:
362: tb_start();
363: tbprintf("%s", p->nif_proto);
364: if (p->nif_family == AF_INET6)
365: tbprintf("6");
366:
367: print_fld_tb(FLD_NS_PROTO);
368:
369: print_fld_size(FLD_NS_RECV_Q, p->nif_rcvcc);
370: print_fld_size(FLD_NS_SEND_Q, p->nif_sndcc);
371:
372: if (streq(p->nif_proto, "tcp")) {
373: if (p->nif_state < 0 || p->nif_state >= TCP_NSTATES)
374: print_fld_uint(FLD_NS_STATE, p->nif_state);
375: else
376: print_fld_str(FLD_NS_STATE, tcpstates[p->nif_state]);
1.1 deraadt 377: }
1.31 canacar 378: end_line();
1.1 deraadt 379: }
380:
381: /*
382: * Pretty print an Internet address (net address + port).
383: * If the nflag was specified, use numbers instead of names.
384: */
385: static void
1.31 canacar 386: inetprint(struct in_addr *in, int port, char *proto, field_def *fld)
1.1 deraadt 387: {
388: struct servent *sp = 0;
389:
1.31 canacar 390: tb_start();
391: tbprintf("%s", inetname(*in));
392:
1.1 deraadt 393: if (!nflag && port)
394: sp = getservbyport(port, proto);
395: if (sp || port == 0)
1.31 canacar 396: tbprintf(":%s", sp ? sp->s_name : "*");
1.1 deraadt 397: else
1.31 canacar 398: tbprintf(":%d", ntohs((u_short)port));
399:
400: print_fld_tb(fld);
1.1 deraadt 401: }
402:
1.12 itojun 403: static void
1.31 canacar 404: inet6print(struct in6_addr *in6, int port, char *proto, field_def *fld)
1.12 itojun 405: {
406: struct servent *sp = 0;
407:
1.31 canacar 408: tb_start();
409:
410: tbprintf("%s", inet6name(in6));
1.12 itojun 411: if (!nflag && port)
412: sp = getservbyport(port, proto);
413: if (sp || port == 0)
1.31 canacar 414: tbprintf(":%s", sp ? sp->s_name : "*");
1.12 itojun 415: else
1.31 canacar 416: tbprintf(":%d", ntohs((u_short)port));
1.12 itojun 417:
1.31 canacar 418: print_fld_tb(fld);
419: }
420:
421: int
422: kvm_ckread(void *a, void *b, size_t l)
423: {
424: if (kvm_read(kd, (u_long)a, b, l) != l) {
425: if (verbose)
1.36 deraadt 426: error("error reading kmem\n");
1.31 canacar 427: return (0);
428: } else
429: return (1);
430: }
431:
432:
1.1 deraadt 433: int
1.31 canacar 434: ns_keyboard_callback(int ch)
1.1 deraadt 435: {
1.31 canacar 436: switch (ch) {
1.35 okan 437: case 'a':
438: aflag = !aflag;
439: gotsig_alarm = 1;
440: break;
1.31 canacar 441: case 'n':
442: nflag = !nflag;
1.35 okan 443: gotsig_alarm = 1;
444: break;
445: case 'r':
446: aflag = 0;
447: nflag = 1;
448: protos = TCP|UDP;
1.31 canacar 449: gotsig_alarm = 1;
450: break;
451: case 't':
452: protos ^= TCP;
453: gotsig_alarm = 1;
454: break;
455: case 'u':
456: protos ^= UDP;
457: gotsig_alarm = 1;
458: break;
459: default:
460: return keyboard_callback(ch);
461: };
1.1 deraadt 462:
1.31 canacar 463: return 1;
1.1 deraadt 464: }
1.31 canacar 465: