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