]> git.saurik.com Git - apple/network_cmds.git/blob - netstat.tproj/inet.c
4942fc0d4bacb3c98562112845d71a8a893cddf7
[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.9 2006/04/04 04:36:27 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, *test;
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 test = _nc_table_find(_serv_cache, key);
120 if (test == 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 %6u %6u ", 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 static struct tcpstat ptcpstat;
440 struct tcpstat tcpstat;
441 size_t len = sizeof tcpstat;
442
443 if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, 0, 0) < 0) {
444 warn("sysctl: net.inet.tcp.stats");
445 return;
446 }
447
448 #ifdef INET6
449 if (tcp_done != 0 && interval == 0)
450 return;
451 else
452 tcp_done = 1;
453 #endif
454
455 printf ("%s:\n", name);
456
457 #define TCPDIFF(f) (tcpstat.f - ptcpstat.f)
458 #define p(f, m) if (TCPDIFF(f) || sflag <= 1) \
459 printf(m, TCPDIFF(f), plural(TCPDIFF(f)))
460 #define p1a(f, m) if (TCPDIFF(f) || sflag <= 1) \
461 printf(m, TCPDIFF(f))
462 #define p2(f1, f2, m) if (TCPDIFF(f1) || TCPDIFF(f2) || sflag <= 1) \
463 printf(m, TCPDIFF(f1), plural(TCPDIFF(f1)), TCPDIFF(f2), plural(TCPDIFF(f2)))
464 #define p2a(f1, f2, m) if (TCPDIFF(f1) || TCPDIFF(f2) || sflag <= 1) \
465 printf(m, TCPDIFF(f1), plural(TCPDIFF(f1)), TCPDIFF(f2))
466 #define p3(f, m) if (TCPDIFF(f) || sflag <= 1) \
467 printf(m, TCPDIFF(f), plurales(TCPDIFF(f)))
468
469 p(tcps_sndtotal, "\t%u packet%s sent\n");
470 p2(tcps_sndpack,tcps_sndbyte,
471 "\t\t%u data packet%s (%u byte%s)\n");
472 p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
473 "\t\t%u data packet%s (%u byte%s) retransmitted\n");
474 p(tcps_mturesent, "\t\t%u resend%s initiated by MTU discovery\n");
475 p2a(tcps_sndacks, tcps_delack,
476 "\t\t%u ack-only packet%s (%u delayed)\n");
477 p(tcps_sndurg, "\t\t%u URG only packet%s\n");
478 p(tcps_sndprobe, "\t\t%u window probe packet%s\n");
479 p(tcps_sndwinup, "\t\t%u window update packet%s\n");
480 p(tcps_sndctrl, "\t\t%u control packet%s\n");
481 p(tcps_rcvtotal, "\t%u packet%s received\n");
482 p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%u ack%s (for %u byte%s)\n");
483 p(tcps_rcvdupack, "\t\t%u duplicate ack%s\n");
484 p(tcps_rcvacktoomuch, "\t\t%u ack%s for unsent data\n");
485 p2(tcps_rcvpack, tcps_rcvbyte,
486 "\t\t%u packet%s (%u byte%s) received in-sequence\n");
487 p2(tcps_rcvduppack, tcps_rcvdupbyte,
488 "\t\t%u completely duplicate packet%s (%u byte%s)\n");
489 p(tcps_pawsdrop, "\t\t%u old duplicate packet%s\n");
490 p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
491 "\t\t%u packet%s with some dup. data (%u byte%s duped)\n");
492 p2(tcps_rcvoopack, tcps_rcvoobyte,
493 "\t\t%u out-of-order packet%s (%u byte%s)\n");
494 p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
495 "\t\t%u packet%s (%u byte%s) of data after window\n");
496 p(tcps_rcvwinprobe, "\t\t%u window probe%s\n");
497 p(tcps_rcvwinupd, "\t\t%u window update packet%s\n");
498 p(tcps_rcvafterclose, "\t\t%u packet%s received after close\n");
499 p(tcps_badrst, "\t\t%u bad reset%s\n");
500 p(tcps_rcvbadsum, "\t\t%u discarded for bad checksum%s\n");
501 p(tcps_rcvbadoff, "\t\t%u discarded for bad header offset field%s\n");
502 p1a(tcps_rcvshort, "\t\t%u discarded because packet too short\n");
503 p(tcps_connattempt, "\t%u connection request%s\n");
504 p(tcps_accepts, "\t%u connection accept%s\n");
505 p(tcps_badsyn, "\t%u bad connection attempt%s\n");
506 p(tcps_listendrop, "\t%u listen queue overflow%s\n");
507 p(tcps_connects, "\t%u connection%s established (including accepts)\n");
508 p2(tcps_closed, tcps_drops,
509 "\t%u connection%s closed (including %u drop%s)\n");
510 p(tcps_cachedrtt, "\t\t%u connection%s updated cached RTT on close\n");
511 p(tcps_cachedrttvar,
512 "\t\t%u connection%s updated cached RTT variance on close\n");
513 p(tcps_cachedssthresh,
514 "\t\t%u connection%s updated cached ssthresh on close\n");
515 p(tcps_conndrops, "\t%u embryonic connection%s dropped\n");
516 p2(tcps_rttupdated, tcps_segstimed,
517 "\t%u segment%s updated rtt (of %u attempt%s)\n");
518 p(tcps_rexmttimeo, "\t%u retransmit timeout%s\n");
519 p(tcps_timeoutdrop, "\t\t%u connection%s dropped by rexmit timeout\n");
520 p(tcps_persisttimeo, "\t%u persist timeout%s\n");
521 p(tcps_persistdrop, "\t\t%u connection%s dropped by persist timeout\n");
522 p(tcps_keeptimeo, "\t%u keepalive timeout%s\n");
523 p(tcps_keepprobe, "\t\t%u keepalive probe%s sent\n");
524 p(tcps_keepdrops, "\t\t%u connection%s dropped by keepalive\n");
525 p(tcps_predack, "\t%u correct ACK header prediction%s\n");
526 p(tcps_preddat, "\t%u correct data packet header prediction%s\n");
527 #ifdef TCP_MAX_SACK
528 /* TCP_MAX_SACK indicates the header has the SACK structures */
529 p(tcps_sack_recovery_episode, "\t%u SACK recovery episode%s\n");
530 p(tcps_sack_rexmits,
531 "\t%u segment rexmit%s in SACK recovery episodes\n");
532 p(tcps_sack_rexmit_bytes,
533 "\t%u byte rexmit%s in SACK recovery episodes\n");
534 p(tcps_sack_rcv_blocks,
535 "\t%u SACK option%s (SACK blocks) received\n");
536 p(tcps_sack_send_blocks, "\t%u SACK option%s (SACK blocks) sent\n");
537 p1a(tcps_sack_sboverflow, "\t%u SACK scoreboard overflow\n");
538 #endif /* TCP_MAX_SACK */
539
540 if (interval > 0)
541 bcopy(&tcpstat, &ptcpstat, len);
542
543 #undef TCPDIFF
544 #undef p
545 #undef p1a
546 #undef p2
547 #undef p2a
548 #undef p3
549 }
550
551 /*
552 * Dump UDP statistics structure.
553 */
554 void
555 udp_stats(u_long off , char *name, int af )
556 {
557 static struct udpstat pudpstat;
558 struct udpstat udpstat;
559 size_t len = sizeof udpstat;
560 u_long delivered;
561
562 if (sysctlbyname("net.inet.udp.stats", &udpstat, &len, 0, 0) < 0) {
563 warn("sysctl: net.inet.udp.stats");
564 return;
565 }
566
567 #ifdef INET6
568 if (udp_done != 0 && interval == 0)
569 return;
570 else
571 udp_done = 1;
572 #endif
573
574 printf("%s:\n", name);
575
576 #define UDPDIFF(f) (udpstat.f - pudpstat.f)
577 #define p(f, m) if (UDPDIFF(f) || sflag <= 1) \
578 printf(m, UDPDIFF(f), plural(UDPDIFF(f)))
579 #define p1a(f, m) if (UDPDIFF(f) || sflag <= 1) \
580 printf(m, UDPDIFF(f))
581 p(udps_ipackets, "\t%u datagram%s received\n");
582 p1a(udps_hdrops, "\t%u with incomplete header\n");
583 p1a(udps_badlen, "\t%u with bad data length field\n");
584 p1a(udps_badsum, "\t%u with bad checksum\n");
585 #ifndef __APPLE__
586 p1a(udps_nosum, "\t%u with no checksum\n");
587 #endif
588 p1a(udps_noport, "\t%u dropped due to no socket\n");
589 p(udps_noportbcast,
590 "\t%u broadcast/multicast datagram%s dropped due to no socket\n");
591 p1a(udps_fullsock, "\t%u dropped due to full socket buffers\n");
592 p1a(udpps_pcbhashmiss, "\t%u not for hashed pcb\n");
593 delivered = UDPDIFF(udps_ipackets) -
594 UDPDIFF(udps_hdrops) -
595 UDPDIFF(udps_badlen) -
596 UDPDIFF(udps_badsum) -
597 UDPDIFF(udps_noport) -
598 UDPDIFF(udps_noportbcast) -
599 UDPDIFF(udps_fullsock);
600 if (delivered || sflag <= 1)
601 printf("\t%lu delivered\n", delivered);
602 p(udps_opackets, "\t%u datagram%s output\n");
603
604 if (interval > 0)
605 bcopy(&udpstat, &pudpstat, len);
606
607 #undef UDPDIFF
608 #undef p
609 #undef p1a
610 }
611
612 /*
613 * Dump IP statistics structure.
614 */
615 void
616 ip_stats(u_long off , char *name, int af )
617 {
618 static struct ipstat pipstat;
619 struct ipstat ipstat;
620 size_t len = sizeof ipstat;
621
622 if (sysctlbyname("net.inet.ip.stats", &ipstat, &len, 0, 0) < 0) {
623 warn("sysctl: net.inet.ip.stats");
624 return;
625 }
626
627 printf("%s:\n", name);
628
629 #define IPDIFF(f) (ipstat.f - pipstat.f)
630 #define p(f, m) if (IPDIFF(f) || sflag <= 1) \
631 printf(m, IPDIFF(f), plural(IPDIFF(f)))
632 #define p1a(f, m) if (IPDIFF(f) || sflag <= 1) \
633 printf(m, IPDIFF(f))
634
635 p(ips_total, "\t%u total packet%s received\n");
636 p(ips_badsum, "\t%u bad header checksum%s\n");
637 p1a(ips_toosmall, "\t%u with size smaller than minimum\n");
638 p1a(ips_tooshort, "\t%u with data size < data length\n");
639 p1a(ips_toolong, "\t%u with ip length > max ip packet size\n");
640 p1a(ips_badhlen, "\t%u with header length < data size\n");
641 p1a(ips_badlen, "\t%u with data length < header length\n");
642 p1a(ips_badoptions, "\t%u with bad options\n");
643 p1a(ips_badvers, "\t%u with incorrect version number\n");
644 p(ips_fragments, "\t%u fragment%s received\n");
645 p(ips_fragdropped, "\t%u fragment%s dropped (dup or out of space)\n");
646 p(ips_fragtimeout, "\t%u fragment%s dropped after timeout\n");
647 p(ips_reassembled, "\t%u packet%s reassembled ok\n");
648 p(ips_delivered, "\t%u packet%s for this host\n");
649 p(ips_noproto, "\t%u packet%s for unknown/unsupported protocol\n");
650 p(ips_forward, "\t%u packet%s forwarded");
651 p(ips_fastforward, " (%u packet%s fast forwarded)");
652 if (IPDIFF(ips_forward) || sflag <= 1)
653 putchar('\n');
654 p(ips_cantforward, "\t%u packet%s not forwardable\n");
655 p(ips_notmember,
656 "\t%u packet%s received for unknown multicast group\n");
657 p(ips_redirectsent, "\t%u redirect%s sent\n");
658 p(ips_localout, "\t%u packet%s sent from this host\n");
659 p(ips_rawout, "\t%u packet%s sent with fabricated ip header\n");
660 p(ips_odropped,
661 "\t%u output packet%s dropped due to no bufs, etc.\n");
662 p(ips_noroute, "\t%u output packet%s discarded due to no route\n");
663 p(ips_fragmented, "\t%u output datagram%s fragmented\n");
664 p(ips_ofragments, "\t%u fragment%s created\n");
665 p(ips_cantfrag, "\t%u datagram%s that can't be fragmented\n");
666 p(ips_nogif, "\t%u tunneling packet%s that can't find gif\n");
667 p(ips_badaddr, "\t%u datagram%s with bad address in header\n");
668
669 if (interval > 0)
670 bcopy(&ipstat, &pipstat, len);
671
672 #undef IPDIFF
673 #undef p
674 #undef p1a
675 }
676
677 static char *icmpnames[] = {
678 "echo reply",
679 "#1",
680 "#2",
681 "destination unreachable",
682 "source quench",
683 "routing redirect",
684 "#6",
685 "#7",
686 "echo",
687 "router advertisement",
688 "router solicitation",
689 "time exceeded",
690 "parameter problem",
691 "time stamp",
692 "time stamp reply",
693 "information request",
694 "information request reply",
695 "address mask request",
696 "address mask reply",
697 };
698
699 /*
700 * Dump ICMP statistics.
701 */
702 void
703 icmp_stats(u_long off , char *name, int af )
704 {
705 static struct icmpstat picmpstat;
706 struct icmpstat icmpstat;
707 int i, first;
708 int mib[4]; /* CTL_NET + PF_INET + IPPROTO_ICMP + req */
709 size_t len;
710
711 mib[0] = CTL_NET;
712 mib[1] = PF_INET;
713 mib[2] = IPPROTO_ICMP;
714 mib[3] = ICMPCTL_STATS;
715
716 len = sizeof icmpstat;
717 memset(&icmpstat, 0, len);
718 if (sysctl(mib, 4, &icmpstat, &len, (void *)0, 0) < 0)
719 return; /* XXX should complain, but not traditional */
720
721 printf("%s:\n", name);
722
723 #define ICMPDIFF(f) (icmpstat.f - picmpstat.f)
724 #define p(f, m) if (ICMPDIFF(f) || sflag <= 1) \
725 printf(m, ICMPDIFF(f), plural(ICMPDIFF(f)))
726 #define p1a(f, m) if (ICMPDIFF(f) || sflag <= 1) \
727 printf(m, ICMPDIFF(f))
728
729 p(icps_error, "\t%u call%s to icmp_error\n");
730 p(icps_oldicmp,
731 "\t%u error%s not generated 'cuz old message was icmp\n");
732 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
733 if (ICMPDIFF(icps_outhist[i]) != 0) {
734 if (first) {
735 printf("\tOutput histogram:\n");
736 first = 0;
737 }
738 printf("\t\t%s: %u\n", icmpnames[i],
739 ICMPDIFF(icps_outhist[i]));
740 }
741 p(icps_badcode, "\t%u message%s with bad code fields\n");
742 p(icps_tooshort, "\t%u message%s < minimum length\n");
743 p(icps_checksum, "\t%u bad checksum%s\n");
744 p(icps_badlen, "\t%u message%s with bad length\n");
745 p1a(icps_bmcastecho, "\t%u multicast echo requests ignored\n");
746 p1a(icps_bmcasttstamp, "\t%u multicast timestamp requests ignored\n");
747 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
748 if (ICMPDIFF(icps_inhist[i]) != 0) {
749 if (first) {
750 printf("\tInput histogram:\n");
751 first = 0;
752 }
753 printf("\t\t%s: %u\n", icmpnames[i],
754 ICMPDIFF(icps_inhist[i]));
755 }
756 p(icps_reflect, "\t%u message response%s generated\n");
757
758 #undef ICMPDIFF
759 #undef p
760 #undef p1a
761 mib[3] = ICMPCTL_MASKREPL;
762 len = sizeof i;
763 if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0)
764 return;
765 printf("\tICMP address mask responses are %sabled\n",
766 i ? "en" : "dis");
767
768 if (interval > 0)
769 bcopy(&icmpstat, &picmpstat, sizeof (icmpstat));
770 }
771
772 /*
773 * Dump IGMP statistics structure.
774 */
775 void
776 igmp_stats(u_long off , char *name, int af )
777 {
778 static struct igmpstat pigmpstat;
779 struct igmpstat igmpstat;
780 size_t len = sizeof igmpstat;
781
782 if (sysctlbyname("net.inet.igmp.stats", &igmpstat, &len, 0, 0) < 0) {
783 warn("sysctl: net.inet.igmp.stats");
784 return;
785 }
786
787 printf("%s:\n", name);
788
789 #define IGMPDIFF(f) (igmpstat.f - pigmpstat.f)
790 #define p(f, m) if (IGMPDIFF(f) || sflag <= 1) \
791 printf(m, IGMPDIFF(f), plural(IGMPDIFF(f)))
792 #define py(f, m) if (IGMPDIFF(f) || sflag <= 1) \
793 printf(m, IGMPDIFF(f), IGMPDIFF(f) != 1 ? "ies" : "y")
794 p(igps_rcv_total, "\t%u message%s received\n");
795 p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n");
796 p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n");
797 py(igps_rcv_queries, "\t%u membership quer%s received\n");
798 py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n");
799 p(igps_rcv_reports, "\t%u membership report%s received\n");
800 p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n");
801 p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n");
802 p(igps_snd_reports, "\t%u membership report%s sent\n");
803
804 if (interval > 0)
805 bcopy(&igmpstat, &pigmpstat, len);
806
807 #undef IGMPDIFF
808 #undef p
809 #undef py
810 }
811
812 /*
813 * Pretty print an Internet address (net address + port).
814 */
815 void
816 inetprint(struct in_addr *in, int port, char *proto, int numeric_port)
817 {
818 struct servent *sp = 0;
819 char line[80], *cp;
820 int width;
821
822 if (Wflag)
823 sprintf(line, "%s.", inetname(in));
824 else
825 sprintf(line, "%.*s.", (Aflag && !numeric_port) ? 12 : 16, inetname(in));
826 cp = index(line, '\0');
827 if (!numeric_port && port)
828 #ifdef _SERVICE_CACHE_
829 sp = _serv_cache_getservbyport(port, proto);
830 #else
831 sp = getservbyport((int)port, proto);
832 #endif
833 if (sp || port == 0)
834 sprintf(cp, "%.15s ", sp ? sp->s_name : "*");
835 else
836 sprintf(cp, "%d ", ntohs((u_short)port));
837 width = (Aflag && !Wflag) ? 18 : 22;
838 if (Wflag)
839 printf("%-*s ", width, line);
840 else
841 printf("%-*.*s ", width, width, line);
842 }
843
844 /*
845 * Construct an Internet address representation.
846 * If the nflag has been supplied, give
847 * numeric value, otherwise try for symbolic name.
848 */
849 char *
850 inetname(struct in_addr *inp)
851 {
852 register char *cp;
853 static char line[MAXHOSTNAMELEN];
854 struct hostent *hp;
855 struct netent *np;
856
857 cp = 0;
858 if (!nflag && inp->s_addr != INADDR_ANY) {
859 int net = inet_netof(*inp);
860 int lna = inet_lnaof(*inp);
861
862 if (lna == INADDR_ANY) {
863 np = getnetbyaddr(net, AF_INET);
864 if (np)
865 cp = np->n_name;
866 }
867 if (cp == 0) {
868 hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
869 if (hp) {
870 cp = hp->h_name;
871 //### trimdomain(cp, strlen(cp));
872 }
873 }
874 }
875 if (inp->s_addr == INADDR_ANY)
876 strcpy(line, "*");
877 else if (cp) {
878 strncpy(line, cp, sizeof(line) - 1);
879 line[sizeof(line) - 1] = '\0';
880 } else {
881 inp->s_addr = ntohl(inp->s_addr);
882 #define C(x) ((u_int)((x) & 0xff))
883 sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24),
884 C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
885 }
886 return (line);
887 }