xref: /freebsd/usr.bin/netstat/inet.c (revision 3e0f6b97b257a96f7275e4442204263e44b16686)
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 	"$FreeBSD$";
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%lu packet%s sent\n");
203 	p2(tcps_sndpack,tcps_sndbyte,
204 		"\t\t%lu data packet%s (%lu byte%s)\n");
205 	p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
206 		"\t\t%lu data packet%s (%lu byte%s) retransmitted\n");
207 	p(tcps_mturesent, "\t\t%lu resend%s initiated by MTU discovery\n");
208 	p2(tcps_sndacks, tcps_delack,
209 		"\t\t%lu ack-only packet%s (%lu delayed)\n");
210 	p(tcps_sndurg, "\t\t%lu URG only packet%s\n");
211 	p(tcps_sndprobe, "\t\t%lu window probe packet%s\n");
212 	p(tcps_sndwinup, "\t\t%lu window update packet%s\n");
213 	p(tcps_sndctrl, "\t\t%lu control packet%s\n");
214 	p(tcps_rcvtotal, "\t%lu packet%s received\n");
215 	p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%lu ack%s (for %lu byte%s)\n");
216 	p(tcps_rcvdupack, "\t\t%lu duplicate ack%s\n");
217 	p(tcps_rcvacktoomuch, "\t\t%lu ack%s for unsent data\n");
218 	p2(tcps_rcvpack, tcps_rcvbyte,
219 		"\t\t%lu packet%s (%lu byte%s) received in-sequence\n");
220 	p2(tcps_rcvduppack, tcps_rcvdupbyte,
221 		"\t\t%lu completely duplicate packet%s (%lu byte%s)\n");
222 	p(tcps_pawsdrop, "\t\t%lu old duplicate packet%s\n");
223 	p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
224 		"\t\t%lu packet%s with some dup. data (%lu byte%s duped)\n");
225 	p2(tcps_rcvoopack, tcps_rcvoobyte,
226 		"\t\t%lu out-of-order packet%s (%lu byte%s)\n");
227 	p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
228 		"\t\t%lu packet%s (%lu byte%s) of data after window\n");
229 	p(tcps_rcvwinprobe, "\t\t%lu window probe%s\n");
230 	p(tcps_rcvwinupd, "\t\t%lu window update packet%s\n");
231 	p(tcps_rcvafterclose, "\t\t%lu packet%s received after close\n");
232 	p(tcps_rcvbadsum, "\t\t%lu discarded for bad checksum%s\n");
233 	p(tcps_rcvbadoff, "\t\t%lu discarded for bad header offset field%s\n");
234 	p(tcps_rcvshort, "\t\t%lu discarded because packet too short\n");
235 	p(tcps_connattempt, "\t%lu connection request%s\n");
236 	p(tcps_accepts, "\t%lu connection accept%s\n");
237 	p(tcps_badsyn, "\t%lu bad connection attempt%s\n");
238 	p(tcps_listendrop, "\t%lu listen queue overflow%s\n");
239 	p(tcps_connects, "\t%lu connection%s established (including accepts)\n");
240 	p2(tcps_closed, tcps_drops,
241 		"\t%lu connection%s closed (including %lu drop%s)\n");
242 	p(tcps_cachedrtt, "\t\t%lu connection%s updated cached RTT on close\n");
243 	p(tcps_cachedrttvar,
244 	  "\t\t%lu connection%s updated cached RTT variance on close\n");
245 	p(tcps_cachedssthresh,
246 	  "\t\t%lu connection%s updated cached ssthresh on close\n");
247 	p(tcps_conndrops, "\t%lu embryonic connection%s dropped\n");
248 	p2(tcps_rttupdated, tcps_segstimed,
249 		"\t%lu segment%s updated rtt (of %lu attempt%s)\n");
250 	p(tcps_rexmttimeo, "\t%lu retransmit timeout%s\n");
251 	p(tcps_timeoutdrop, "\t\t%lu connection%s dropped by rexmit timeout\n");
252 	p(tcps_persisttimeo, "\t%lu persist timeout%s\n");
253 	p(tcps_persistdrop, "\t\t%lu connection%s dropped by persist timeout\n");
254 	p(tcps_keeptimeo, "\t%lu keepalive timeout%s\n");
255 	p(tcps_keepprobe, "\t\t%lu keepalive probe%s sent\n");
256 	p(tcps_keepdrops, "\t\t%lu connection%s dropped by keepalive\n");
257 	p(tcps_predack, "\t%lu correct ACK header prediction%s\n");
258 	p(tcps_preddat, "\t%lu 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_notmember,
337 	  "\t%lu packet%s received for unknown multicast group\n");
338 	p(ips_redirectsent, "\t%lu redirect%s sent\n");
339 	p(ips_localout, "\t%lu packet%s sent from this host\n");
340 	p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n");
341 	p(ips_odropped,
342 	  "\t%lu output packet%s dropped due to no bufs, etc.\n");
343 	p(ips_noroute, "\t%lu output packet%s discarded due to no route\n");
344 	p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
345 	p(ips_ofragments, "\t%lu fragment%s created\n");
346 	p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
347 #undef p
348 }
349 
350 static	char *icmpnames[] = {
351 	"echo reply",
352 	"#1",
353 	"#2",
354 	"destination unreachable",
355 	"source quench",
356 	"routing redirect",
357 	"#6",
358 	"#7",
359 	"echo",
360 	"router advertisement",
361 	"router solicitation",
362 	"time exceeded",
363 	"parameter problem",
364 	"time stamp",
365 	"time stamp reply",
366 	"information request",
367 	"information request reply",
368 	"address mask request",
369 	"address mask reply",
370 };
371 
372 /*
373  * Dump ICMP statistics.
374  */
375 void
376 icmp_stats(off, name)
377 	u_long off;
378 	char *name;
379 {
380 	struct icmpstat icmpstat;
381 	register int i, first;
382 
383 	if (off == 0)
384 		return;
385 	kread(off, (char *)&icmpstat, sizeof (icmpstat));
386 	printf("%s:\n", name);
387 
388 #define	p(f, m) if (icmpstat.f || sflag <= 1) \
389     printf(m, icmpstat.f, plural(icmpstat.f))
390 
391 	p(icps_error, "\t%lu call%s to icmp_error\n");
392 	p(icps_oldicmp,
393 	    "\t%lu error%s not generated 'cuz old message was icmp\n");
394 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
395 		if (icmpstat.icps_outhist[i] != 0) {
396 			if (first) {
397 				printf("\tOutput histogram:\n");
398 				first = 0;
399 			}
400 			printf("\t\t%s: %lu\n", icmpnames[i],
401 				icmpstat.icps_outhist[i]);
402 		}
403 	p(icps_badcode, "\t%lu message%s with bad code fields\n");
404 	p(icps_tooshort, "\t%lu message%s < minimum length\n");
405 	p(icps_checksum, "\t%lu bad checksum%s\n");
406 	p(icps_badlen, "\t%lu message%s with bad length\n");
407 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
408 		if (icmpstat.icps_inhist[i] != 0) {
409 			if (first) {
410 				printf("\tInput histogram:\n");
411 				first = 0;
412 			}
413 			printf("\t\t%s: %lu\n", icmpnames[i],
414 				icmpstat.icps_inhist[i]);
415 		}
416 	p(icps_reflect, "\t%lu message response%s generated\n");
417 #undef p
418 }
419 
420 /*
421  * Dump IGMP statistics structure.
422  */
423 void
424 igmp_stats(off, name)
425 	u_long off;
426 	char *name;
427 {
428 	struct igmpstat igmpstat;
429 
430 	if (off == 0)
431 		return;
432 	kread(off, (char *)&igmpstat, sizeof (igmpstat));
433 	printf("%s:\n", name);
434 
435 #define	p(f, m) if (igmpstat.f || sflag <= 1) \
436     printf(m, igmpstat.f, plural(igmpstat.f))
437 #define	py(f, m) if (igmpstat.f || sflag <= 1) \
438     printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
439 	p(igps_rcv_total, "\t%u message%s received\n");
440         p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n");
441         p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n");
442         py(igps_rcv_queries, "\t%u membership quer%s received\n");
443         py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n");
444         p(igps_rcv_reports, "\t%u membership report%s received\n");
445         p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n");
446         p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n");
447         p(igps_snd_reports, "\t%u membership report%s sent\n");
448 #undef p
449 #undef py
450 }
451 
452 /*
453  * Pretty print an Internet address (net address + port).
454  */
455 void
456 inetprint(in, port, proto,numeric)
457 	register struct in_addr *in;
458 	int port;
459 	char *proto;
460 	int numeric;
461 {
462 	struct servent *sp = 0;
463 	char line[80], *cp;
464 	int width;
465 
466 	sprintf(line, "%.*s.", (Aflag && !numeric) ? 12 : 16, inetname(in));
467 	cp = index(line, '\0');
468 	if (!numeric && port)
469 		sp = getservbyport((int)port, proto);
470 	if (sp || port == 0)
471 		sprintf(cp, "%.15s", sp ? sp->s_name : "*");
472 	else
473 		sprintf(cp, "%d", ntohs((u_short)port));
474 	width = Aflag ? 18 : 22;
475 	printf(" %-*.*s", width, width, line);
476 }
477 
478 /*
479  * Construct an Internet address representation.
480  * If the nflag has been supplied, give
481  * numeric value, otherwise try for symbolic name.
482  */
483 char *
484 inetname(inp)
485 	struct in_addr *inp;
486 {
487 	register char *cp;
488 	static char line[50];
489 	struct hostent *hp;
490 	struct netent *np;
491 
492 	cp = 0;
493 	if (!nflag && inp->s_addr != INADDR_ANY) {
494 		int net = inet_netof(*inp);
495 		int lna = inet_lnaof(*inp);
496 
497 		if (lna == INADDR_ANY) {
498 			np = getnetbyaddr(net, AF_INET);
499 			if (np)
500 				cp = np->n_name;
501 		}
502 		if (cp == 0) {
503 			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
504 			if (hp) {
505 				cp = hp->h_name;
506 				trimdomain(cp);
507 			}
508 		}
509 	}
510 	if (inp->s_addr == INADDR_ANY)
511 		strcpy(line, "*");
512 	else if (cp)
513 		strcpy(line, cp);
514 	else {
515 		inp->s_addr = ntohl(inp->s_addr);
516 #define C(x)	((x) & 0xff)
517 		sprintf(line, "%lu.%lu.%lu.%lu", C(inp->s_addr >> 24),
518 		    C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
519 	}
520 	return (line);
521 }
522