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