inet.c revision 17796
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
35static char sccsid[] = "@(#)inet.c	8.5 (Berkeley) 5/24/95";
36#endif /* not lint */
37
38#include <sys/param.h>
39#include <sys/queue.h>
40#include <sys/socket.h>
41#include <sys/socketvar.h>
42#include <sys/mbuf.h>
43#include <sys/protosw.h>
44
45#include <net/route.h>
46#include <netinet/in.h>
47#include <netinet/in_systm.h>
48#include <netinet/ip.h>
49#include <netinet/in_pcb.h>
50#include <netinet/ip_icmp.h>
51#include <netinet/icmp_var.h>
52#include <netinet/igmp_var.h>
53#include <netinet/ip_var.h>
54#include <netinet/tcp.h>
55#include <netinet/tcpip.h>
56#include <netinet/tcp_seq.h>
57#define TCPSTATES
58#include <netinet/tcp_fsm.h>
59#include <netinet/tcp_timer.h>
60#include <netinet/tcp_var.h>
61#include <netinet/tcp_debug.h>
62#include <netinet/udp.h>
63#include <netinet/udp_var.h>
64
65#include <arpa/inet.h>
66#include <netdb.h>
67#include <stdio.h>
68#include <string.h>
69#include <unistd.h>
70#include "netstat.h"
71
72struct	inpcb inpcb;
73struct	tcpcb tcpcb;
74struct	socket sockb;
75
76char	*inetname __P((struct in_addr *));
77void	inetprint __P((struct in_addr *, int, char *, int));
78
79/*
80 * Print a summary of connections related to an Internet
81 * protocol.  For TCP, also give state of connection.
82 * Listening processes (aflag) are suppressed unless the
83 * -a (all) flag is specified.
84 */
85void
86protopr(off, name)
87	u_long off;
88	char *name;
89{
90	struct inpcbhead head;
91	register struct inpcb *prev, *next;
92	int istcp;
93	static int first = 1;
94
95	if (off == 0)
96		return;
97
98	istcp = strcmp(name, "tcp") == 0;
99	kread(off, (char *)&head, sizeof (struct inpcbhead));
100	prev = (struct inpcb *)off;
101
102	for (next = head.lh_first; next != NULL; next = inpcb.inp_list.le_next) {
103		if (kread((u_long)next, (char *)&inpcb, sizeof (inpcb))) {
104			printf("???\n");
105			break;
106		}
107		if (!aflag &&
108		  inet_lnaof(inpcb.inp_laddr) == INADDR_ANY) {
109			prev = next;
110			continue;
111		}
112		if (kread((u_long)inpcb.inp_socket, (char *)&sockb, sizeof (sockb))) {
113			printf("???\n");
114			break;
115		};
116		if (istcp) {
117			if (kread((u_long)inpcb.inp_ppcb,
118			    (char *)&tcpcb, sizeof (tcpcb))) {
119				printf("???\n");
120				break;
121			};
122		}
123		if (first) {
124			printf("Active Internet connections");
125			if (aflag)
126				printf(" (including servers)");
127			putchar('\n');
128			if (Aflag)
129				printf("%-8.8s ", "PCB");
130			printf(Aflag ?
131				"%-5.5s %-6.6s %-6.6s  %-18.18s %-18.18s %s\n" :
132				"%-5.5s %-6.6s %-6.6s  %-22.22s %-22.22s %s\n",
133				"Proto", "Recv-Q", "Send-Q",
134				"Local Address", "Foreign Address", "(state)");
135			first = 0;
136		}
137		if (Aflag)
138			if (istcp)
139				printf("%8x ", (int)inpcb.inp_ppcb);
140			else
141				printf("%8x ", (int)next);
142		printf("%-5.5s %6ld %6ld ", name, sockb.so_rcv.sb_cc,
143			sockb.so_snd.sb_cc);
144		if (nflag) {
145			inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport,
146			    name, 1);
147			inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport,
148			    name, 1);
149		} else if (inpcb.inp_flags & INP_ANONPORT) {
150			inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport,
151			    name, 1);
152			inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport,
153			    name, 0);
154		} else {
155			inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport,
156			    name, 0);
157			inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport,
158			    name, inpcb.inp_lport != inpcb.inp_fport);
159		}
160		if (istcp) {
161			if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
162				printf(" %d", tcpcb.t_state);
163                      else {
164				printf(" %s", tcpstates[tcpcb.t_state]);
165#if defined(TF_NEEDSYN) && defined(TF_NEEDFIN)
166                              /* Show T/TCP `hidden state' */
167                              if (tcpcb.t_flags & (TF_NEEDSYN|TF_NEEDFIN))
168                                      putchar('*');
169#endif /* defined(TF_NEEDSYN) && defined(TF_NEEDFIN) */
170                      }
171		}
172		putchar('\n');
173		prev = next;
174	}
175}
176
177/*
178 * Dump TCP statistics structure.
179 */
180void
181tcp_stats(off, name)
182	u_long off;
183	char *name;
184{
185	struct tcpstat tcpstat;
186
187	if (off == 0)
188		return;
189	printf ("%s:\n", name);
190	kread(off, (char *)&tcpstat, sizeof (tcpstat));
191
192#define	p(f, m) if (tcpstat.f || sflag <= 1) \
193    printf(m, tcpstat.f, plural(tcpstat.f))
194#define	p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
195    printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2, plural(tcpstat.f2))
196#define	p3(f, m) if (tcpstat.f || sflag <= 1) \
197    printf(m, tcpstat.f, plurales(tcpstat.f))
198
199	p(tcps_sndtotal, "\t%ld packet%s sent\n");
200	p2(tcps_sndpack,tcps_sndbyte,
201		"\t\t%ld data packet%s (%ld byte%s)\n");
202	p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
203		"\t\t%ld data packet%s (%ld byte%s) retransmitted\n");
204	p(tcps_mturesent, "\t\t%ld resend%s initiated by MTU discovery\n");
205	p2(tcps_sndacks, tcps_delack,
206		"\t\t%ld ack-only packet%s (%ld delayed)\n");
207	p(tcps_sndurg, "\t\t%ld URG only packet%s\n");
208	p(tcps_sndprobe, "\t\t%ld window probe packet%s\n");
209	p(tcps_sndwinup, "\t\t%ld window update packet%s\n");
210	p(tcps_sndctrl, "\t\t%ld control packet%s\n");
211	p(tcps_rcvtotal, "\t%ld packet%s received\n");
212	p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%ld ack%s (for %ld byte%s)\n");
213	p(tcps_rcvdupack, "\t\t%ld duplicate ack%s\n");
214	p(tcps_rcvacktoomuch, "\t\t%ld ack%s for unsent data\n");
215	p2(tcps_rcvpack, tcps_rcvbyte,
216		"\t\t%ld packet%s (%ld byte%s) received in-sequence\n");
217	p2(tcps_rcvduppack, tcps_rcvdupbyte,
218		"\t\t%ld completely duplicate packet%s (%ld byte%s)\n");
219	p(tcps_pawsdrop, "\t\t%ld old duplicate packet%s\n");
220	p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
221		"\t\t%ld packet%s with some dup. data (%ld byte%s duped)\n");
222	p2(tcps_rcvoopack, tcps_rcvoobyte,
223		"\t\t%ld out-of-order packet%s (%ld byte%s)\n");
224	p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
225		"\t\t%ld packet%s (%ld byte%s) of data after window\n");
226	p(tcps_rcvwinprobe, "\t\t%ld window probe%s\n");
227	p(tcps_rcvwinupd, "\t\t%ld window update packet%s\n");
228	p(tcps_rcvafterclose, "\t\t%ld packet%s received after close\n");
229	p(tcps_rcvbadsum, "\t\t%ld discarded for bad checksum%s\n");
230	p(tcps_rcvbadoff, "\t\t%ld discarded for bad header offset field%s\n");
231	p(tcps_rcvshort, "\t\t%ld discarded because packet too short\n");
232	p(tcps_connattempt, "\t%ld connection request%s\n");
233	p(tcps_accepts, "\t%ld connection accept%s\n");
234	p(tcps_badsyn, "\t%ld bad connection attempt%s\n");
235	p(tcps_listendrop, "\t%ld listen queue overflow%s\n");
236	p(tcps_connects, "\t%ld connection%s established (including accepts)\n");
237	p2(tcps_closed, tcps_drops,
238		"\t%ld connection%s closed (including %ld drop%s)\n");
239	p(tcps_cachedrtt, "\t\t%ld connection%s updated cached RTT on close\n");
240	p(tcps_cachedrttvar,
241	  "\t\t%ld connection%s updated cached RTT variance on close\n");
242	p(tcps_cachedssthresh,
243	  "\t\t%ld connection%s updated cached ssthresh on close\n");
244	p(tcps_conndrops, "\t%ld embryonic connection%s dropped\n");
245	p2(tcps_rttupdated, tcps_segstimed,
246		"\t%ld segment%s updated rtt (of %ld attempt%s)\n");
247	p(tcps_rexmttimeo, "\t%ld retransmit timeout%s\n");
248	p(tcps_timeoutdrop, "\t\t%ld connection%s dropped by rexmit timeout\n");
249	p(tcps_persisttimeo, "\t%ld persist timeout%s\n");
250	p(tcps_persistdrop, "\t\t%ld connection%s dropped by persist timeout\n");
251	p(tcps_keeptimeo, "\t%ld keepalive timeout%s\n");
252	p(tcps_keepprobe, "\t\t%ld keepalive probe%s sent\n");
253	p(tcps_keepdrops, "\t\t%ld connection%s dropped by keepalive\n");
254	p(tcps_predack, "\t%ld correct ACK header prediction%s\n");
255	p(tcps_preddat, "\t%ld correct data packet header prediction%s\n");
256#undef p
257#undef p2
258#undef p3
259}
260
261/*
262 * Dump UDP statistics structure.
263 */
264void
265udp_stats(off, name)
266	u_long off;
267	char *name;
268{
269	struct udpstat udpstat;
270	u_long delivered;
271
272	if (off == 0)
273		return;
274	kread(off, (char *)&udpstat, sizeof (udpstat));
275	printf("%s:\n", name);
276#define	p(f, m) if (udpstat.f || sflag <= 1) \
277    printf(m, udpstat.f, plural(udpstat.f))
278	p(udps_ipackets, "\t%lu datagram%s received\n");
279	p(udps_hdrops, "\t%lu with incomplete header\n");
280	p(udps_badlen, "\t%lu with bad data length field\n");
281	p(udps_badsum, "\t%lu with bad checksum\n");
282	p(udps_noport, "\t%lu dropped due to no socket\n");
283	p(udps_noportbcast, "\t%lu broadcast/multicast datagram%s dropped due to no socket\n");
284	p(udps_fullsock, "\t%lu dropped due to full socket buffers\n");
285	p(udpps_pcbhashmiss, "\t%lu not for hashed pcb\n");
286	delivered = udpstat.udps_ipackets -
287		    udpstat.udps_hdrops -
288		    udpstat.udps_badlen -
289		    udpstat.udps_badsum -
290		    udpstat.udps_noport -
291		    udpstat.udps_noportbcast -
292		    udpstat.udps_fullsock;
293	if (delivered || sflag <= 1)
294		printf("\t%lu delivered\n", delivered);
295	p(udps_opackets, "\t%lu datagram%s output\n");
296#undef p
297}
298
299/*
300 * Dump IP statistics structure.
301 */
302void
303ip_stats(off, name)
304	u_long off;
305	char *name;
306{
307	struct ipstat ipstat;
308
309	if (off == 0)
310		return;
311	kread(off, (char *)&ipstat, sizeof (ipstat));
312	printf("%s:\n", name);
313
314#define	p(f, m) if (ipstat.f || sflag <= 1) \
315    printf(m, ipstat.f, plural(ipstat.f))
316
317	p(ips_total, "\t%lu total packet%s received\n");
318	p(ips_badsum, "\t%lu bad header checksum%s\n");
319	p(ips_toosmall, "\t%lu with size smaller than minimum\n");
320	p(ips_tooshort, "\t%lu with data size < data length\n");
321	p(ips_badhlen, "\t%lu with header length < data size\n");
322	p(ips_badlen, "\t%lu with data length < header length\n");
323	p(ips_badoptions, "\t%lu with bad options\n");
324	p(ips_badvers, "\t%lu with incorrect version number\n");
325	p(ips_fragments, "\t%lu fragment%s received\n");
326	p(ips_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
327	p(ips_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
328	p(ips_reassembled, "\t%lu packet%s reassembled ok\n");
329	p(ips_delivered, "\t%lu packet%s for this host\n");
330	p(ips_noproto, "\t%lu packet%s for unknown/unsupported protocol\n");
331	p(ips_forward, "\t%lu packet%s forwarded\n");
332	p(ips_cantforward, "\t%lu packet%s not forwardable\n");
333	p(ips_redirectsent, "\t%lu redirect%s sent\n");
334	p(ips_localout, "\t%lu packet%s sent from this host\n");
335	p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n");
336	p(ips_odropped, "\t%lu output packet%s dropped due to no bufs, etc.\n");
337	p(ips_noroute, "\t%lu output packet%s discarded due to no route\n");
338	p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
339	p(ips_ofragments, "\t%lu fragment%s created\n");
340	p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
341#undef p
342}
343
344static	char *icmpnames[] = {
345	"echo reply",
346	"#1",
347	"#2",
348	"destination unreachable",
349	"source quench",
350	"routing redirect",
351	"#6",
352	"#7",
353	"echo",
354	"router advertisement",
355	"router solicitation",
356	"time exceeded",
357	"parameter problem",
358	"time stamp",
359	"time stamp reply",
360	"information request",
361	"information request reply",
362	"address mask request",
363	"address mask reply",
364};
365
366/*
367 * Dump ICMP statistics.
368 */
369void
370icmp_stats(off, name)
371	u_long off;
372	char *name;
373{
374	struct icmpstat icmpstat;
375	register int i, first;
376
377	if (off == 0)
378		return;
379	kread(off, (char *)&icmpstat, sizeof (icmpstat));
380	printf("%s:\n", name);
381
382#define	p(f, m) if (icmpstat.f || sflag <= 1) \
383    printf(m, icmpstat.f, plural(icmpstat.f))
384
385	p(icps_error, "\t%lu call%s to icmp_error\n");
386	p(icps_oldicmp,
387	    "\t%lu error%s not generated 'cuz old message was icmp\n");
388	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
389		if (icmpstat.icps_outhist[i] != 0) {
390			if (first) {
391				printf("\tOutput histogram:\n");
392				first = 0;
393			}
394			printf("\t\t%s: %lu\n", icmpnames[i],
395				icmpstat.icps_outhist[i]);
396		}
397	p(icps_badcode, "\t%lu message%s with bad code fields\n");
398	p(icps_tooshort, "\t%lu message%s < minimum length\n");
399	p(icps_checksum, "\t%lu bad checksum%s\n");
400	p(icps_badlen, "\t%lu message%s with bad length\n");
401	for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
402		if (icmpstat.icps_inhist[i] != 0) {
403			if (first) {
404				printf("\tInput histogram:\n");
405				first = 0;
406			}
407			printf("\t\t%s: %lu\n", icmpnames[i],
408				icmpstat.icps_inhist[i]);
409		}
410	p(icps_reflect, "\t%lu message response%s generated\n");
411#undef p
412}
413
414/*
415 * Dump IGMP statistics structure.
416 */
417void
418igmp_stats(off, name)
419	u_long off;
420	char *name;
421{
422	struct igmpstat igmpstat;
423
424	if (off == 0)
425		return;
426	kread(off, (char *)&igmpstat, sizeof (igmpstat));
427	printf("%s:\n", name);
428
429#define	p(f, m) if (igmpstat.f || sflag <= 1) \
430    printf(m, igmpstat.f, plural(igmpstat.f))
431#define	py(f, m) if (igmpstat.f || sflag <= 1) \
432    printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
433	p(igps_rcv_total, "\t%u message%s received\n");
434        p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n");
435        p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n");
436        py(igps_rcv_queries, "\t%u membership quer%s received\n");
437        py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n");
438        p(igps_rcv_reports, "\t%u membership report%s received\n");
439        p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n");
440        p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n");
441        p(igps_snd_reports, "\t%u membership report%s sent\n");
442#undef p
443#undef py
444}
445
446/*
447 * Pretty print an Internet address (net address + port).
448 */
449void
450inetprint(in, port, proto,numeric)
451	register struct in_addr *in;
452	int port;
453	char *proto;
454	int numeric;
455{
456	struct servent *sp = 0;
457	char line[80], *cp;
458	int width;
459
460	sprintf(line, "%.*s.", (Aflag && !numeric) ? 12 : 16, inetname(in));
461	cp = index(line, '\0');
462	if (!numeric && port)
463		sp = getservbyport((int)port, proto);
464	if (sp || port == 0)
465		sprintf(cp, "%.15s", sp ? sp->s_name : "*");
466	else
467		sprintf(cp, "%d", ntohs((u_short)port));
468	width = Aflag ? 18 : 22;
469	printf(" %-*.*s", width, width, line);
470}
471
472/*
473 * Construct an Internet address representation.
474 * If the nflag has been supplied, give
475 * numeric value, otherwise try for symbolic name.
476 */
477char *
478inetname(inp)
479	struct in_addr *inp;
480{
481	register char *cp;
482	static char line[50];
483	struct hostent *hp;
484	struct netent *np;
485
486	cp = 0;
487	if (!nflag && inp->s_addr != INADDR_ANY) {
488		int net = inet_netof(*inp);
489		int lna = inet_lnaof(*inp);
490
491		if (lna == INADDR_ANY) {
492			np = getnetbyaddr(net, AF_INET);
493			if (np)
494				cp = np->n_name;
495		}
496		if (cp == 0) {
497			hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
498			if (hp) {
499				cp = hp->h_name;
500				trimdomain(cp);
501			}
502		}
503	}
504	if (inp->s_addr == INADDR_ANY)
505		strcpy(line, "*");
506	else if (cp)
507		strcpy(line, cp);
508	else {
509		inp->s_addr = ntohl(inp->s_addr);
510#define C(x)	((x) & 0xff)
511		sprintf(line, "%lu.%lu.%lu.%lu", C(inp->s_addr >> 24),
512		    C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
513	}
514	return (line);
515}
516