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