xref: /freebsd/usr.bin/netstat/inet.c (revision 05c7a37afb48ddd5ee1bd921a5d46fe59cc70b15)
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 *));
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 ", inpcb.inp_ppcb);
140 			else
141 				printf("%8x ", next);
142 		printf("%-5.5s %6d %6d ", name, sockb.so_rcv.sb_cc,
143 			sockb.so_snd.sb_cc);
144 		inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport, name);
145 		inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport, name);
146 		if (istcp) {
147 			if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
148 				printf(" %d", tcpcb.t_state);
149                       else {
150 				printf(" %s", tcpstates[tcpcb.t_state]);
151 #if defined(TF_NEEDSYN) && defined(TF_NEEDFIN)
152                               /* Show T/TCP `hidden state' */
153                               if (tcpcb.t_flags & (TF_NEEDSYN|TF_NEEDFIN))
154                                       putchar('*');
155 #endif /* defined(TF_NEEDSYN) && defined(TF_NEEDFIN) */
156                       }
157 		}
158 		putchar('\n');
159 		prev = next;
160 	}
161 }
162 
163 /*
164  * Dump TCP statistics structure.
165  */
166 void
167 tcp_stats(off, name)
168 	u_long off;
169 	char *name;
170 {
171 	struct tcpstat tcpstat;
172 
173 	if (off == 0)
174 		return;
175 	printf ("%s:\n", name);
176 	kread(off, (char *)&tcpstat, sizeof (tcpstat));
177 
178 #define	p(f, m) if (tcpstat.f || sflag <= 1) \
179     printf(m, tcpstat.f, plural(tcpstat.f))
180 #define	p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
181     printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2, plural(tcpstat.f2))
182 #define	p3(f, m) if (tcpstat.f || sflag <= 1) \
183     printf(m, tcpstat.f, plurales(tcpstat.f))
184 
185 	p(tcps_sndtotal, "\t%d packet%s sent\n");
186 	p2(tcps_sndpack,tcps_sndbyte,
187 		"\t\t%d data packet%s (%d byte%s)\n");
188 	p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
189 		"\t\t%d data packet%s (%d byte%s) retransmitted\n");
190 	p(tcps_mturesent, "\t\t%d resend%s initiated by MTU discovery\n");
191 	p2(tcps_sndacks, tcps_delack,
192 		"\t\t%d ack-only packet%s (%d delayed)\n");
193 	p(tcps_sndurg, "\t\t%d URG only packet%s\n");
194 	p(tcps_sndprobe, "\t\t%d window probe packet%s\n");
195 	p(tcps_sndwinup, "\t\t%d window update packet%s\n");
196 	p(tcps_sndctrl, "\t\t%d control packet%s\n");
197 	p(tcps_rcvtotal, "\t%d packet%s received\n");
198 	p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%d ack%s (for %d byte%s)\n");
199 	p(tcps_rcvdupack, "\t\t%d duplicate ack%s\n");
200 	p(tcps_rcvacktoomuch, "\t\t%d ack%s for unsent data\n");
201 	p2(tcps_rcvpack, tcps_rcvbyte,
202 		"\t\t%d packet%s (%d byte%s) received in-sequence\n");
203 	p2(tcps_rcvduppack, tcps_rcvdupbyte,
204 		"\t\t%d completely duplicate packet%s (%d byte%s)\n");
205 	p(tcps_pawsdrop, "\t\t%d old duplicate packet%s\n");
206 	p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
207 		"\t\t%d packet%s with some dup. data (%d byte%s duped)\n");
208 	p2(tcps_rcvoopack, tcps_rcvoobyte,
209 		"\t\t%d out-of-order packet%s (%d byte%s)\n");
210 	p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
211 		"\t\t%d packet%s (%d byte%s) of data after window\n");
212 	p(tcps_rcvwinprobe, "\t\t%d window probe%s\n");
213 	p(tcps_rcvwinupd, "\t\t%d window update packet%s\n");
214 	p(tcps_rcvafterclose, "\t\t%d packet%s received after close\n");
215 	p(tcps_rcvbadsum, "\t\t%d discarded for bad checksum%s\n");
216 	p(tcps_rcvbadoff, "\t\t%d discarded for bad header offset field%s\n");
217 	p(tcps_rcvshort, "\t\t%d discarded because packet too short\n");
218 	p(tcps_connattempt, "\t%d connection request%s\n");
219 	p(tcps_accepts, "\t%d connection accept%s\n");
220 	p(tcps_badsyn, "\t%d bad connection attempt%s\n");
221 	p(tcps_listendrop, "\t%d listen queue overflow%s\n");
222 	p(tcps_connects, "\t%d connection%s established (including accepts)\n");
223 	p2(tcps_closed, tcps_drops,
224 		"\t%d connection%s closed (including %d drop%s)\n");
225 	p(tcps_cachedrtt, "\t\t%d connection%s updated cached RTT on close\n");
226 	p(tcps_cachedrttvar,
227 	  "\t\t%d connection%s updated cached RTT variance on close\n");
228 	p(tcps_cachedssthresh,
229 	  "\t\t%d connection%s updated cached ssthresh on close\n");
230 	p(tcps_conndrops, "\t%d embryonic connection%s dropped\n");
231 	p2(tcps_rttupdated, tcps_segstimed,
232 		"\t%d segment%s updated rtt (of %d attempt%s)\n");
233 	p(tcps_rexmttimeo, "\t%d retransmit timeout%s\n");
234 	p(tcps_timeoutdrop, "\t\t%d connection%s dropped by rexmit timeout\n");
235 	p(tcps_persisttimeo, "\t%d persist timeout%s\n");
236 	p(tcps_persistdrop, "\t\t%d connection%s dropped by persist timeout\n");
237 	p(tcps_keeptimeo, "\t%d keepalive timeout%s\n");
238 	p(tcps_keepprobe, "\t\t%d keepalive probe%s sent\n");
239 	p(tcps_keepdrops, "\t\t%d connection%s dropped by keepalive\n");
240 	p(tcps_predack, "\t%d correct ACK header prediction%s\n");
241 	p(tcps_preddat, "\t%d correct data packet header prediction%s\n");
242 #undef p
243 #undef p2
244 #undef p3
245 }
246 
247 /*
248  * Dump UDP statistics structure.
249  */
250 void
251 udp_stats(off, name)
252 	u_long off;
253 	char *name;
254 {
255 	struct udpstat udpstat;
256 	u_long delivered;
257 
258 	if (off == 0)
259 		return;
260 	kread(off, (char *)&udpstat, sizeof (udpstat));
261 	printf("%s:\n", name);
262 #define	p(f, m) if (udpstat.f || sflag <= 1) \
263     printf(m, udpstat.f, plural(udpstat.f))
264 	p(udps_ipackets, "\t%u datagram%s received\n");
265 	p(udps_hdrops, "\t%u with incomplete header\n");
266 	p(udps_badlen, "\t%u with bad data length field\n");
267 	p(udps_badsum, "\t%u with bad checksum\n");
268 	p(udps_noport, "\t%u dropped due to no socket\n");
269 	p(udps_noportbcast, "\t%u broadcast/multicast datagram%s dropped due to no socket\n");
270 	p(udps_fullsock, "\t%u dropped due to full socket buffers\n");
271 	delivered = udpstat.udps_ipackets -
272 		    udpstat.udps_hdrops -
273 		    udpstat.udps_badlen -
274 		    udpstat.udps_badsum -
275 		    udpstat.udps_noport -
276 		    udpstat.udps_noportbcast -
277 		    udpstat.udps_fullsock;
278 	if (delivered || sflag <= 1)
279 		printf("\t%u delivered\n", delivered);
280 	p(udps_opackets, "\t%u datagram%s output\n");
281 #undef p
282 }
283 
284 /*
285  * Dump IP statistics structure.
286  */
287 void
288 ip_stats(off, name)
289 	u_long off;
290 	char *name;
291 {
292 	struct ipstat ipstat;
293 
294 	if (off == 0)
295 		return;
296 	kread(off, (char *)&ipstat, sizeof (ipstat));
297 	printf("%s:\n", name);
298 
299 #define	p(f, m) if (ipstat.f || sflag <= 1) \
300     printf(m, ipstat.f, plural(ipstat.f))
301 
302 	p(ips_total, "\t%u total packet%s received\n");
303 	p(ips_badsum, "\t%u bad header checksum%s\n");
304 	p(ips_toosmall, "\t%u with size smaller than minimum\n");
305 	p(ips_tooshort, "\t%u with data size < data length\n");
306 	p(ips_badhlen, "\t%u with header length < data size\n");
307 	p(ips_badlen, "\t%u with data length < header length\n");
308 	p(ips_badoptions, "\t%u with bad options\n");
309 	p(ips_badvers, "\t%u with incorrect version number\n");
310 	p(ips_fragments, "\t%u fragment%s received\n");
311 	p(ips_fragdropped, "\t%u fragment%s dropped (dup or out of space)\n");
312 	p(ips_fragtimeout, "\t%u fragment%s dropped after timeout\n");
313 	p(ips_reassembled, "\t%u packet%s reassembled ok\n");
314 	p(ips_delivered, "\t%u packet%s for this host\n");
315 	p(ips_noproto, "\t%u packet%s for unknown/unsupported protocol\n");
316 	p(ips_forward, "\t%u packet%s forwarded\n");
317 	p(ips_cantforward, "\t%u packet%s not forwardable\n");
318 	p(ips_redirectsent, "\t%u redirect%s sent\n");
319 	p(ips_localout, "\t%u packet%s sent from this host\n");
320 	p(ips_rawout, "\t%u packet%s sent with fabricated ip header\n");
321 	p(ips_odropped, "\t%u output packet%s dropped due to no bufs, etc.\n");
322 	p(ips_noroute, "\t%u output packet%s discarded due to no route\n");
323 	p(ips_fragmented, "\t%u output datagram%s fragmented\n");
324 	p(ips_ofragments, "\t%u fragment%s created\n");
325 	p(ips_cantfrag, "\t%u datagram%s that can't be fragmented\n");
326 #undef p
327 }
328 
329 static	char *icmpnames[] = {
330 	"echo reply",
331 	"#1",
332 	"#2",
333 	"destination unreachable",
334 	"source quench",
335 	"routing redirect",
336 	"#6",
337 	"#7",
338 	"echo",
339 	"router advertisement",
340 	"router solicitation",
341 	"time exceeded",
342 	"parameter problem",
343 	"time stamp",
344 	"time stamp reply",
345 	"information request",
346 	"information request reply",
347 	"address mask request",
348 	"address mask reply",
349 };
350 
351 /*
352  * Dump ICMP statistics.
353  */
354 void
355 icmp_stats(off, name)
356 	u_long off;
357 	char *name;
358 {
359 	struct icmpstat icmpstat;
360 	register int i, first;
361 
362 	if (off == 0)
363 		return;
364 	kread(off, (char *)&icmpstat, sizeof (icmpstat));
365 	printf("%s:\n", name);
366 
367 #define	p(f, m) if (icmpstat.f || sflag <= 1) \
368     printf(m, icmpstat.f, plural(icmpstat.f))
369 
370 	p(icps_error, "\t%u call%s to icmp_error\n");
371 	p(icps_oldicmp,
372 	    "\t%u error%s not generated 'cuz old message was icmp\n");
373 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
374 		if (icmpstat.icps_outhist[i] != 0) {
375 			if (first) {
376 				printf("\tOutput histogram:\n");
377 				first = 0;
378 			}
379 			printf("\t\t%s: %u\n", icmpnames[i],
380 				icmpstat.icps_outhist[i]);
381 		}
382 	p(icps_badcode, "\t%u message%s with bad code fields\n");
383 	p(icps_tooshort, "\t%u message%s < minimum length\n");
384 	p(icps_checksum, "\t%u bad checksum%s\n");
385 	p(icps_badlen, "\t%u message%s with bad length\n");
386 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
387 		if (icmpstat.icps_inhist[i] != 0) {
388 			if (first) {
389 				printf("\tInput histogram:\n");
390 				first = 0;
391 			}
392 			printf("\t\t%s: %u\n", icmpnames[i],
393 				icmpstat.icps_inhist[i]);
394 		}
395 	p(icps_reflect, "\t%u message response%s generated\n");
396 #undef p
397 }
398 
399 /*
400  * Dump IGMP statistics structure.
401  */
402 void
403 igmp_stats(off, name)
404 	u_long off;
405 	char *name;
406 {
407 	struct igmpstat igmpstat;
408 
409 	if (off == 0)
410 		return;
411 	kread(off, (char *)&igmpstat, sizeof (igmpstat));
412 	printf("%s:\n", name);
413 
414 #define	p(f, m) if (igmpstat.f || sflag <= 1) \
415     printf(m, igmpstat.f, plural(igmpstat.f))
416 #define	py(f, m) if (igmpstat.f || sflag <= 1) \
417     printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
418 	p(igps_rcv_total, "\t%u message%s received\n");
419         p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n");
420         p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n");
421         py(igps_rcv_queries, "\t%u membership quer%s received\n");
422         py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n");
423         p(igps_rcv_reports, "\t%u membership report%s received\n");
424         p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n");
425         p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n");
426         p(igps_snd_reports, "\t%u membership report%s sent\n");
427 #undef p
428 #undef py
429 }
430 
431 /*
432  * Pretty print an Internet address (net address + port).
433  * If the nflag was specified, use numbers instead of names.
434  */
435 void
436 inetprint(in, port, proto)
437 	register struct in_addr *in;
438 	int port;
439 	char *proto;
440 {
441 	struct servent *sp = 0;
442 	char line[80], *cp;
443 	int width;
444 
445 	sprintf(line, "%.*s.", (Aflag && !nflag) ? 12 : 16, inetname(in));
446 	cp = index(line, '\0');
447 	if (!nflag && port)
448 		sp = getservbyport((int)port, proto);
449 	if (sp || port == 0)
450 		sprintf(cp, "%.15s", sp ? sp->s_name : "*");
451 	else
452 		sprintf(cp, "%d", ntohs((u_short)port));
453 	width = Aflag ? 18 : 22;
454 	printf(" %-*.*s", width, width, line);
455 }
456 
457 /*
458  * Construct an Internet address representation.
459  * If the nflag has been supplied, give
460  * numeric value, otherwise try for symbolic name.
461  */
462 char *
463 inetname(inp)
464 	struct in_addr *inp;
465 {
466 	register char *cp;
467 	static char line[50];
468 	struct hostent *hp;
469 	struct netent *np;
470 
471 	cp = 0;
472 	if (!nflag && inp->s_addr != INADDR_ANY) {
473 		int net = inet_netof(*inp);
474 		int lna = inet_lnaof(*inp);
475 
476 		if (lna == INADDR_ANY) {
477 			np = getnetbyaddr(net, AF_INET);
478 			if (np)
479 				cp = np->n_name;
480 		}
481 		if (cp == 0) {
482 			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
483 			if (hp) {
484 				cp = hp->h_name;
485 				trimdomain(cp);
486 			}
487 		}
488 	}
489 	if (inp->s_addr == INADDR_ANY)
490 		strcpy(line, "*");
491 	else if (cp)
492 		strcpy(line, cp);
493 	else {
494 		inp->s_addr = ntohl(inp->s_addr);
495 #define C(x)	((x) & 0xff)
496 		sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24),
497 		    C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
498 	}
499 	return (line);
500 }
501