]> git.saurik.com Git - apple/network_cmds.git/blob - netstat.tproj/inet.c
network_cmds-396.6.tar.gz
[apple/network_cmds.git] / netstat.tproj / inet.c
1 /*
2 * Copyright (c) 2008-2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 ** @APPLE_OSREFERENCE_LICENSE_HEADER_END@
26 */
27 /*
28 * Copyright (c) 1983, 1988, 1993, 1995
29 * The Regents of the University of California. All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed by the University of
42 * California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * SUCH DAMAGE.
58 */
59
60 #ifndef lint
61 /*
62 static char sccsid[] = "@(#)inet.c 8.5 (Berkeley) 5/24/95";
63 */
64 static const char rcsid[] =
65 "$Id: inet.c,v 1.9 2006/04/04 04:36:27 lindak Exp $";
66 #endif /* not lint */
67
68 #include <sys/param.h>
69 #include <sys/queue.h>
70 #include <sys/socket.h>
71 #include <sys/socketvar.h>
72 #include <sys/sysctl.h>
73
74 #include <net/route.h>
75 #include <netinet/in.h>
76 #include <netinet/in_systm.h>
77 #include <netinet/ip.h>
78 #ifdef INET6
79 #include <netinet/ip6.h>
80 #endif /* INET6 */
81 #include <netinet/in_pcb.h>
82 #include <netinet/ip_icmp.h>
83 #include <netinet/icmp_var.h>
84 #include <netinet/igmp_var.h>
85 #include <netinet/ip_var.h>
86 #include <netinet/tcp.h>
87 #include <netinet/tcpip.h>
88 #include <netinet/tcp_seq.h>
89 #define TCPSTATES
90 #include <netinet/tcp_fsm.h>
91 #include <netinet/tcp_var.h>
92 #include <netinet/udp.h>
93 #include <netinet/udp_var.h>
94
95 #include <arpa/inet.h>
96 #include <err.h>
97 #include <errno.h>
98 #include <netdb.h>
99 #include <stdio.h>
100 #include <stdlib.h>
101 #include <stdint.h>
102 #include <string.h>
103 #include <unistd.h>
104 #include "netstat.h"
105
106 #define ROUNDUP64(a) \
107 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint64_t) - 1))) : sizeof(uint64_t))
108 #define ADVANCE64(x, n) (((char *)x) += ROUNDUP64(n))
109
110 char *inetname (struct in_addr *);
111 void inetprint (struct in_addr *, int, char *, int);
112 #ifdef INET6
113 extern void inet6print (struct in6_addr *, int, char *, int);
114 static int udp_done, tcp_done;
115 #endif /* INET6 */
116
117 #ifdef SRVCACHE
118 typedef struct __table_private table_t;
119
120 extern table_t *_nc_table_new(uint32_t n);
121 extern void _nc_table_free(table_t *tin);
122
123 extern void _nc_table_insert(table_t *t, const char *key, void *datum);
124 extern void *_nc_table_find(table_t *t, const char *key);
125 extern void _nc_table_delete(table_t *t, const char *key);
126
127 static table_t *_serv_cache = NULL;
128
129 /*
130 * Read and cache all known services
131 */
132 static void
133 _serv_cache_open()
134 {
135 struct servent *s;
136 char *key, *name, *test;
137
138 if (_serv_cache != NULL) return;
139
140 _serv_cache = _nc_table_new(8192);
141 setservent(0);
142
143 while (NULL != (s = getservent()))
144 {
145 if (s->s_name == NULL) continue;
146 key = NULL;
147 asprintf(&key, "%hu/%s", (unsigned short)ntohs(s->s_port), s->s_proto);
148 name = strdup(s->s_name);
149 test = _nc_table_find(_serv_cache, key);
150 if (test == NULL) _nc_table_insert(_serv_cache, key, name);
151 free(key);
152 }
153
154 endservent();
155 }
156
157 void
158 _serv_cache_close()
159 {
160 _nc_table_free(_serv_cache);
161 _serv_cache = NULL;
162 }
163
164 struct servent *
165 _serv_cache_getservbyport(int port, char *proto)
166 {
167 static struct servent s;
168 char *key;
169 unsigned short p;
170
171 _serv_cache_open();
172
173 memset(&s, 0, sizeof(struct servent));
174 asprintf(&key, "%u/%s", port, (proto == NULL) ? "udp" : proto);
175
176 s.s_name = _nc_table_find(_serv_cache, key);
177 free(key);
178 if (s.s_name == NULL) return NULL;
179
180 p = port;
181 s.s_port = htons(p);
182 s.s_proto = proto;
183 return &s;
184 }
185
186 #endif /* SRVCACHE */
187
188 /*
189 * Print a summary of connections related to an Internet
190 * protocol. For TCP, also give state of connection.
191 * Listening processes (aflag) are suppressed unless the
192 * -a (all) flag is specified.
193 */
194
195 struct xgen_n {
196 u_int32_t xgn_len; /* length of this structure */
197 u_int32_t xgn_kind; /* number of PCBs at this time */
198 };
199
200 #define ALL_XGN_KIND_INP (XSO_SOCKET | XSO_RCVBUF | XSO_SNDBUF | XSO_STATS | XSO_INPCB)
201 #define ALL_XGN_KIND_TCP (ALL_XGN_KIND_INP | XSO_TCPCB)
202
203 void
204 protopr(uint32_t proto, /* for sysctl version we pass proto # */
205 char *name, int af)
206 {
207 int istcp;
208 static int first = 1;
209 char *buf, *next;
210 const char *mibvar;
211 struct xinpgen *xig, *oxig;
212 struct xgen_n *xgn;
213 size_t len;
214 struct xtcpcb_n *tp = NULL;
215 struct xinpcb_n *inp = NULL;
216 struct xsocket_n *so = NULL;
217 struct xsockbuf_n *so_rcv = NULL;
218 struct xsockbuf_n *so_snd = NULL;
219 struct xsockstat_n *so_stat = NULL;
220 int which = 0;
221
222 istcp = 0;
223 switch (proto) {
224 case IPPROTO_TCP:
225 #ifdef INET6
226 if (tcp_done != 0)
227 return;
228 else
229 tcp_done = 1;
230 #endif
231 istcp = 1;
232 mibvar = "net.inet.tcp.pcblist_n";
233 break;
234 case IPPROTO_UDP:
235 #ifdef INET6
236 if (udp_done != 0)
237 return;
238 else
239 udp_done = 1;
240 #endif
241 mibvar = "net.inet.udp.pcblist_n";
242 break;
243 case IPPROTO_DIVERT:
244 mibvar = "net.inet.divert.pcblist_n";
245 break;
246 default:
247 mibvar = "net.inet.raw.pcblist_n";
248 break;
249 }
250 len = 0;
251 if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
252 if (errno != ENOENT)
253 warn("sysctl: %s", mibvar);
254 return;
255 }
256 if ((buf = malloc(len)) == 0) {
257 warn("malloc %lu bytes", (u_long)len);
258 return;
259 }
260 if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
261 warn("sysctl: %s", mibvar);
262 free(buf);
263 return;
264 }
265
266 /*
267 * Bail-out to avoid logic error in the loop below when
268 * there is in fact no more control block to process
269 */
270 if (len <= sizeof(struct xinpgen)) {
271 free(buf);
272 return;
273 }
274
275 oxig = xig = (struct xinpgen *)buf;
276 for (next = buf + ROUNDUP64(xig->xig_len); next < buf + len; next += ROUNDUP64(xgn->xgn_len)) {
277
278 xgn = (struct xgen_n*)next;
279 if (xgn->xgn_len <= sizeof(struct xinpgen))
280 break;
281
282 if ((which & xgn->xgn_kind) == 0) {
283 which |= xgn->xgn_kind;
284 switch (xgn->xgn_kind) {
285 case XSO_SOCKET:
286 so = (struct xsocket_n *)xgn;
287 break;
288 case XSO_RCVBUF:
289 so_rcv = (struct xsockbuf_n *)xgn;
290 break;
291 case XSO_SNDBUF:
292 so_snd = (struct xsockbuf_n *)xgn;
293 break;
294 case XSO_STATS:
295 so_stat = (struct xsockstat_n *)xgn;
296 break;
297 case XSO_INPCB:
298 inp = (struct xinpcb_n *)xgn;
299 break;
300 case XSO_TCPCB:
301 tp = (struct xtcpcb_n *)xgn;
302 break;
303 default:
304 printf("unexpected kind %d\n", xgn->xgn_kind);
305 break;
306 }
307 } else {
308 printf("got %d twice\n", xgn->xgn_kind);
309 }
310
311 if ((istcp && which != ALL_XGN_KIND_TCP) || (!istcp && which != ALL_XGN_KIND_INP))
312 continue;
313 which = 0;
314
315 /* Ignore sockets for protocols other than the desired one. */
316 if (so->xso_protocol != (int)proto)
317 continue;
318
319 /* Ignore PCBs which were freed during copyout. */
320 if (inp->inp_gencnt > oxig->xig_gen)
321 continue;
322
323 if ((af == AF_INET && (inp->inp_vflag & INP_IPV4) == 0)
324 #ifdef INET6
325 || (af == AF_INET6 && (inp->inp_vflag & INP_IPV6) == 0)
326 #endif /* INET6 */
327 || (af == AF_UNSPEC && ((inp->inp_vflag & INP_IPV4) == 0
328 #ifdef INET6
329 && (inp->inp_vflag &
330 INP_IPV6) == 0
331 #endif /* INET6 */
332 ))
333 )
334 continue;
335
336 /*
337 * Local address is not an indication of listening socket or
338 * server sockey but just rather the socket has been bound.
339 * That why many UDP sockets were not displayed in the original code.
340 */
341 if (!aflag && istcp && tp->t_state <= TCPS_LISTEN)
342 continue;
343
344 if (Lflag && !so->so_qlimit)
345 continue;
346
347 if (first) {
348 if (!Lflag) {
349 printf("Active Internet connections");
350 if (aflag)
351 printf(" (including servers)");
352 } else
353 printf(
354 "Current listen queue sizes (qlen/incqlen/maxqlen)");
355 putchar('\n');
356 if (Aflag) {
357 #if !TARGET_OS_EMBEDDED
358 printf("%-16.16s ", "Socket");
359 #else
360 printf("%-8.8s ", "Socket");
361 #endif
362 printf("%-9.9s", "Flowhash");
363 }
364 if (Lflag)
365 printf("%-14.14s %-22.22s\n",
366 "Listen", "Local Address");
367 else {
368 printf((Aflag && !Wflag) ?
369 "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %-11.11s" :
370 "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %-11.11s",
371 "Proto", "Recv-Q", "Send-Q",
372 "Local Address", "Foreign Address",
373 "(state)");
374 if (bflag > 0)
375 printf(" %10.10s %10.10s", "rxbytes", "txbytes");
376 if (prioflag >= 0)
377 printf(" %7.7s[%1d] %7.7s[%1d]", "rxbytes", prioflag, "txbytes", prioflag);
378 printf("\n");
379 }
380 first = 0;
381 }
382 if (Aflag) {
383 if (istcp)
384 #if !TARGET_OS_EMBEDDED
385 printf("%16lx ", (u_long)inp->inp_ppcb);
386 #else
387 printf("%8lx ", (u_long)inp->inp_ppcb);
388
389 #endif
390 else
391 #if !TARGET_OS_EMBEDDED
392 printf("%16lx ", (u_long)so->so_pcb);
393 #else
394 printf("%8lx ", (u_long)so->so_pcb);
395 #endif
396 printf("%8x ", inp->inp_flowhash);
397 }
398 if (Lflag) {
399 char buf[15];
400
401 snprintf(buf, 15, "%d/%d/%d", so->so_qlen,
402 so->so_incqlen, so->so_qlimit);
403 printf("%-14.14s ", buf);
404 }
405 else {
406 const char *vchar;
407
408 #ifdef INET6
409 if ((inp->inp_vflag & INP_IPV6) != 0)
410 vchar = ((inp->inp_vflag & INP_IPV4) != 0)
411 ? "46" : "6 ";
412 else
413 #endif
414 vchar = ((inp->inp_vflag & INP_IPV4) != 0)
415 ? "4 " : " ";
416
417 printf("%-3.3s%-2.2s %6u %6u ", name, vchar,
418 so_rcv->sb_cc,
419 so_snd->sb_cc);
420 }
421 if (nflag) {
422 if (inp->inp_vflag & INP_IPV4) {
423 inetprint(&inp->inp_laddr, (int)inp->inp_lport,
424 name, 1);
425 if (!Lflag)
426 inetprint(&inp->inp_faddr,
427 (int)inp->inp_fport, name, 1);
428 }
429 #ifdef INET6
430 else if (inp->inp_vflag & INP_IPV6) {
431 inet6print(&inp->in6p_laddr,
432 (int)inp->inp_lport, name, 1);
433 if (!Lflag)
434 inet6print(&inp->in6p_faddr,
435 (int)inp->inp_fport, name, 1);
436 } /* else nothing printed now */
437 #endif /* INET6 */
438 } else if (inp->inp_flags & INP_ANONPORT) {
439 if (inp->inp_vflag & INP_IPV4) {
440 inetprint(&inp->inp_laddr, (int)inp->inp_lport,
441 name, 1);
442 if (!Lflag)
443 inetprint(&inp->inp_faddr,
444 (int)inp->inp_fport, name, 0);
445 }
446 #ifdef INET6
447 else if (inp->inp_vflag & INP_IPV6) {
448 inet6print(&inp->in6p_laddr,
449 (int)inp->inp_lport, name, 1);
450 if (!Lflag)
451 inet6print(&inp->in6p_faddr,
452 (int)inp->inp_fport, name, 0);
453 } /* else nothing printed now */
454 #endif /* INET6 */
455 } else {
456 if (inp->inp_vflag & INP_IPV4) {
457 inetprint(&inp->inp_laddr, (int)inp->inp_lport,
458 name, 0);
459 if (!Lflag)
460 inetprint(&inp->inp_faddr,
461 (int)inp->inp_fport, name,
462 inp->inp_lport !=
463 inp->inp_fport);
464 }
465 #ifdef INET6
466 else if (inp->inp_vflag & INP_IPV6) {
467 inet6print(&inp->in6p_laddr,
468 (int)inp->inp_lport, name, 0);
469 if (!Lflag)
470 inet6print(&inp->in6p_faddr,
471 (int)inp->inp_fport, name,
472 inp->inp_lport !=
473 inp->inp_fport);
474 } /* else nothing printed now */
475 #endif /* INET6 */
476 }
477 if (istcp && !Lflag) {
478 if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES)
479 printf("%-11d", tp->t_state);
480 else {
481 printf("%-11s", tcpstates[tp->t_state]);
482 #if defined(TF_NEEDSYN) && defined(TF_NEEDFIN)
483 /* Show T/TCP `hidden state' */
484 if (tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN))
485 putchar('*');
486 #endif /* defined(TF_NEEDSYN) && defined(TF_NEEDFIN) */
487 }
488 }
489 if (!istcp)
490 printf("%-11s", " ");
491 if (bflag > 0) {
492 int i;
493 u_int64_t rxbytes = 0;
494 u_int64_t txbytes = 0;
495
496 for (i = 0; i < SO_TC_MAX; i++) {
497 rxbytes += so_stat->xst_tc_stats[i].rxbytes;
498 txbytes += so_stat->xst_tc_stats[i].txbytes;
499 }
500
501 printf(" %10llu %10llu", rxbytes, txbytes);
502 }
503 if (prioflag >= 0) {
504 printf(" %10llu %10llu",
505 prioflag < SO_TC_MAX ? so_stat->xst_tc_stats[prioflag].rxbytes : 0,
506 prioflag < SO_TC_MAX ? so_stat->xst_tc_stats[prioflag].txbytes : 0);
507 }
508 putchar('\n');
509 }
510 if (xig != oxig && xig->xig_gen != oxig->xig_gen) {
511 if (oxig->xig_count > xig->xig_count) {
512 printf("Some %s sockets may have been deleted.\n",
513 name);
514 } else if (oxig->xig_count < xig->xig_count) {
515 printf("Some %s sockets may have been created.\n",
516 name);
517 } else {
518 printf("Some %s sockets may have been created or deleted",
519 name);
520 }
521 }
522 free(buf);
523 }
524
525 /*
526 * Dump TCP statistics structure.
527 */
528 void
529 tcp_stats(uint32_t off , char *name, int af )
530 {
531 static struct tcpstat ptcpstat;
532 struct tcpstat tcpstat;
533 size_t len = sizeof tcpstat;
534
535 if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, 0, 0) < 0) {
536 warn("sysctl: net.inet.tcp.stats");
537 return;
538 }
539
540 #ifdef INET6
541 if (tcp_done != 0 && interval == 0)
542 return;
543 else
544 tcp_done = 1;
545 #endif
546
547 printf ("%s:\n", name);
548
549 #define TCPDIFF(f) (tcpstat.f - ptcpstat.f)
550 #define p(f, m) if (TCPDIFF(f) || sflag <= 1) \
551 printf(m, TCPDIFF(f), plural(TCPDIFF(f)))
552 #define p1a(f, m) if (TCPDIFF(f) || sflag <= 1) \
553 printf(m, TCPDIFF(f))
554 #define p2(f1, f2, m) if (TCPDIFF(f1) || TCPDIFF(f2) || sflag <= 1) \
555 printf(m, TCPDIFF(f1), plural(TCPDIFF(f1)), TCPDIFF(f2), plural(TCPDIFF(f2)))
556 #define p2a(f1, f2, m) if (TCPDIFF(f1) || TCPDIFF(f2) || sflag <= 1) \
557 printf(m, TCPDIFF(f1), plural(TCPDIFF(f1)), TCPDIFF(f2))
558 #define p3(f, m) if (TCPDIFF(f) || sflag <= 1) \
559 printf(m, TCPDIFF(f), plurales(TCPDIFF(f)))
560
561 p(tcps_sndtotal, "\t%u packet%s sent\n");
562 p2(tcps_sndpack,tcps_sndbyte,
563 "\t\t%u data packet%s (%u byte%s)\n");
564 p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
565 "\t\t%u data packet%s (%u byte%s) retransmitted\n");
566 p(tcps_mturesent, "\t\t%u resend%s initiated by MTU discovery\n");
567 p2a(tcps_sndacks, tcps_delack,
568 "\t\t%u ack-only packet%s (%u delayed)\n");
569 p(tcps_sndurg, "\t\t%u URG only packet%s\n");
570 p(tcps_sndprobe, "\t\t%u window probe packet%s\n");
571 p(tcps_sndwinup, "\t\t%u window update packet%s\n");
572 p(tcps_sndctrl, "\t\t%u control packet%s\n");
573 p(tcps_fcholdpacket, "\t\t%u data packet%s sent after flow control\n");
574 p(tcps_rcvtotal, "\t%u packet%s received\n");
575 p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%u ack%s (for %u byte%s)\n");
576 p(tcps_rcvdupack, "\t\t%u duplicate ack%s\n");
577 p(tcps_rcvacktoomuch, "\t\t%u ack%s for unsent data\n");
578 p2(tcps_rcvpack, tcps_rcvbyte,
579 "\t\t%u packet%s (%u byte%s) received in-sequence\n");
580 p2(tcps_rcvduppack, tcps_rcvdupbyte,
581 "\t\t%u completely duplicate packet%s (%u byte%s)\n");
582 p(tcps_pawsdrop, "\t\t%u old duplicate packet%s\n");
583 p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
584 "\t\t%u packet%s with some dup. data (%u byte%s duped)\n");
585 p2(tcps_rcvoopack, tcps_rcvoobyte,
586 "\t\t%u out-of-order packet%s (%u byte%s)\n");
587 p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
588 "\t\t%u packet%s (%u byte%s) of data after window\n");
589 p(tcps_rcvwinprobe, "\t\t%u window probe%s\n");
590 p(tcps_rcvwinupd, "\t\t%u window update packet%s\n");
591 p(tcps_rcvafterclose, "\t\t%u packet%s received after close\n");
592 p(tcps_badrst, "\t\t%u bad reset%s\n");
593 p(tcps_rcvbadsum, "\t\t%u discarded for bad checksum%s\n");
594 p(tcps_rcvbadoff, "\t\t%u discarded for bad header offset field%s\n");
595 p1a(tcps_rcvshort, "\t\t%u discarded because packet too short\n");
596 p(tcps_connattempt, "\t%u connection request%s\n");
597 p(tcps_accepts, "\t%u connection accept%s\n");
598 p(tcps_badsyn, "\t%u bad connection attempt%s\n");
599 p(tcps_listendrop, "\t%u listen queue overflow%s\n");
600 p(tcps_connects, "\t%u connection%s established (including accepts)\n");
601 p2(tcps_closed, tcps_drops,
602 "\t%u connection%s closed (including %u drop%s)\n");
603 p(tcps_cachedrtt, "\t\t%u connection%s updated cached RTT on close\n");
604 p(tcps_cachedrttvar,
605 "\t\t%u connection%s updated cached RTT variance on close\n");
606 p(tcps_cachedssthresh,
607 "\t\t%u connection%s updated cached ssthresh on close\n");
608 p(tcps_conndrops, "\t%u embryonic connection%s dropped\n");
609 p2(tcps_rttupdated, tcps_segstimed,
610 "\t%u segment%s updated rtt (of %u attempt%s)\n");
611 p(tcps_rexmttimeo, "\t%u retransmit timeout%s\n");
612 p(tcps_timeoutdrop, "\t\t%u connection%s dropped by rexmit timeout\n");
613 p(tcps_rxtfindrop, "\t\t%u connection%s dropped after retransmitting FIN\n");
614 p(tcps_persisttimeo, "\t%u persist timeout%s\n");
615 p(tcps_persistdrop, "\t\t%u connection%s dropped by persist timeout\n");
616 p(tcps_keeptimeo, "\t%u keepalive timeout%s\n");
617 p(tcps_keepprobe, "\t\t%u keepalive probe%s sent\n");
618 p(tcps_keepdrops, "\t\t%u connection%s dropped by keepalive\n");
619 p(tcps_predack, "\t%u correct ACK header prediction%s\n");
620 p(tcps_preddat, "\t%u correct data packet header prediction%s\n");
621 #ifdef TCP_MAX_SACK
622 /* TCP_MAX_SACK indicates the header has the SACK structures */
623 p(tcps_sack_recovery_episode, "\t%u SACK recovery episode%s\n");
624 p(tcps_sack_rexmits,
625 "\t%u segment rexmit%s in SACK recovery episodes\n");
626 p(tcps_sack_rexmit_bytes,
627 "\t%u byte rexmit%s in SACK recovery episodes\n");
628 p(tcps_sack_rcv_blocks,
629 "\t%u SACK option%s (SACK blocks) received\n");
630 p(tcps_sack_send_blocks, "\t%u SACK option%s (SACK blocks) sent\n");
631 p1a(tcps_sack_sboverflow, "\t%u SACK scoreboard overflow\n");
632 #endif /* TCP_MAX_SACK */
633
634 if (interval > 0)
635 bcopy(&tcpstat, &ptcpstat, len);
636
637 #undef TCPDIFF
638 #undef p
639 #undef p1a
640 #undef p2
641 #undef p2a
642 #undef p3
643 }
644
645 /*
646 * Dump UDP statistics structure.
647 */
648 void
649 udp_stats(uint32_t off , char *name, int af )
650 {
651 static struct udpstat pudpstat;
652 struct udpstat udpstat;
653 size_t len = sizeof udpstat;
654 uint32_t delivered;
655
656 if (sysctlbyname("net.inet.udp.stats", &udpstat, &len, 0, 0) < 0) {
657 warn("sysctl: net.inet.udp.stats");
658 return;
659 }
660
661 #ifdef INET6
662 if (udp_done != 0 && interval == 0)
663 return;
664 else
665 udp_done = 1;
666 #endif
667
668 printf("%s:\n", name);
669
670 #define UDPDIFF(f) (udpstat.f - pudpstat.f)
671 #define p(f, m) if (UDPDIFF(f) || sflag <= 1) \
672 printf(m, UDPDIFF(f), plural(UDPDIFF(f)))
673 #define p1a(f, m) if (UDPDIFF(f) || sflag <= 1) \
674 printf(m, UDPDIFF(f))
675 p(udps_ipackets, "\t%u datagram%s received\n");
676 p1a(udps_hdrops, "\t%u with incomplete header\n");
677 p1a(udps_badlen, "\t%u with bad data length field\n");
678 p1a(udps_badsum, "\t%u with bad checksum\n");
679 p1a(udps_noport, "\t%u dropped due to no socket\n");
680 p(udps_noportbcast,
681 "\t%u broadcast/multicast datagram%s dropped due to no socket\n");
682 p1a(udps_fullsock, "\t%u dropped due to full socket buffers\n");
683 p1a(udpps_pcbhashmiss, "\t%u not for hashed pcb\n");
684 delivered = UDPDIFF(udps_ipackets) -
685 UDPDIFF(udps_hdrops) -
686 UDPDIFF(udps_badlen) -
687 UDPDIFF(udps_badsum) -
688 UDPDIFF(udps_noport) -
689 UDPDIFF(udps_noportbcast) -
690 UDPDIFF(udps_fullsock);
691 if (delivered || sflag <= 1)
692 printf("\t%u delivered\n", delivered);
693 p(udps_opackets, "\t%u datagram%s output\n");
694
695 if (interval > 0)
696 bcopy(&udpstat, &pudpstat, len);
697
698 #undef UDPDIFF
699 #undef p
700 #undef p1a
701 }
702
703 /*
704 * Dump IP statistics structure.
705 */
706 void
707 ip_stats(uint32_t off , char *name, int af )
708 {
709 static struct ipstat pipstat;
710 struct ipstat ipstat;
711 size_t len = sizeof ipstat;
712
713 if (sysctlbyname("net.inet.ip.stats", &ipstat, &len, 0, 0) < 0) {
714 warn("sysctl: net.inet.ip.stats");
715 return;
716 }
717
718 printf("%s:\n", name);
719
720 #define IPDIFF(f) (ipstat.f - pipstat.f)
721 #define p(f, m) if (IPDIFF(f) || sflag <= 1) \
722 printf(m, IPDIFF(f), plural(IPDIFF(f)))
723 #define p1a(f, m) if (IPDIFF(f) || sflag <= 1) \
724 printf(m, IPDIFF(f))
725
726 p(ips_total, "\t%u total packet%s received\n");
727 p(ips_badsum, "\t%u bad header checksum%s\n");
728 p1a(ips_toosmall, "\t%u with size smaller than minimum\n");
729 p1a(ips_tooshort, "\t%u with data size < data length\n");
730 p1a(ips_toolong, "\t%u with ip length > max ip packet size\n");
731 p1a(ips_badhlen, "\t%u with header length < data size\n");
732 p1a(ips_badlen, "\t%u with data length < header length\n");
733 p1a(ips_badoptions, "\t%u with bad options\n");
734 p1a(ips_badvers, "\t%u with incorrect version number\n");
735 p(ips_fragments, "\t%u fragment%s received\n");
736 p(ips_fragdropped, "\t%u fragment%s dropped (dup or out of space)\n");
737 p(ips_fragtimeout, "\t%u fragment%s dropped after timeout\n");
738 p(ips_reassembled, "\t%u packet%s reassembled ok\n");
739 p(ips_delivered, "\t%u packet%s for this host\n");
740 p(ips_noproto, "\t%u packet%s for unknown/unsupported protocol\n");
741 p(ips_forward, "\t%u packet%s forwarded");
742 p(ips_fastforward, " (%u packet%s fast forwarded)");
743 if (IPDIFF(ips_forward) || sflag <= 1)
744 putchar('\n');
745 p(ips_cantforward, "\t%u packet%s not forwardable\n");
746 p(ips_notmember,
747 "\t%u packet%s received for unknown multicast group\n");
748 p(ips_redirectsent, "\t%u redirect%s sent\n");
749 p(ips_localout, "\t%u packet%s sent from this host\n");
750 p(ips_rawout, "\t%u packet%s sent with fabricated ip header\n");
751 p(ips_odropped,
752 "\t%u output packet%s dropped due to no bufs, etc.\n");
753 p(ips_noroute, "\t%u output packet%s discarded due to no route\n");
754 p(ips_fragmented, "\t%u output datagram%s fragmented\n");
755 p(ips_ofragments, "\t%u fragment%s created\n");
756 p(ips_cantfrag, "\t%u datagram%s that can't be fragmented\n");
757 p(ips_nogif, "\t%u tunneling packet%s that can't find gif\n");
758 p(ips_badaddr, "\t%u datagram%s with bad address in header\n");
759 p(ips_pktdropcntrl, "\t%u packet%s dropped due to no bufs for control data\n");
760
761 if (interval > 0)
762 bcopy(&ipstat, &pipstat, len);
763
764 #undef IPDIFF
765 #undef p
766 #undef p1a
767 }
768
769 static char *icmpnames[] = {
770 "echo reply",
771 "#1",
772 "#2",
773 "destination unreachable",
774 "source quench",
775 "routing redirect",
776 "#6",
777 "#7",
778 "echo",
779 "router advertisement",
780 "router solicitation",
781 "time exceeded",
782 "parameter problem",
783 "time stamp",
784 "time stamp reply",
785 "information request",
786 "information request reply",
787 "address mask request",
788 "address mask reply",
789 };
790
791 /*
792 * Dump ICMP statistics.
793 */
794 void
795 icmp_stats(uint32_t off , char *name, int af )
796 {
797 static struct icmpstat picmpstat;
798 struct icmpstat icmpstat;
799 int i, first;
800 int mib[4]; /* CTL_NET + PF_INET + IPPROTO_ICMP + req */
801 size_t len;
802
803 mib[0] = CTL_NET;
804 mib[1] = PF_INET;
805 mib[2] = IPPROTO_ICMP;
806 mib[3] = ICMPCTL_STATS;
807
808 len = sizeof icmpstat;
809 memset(&icmpstat, 0, len);
810 if (sysctl(mib, 4, &icmpstat, &len, (void *)0, 0) < 0)
811 return; /* XXX should complain, but not traditional */
812
813 printf("%s:\n", name);
814
815 #define ICMPDIFF(f) (icmpstat.f - picmpstat.f)
816 #define p(f, m) if (ICMPDIFF(f) || sflag <= 1) \
817 printf(m, ICMPDIFF(f), plural(ICMPDIFF(f)))
818 #define p1a(f, m) if (ICMPDIFF(f) || sflag <= 1) \
819 printf(m, ICMPDIFF(f))
820
821 p(icps_error, "\t%u call%s to icmp_error\n");
822 p(icps_oldicmp,
823 "\t%u error%s not generated 'cuz old message was icmp\n");
824 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
825 if (ICMPDIFF(icps_outhist[i]) != 0) {
826 if (first) {
827 printf("\tOutput histogram:\n");
828 first = 0;
829 }
830 printf("\t\t%s: %u\n", icmpnames[i],
831 ICMPDIFF(icps_outhist[i]));
832 }
833 p(icps_badcode, "\t%u message%s with bad code fields\n");
834 p(icps_tooshort, "\t%u message%s < minimum length\n");
835 p(icps_checksum, "\t%u bad checksum%s\n");
836 p(icps_badlen, "\t%u message%s with bad length\n");
837 p1a(icps_bmcastecho, "\t%u multicast echo requests ignored\n");
838 p1a(icps_bmcasttstamp, "\t%u multicast timestamp requests ignored\n");
839 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
840 if (ICMPDIFF(icps_inhist[i]) != 0) {
841 if (first) {
842 printf("\tInput histogram:\n");
843 first = 0;
844 }
845 printf("\t\t%s: %u\n", icmpnames[i],
846 ICMPDIFF(icps_inhist[i]));
847 }
848 p(icps_reflect, "\t%u message response%s generated\n");
849
850 #undef ICMPDIFF
851 #undef p
852 #undef p1a
853 mib[3] = ICMPCTL_MASKREPL;
854 len = sizeof i;
855 if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0)
856 return;
857 printf("\tICMP address mask responses are %sabled\n",
858 i ? "en" : "dis");
859
860 if (interval > 0)
861 bcopy(&icmpstat, &picmpstat, sizeof (icmpstat));
862 }
863
864 /*
865 * Dump IGMP statistics structure.
866 */
867 void
868 igmp_stats(uint32_t off , char *name, int af )
869 {
870 static struct igmpstat_v3 pigmpstat;
871 struct igmpstat_v3 igmpstat;
872 size_t len = sizeof igmpstat;
873
874 if (sysctlbyname("net.inet.igmp.v3stats", &igmpstat, &len, 0, 0) < 0) {
875 warn("sysctl: net.inet.igmp.v3stats");
876 return;
877 }
878
879 if (igmpstat.igps_version != IGPS_VERSION_3) {
880 warnx("%s: version mismatch (%d != %d)", __func__,
881 igmpstat.igps_version, IGPS_VERSION_3);
882 }
883 if (igmpstat.igps_len != IGPS_VERSION3_LEN) {
884 warnx("%s: size mismatch (%d != %d)", __func__,
885 igmpstat.igps_len, IGPS_VERSION3_LEN);
886 }
887
888 printf("%s:\n", name);
889
890 #define IGMPDIFF(f) ((uintmax_t)(igmpstat.f - pigmpstat.f))
891 #define p64(f, m) if (IGMPDIFF(f) || sflag <= 1) \
892 printf(m, IGMPDIFF(f), plural(IGMPDIFF(f)))
893 #define py64(f, m) if (IGMPDIFF(f) || sflag <= 1) \
894 printf(m, IGMPDIFF(f), IGMPDIFF(f) != 1 ? "ies" : "y")
895
896 p64(igps_rcv_total, "\t%ju message%s received\n");
897 p64(igps_rcv_tooshort, "\t%ju message%s received with too few bytes\n");
898 p64(igps_rcv_badttl, "\t%ju message%s received with wrong TTL\n");
899 p64(igps_rcv_badsum, "\t%ju message%s received with bad checksum\n");
900 py64(igps_rcv_v1v2_queries, "\t%ju V1/V2 membership quer%s received\n");
901 py64(igps_rcv_v3_queries, "\t%ju V3 membership quer%s received\n");
902 py64(igps_rcv_badqueries,
903 "\t%ju membership quer%s received with invalid field(s)\n");
904 py64(igps_rcv_gen_queries, "\t%ju general quer%s received\n");
905 py64(igps_rcv_group_queries, "\t%ju group quer%s received\n");
906 py64(igps_rcv_gsr_queries, "\t%ju group-source quer%s received\n");
907 py64(igps_drop_gsr_queries, "\t%ju group-source quer%s dropped\n");
908 p64(igps_rcv_reports, "\t%ju membership report%s received\n");
909 p64(igps_rcv_badreports,
910 "\t%ju membership report%s received with invalid field(s)\n");
911 p64(igps_rcv_ourreports,
912 "\t%ju membership report%s received for groups to which we belong\n");
913 p64(igps_rcv_nora, "\t%ju V3 report%s received without Router Alert\n");
914 p64(igps_snd_reports, "\t%ju membership report%s sent\n");
915
916 if (interval > 0)
917 bcopy(&igmpstat, &pigmpstat, len);
918
919 #undef IGMPDIFF
920 #undef p64
921 #undef py64
922 }
923
924 /*
925 * Pretty print an Internet address (net address + port).
926 */
927 void
928 inetprint(struct in_addr *in, int port, char *proto, int numeric_port)
929 {
930 struct servent *sp = 0;
931 char line[80], *cp;
932 int width;
933
934 if (Wflag)
935 snprintf(line, sizeof(line), "%s.", inetname(in));
936 else
937 snprintf(line, sizeof(line), "%.*s.", (Aflag && !numeric_port) ? 12 : 16, inetname(in));
938 cp = index(line, '\0');
939 if (!numeric_port && port)
940 #ifdef _SERVICE_CACHE_
941 sp = _serv_cache_getservbyport(port, proto);
942 #else
943 sp = getservbyport((int)port, proto);
944 #endif
945 if (sp || port == 0)
946 snprintf(cp, sizeof(line) - (cp - line), "%.15s ", sp ? sp->s_name : "*");
947 else
948 snprintf(cp, sizeof(line) - (cp - line), "%d ", ntohs((u_short)port));
949 width = (Aflag && !Wflag) ? 18 : 22;
950 if (Wflag)
951 printf("%-*s ", width, line);
952 else
953 printf("%-*.*s ", width, width, line);
954 }
955
956 /*
957 * Construct an Internet address representation.
958 * If the nflag has been supplied, give
959 * numeric value, otherwise try for symbolic name.
960 */
961 char *
962 inetname(struct in_addr *inp)
963 {
964 register char *cp;
965 static char line[MAXHOSTNAMELEN];
966 struct hostent *hp;
967 struct netent *np;
968
969 cp = 0;
970 if (!nflag && inp->s_addr != INADDR_ANY) {
971 int net = inet_netof(*inp);
972 int lna = inet_lnaof(*inp);
973
974 if (lna == INADDR_ANY) {
975 np = getnetbyaddr(net, AF_INET);
976 if (np)
977 cp = np->n_name;
978 }
979 if (cp == 0) {
980 hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
981 if (hp) {
982 cp = hp->h_name;
983 //### trimdomain(cp, strlen(cp));
984 }
985 }
986 }
987 if (inp->s_addr == INADDR_ANY)
988 strlcpy(line, "*", sizeof(line));
989 else if (cp) {
990 strncpy(line, cp, sizeof(line) - 1);
991 line[sizeof(line) - 1] = '\0';
992 } else {
993 inp->s_addr = ntohl(inp->s_addr);
994 #define C(x) ((u_int)((x) & 0xff))
995 snprintf(line, sizeof(line), "%u.%u.%u.%u", C(inp->s_addr >> 24),
996 C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
997 }
998 return (line);
999 }