]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/netstat/inet.c
This commit was generated by cvs2svn to compensate for changes in r106907,
[FreeBSD/FreeBSD.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$";
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, const char *, int);
85 #ifdef INET6
86 static int udp_done, tcp_done;
87 #endif /* INET6 */
88
89 /*
90  * Print a summary of connections related to an Internet
91  * protocol.  For TCP, also give state of connection.
92  * Listening processes (aflag) are suppressed unless the
93  * -a (all) flag is specified.
94  */
95 void
96 protopr(u_long proto,           /* for sysctl version we pass proto # */
97         const char *name, int af1)
98 {
99         int istcp;
100         static int first = 1;
101         char *buf;
102         const char *mibvar, *vchar;
103         struct tcpcb *tp = NULL;
104         struct inpcb *inp;
105         struct xinpgen *xig, *oxig;
106         struct xsocket *so;
107         size_t len;
108
109         istcp = 0;
110         switch (proto) {
111         case IPPROTO_TCP:
112 #ifdef INET6
113                 if (tcp_done != 0)
114                         return;
115                 else
116                         tcp_done = 1;
117 #endif
118                 istcp = 1;
119                 mibvar = "net.inet.tcp.pcblist";
120                 break;
121         case IPPROTO_UDP:
122 #ifdef INET6
123                 if (udp_done != 0)
124                         return;
125                 else
126                         udp_done = 1;
127 #endif
128                 mibvar = "net.inet.udp.pcblist";
129                 break;
130         case IPPROTO_DIVERT:
131                 mibvar = "net.inet.divert.pcblist";
132                 break;
133         default:
134                 mibvar = "net.inet.raw.pcblist";
135                 break;
136         }
137         len = 0;
138         if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
139                 if (errno != ENOENT)
140                         warn("sysctl: %s", mibvar);
141                 return;
142         }
143         if ((buf = malloc(len)) == 0) {
144                 warn("malloc %lu bytes", (u_long)len);
145                 return;
146         }
147         if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
148                 warn("sysctl: %s", mibvar);
149                 free(buf);
150                 return;
151         }
152
153         oxig = xig = (struct xinpgen *)buf;
154         for (xig = (struct xinpgen *)((char *)xig + xig->xig_len);
155              xig->xig_len > sizeof(struct xinpgen);
156              xig = (struct xinpgen *)((char *)xig + xig->xig_len)) {
157                 if (istcp) {
158                         tp = &((struct xtcpcb *)xig)->xt_tp;
159                         inp = &((struct xtcpcb *)xig)->xt_inp;
160                         so = &((struct xtcpcb *)xig)->xt_socket;
161                 } else {
162                         inp = &((struct xinpcb *)xig)->xi_inp;
163                         so = &((struct xinpcb *)xig)->xi_socket;
164                 }
165
166                 /* Ignore sockets for protocols other than the desired one. */
167                 if (so->xso_protocol != (int)proto)
168                         continue;
169
170                 /* Ignore PCBs which were freed during copyout. */
171                 if (inp->inp_gencnt > oxig->xig_gen)
172                         continue;
173
174                 if ((af1 == AF_INET && (inp->inp_vflag & INP_IPV4) == 0)
175 #ifdef INET6
176                     || (af1 == AF_INET6 && (inp->inp_vflag & INP_IPV6) == 0)
177 #endif /* INET6 */
178                     || (af1 == AF_UNSPEC && ((inp->inp_vflag & INP_IPV4) == 0
179 #ifdef INET6
180                                             && (inp->inp_vflag &
181                                                 INP_IPV6) == 0
182 #endif /* INET6 */
183                         ))
184                     )
185                         continue;
186                 if (!aflag &&
187                     (
188                      (af1 == AF_INET &&
189                       inet_lnaof(inp->inp_laddr) == INADDR_ANY)
190 #ifdef INET6
191                      || (af1 == AF_INET6 &&
192                          IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
193 #endif /* INET6 */
194                      || (af1 == AF_UNSPEC &&
195                          (((inp->inp_vflag & INP_IPV4) != 0 &&
196                            inet_lnaof(inp->inp_laddr) == INADDR_ANY)
197 #ifdef INET6
198                           || ((inp->inp_vflag & INP_IPV6) != 0 &&
199                               IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
200 #endif
201                           ))
202                      ))
203                         continue;
204
205                 if (first) {
206                         if (!Lflag) {
207                                 printf("Active Internet connections");
208                                 if (aflag)
209                                         printf(" (including servers)");
210                         } else
211                                 printf(
212         "Current listen queue sizes (qlen/incqlen/maxqlen)");
213                         putchar('\n');
214                         if (Aflag)
215                                 printf("%-8.8s ", "Socket");
216                         if (Lflag)
217                                 printf("%-5.5s %-14.14s %-22.22s\n",
218                                         "Proto", "Listen", "Local Address");
219                         else
220                                 printf((Aflag && !Wflag) ?
221                 "%-5.5s %-6.6s %-6.6s  %-18.18s %-18.18s %s\n" :
222                 "%-5.5s %-6.6s %-6.6s  %-22.22s %-22.22s %s\n",
223                                         "Proto", "Recv-Q", "Send-Q",
224                                         "Local Address", "Foreign Address",
225                                         "(state)");
226                         first = 0;
227                 }
228                 if (Lflag && so->so_qlimit == 0)
229                         continue;
230                 if (Aflag) {
231                         if (istcp)
232                                 printf("%8lx ", (u_long)inp->inp_ppcb);
233                         else
234                                 printf("%8lx ", (u_long)so->so_pcb);
235                 }
236 #ifdef INET6
237                 if ((inp->inp_vflag & INP_IPV6) != 0)
238                         vchar = ((inp->inp_vflag & INP_IPV4) != 0)
239                                 ? "46" : "6 ";
240                 else
241 #endif
242                 vchar = ((inp->inp_vflag & INP_IPV4) != 0)
243                                 ? "4 " : "  ";
244                 printf("%-3.3s%-2.2s ", name, vchar);
245                 if (Lflag) {
246                         char buf1[15];
247
248                         snprintf(buf1, 15, "%d/%d/%d", so->so_qlen,
249                                  so->so_incqlen, so->so_qlimit);
250                         printf("%-14.14s ", buf1);
251                 } else {
252                         printf("%6u %6u  ",
253                                so->so_rcv.sb_cc,
254                                so->so_snd.sb_cc);
255                 }
256                 if (numeric_port) {
257                         if (inp->inp_vflag & INP_IPV4) {
258                                 inetprint(&inp->inp_laddr, (int)inp->inp_lport,
259                                           name, 1);
260                                 if (!Lflag)
261                                         inetprint(&inp->inp_faddr,
262                                                   (int)inp->inp_fport, name, 1);
263                         }
264 #ifdef INET6
265                         else if (inp->inp_vflag & INP_IPV6) {
266                                 inet6print(&inp->in6p_laddr,
267                                            (int)inp->inp_lport, name, 1);
268                                 if (!Lflag)
269                                         inet6print(&inp->in6p_faddr,
270                                                    (int)inp->inp_fport, name, 1);
271                         } /* else nothing printed now */
272 #endif /* INET6 */
273                 } else if (inp->inp_flags & INP_ANONPORT) {
274                         if (inp->inp_vflag & INP_IPV4) {
275                                 inetprint(&inp->inp_laddr, (int)inp->inp_lport,
276                                           name, 1);
277                                 if (!Lflag)
278                                         inetprint(&inp->inp_faddr,
279                                                   (int)inp->inp_fport, name, 0);
280                         }
281 #ifdef INET6
282                         else if (inp->inp_vflag & INP_IPV6) {
283                                 inet6print(&inp->in6p_laddr,
284                                            (int)inp->inp_lport, name, 1);
285                                 if (!Lflag)
286                                         inet6print(&inp->in6p_faddr,
287                                                    (int)inp->inp_fport, name, 0);
288                         } /* else nothing printed now */
289 #endif /* INET6 */
290                 } else {
291                         if (inp->inp_vflag & INP_IPV4) {
292                                 inetprint(&inp->inp_laddr, (int)inp->inp_lport,
293                                           name, 0);
294                                 if (!Lflag)
295                                         inetprint(&inp->inp_faddr,
296                                                   (int)inp->inp_fport, name,
297                                                   inp->inp_lport !=
298                                                         inp->inp_fport);
299                         }
300 #ifdef INET6
301                         else if (inp->inp_vflag & INP_IPV6) {
302                                 inet6print(&inp->in6p_laddr,
303                                            (int)inp->inp_lport, name, 0);
304                                 if (!Lflag)
305                                         inet6print(&inp->in6p_faddr,
306                                                    (int)inp->inp_fport, name,
307                                                    inp->inp_lport !=
308                                                         inp->inp_fport);
309                         } /* else nothing printed now */
310 #endif /* INET6 */
311                 }
312                 if (istcp && !Lflag) {
313                         if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES)
314                                 printf("%d", tp->t_state);
315                       else {
316                                 printf("%s", tcpstates[tp->t_state]);
317 #if defined(TF_NEEDSYN) && defined(TF_NEEDFIN)
318                               /* Show T/TCP `hidden state' */
319                               if (tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN))
320                                       putchar('*');
321 #endif /* defined(TF_NEEDSYN) && defined(TF_NEEDFIN) */
322                       }
323                 }
324                 putchar('\n');
325         }
326         if (xig != oxig && xig->xig_gen != oxig->xig_gen) {
327                 if (oxig->xig_count > xig->xig_count) {
328                         printf("Some %s sockets may have been deleted.\n",
329                                name);
330                 } else if (oxig->xig_count < xig->xig_count) {
331                         printf("Some %s sockets may have been created.\n",
332                                name);
333                 } else {
334                         printf("Some %s sockets may have been created or deleted",
335                                name);
336                 }
337         }
338         free(buf);
339 }
340
341 /*
342  * Dump TCP statistics structure.
343  */
344 void
345 tcp_stats(u_long off __unused, const char *name, int af1 __unused)
346 {
347         struct tcpstat tcpstat, zerostat;
348         size_t len = sizeof tcpstat;
349         
350         if (zflag)
351                 memset(&zerostat, 0, len);
352         if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len,
353             zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
354                 warn("sysctl: net.inet.tcp.stats");
355                 return;
356         }
357
358 #ifdef INET6
359         if (tcp_done != 0)
360                 return;
361         else
362                 tcp_done = 1;
363 #endif
364
365         printf ("%s:\n", name);
366
367 #define p(f, m) if (tcpstat.f || sflag <= 1) \
368     printf(m, tcpstat.f, plural(tcpstat.f))
369 #define p1a(f, m) if (tcpstat.f || sflag <= 1) \
370     printf(m, tcpstat.f)
371 #define p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
372     printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2, plural(tcpstat.f2))
373 #define p2a(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
374     printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2)
375 #define p3(f, m) if (tcpstat.f || sflag <= 1) \
376     printf(m, tcpstat.f, plurales(tcpstat.f))
377
378         p(tcps_sndtotal, "\t%lu packet%s sent\n");
379         p2(tcps_sndpack,tcps_sndbyte,
380                 "\t\t%lu data packet%s (%lu byte%s)\n");
381         p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
382                 "\t\t%lu data packet%s (%lu byte%s) retransmitted\n");
383         p(tcps_sndrexmitbad,
384                 "\t\t%lu data packet%s unnecessarily retransmitted\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 entrie%s added\n"); 
439         p1a(tcps_sc_retransmitted, "\t\t%lu retransmitted\n"); 
440         p1a(tcps_sc_dupsyn, "\t\t%lu dupsyn\n"); 
441         p1a(tcps_sc_dropped, "\t\t%lu dropped\n"); 
442         p1a(tcps_sc_completed, "\t\t%lu completed\n"); 
443         p1a(tcps_sc_bucketoverflow, "\t\t%lu bucket overflow\n"); 
444         p1a(tcps_sc_cacheoverflow, "\t\t%lu cache overflow\n"); 
445         p1a(tcps_sc_reset, "\t\t%lu reset\n"); 
446         p1a(tcps_sc_stale, "\t\t%lu stale\n"); 
447         p1a(tcps_sc_aborted, "\t\t%lu aborted\n"); 
448         p1a(tcps_sc_badack, "\t\t%lu badack\n"); 
449         p1a(tcps_sc_unreach, "\t\t%lu unreach\n"); 
450         p(tcps_sc_zonefail, "\t\t%lu zone failure%s\n"); 
451         p(tcps_sc_sendcookie, "\t%lu cookie%s sent\n"); 
452         p(tcps_sc_recvcookie, "\t%lu cookie%s 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, const char *name, int af1 __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, const char *name, int af1 __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  const 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, const char *name, int af1 __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, const char *name, int af1 __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  * Pretty print an Internet address (net address + port).
710  */
711 void
712 inetprint(struct in_addr *in, int port, const char *proto, int num_port)
713 {
714         struct servent *sp = 0;
715         char line[80], *cp;
716         int width;
717
718         if (Wflag)
719             sprintf(line, "%s.", inetname(in));
720         else
721             sprintf(line, "%.*s.", (Aflag && !num_port) ? 12 : 16, inetname(in));
722         cp = index(line, '\0');
723         if (!num_port && port)
724                 sp = getservbyport((int)port, proto);
725         if (sp || port == 0)
726                 sprintf(cp, "%.15s ", sp ? sp->s_name : "*");
727         else
728                 sprintf(cp, "%d ", ntohs((u_short)port));
729         width = (Aflag && !Wflag) ? 18 : 22;
730         if (Wflag)
731             printf("%-*s ", width, line);
732         else
733             printf("%-*.*s ", width, width, line);
734 }
735
736 /*
737  * Construct an Internet address representation.
738  * If numeric_addr has been supplied, give
739  * numeric value, otherwise try for symbolic name.
740  */
741 char *
742 inetname(struct in_addr *inp)
743 {
744         char *cp;
745         static char line[MAXHOSTNAMELEN];
746         struct hostent *hp;
747         struct netent *np;
748
749         cp = 0;
750         if (!numeric_addr && inp->s_addr != INADDR_ANY) {
751                 int net = inet_netof(*inp);
752                 int lna = inet_lnaof(*inp);
753
754                 if (lna == INADDR_ANY) {
755                         np = getnetbyaddr(net, AF_INET);
756                         if (np)
757                                 cp = np->n_name;
758                 }
759                 if (cp == 0) {
760                         hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
761                         if (hp) {
762                                 cp = hp->h_name;
763                                 trimdomain(cp, strlen(cp));
764                         }
765                 }
766         }
767         if (inp->s_addr == INADDR_ANY)
768                 strcpy(line, "*");
769         else if (cp) {
770                 strncpy(line, cp, sizeof(line) - 1);
771                 line[sizeof(line) - 1] = '\0';
772         } else {
773                 inp->s_addr = ntohl(inp->s_addr);
774 #define C(x)    ((u_int)((x) & 0xff))
775                 sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24),
776                     C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
777         }
778         return (line);
779 }