Deleted Added
sdiff udiff text old ( 78064 ) new ( 78238 )
full compact
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
34#ifndef lint
35/*
36static char sccsid[] = "@(#)inet.c 8.5 (Berkeley) 5/24/95";
37*/
38static const char rcsid[] =
39 "$FreeBSD: head/usr.bin/netstat/inet.c 78238 2001-06-15 00:25:44Z assar $";
40#endif /* not lint */
41
42#include <sys/param.h>
43#include <sys/queue.h>
44#include <sys/socket.h>
45#include <sys/socketvar.h>
46#include <sys/sysctl.h>
47#include <sys/protosw.h>
48
49#include <net/route.h>
50#include <netinet/in.h>
51#include <netinet/in_systm.h>
52#include <netinet/ip.h>
53#ifdef INET6
54#include <netinet/ip6.h>
55#endif /* INET6 */
56#include <netinet/in_pcb.h>
57#include <netinet/ip_icmp.h>
58#include <netinet/icmp_var.h>
59#include <netinet/igmp_var.h>
60#include <netinet/ip_var.h>
61#include <netinet/tcp.h>
62#include <netinet/tcpip.h>
63#include <netinet/tcp_seq.h>
64#define TCPSTATES
65#include <netinet/tcp_fsm.h>
66#include <netinet/tcp_timer.h>
67#include <netinet/tcp_var.h>
68#include <netinet/tcp_debug.h>
69#include <netinet/udp.h>
70#include <netinet/udp_var.h>
71
72#include <arpa/inet.h>
73#include <err.h>
74#include <errno.h>
75#include <libutil.h>
76#include <netdb.h>
77#include <stdio.h>
78#include <stdlib.h>
79#include <string.h>
80#include <unistd.h>
81#include "netstat.h"
82
83char *inetname __P((struct in_addr *));
84void inetprint __P((struct in_addr *, int, char *, int));
85#ifdef INET6
86extern void inet6print __P((struct in6_addr *, int, char *, int));
87static int udp_done, tcp_done;
88#endif /* INET6 */
89
90/*
91 * Print a summary of connections related to an Internet
92 * protocol. For TCP, also give state of connection.
93 * Listening processes (aflag) are suppressed unless the
94 * -a (all) flag is specified.
95 */
96void
97protopr(proto, name, af)
98 u_long proto; /* for sysctl version we pass proto # */
99 char *name;
100 int af;
101{
102 int istcp;
103 static int first = 1;
104 char *buf;
105 const char *mibvar;
106 struct tcpcb *tp = NULL;
107 struct inpcb *inp;
108 struct xinpgen *xig, *oxig;
109 struct xsocket *so;
110 size_t len;
111
112 istcp = 0;
113 switch (proto) {
114 case IPPROTO_TCP:
115#ifdef INET6
116 if (tcp_done != 0)
117 return;
118 else
119 tcp_done = 1;
120#endif
121 istcp = 1;
122 mibvar = "net.inet.tcp.pcblist";
123 break;
124 case IPPROTO_UDP:
125#ifdef INET6
126 if (udp_done != 0)
127 return;
128 else
129 udp_done = 1;
130#endif
131 mibvar = "net.inet.udp.pcblist";
132 break;
133 case IPPROTO_DIVERT:
134 mibvar = "net.inet.divert.pcblist";
135 break;
136 default:
137 mibvar = "net.inet.raw.pcblist";
138 break;
139 }
140 len = 0;
141 if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
142 if (errno != ENOENT)
143 warn("sysctl: %s", mibvar);
144 return;
145 }
146 if ((buf = malloc(len)) == 0) {
147 warn("malloc %lu bytes", (u_long)len);
148 return;
149 }
150 if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
151 warn("sysctl: %s", mibvar);
152 free(buf);
153 return;
154 }
155
156 oxig = xig = (struct xinpgen *)buf;
157 for (xig = (struct xinpgen *)((char *)xig + xig->xig_len);
158 xig->xig_len > sizeof(struct xinpgen);
159 xig = (struct xinpgen *)((char *)xig + xig->xig_len)) {
160 if (istcp) {
161 tp = &((struct xtcpcb *)xig)->xt_tp;
162 inp = &((struct xtcpcb *)xig)->xt_inp;
163 so = &((struct xtcpcb *)xig)->xt_socket;
164 } else {
165 inp = &((struct xinpcb *)xig)->xi_inp;
166 so = &((struct xinpcb *)xig)->xi_socket;
167 }
168
169 /* Ignore sockets for protocols other than the desired one. */
170 if (so->xso_protocol != proto)
171 continue;
172
173 /* Ignore PCBs which were freed during copyout. */
174 if (inp->inp_gencnt > oxig->xig_gen)
175 continue;
176
177 if ((af == AF_INET && (inp->inp_vflag & INP_IPV4) == 0)
178#ifdef INET6
179 || (af == AF_INET6 && (inp->inp_vflag & INP_IPV6) == 0)
180#endif /* INET6 */
181 || (af == AF_UNSPEC && ((inp->inp_vflag & INP_IPV4) == 0
182#ifdef INET6
183 && (inp->inp_vflag &
184 INP_IPV6) == 0
185#endif /* INET6 */
186 ))
187 )
188 continue;
189 if (!aflag &&
190 (
191 (af == AF_INET &&
192 inet_lnaof(inp->inp_laddr) == INADDR_ANY)
193#ifdef INET6
194 || (af == AF_INET6 &&
195 IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
196#endif /* INET6 */
197 || (af == AF_UNSPEC &&
198 (((inp->inp_vflag & INP_IPV4) != 0 &&
199 inet_lnaof(inp->inp_laddr) == INADDR_ANY)
200#ifdef INET6
201 || ((inp->inp_vflag & INP_IPV6) != 0 &&
202 IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
203#endif
204 ))
205 ))
206 continue;
207
208 if (first) {
209 if (!Lflag) {
210 printf("Active Internet connections");
211 if (aflag)
212 printf(" (including servers)");
213 } else
214 printf(
215 "Current listen queue sizes (qlen/incqlen/maxqlen)");
216 putchar('\n');
217 if (Aflag)
218 printf("%-8.8s ", "Socket");
219 if (Lflag)
220 printf("%-14.14s %-22.22s\n",
221 "Listen", "Local Address");
222 else
223 printf((Aflag && !Wflag) ?
224 "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" :
225 "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n",
226 "Proto", "Recv-Q", "Send-Q",
227 "Local Address", "Foreign Address",
228 "(state)");
229 first = 0;
230 }
231 if (Aflag) {
232 if (istcp)
233 printf("%8lx ", (u_long)inp->inp_ppcb);
234 else
235 printf("%8lx ", (u_long)so->so_pcb);
236 }
237 if (Lflag)
238 if (so->so_qlimit) {
239 char buf[15];
240
241 snprintf(buf, 15, "%d/%d/%d", so->so_qlen,
242 so->so_incqlen, so->so_qlimit);
243 printf("%-14.14s ", buf);
244 } else
245 continue;
246 else {
247 const char *vchar;
248
249#ifdef INET6
250 if ((inp->inp_vflag & INP_IPV6) != 0)
251 vchar = ((inp->inp_vflag & INP_IPV4) != 0)
252 ? "46" : "6 ";
253 else
254#endif
255 vchar = ((inp->inp_vflag & INP_IPV4) != 0)
256 ? "4 " : " ";
257
258 printf("%-3.3s%-2.2s %6ld %6ld ", name, vchar,
259 so->so_rcv.sb_cc,
260 so->so_snd.sb_cc);
261 }
262 if (numeric_port) {
263 if (inp->inp_vflag & INP_IPV4) {
264 inetprint(&inp->inp_laddr, (int)inp->inp_lport,
265 name, 1);
266 if (!Lflag)
267 inetprint(&inp->inp_faddr,
268 (int)inp->inp_fport, name, 1);
269 }
270#ifdef INET6
271 else if (inp->inp_vflag & INP_IPV6) {
272 inet6print(&inp->in6p_laddr,
273 (int)inp->inp_lport, name, 1);
274 if (!Lflag)
275 inet6print(&inp->in6p_faddr,
276 (int)inp->inp_fport, name, 1);
277 } /* else nothing printed now */
278#endif /* INET6 */
279 } else if (inp->inp_flags & INP_ANONPORT) {
280 if (inp->inp_vflag & INP_IPV4) {
281 inetprint(&inp->inp_laddr, (int)inp->inp_lport,
282 name, 1);
283 if (!Lflag)
284 inetprint(&inp->inp_faddr,
285 (int)inp->inp_fport, name, 0);
286 }
287#ifdef INET6
288 else if (inp->inp_vflag & INP_IPV6) {
289 inet6print(&inp->in6p_laddr,
290 (int)inp->inp_lport, name, 1);
291 if (!Lflag)
292 inet6print(&inp->in6p_faddr,
293 (int)inp->inp_fport, name, 0);
294 } /* else nothing printed now */
295#endif /* INET6 */
296 } else {
297 if (inp->inp_vflag & INP_IPV4) {
298 inetprint(&inp->inp_laddr, (int)inp->inp_lport,
299 name, 0);
300 if (!Lflag)
301 inetprint(&inp->inp_faddr,
302 (int)inp->inp_fport, name,
303 inp->inp_lport !=
304 inp->inp_fport);
305 }
306#ifdef INET6
307 else if (inp->inp_vflag & INP_IPV6) {
308 inet6print(&inp->in6p_laddr,
309 (int)inp->inp_lport, name, 0);
310 if (!Lflag)
311 inet6print(&inp->in6p_faddr,
312 (int)inp->inp_fport, name,
313 inp->inp_lport !=
314 inp->inp_fport);
315 } /* else nothing printed now */
316#endif /* INET6 */
317 }
318 if (istcp && !Lflag) {
319 if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES)
320 printf("%d", tp->t_state);
321 else {
322 printf("%s", tcpstates[tp->t_state]);
323#if defined(TF_NEEDSYN) && defined(TF_NEEDFIN)
324 /* Show T/TCP `hidden state' */
325 if (tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN))
326 putchar('*');
327#endif /* defined(TF_NEEDSYN) && defined(TF_NEEDFIN) */
328 }
329 }
330 putchar('\n');
331 }
332 if (xig != oxig && xig->xig_gen != oxig->xig_gen) {
333 if (oxig->xig_count > xig->xig_count) {
334 printf("Some %s sockets may have been deleted.\n",
335 name);
336 } else if (oxig->xig_count < xig->xig_count) {
337 printf("Some %s sockets may have been created.\n",
338 name);
339 } else {
340 printf("Some %s sockets may have been created or deleted",
341 name);
342 }
343 }
344 free(buf);
345}
346
347/*
348 * Dump TCP statistics structure.
349 */
350void
351tcp_stats(off, name)
352 u_long off;
353 char *name;
354{
355 struct tcpstat tcpstat;
356 size_t len = sizeof tcpstat;
357
358 if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, 0, 0) < 0) {
359 warn("sysctl: net.inet.tcp.stats");
360 return;
361 }
362
363#ifdef INET6
364 if (tcp_done != 0)
365 return;
366 else
367 tcp_done = 1;
368#endif
369
370 printf ("%s:\n", name);
371
372#define p(f, m) if (tcpstat.f || sflag <= 1) \
373 printf(m, tcpstat.f, plural(tcpstat.f))
374#define p1a(f, m) if (tcpstat.f || sflag <= 1) \
375 printf(m, tcpstat.f)
376#define p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
377 printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2, plural(tcpstat.f2))
378#define p2a(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
379 printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2)
380#define p3(f, m) if (tcpstat.f || sflag <= 1) \
381 printf(m, tcpstat.f, plurales(tcpstat.f))
382
383 p(tcps_sndtotal, "\t%lu packet%s sent\n");
384 p2(tcps_sndpack,tcps_sndbyte,
385 "\t\t%lu data packet%s (%lu byte%s)\n");
386 p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
387 "\t\t%lu data packet%s (%lu byte%s) retransmitted\n");
388 p(tcps_mturesent, "\t\t%lu resend%s initiated by MTU discovery\n");
389 p2a(tcps_sndacks, tcps_delack,
390 "\t\t%lu ack-only packet%s (%lu delayed)\n");
391 p(tcps_sndurg, "\t\t%lu URG only packet%s\n");
392 p(tcps_sndprobe, "\t\t%lu window probe packet%s\n");
393 p(tcps_sndwinup, "\t\t%lu window update packet%s\n");
394 p(tcps_sndctrl, "\t\t%lu control packet%s\n");
395 p(tcps_rcvtotal, "\t%lu packet%s received\n");
396 p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%lu ack%s (for %lu byte%s)\n");
397 p(tcps_rcvdupack, "\t\t%lu duplicate ack%s\n");
398 p(tcps_rcvacktoomuch, "\t\t%lu ack%s for unsent data\n");
399 p2(tcps_rcvpack, tcps_rcvbyte,
400 "\t\t%lu packet%s (%lu byte%s) received in-sequence\n");
401 p2(tcps_rcvduppack, tcps_rcvdupbyte,
402 "\t\t%lu completely duplicate packet%s (%lu byte%s)\n");
403 p(tcps_pawsdrop, "\t\t%lu old duplicate packet%s\n");
404 p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
405 "\t\t%lu packet%s with some dup. data (%lu byte%s duped)\n");
406 p2(tcps_rcvoopack, tcps_rcvoobyte,
407 "\t\t%lu out-of-order packet%s (%lu byte%s)\n");
408 p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
409 "\t\t%lu packet%s (%lu byte%s) of data after window\n");
410 p(tcps_rcvwinprobe, "\t\t%lu window probe%s\n");
411 p(tcps_rcvwinupd, "\t\t%lu window update packet%s\n");
412 p(tcps_rcvafterclose, "\t\t%lu packet%s received after close\n");
413 p(tcps_rcvbadsum, "\t\t%lu discarded for bad checksum%s\n");
414 p(tcps_rcvbadoff, "\t\t%lu discarded for bad header offset field%s\n");
415 p1a(tcps_rcvshort, "\t\t%lu discarded because packet too short\n");
416 p(tcps_connattempt, "\t%lu connection request%s\n");
417 p(tcps_accepts, "\t%lu connection accept%s\n");
418 p(tcps_badsyn, "\t%lu bad connection attempt%s\n");
419 p(tcps_listendrop, "\t%lu listen queue overflow%s\n");
420 p(tcps_connects, "\t%lu connection%s established (including accepts)\n");
421 p2(tcps_closed, tcps_drops,
422 "\t%lu connection%s closed (including %lu drop%s)\n");
423 p(tcps_cachedrtt, "\t\t%lu connection%s updated cached RTT on close\n");
424 p(tcps_cachedrttvar,
425 "\t\t%lu connection%s updated cached RTT variance on close\n");
426 p(tcps_cachedssthresh,
427 "\t\t%lu connection%s updated cached ssthresh on close\n");
428 p(tcps_conndrops, "\t%lu embryonic connection%s dropped\n");
429 p2(tcps_rttupdated, tcps_segstimed,
430 "\t%lu segment%s updated rtt (of %lu attempt%s)\n");
431 p(tcps_rexmttimeo, "\t%lu retransmit timeout%s\n");
432 p(tcps_timeoutdrop, "\t\t%lu connection%s dropped by rexmit timeout\n");
433 p(tcps_persisttimeo, "\t%lu persist timeout%s\n");
434 p(tcps_persistdrop, "\t\t%lu connection%s dropped by persist timeout\n");
435 p(tcps_keeptimeo, "\t%lu keepalive timeout%s\n");
436 p(tcps_keepprobe, "\t\t%lu keepalive probe%s sent\n");
437 p(tcps_keepdrops, "\t\t%lu connection%s dropped by keepalive\n");
438 p(tcps_predack, "\t%lu correct ACK header prediction%s\n");
439 p(tcps_preddat, "\t%lu correct data packet header prediction%s\n");
440#undef p
441#undef p1a
442#undef p2
443#undef p2a
444#undef p3
445}
446
447/*
448 * Dump UDP statistics structure.
449 */
450void
451udp_stats(off, name)
452 u_long off;
453 char *name;
454{
455 struct udpstat udpstat;
456 size_t len = sizeof udpstat;
457 u_long delivered;
458
459 if (sysctlbyname("net.inet.udp.stats", &udpstat, &len, 0, 0) < 0) {
460 warn("sysctl: net.inet.udp.stats");
461 return;
462 }
463
464#ifdef INET6
465 if (udp_done != 0)
466 return;
467 else
468 udp_done = 1;
469#endif
470
471 printf("%s:\n", name);
472#define p(f, m) if (udpstat.f || sflag <= 1) \
473 printf(m, udpstat.f, plural(udpstat.f))
474#define p1a(f, m) if (udpstat.f || sflag <= 1) \
475 printf(m, udpstat.f)
476 p(udps_ipackets, "\t%lu datagram%s received\n");
477 p1a(udps_hdrops, "\t%lu with incomplete header\n");
478 p1a(udps_badlen, "\t%lu with bad data length field\n");
479 p1a(udps_badsum, "\t%lu with bad checksum\n");
480 p1a(udps_nosum, "\t%lu with no checksum\n");
481 p1a(udps_noport, "\t%lu dropped due to no socket\n");
482 p(udps_noportbcast,
483 "\t%lu broadcast/multicast datagram%s dropped due to no socket\n");
484 p1a(udps_fullsock, "\t%lu dropped due to full socket buffers\n");
485 p1a(udpps_pcbhashmiss, "\t%lu not for hashed pcb\n");
486 delivered = udpstat.udps_ipackets -
487 udpstat.udps_hdrops -
488 udpstat.udps_badlen -
489 udpstat.udps_badsum -
490 udpstat.udps_noport -
491 udpstat.udps_noportbcast -
492 udpstat.udps_fullsock;
493 if (delivered || sflag <= 1)
494 printf("\t%lu delivered\n", delivered);
495 p(udps_opackets, "\t%lu datagram%s output\n");
496#undef p
497#undef p1a
498}
499
500/*
501 * Dump IP statistics structure.
502 */
503void
504ip_stats(off, name)
505 u_long off;
506 char *name;
507{
508 struct ipstat ipstat;
509 size_t len = sizeof ipstat;
510
511 if (sysctlbyname("net.inet.ip.stats", &ipstat, &len, 0, 0) < 0) {
512 warn("sysctl: net.inet.ip.stats");
513 return;
514 }
515
516 printf("%s:\n", name);
517
518#define p(f, m) if (ipstat.f || sflag <= 1) \
519 printf(m, ipstat.f, plural(ipstat.f))
520#define p1a(f, m) if (ipstat.f || sflag <= 1) \
521 printf(m, ipstat.f)
522
523 p(ips_total, "\t%lu total packet%s received\n");
524 p(ips_badsum, "\t%lu bad header checksum%s\n");
525 p1a(ips_toosmall, "\t%lu with size smaller than minimum\n");
526 p1a(ips_tooshort, "\t%lu with data size < data length\n");
527 p1a(ips_toolong, "\t%lu with ip length > max ip packet size\n");
528 p1a(ips_badhlen, "\t%lu with header length < data size\n");
529 p1a(ips_badlen, "\t%lu with data length < header length\n");
530 p1a(ips_badoptions, "\t%lu with bad options\n");
531 p1a(ips_badvers, "\t%lu with incorrect version number\n");
532 p(ips_fragments, "\t%lu fragment%s received\n");
533 p(ips_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
534 p(ips_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
535 p(ips_reassembled, "\t%lu packet%s reassembled ok\n");
536 p(ips_delivered, "\t%lu packet%s for this host\n");
537 p(ips_noproto, "\t%lu packet%s for unknown/unsupported protocol\n");
538 p(ips_forward, "\t%lu packet%s forwarded");
539 p(ips_fastforward, " (%lu packet%s fast forwarded)");
540 if (ipstat.ips_forward || sflag <= 1)
541 putchar('\n');
542 p(ips_cantforward, "\t%lu packet%s not forwardable\n");
543 p(ips_notmember,
544 "\t%lu packet%s received for unknown multicast group\n");
545 p(ips_redirectsent, "\t%lu redirect%s sent\n");
546 p(ips_localout, "\t%lu packet%s sent from this host\n");
547 p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n");
548 p(ips_odropped,
549 "\t%lu output packet%s dropped due to no bufs, etc.\n");
550 p(ips_noroute, "\t%lu output packet%s discarded due to no route\n");
551 p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
552 p(ips_ofragments, "\t%lu fragment%s created\n");
553 p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
554 p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n");
555 p(ips_badaddr, "\t%lu datagram%s with bad address in header\n");
556#undef p
557#undef p1a
558}
559
560static char *icmpnames[] = {
561 "echo reply",
562 "#1",
563 "#2",
564 "destination unreachable",
565 "source quench",
566 "routing redirect",
567 "#6",
568 "#7",
569 "echo",
570 "router advertisement",
571 "router solicitation",
572 "time exceeded",
573 "parameter problem",
574 "time stamp",
575 "time stamp reply",
576 "information request",
577 "information request reply",
578 "address mask request",
579 "address mask reply",
580};
581
582/*
583 * Dump ICMP statistics.
584 */
585void
586icmp_stats(off, name)
587 u_long off;
588 char *name;
589{
590 struct icmpstat icmpstat;
591 int i, first;
592 int mib[4]; /* CTL_NET + PF_INET + IPPROTO_ICMP + req */
593 size_t len;
594
595 mib[0] = CTL_NET;
596 mib[1] = PF_INET;
597 mib[2] = IPPROTO_ICMP;
598 mib[3] = ICMPCTL_STATS;
599
600 len = sizeof icmpstat;
601 memset(&icmpstat, 0, len);
602 if (sysctl(mib, 4, &icmpstat, &len, (void *)0, 0) < 0)
603 return; /* XXX should complain, but not traditional */
604
605 printf("%s:\n", name);
606
607#define p(f, m) if (icmpstat.f || sflag <= 1) \
608 printf(m, icmpstat.f, plural(icmpstat.f))
609#define p1a(f, m) if (icmpstat.f || sflag <= 1) \
610 printf(m, icmpstat.f)
611
612 p(icps_error, "\t%lu call%s to icmp_error\n");
613 p(icps_oldicmp,
614 "\t%lu error%s not generated 'cuz old message was icmp\n");
615 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
616 if (icmpstat.icps_outhist[i] != 0) {
617 if (first) {
618 printf("\tOutput histogram:\n");
619 first = 0;
620 }
621 printf("\t\t%s: %lu\n", icmpnames[i],
622 icmpstat.icps_outhist[i]);
623 }
624 p(icps_badcode, "\t%lu message%s with bad code fields\n");
625 p(icps_tooshort, "\t%lu message%s < minimum length\n");
626 p(icps_checksum, "\t%lu bad checksum%s\n");
627 p(icps_badlen, "\t%lu message%s with bad length\n");
628 p1a(icps_bmcastecho, "\t%lu multicast echo requests ignored\n");
629 p1a(icps_bmcasttstamp, "\t%lu multicast timestamp requests ignored\n");
630 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
631 if (icmpstat.icps_inhist[i] != 0) {
632 if (first) {
633 printf("\tInput histogram:\n");
634 first = 0;
635 }
636 printf("\t\t%s: %lu\n", icmpnames[i],
637 icmpstat.icps_inhist[i]);
638 }
639 p(icps_reflect, "\t%lu message response%s generated\n");
640#undef p
641#undef p1a
642 mib[3] = ICMPCTL_MASKREPL;
643 len = sizeof i;
644 if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0)
645 return;
646 printf("\tICMP address mask responses are %sabled\n",
647 i ? "en" : "dis");
648}
649
650/*
651 * Dump IGMP statistics structure.
652 */
653void
654igmp_stats(off, name)
655 u_long off;
656 char *name;
657{
658 struct igmpstat igmpstat;
659 size_t len = sizeof igmpstat;
660
661 if (sysctlbyname("net.inet.igmp.stats", &igmpstat, &len, 0, 0) < 0) {
662 warn("sysctl: net.inet.igmp.stats");
663 return;
664 }
665
666 printf("%s:\n", name);
667
668#define p(f, m) if (igmpstat.f || sflag <= 1) \
669 printf(m, igmpstat.f, plural(igmpstat.f))
670#define py(f, m) if (igmpstat.f || sflag <= 1) \
671 printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
672 p(igps_rcv_total, "\t%u message%s received\n");
673 p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n");
674 p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n");
675 py(igps_rcv_queries, "\t%u membership quer%s received\n");
676 py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n");
677 p(igps_rcv_reports, "\t%u membership report%s received\n");
678 p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n");
679 p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n");
680 p(igps_snd_reports, "\t%u membership report%s sent\n");
681#undef p
682#undef py
683}
684
685/*
686 * Pretty print an Internet address (net address + port).
687 */
688void
689inetprint(in, port, proto, numeric_port)
690 register struct in_addr *in;
691 int port;
692 char *proto;
693 int numeric_port;
694{
695 struct servent *sp = 0;
696 char line[80], *cp;
697 int width;
698
699 if (Wflag)
700 sprintf(line, "%s.", inetname(in));
701 else
702 sprintf(line, "%.*s.", (Aflag && !numeric_port) ? 12 : 16, inetname(in));
703 cp = index(line, '\0');
704 if (!numeric_port && port)
705 sp = getservbyport((int)port, proto);
706 if (sp || port == 0)
707 sprintf(cp, "%.15s ", sp ? sp->s_name : "*");
708 else
709 sprintf(cp, "%d ", ntohs((u_short)port));
710 width = (Aflag && !Wflag) ? 18 : 22;
711 if (Wflag)
712 printf("%-*s ", width, line);
713 else
714 printf("%-*.*s ", width, width, line);
715}
716
717/*
718 * Construct an Internet address representation.
719 * If numeric_addr has been supplied, give
720 * numeric value, otherwise try for symbolic name.
721 */
722char *
723inetname(inp)
724 struct in_addr *inp;
725{
726 register char *cp;
727 static char line[MAXHOSTNAMELEN];
728 struct hostent *hp;
729 struct netent *np;
730
731 cp = 0;
732 if (!numeric_addr && inp->s_addr != INADDR_ANY) {
733 int net = inet_netof(*inp);
734 int lna = inet_lnaof(*inp);
735
736 if (lna == INADDR_ANY) {
737 np = getnetbyaddr(net, AF_INET);
738 if (np)
739 cp = np->n_name;
740 }
741 if (cp == 0) {
742 hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
743 if (hp) {
744 cp = hp->h_name;
745 trimdomain(cp, strlen(cp));
746 }
747 }
748 }
749 if (inp->s_addr == INADDR_ANY)
750 strcpy(line, "*");
751 else if (cp) {
752 strncpy(line, cp, sizeof(line) - 1);
753 line[sizeof(line) - 1] = '\0';
754 } else {
755 inp->s_addr = ntohl(inp->s_addr);
756#define C(x) ((u_int)((x) & 0xff))
757 sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24),
758 C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
759 }
760 return (line);
761}