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