date and time created 87/01/19 15:23:17 by karels
[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
bd91d3f9 8static char sccsid[] = "@(#)inet.c 5.6 (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;
6df0a927
SL
141 klseek(kmem, off, 0);
142 read(kmem, (char *)&tcpstat, sizeof (tcpstat));
bd91d3f9 143 printf("%s:\n\t%u incomplete header%s\n", name,
a960d94f 144 tcpstat.tcps_hdrops, plural(tcpstat.tcps_hdrops));
bd91d3f9 145 printf("\t%u bad checksum%s\n",
d69a747c 146 tcpstat.tcps_badsum, plural(tcpstat.tcps_badsum));
bd91d3f9 147 printf("\t%u bad header offset field%s\n",
d69a747c 148 tcpstat.tcps_badoff, plural(tcpstat.tcps_badoff));
6df0a927 149#ifdef notdef
bd91d3f9 150 printf("\t%u bad segment%s\n",
d69a747c 151 tcpstat.tcps_badsegs, plural(tcpstat.badsegs));
bd91d3f9 152 printf("\t%u unacknowledged packet%s\n",
d69a747c 153 tcpstat.tcps_unack, plural(tcpstat.tcps_unack));
6df0a927
SL
154#endif
155}
156
157/*
158 * Dump UDP statistics structure.
159 */
160udp_stats(off, name)
161 off_t off;
162 char *name;
163{
164 struct udpstat udpstat;
165
a960d94f 166 if (off == 0)
6df0a927 167 return;
6df0a927
SL
168 klseek(kmem, off, 0);
169 read(kmem, (char *)&udpstat, sizeof (udpstat));
bd91d3f9 170 printf("%s:\n\t%u incomplete header%s\n", name,
d69a747c 171 udpstat.udps_hdrops, plural(udpstat.udps_hdrops));
bd91d3f9 172 printf("\t%u bad data length field%s\n",
d69a747c 173 udpstat.udps_badlen, plural(udpstat.udps_badlen));
bd91d3f9 174 printf("\t%u bad checksum%s\n",
a960d94f 175 udpstat.udps_badsum, plural(udpstat.udps_badsum));
6df0a927
SL
176}
177
178/*
179 * Dump IP statistics structure.
180 */
181ip_stats(off, name)
182 off_t off;
183 char *name;
184{
185 struct ipstat ipstat;
186
a960d94f 187 if (off == 0)
6df0a927 188 return;
6df0a927
SL
189 klseek(kmem, off, 0);
190 read(kmem, (char *)&ipstat, sizeof (ipstat));
bd91d3f9 191 printf("%s:\n\t%u total packets received\n", name,
a960d94f 192 ipstat.ips_total);
bd91d3f9 193 printf("\t%u bad header checksum%s\n",
d69a747c 194 ipstat.ips_badsum, plural(ipstat.ips_badsum));
bd91d3f9
SL
195 printf("\t%u with size smaller than minimum\n", ipstat.ips_tooshort);
196 printf("\t%u with data size < data length\n", ipstat.ips_toosmall);
197 printf("\t%u with header length < data size\n", ipstat.ips_badhlen);
198 printf("\t%u with data length < header length\n", ipstat.ips_badlen);
199 printf("\t%u fragment%s received\n",
a960d94f 200 ipstat.ips_fragments, plural(ipstat.ips_fragments));
bd91d3f9 201 printf("\t%u fragment%s dropped (dup or out of space)\n",
a960d94f 202 ipstat.ips_fragdropped, plural(ipstat.ips_fragdropped));
bd91d3f9 203 printf("\t%u fragment%s dropped after timeout\n",
a960d94f 204 ipstat.ips_fragtimeout, plural(ipstat.ips_fragtimeout));
bd91d3f9 205 printf("\t%u packet%s forwarded\n",
a960d94f 206 ipstat.ips_forward, plural(ipstat.ips_forward));
bd91d3f9 207 printf("\t%u packet%s not forwardable\n",
a960d94f 208 ipstat.ips_cantforward, plural(ipstat.ips_cantforward));
bd91d3f9 209 printf("\t%u redirect%s sent\n",
a960d94f 210 ipstat.ips_redirectsent, plural(ipstat.ips_redirectsent));
6df0a927
SL
211}
212
7333c75b
SL
213static char *icmpnames[] = {
214 "echo reply",
215 "#1",
216 "#2",
217 "destination unreachable",
218 "source quench",
219 "routing redirect",
220 "#6",
221 "#7",
222 "echo",
223 "#9",
224 "#10",
225 "time exceeded",
226 "parameter problem",
227 "time stamp",
228 "time stamp reply",
229 "information request",
a960d94f
MK
230 "information request reply",
231 "address mask request",
232 "address mask reply",
7333c75b
SL
233};
234
235/*
236 * Dump ICMP statistics.
237 */
238icmp_stats(off, name)
239 off_t off;
240 char *name;
241{
242 struct icmpstat icmpstat;
243 register int i, first;
244
a960d94f 245 if (off == 0)
7333c75b 246 return;
7333c75b
SL
247 klseek(kmem, off, 0);
248 read(kmem, (char *)&icmpstat, sizeof (icmpstat));
bd91d3f9 249 printf("%s:\n\t%u call%s to icmp_error\n", name,
d69a747c 250 icmpstat.icps_error, plural(icmpstat.icps_error));
bd91d3f9 251 printf("\t%u error%s not generated 'cuz old message was icmp\n",
d69a747c 252 icmpstat.icps_oldicmp, plural(icmpstat.icps_oldicmp));
94ff35a7 253 for (first = 1, i = 0; i < ICMP_IREQREPLY + 1; i++)
7333c75b
SL
254 if (icmpstat.icps_outhist[i] != 0) {
255 if (first) {
256 printf("\tOutput histogram:\n");
257 first = 0;
258 }
bd91d3f9 259 printf("\t\t%s: %u\n", icmpnames[i],
7333c75b
SL
260 icmpstat.icps_outhist[i]);
261 }
bd91d3f9 262 printf("\t%u message%s with bad code fields\n",
bdf25b53 263 icmpstat.icps_badcode, plural(icmpstat.icps_badcode));
bd91d3f9 264 printf("\t%u message%s < minimum length\n",
d69a747c 265 icmpstat.icps_tooshort, plural(icmpstat.icps_tooshort));
bd91d3f9 266 printf("\t%u bad checksum%s\n",
4fbbc6d9 267 icmpstat.icps_checksum, plural(icmpstat.icps_checksum));
bd91d3f9 268 printf("\t%u message%s with bad length\n",
d69a747c 269 icmpstat.icps_badlen, plural(icmpstat.icps_badlen));
94ff35a7 270 for (first = 1, i = 0; i < ICMP_IREQREPLY + 1; i++)
7333c75b
SL
271 if (icmpstat.icps_inhist[i] != 0) {
272 if (first) {
273 printf("\tInput histogram:\n");
274 first = 0;
275 }
bd91d3f9 276 printf("\t\t%s: %u\n", icmpnames[i],
7333c75b
SL
277 icmpstat.icps_inhist[i]);
278 }
bd91d3f9 279 printf("\t%u message response%s generated\n",
a960d94f 280 icmpstat.icps_reflect, plural(icmpstat.icps_reflect));
7333c75b
SL
281}
282
c7fc5288
SL
283/*
284 * Pretty print an Internet address (net address + port).
285 * If the nflag was specified, use numbers instead of names.
286 */
287inetprint(in, port, proto)
288 register struct in_addr *in;
f7c99b06 289 u_short port;
c7fc5288
SL
290 char *proto;
291{
292 struct servent *sp = 0;
293 char line[80], *cp, *index();
f36bd7cf 294 int width;
c7fc5288 295
8e7710ba 296 sprintf(line, "%.*s.", (Aflag && !nflag) ? 12 : 16, inetname(*in));
c7fc5288 297 cp = index(line, '\0');
c7fc5288 298 if (!nflag && port)
f7c99b06 299 sp = getservbyport((int)port, proto);
c7fc5288
SL
300 if (sp || port == 0)
301 sprintf(cp, "%.8s", sp ? sp->s_name : "*");
302 else
1f34f70d 303 sprintf(cp, "%d", ntohs((u_short)port));
f36bd7cf
MK
304 width = Aflag ? 18 : 22;
305 printf(" %-*.*s", width, width, line);
c7fc5288
SL
306}
307
c7fc5288
SL
308/*
309 * Construct an Internet address representation.
310 * If the nflag has been supplied, give
311 * numeric value, otherwise try for symbolic name.
312 */
313char *
314inetname(in)
315 struct in_addr in;
316{
6c5bed6c 317 register char *cp;
c7fc5288 318 static char line[50];
f6d7bbb7
MK
319 struct hostent *hp;
320 struct netent *np;
6c5bed6c
MK
321 static char domain[MAXHOSTNAMELEN + 1];
322 static int first = 1;
c7fc5288 323
6c5bed6c
MK
324 if (first && !nflag) {
325 first = 0;
326 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
327 (cp = index(domain, '.')))
328 (void) strcpy(domain, cp + 1);
329 else
330 domain[0] = 0;
331 }
332 cp = 0;
227faf58 333 if (!nflag && in.s_addr != INADDR_ANY) {
cab3a575 334 int net = inet_netof(in);
f6d7bbb7 335 int lna = inet_lnaof(in);
227faf58 336
f6d7bbb7 337 if (lna == INADDR_ANY) {
40f48772 338 np = getnetbyaddr(net, AF_INET);
c7fc5288
SL
339 if (np)
340 cp = np->n_name;
cab3a575
MK
341 }
342 if (cp == 0) {
f7c99b06 343 hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
6c5bed6c
MK
344 if (hp) {
345 if ((cp = index(hp->h_name, '.')) &&
346 !strcmp(cp + 1, domain))
347 *cp = 0;
c7fc5288 348 cp = hp->h_name;
6c5bed6c 349 }
c7fc5288
SL
350 }
351 }
352 if (in.s_addr == INADDR_ANY)
353 strcpy(line, "*");
354 else if (cp)
355 strcpy(line, cp);
356 else {
cab3a575
MK
357 in.s_addr = ntohl(in.s_addr);
358#define C(x) ((x) & 0xff)
359 sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
360 C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
c7fc5288
SL
361 }
362 return (line);
363}