xref: /freebsd/usr.bin/netstat/inet.c (revision e627b39baccd1ec9129690167cf5e6d860509655)
1 /*
2  * Copyright (c) 1983, 1988, 1993, 1995
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 static char sccsid[] = "@(#)inet.c	8.5 (Berkeley) 5/24/95";
36 #endif /* not lint */
37 
38 #include <sys/param.h>
39 #include <sys/queue.h>
40 #include <sys/socket.h>
41 #include <sys/socketvar.h>
42 #include <sys/mbuf.h>
43 #include <sys/protosw.h>
44 
45 #include <net/route.h>
46 #include <netinet/in.h>
47 #include <netinet/in_systm.h>
48 #include <netinet/ip.h>
49 #include <netinet/in_pcb.h>
50 #include <netinet/ip_icmp.h>
51 #include <netinet/icmp_var.h>
52 #include <netinet/igmp_var.h>
53 #include <netinet/ip_var.h>
54 #include <netinet/tcp.h>
55 #include <netinet/tcpip.h>
56 #include <netinet/tcp_seq.h>
57 #define TCPSTATES
58 #include <netinet/tcp_fsm.h>
59 #include <netinet/tcp_timer.h>
60 #include <netinet/tcp_var.h>
61 #include <netinet/tcp_debug.h>
62 #include <netinet/udp.h>
63 #include <netinet/udp_var.h>
64 
65 #include <arpa/inet.h>
66 #include <netdb.h>
67 #include <stdio.h>
68 #include <string.h>
69 #include <unistd.h>
70 #include "netstat.h"
71 
72 struct	inpcb inpcb;
73 struct	tcpcb tcpcb;
74 struct	socket sockb;
75 
76 char	*inetname __P((struct in_addr *));
77 void	inetprint __P((struct in_addr *, int, char *, int));
78 
79 /*
80  * Print a summary of connections related to an Internet
81  * protocol.  For TCP, also give state of connection.
82  * Listening processes (aflag) are suppressed unless the
83  * -a (all) flag is specified.
84  */
85 void
86 protopr(off, name)
87 	u_long off;
88 	char *name;
89 {
90 	struct inpcbhead head;
91 	register struct inpcb *prev, *next;
92 	int istcp;
93 	static int first = 1;
94 
95 	if (off == 0)
96 		return;
97 
98 	istcp = strcmp(name, "tcp") == 0;
99 	kread(off, (char *)&head, sizeof (struct inpcbhead));
100 	prev = (struct inpcb *)off;
101 
102 	for (next = head.lh_first; next != NULL; next = inpcb.inp_list.le_next) {
103 		if (kread((u_long)next, (char *)&inpcb, sizeof (inpcb))) {
104 			printf("???\n");
105 			break;
106 		}
107 		if (!aflag &&
108 		  inet_lnaof(inpcb.inp_laddr) == INADDR_ANY) {
109 			prev = next;
110 			continue;
111 		}
112 		if (kread((u_long)inpcb.inp_socket, (char *)&sockb, sizeof (sockb))) {
113 			printf("???\n");
114 			break;
115 		};
116 		if (istcp) {
117 			if (kread((u_long)inpcb.inp_ppcb,
118 			    (char *)&tcpcb, sizeof (tcpcb))) {
119 				printf("???\n");
120 				break;
121 			};
122 		}
123 		if (first) {
124 			printf("Active Internet connections");
125 			if (aflag)
126 				printf(" (including servers)");
127 			putchar('\n');
128 			if (Aflag)
129 				printf("%-8.8s ", "PCB");
130 			printf(Aflag ?
131 				"%-5.5s %-6.6s %-6.6s  %-18.18s %-18.18s %s\n" :
132 				"%-5.5s %-6.6s %-6.6s  %-22.22s %-22.22s %s\n",
133 				"Proto", "Recv-Q", "Send-Q",
134 				"Local Address", "Foreign Address", "(state)");
135 			first = 0;
136 		}
137 		if (Aflag)
138 			if (istcp)
139 				printf("%8x ", (int)inpcb.inp_ppcb);
140 			else
141 				printf("%8x ", (int)next);
142 		printf("%-5.5s %6ld %6ld ", name, sockb.so_rcv.sb_cc,
143 			sockb.so_snd.sb_cc);
144 		if (nflag) {
145 			inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport,
146 			    name, 1);
147 			inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport,
148 			    name, 1);
149 		} else if (inpcb.inp_flags & INP_ANONPORT) {
150 			inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport,
151 			    name, 1);
152 			inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport,
153 			    name, 0);
154 		} else {
155 			inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport,
156 			    name, 0);
157 			inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport,
158 			    name, inpcb.inp_lport != inpcb.inp_fport);
159 		}
160 		if (istcp) {
161 			if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
162 				printf(" %d", tcpcb.t_state);
163                       else {
164 				printf(" %s", tcpstates[tcpcb.t_state]);
165 #if defined(TF_NEEDSYN) && defined(TF_NEEDFIN)
166                               /* Show T/TCP `hidden state' */
167                               if (tcpcb.t_flags & (TF_NEEDSYN|TF_NEEDFIN))
168                                       putchar('*');
169 #endif /* defined(TF_NEEDSYN) && defined(TF_NEEDFIN) */
170                       }
171 		}
172 		putchar('\n');
173 		prev = next;
174 	}
175 }
176 
177 /*
178  * Dump TCP statistics structure.
179  */
180 void
181 tcp_stats(off, name)
182 	u_long off;
183 	char *name;
184 {
185 	struct tcpstat tcpstat;
186 
187 	if (off == 0)
188 		return;
189 	printf ("%s:\n", name);
190 	kread(off, (char *)&tcpstat, sizeof (tcpstat));
191 
192 #define	p(f, m) if (tcpstat.f || sflag <= 1) \
193     printf(m, tcpstat.f, plural(tcpstat.f))
194 #define	p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
195     printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2, plural(tcpstat.f2))
196 #define	p3(f, m) if (tcpstat.f || sflag <= 1) \
197     printf(m, tcpstat.f, plurales(tcpstat.f))
198 
199 	p(tcps_sndtotal, "\t%ld packet%s sent\n");
200 	p2(tcps_sndpack,tcps_sndbyte,
201 		"\t\t%ld data packet%s (%ld byte%s)\n");
202 	p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
203 		"\t\t%ld data packet%s (%ld byte%s) retransmitted\n");
204 	p(tcps_mturesent, "\t\t%ld resend%s initiated by MTU discovery\n");
205 	p2(tcps_sndacks, tcps_delack,
206 		"\t\t%ld ack-only packet%s (%ld delayed)\n");
207 	p(tcps_sndurg, "\t\t%ld URG only packet%s\n");
208 	p(tcps_sndprobe, "\t\t%ld window probe packet%s\n");
209 	p(tcps_sndwinup, "\t\t%ld window update packet%s\n");
210 	p(tcps_sndctrl, "\t\t%ld control packet%s\n");
211 	p(tcps_rcvtotal, "\t%ld packet%s received\n");
212 	p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%ld ack%s (for %ld byte%s)\n");
213 	p(tcps_rcvdupack, "\t\t%ld duplicate ack%s\n");
214 	p(tcps_rcvacktoomuch, "\t\t%ld ack%s for unsent data\n");
215 	p2(tcps_rcvpack, tcps_rcvbyte,
216 		"\t\t%ld packet%s (%ld byte%s) received in-sequence\n");
217 	p2(tcps_rcvduppack, tcps_rcvdupbyte,
218 		"\t\t%ld completely duplicate packet%s (%ld byte%s)\n");
219 	p(tcps_pawsdrop, "\t\t%ld old duplicate packet%s\n");
220 	p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
221 		"\t\t%ld packet%s with some dup. data (%ld byte%s duped)\n");
222 	p2(tcps_rcvoopack, tcps_rcvoobyte,
223 		"\t\t%ld out-of-order packet%s (%ld byte%s)\n");
224 	p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
225 		"\t\t%ld packet%s (%ld byte%s) of data after window\n");
226 	p(tcps_rcvwinprobe, "\t\t%ld window probe%s\n");
227 	p(tcps_rcvwinupd, "\t\t%ld window update packet%s\n");
228 	p(tcps_rcvafterclose, "\t\t%ld packet%s received after close\n");
229 	p(tcps_rcvbadsum, "\t\t%ld discarded for bad checksum%s\n");
230 	p(tcps_rcvbadoff, "\t\t%ld discarded for bad header offset field%s\n");
231 	p(tcps_rcvshort, "\t\t%ld discarded because packet too short\n");
232 	p(tcps_connattempt, "\t%ld connection request%s\n");
233 	p(tcps_accepts, "\t%ld connection accept%s\n");
234 	p(tcps_badsyn, "\t%ld bad connection attempt%s\n");
235 	p(tcps_listendrop, "\t%ld listen queue overflow%s\n");
236 	p(tcps_connects, "\t%ld connection%s established (including accepts)\n");
237 	p2(tcps_closed, tcps_drops,
238 		"\t%ld connection%s closed (including %ld drop%s)\n");
239 	p(tcps_cachedrtt, "\t\t%ld connection%s updated cached RTT on close\n");
240 	p(tcps_cachedrttvar,
241 	  "\t\t%ld connection%s updated cached RTT variance on close\n");
242 	p(tcps_cachedssthresh,
243 	  "\t\t%ld connection%s updated cached ssthresh on close\n");
244 	p(tcps_conndrops, "\t%ld embryonic connection%s dropped\n");
245 	p2(tcps_rttupdated, tcps_segstimed,
246 		"\t%ld segment%s updated rtt (of %ld attempt%s)\n");
247 	p(tcps_rexmttimeo, "\t%ld retransmit timeout%s\n");
248 	p(tcps_timeoutdrop, "\t\t%ld connection%s dropped by rexmit timeout\n");
249 	p(tcps_persisttimeo, "\t%ld persist timeout%s\n");
250 	p(tcps_persistdrop, "\t\t%ld connection%s dropped by persist timeout\n");
251 	p(tcps_keeptimeo, "\t%ld keepalive timeout%s\n");
252 	p(tcps_keepprobe, "\t\t%ld keepalive probe%s sent\n");
253 	p(tcps_keepdrops, "\t\t%ld connection%s dropped by keepalive\n");
254 	p(tcps_predack, "\t%ld correct ACK header prediction%s\n");
255 	p(tcps_preddat, "\t%ld correct data packet header prediction%s\n");
256 #undef p
257 #undef p2
258 #undef p3
259 }
260 
261 /*
262  * Dump UDP statistics structure.
263  */
264 void
265 udp_stats(off, name)
266 	u_long off;
267 	char *name;
268 {
269 	struct udpstat udpstat;
270 	u_long delivered;
271 
272 	if (off == 0)
273 		return;
274 	kread(off, (char *)&udpstat, sizeof (udpstat));
275 	printf("%s:\n", name);
276 #define	p(f, m) if (udpstat.f || sflag <= 1) \
277     printf(m, udpstat.f, plural(udpstat.f))
278 	p(udps_ipackets, "\t%lu datagram%s received\n");
279 	p(udps_hdrops, "\t%lu with incomplete header\n");
280 	p(udps_badlen, "\t%lu with bad data length field\n");
281 	p(udps_badsum, "\t%lu with bad checksum\n");
282 	p(udps_noport, "\t%lu dropped due to no socket\n");
283 	p(udps_noportbcast, "\t%lu broadcast/multicast datagram%s dropped due to no socket\n");
284 	p(udps_fullsock, "\t%lu dropped due to full socket buffers\n");
285 	p(udpps_pcbhashmiss, "\t%lu not for hashed pcb\n");
286 	delivered = udpstat.udps_ipackets -
287 		    udpstat.udps_hdrops -
288 		    udpstat.udps_badlen -
289 		    udpstat.udps_badsum -
290 		    udpstat.udps_noport -
291 		    udpstat.udps_noportbcast -
292 		    udpstat.udps_fullsock;
293 	if (delivered || sflag <= 1)
294 		printf("\t%lu delivered\n", delivered);
295 	p(udps_opackets, "\t%lu datagram%s output\n");
296 #undef p
297 }
298 
299 /*
300  * Dump IP statistics structure.
301  */
302 void
303 ip_stats(off, name)
304 	u_long off;
305 	char *name;
306 {
307 	struct ipstat ipstat;
308 
309 	if (off == 0)
310 		return;
311 	kread(off, (char *)&ipstat, sizeof (ipstat));
312 	printf("%s:\n", name);
313 
314 #define	p(f, m) if (ipstat.f || sflag <= 1) \
315     printf(m, ipstat.f, plural(ipstat.f))
316 
317 	p(ips_total, "\t%lu total packet%s received\n");
318 	p(ips_badsum, "\t%lu bad header checksum%s\n");
319 	p(ips_toosmall, "\t%lu with size smaller than minimum\n");
320 	p(ips_tooshort, "\t%lu with data size < data length\n");
321 	p(ips_badhlen, "\t%lu with header length < data size\n");
322 	p(ips_badlen, "\t%lu with data length < header length\n");
323 	p(ips_badoptions, "\t%lu with bad options\n");
324 	p(ips_badvers, "\t%lu with incorrect version number\n");
325 	p(ips_fragments, "\t%lu fragment%s received\n");
326 	p(ips_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
327 	p(ips_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
328 	p(ips_reassembled, "\t%lu packet%s reassembled ok\n");
329 	p(ips_delivered, "\t%lu packet%s for this host\n");
330 	p(ips_noproto, "\t%lu packet%s for unknown/unsupported protocol\n");
331 	p(ips_forward, "\t%lu packet%s forwarded\n");
332 	p(ips_cantforward, "\t%lu packet%s not forwardable\n");
333 	p(ips_redirectsent, "\t%lu redirect%s sent\n");
334 	p(ips_localout, "\t%lu packet%s sent from this host\n");
335 	p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n");
336 	p(ips_odropped, "\t%lu output packet%s dropped due to no bufs, etc.\n");
337 	p(ips_noroute, "\t%lu output packet%s discarded due to no route\n");
338 	p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
339 	p(ips_ofragments, "\t%lu fragment%s created\n");
340 	p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
341 #undef p
342 }
343 
344 static	char *icmpnames[] = {
345 	"echo reply",
346 	"#1",
347 	"#2",
348 	"destination unreachable",
349 	"source quench",
350 	"routing redirect",
351 	"#6",
352 	"#7",
353 	"echo",
354 	"router advertisement",
355 	"router solicitation",
356 	"time exceeded",
357 	"parameter problem",
358 	"time stamp",
359 	"time stamp reply",
360 	"information request",
361 	"information request reply",
362 	"address mask request",
363 	"address mask reply",
364 };
365 
366 /*
367  * Dump ICMP statistics.
368  */
369 void
370 icmp_stats(off, name)
371 	u_long off;
372 	char *name;
373 {
374 	struct icmpstat icmpstat;
375 	register int i, first;
376 
377 	if (off == 0)
378 		return;
379 	kread(off, (char *)&icmpstat, sizeof (icmpstat));
380 	printf("%s:\n", name);
381 
382 #define	p(f, m) if (icmpstat.f || sflag <= 1) \
383     printf(m, icmpstat.f, plural(icmpstat.f))
384 
385 	p(icps_error, "\t%lu call%s to icmp_error\n");
386 	p(icps_oldicmp,
387 	    "\t%lu error%s not generated 'cuz old message was icmp\n");
388 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
389 		if (icmpstat.icps_outhist[i] != 0) {
390 			if (first) {
391 				printf("\tOutput histogram:\n");
392 				first = 0;
393 			}
394 			printf("\t\t%s: %lu\n", icmpnames[i],
395 				icmpstat.icps_outhist[i]);
396 		}
397 	p(icps_badcode, "\t%lu message%s with bad code fields\n");
398 	p(icps_tooshort, "\t%lu message%s < minimum length\n");
399 	p(icps_checksum, "\t%lu bad checksum%s\n");
400 	p(icps_badlen, "\t%lu message%s with bad length\n");
401 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
402 		if (icmpstat.icps_inhist[i] != 0) {
403 			if (first) {
404 				printf("\tInput histogram:\n");
405 				first = 0;
406 			}
407 			printf("\t\t%s: %lu\n", icmpnames[i],
408 				icmpstat.icps_inhist[i]);
409 		}
410 	p(icps_reflect, "\t%lu message response%s generated\n");
411 #undef p
412 }
413 
414 /*
415  * Dump IGMP statistics structure.
416  */
417 void
418 igmp_stats(off, name)
419 	u_long off;
420 	char *name;
421 {
422 	struct igmpstat igmpstat;
423 
424 	if (off == 0)
425 		return;
426 	kread(off, (char *)&igmpstat, sizeof (igmpstat));
427 	printf("%s:\n", name);
428 
429 #define	p(f, m) if (igmpstat.f || sflag <= 1) \
430     printf(m, igmpstat.f, plural(igmpstat.f))
431 #define	py(f, m) if (igmpstat.f || sflag <= 1) \
432     printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
433 	p(igps_rcv_total, "\t%u message%s received\n");
434         p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n");
435         p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n");
436         py(igps_rcv_queries, "\t%u membership quer%s received\n");
437         py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n");
438         p(igps_rcv_reports, "\t%u membership report%s received\n");
439         p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n");
440         p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n");
441         p(igps_snd_reports, "\t%u membership report%s sent\n");
442 #undef p
443 #undef py
444 }
445 
446 /*
447  * Pretty print an Internet address (net address + port).
448  */
449 void
450 inetprint(in, port, proto,numeric)
451 	register struct in_addr *in;
452 	int port;
453 	char *proto;
454 	int numeric;
455 {
456 	struct servent *sp = 0;
457 	char line[80], *cp;
458 	int width;
459 
460 	sprintf(line, "%.*s.", (Aflag && !numeric) ? 12 : 16, inetname(in));
461 	cp = index(line, '\0');
462 	if (!numeric && port)
463 		sp = getservbyport((int)port, proto);
464 	if (sp || port == 0)
465 		sprintf(cp, "%.15s", sp ? sp->s_name : "*");
466 	else
467 		sprintf(cp, "%d", ntohs((u_short)port));
468 	width = Aflag ? 18 : 22;
469 	printf(" %-*.*s", width, width, line);
470 }
471 
472 /*
473  * Construct an Internet address representation.
474  * If the nflag has been supplied, give
475  * numeric value, otherwise try for symbolic name.
476  */
477 char *
478 inetname(inp)
479 	struct in_addr *inp;
480 {
481 	register char *cp;
482 	static char line[50];
483 	struct hostent *hp;
484 	struct netent *np;
485 
486 	cp = 0;
487 	if (!nflag && inp->s_addr != INADDR_ANY) {
488 		int net = inet_netof(*inp);
489 		int lna = inet_lnaof(*inp);
490 
491 		if (lna == INADDR_ANY) {
492 			np = getnetbyaddr(net, AF_INET);
493 			if (np)
494 				cp = np->n_name;
495 		}
496 		if (cp == 0) {
497 			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
498 			if (hp) {
499 				cp = hp->h_name;
500 				trimdomain(cp);
501 			}
502 		}
503 	}
504 	if (inp->s_addr == INADDR_ANY)
505 		strcpy(line, "*");
506 	else if (cp)
507 		strcpy(line, cp);
508 	else {
509 		inp->s_addr = ntohl(inp->s_addr);
510 #define C(x)	((x) & 0xff)
511 		sprintf(line, "%lu.%lu.%lu.%lu", C(inp->s_addr >> 24),
512 		    C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
513 	}
514 	return (line);
515 }
516