xref: /netbsd-src/usr.bin/netstat/inet.c (revision d48f14661dda8638fee055ba15d35bdfb29b9fa8)
1 /*	$NetBSD: inet.c,v 1.73 2006/06/20 19:22:17 rpaulo Exp $	*/
2 
3 /*
4  * Copyright (c) 1983, 1988, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "from: @(#)inet.c	8.4 (Berkeley) 4/20/94";
36 #else
37 __RCSID("$NetBSD: inet.c,v 1.73 2006/06/20 19:22:17 rpaulo Exp $");
38 #endif
39 #endif /* not lint */
40 
41 #include <sys/param.h>
42 #include <sys/queue.h>
43 #include <sys/socket.h>
44 #include <sys/socketvar.h>
45 #include <sys/mbuf.h>
46 #include <sys/protosw.h>
47 #include <sys/sysctl.h>
48 
49 #include <net/if_arp.h>
50 #include <net/route.h>
51 #include <netinet/in.h>
52 #include <netinet/in_systm.h>
53 #include <netinet/ip.h>
54 #include <netinet/in_pcb.h>
55 #include <netinet/ip_icmp.h>
56 
57 #ifdef INET6
58 #include <netinet/ip6.h>
59 #endif
60 
61 #include <netinet/icmp_var.h>
62 #include <netinet/igmp_var.h>
63 #include <netinet/ip_var.h>
64 #include <netinet/pim_var.h>
65 #include <netinet/tcp.h>
66 #include <netinet/tcpip.h>
67 #include <netinet/tcp_seq.h>
68 #define TCPSTATES
69 #include <netinet/tcp_fsm.h>
70 #define	TCPTIMERS
71 #include <netinet/tcp_timer.h>
72 #include <netinet/tcp_var.h>
73 #include <netinet/tcp_debug.h>
74 #include <netinet/udp.h>
75 #include <netinet/ip_carp.h>
76 #include <netinet/udp_var.h>
77 
78 #include <arpa/inet.h>
79 #include <kvm.h>
80 #include <netdb.h>
81 #include <stdio.h>
82 #include <string.h>
83 #include <unistd.h>
84 #include <stdlib.h>
85 #include <err.h>
86 #include "netstat.h"
87 
88 struct	inpcb inpcb;
89 struct	tcpcb tcpcb;
90 struct	socket sockb;
91 
92 char	*inetname __P((struct in_addr *));
93 void	inetprint __P((struct in_addr *, u_int16_t, const char *, int));
94 
95 /*
96  * Print a summary of connections related to an Internet
97  * protocol.  For TCP, also give state of connection.
98  * Listening processes (aflag) are suppressed unless the
99  * -a (all) flag is specified.
100  */
101 static int width;
102 static int compact;
103 
104 static void
105 protoprhdr(void)
106 {
107 	printf("Active Internet connections");
108 	if (aflag)
109 		printf(" (including servers)");
110 	putchar('\n');
111 	if (Aflag)
112 		printf("%-8.8s ", "PCB");
113 	printf("%-5.5s %-6.6s %-6.6s %s%-*.*s %-*.*s %s\n",
114 		"Proto", "Recv-Q", "Send-Q", compact ? "" : " ",
115 		width, width, "Local Address",
116 		width, width, "Foreign Address",
117 		"State");
118 }
119 
120 static void
121 protopr0(intptr_t ppcb, u_long rcv_sb_cc, u_long snd_sb_cc,
122 	 struct in_addr *laddr, u_int16_t lport,
123 	 struct in_addr *faddr, u_int16_t fport,
124 	 short t_state, char *name)
125 {
126 	static char *shorttcpstates[] = {
127 		"CLOSED",	"LISTEN",	"SYNSEN",	"SYSRCV",
128 		"ESTABL",	"CLWAIT",	"FWAIT1",	"CLOSNG",
129 		"LASTAK",	"FWAIT2",	"TMWAIT",
130 	};
131 	int istcp;
132 
133 	istcp = strcmp(name, "tcp") == 0;
134 
135 	if (Aflag) {
136 		printf("%8" PRIxPTR " ", ppcb);
137 	}
138 	printf("%-5.5s %6ld %6ld%s", name, rcv_sb_cc, snd_sb_cc,
139 	       compact ? "" : " ");
140 	if (numeric_port) {
141 		inetprint(laddr, lport, name, 1);
142 		inetprint(faddr, fport, name, 1);
143 	} else if (inpcb.inp_flags & INP_ANONPORT) {
144 		inetprint(laddr, lport, name, 1);
145 		inetprint(faddr, fport, name, 0);
146 	} else {
147 		inetprint(laddr, lport, name, 0);
148 		inetprint(faddr, fport, name, 0);
149 	}
150 	if (istcp) {
151 		if (t_state < 0 || t_state >= TCP_NSTATES)
152 			printf(" %d", t_state);
153 		else
154 			printf(" %s", compact ? shorttcpstates[t_state] :
155 			       tcpstates[t_state]);
156 	}
157 	putchar('\n');
158 }
159 
160 void
161 protopr(off, name)
162 	u_long off;
163 	char *name;
164 {
165 	struct inpcbtable table;
166 	struct inpcb *head, *next, *prev;
167 	struct inpcb inpcb;
168 	int istcp;
169 	static int first = 1;
170 
171 	compact = 0;
172 	if (Aflag) {
173 		if (!numeric_addr)
174 			width = 18;
175 		else {
176 			width = 21;
177 			compact = 1;
178 		}
179 	} else
180 		width = 22;
181 
182 	if (use_sysctl) {
183 		struct kinfo_pcb *pcblist;
184 		int mib[8];
185 		size_t namelen = 0, size = 0, i;
186 		char *mibname = NULL;
187 
188 		memset(mib, 0, sizeof(mib));
189 
190 		if (asprintf(&mibname, "net.inet.%s.pcblist", name) == -1)
191 			err(1, "asprintf");
192 
193 		/* get dynamic pcblist node */
194 		if (sysctlnametomib(mibname, mib, &namelen) == -1)
195 			err(1, "sysctlnametomib");
196 
197 		if (sysctl(mib, sizeof(mib) / sizeof(*mib), NULL, &size,
198 			   NULL, 0) == -1)
199 			err(1, "sysctl (query)");
200 
201 		if ((pcblist = malloc(size)) == NULL)
202 			err(1, "malloc");
203 		memset(pcblist, 0, size);
204 
205 	        mib[6] = sizeof(*pcblist);
206         	mib[7] = size / sizeof(*pcblist);
207 
208 		if (sysctl(mib, sizeof(mib) / sizeof(*mib), pcblist,
209 			   &size, NULL, 0) == -1)
210 			err(1, "sysctl (copy)");
211 
212 		for (i = 0; i < size / sizeof(*pcblist); i++) {
213 			struct sockaddr_in src, dst;
214 
215 			memcpy(&src, &pcblist[i].ki_s, sizeof(src));
216 			memcpy(&dst, &pcblist[i].ki_d, sizeof(dst));
217 
218 			if (first) {
219 				protoprhdr();
220 				first = 0;
221 			}
222 
223 	                protopr0((intptr_t) pcblist[i].ki_ppcbaddr,
224 				 pcblist[i].ki_rcvq, pcblist[i].ki_sndq,
225 				 &src.sin_addr, src.sin_port,
226 				 &dst.sin_addr, dst.sin_port,
227 				 pcblist[i].ki_tstate, name);
228 		}
229 
230 		free(pcblist);
231 		return;
232 	}
233 
234 	if (off == 0)
235 		return;
236 	istcp = strcmp(name, "tcp") == 0;
237 	kread(off, (char *)&table, sizeof table);
238 	prev = head =
239 	    (struct inpcb *)&((struct inpcbtable *)off)->inpt_queue.cqh_first;
240 	next = (struct inpcb *)table.inpt_queue.cqh_first;
241 
242 	while (next != head) {
243 		kread((u_long)next, (char *)&inpcb, sizeof inpcb);
244 		if ((struct inpcb *)inpcb.inp_queue.cqe_prev != prev) {
245 			printf("???\n");
246 			break;
247 		}
248 		prev = next;
249 		next = (struct inpcb *)inpcb.inp_queue.cqe_next;
250 
251 		if (inpcb.inp_af != AF_INET)
252 			continue;
253 
254 		if (!aflag &&
255 		    inet_lnaof(inpcb.inp_laddr) == INADDR_ANY)
256 			continue;
257 		kread((u_long)inpcb.inp_socket, (char *)&sockb, sizeof (sockb));
258 		if (istcp) {
259 			kread((u_long)inpcb.inp_ppcb,
260 			    (char *)&tcpcb, sizeof (tcpcb));
261 		}
262 
263 		if (first) {
264 			protoprhdr();
265 			first = 0;
266 		}
267 
268 		protopr0(istcp ? (intptr_t) inpcb.inp_ppcb : (intptr_t) prev,
269 			 sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc,
270 			 &inpcb.inp_laddr, inpcb.inp_lport,
271 			 &inpcb.inp_faddr, inpcb.inp_fport,
272 			 tcpcb.t_state, name);
273 	}
274 }
275 
276 /*
277  * Dump TCP statistics structure.
278  */
279 void
280 tcp_stats(off, name)
281 	u_long off;
282 	char *name;
283 {
284 	struct tcpstat tcpstat;
285 
286 	if (use_sysctl) {
287 		size_t size = sizeof(tcpstat);
288 
289 		if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &size,
290 				 NULL, 0) == -1)
291 			err(1, "net.inet.tcp.stats");
292 	} else {
293 		if (off == 0)
294 			return;
295 		kread(off, (char *)&tcpstat, sizeof (tcpstat));
296 	}
297 
298 	printf ("%s:\n", name);
299 
300 #define	ps(f, m) if (tcpstat.f || sflag <= 1) \
301     printf(m, (unsigned long long)tcpstat.f)
302 #define	p(f, m) if (tcpstat.f || sflag <= 1) \
303     printf(m, (unsigned long long)tcpstat.f, plural(tcpstat.f))
304 #define	p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
305     printf(m, (unsigned long long)tcpstat.f1, plural(tcpstat.f1), \
306     (unsigned long long)tcpstat.f2, plural(tcpstat.f2))
307 #define	p2s(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
308     printf(m, (unsigned long long)tcpstat.f1, plural(tcpstat.f1), \
309     (unsigned long long)tcpstat.f2)
310 #define	p3(f, m) if (tcpstat.f || sflag <= 1) \
311     printf(m, (unsigned long long)tcpstat.f, plurales(tcpstat.f))
312 
313 	p(tcps_sndtotal, "\t%llu packet%s sent\n");
314 	p2(tcps_sndpack,tcps_sndbyte,
315 		"\t\t%llu data packet%s (%llu byte%s)\n");
316 	p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
317 		"\t\t%llu data packet%s (%llu byte%s) retransmitted\n");
318 	p2s(tcps_sndacks, tcps_delack,
319 		"\t\t%llu ack-only packet%s (%llu delayed)\n");
320 	p(tcps_sndurg, "\t\t%llu URG only packet%s\n");
321 	p(tcps_sndprobe, "\t\t%llu window probe packet%s\n");
322 	p(tcps_sndwinup, "\t\t%llu window update packet%s\n");
323 	p(tcps_sndctrl, "\t\t%llu control packet%s\n");
324 	p(tcps_selfquench,
325 	    "\t\t%llu send attempt%s resulted in self-quench\n");
326 	p(tcps_rcvtotal, "\t%llu packet%s received\n");
327 	p2(tcps_rcvackpack, tcps_rcvackbyte,
328 		"\t\t%llu ack%s (for %llu byte%s)\n");
329 	p(tcps_rcvdupack, "\t\t%llu duplicate ack%s\n");
330 	p(tcps_rcvacktoomuch, "\t\t%llu ack%s for unsent data\n");
331 	p2(tcps_rcvpack, tcps_rcvbyte,
332 		"\t\t%llu packet%s (%llu byte%s) received in-sequence\n");
333 	p2(tcps_rcvduppack, tcps_rcvdupbyte,
334 		"\t\t%llu completely duplicate packet%s (%llu byte%s)\n");
335 	p(tcps_pawsdrop, "\t\t%llu old duplicate packet%s\n");
336 	p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
337 		"\t\t%llu packet%s with some dup. data (%llu byte%s duped)\n");
338 	p2(tcps_rcvoopack, tcps_rcvoobyte,
339 		"\t\t%llu out-of-order packet%s (%llu byte%s)\n");
340 	p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
341 		"\t\t%llu packet%s (%llu byte%s) of data after window\n");
342 	p(tcps_rcvwinprobe, "\t\t%llu window probe%s\n");
343 	p(tcps_rcvwinupd, "\t\t%llu window update packet%s\n");
344 	p(tcps_rcvafterclose, "\t\t%llu packet%s received after close\n");
345 	p(tcps_rcvbadsum, "\t\t%llu discarded for bad checksum%s\n");
346 	p(tcps_rcvbadoff, "\t\t%llu discarded for bad header offset field%s\n");
347 	ps(tcps_rcvshort, "\t\t%llu discarded because packet too short\n");
348 	p(tcps_connattempt, "\t%llu connection request%s\n");
349 	p(tcps_accepts, "\t%llu connection accept%s\n");
350 	p(tcps_connects,
351 		"\t%llu connection%s established (including accepts)\n");
352 	p2(tcps_closed, tcps_drops,
353 		"\t%llu connection%s closed (including %llu drop%s)\n");
354 	p(tcps_conndrops, "\t%llu embryonic connection%s dropped\n");
355 	p(tcps_delayed_free, "\t%llu delayed free%s of tcpcb\n");
356 	p2(tcps_rttupdated, tcps_segstimed,
357 		"\t%llu segment%s updated rtt (of %llu attempt%s)\n");
358 	p(tcps_rexmttimeo, "\t%llu retransmit timeout%s\n");
359 	p(tcps_timeoutdrop,
360 		"\t\t%llu connection%s dropped by rexmit timeout\n");
361 	p2(tcps_persisttimeo, tcps_persistdrops,
362 	   "\t%llu persist timeout%s (resulting in %llu dropped "
363 		"connection%s)\n");
364 	p(tcps_keeptimeo, "\t%llu keepalive timeout%s\n");
365 	p(tcps_keepprobe, "\t\t%llu keepalive probe%s sent\n");
366 	p(tcps_keepdrops, "\t\t%llu connection%s dropped by keepalive\n");
367 	p(tcps_predack, "\t%llu correct ACK header prediction%s\n");
368 	p(tcps_preddat, "\t%llu correct data packet header prediction%s\n");
369 	p3(tcps_pcbhashmiss, "\t%llu PCB hash miss%s\n");
370 	ps(tcps_noport, "\t%llu dropped due to no socket\n");
371 	p(tcps_connsdrained, "\t%llu connection%s drained due to memory "
372 		"shortage\n");
373 	p(tcps_pmtublackhole, "\t%llu PMTUD blackhole%s detected\n");
374 
375 	p(tcps_badsyn, "\t%llu bad connection attempt%s\n");
376 	ps(tcps_sc_added, "\t%llu SYN cache entries added\n");
377 	p(tcps_sc_collisions, "\t\t%llu hash collision%s\n");
378 	ps(tcps_sc_completed, "\t\t%llu completed\n");
379 	ps(tcps_sc_aborted, "\t\t%llu aborted (no space to build PCB)\n");
380 	ps(tcps_sc_timed_out, "\t\t%llu timed out\n");
381 	ps(tcps_sc_overflowed, "\t\t%llu dropped due to overflow\n");
382 	ps(tcps_sc_bucketoverflow, "\t\t%llu dropped due to bucket overflow\n");
383 	ps(tcps_sc_reset, "\t\t%llu dropped due to RST\n");
384 	ps(tcps_sc_unreach, "\t\t%llu dropped due to ICMP unreachable\n");
385 	ps(tcps_sc_delayed_free, "\t\t%llu delayed free of SYN cache "
386 		"entries\n");
387 	p(tcps_sc_retransmitted, "\t%llu SYN,ACK%s retransmitted\n");
388 	p(tcps_sc_dupesyn, "\t%llu duplicate SYN%s received for entries "
389 		"already in the cache\n");
390 	p(tcps_sc_dropped, "\t%llu SYN%s dropped (no route or no space)\n");
391 	p(tcps_badsig, "\t%llu packet%s with bad signature\n");
392 	p(tcps_goodsig, "\t%llu packet%s with good signature\n");
393 
394 #undef p
395 #undef ps
396 #undef p2
397 #undef p2s
398 #undef p3
399 }
400 
401 /*
402  * Dump UDP statistics structure.
403  */
404 void
405 udp_stats(off, name)
406 	u_long off;
407 	char *name;
408 {
409 	struct udpstat udpstat;
410 	u_quad_t delivered;
411 
412 	if (use_sysctl) {
413 		size_t size = sizeof(udpstat);
414 
415 		if (sysctlbyname("net.inet.udp.stats", &udpstat, &size,
416 				 NULL, 0) == -1)
417 			err(1, "net.inet.udp.stats");
418 	} else {
419 		if (off == 0)
420 			return;
421 		kread(off, (char *)&udpstat, sizeof (udpstat));
422 	}
423 
424 	printf ("%s:\n", name);
425 
426 #define	ps(f, m) if (udpstat.f || sflag <= 1) \
427     printf(m, (unsigned long long)udpstat.f)
428 #define	p(f, m) if (udpstat.f || sflag <= 1) \
429     printf(m, (unsigned long long)udpstat.f, plural(udpstat.f))
430 #define	p3(f, m) if (udpstat.f || sflag <= 1) \
431     printf(m, (unsigned long long)udpstat.f, plurales(udpstat.f))
432 
433 	p(udps_ipackets, "\t%llu datagram%s received\n");
434 	ps(udps_hdrops, "\t%llu with incomplete header\n");
435 	ps(udps_badlen, "\t%llu with bad data length field\n");
436 	ps(udps_badsum, "\t%llu with bad checksum\n");
437 	ps(udps_noport, "\t%llu dropped due to no socket\n");
438 	p(udps_noportbcast, "\t%llu broadcast/multicast datagram%s dropped due to no socket\n");
439 	ps(udps_fullsock, "\t%llu dropped due to full socket buffers\n");
440 	delivered = udpstat.udps_ipackets -
441 		    udpstat.udps_hdrops -
442 		    udpstat.udps_badlen -
443 		    udpstat.udps_badsum -
444 		    udpstat.udps_noport -
445 		    udpstat.udps_noportbcast -
446 		    udpstat.udps_fullsock;
447 	if (delivered || sflag <= 1)
448 		printf("\t%llu delivered\n", (unsigned long long)delivered);
449 	p3(udps_pcbhashmiss, "\t%llu PCB hash miss%s\n");
450 	p(udps_opackets, "\t%llu datagram%s output\n");
451 
452 #undef ps
453 #undef p
454 #undef p3
455 }
456 
457 /*
458  * Dump IP statistics structure.
459  */
460 void
461 ip_stats(off, name)
462 	u_long off;
463 	char *name;
464 {
465 	struct ipstat ipstat;
466 
467 	if (use_sysctl) {
468 		size_t size = sizeof(ipstat);
469 
470 		if (sysctlbyname("net.inet.ip.stats", &ipstat, &size,
471 				 NULL, 0) == -1)
472 			err(1, "net.inet.ip.stats");
473 	} else {
474 		if (off == 0)
475 			return;
476 		kread(off, (char *)&ipstat, sizeof (ipstat));
477 	}
478 
479 	printf("%s:\n", name);
480 
481 #define	ps(f, m) if (ipstat.f || sflag <= 1) \
482     printf(m, (unsigned long long)ipstat.f)
483 #define	p(f, m) if (ipstat.f || sflag <= 1) \
484     printf(m, (unsigned long long)ipstat.f, plural(ipstat.f))
485 
486 	p(ips_total, "\t%llu total packet%s received\n");
487 	p(ips_badsum, "\t%llu bad header checksum%s\n");
488 	ps(ips_toosmall, "\t%llu with size smaller than minimum\n");
489 	ps(ips_tooshort, "\t%llu with data size < data length\n");
490 	ps(ips_toolong, "\t%llu with length > max ip packet size\n");
491 	ps(ips_badhlen, "\t%llu with header length < data size\n");
492 	ps(ips_badlen, "\t%llu with data length < header length\n");
493 	ps(ips_badoptions, "\t%llu with bad options\n");
494 	ps(ips_badvers, "\t%llu with incorrect version number\n");
495 	p(ips_fragments, "\t%llu fragment%s received\n");
496 	p(ips_fragdropped, "\t%llu fragment%s dropped (dup or out of space)\n");
497 	p(ips_rcvmemdrop, "\t%llu fragment%s dropped (out of ipqent)\n");
498 	p(ips_badfrags, "\t%llu malformed fragment%s dropped\n");
499 	p(ips_fragtimeout, "\t%llu fragment%s dropped after timeout\n");
500 	p(ips_reassembled, "\t%llu packet%s reassembled ok\n");
501 	p(ips_delivered, "\t%llu packet%s for this host\n");
502 	p(ips_noproto, "\t%llu packet%s for unknown/unsupported protocol\n");
503 	p(ips_forward, "\t%llu packet%s forwarded");
504 	p(ips_fastforward, " (%llu packet%s fast forwarded)");
505 	if (ipstat.ips_forward || sflag <= 1)
506 		putchar('\n');
507 	p(ips_cantforward, "\t%llu packet%s not forwardable\n");
508 	p(ips_redirectsent, "\t%llu redirect%s sent\n");
509 	p(ips_nogif, "\t%llu packet%s no matching gif found\n");
510 	p(ips_localout, "\t%llu packet%s sent from this host\n");
511 	p(ips_rawout, "\t%llu packet%s sent with fabricated ip header\n");
512 	p(ips_odropped, "\t%llu output packet%s dropped due to no bufs, etc.\n");
513 	p(ips_noroute, "\t%llu output packet%s discarded due to no route\n");
514 	p(ips_fragmented, "\t%llu output datagram%s fragmented\n");
515 	p(ips_ofragments, "\t%llu fragment%s created\n");
516 	p(ips_cantfrag, "\t%llu datagram%s that can't be fragmented\n");
517 	p(ips_badaddr, "\t%llu datagram%s with bad address in header\n");
518 #undef ps
519 #undef p
520 }
521 
522 static	char *icmpnames[] = {
523 	"echo reply",
524 	"#1",
525 	"#2",
526 	"destination unreachable",
527 	"source quench",
528 	"routing redirect",
529 	"alternate host address",
530 	"#7",
531 	"echo",
532 	"router advertisement",
533 	"router solicitation",
534 	"time exceeded",
535 	"parameter problem",
536 	"time stamp",
537 	"time stamp reply",
538 	"information request",
539 	"information request reply",
540 	"address mask request",
541 	"address mask reply",
542 };
543 
544 /*
545  * Dump ICMP statistics.
546  */
547 void
548 icmp_stats(off, name)
549 	u_long off;
550 	char *name;
551 {
552 	struct icmpstat icmpstat;
553 	int i, first;
554 
555 	if (use_sysctl) {
556 		size_t size = sizeof(icmpstat);
557 
558 		if (sysctlbyname("net.inet.icmp.stats", &icmpstat, &size,
559 				 NULL, 0) == -1)
560 			err(1, "net.inet.icmp.stats");
561 	} else {
562 		if (off == 0)
563 			return;
564 		kread(off, (char *)&icmpstat, sizeof (icmpstat));
565 	}
566 
567 	printf("%s:\n", name);
568 
569 #define	p(f, m) if (icmpstat.f || sflag <= 1) \
570     printf(m, (unsigned long long)icmpstat.f, plural(icmpstat.f))
571 
572 	p(icps_error, "\t%llu call%s to icmp_error\n");
573 	p(icps_oldicmp,
574 	    "\t%llu error%s not generated because old message was icmp\n");
575 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
576 		if (icmpstat.icps_outhist[i] != 0) {
577 			if (first) {
578 				printf("\tOutput histogram:\n");
579 				first = 0;
580 			}
581 			printf("\t\t%s: %llu\n", icmpnames[i],
582 				(unsigned long long)icmpstat.icps_outhist[i]);
583 		}
584 	p(icps_badcode, "\t%llu message%s with bad code fields\n");
585 	p(icps_tooshort, "\t%llu message%s < minimum length\n");
586 	p(icps_checksum, "\t%llu bad checksum%s\n");
587 	p(icps_badlen, "\t%llu message%s with bad length\n");
588 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
589 		if (icmpstat.icps_inhist[i] != 0) {
590 			if (first) {
591 				printf("\tInput histogram:\n");
592 				first = 0;
593 			}
594 			printf("\t\t%s: %llu\n", icmpnames[i],
595 				(unsigned long long)icmpstat.icps_inhist[i]);
596 		}
597 	p(icps_reflect, "\t%llu message response%s generated\n");
598 	p(icps_pmtuchg, "\t%llu path MTU change%s\n");
599 #undef p
600 }
601 
602 /*
603  * Dump IGMP statistics structure.
604  */
605 void
606 igmp_stats(off, name)
607 	u_long off;
608 	char *name;
609 {
610 	struct igmpstat igmpstat;
611 
612 	if (off == 0)
613 		return;
614 	kread(off, (char *)&igmpstat, sizeof (igmpstat));
615 	printf("%s:\n", name);
616 
617 #define	p(f, m) if (igmpstat.f || sflag <= 1) \
618     printf(m, (unsigned long long)igmpstat.f, plural(igmpstat.f))
619 #define	py(f, m) if (igmpstat.f || sflag <= 1) \
620     printf(m, (unsigned long long)igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
621 	p(igps_rcv_total, "\t%llu message%s received\n");
622         p(igps_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
623         p(igps_rcv_badsum, "\t%llu message%s received with bad checksum\n");
624         py(igps_rcv_queries, "\t%llu membership quer%s received\n");
625         py(igps_rcv_badqueries, "\t%llu membership quer%s received with invalid field(s)\n");
626         p(igps_rcv_reports, "\t%llu membership report%s received\n");
627         p(igps_rcv_badreports, "\t%llu membership report%s received with invalid field(s)\n");
628         p(igps_rcv_ourreports, "\t%llu membership report%s received for groups to which we belong\n");
629         p(igps_snd_reports, "\t%llu membership report%s sent\n");
630 #undef p
631 #undef py
632 }
633 
634 /*
635  * Dump CARP statistics structure.
636  */
637 void
638 carp_stats(u_long off, char *name)
639 {
640 	struct carpstats carpstat;
641 
642 	if (use_sysctl) {
643 		size_t size = sizeof(carpstat);
644 
645 		if (sysctlbyname("net.inet.carp.stats", &carpstat, &size,
646 				 NULL, 0) == -1) {
647 			/* most likely CARP is not compiled in the kernel */
648 			return;
649 		}
650 	} else {
651 		if (off == 0)
652 			return;
653 		kread(off, (char *)&carpstat, sizeof(carpstat));
654 	}
655 
656 	printf("%s:\n", name);
657 
658 #define p(f, m) if (carpstat.f || sflag <= 1) \
659 	printf(m, carpstat.f, plural(carpstat.f))
660 #define p2(f, m) if (carpstat.f || sflag <= 1) \
661 	printf(m, carpstat.f)
662 
663 	p(carps_ipackets, "\t%" PRIu64 " packet%s received (IPv4)\n");
664 	p(carps_ipackets6, "\t%" PRIu64 " packet%s received (IPv6)\n");
665 	p(carps_badif,
666 	    "\t\t%" PRIu64 " packet%s discarded for bad interface\n");
667 	p(carps_badttl,
668 	    "\t\t%" PRIu64 " packet%s discarded for wrong TTL\n");
669 	p(carps_hdrops, "\t\t%" PRIu64 " packet%s shorter than header\n");
670 	p(carps_badsum, "\t\t%" PRIu64
671 		" packet%s discarded for bad checksum\n");
672 	p(carps_badver,
673 	    "\t\t%" PRIu64 " packet%s discarded with a bad version\n");
674 	p2(carps_badlen,
675 	    "\t\t%" PRIu64 " discarded because packet was too short\n");
676 	p(carps_badauth,
677 	    "\t\t%" PRIu64 " packet%s discarded for bad authentication\n");
678 	p(carps_badvhid, "\t\t%" PRIu64 " packet%s discarded for bad vhid\n");
679 	p(carps_badaddrs, "\t\t%" PRIu64
680 		" packet%s discarded because of a bad address list\n");
681 	p(carps_opackets, "\t%" PRIu64 " packet%s sent (IPv4)\n");
682 	p(carps_opackets6, "\t%" PRIu64 " packet%s sent (IPv6)\n");
683 	p2(carps_onomem,
684 	    "\t\t%" PRIu64 " send failed due to mbuf memory error\n");
685 #undef p
686 #undef p2
687 }
688 
689 /*
690  * Dump PIM statistics structure.
691  */
692 void
693 pim_stats(off, name)
694 	u_long off;
695 	char *name;
696 {
697 	struct pimstat pimstat;
698 
699 	if (off == 0)
700 		return;
701 	if (kread(off, (char *)&pimstat, sizeof (pimstat)) != 0) {
702 		/* XXX: PIM is probably not enabled in the kernel */
703 		return;
704 	}
705 
706 	printf("%s:\n", name);
707 
708 #define	p(f, m) if (pimstat.f || sflag <= 1) \
709 	printf(m, (unsigned long long)pimstat.f, plural(pimstat.f))
710 
711 	p(pims_rcv_total_msgs, "\t%llu message%s received\n");
712 	p(pims_rcv_total_bytes, "\t%llu byte%s received\n");
713 	p(pims_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
714         p(pims_rcv_badsum, "\t%llu message%s received with bad checksum\n");
715 	p(pims_rcv_badversion, "\t%llu message%s received with bad version\n");
716 	p(pims_rcv_registers_msgs, "\t%llu data register message%s received\n");
717 	p(pims_rcv_registers_bytes, "\t%llu data register byte%s received\n");
718 	p(pims_rcv_registers_wrongiif, "\t%llu data register message%s received on wrong iif\n");
719 	p(pims_rcv_badregisters, "\t%llu bad register%s received\n");
720 	p(pims_snd_registers_msgs, "\t%llu data register message%s sent\n");
721 	p(pims_snd_registers_bytes, "\t%llu data register byte%s sent\n");
722 #undef p
723 }
724 
725 /*
726  * Dump the ARP statistics structure.
727  */
728 void
729 arp_stats(off, name)
730 	u_long off;
731 	char *name;
732 {
733 	struct arpstat arpstat;
734 
735 	if (off == 0)
736 		return;
737 	kread(off, (char *)&arpstat, sizeof (arpstat));
738 	printf("%s:\n", name);
739 
740 #define	ps(f, m) if (arpstat.f || sflag <= 1) \
741     printf(m, (unsigned long long)arpstat.f)
742 #define	p(f, m) if (arpstat.f || sflag <= 1) \
743     printf(m, (unsigned long long)arpstat.f, plural(arpstat.f))
744 
745 	p(as_sndtotal, "\t%llu packet%s sent\n");
746 	p(as_sndreply, "\t\t%llu reply packet%s\n");
747 	p(as_sndrequest, "\t\t%llu request packet%s\n");
748 
749 	p(as_rcvtotal, "\t%llu packet%s received\n");
750 	p(as_rcvreply, "\t\t%llu reply packet%s\n");
751 	p(as_rcvrequest, "\t\t%llu valid request packet%s\n");
752 	p(as_rcvmcast, "\t\t%llu broadcast/multicast packet%s\n");
753 	p(as_rcvbadproto, "\t\t%llu packet%s with unknown protocol type\n");
754 	p(as_rcvbadlen, "\t\t%llu packet%s with bad (short) length\n");
755 	p(as_rcvzerotpa, "\t\t%llu packet%s with null target IP address\n");
756 	p(as_rcvzerospa, "\t\t%llu packet%s with null source IP address\n");
757 	ps(as_rcvnoint, "\t\t%llu could not be mapped to an interface\n");
758 	p(as_rcvlocalsha, "\t\t%llu packet%s sourced from a local hardware "
759 	    "address\n");
760 	p(as_rcvbcastsha, "\t\t%llu packet%s with a broadcast "
761 	    "source hardware address\n");
762 	p(as_rcvlocalspa, "\t\t%llu duplicate%s for a local IP address\n");
763 	p(as_rcvoverperm, "\t\t%llu attempt%s to overwrite a static entry\n");
764 	p(as_rcvoverint, "\t\t%llu packet%s received on wrong interface\n");
765 	p(as_rcvover, "\t\t%llu entry%s overwritten\n");
766 	p(as_rcvlenchg, "\t\t%llu change%s in hardware address length\n");
767 
768 	p(as_dfrtotal, "\t%llu packet%s deferred pending ARP resolution\n");
769 	ps(as_dfrsent, "\t\t%llu sent\n");
770 	ps(as_dfrdropped, "\t\t%llu dropped\n");
771 
772 	p(as_allocfail, "\t%llu failure%s to allocate llinfo\n");
773 
774 #undef ps
775 #undef p
776 }
777 
778 /*
779  * Pretty print an Internet address (net address + port).
780  * Take numeric_addr and numeric_port into consideration.
781  */
782 void
783 inetprint(in, port, proto, numeric_port)
784 	struct in_addr *in;
785 	u_int16_t port;
786 	const char *proto;
787 	int numeric_port;
788 {
789 	struct servent *sp = 0;
790 	char line[80], *cp;
791 	size_t space;
792 
793 	(void)snprintf(line, sizeof line, "%.*s.",
794 	    (Aflag && !numeric_addr) ? 12 : 16, inetname(in));
795 	cp = strchr(line, '\0');
796 	if (!numeric_port && port)
797 		sp = getservbyport((int)port, proto);
798 	space = sizeof line - (cp-line);
799 	if (sp || port == 0)
800 		(void)snprintf(cp, space, "%s", sp ? sp->s_name : "*");
801 	else
802 		(void)snprintf(cp, space, "%u", ntohs(port));
803 	(void)printf(" %-*.*s", width, width, line);
804 }
805 
806 /*
807  * Construct an Internet address representation.
808  * If numeric_addr has been supplied, give
809  * numeric value, otherwise try for symbolic name.
810  */
811 char *
812 inetname(inp)
813 	struct in_addr *inp;
814 {
815 	char *cp;
816 	static char line[50];
817 	struct hostent *hp;
818 	struct netent *np;
819 	static char domain[MAXHOSTNAMELEN + 1];
820 	static int first = 1;
821 
822 	if (first && !numeric_addr) {
823 		first = 0;
824 		if (gethostname(domain, sizeof domain) == 0) {
825 			domain[sizeof(domain) - 1] = '\0';
826 			if ((cp = strchr(domain, '.')))
827 				(void) strlcpy(domain, cp + 1, sizeof(domain));
828 			else
829 				domain[0] = 0;
830 		} else
831 			domain[0] = 0;
832 	}
833 	cp = 0;
834 	if (!numeric_addr && inp->s_addr != INADDR_ANY) {
835 		int net = inet_netof(*inp);
836 		int lna = inet_lnaof(*inp);
837 
838 		if (lna == INADDR_ANY) {
839 			np = getnetbyaddr(net, AF_INET);
840 			if (np)
841 				cp = np->n_name;
842 		}
843 		if (cp == 0) {
844 			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
845 			if (hp) {
846 				if ((cp = strchr(hp->h_name, '.')) &&
847 				    !strcmp(cp + 1, domain))
848 					*cp = 0;
849 				cp = hp->h_name;
850 			}
851 		}
852 	}
853 	if (inp->s_addr == INADDR_ANY)
854 		strlcpy(line, "*", sizeof line);
855 	else if (cp)
856 		strlcpy(line, cp, sizeof line);
857 	else {
858 		inp->s_addr = ntohl(inp->s_addr);
859 #define C(x)	((x) & 0xff)
860 		(void)snprintf(line, sizeof line, "%u.%u.%u.%u",
861 		    C(inp->s_addr >> 24), C(inp->s_addr >> 16),
862 		    C(inp->s_addr >> 8), C(inp->s_addr));
863 #undef C
864 	}
865 	return (line);
866 }
867 
868 /*
869  * Dump the contents of a TCP PCB.
870  */
871 void
872 tcp_dump(pcbaddr)
873 	u_long pcbaddr;
874 {
875 	struct tcpcb tcpcb;
876 	int i, hardticks;
877 
878 	kread(pcbaddr, (char *)&tcpcb, sizeof(tcpcb));
879 	hardticks = get_hardticks();
880 
881 	printf("TCP Protocol Control Block at 0x%08lx:\n\n", pcbaddr);
882 
883 	printf("Timers:\n");
884 	for (i = 0; i < TCPT_NTIMERS; i++) {
885 		printf("\t%s: %d", tcptimers[i],
886 		    (tcpcb.t_timer[i].c_flags & CALLOUT_PENDING) ?
887 		    tcpcb.t_timer[i].c_time - hardticks : 0);
888 	}
889 	printf("\n\n");
890 
891 	if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
892 		printf("State: %d", tcpcb.t_state);
893 	else
894 		printf("State: %s", tcpstates[tcpcb.t_state]);
895 	printf(", flags 0x%x, inpcb 0x%lx, in6pcb 0x%lx\n\n", tcpcb.t_flags,
896 	    (u_long)tcpcb.t_inpcb, (u_long)tcpcb.t_in6pcb);
897 
898 	printf("rxtshift %d, rxtcur %d, dupacks %d\n", tcpcb.t_rxtshift,
899 	    tcpcb.t_rxtcur, tcpcb.t_dupacks);
900 	printf("peermss %u, ourmss %u, segsz %u\n\n", tcpcb.t_peermss,
901 	    tcpcb.t_ourmss, tcpcb.t_segsz);
902 
903 	printf("snd_una %u, snd_nxt %u, snd_up %u\n",
904 	    tcpcb.snd_una, tcpcb.snd_nxt, tcpcb.snd_up);
905 	printf("snd_wl1 %u, snd_wl2 %u, iss %u, snd_wnd %lu\n\n",
906 	    tcpcb.snd_wl1, tcpcb.snd_wl2, tcpcb.iss, tcpcb.snd_wnd);
907 
908 	printf("rcv_wnd %lu, rcv_nxt %u, rcv_up %u, irs %u\n\n",
909 	    tcpcb.rcv_wnd, tcpcb.rcv_nxt, tcpcb.rcv_up, tcpcb.irs);
910 
911 	printf("rcv_adv %u, snd_max %u, snd_cwnd %lu, snd_ssthresh %lu\n",
912 	    tcpcb.rcv_adv, tcpcb.snd_max, tcpcb.snd_cwnd, tcpcb.snd_ssthresh);
913 
914 	printf("rcvtime %u, rtttime %u, rtseq %u, srtt %d, rttvar %d, "
915 	    "rttmin %d, max_sndwnd %lu\n\n", tcpcb.t_rcvtime, tcpcb.t_rtttime,
916 	    tcpcb.t_rtseq, tcpcb.t_srtt, tcpcb.t_rttvar, tcpcb.t_rttmin,
917 	    tcpcb.max_sndwnd);
918 
919 	printf("oobflags %d, iobc %d, softerror %d\n\n", tcpcb.t_oobflags,
920 	    tcpcb.t_iobc, tcpcb.t_softerror);
921 
922 	printf("snd_scale %d, rcv_scale %d, req_r_scale %d, req_s_scale %d\n",
923 	    tcpcb.snd_scale, tcpcb.rcv_scale, tcpcb.request_r_scale,
924 	    tcpcb.requested_s_scale);
925 	printf("ts_recent %u, ts_regent_age %d, last_ack_sent %u\n",
926 	    tcpcb.ts_recent, tcpcb.ts_recent_age, tcpcb.last_ack_sent);
927 }
928