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