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