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