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