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