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