xref: /freebsd/usr.bin/netstat/inet.c (revision 6e8394b8baa7d5d9153ab90de6824bcd19b3b4e1)
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.30 1998/07/06 21:01:23 bde 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 #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 {
219 			printf("Some %s sockets may have been created or deleted",
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 }
617