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