new IMP stuff
[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
37c1b971 8static char sccsid[] = "@(#)inet.c 5.9.1.1 (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));
37c1b971
MK
216#ifdef sun
217 printf("\t%d socket overflow%s\n",
218 udpstat.udps_fullsock, plural(udpstat.udps_fullsock));
219#endif
6df0a927
SL
220}
221
222/*
223 * Dump IP statistics structure.
224 */
225ip_stats(off, name)
226 off_t off;
227 char *name;
228{
229 struct ipstat ipstat;
230
a960d94f 231 if (off == 0)
6df0a927 232 return;
6df0a927
SL
233 klseek(kmem, off, 0);
234 read(kmem, (char *)&ipstat, sizeof (ipstat));
37c1b971 235#if BSD>=43
bd91d3f9 236 printf("%s:\n\t%u total packets received\n", name,
a960d94f 237 ipstat.ips_total);
37c1b971 238#endif
bd91d3f9 239 printf("\t%u bad header checksum%s\n",
d69a747c 240 ipstat.ips_badsum, plural(ipstat.ips_badsum));
bd91d3f9
SL
241 printf("\t%u with size smaller than minimum\n", ipstat.ips_tooshort);
242 printf("\t%u with data size < data length\n", ipstat.ips_toosmall);
243 printf("\t%u with header length < data size\n", ipstat.ips_badhlen);
244 printf("\t%u with data length < header length\n", ipstat.ips_badlen);
37c1b971 245#if BSD>=43
bd91d3f9 246 printf("\t%u fragment%s received\n",
a960d94f 247 ipstat.ips_fragments, plural(ipstat.ips_fragments));
bd91d3f9 248 printf("\t%u fragment%s dropped (dup or out of space)\n",
a960d94f 249 ipstat.ips_fragdropped, plural(ipstat.ips_fragdropped));
bd91d3f9 250 printf("\t%u fragment%s dropped after timeout\n",
a960d94f 251 ipstat.ips_fragtimeout, plural(ipstat.ips_fragtimeout));
bd91d3f9 252 printf("\t%u packet%s forwarded\n",
a960d94f 253 ipstat.ips_forward, plural(ipstat.ips_forward));
bd91d3f9 254 printf("\t%u packet%s not forwardable\n",
a960d94f 255 ipstat.ips_cantforward, plural(ipstat.ips_cantforward));
bd91d3f9 256 printf("\t%u redirect%s sent\n",
a960d94f 257 ipstat.ips_redirectsent, plural(ipstat.ips_redirectsent));
37c1b971 258#endif
6df0a927
SL
259}
260
7333c75b
SL
261static char *icmpnames[] = {
262 "echo reply",
263 "#1",
264 "#2",
265 "destination unreachable",
266 "source quench",
267 "routing redirect",
268 "#6",
269 "#7",
270 "echo",
271 "#9",
272 "#10",
273 "time exceeded",
274 "parameter problem",
275 "time stamp",
276 "time stamp reply",
277 "information request",
a960d94f
MK
278 "information request reply",
279 "address mask request",
280 "address mask reply",
7333c75b
SL
281};
282
283/*
284 * Dump ICMP statistics.
285 */
286icmp_stats(off, name)
287 off_t off;
288 char *name;
289{
290 struct icmpstat icmpstat;
291 register int i, first;
292
a960d94f 293 if (off == 0)
7333c75b 294 return;
7333c75b
SL
295 klseek(kmem, off, 0);
296 read(kmem, (char *)&icmpstat, sizeof (icmpstat));
bd91d3f9 297 printf("%s:\n\t%u call%s to icmp_error\n", name,
d69a747c 298 icmpstat.icps_error, plural(icmpstat.icps_error));
bd91d3f9 299 printf("\t%u error%s not generated 'cuz old message was icmp\n",
d69a747c 300 icmpstat.icps_oldicmp, plural(icmpstat.icps_oldicmp));
7dbb09e5 301 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
7333c75b
SL
302 if (icmpstat.icps_outhist[i] != 0) {
303 if (first) {
304 printf("\tOutput histogram:\n");
305 first = 0;
306 }
bd91d3f9 307 printf("\t\t%s: %u\n", icmpnames[i],
7333c75b
SL
308 icmpstat.icps_outhist[i]);
309 }
bd91d3f9 310 printf("\t%u message%s with bad code fields\n",
bdf25b53 311 icmpstat.icps_badcode, plural(icmpstat.icps_badcode));
bd91d3f9 312 printf("\t%u message%s < minimum length\n",
d69a747c 313 icmpstat.icps_tooshort, plural(icmpstat.icps_tooshort));
bd91d3f9 314 printf("\t%u bad checksum%s\n",
4fbbc6d9 315 icmpstat.icps_checksum, plural(icmpstat.icps_checksum));
bd91d3f9 316 printf("\t%u message%s with bad length\n",
d69a747c 317 icmpstat.icps_badlen, plural(icmpstat.icps_badlen));
7dbb09e5 318 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
7333c75b
SL
319 if (icmpstat.icps_inhist[i] != 0) {
320 if (first) {
321 printf("\tInput histogram:\n");
322 first = 0;
323 }
bd91d3f9 324 printf("\t\t%s: %u\n", icmpnames[i],
7333c75b
SL
325 icmpstat.icps_inhist[i]);
326 }
bd91d3f9 327 printf("\t%u message response%s generated\n",
a960d94f 328 icmpstat.icps_reflect, plural(icmpstat.icps_reflect));
7333c75b
SL
329}
330
c7fc5288
SL
331/*
332 * Pretty print an Internet address (net address + port).
333 * If the nflag was specified, use numbers instead of names.
334 */
335inetprint(in, port, proto)
336 register struct in_addr *in;
f7c99b06 337 u_short port;
c7fc5288
SL
338 char *proto;
339{
340 struct servent *sp = 0;
341 char line[80], *cp, *index();
f36bd7cf 342 int width;
c7fc5288 343
8e7710ba 344 sprintf(line, "%.*s.", (Aflag && !nflag) ? 12 : 16, inetname(*in));
c7fc5288 345 cp = index(line, '\0');
c7fc5288 346 if (!nflag && port)
f7c99b06 347 sp = getservbyport((int)port, proto);
c7fc5288
SL
348 if (sp || port == 0)
349 sprintf(cp, "%.8s", sp ? sp->s_name : "*");
350 else
1f34f70d 351 sprintf(cp, "%d", ntohs((u_short)port));
f36bd7cf
MK
352 width = Aflag ? 18 : 22;
353 printf(" %-*.*s", width, width, line);
c7fc5288
SL
354}
355
c7fc5288
SL
356/*
357 * Construct an Internet address representation.
358 * If the nflag has been supplied, give
359 * numeric value, otherwise try for symbolic name.
360 */
361char *
362inetname(in)
363 struct in_addr in;
364{
6c5bed6c 365 register char *cp;
c7fc5288 366 static char line[50];
f6d7bbb7
MK
367 struct hostent *hp;
368 struct netent *np;
6c5bed6c
MK
369 static char domain[MAXHOSTNAMELEN + 1];
370 static int first = 1;
c7fc5288 371
6c5bed6c
MK
372 if (first && !nflag) {
373 first = 0;
374 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
375 (cp = index(domain, '.')))
376 (void) strcpy(domain, cp + 1);
377 else
378 domain[0] = 0;
379 }
380 cp = 0;
227faf58 381 if (!nflag && in.s_addr != INADDR_ANY) {
cab3a575 382 int net = inet_netof(in);
f6d7bbb7 383 int lna = inet_lnaof(in);
227faf58 384
f6d7bbb7 385 if (lna == INADDR_ANY) {
40f48772 386 np = getnetbyaddr(net, AF_INET);
c7fc5288
SL
387 if (np)
388 cp = np->n_name;
cab3a575
MK
389 }
390 if (cp == 0) {
f7c99b06 391 hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
6c5bed6c
MK
392 if (hp) {
393 if ((cp = index(hp->h_name, '.')) &&
394 !strcmp(cp + 1, domain))
395 *cp = 0;
c7fc5288 396 cp = hp->h_name;
6c5bed6c 397 }
c7fc5288
SL
398 }
399 }
400 if (in.s_addr == INADDR_ANY)
401 strcpy(line, "*");
402 else if (cp)
403 strcpy(line, cp);
404 else {
cab3a575
MK
405 in.s_addr = ntohl(in.s_addr);
406#define C(x) ((x) & 0xff)
407 sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
408 C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
c7fc5288
SL
409 }
410 return (line);
411}