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