branch for FTP release (#ifdefs for non-4.3)
[unix-history] / usr / src / usr.bin / netstat / inet.c
CommitLineData
5ff67f98
DF
1/*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
c7fc5288 7#ifndef lint
01052009 8static char sccsid[] = "@(#)inet.c 5.9 (Berkeley) %G%";
5ff67f98 9#endif not lint
c7fc5288 10
f7c99b06
MK
11#include <strings.h>
12#include <stdio.h>
13
6c5bed6c 14#include <sys/param.h>
c7fc5288
SL
15#include <sys/socket.h>
16#include <sys/socketvar.h>
17#include <sys/mbuf.h>
18#include <sys/protosw.h>
44906619 19
c7fc5288 20#include <net/route.h>
44906619
SL
21#include <netinet/in.h>
22#include <netinet/in_systm.h>
23#include <netinet/in_pcb.h>
24#include <netinet/ip.h>
25#include <netinet/ip_icmp.h>
7333c75b 26#include <netinet/icmp_var.h>
44906619
SL
27#include <netinet/ip_var.h>
28#include <netinet/tcp.h>
29#include <netinet/tcpip.h>
30#include <netinet/tcp_seq.h>
c7fc5288 31#define TCPSTATES
44906619
SL
32#include <netinet/tcp_fsm.h>
33#include <netinet/tcp_timer.h>
34#include <netinet/tcp_var.h>
35#include <netinet/tcp_debug.h>
36#include <netinet/udp.h>
37#include <netinet/udp_var.h>
38
c7fc5288
SL
39#include <netdb.h>
40
41struct inpcb inpcb;
42struct tcpcb tcpcb;
cab3a575 43struct socket sockb;
c7fc5288
SL
44extern int kmem;
45extern int Aflag;
46extern int aflag;
47extern int nflag;
f7c99b06 48extern char *plural();
c7fc5288 49
c7fc5288
SL
50char *inetname();
51
52/*
53 * Print a summary of connections related to an Internet
54 * protocol. For TCP, also give state of connection.
55 * Listening processes (aflag) are suppressed unless the
56 * -a (all) flag is specified.
57 */
58protopr(off, name)
59 off_t off;
60 char *name;
61{
62 struct inpcb cb;
63 register struct inpcb *prev, *next;
64 int istcp;
f7c99b06 65 static int first = 1;
c7fc5288 66
a960d94f 67 if (off == 0)
c7fc5288 68 return;
c7fc5288
SL
69 istcp = strcmp(name, "tcp") == 0;
70 klseek(kmem, off, 0);
f7c99b06 71 read(kmem, (char *)&cb, sizeof (struct inpcb));
c7fc5288
SL
72 inpcb = cb;
73 prev = (struct inpcb *)off;
a960d94f
MK
74 if (inpcb.inp_next == (struct inpcb *)off)
75 return;
c7fc5288 76 while (inpcb.inp_next != (struct inpcb *)off) {
c7fc5288
SL
77
78 next = inpcb.inp_next;
79 klseek(kmem, (off_t)next, 0);
f7c99b06 80 read(kmem, (char *)&inpcb, sizeof (inpcb));
c7fc5288
SL
81 if (inpcb.inp_prev != prev) {
82 printf("???\n");
83 break;
84 }
85 if (!aflag &&
f7c99b06 86 inet_lnaof(inpcb.inp_laddr) == INADDR_ANY) {
c7fc5288
SL
87 prev = next;
88 continue;
89 }
90 klseek(kmem, (off_t)inpcb.inp_socket, 0);
f7c99b06 91 read(kmem, (char *)&sockb, sizeof (sockb));
c7fc5288
SL
92 if (istcp) {
93 klseek(kmem, (off_t)inpcb.inp_ppcb, 0);
f7c99b06 94 read(kmem, (char *)&tcpcb, sizeof (tcpcb));
c7fc5288 95 }
a960d94f
MK
96 if (first) {
97 printf("Active Internet connections");
98 if (aflag)
99 printf(" (including servers)");
100 putchar('\n');
101 if (Aflag)
102 printf("%-8.8s ", "PCB");
103 printf(Aflag ?
104 "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" :
105 "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n",
106 "Proto", "Recv-Q", "Send-Q",
107 "Local Address", "Foreign Address", "(state)");
108 first = 0;
109 }
c7fc5288 110 if (Aflag)
a960d94f
MK
111 if (istcp)
112 printf("%8x ", inpcb.inp_ppcb);
113 else
114 printf("%8x ", next);
cab3a575
MK
115 printf("%-5.5s %6d %6d ", name, sockb.so_rcv.sb_cc,
116 sockb.so_snd.sb_cc);
c7fc5288
SL
117 inetprint(&inpcb.inp_laddr, inpcb.inp_lport, name);
118 inetprint(&inpcb.inp_faddr, inpcb.inp_fport, name);
119 if (istcp) {
120 if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES)
121 printf(" %d", tcpcb.t_state);
122 else
123 printf(" %s", tcpstates[tcpcb.t_state]);
124 }
125 putchar('\n');
126 prev = next;
127 }
128}
129
6df0a927
SL
130/*
131 * Dump TCP statistics structure.
132 */
133tcp_stats(off, name)
134 off_t off;
135 char *name;
136{
137 struct tcpstat tcpstat;
138
a960d94f 139 if (off == 0)
6df0a927 140 return;
49a4dfd4 141 printf ("%s:\n", name);
6df0a927
SL
142 klseek(kmem, off, 0);
143 read(kmem, (char *)&tcpstat, sizeof (tcpstat));
49a4dfd4 144
01052009
KB
145#define p(f, m) printf(m, tcpstat.f, plural(tcpstat.f))
146#define p2(f1, f2, m) printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2, plural(tcpstat.f2))
147
148 p(tcps_sndtotal, "\t%d packet%s sent\n");
149 p2(tcps_sndpack,tcps_sndbyte,
150 "\t\t%d data packet%s (%d byte%s)\n");
151 p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
152 "\t\t%d data packet%s (%d byte%s) retransmitted\n");
153 p2(tcps_sndacks, tcps_delack,
154 "\t\t%d ack-only packet%s (%d delayed)\n");
155 p(tcps_sndurg, "\t\t%d URG only packet%s\n");
156 p(tcps_sndprobe, "\t\t%d window probe packet%s\n");
157 p(tcps_sndwinup, "\t\t%d window update packet%s\n");
158 p(tcps_sndctrl, "\t\t%d control packet%s\n");
159 p(tcps_rcvtotal, "\t%d packet%s received\n");
160 p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%d ack%s (for %d byte%s)\n");
161 p(tcps_rcvdupack, "\t\t%d duplicate ack%s\n");
162 p(tcps_rcvacktoomuch, "\t\t%d ack%s for unsent data\n");
163 p2(tcps_rcvpack, tcps_rcvbyte,
164 "\t\t%d packet%s (%d byte%s) received in-sequence\n");
165 p2(tcps_rcvduppack, tcps_rcvdupbyte,
166 "\t\t%d completely duplicate packet%s (%d byte%s)\n");
167 p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
168 "\t\t%d packet%s with some dup. data (%d byte%s duped)\n");
169 p2(tcps_rcvoopack, tcps_rcvoobyte,
170 "\t\t%d out-of-order packet%s (%d byte%s)\n");
171 p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
172 "\t\t%d packet%s (%d byte%s) of data after window\n");
173 p(tcps_rcvwinprobe, "\t\t%d window probe%s\n");
174 p(tcps_rcvwinupd, "\t\t%d window update packet%s\n");
175 p(tcps_rcvafterclose, "\t\t%d packet%s received after close\n");
176 p(tcps_rcvbadsum, "\t\t%d discarded for bad checksum%s\n");
177 p(tcps_rcvbadoff, "\t\t%d discarded for bad header offset field%s\n");
178 p(tcps_rcvshort, "\t\t%d discarded because packet too short\n");
179 p(tcps_connattempt, "\t%d connection request%s\n");
180 p(tcps_accepts, "\t%d connection accept%s\n");
181 p(tcps_connects, "\t%d connection%s established (including accepts)\n");
182 p2(tcps_closed, tcps_drops,
183 "\t%d connection%s closed (including %d drop%s)\n");
184 p(tcps_conndrops, "\t%d embryonic connection%s dropped\n");
185 p2(tcps_rttupdated, tcps_segstimed,
186 "\t%d segment%s updated rtt (of %d attempt%s)\n");
187 p(tcps_rexmttimeo, "\t%d retransmit timeout%s\n");
188 p(tcps_timeoutdrop, "\t\t%d connection%s dropped by rexmit timeout\n");
189 p(tcps_persisttimeo, "\t%d persist timeout%s\n");
190 p(tcps_keeptimeo, "\t%d keepalive timeout%s\n");
191 p(tcps_keepprobe, "\t\t%d keepalive probe%s sent\n");
192 p(tcps_keepdrops, "\t\t%d connection%s dropped by keepalive\n");
49a4dfd4
MK
193#undef p
194#undef p2
6df0a927
SL
195}
196
197/*
198 * Dump UDP statistics structure.
199 */
200udp_stats(off, name)
201 off_t off;
202 char *name;
203{
204 struct udpstat udpstat;
205
a960d94f 206 if (off == 0)
6df0a927 207 return;
6df0a927
SL
208 klseek(kmem, off, 0);
209 read(kmem, (char *)&udpstat, sizeof (udpstat));
bd91d3f9 210 printf("%s:\n\t%u incomplete header%s\n", name,
d69a747c 211 udpstat.udps_hdrops, plural(udpstat.udps_hdrops));
bd91d3f9 212 printf("\t%u bad data length field%s\n",
d69a747c 213 udpstat.udps_badlen, plural(udpstat.udps_badlen));
bd91d3f9 214 printf("\t%u bad checksum%s\n",
a960d94f 215 udpstat.udps_badsum, plural(udpstat.udps_badsum));
6df0a927
SL
216}
217
218/*
219 * Dump IP statistics structure.
220 */
221ip_stats(off, name)
222 off_t off;
223 char *name;
224{
225 struct ipstat ipstat;
226
a960d94f 227 if (off == 0)
6df0a927 228 return;
6df0a927
SL
229 klseek(kmem, off, 0);
230 read(kmem, (char *)&ipstat, sizeof (ipstat));
bd91d3f9 231 printf("%s:\n\t%u total packets received\n", name,
a960d94f 232 ipstat.ips_total);
bd91d3f9 233 printf("\t%u bad header checksum%s\n",
d69a747c 234 ipstat.ips_badsum, plural(ipstat.ips_badsum));
bd91d3f9
SL
235 printf("\t%u with size smaller than minimum\n", ipstat.ips_tooshort);
236 printf("\t%u with data size < data length\n", ipstat.ips_toosmall);
237 printf("\t%u with header length < data size\n", ipstat.ips_badhlen);
238 printf("\t%u with data length < header length\n", ipstat.ips_badlen);
239 printf("\t%u fragment%s received\n",
a960d94f 240 ipstat.ips_fragments, plural(ipstat.ips_fragments));
bd91d3f9 241 printf("\t%u fragment%s dropped (dup or out of space)\n",
a960d94f 242 ipstat.ips_fragdropped, plural(ipstat.ips_fragdropped));
bd91d3f9 243 printf("\t%u fragment%s dropped after timeout\n",
a960d94f 244 ipstat.ips_fragtimeout, plural(ipstat.ips_fragtimeout));
bd91d3f9 245 printf("\t%u packet%s forwarded\n",
a960d94f 246 ipstat.ips_forward, plural(ipstat.ips_forward));
bd91d3f9 247 printf("\t%u packet%s not forwardable\n",
a960d94f 248 ipstat.ips_cantforward, plural(ipstat.ips_cantforward));
bd91d3f9 249 printf("\t%u redirect%s sent\n",
a960d94f 250 ipstat.ips_redirectsent, plural(ipstat.ips_redirectsent));
6df0a927
SL
251}
252
7333c75b
SL
253static char *icmpnames[] = {
254 "echo reply",
255 "#1",
256 "#2",
257 "destination unreachable",
258 "source quench",
259 "routing redirect",
260 "#6",
261 "#7",
262 "echo",
263 "#9",
264 "#10",
265 "time exceeded",
266 "parameter problem",
267 "time stamp",
268 "time stamp reply",
269 "information request",
a960d94f
MK
270 "information request reply",
271 "address mask request",
272 "address mask reply",
7333c75b
SL
273};
274
275/*
276 * Dump ICMP statistics.
277 */
278icmp_stats(off, name)
279 off_t off;
280 char *name;
281{
282 struct icmpstat icmpstat;
283 register int i, first;
284
a960d94f 285 if (off == 0)
7333c75b 286 return;
7333c75b
SL
287 klseek(kmem, off, 0);
288 read(kmem, (char *)&icmpstat, sizeof (icmpstat));
bd91d3f9 289 printf("%s:\n\t%u call%s to icmp_error\n", name,
d69a747c 290 icmpstat.icps_error, plural(icmpstat.icps_error));
bd91d3f9 291 printf("\t%u error%s not generated 'cuz old message was icmp\n",
d69a747c 292 icmpstat.icps_oldicmp, plural(icmpstat.icps_oldicmp));
7dbb09e5 293 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
7333c75b
SL
294 if (icmpstat.icps_outhist[i] != 0) {
295 if (first) {
296 printf("\tOutput histogram:\n");
297 first = 0;
298 }
bd91d3f9 299 printf("\t\t%s: %u\n", icmpnames[i],
7333c75b
SL
300 icmpstat.icps_outhist[i]);
301 }
bd91d3f9 302 printf("\t%u message%s with bad code fields\n",
bdf25b53 303 icmpstat.icps_badcode, plural(icmpstat.icps_badcode));
bd91d3f9 304 printf("\t%u message%s < minimum length\n",
d69a747c 305 icmpstat.icps_tooshort, plural(icmpstat.icps_tooshort));
bd91d3f9 306 printf("\t%u bad checksum%s\n",
4fbbc6d9 307 icmpstat.icps_checksum, plural(icmpstat.icps_checksum));
bd91d3f9 308 printf("\t%u message%s with bad length\n",
d69a747c 309 icmpstat.icps_badlen, plural(icmpstat.icps_badlen));
7dbb09e5 310 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
7333c75b
SL
311 if (icmpstat.icps_inhist[i] != 0) {
312 if (first) {
313 printf("\tInput histogram:\n");
314 first = 0;
315 }
bd91d3f9 316 printf("\t\t%s: %u\n", icmpnames[i],
7333c75b
SL
317 icmpstat.icps_inhist[i]);
318 }
bd91d3f9 319 printf("\t%u message response%s generated\n",
a960d94f 320 icmpstat.icps_reflect, plural(icmpstat.icps_reflect));
7333c75b
SL
321}
322
c7fc5288
SL
323/*
324 * Pretty print an Internet address (net address + port).
325 * If the nflag was specified, use numbers instead of names.
326 */
327inetprint(in, port, proto)
328 register struct in_addr *in;
f7c99b06 329 u_short port;
c7fc5288
SL
330 char *proto;
331{
332 struct servent *sp = 0;
333 char line[80], *cp, *index();
f36bd7cf 334 int width;
c7fc5288 335
8e7710ba 336 sprintf(line, "%.*s.", (Aflag && !nflag) ? 12 : 16, inetname(*in));
c7fc5288 337 cp = index(line, '\0');
c7fc5288 338 if (!nflag && port)
f7c99b06 339 sp = getservbyport((int)port, proto);
c7fc5288
SL
340 if (sp || port == 0)
341 sprintf(cp, "%.8s", sp ? sp->s_name : "*");
342 else
1f34f70d 343 sprintf(cp, "%d", ntohs((u_short)port));
f36bd7cf
MK
344 width = Aflag ? 18 : 22;
345 printf(" %-*.*s", width, width, line);
c7fc5288
SL
346}
347
c7fc5288
SL
348/*
349 * Construct an Internet address representation.
350 * If the nflag has been supplied, give
351 * numeric value, otherwise try for symbolic name.
352 */
353char *
354inetname(in)
355 struct in_addr in;
356{
6c5bed6c 357 register char *cp;
c7fc5288 358 static char line[50];
f6d7bbb7
MK
359 struct hostent *hp;
360 struct netent *np;
6c5bed6c
MK
361 static char domain[MAXHOSTNAMELEN + 1];
362 static int first = 1;
c7fc5288 363
6c5bed6c
MK
364 if (first && !nflag) {
365 first = 0;
366 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
367 (cp = index(domain, '.')))
368 (void) strcpy(domain, cp + 1);
369 else
370 domain[0] = 0;
371 }
372 cp = 0;
227faf58 373 if (!nflag && in.s_addr != INADDR_ANY) {
cab3a575 374 int net = inet_netof(in);
f6d7bbb7 375 int lna = inet_lnaof(in);
227faf58 376
f6d7bbb7 377 if (lna == INADDR_ANY) {
40f48772 378 np = getnetbyaddr(net, AF_INET);
c7fc5288
SL
379 if (np)
380 cp = np->n_name;
cab3a575
MK
381 }
382 if (cp == 0) {
f7c99b06 383 hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
6c5bed6c
MK
384 if (hp) {
385 if ((cp = index(hp->h_name, '.')) &&
386 !strcmp(cp + 1, domain))
387 *cp = 0;
c7fc5288 388 cp = hp->h_name;
6c5bed6c 389 }
c7fc5288
SL
390 }
391 }
392 if (in.s_addr == INADDR_ANY)
393 strcpy(line, "*");
394 else if (cp)
395 strcpy(line, cp);
396 else {
cab3a575
MK
397 in.s_addr = ntohl(in.s_addr);
398#define C(x) ((x) & 0xff)
399 sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
400 C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
c7fc5288
SL
401 }
402 return (line);
403}