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