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