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