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