inet.c revision 1.95 1 /* $NetBSD: inet.c,v 1.95 2011/03/02 19:52:03 dyoung 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.95 2011/03/02 19:52:03 dyoung Exp $");
38 #endif
39 #endif /* not lint */
40
41 #define _CALLOUT_PRIVATE /* for defs in sys/callout.h */
42
43 #include <sys/param.h>
44 #include <sys/queue.h>
45 #include <sys/socket.h>
46 #include <sys/socketvar.h>
47 #include <sys/mbuf.h>
48 #include <sys/protosw.h>
49 #include <sys/sysctl.h>
50
51 #include <net/if_arp.h>
52 #include <net/route.h>
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/ip.h>
56 #include <netinet/in_pcb.h>
57 #include <netinet/ip_icmp.h>
58
59 #ifdef INET6
60 #include <netinet/ip6.h>
61 #endif
62
63 #include <netinet/icmp_var.h>
64 #include <netinet/igmp_var.h>
65 #include <netinet/ip_var.h>
66 #include <netinet/pim_var.h>
67 #include <netinet/tcp.h>
68 #include <netinet/tcpip.h>
69 #include <netinet/tcp_seq.h>
70 #define TCPSTATES
71 #include <netinet/tcp_fsm.h>
72 #define TCPTIMERS
73 #include <netinet/tcp_timer.h>
74 #include <netinet/tcp_var.h>
75 #include <netinet/tcp_debug.h>
76 #include <netinet/udp.h>
77 #include <netinet/ip_carp.h>
78 #include <netinet/udp_var.h>
79
80 #include <arpa/inet.h>
81 #include <kvm.h>
82 #include <netdb.h>
83 #include <stdio.h>
84 #include <string.h>
85 #include <unistd.h>
86 #include <stdlib.h>
87 #include <err.h>
88 #include "netstat.h"
89 #include "prog_ops.h"
90
91 char *inetname(struct in_addr *);
92 void inetprint(struct in_addr *, u_int16_t, const char *, int);
93
94 /*
95 * Print a summary of connections related to an Internet
96 * protocol. For TCP, also give state of connection.
97 * Listening processes (aflag) are suppressed unless the
98 * -a (all) flag is specified.
99 */
100 static int width;
101 static int compact;
102
103 static void
104 protoprhdr(void)
105 {
106 printf("Active Internet connections");
107 if (aflag)
108 printf(" (including servers)");
109 putchar('\n');
110 if (Aflag)
111 printf("%-8.8s ", "PCB");
112 printf("%-5.5s %-6.6s %-6.6s %s%-*.*s %-*.*s %s\n",
113 "Proto", "Recv-Q", "Send-Q", compact ? "" : " ",
114 width, width, "Local Address",
115 width, width, "Foreign Address",
116 "State");
117 }
118
119 static void
120 protopr0(intptr_t ppcb, u_long rcv_sb_cc, u_long snd_sb_cc,
121 struct in_addr *laddr, u_int16_t lport,
122 struct in_addr *faddr, u_int16_t fport,
123 short t_state, const char *name, int inp_flags)
124 {
125 static const char *shorttcpstates[] = {
126 "CLOSED", "LISTEN", "SYNSEN", "SYSRCV",
127 "ESTABL", "CLWAIT", "FWAIT1", "CLOSNG",
128 "LASTAK", "FWAIT2", "TMWAIT",
129 };
130 int istcp;
131
132 istcp = strcmp(name, "tcp") == 0;
133
134 if (Aflag) {
135 printf("%8" PRIxPTR " ", ppcb);
136 }
137 printf("%-5.5s %6ld %6ld%s", name, rcv_sb_cc, snd_sb_cc,
138 compact ? "" : " ");
139 if (numeric_port) {
140 inetprint(laddr, lport, name, 1);
141 inetprint(faddr, fport, name, 1);
142 } else if (inp_flags & INP_ANONPORT) {
143 inetprint(laddr, lport, name, 1);
144 inetprint(faddr, fport, name, 0);
145 } else {
146 inetprint(laddr, lport, name, 0);
147 inetprint(faddr, fport, name, 0);
148 }
149 if (istcp) {
150 if (t_state < 0 || t_state >= TCP_NSTATES)
151 printf(" %d", t_state);
152 else
153 printf(" %s", compact ? shorttcpstates[t_state] :
154 tcpstates[t_state]);
155 }
156 putchar('\n');
157 }
158
159 void
160 protopr(u_long off, const char *name)
161 {
162 struct inpcbtable table;
163 struct inpcb *head, *next, *prev;
164 struct inpcb inpcb;
165 struct tcpcb tcpcb;
166 struct socket sockb;
167 int istcp;
168 static int first = 1;
169
170 compact = 0;
171 if (Aflag) {
172 if (!numeric_addr)
173 width = 18;
174 else {
175 width = 21;
176 compact = 1;
177 }
178 } else
179 width = 22;
180
181 if (use_sysctl) {
182 struct kinfo_pcb *pcblist;
183 int mib[8];
184 size_t namelen = 0, size = 0, i;
185 char *mibname = NULL;
186
187 memset(mib, 0, sizeof(mib));
188
189 if (asprintf(&mibname, "net.inet.%s.pcblist", name) == -1)
190 err(1, "asprintf");
191
192 /* get dynamic pcblist node */
193 if (sysctlnametomib(mibname, mib, &namelen) == -1)
194 err(1, "sysctlnametomib: %s", mibname);
195
196 if (prog_sysctl(mib, __arraycount(mib),
197 NULL, &size, NULL, 0) == -1)
198 err(1, "sysctl (query)");
199
200 if ((pcblist = malloc(size)) == NULL)
201 err(1, "malloc");
202 memset(pcblist, 0, size);
203
204 mib[6] = sizeof(*pcblist);
205 mib[7] = size / sizeof(*pcblist);
206
207 if (prog_sysctl(mib, __arraycount(mib),
208 pcblist, &size, NULL, 0) == -1)
209 err(1, "sysctl (copy)");
210
211 for (i = 0; i < size / sizeof(*pcblist); i++) {
212 struct sockaddr_in src, dst;
213
214 memcpy(&src, &pcblist[i].ki_s, sizeof(src));
215 memcpy(&dst, &pcblist[i].ki_d, sizeof(dst));
216
217 if (!aflag &&
218 inet_lnaof(dst.sin_addr) == INADDR_ANY)
219 continue;
220
221 if (first) {
222 protoprhdr();
223 first = 0;
224 }
225
226 protopr0((intptr_t) pcblist[i].ki_ppcbaddr,
227 pcblist[i].ki_rcvq, pcblist[i].ki_sndq,
228 &src.sin_addr, src.sin_port,
229 &dst.sin_addr, dst.sin_port,
230 pcblist[i].ki_tstate, name,
231 pcblist[i].ki_pflags);
232 }
233
234 free(pcblist);
235 return;
236 }
237
238 if (off == 0)
239 return;
240 istcp = strcmp(name, "tcp") == 0;
241 kread(off, (char *)&table, sizeof table);
242 prev = head =
243 (struct inpcb *)&((struct inpcbtable *)off)->inpt_queue.cqh_first;
244 next = (struct inpcb *)table.inpt_queue.cqh_first;
245
246 while (next != head) {
247 kread((u_long)next, (char *)&inpcb, sizeof inpcb);
248 if ((struct inpcb *)inpcb.inp_queue.cqe_prev != prev) {
249 printf("???\n");
250 break;
251 }
252 prev = next;
253 next = (struct inpcb *)inpcb.inp_queue.cqe_next;
254
255 if (inpcb.inp_af != AF_INET)
256 continue;
257
258 if (!aflag &&
259 inet_lnaof(inpcb.inp_faddr) == INADDR_ANY)
260 continue;
261 kread((u_long)inpcb.inp_socket, (char *)&sockb, sizeof (sockb));
262 if (istcp) {
263 kread((u_long)inpcb.inp_ppcb,
264 (char *)&tcpcb, sizeof (tcpcb));
265 }
266
267 if (first) {
268 protoprhdr();
269 first = 0;
270 }
271
272 protopr0(istcp ? (intptr_t) inpcb.inp_ppcb : (intptr_t) prev,
273 sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc,
274 &inpcb.inp_laddr, inpcb.inp_lport,
275 &inpcb.inp_faddr, inpcb.inp_fport,
276 tcpcb.t_state, name, inpcb.inp_flags);
277 }
278 }
279
280 /*
281 * Dump TCP statistics structure.
282 */
283 void
284 tcp_stats(u_long off, const char *name)
285 {
286 uint64_t tcpstat[TCP_NSTATS];
287
288 if (use_sysctl) {
289 size_t size = sizeof(tcpstat);
290
291 if (sysctlbyname("net.inet.tcp.stats", tcpstat, &size,
292 NULL, 0) == -1)
293 return;
294 } else {
295 warnx("%s stats not available via KVM.", name);
296 return;
297 }
298
299 printf ("%s:\n", name);
300
301 #define ps(f, m) if (tcpstat[f] || sflag <= 1) \
302 printf(m, tcpstat[f])
303 #define p(f, m) if (tcpstat[f] || sflag <= 1) \
304 printf(m, tcpstat[f], plural(tcpstat[f]))
305 #define p2(f1, f2, m) if (tcpstat[f1] || tcpstat[f2] || sflag <= 1) \
306 printf(m, tcpstat[f1], plural(tcpstat[f1]), \
307 tcpstat[f2], plural(tcpstat[f2]))
308 #define p2s(f1, f2, m) if (tcpstat[f1] || tcpstat[f2] || sflag <= 1) \
309 printf(m, tcpstat[f1], plural(tcpstat[f1]), \
310 tcpstat[f2])
311 #define p3(f, m) if (tcpstat[f] || sflag <= 1) \
312 printf(m, tcpstat[f], plurales(tcpstat[f]))
313
314 p(TCP_STAT_SNDTOTAL, "\t%" PRIu64 " packet%s sent\n");
315 p2(TCP_STAT_SNDPACK,TCP_STAT_SNDBYTE,
316 "\t\t%" PRIu64 " data packet%s (%" PRIu64 " byte%s)\n");
317 p2(TCP_STAT_SNDREXMITPACK, TCP_STAT_SNDREXMITBYTE,
318 "\t\t%" PRIu64 " data packet%s (%" PRIu64 " byte%s) retransmitted\n");
319 p2s(TCP_STAT_SNDACKS, TCP_STAT_DELACK,
320 "\t\t%" PRIu64 " ack-only packet%s (%" PRIu64 " delayed)\n");
321 p(TCP_STAT_SNDURG, "\t\t%" PRIu64 " URG only packet%s\n");
322 p(TCP_STAT_SNDPROBE, "\t\t%" PRIu64 " window probe packet%s\n");
323 p(TCP_STAT_SNDWINUP, "\t\t%" PRIu64 " window update packet%s\n");
324 p(TCP_STAT_SNDCTRL, "\t\t%" PRIu64 " control packet%s\n");
325 p(TCP_STAT_SELFQUENCH,
326 "\t\t%" PRIu64 " send attempt%s resulted in self-quench\n");
327 p(TCP_STAT_RCVTOTAL, "\t%" PRIu64 " packet%s received\n");
328 p2(TCP_STAT_RCVACKPACK, TCP_STAT_RCVACKBYTE,
329 "\t\t%" PRIu64 " ack%s (for %" PRIu64 " byte%s)\n");
330 p(TCP_STAT_RCVDUPACK, "\t\t%" PRIu64 " duplicate ack%s\n");
331 p(TCP_STAT_RCVACKTOOMUCH, "\t\t%" PRIu64 " ack%s for unsent data\n");
332 p2(TCP_STAT_RCVPACK, TCP_STAT_RCVBYTE,
333 "\t\t%" PRIu64 " packet%s (%" PRIu64 " byte%s) received in-sequence\n");
334 p2(TCP_STAT_RCVDUPPACK, TCP_STAT_RCVDUPBYTE,
335 "\t\t%" PRIu64 " completely duplicate packet%s (%" PRIu64 " byte%s)\n");
336 p(TCP_STAT_PAWSDROP, "\t\t%" PRIu64 " old duplicate packet%s\n");
337 p2(TCP_STAT_RCVPARTDUPPACK, TCP_STAT_RCVPARTDUPBYTE,
338 "\t\t%" PRIu64 " packet%s with some dup. data (%" PRIu64 " byte%s duped)\n");
339 p2(TCP_STAT_RCVOOPACK, TCP_STAT_RCVOOBYTE,
340 "\t\t%" PRIu64 " out-of-order packet%s (%" PRIu64 " byte%s)\n");
341 p2(TCP_STAT_RCVPACKAFTERWIN, TCP_STAT_RCVBYTEAFTERWIN,
342 "\t\t%" PRIu64 " packet%s (%" PRIu64 " byte%s) of data after window\n");
343 p(TCP_STAT_RCVWINPROBE, "\t\t%" PRIu64 " window probe%s\n");
344 p(TCP_STAT_RCVWINUPD, "\t\t%" PRIu64 " window update packet%s\n");
345 p(TCP_STAT_RCVAFTERCLOSE, "\t\t%" PRIu64 " packet%s received after close\n");
346 p(TCP_STAT_RCVBADSUM, "\t\t%" PRIu64 " discarded for bad checksum%s\n");
347 p(TCP_STAT_RCVBADOFF, "\t\t%" PRIu64 " discarded for bad header offset field%s\n");
348 ps(TCP_STAT_RCVSHORT, "\t\t%" PRIu64 " discarded because packet too short\n");
349 p(TCP_STAT_CONNATTEMPT, "\t%" PRIu64 " connection request%s\n");
350 p(TCP_STAT_ACCEPTS, "\t%" PRIu64 " connection accept%s\n");
351 p(TCP_STAT_CONNECTS,
352 "\t%" PRIu64 " connection%s established (including accepts)\n");
353 p2(TCP_STAT_CLOSED, TCP_STAT_DROPS,
354 "\t%" PRIu64 " connection%s closed (including %" PRIu64 " drop%s)\n");
355 p(TCP_STAT_CONNDROPS, "\t%" PRIu64 " embryonic connection%s dropped\n");
356 p(TCP_STAT_DELAYED_FREE, "\t%" PRIu64 " delayed free%s of tcpcb\n");
357 p2(TCP_STAT_RTTUPDATED, TCP_STAT_SEGSTIMED,
358 "\t%" PRIu64 " segment%s updated rtt (of %" PRIu64 " attempt%s)\n");
359 p(TCP_STAT_REXMTTIMEO, "\t%" PRIu64 " retransmit timeout%s\n");
360 p(TCP_STAT_TIMEOUTDROP,
361 "\t\t%" PRIu64 " connection%s dropped by rexmit timeout\n");
362 p2(TCP_STAT_PERSISTTIMEO, TCP_STAT_PERSISTDROPS,
363 "\t%" PRIu64 " persist timeout%s (resulting in %" PRIu64 " dropped "
364 "connection%s)\n");
365 p(TCP_STAT_KEEPTIMEO, "\t%" PRIu64 " keepalive timeout%s\n");
366 p(TCP_STAT_KEEPPROBE, "\t\t%" PRIu64 " keepalive probe%s sent\n");
367 p(TCP_STAT_KEEPDROPS, "\t\t%" PRIu64 " connection%s dropped by keepalive\n");
368 p(TCP_STAT_PREDACK, "\t%" PRIu64 " correct ACK header prediction%s\n");
369 p(TCP_STAT_PREDDAT, "\t%" PRIu64 " correct data packet header prediction%s\n");
370 p3(TCP_STAT_PCBHASHMISS, "\t%" PRIu64 " PCB hash miss%s\n");
371 ps(TCP_STAT_NOPORT, "\t%" PRIu64 " dropped due to no socket\n");
372 p(TCP_STAT_CONNSDRAINED, "\t%" PRIu64 " connection%s drained due to memory "
373 "shortage\n");
374 p(TCP_STAT_PMTUBLACKHOLE, "\t%" PRIu64 " PMTUD blackhole%s detected\n");
375
376 p(TCP_STAT_BADSYN, "\t%" PRIu64 " bad connection attempt%s\n");
377 ps(TCP_STAT_SC_ADDED, "\t%" PRIu64 " SYN cache entries added\n");
378 p(TCP_STAT_SC_COLLISIONS, "\t\t%" PRIu64 " hash collision%s\n");
379 ps(TCP_STAT_SC_COMPLETED, "\t\t%" PRIu64 " completed\n");
380 ps(TCP_STAT_SC_ABORTED, "\t\t%" PRIu64 " aborted (no space to build PCB)\n");
381 ps(TCP_STAT_SC_TIMED_OUT, "\t\t%" PRIu64 " timed out\n");
382 ps(TCP_STAT_SC_OVERFLOWED, "\t\t%" PRIu64 " dropped due to overflow\n");
383 ps(TCP_STAT_SC_BUCKETOVERFLOW, "\t\t%" PRIu64 " dropped due to bucket overflow\n");
384 ps(TCP_STAT_SC_RESET, "\t\t%" PRIu64 " dropped due to RST\n");
385 ps(TCP_STAT_SC_UNREACH, "\t\t%" PRIu64 " dropped due to ICMP unreachable\n");
386 ps(TCP_STAT_SC_DELAYED_FREE, "\t\t%" PRIu64 " delayed free of SYN cache "
387 "entries\n");
388 p(TCP_STAT_SC_RETRANSMITTED, "\t%" PRIu64 " SYN,ACK%s retransmitted\n");
389 p(TCP_STAT_SC_DUPESYN, "\t%" PRIu64 " duplicate SYN%s received for entries "
390 "already in the cache\n");
391 p(TCP_STAT_SC_DROPPED, "\t%" PRIu64 " SYN%s dropped (no route or no space)\n");
392 p(TCP_STAT_BADSIG, "\t%" PRIu64 " packet%s with bad signature\n");
393 p(TCP_STAT_GOODSIG, "\t%" PRIu64 " packet%s with good signature\n");
394
395 p(TCP_STAT_ECN_SHS, "\t%" PRIu64 " successful ECN handshake%s\n");
396 p(TCP_STAT_ECN_CE, "\t%" PRIu64 " packet%s with ECN CE bit\n");
397 p(TCP_STAT_ECN_ECT, "\t%" PRIu64 " packet%s ECN ECT(0) bit\n");
398 #undef p
399 #undef ps
400 #undef p2
401 #undef p2s
402 #undef p3
403 }
404
405 /*
406 * Dump UDP statistics structure.
407 */
408 void
409 udp_stats(u_long off, const char *name)
410 {
411 uint64_t udpstat[UDP_NSTATS];
412 u_quad_t delivered;
413
414 if (use_sysctl) {
415 size_t size = sizeof(udpstat);
416
417 if (sysctlbyname("net.inet.udp.stats", udpstat, &size,
418 NULL, 0) == -1)
419 return;
420 } else {
421 warnx("%s stats not available via KVM.", name);
422 return;
423 }
424
425 printf ("%s:\n", name);
426
427 #define ps(f, m) if (udpstat[f] || sflag <= 1) \
428 printf(m, udpstat[f])
429 #define p(f, m) if (udpstat[f] || sflag <= 1) \
430 printf(m, udpstat[f], plural(udpstat[f]))
431 #define p3(f, m) if (udpstat[f] || sflag <= 1) \
432 printf(m, udpstat[f], plurales(udpstat[f]))
433
434 p(UDP_STAT_IPACKETS, "\t%" PRIu64 " datagram%s received\n");
435 ps(UDP_STAT_HDROPS, "\t%" PRIu64 " with incomplete header\n");
436 ps(UDP_STAT_BADLEN, "\t%" PRIu64 " with bad data length field\n");
437 ps(UDP_STAT_BADSUM, "\t%" PRIu64 " with bad checksum\n");
438 ps(UDP_STAT_NOPORT, "\t%" PRIu64 " dropped due to no socket\n");
439 p(UDP_STAT_NOPORTBCAST,
440 "\t%" PRIu64 " broadcast/multicast datagram%s dropped due to no socket\n");
441 ps(UDP_STAT_FULLSOCK, "\t%" PRIu64 " dropped due to full socket buffers\n");
442 delivered = udpstat[UDP_STAT_IPACKETS] -
443 udpstat[UDP_STAT_HDROPS] -
444 udpstat[UDP_STAT_BADLEN] -
445 udpstat[UDP_STAT_BADSUM] -
446 udpstat[UDP_STAT_NOPORT] -
447 udpstat[UDP_STAT_NOPORTBCAST] -
448 udpstat[UDP_STAT_FULLSOCK];
449 if (delivered || sflag <= 1)
450 printf("\t%" PRIu64 " delivered\n", delivered);
451 p3(UDP_STAT_PCBHASHMISS, "\t%" PRIu64 " PCB hash miss%s\n");
452 p(UDP_STAT_OPACKETS, "\t%" PRIu64 " datagram%s output\n");
453
454 #undef ps
455 #undef p
456 #undef p3
457 }
458
459 /*
460 * Dump IP statistics structure.
461 */
462 void
463 ip_stats(u_long off, const char *name)
464 {
465 uint64_t ipstat[IP_NSTATS];
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 return;
473 } else {
474 warnx("%s stats not available via KVM.", name);
475 return;
476 }
477
478 printf("%s:\n", name);
479
480 #define ps(f, m) if (ipstat[f] || sflag <= 1) \
481 printf(m, ipstat[f])
482 #define p(f, m) if (ipstat[f] || sflag <= 1) \
483 printf(m, ipstat[f], plural(ipstat[f]))
484
485 p(IP_STAT_TOTAL, "\t%" PRIu64 " total packet%s received\n");
486 p(IP_STAT_BADSUM, "\t%" PRIu64 " bad header checksum%s\n");
487 ps(IP_STAT_TOOSMALL, "\t%" PRIu64 " with size smaller than minimum\n");
488 ps(IP_STAT_TOOSHORT, "\t%" PRIu64 " with data size < data length\n");
489 ps(IP_STAT_TOOLONG, "\t%" PRIu64 " with length > max ip packet size\n");
490 ps(IP_STAT_BADHLEN, "\t%" PRIu64 " with header length < data size\n");
491 ps(IP_STAT_BADLEN, "\t%" PRIu64 " with data length < header length\n");
492 ps(IP_STAT_BADOPTIONS, "\t%" PRIu64 " with bad options\n");
493 ps(IP_STAT_BADVERS, "\t%" PRIu64 " with incorrect version number\n");
494 p(IP_STAT_FRAGMENTS, "\t%" PRIu64 " fragment%s received\n");
495 p(IP_STAT_FRAGDROPPED, "\t%" PRIu64 " fragment%s dropped (dup or out of space)\n");
496 p(IP_STAT_RCVMEMDROP, "\t%" PRIu64 " fragment%s dropped (out of ipqent)\n");
497 p(IP_STAT_BADFRAGS, "\t%" PRIu64 " malformed fragment%s dropped\n");
498 p(IP_STAT_FRAGTIMEOUT, "\t%" PRIu64 " fragment%s dropped after timeout\n");
499 p(IP_STAT_REASSEMBLED, "\t%" PRIu64 " packet%s reassembled ok\n");
500 p(IP_STAT_DELIVERED, "\t%" PRIu64 " packet%s for this host\n");
501 p(IP_STAT_NOPROTO, "\t%" PRIu64 " packet%s for unknown/unsupported protocol\n");
502 p(IP_STAT_FORWARD, "\t%" PRIu64 " packet%s forwarded");
503 p(IP_STAT_FASTFORWARD, " (%" PRIu64 " packet%s fast forwarded)");
504 if (ipstat[IP_STAT_FORWARD] || sflag <= 1)
505 putchar('\n');
506 p(IP_STAT_CANTFORWARD, "\t%" PRIu64 " packet%s not forwardable\n");
507 p(IP_STAT_REDIRECTSENT, "\t%" PRIu64 " redirect%s sent\n");
508 p(IP_STAT_NOGIF, "\t%" PRIu64 " packet%s no matching gif found\n");
509 p(IP_STAT_LOCALOUT, "\t%" PRIu64 " packet%s sent from this host\n");
510 p(IP_STAT_RAWOUT, "\t%" PRIu64 " packet%s sent with fabricated ip header\n");
511 p(IP_STAT_ODROPPED, "\t%" PRIu64 " output packet%s dropped due to no bufs, etc.\n");
512 p(IP_STAT_NOROUTE, "\t%" PRIu64 " output packet%s discarded due to no route\n");
513 p(IP_STAT_FRAGMENTED, "\t%" PRIu64 " output datagram%s fragmented\n");
514 p(IP_STAT_OFRAGMENTS, "\t%" PRIu64 " fragment%s created\n");
515 p(IP_STAT_CANTFRAG, "\t%" PRIu64 " datagram%s that can't be fragmented\n");
516 p(IP_STAT_BADADDR, "\t%" PRIu64 " datagram%s with bad address in header\n");
517 #undef ps
518 #undef p
519 }
520
521 static const char *icmpnames[] = {
522 "echo reply",
523 "#1",
524 "#2",
525 "destination unreachable",
526 "source quench",
527 "routing redirect",
528 "alternate host address",
529 "#7",
530 "echo",
531 "router advertisement",
532 "router solicitation",
533 "time exceeded",
534 "parameter problem",
535 "time stamp",
536 "time stamp reply",
537 "information request",
538 "information request reply",
539 "address mask request",
540 "address mask reply",
541 };
542
543 /*
544 * Dump ICMP statistics.
545 */
546 void
547 icmp_stats(u_long off, const char *name)
548 {
549 uint64_t icmpstat[ICMP_NSTATS];
550 int i, first;
551
552 if (use_sysctl) {
553 size_t size = sizeof(icmpstat);
554
555 if (sysctlbyname("net.inet.icmp.stats", icmpstat, &size,
556 NULL, 0) == -1)
557 return;
558 } else {
559 warnx("%s stats not available via KVM.", name);
560 return;
561 }
562
563 printf("%s:\n", name);
564
565 #define p(f, m) if (icmpstat[f] || sflag <= 1) \
566 printf(m, icmpstat[f], plural(icmpstat[f]))
567
568 p(ICMP_STAT_ERROR, "\t%" PRIu64 " call%s to icmp_error\n");
569 p(ICMP_STAT_OLDICMP,
570 "\t%" PRIu64 " error%s not generated because old message was icmp\n");
571 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
572 if (icmpstat[ICMP_STAT_OUTHIST + i] != 0) {
573 if (first) {
574 printf("\tOutput histogram:\n");
575 first = 0;
576 }
577 printf("\t\t%s: %" PRIu64 "\n", icmpnames[i],
578 icmpstat[ICMP_STAT_OUTHIST + i]);
579 }
580 p(ICMP_STAT_BADCODE, "\t%" PRIu64 " message%s with bad code fields\n");
581 p(ICMP_STAT_TOOSHORT, "\t%" PRIu64 " message%s < minimum length\n");
582 p(ICMP_STAT_CHECKSUM, "\t%" PRIu64 " bad checksum%s\n");
583 p(ICMP_STAT_BADLEN, "\t%" PRIu64 " message%s with bad length\n");
584 p(ICMP_STAT_BMCASTECHO, "\t%" PRIu64 " multicast echo request%s ignored\n");
585 p(ICMP_STAT_BMCASTTSTAMP, "\t%" PRIu64 " multicast timestamp request%s ignored\n");
586 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
587 if (icmpstat[ICMP_STAT_INHIST + i] != 0) {
588 if (first) {
589 printf("\tInput histogram:\n");
590 first = 0;
591 }
592 printf("\t\t%s: %" PRIu64 "\n", icmpnames[i],
593 icmpstat[ICMP_STAT_INHIST + i]);
594 }
595 p(ICMP_STAT_REFLECT, "\t%" PRIu64 " message response%s generated\n");
596 p(ICMP_STAT_PMTUCHG, "\t%" PRIu64 " path MTU change%s\n");
597 #undef p
598 }
599
600 /*
601 * Dump IGMP statistics structure.
602 */
603 void
604 igmp_stats(u_long off, const char *name)
605 {
606 uint64_t igmpstat[IGMP_NSTATS];
607
608 if (use_sysctl) {
609 size_t size = sizeof(igmpstat);
610
611 if (sysctlbyname("net.inet.igmp.stats", igmpstat, &size,
612 NULL, 0) == -1)
613 return;
614 } else {
615 warnx("%s stats not available via KVM.", name);
616 return;
617 }
618
619 printf("%s:\n", name);
620
621 #define p(f, m) if (igmpstat[f] || sflag <= 1) \
622 printf(m, igmpstat[f], plural(igmpstat[f]))
623 #define py(f, m) if (igmpstat[f] || sflag <= 1) \
624 printf(m, igmpstat[f], igmpstat[f] != 1 ? "ies" : "y")
625 p(IGMP_STAT_RCV_TOTAL, "\t%" PRIu64 " message%s received\n");
626 p(IGMP_STAT_RCV_TOOSHORT, "\t%" PRIu64 " message%s received with too few bytes\n");
627 p(IGMP_STAT_RCV_BADSUM, "\t%" PRIu64 " message%s received with bad checksum\n");
628 py(IGMP_STAT_RCV_QUERIES, "\t%" PRIu64 " membership quer%s received\n");
629 py(IGMP_STAT_RCV_BADQUERIES, "\t%" PRIu64 " membership quer%s received with invalid field(s)\n");
630 p(IGMP_STAT_RCV_REPORTS, "\t%" PRIu64 " membership report%s received\n");
631 p(IGMP_STAT_RCV_BADREPORTS, "\t%" PRIu64 " membership report%s received with invalid field(s)\n");
632 p(IGMP_STAT_RCV_OURREPORTS, "\t%" PRIu64 " membership report%s received for groups to which we belong\n");
633 p(IGMP_STAT_SND_REPORTS, "\t%" PRIu64 " membership report%s sent\n");
634 #undef p
635 #undef py
636 }
637
638 /*
639 * Dump CARP statistics structure.
640 */
641 void
642 carp_stats(u_long off, const char *name)
643 {
644 uint64_t carpstat[CARP_NSTATS];
645
646 if (use_sysctl) {
647 size_t size = sizeof(carpstat);
648
649 if (sysctlbyname("net.inet.carp.stats", carpstat, &size,
650 NULL, 0) == -1)
651 return;
652 } else {
653 warnx("%s stats not available via KVM.", name);
654 return;
655 }
656
657 printf("%s:\n", name);
658
659 #define p(f, m) if (carpstat[f] || sflag <= 1) \
660 printf(m, carpstat[f], plural(carpstat[f]))
661 #define p2(f, m) if (carpstat[f] || sflag <= 1) \
662 printf(m, carpstat[f])
663
664 p(CARP_STAT_IPACKETS, "\t%" PRIu64 " packet%s received (IPv4)\n");
665 p(CARP_STAT_IPACKETS6, "\t%" PRIu64 " packet%s received (IPv6)\n");
666 p(CARP_STAT_BADIF,
667 "\t\t%" PRIu64 " packet%s discarded for bad interface\n");
668 p(CARP_STAT_BADTTL,
669 "\t\t%" PRIu64 " packet%s discarded for wrong TTL\n");
670 p(CARP_STAT_HDROPS, "\t\t%" PRIu64 " packet%s shorter than header\n");
671 p(CARP_STAT_BADSUM, "\t\t%" PRIu64
672 " packet%s discarded for bad checksum\n");
673 p(CARP_STAT_BADVER,
674 "\t\t%" PRIu64 " packet%s discarded with a bad version\n");
675 p2(CARP_STAT_BADLEN,
676 "\t\t%" PRIu64 " discarded because packet was too short\n");
677 p(CARP_STAT_BADAUTH,
678 "\t\t%" PRIu64 " packet%s discarded for bad authentication\n");
679 p(CARP_STAT_BADVHID, "\t\t%" PRIu64 " packet%s discarded for bad vhid\n");
680 p(CARP_STAT_BADADDRS, "\t\t%" PRIu64
681 " packet%s discarded because of a bad address list\n");
682 p(CARP_STAT_OPACKETS, "\t%" PRIu64 " packet%s sent (IPv4)\n");
683 p(CARP_STAT_OPACKETS6, "\t%" PRIu64 " packet%s sent (IPv6)\n");
684 p2(CARP_STAT_ONOMEM,
685 "\t\t%" PRIu64 " send failed due to mbuf memory error\n");
686 #undef p
687 #undef p2
688 }
689
690 /*
691 * Dump PIM statistics structure.
692 */
693 void
694 pim_stats(u_long off, const char *name)
695 {
696 struct pimstat pimstat;
697
698 if (off == 0)
699 return;
700 if (kread(off, (char *)&pimstat, sizeof (pimstat)) != 0) {
701 /* XXX: PIM is probably not enabled in the kernel */
702 return;
703 }
704
705 printf("%s:\n", name);
706
707 #define p(f, m) if (pimstat.f || sflag <= 1) \
708 printf(m, pimstat.f, plural(pimstat.f))
709
710 p(pims_rcv_total_msgs, "\t%" PRIu64 " message%s received\n");
711 p(pims_rcv_total_bytes, "\t%" PRIu64 " byte%s received\n");
712 p(pims_rcv_tooshort, "\t%" PRIu64 " message%s received with too few bytes\n");
713 p(pims_rcv_badsum, "\t%" PRIu64 " message%s received with bad checksum\n");
714 p(pims_rcv_badversion, "\t%" PRIu64 " message%s received with bad version\n");
715 p(pims_rcv_registers_msgs, "\t%" PRIu64 " data register message%s received\n");
716 p(pims_rcv_registers_bytes, "\t%" PRIu64 " data register byte%s received\n");
717 p(pims_rcv_registers_wrongiif, "\t%" PRIu64 " data register message%s received on wrong iif\n");
718 p(pims_rcv_badregisters, "\t%" PRIu64 " bad register%s received\n");
719 p(pims_snd_registers_msgs, "\t%" PRIu64 " data register message%s sent\n");
720 p(pims_snd_registers_bytes, "\t%" PRIu64 " data register byte%s sent\n");
721 #undef p
722 }
723
724 /*
725 * Dump the ARP statistics structure.
726 */
727 void
728 arp_stats(u_long off, const char *name)
729 {
730 uint64_t arpstat[ARP_NSTATS];
731
732 if (use_sysctl) {
733 size_t size = sizeof(arpstat);
734
735 if (sysctlbyname("net.inet.arp.stats", arpstat, &size,
736 NULL, 0) == -1)
737 return;
738 } else {
739 warnx("%s stats not available via KVM.", name);
740 return;
741 }
742
743 printf("%s:\n", name);
744
745 #define ps(f, m) if (arpstat[f] || sflag <= 1) \
746 printf(m, arpstat[f])
747 #define p(f, m) if (arpstat[f] || sflag <= 1) \
748 printf(m, arpstat[f], plural(arpstat[f]))
749
750 p(ARP_STAT_SNDTOTAL, "\t%" PRIu64 " packet%s sent\n");
751 p(ARP_STAT_SNDREPLY, "\t\t%" PRIu64 " reply packet%s\n");
752 p(ARP_STAT_SENDREQUEST, "\t\t%" PRIu64 " request packet%s\n");
753
754 p(ARP_STAT_RCVTOTAL, "\t%" PRIu64 " packet%s received\n");
755 p(ARP_STAT_RCVREPLY, "\t\t%" PRIu64 " reply packet%s\n");
756 p(ARP_STAT_RCVREQUEST, "\t\t%" PRIu64 " valid request packet%s\n");
757 p(ARP_STAT_RCVMCAST, "\t\t%" PRIu64 " broadcast/multicast packet%s\n");
758 p(ARP_STAT_RCVBADPROTO, "\t\t%" PRIu64 " packet%s with unknown protocol type\n");
759 p(ARP_STAT_RCVBADLEN, "\t\t%" PRIu64 " packet%s with bad (short) length\n");
760 p(ARP_STAT_RCVZEROTPA, "\t\t%" PRIu64 " packet%s with null target IP address\n");
761 p(ARP_STAT_RCVZEROSPA, "\t\t%" PRIu64 " packet%s with null source IP address\n");
762 ps(ARP_STAT_RCVNOINT, "\t\t%" PRIu64 " could not be mapped to an interface\n");
763 p(ARP_STAT_RCVLOCALSHA, "\t\t%" PRIu64 " packet%s sourced from a local hardware "
764 "address\n");
765 p(ARP_STAT_RCVBCASTSHA, "\t\t%" PRIu64 " packet%s with a broadcast "
766 "source hardware address\n");
767 p(ARP_STAT_RCVLOCALSPA, "\t\t%" PRIu64 " duplicate%s for a local IP address\n");
768 p(ARP_STAT_RCVOVERPERM, "\t\t%" PRIu64 " attempt%s to overwrite a static entry\n");
769 p(ARP_STAT_RCVOVERINT, "\t\t%" PRIu64 " packet%s received on wrong interface\n");
770 p(ARP_STAT_RCVOVER, "\t\t%" PRIu64 " entry%s overwritten\n");
771 p(ARP_STAT_RCVLENCHG, "\t\t%" PRIu64 " change%s in hardware address length\n");
772
773 p(ARP_STAT_DFRTOTAL, "\t%" PRIu64 " packet%s deferred pending ARP resolution\n");
774 ps(ARP_STAT_DFRSENT, "\t\t%" PRIu64 " sent\n");
775 ps(ARP_STAT_DFRDROPPED, "\t\t%" PRIu64 " dropped\n");
776
777 p(ARP_STAT_ALLOCFAIL, "\t%" PRIu64 " failure%s to allocate llinfo\n");
778
779 #undef ps
780 #undef p
781 }
782
783 /*
784 * Pretty print an Internet address (net address + port).
785 * Take numeric_addr and numeric_port into consideration.
786 */
787 void
788 inetprint(struct in_addr *in, uint16_t port, const char *proto,
789 int port_numeric)
790 {
791 struct servent *sp = 0;
792 char line[80], *cp;
793 size_t space;
794
795 (void)snprintf(line, sizeof line, "%.*s.",
796 (Aflag && !numeric_addr) ? 12 : 16, inetname(in));
797 cp = strchr(line, '\0');
798 if (!port_numeric && port)
799 sp = getservbyport((int)port, proto);
800 space = sizeof line - (cp-line);
801 if (sp || port == 0)
802 (void)snprintf(cp, space, "%s", sp ? sp->s_name : "*");
803 else
804 (void)snprintf(cp, space, "%u", ntohs(port));
805 (void)printf(" %-*.*s", width, width, line);
806 }
807
808 /*
809 * Construct an Internet address representation.
810 * If numeric_addr has been supplied, give
811 * numeric value, otherwise try for symbolic name.
812 */
813 char *
814 inetname(struct in_addr *inp)
815 {
816 char *cp;
817 static char line[50];
818 struct hostent *hp;
819 struct netent *np;
820 static char domain[MAXHOSTNAMELEN + 1];
821 static int first = 1;
822
823 if (first && !numeric_addr) {
824 first = 0;
825 if (gethostname(domain, sizeof domain) == 0) {
826 domain[sizeof(domain) - 1] = '\0';
827 if ((cp = strchr(domain, '.')))
828 (void) strlcpy(domain, cp + 1, sizeof(domain));
829 else
830 domain[0] = 0;
831 } else
832 domain[0] = 0;
833 }
834 cp = 0;
835 if (!numeric_addr && inp->s_addr != INADDR_ANY) {
836 int net = inet_netof(*inp);
837 int lna = inet_lnaof(*inp);
838
839 if (lna == INADDR_ANY) {
840 np = getnetbyaddr(net, AF_INET);
841 if (np)
842 cp = np->n_name;
843 }
844 if (cp == 0) {
845 hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
846 if (hp) {
847 if ((cp = strchr(hp->h_name, '.')) &&
848 !strcmp(cp + 1, domain))
849 *cp = 0;
850 cp = hp->h_name;
851 }
852 }
853 }
854 if (inp->s_addr == INADDR_ANY)
855 strlcpy(line, "*", sizeof line);
856 else if (cp)
857 strlcpy(line, cp, sizeof line);
858 else {
859 inp->s_addr = ntohl(inp->s_addr);
860 #define C(x) ((x) & 0xff)
861 (void)snprintf(line, sizeof line, "%u.%u.%u.%u",
862 C(inp->s_addr >> 24), C(inp->s_addr >> 16),
863 C(inp->s_addr >> 8), C(inp->s_addr));
864 #undef C
865 }
866 return (line);
867 }
868
869 /*
870 * Dump the contents of a TCP PCB.
871 */
872 void
873 tcp_dump(u_long pcbaddr)
874 {
875 callout_impl_t *ci;
876 struct tcpcb tcpcb;
877 int i, hardticks;
878
879 kread(pcbaddr, (char *)&tcpcb, sizeof(tcpcb));
880 hardticks = get_hardticks();
881
882 printf("TCP Protocol Control Block at 0x%08lx:\n\n", pcbaddr);
883
884 printf("Timers:\n");
885 for (i = 0; i < TCPT_NTIMERS; i++) {
886 ci = (callout_impl_t *)&tcpcb.t_timer[i];
887 printf("\t%s: %d", tcptimers[i],
888 (ci->c_flags & CALLOUT_PENDING) ?
889 ci->c_time - hardticks : 0);
890 }
891 printf("\n\n");
892
893 if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
894 printf("State: %d", tcpcb.t_state);
895 else
896 printf("State: %s", tcpstates[tcpcb.t_state]);
897 printf(", flags 0x%x, inpcb 0x%lx, in6pcb 0x%lx\n\n", tcpcb.t_flags,
898 (u_long)tcpcb.t_inpcb, (u_long)tcpcb.t_in6pcb);
899
900 printf("rxtshift %d, rxtcur %d, dupacks %d\n", tcpcb.t_rxtshift,
901 tcpcb.t_rxtcur, tcpcb.t_dupacks);
902 printf("peermss %u, ourmss %u, segsz %u\n\n", tcpcb.t_peermss,
903 tcpcb.t_ourmss, tcpcb.t_segsz);
904
905 printf("snd_una %u, snd_nxt %u, snd_up %u\n",
906 tcpcb.snd_una, tcpcb.snd_nxt, tcpcb.snd_up);
907 printf("snd_wl1 %u, snd_wl2 %u, iss %u, snd_wnd %lu\n\n",
908 tcpcb.snd_wl1, tcpcb.snd_wl2, tcpcb.iss, tcpcb.snd_wnd);
909
910 printf("rcv_wnd %lu, rcv_nxt %u, rcv_up %u, irs %u\n\n",
911 tcpcb.rcv_wnd, tcpcb.rcv_nxt, tcpcb.rcv_up, tcpcb.irs);
912
913 printf("rcv_adv %u, snd_max %u, snd_cwnd %lu, snd_ssthresh %lu\n",
914 tcpcb.rcv_adv, tcpcb.snd_max, tcpcb.snd_cwnd, tcpcb.snd_ssthresh);
915
916 printf("rcvtime %u, rtttime %u, rtseq %u, srtt %d, rttvar %d, "
917 "rttmin %d, max_sndwnd %lu\n\n", tcpcb.t_rcvtime, tcpcb.t_rtttime,
918 tcpcb.t_rtseq, tcpcb.t_srtt, tcpcb.t_rttvar, tcpcb.t_rttmin,
919 tcpcb.max_sndwnd);
920
921 printf("oobflags %d, iobc %d, softerror %d\n\n", tcpcb.t_oobflags,
922 tcpcb.t_iobc, tcpcb.t_softerror);
923
924 printf("snd_scale %d, rcv_scale %d, req_r_scale %d, req_s_scale %d\n",
925 tcpcb.snd_scale, tcpcb.rcv_scale, tcpcb.request_r_scale,
926 tcpcb.requested_s_scale);
927 printf("ts_recent %u, ts_regent_age %d, last_ack_sent %u\n",
928 tcpcb.ts_recent, tcpcb.ts_recent_age, tcpcb.last_ack_sent);
929 }
930