Annotation of src/usr.bin/systat/netstat.c, Revision 1.42
1.42 ! schwarze 1: /* $OpenBSD: netstat.c,v 1.41 2014/10/08 04:10:04 doug 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/ip.h>
45: #include <netinet/in_pcb.h>
46: #include <netinet/ip_icmp.h>
47: #include <netinet/icmp_var.h>
48: #include <netinet/ip_var.h>
49: #include <netinet/tcp.h>
50: #include <netinet/tcp_seq.h>
51: #define TCPSTATES
52: #include <netinet/tcp_fsm.h>
53: #include <netinet/tcp_timer.h>
54: #include <netinet/tcp_var.h>
55: #include <netinet/udp.h>
56: #include <netinet/udp_var.h>
1.7 millert 57: #include <arpa/inet.h>
1.1 deraadt 58:
59: #include <netdb.h>
60: #include <stdlib.h>
61: #include <string.h>
1.16 pvalchev 62: #include <err.h>
1.1 deraadt 63: #include <nlist.h>
64: #include <paths.h>
65: #include "systat.h"
1.31 canacar 66: #include "engine.h"
67:
68: struct netinfo {
69: union {
70: struct in_addr nif_laddr; /* local address */
71: struct in6_addr nif_laddr6; /* local address */
72: } l;
73: union {
74: struct in_addr nif_faddr; /* foreign address */
75: struct in6_addr nif_faddr6; /* foreign address */
76: } f;
77: char *nif_proto; /* protocol */
78: long nif_rcvcc; /* rcv buffer character count */
79: long nif_sndcc; /* snd buffer character count */
80: short nif_lport; /* local port */
81: short nif_fport; /* foreign port */
82: short nif_state; /* tcp state */
83: short nif_family;
84: };
85:
86: #define nif_laddr l.nif_laddr
87: #define nif_laddr6 l.nif_laddr6
88: #define nif_faddr f.nif_faddr
89: #define nif_faddr6 f.nif_faddr6
1.1 deraadt 90:
1.21 millert 91: static void enter(struct inpcb *, struct socket *, int, char *);
1.31 canacar 92: static void inetprint(struct in_addr *, int, char *, field_def *);
93: static void inet6print(struct in6_addr *, int, char *, field_def *);
94: static void shownetstat(struct netinfo *p);
95:
96: void print_ns(void);
97: int read_ns(void);
98: int select_ns(void);
99: int ns_keyboard_callback(int);
1.1 deraadt 100:
101: #define streq(a,b) (strcmp(a,b)==0)
102:
1.31 canacar 103: static int aflag = 0;
104:
105: static struct nlist namelist[] = {
106: #define X_TCBTABLE 0 /* no sysctl */
107: { "_tcbtable" },
108: #define X_UDBTABLE 1 /* no sysctl */
109: { "_udbtable" },
110: { "" },
111: };
112: #define ADD_ALLOC 1000
113:
114:
115: int protos;
116:
117: struct netinfo *netinfos = NULL;
118: size_t num_ns = 0;
119: static size_t num_alloc = 0;
120:
121:
122: field_def fields_ns[] = {
123: {"LOCAL ADDRESS", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
124: {"FOREIGN ADDRESS", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
125: {"PROTO", 4, 9, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
126: {"RECV-Q", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
127: {"SEND-Q", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
128: {"STATE", 5, 11, 6, FLD_ALIGN_LEFT, -1, 0, 0, 0},
129: };
130:
1.34 jasper 131: #define FLD_NS_LOCAL FIELD_ADDR(fields_ns,0)
132: #define FLD_NS_FOREIGN FIELD_ADDR(fields_ns,1)
133: #define FLD_NS_PROTO FIELD_ADDR(fields_ns,2)
134: #define FLD_NS_RECV_Q FIELD_ADDR(fields_ns,3)
135: #define FLD_NS_SEND_Q FIELD_ADDR(fields_ns,4)
136: #define FLD_NS_STATE FIELD_ADDR(fields_ns,5)
1.31 canacar 137:
138: /* Define views */
139: field_def *view_ns_0[] = {
140: FLD_NS_LOCAL, FLD_NS_FOREIGN, FLD_NS_PROTO,
141: FLD_NS_RECV_Q, FLD_NS_SEND_Q, FLD_NS_STATE, NULL
142: };
143:
144: /* Define view managers */
145: struct view_manager netstat_mgr = {
146: "Netstat", select_ns, read_ns, NULL, print_header,
147: print_ns, ns_keyboard_callback, NULL, NULL
148: };
1.1 deraadt 149:
1.31 canacar 150: field_view views_ns[] = {
151: {view_ns_0, "netstat", '0', &netstat_mgr},
152: {NULL, NULL, 0, NULL}
1.1 deraadt 153: };
154:
155:
156:
1.31 canacar 157:
158: struct netinfo *
159: next_ns(void)
160: {
161: if (num_alloc <= num_ns) {
162: struct netinfo *ni;
163: size_t a = num_alloc + ADD_ALLOC;
164: if (a < num_alloc)
165: return NULL;
1.41 doug 166: ni = reallocarray(netinfos, a, sizeof(*ni));
1.31 canacar 167: if (ni == NULL)
168: return NULL;
169: netinfos = ni;
170: num_alloc = a;
171: }
172:
173: return &netinfos[num_ns++];
174: }
175:
176: static void
177: enter(struct inpcb *inp, struct socket *so, int state, char *proto)
1.1 deraadt 178: {
1.17 mpech 179: struct netinfo *p;
1.1 deraadt 180:
1.31 canacar 181: p = next_ns();
182: if (p == NULL) {
183: error("Out of Memory!");
184: return;
1.1 deraadt 185: }
1.31 canacar 186:
187: p->nif_lport = inp->inp_lport;
188: p->nif_fport = inp->inp_fport;
189: p->nif_proto = proto;
190:
191: if (inp->inp_flags & INP_IPV6) {
192: p->nif_laddr6 = inp->inp_laddr6;
193: p->nif_faddr6 = inp->inp_faddr6;
194: p->nif_family = AF_INET6;
195: } else {
196: p->nif_laddr = inp->inp_laddr;
197: p->nif_faddr = inp->inp_faddr;
198: p->nif_family = AF_INET;
199: }
200:
201: p->nif_rcvcc = so->so_rcv.sb_cc;
202: p->nif_sndcc = so->so_snd.sb_cc;
203: p->nif_state = state;
1.1 deraadt 204: }
205:
1.31 canacar 206:
207: /* netstat callback functions */
1.1 deraadt 208:
209: int
1.31 canacar 210: select_ns(void)
1.1 deraadt 211: {
1.31 canacar 212: if (kd == NULL) {
213: num_disp = 1;
214: return (0);
215: }
216: num_disp = num_ns;
217: return (0);
1.1 deraadt 218: }
219:
1.31 canacar 220: int
221: read_ns(void)
1.1 deraadt 222: {
223: struct inpcbtable pcbtable;
1.39 tedu 224: struct inpcb *next, *prev;
225: struct inpcb inpcb, prevpcb;
1.1 deraadt 226: struct socket sockb;
227: struct tcpcb tcpcb;
228: void *off;
229: int istcp;
230:
1.31 canacar 231: if (kd == NULL) {
232: return (0);
233: }
234:
235: num_ns = 0;
236:
1.1 deraadt 237: if (namelist[X_TCBTABLE].n_value == 0)
1.31 canacar 238: return 0;
239:
240: if (protos & TCP) {
1.20 deraadt 241: off = NPTR(X_TCBTABLE);
1.1 deraadt 242: istcp = 1;
1.31 canacar 243: } else if (protos & UDP) {
1.20 deraadt 244: off = NPTR(X_UDBTABLE);
1.1 deraadt 245: istcp = 0;
1.20 deraadt 246: } else {
1.1 deraadt 247: error("No protocols to display");
1.31 canacar 248: return 0;
1.1 deraadt 249: }
1.31 canacar 250:
1.1 deraadt 251: again:
252: KREAD(off, &pcbtable, sizeof (struct inpcbtable));
1.31 canacar 253:
1.39 tedu 254: prev = NULL;
1.37 krw 255: next = TAILQ_FIRST(&pcbtable.inpt_queue);
1.31 canacar 256:
1.38 tedu 257: while (next != NULL) {
1.1 deraadt 258: KREAD(next, &inpcb, sizeof (inpcb));
1.39 tedu 259: if (prev != NULL) {
260: KREAD(prev, &prevpcb, sizeof (prevpcb));
261: if (TAILQ_NEXT(&prevpcb, inp_queue) != next) {
262: error("Kernel state in transition");
263: return 0;
264: }
265: }
266: prev = next;
1.37 krw 267: next = TAILQ_NEXT(&inpcb, inp_queue);
1.12 itojun 268:
269: if (!aflag) {
1.20 deraadt 270: if (!(inpcb.inp_flags & INP_IPV6) &&
1.35 okan 271: inet_lnaof(inpcb.inp_faddr) == INADDR_ANY)
1.12 itojun 272: continue;
1.20 deraadt 273: if ((inpcb.inp_flags & INP_IPV6) &&
1.35 okan 274: IN6_IS_ADDR_UNSPECIFIED(&inpcb.inp_faddr6))
1.12 itojun 275: continue;
276: }
1.1 deraadt 277: KREAD(inpcb.inp_socket, &sockb, sizeof (sockb));
278: if (istcp) {
279: KREAD(inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb));
1.35 okan 280: if (!aflag && tcpcb.t_state <= TCPS_LISTEN)
281: continue;
1.1 deraadt 282: enter(&inpcb, &sockb, tcpcb.t_state, "tcp");
283: } else
284: enter(&inpcb, &sockb, 0, "udp");
285: }
1.31 canacar 286: if (istcp && (protos & UDP)) {
1.1 deraadt 287: istcp = 0;
288: off = NPTR(X_UDBTABLE);
289: goto again;
290: }
1.31 canacar 291:
292: num_disp = num_ns;
293: return 0;
1.1 deraadt 294: }
295:
1.31 canacar 296: void
297: print_ns(void)
1.1 deraadt 298: {
1.31 canacar 299: int n, count = 0;
1.1 deraadt 300:
1.31 canacar 301: if (kd == NULL) {
302: print_fld_str(FLD_NS_LOCAL, "Failed to initialize KVM!");
303: print_fld_str(FLD_NS_FOREIGN, "Failed to initialize KVM!");
304: end_line();
305: return;
1.1 deraadt 306: }
1.31 canacar 307:
308: for (n = dispstart; n < num_disp; n++) {
309: shownetstat(netinfos + n);
310: count++;
311: if (maxprint > 0 && count >= maxprint)
312: break;
1.11 angelos 313: }
1.1 deraadt 314: }
315:
316:
1.31 canacar 317: int
318: initnetstat(void)
319: {
320: field_view *v;
321: int ret;
1.1 deraadt 322:
1.31 canacar 323: if (kd) {
324: if ((ret = kvm_nlist(kd, namelist)) == -1)
325: errx(1, "%s", kvm_geterr(kd));
326: else if (ret)
327: nlisterr(namelist);
328:
329: if (namelist[X_TCBTABLE].n_value == 0) {
330: error("No symbols in namelist");
331: return(0);
332: }
333: }
334: protos = TCP|UDP;
335:
336: for (v = views_ns; v->name != NULL; v++)
337: add_view(v);
338:
339: return(1);
1.1 deraadt 340: }
341:
1.31 canacar 342: static void
343: shownetstat(struct netinfo *p)
1.1 deraadt 344: {
1.31 canacar 345: switch (p->nif_family) {
346: case AF_INET:
347: inetprint(&p->nif_laddr, p->nif_lport,
348: p->nif_proto, FLD_NS_LOCAL);
349: inetprint(&p->nif_faddr, p->nif_fport,
350: p->nif_proto, FLD_NS_FOREIGN);
351: break;
352: case AF_INET6:
353: inet6print(&p->nif_laddr6, p->nif_lport,
354: p->nif_proto, FLD_NS_LOCAL);
355: inet6print(&p->nif_faddr6, p->nif_fport,
356: p->nif_proto, FLD_NS_FOREIGN);
357: break;
358: }
359:
360: tb_start();
361: tbprintf("%s", p->nif_proto);
362: if (p->nif_family == AF_INET6)
363: tbprintf("6");
364:
365: print_fld_tb(FLD_NS_PROTO);
366:
367: print_fld_size(FLD_NS_RECV_Q, p->nif_rcvcc);
368: print_fld_size(FLD_NS_SEND_Q, p->nif_sndcc);
369:
370: if (streq(p->nif_proto, "tcp")) {
371: if (p->nif_state < 0 || p->nif_state >= TCP_NSTATES)
372: print_fld_uint(FLD_NS_STATE, p->nif_state);
373: else
374: print_fld_str(FLD_NS_STATE, tcpstates[p->nif_state]);
1.1 deraadt 375: }
1.31 canacar 376: end_line();
1.1 deraadt 377: }
378:
379: /*
380: * Pretty print an Internet address (net address + port).
381: * If the nflag was specified, use numbers instead of names.
382: */
383: static void
1.31 canacar 384: inetprint(struct in_addr *in, int port, char *proto, field_def *fld)
1.1 deraadt 385: {
386: struct servent *sp = 0;
387:
1.31 canacar 388: tb_start();
389: tbprintf("%s", inetname(*in));
390:
1.1 deraadt 391: if (!nflag && port)
392: sp = getservbyport(port, proto);
393: if (sp || port == 0)
1.31 canacar 394: tbprintf(":%s", sp ? sp->s_name : "*");
1.1 deraadt 395: else
1.31 canacar 396: tbprintf(":%d", ntohs((u_short)port));
397:
398: print_fld_tb(fld);
1.1 deraadt 399: }
400:
1.12 itojun 401: static void
1.31 canacar 402: inet6print(struct in6_addr *in6, int port, char *proto, field_def *fld)
1.12 itojun 403: {
404: struct servent *sp = 0;
405:
1.31 canacar 406: tb_start();
407:
408: tbprintf("%s", inet6name(in6));
1.12 itojun 409: if (!nflag && port)
410: sp = getservbyport(port, proto);
411: if (sp || port == 0)
1.31 canacar 412: tbprintf(":%s", sp ? sp->s_name : "*");
1.12 itojun 413: else
1.31 canacar 414: tbprintf(":%d", ntohs((u_short)port));
1.12 itojun 415:
1.31 canacar 416: print_fld_tb(fld);
417: }
418:
419: int
420: kvm_ckread(void *a, void *b, size_t l)
421: {
422: if (kvm_read(kd, (u_long)a, b, l) != l) {
423: if (verbose)
1.36 deraadt 424: error("error reading kmem\n");
1.31 canacar 425: return (0);
426: } else
427: return (1);
428: }
429:
430:
1.1 deraadt 431: int
1.31 canacar 432: ns_keyboard_callback(int ch)
1.1 deraadt 433: {
1.31 canacar 434: switch (ch) {
1.35 okan 435: case 'a':
436: aflag = !aflag;
437: gotsig_alarm = 1;
438: break;
1.31 canacar 439: case 'n':
440: nflag = !nflag;
1.35 okan 441: gotsig_alarm = 1;
442: break;
443: case 'r':
444: aflag = 0;
445: nflag = 1;
446: protos = TCP|UDP;
1.31 canacar 447: gotsig_alarm = 1;
448: break;
449: case 't':
450: protos ^= TCP;
451: gotsig_alarm = 1;
452: break;
453: case 'u':
454: protos ^= UDP;
455: gotsig_alarm = 1;
456: break;
457: default:
458: return keyboard_callback(ch);
459: };
1.1 deraadt 460:
1.31 canacar 461: return 1;
1.1 deraadt 462: }
1.31 canacar 463: