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