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