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