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