d3dd8ddc9c7b3e1ab755cbbaa47a8cfe9786ef77
[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.20 2007/08/16 20:03:58 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 #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                 (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, char *name, int af __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, char *name, int af __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, 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, (unsigned long long)carpstat.f, plural((int)carpstat.f))
609 #define p2(f, m) if (carpstat.f || sflag <= 1) \
610        printf(m, (unsigned long long)carpstat.f)
611
612        p(carps_ipackets, "\t%llu packet%s received (IPv4)\n");
613        p(carps_ipackets6, "\t%llu packet%s received (IPv6)\n");
614        p(carps_badttl, "\t\t%llu packet%s discarded for wrong TTL\n");
615        p(carps_hdrops, "\t\t%llu packet%s shorter than header\n");
616        p(carps_badsum, "\t\t%llu discarded for bad checksum%s\n");
617        p(carps_badver, "\t\t%llu discarded packet%s with a bad version\n");
618        p2(carps_badlen, "\t\t%llu discarded because packet too short\n");
619        p2(carps_badauth, "\t\t%llu discarded for bad authentication\n");
620        p2(carps_badvhid, "\t\t%llu discarded for bad vhid\n");
621        p2(carps_badaddrs, "\t\t%llu discarded because of a bad address list\n");
622        p(carps_opackets, "\t%llu packet%s sent (IPv4)\n");
623        p(carps_opackets6, "\t%llu packet%s sent (IPv6)\n");
624        p2(carps_onomem, "\t\t%llu 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, char *name, int af __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  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, char *name, int af __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, (void *)0, 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, char *name, int af __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, 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, pimstat.f, plural(pimstat.f))
863 #define py(f, m) if (pimstat.f || sflag <= 1) \
864     printf(m, pimstat.f, pimstat.f != 1 ? "ies" : "y")
865         p(pims_rcv_total_msgs, "\t%llu message%s received\n");
866         p(pims_rcv_total_bytes, "\t%llu byte%s received\n");
867         p(pims_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
868         p(pims_rcv_badsum, "\t%llu message%s received with bad checksum\n");
869         p(pims_rcv_badversion, "\t%llu message%s received with bad version\n");
870         p(pims_rcv_registers_msgs, "\t%llu data register message%s received\n");
871         p(pims_rcv_registers_bytes, "\t%llu data register byte%s received\n");
872         p(pims_rcv_registers_wrongiif, "\t%llu data register message%s received on wrong iif\n");
873         p(pims_rcv_badregisters, "\t%llu bad register%s received\n");
874         p(pims_snd_registers_msgs, "\t%llu data register message%s sent\n");
875         p(pims_snd_registers_bytes, "\t%llu 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 numeric_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 && !numeric_port) ? 12 : 16, inetname(in));
894         cp = strchr(line, '\0');
895         if (!numeric_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((char *)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 }