xref: /openbsd-src/usr.bin/netstat/inet.c (revision 62a742911104f98b9185b2c6b6007d9b1c36396c)
1 /*	$OpenBSD: inet.c,v 1.33 1999/04/11 19:41:40 niklas Exp $	*/
2 /*	$NetBSD: inet.c,v 1.14 1995/10/03 21:42:37 thorpej Exp $	*/
3 
4 /*
5  * Copyright (c) 1983, 1988, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "from: @(#)inet.c	8.4 (Berkeley) 4/20/94";
40 #else
41 static char *rcsid = "$OpenBSD: inet.c,v 1.33 1999/04/11 19:41:40 niklas Exp $";
42 #endif
43 #endif /* not lint */
44 
45 #include <sys/param.h>
46 #include <sys/queue.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
49 #include <sys/mbuf.h>
50 #include <sys/protosw.h>
51 
52 #include <net/route.h>
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/ip.h>
56 #include <netinet/in_pcb.h>
57 #include <netinet/ip_icmp.h>
58 #include <netinet/icmp_var.h>
59 #include <netinet/igmp_var.h>
60 #include <netinet/ip_var.h>
61 #include <netinet/tcp.h>
62 #include <netinet/tcpip.h>
63 #include <netinet/tcp_seq.h>
64 #define TCPSTATES
65 #include <netinet/tcp_fsm.h>
66 #include <netinet/tcp_timer.h>
67 #include <netinet/tcp_var.h>
68 #include <netinet/tcp_debug.h>
69 #include <netinet/udp.h>
70 #include <netinet/udp_var.h>
71 #include <netinet/ip_ipsp.h>
72 #include <netinet/ip_ah.h>
73 #include <netinet/ip_esp.h>
74 #include <netinet/ip_ip4.h>
75 
76 #include <arpa/inet.h>
77 #include <limits.h>
78 #include <netdb.h>
79 #include <stdio.h>
80 #include <string.h>
81 #include <unistd.h>
82 #include <stdlib.h>
83 #include "netstat.h"
84 
85 #include <rpc/rpc.h>
86 #include <rpc/pmap_prot.h>
87 #include <rpc/pmap_clnt.h>
88 
89 struct	inpcb inpcb;
90 struct	tcpcb tcpcb;
91 struct	socket sockb;
92 
93 char	*inetname __P((struct in_addr *));
94 void	inetprint __P((struct in_addr *, int, char *, int));
95 
96 /*
97  * Print a summary of connections related to an Internet
98  * protocol.  For TCP, also give state of connection.
99  * Listening processes (aflag) are suppressed unless the
100  * -a (all) flag is specified.
101  */
102 void
103 protopr(off, name)
104 	u_long off;
105 	char *name;
106 {
107 	struct inpcbtable table;
108 	register struct inpcb *head, *next, *prev;
109 	struct inpcb inpcb;
110 	int istcp;
111 	static int first = 1;
112 
113 	if (off == 0)
114 		return;
115 	istcp = strcmp(name, "tcp") == 0;
116 	kread(off, (char *)&table, sizeof table);
117 	prev = head =
118 	    (struct inpcb *)&((struct inpcbtable *)off)->inpt_queue.cqh_first;
119 	next = table.inpt_queue.cqh_first;
120 
121 	while (next != head) {
122 		kread((u_long)next, (char *)&inpcb, sizeof inpcb);
123 		if (inpcb.inp_queue.cqe_prev != prev) {
124 			printf("???\n");
125 			break;
126 		}
127 		prev = next;
128 		next = inpcb.inp_queue.cqe_next;
129 
130 		if (!aflag &&
131 		    inet_lnaof(inpcb.inp_laddr) == INADDR_ANY)
132 			continue;
133 		kread((u_long)inpcb.inp_socket, (char *)&sockb, sizeof (sockb));
134 		if (istcp) {
135 			kread((u_long)inpcb.inp_ppcb,
136 			    (char *)&tcpcb, sizeof (tcpcb));
137 		}
138 		if (first) {
139 			printf("Active Internet connections");
140 			if (aflag)
141 				printf(" (including servers)");
142 			putchar('\n');
143 			if (Aflag)
144 				printf("%-*.*s %-5.5s %-6.6s %-6.6s  %-18.18s %-18.18s %s\n",
145 				    PLEN, PLEN, "PCB", "Proto", "Recv-Q",
146 				    "Send-Q", "Local Address",
147 				    "Foreign Address", "(state)");
148 			else
149 				printf("%-5.5s %-6.6s %-6.6s  %-22.22s %-22.22s %s\n",
150 				    "Proto", "Recv-Q", "Send-Q",
151 				    "Local Address", "Foreign Address",
152 				    "(state)");
153 			first = 0;
154 		}
155 		if (Aflag)
156 			if (istcp)
157 				printf("%*p ", PLEN, inpcb.inp_ppcb);
158 			else
159 				printf("%*p ", PLEN, prev);
160 		printf("%-5.5s %6ld %6ld ", name, sockb.so_rcv.sb_cc,
161 			sockb.so_snd.sb_cc);
162 		inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport, name, 1);
163 		inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport, name, 0);
164 		if (istcp) {
165 			if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
166 				printf(" %d", tcpcb.t_state);
167 			else
168 				printf(" %s", tcpstates[tcpcb.t_state]);
169 		}
170 		putchar('\n');
171 	}
172 }
173 
174 /*
175  * Dump TCP statistics structure.
176  */
177 void
178 tcp_stats(off, name)
179 	u_long off;
180 	char *name;
181 {
182 	struct tcpstat tcpstat;
183 
184 	if (off == 0)
185 		return;
186 	printf ("%s:\n", name);
187 	kread(off, (char *)&tcpstat, sizeof (tcpstat));
188 
189 #define	p(f, m) if (tcpstat.f || sflag <= 1) \
190     printf(m, tcpstat.f, plural(tcpstat.f))
191 #define	p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
192     printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2, plural(tcpstat.f2))
193 #define	p3(f, m) if (tcpstat.f || sflag <= 1) \
194     printf(m, tcpstat.f, plurales(tcpstat.f))
195 
196 	p(tcps_sndtotal, "\t%ld packet%s sent\n");
197 	p2(tcps_sndpack,tcps_sndbyte,
198 		"\t\t%ld data packet%s (%qd byte%s)\n");
199 	p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
200 		"\t\t%ld data packet%s (%qd byte%s) retransmitted\n");
201 	p(tcps_sndrexmitfast, "\t\t%qd fast retransmitted packet%s\n");
202 	p2(tcps_sndacks, tcps_delack,
203 		"\t\t%ld ack-only packet%s (%ld delayed)\n");
204 	p(tcps_sndurg, "\t\t%ld URG only packet%s\n");
205 	p(tcps_sndprobe, "\t\t%ld window probe packet%s\n");
206 	p(tcps_sndwinup, "\t\t%ld window update packet%s\n");
207 	p(tcps_sndctrl, "\t\t%ld control packet%s\n");
208 	p(tcps_rcvtotal, "\t%ld packet%s received\n");
209 	p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%ld ack%s (for %qd byte%s)\n");
210 	p(tcps_rcvdupack, "\t\t%ld duplicate ack%s\n");
211 	p(tcps_rcvacktoomuch, "\t\t%ld ack%s for unsent data\n");
212 	p2(tcps_rcvpack, tcps_rcvbyte,
213 		"\t\t%ld packet%s (%qd byte%s) received in-sequence\n");
214 	p2(tcps_rcvduppack, tcps_rcvdupbyte,
215 		"\t\t%ld completely duplicate packet%s (%qd byte%s)\n");
216 	p(tcps_pawsdrop, "\t\t%ld old duplicate packet%s\n");
217 	p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
218 		"\t\t%ld packet%s with some dup. data (%qd byte%s duped)\n");
219 	p2(tcps_rcvoopack, tcps_rcvoobyte,
220 		"\t\t%ld out-of-order packet%s (%qd byte%s)\n");
221 	p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
222 		"\t\t%ld packet%s (%qd byte%s) of data after window\n");
223 	p(tcps_rcvwinprobe, "\t\t%ld window probe%s\n");
224 	p(tcps_rcvwinupd, "\t\t%ld window update packet%s\n");
225 	p(tcps_rcvafterclose, "\t\t%ld packet%s received after close\n");
226 	p(tcps_rcvbadsum, "\t\t%ld discarded for bad checksum%s\n");
227 	p(tcps_rcvbadoff, "\t\t%ld discarded for bad header offset field%s\n");
228 	p(tcps_rcvshort, "\t\t%ld discarded because packet too short\n");
229 	p(tcps_rcvnosec, "\t\t%ld discarded for missing IPSec protection\n");
230 	p(tcps_connattempt, "\t%ld connection request%s\n");
231 	p(tcps_accepts, "\t%ld connection accept%s\n");
232 	p(tcps_connects, "\t%ld connection%s established (including accepts)\n");
233 	p2(tcps_closed, tcps_drops,
234 		"\t%ld connection%s closed (including %ld drop%s)\n");
235 	p(tcps_conndrops, "\t%ld embryonic connection%s dropped\n");
236 	p2(tcps_rttupdated, tcps_segstimed,
237 		"\t%ld segment%s updated rtt (of %ld attempt%s)\n");
238 	p(tcps_rexmttimeo, "\t%ld retransmit timeout%s\n");
239 	p(tcps_timeoutdrop, "\t\t%ld connection%s dropped by rexmit timeout\n");
240 	p(tcps_persisttimeo, "\t%ld persist timeout%s\n");
241 	p(tcps_keeptimeo, "\t%ld keepalive timeout%s\n");
242 	p(tcps_keepprobe, "\t\t%ld keepalive probe%s sent\n");
243 	p(tcps_keepdrops, "\t\t%ld connection%s dropped by keepalive\n");
244 	p(tcps_predack, "\t%ld correct ACK header prediction%s\n");
245 	p(tcps_preddat, "\t%ld correct data packet header prediction%s\n");
246 	p3(tcps_pcbhashmiss, "\t%ld PCB cache miss%s\n");
247 	p(tcps_badsyn, "\t%ld SYN packet%s received with same src/dst address/port\n");
248 #undef p
249 #undef p2
250 #undef p3
251 }
252 
253 /*
254  * Dump UDP statistics structure.
255  */
256 void
257 udp_stats(off, name)
258 	u_long off;
259 	char *name;
260 {
261 	struct udpstat udpstat;
262 	u_long delivered;
263 
264 	if (off == 0)
265 		return;
266 	kread(off, (char *)&udpstat, sizeof (udpstat));
267 	printf("%s:\n", name);
268 #define	p(f, m) if (udpstat.f || sflag <= 1) \
269     printf(m, udpstat.f, plural(udpstat.f))
270 	p(udps_ipackets, "\t%lu datagram%s received\n");
271 	p(udps_hdrops, "\t%lu with incomplete header\n");
272 	p(udps_badlen, "\t%lu with bad data length field\n");
273 	p(udps_badsum, "\t%lu with bad checksum\n");
274 	p(udps_nosum, "\t%lu with no checksum\n");
275 	p(udps_noport, "\t%lu dropped due to no socket\n");
276 	p(udps_noportbcast, "\t%lu broadcast/multicast datagram%s dropped due to no socket\n");
277 	p(udps_nosec, "\t%lu dropped due to missing IPSec protection\n");
278 	p(udps_fullsock, "\t%lu dropped due to full socket buffers\n");
279 	delivered = udpstat.udps_ipackets -
280 		    udpstat.udps_hdrops -
281 		    udpstat.udps_badlen -
282 		    udpstat.udps_badsum -
283 		    udpstat.udps_noport -
284 		    udpstat.udps_noportbcast -
285 		    udpstat.udps_fullsock;
286 	if (delivered || sflag <= 1)
287 		printf("\t%lu delivered\n", delivered);
288 	p(udps_opackets, "\t%lu datagram%s output\n");
289 	p(udps_pcbhashmiss, "\t%lu missed PCB cache\n");
290 #undef p
291 }
292 
293 /*
294  * Dump IP statistics structure.
295  */
296 void
297 ip_stats(off, name)
298 	u_long off;
299 	char *name;
300 {
301 	struct ipstat ipstat;
302 
303 	if (off == 0)
304 		return;
305 	kread(off, (char *)&ipstat, sizeof (ipstat));
306 	printf("%s:\n", name);
307 
308 #define	p(f, m) if (ipstat.f || sflag <= 1) \
309     printf(m, ipstat.f, plural(ipstat.f))
310 
311 	p(ips_total, "\t%lu total packet%s received\n");
312 	p(ips_badsum, "\t%lu bad header checksum%s\n");
313 	p(ips_toosmall, "\t%lu with size smaller than minimum\n");
314 	p(ips_tooshort, "\t%lu with data size < data length\n");
315 	p(ips_badhlen, "\t%lu with header length < data size\n");
316 	p(ips_badlen, "\t%lu with data length < header length\n");
317 	p(ips_badoptions, "\t%lu with bad options\n");
318 	p(ips_badvers, "\t%lu with incorrect version number\n");
319 	p(ips_fragments, "\t%lu fragment%s received\n");
320 	p(ips_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
321 	p(ips_badfrags, "\t%lu malformed fragment%s dropped\n");
322 	p(ips_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
323 	p(ips_reassembled, "\t%lu packet%s reassembled ok\n");
324 	p(ips_delivered, "\t%lu packet%s for this host\n");
325 	p(ips_noproto, "\t%lu packet%s for unknown/unsupported protocol\n");
326 	p(ips_forward, "\t%lu packet%s forwarded\n");
327 	p(ips_cantforward, "\t%lu packet%s not forwardable\n");
328 	p(ips_redirectsent, "\t%lu redirect%s sent\n");
329 	p(ips_localout, "\t%lu packet%s sent from this host\n");
330 	p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n");
331 	p(ips_odropped, "\t%lu output packet%s dropped due to no bufs, etc.\n");
332 	p(ips_noroute, "\t%lu output packet%s discarded due to no route\n");
333 	p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
334 	p(ips_ofragments, "\t%lu fragment%s created\n");
335 	p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
336 	p(ips_rcvmemdrop, "\t%lu fragment floods\n");
337 #undef p
338 }
339 
340 static	char *icmpnames[] = {
341 	"echo reply",
342 	"#1",
343 	"#2",
344 	"destination unreachable",
345 	"source quench",
346 	"routing redirect",
347 	"#6",
348 	"#7",
349 	"echo",
350 	"router advertisement",
351 	"router solicitation",
352 	"time exceeded",
353 	"parameter problem",
354 	"time stamp",
355 	"time stamp reply",
356 	"information request",
357 	"information request reply",
358 	"address mask request",
359 	"address mask reply",
360 };
361 
362 /*
363  * Dump ICMP statistics.
364  */
365 void
366 icmp_stats(off, name)
367 	u_long off;
368 	char *name;
369 {
370 	struct icmpstat icmpstat;
371 	register int i, first;
372 
373 	if (off == 0)
374 		return;
375 	kread(off, (char *)&icmpstat, sizeof (icmpstat));
376 	printf("%s:\n", name);
377 
378 #define	p(f, m) if (icmpstat.f || sflag <= 1) \
379     printf(m, icmpstat.f, plural(icmpstat.f))
380 
381 	p(icps_error, "\t%lu call%s to icmp_error\n");
382 	p(icps_oldicmp,
383 	    "\t%lu error%s not generated 'cuz old message was icmp\n");
384 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
385 		if (icmpstat.icps_outhist[i] != 0) {
386 			if (first) {
387 				printf("\tOutput histogram:\n");
388 				first = 0;
389 			}
390 			printf("\t\t%s: %lu\n", icmpnames[i],
391 				icmpstat.icps_outhist[i]);
392 		}
393 	p(icps_badcode, "\t%lu message%s with bad code fields\n");
394 	p(icps_tooshort, "\t%lu message%s < minimum length\n");
395 	p(icps_checksum, "\t%lu bad checksum%s\n");
396 	p(icps_badlen, "\t%lu message%s with bad length\n");
397 	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
398 		if (icmpstat.icps_inhist[i] != 0) {
399 			if (first) {
400 				printf("\tInput histogram:\n");
401 				first = 0;
402 			}
403 			printf("\t\t%s: %lu\n", icmpnames[i],
404 				icmpstat.icps_inhist[i]);
405 		}
406 	p(icps_reflect, "\t%lu message response%s generated\n");
407 #undef p
408 }
409 
410 /*
411  * Dump IGMP statistics structure.
412  */
413 void
414 igmp_stats(off, name)
415 	u_long off;
416 	char *name;
417 {
418 	struct igmpstat igmpstat;
419 
420 	if (off == 0)
421 		return;
422 	kread(off, (char *)&igmpstat, sizeof (igmpstat));
423 	printf("%s:\n", name);
424 
425 #define	p(f, m) if (igmpstat.f || sflag <= 1) \
426     printf(m, igmpstat.f, plural(igmpstat.f))
427 #define	py(f, m) if (igmpstat.f || sflag <= 1) \
428     printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
429 	p(igps_rcv_total, "\t%lu message%s received\n");
430         p(igps_rcv_tooshort, "\t%lu message%s received with too few bytes\n");
431         p(igps_rcv_badsum, "\t%lu message%s received with bad checksum\n");
432         py(igps_rcv_queries, "\t%lu membership quer%s received\n");
433         py(igps_rcv_badqueries, "\t%lu membership quer%s received with invalid field(s)\n");
434         p(igps_rcv_reports, "\t%lu membership report%s received\n");
435         p(igps_rcv_badreports, "\t%lu membership report%s received with invalid field(s)\n");
436         p(igps_rcv_ourreports, "\t%lu membership report%s received for groups to which we belong\n");
437         p(igps_snd_reports, "\t%lu membership report%s sent\n");
438 #undef p
439 #undef py
440 }
441 
442 struct rpcnams {
443 	struct rpcnams *next;
444 	in_port_t port;
445 	int	  proto;
446 	char	*rpcname;
447 };
448 
449 char *
450 getrpcportnam(port, proto)
451 	in_port_t port;
452 	int proto;
453 {
454 	struct sockaddr_in server_addr;
455 	register struct hostent *hp;
456 	static struct pmaplist *head;
457 	int socket = RPC_ANYSOCK;
458 	struct timeval minutetimeout;
459 	register CLIENT *client;
460 	struct rpcent *rpc;
461 	static int first;
462 	static struct rpcnams *rpcn;
463 	struct rpcnams *n;
464 	char num[20];
465 
466 	if (first == 0) {
467 		first = 1;
468 		memset((char *)&server_addr, 0, sizeof server_addr);
469 		server_addr.sin_family = AF_INET;
470 		if ((hp = gethostbyname("localhost")) != NULL)
471 			memmove((caddr_t)&server_addr.sin_addr, hp->h_addr,
472 			    hp->h_length);
473 		else
474 			(void) inet_aton("0.0.0.0", &server_addr.sin_addr);
475 
476 		minutetimeout.tv_sec = 60;
477 		minutetimeout.tv_usec = 0;
478 		server_addr.sin_port = htons(PMAPPORT);
479 		if ((client = clnttcp_create(&server_addr, PMAPPROG,
480 		    PMAPVERS, &socket, 50, 500)) == NULL)
481 			return (NULL);
482 		if (clnt_call(client, PMAPPROC_DUMP, xdr_void, NULL,
483 		    xdr_pmaplist, &head, minutetimeout) != RPC_SUCCESS) {
484 			clnt_destroy(client);
485 			return (NULL);
486 		}
487 		for (; head != NULL; head = head->pml_next) {
488 			n = (struct rpcnams *)malloc(sizeof(struct rpcnams));
489 			if (n == NULL)
490 				continue;
491 			n->next = rpcn;
492 			rpcn = n;
493 			n->port = head->pml_map.pm_port;
494 			n->proto = head->pml_map.pm_prot;
495 
496 			rpc = getrpcbynumber(head->pml_map.pm_prog);
497 			if (rpc)
498 				n->rpcname = strdup(rpc->r_name);
499 			else {
500 				snprintf(num, sizeof num, "%ld",
501 				    head->pml_map.pm_prog);
502 				n->rpcname = strdup(num);
503 			}
504 		}
505 		clnt_destroy(client);
506 	}
507 
508 	for (n = rpcn; n; n = n->next)
509 		if (n->port == port && n->proto == proto)
510 			return (n->rpcname);
511 	return (NULL);
512 }
513 
514 /*
515  * Pretty print an Internet address (net address + port).
516  * If the nflag was specified, use numbers instead of names.
517  */
518 void
519 inetprint(in, port, proto, local)
520 	register struct in_addr *in;
521 	in_port_t port;
522 	char *proto;
523 	int local;
524 {
525 	struct servent *sp = 0;
526 	char line[80], *cp, *nam;
527 	int proton;
528 	int width;
529 
530 	snprintf(line, sizeof line, "%.*s.", (Aflag && !nflag) ? 12 : 16,
531 	    inetname(in));
532 	cp = strchr(line, '\0');
533 	if (!nflag && port)
534 		sp = getservbyport((int)port, proto);
535 	if (sp || port == 0)
536 		snprintf(cp, line + sizeof line - cp, "%.8s",
537 		    sp ? sp->s_name : "*");
538 	else if (local && !nflag && (nam = getrpcportnam(ntohs(port),
539 	    (strcmp(proto, "tcp") == 0 ? IPPROTO_TCP : IPPROTO_UDP))))
540 		snprintf(cp, line + sizeof line - cp, "%d[%.8s]",
541 		    ntohs(port), nam);
542 	else
543 		snprintf(cp, line + sizeof line - cp, "%d", ntohs(port));
544 	width = Aflag ? 18 : 22;
545 	printf(" %-*.*s", width, width, line);
546 }
547 
548 /*
549  * Construct an Internet address representation.
550  * If the nflag has been supplied, give
551  * numeric value, otherwise try for symbolic name.
552  */
553 char *
554 inetname(inp)
555 	struct in_addr *inp;
556 {
557 	register char *cp;
558 	static char line[50];
559 	struct hostent *hp;
560 	struct netent *np;
561 	static char domain[MAXHOSTNAMELEN + 1];
562 	static int first = 1;
563 
564 	if (first && !nflag) {
565 		first = 0;
566 		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
567 		    (cp = strchr(domain, '.')))
568 			(void) strcpy(domain, cp + 1);
569 		else
570 			domain[0] = 0;
571 	}
572 	cp = 0;
573 	if (!nflag && inp->s_addr != INADDR_ANY) {
574 		int net = inet_netof(*inp);
575 		int lna = inet_lnaof(*inp);
576 
577 		if (lna == INADDR_ANY) {
578 			np = getnetbyaddr(net, AF_INET);
579 			if (np)
580 				cp = np->n_name;
581 		}
582 		if (cp == 0) {
583 			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
584 			if (hp) {
585 				if ((cp = strchr(hp->h_name, '.')) &&
586 				    !strcmp(cp + 1, domain))
587 					*cp = 0;
588 				cp = hp->h_name;
589 			}
590 		}
591 	}
592 	if (inp->s_addr == INADDR_ANY)
593 		snprintf(line, sizeof line, "*");
594 	else if (cp)
595 		snprintf(line, sizeof line, "%s", cp);
596 	else {
597 		inp->s_addr = ntohl(inp->s_addr);
598 #define C(x)	((x) & 0xff)
599 		snprintf(line, sizeof line, "%u.%u.%u.%u",
600 		    C(inp->s_addr >> 24), C(inp->s_addr >> 16),
601 		    C(inp->s_addr >> 8), C(inp->s_addr));
602 	}
603 	return (line);
604 }
605 
606 /*
607  * Dump AH statistics structure.
608  */
609 void
610 ah_stats(off, name)
611         u_long off;
612         char *name;
613 {
614         struct ahstat ahstat;
615 
616         if (off == 0)
617                 return;
618         kread(off, (char *)&ahstat, sizeof (ahstat));
619         printf("%s:\n", name);
620 
621 #define p(f, m) if (ahstat.f || sflag <= 1) \
622     printf(m, ahstat.f, plural(ahstat.f))
623 
624 	p(ahs_input, "\t%u input AH packets\n");
625 	p(ahs_output, "\t%u output AH packets\n");
626         p(ahs_hdrops, "\t%u packet%s shorter than header shows\n");
627         p(ahs_pdrops, "\t%u packet%s dropped due to policy\n");
628         p(ahs_notdb, "\t%u packet%s for which no TDB was found\n");
629         p(ahs_badkcr, "\t%u input packet%s that failed to be processed\n");
630         p(ahs_badauth, "\t%u packet%s that failed verification received\n");
631         p(ahs_noxform, "\t%u packet%s for which no XFORM was set in TDB received\n");
632         p(ahs_qfull, "\t%u packet%s were dropped due to full output queue\n");
633         p(ahs_wrap, "\t%u packet%s where counter wrapping was detected\n");
634         p(ahs_replay, "\t%u possibly replayed packet%s received\n");
635         p(ahs_badauthl, "\t%u packet%s with bad authenticator length received\n");
636 	p(ahs_invalid, "\t%u packet%s attempted to use an invalid tdb\n");
637 	p(ahs_toobig, "\t%u packet%s got larger than max IP packet size\n");
638 	p(ahs_ibytes, "\t%qu input byte%s\n");
639 	p(ahs_obytes, "\t%qu output byte%s\n");
640 
641 #undef p
642 }
643 
644 /*
645  * Dump ESP statistics structure.
646  */
647 void
648 esp_stats(off, name)
649         u_long off;
650         char *name;
651 {
652         struct espstat espstat;
653 
654 
655         if (off == 0)
656                 return;
657         kread(off, (char *)&espstat, sizeof (espstat));
658         printf("%s:\n", name);
659 
660 #define p(f, m) if (espstat.f || sflag <= 1) \
661     printf(m, espstat.f, plural(espstat.f))
662 
663 	p(esps_input, "\t%u input ESP packets\n");
664 	p(esps_output, "\t%u output ESP packets\n");
665         p(esps_hdrops, "\t%u packet%s shorter than header shows\n");
666         p(esps_pdrops, "\t%u packet%s dropped due to policy\n");
667         p(esps_notdb, "\t%u packet%s for which no TDB was found\n");
668         p(esps_badkcr, "\t%u input packet%s that failed to be processed\n");
669         p(esps_badauth, "\t%u packet%s that failed verification received\n");
670         p(esps_noxform, "\t%u packet%s for which no XFORM was set in TDB received\n");
671         p(esps_qfull, "\t%u packet%s were dropped due to full output queue\n");
672         p(esps_wrap, "\t%u packet%s where counter wrapping was detected\n");
673         p(esps_replay, "\t%u possibly replayed packet%s received\n");
674         p(esps_badilen, "\t%u packet%s with payload not a multiple of 8 received\n");
675 	p(esps_invalid, "\t%u packet%s attempted to use an invalid tdb\n");
676 	p(esps_toobig, "\t%u packet%s got larger than max IP packet size\n");
677 	p(esps_ibytes, "\t%qu input byte%s\n");
678 	p(esps_obytes, "\t%qu output byte%s\n");
679 
680 #undef p
681 }
682 
683 /*
684  * Dump ESP statistics structure.
685  */
686 void
687 ip4_stats(off, name)
688         u_long off;
689         char *name;
690 {
691         struct ip4stat ip4stat;
692 
693         if (off == 0)
694                 return;
695         kread(off, (char *)&ip4stat, sizeof (ip4stat));
696         printf("%s:\n", name);
697 
698 #define p(f, m) if (ip4stat.f || sflag <= 1) \
699     printf(m, ip4stat.f, plural(ip4stat.f))
700 
701         p(ip4s_ipackets, "\t%u total input packet%s\n");
702         p(ip4s_opackets, "\t%u total output packet%s\n");
703         p(ip4s_hdrops, "\t%u packet%s shorter than header shows\n");
704         p(ip4s_pdrops, "\t%u packet%s dropped due to policy\n");
705         p(ip4s_spoof, "\t%u packet%s with possibly spoofed local addresses\n");
706         p(ip4s_notip4, "\t%u packet%s with internal header not IPv4 received\n");
707         p(ip4s_qfull, "\t%u packet%s were dropped due to full output queue\n");
708 	p(ip4s_ibytes, "\t%qu input byte%s\n");
709 	p(ip4s_obytes, "\t%qu output byte%s\n");
710 
711 #undef p
712 }
713