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