1 /* 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. 11 */ 12 13 #ifndef lint 14 static char sccsid[] = "@(#)inet.c 5.10 (Berkeley) 02/07/88"; 15 #endif not lint 16 17 #include <strings.h> 18 #include <stdio.h> 19 20 #include <sys/param.h> 21 #include <sys/socket.h> 22 #include <sys/socketvar.h> 23 #include <sys/mbuf.h> 24 #include <sys/protosw.h> 25 26 #include <net/route.h> 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> 32 #include <netinet/icmp_var.h> 33 #include <netinet/ip_var.h> 34 #include <netinet/tcp.h> 35 #include <netinet/tcpip.h> 36 #include <netinet/tcp_seq.h> 37 #define TCPSTATES 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 45 #include <netdb.h> 46 47 struct inpcb inpcb; 48 struct tcpcb tcpcb; 49 struct socket sockb; 50 extern int kmem; 51 extern int Aflag; 52 extern int aflag; 53 extern int nflag; 54 extern char *plural(); 55 56 char *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 */ 64 protopr(off, name) 65 off_t off; 66 char *name; 67 { 68 struct inpcb cb; 69 register struct inpcb *prev, *next; 70 int istcp; 71 static int first = 1; 72 73 if (off == 0) 74 return; 75 istcp = strcmp(name, "tcp") == 0; 76 klseek(kmem, off, 0); 77 read(kmem, (char *)&cb, sizeof (struct inpcb)); 78 inpcb = cb; 79 prev = (struct inpcb *)off; 80 if (inpcb.inp_next == (struct inpcb *)off) 81 return; 82 while (inpcb.inp_next != (struct inpcb *)off) { 83 84 next = inpcb.inp_next; 85 klseek(kmem, (off_t)next, 0); 86 read(kmem, (char *)&inpcb, sizeof (inpcb)); 87 if (inpcb.inp_prev != prev) { 88 printf("???\n"); 89 break; 90 } 91 if (!aflag && 92 inet_lnaof(inpcb.inp_laddr) == INADDR_ANY) { 93 prev = next; 94 continue; 95 } 96 klseek(kmem, (off_t)inpcb.inp_socket, 0); 97 read(kmem, (char *)&sockb, sizeof (sockb)); 98 if (istcp) { 99 klseek(kmem, (off_t)inpcb.inp_ppcb, 0); 100 read(kmem, (char *)&tcpcb, sizeof (tcpcb)); 101 } 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 } 116 if (Aflag) 117 if (istcp) 118 printf("%8x ", inpcb.inp_ppcb); 119 else 120 printf("%8x ", next); 121 printf("%-5.5s %6d %6d ", name, sockb.so_rcv.sb_cc, 122 sockb.so_snd.sb_cc); 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 136 /* 137 * Dump TCP statistics structure. 138 */ 139 tcp_stats(off, name) 140 off_t off; 141 char *name; 142 { 143 struct tcpstat tcpstat; 144 145 if (off == 0) 146 return; 147 printf ("%s:\n", name); 148 klseek(kmem, off, 0); 149 read(kmem, (char *)&tcpstat, sizeof (tcpstat)); 150 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"); 199 #undef p 200 #undef p2 201 } 202 203 /* 204 * Dump UDP statistics structure. 205 */ 206 udp_stats(off, name) 207 off_t off; 208 char *name; 209 { 210 struct udpstat udpstat; 211 212 if (off == 0) 213 return; 214 klseek(kmem, off, 0); 215 read(kmem, (char *)&udpstat, sizeof (udpstat)); 216 printf("%s:\n\t%u incomplete header%s\n", name, 217 udpstat.udps_hdrops, plural(udpstat.udps_hdrops)); 218 printf("\t%u bad data length field%s\n", 219 udpstat.udps_badlen, plural(udpstat.udps_badlen)); 220 printf("\t%u bad checksum%s\n", 221 udpstat.udps_badsum, plural(udpstat.udps_badsum)); 222 } 223 224 /* 225 * Dump IP statistics structure. 226 */ 227 ip_stats(off, name) 228 off_t off; 229 char *name; 230 { 231 struct ipstat ipstat; 232 233 if (off == 0) 234 return; 235 klseek(kmem, off, 0); 236 read(kmem, (char *)&ipstat, sizeof (ipstat)); 237 printf("%s:\n\t%u total packets received\n", name, 238 ipstat.ips_total); 239 printf("\t%u bad header checksum%s\n", 240 ipstat.ips_badsum, plural(ipstat.ips_badsum)); 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); 245 printf("\t%u fragment%s received\n", 246 ipstat.ips_fragments, plural(ipstat.ips_fragments)); 247 printf("\t%u fragment%s dropped (dup or out of space)\n", 248 ipstat.ips_fragdropped, plural(ipstat.ips_fragdropped)); 249 printf("\t%u fragment%s dropped after timeout\n", 250 ipstat.ips_fragtimeout, plural(ipstat.ips_fragtimeout)); 251 printf("\t%u packet%s forwarded\n", 252 ipstat.ips_forward, plural(ipstat.ips_forward)); 253 printf("\t%u packet%s not forwardable\n", 254 ipstat.ips_cantforward, plural(ipstat.ips_cantforward)); 255 printf("\t%u redirect%s sent\n", 256 ipstat.ips_redirectsent, plural(ipstat.ips_redirectsent)); 257 } 258 259 static char *icmpnames[] = { 260 "echo reply", 261 "#1", 262 "#2", 263 "destination unreachable", 264 "source quench", 265 "routing redirect", 266 "#6", 267 "#7", 268 "echo", 269 "#9", 270 "#10", 271 "time exceeded", 272 "parameter problem", 273 "time stamp", 274 "time stamp reply", 275 "information request", 276 "information request reply", 277 "address mask request", 278 "address mask reply", 279 }; 280 281 /* 282 * Dump ICMP statistics. 283 */ 284 icmp_stats(off, name) 285 off_t off; 286 char *name; 287 { 288 struct icmpstat icmpstat; 289 register int i, first; 290 291 if (off == 0) 292 return; 293 klseek(kmem, off, 0); 294 read(kmem, (char *)&icmpstat, sizeof (icmpstat)); 295 printf("%s:\n\t%u call%s to icmp_error\n", name, 296 icmpstat.icps_error, plural(icmpstat.icps_error)); 297 printf("\t%u error%s not generated 'cuz old message was icmp\n", 298 icmpstat.icps_oldicmp, plural(icmpstat.icps_oldicmp)); 299 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++) 300 if (icmpstat.icps_outhist[i] != 0) { 301 if (first) { 302 printf("\tOutput histogram:\n"); 303 first = 0; 304 } 305 printf("\t\t%s: %u\n", icmpnames[i], 306 icmpstat.icps_outhist[i]); 307 } 308 printf("\t%u message%s with bad code fields\n", 309 icmpstat.icps_badcode, plural(icmpstat.icps_badcode)); 310 printf("\t%u message%s < minimum length\n", 311 icmpstat.icps_tooshort, plural(icmpstat.icps_tooshort)); 312 printf("\t%u bad checksum%s\n", 313 icmpstat.icps_checksum, plural(icmpstat.icps_checksum)); 314 printf("\t%u message%s with bad length\n", 315 icmpstat.icps_badlen, plural(icmpstat.icps_badlen)); 316 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++) 317 if (icmpstat.icps_inhist[i] != 0) { 318 if (first) { 319 printf("\tInput histogram:\n"); 320 first = 0; 321 } 322 printf("\t\t%s: %u\n", icmpnames[i], 323 icmpstat.icps_inhist[i]); 324 } 325 printf("\t%u message response%s generated\n", 326 icmpstat.icps_reflect, plural(icmpstat.icps_reflect)); 327 } 328 329 /* 330 * Pretty print an Internet address (net address + port). 331 * If the nflag was specified, use numbers instead of names. 332 */ 333 inetprint(in, port, proto) 334 register struct in_addr *in; 335 u_short port; 336 char *proto; 337 { 338 struct servent *sp = 0; 339 char line[80], *cp, *index(); 340 int width; 341 342 sprintf(line, "%.*s.", (Aflag && !nflag) ? 12 : 16, inetname(*in)); 343 cp = index(line, '\0'); 344 if (!nflag && port) 345 sp = getservbyport((int)port, proto); 346 if (sp || port == 0) 347 sprintf(cp, "%.8s", sp ? sp->s_name : "*"); 348 else 349 sprintf(cp, "%d", ntohs((u_short)port)); 350 width = Aflag ? 18 : 22; 351 printf(" %-*.*s", width, width, line); 352 } 353 354 /* 355 * Construct an Internet address representation. 356 * If the nflag has been supplied, give 357 * numeric value, otherwise try for symbolic name. 358 */ 359 char * 360 inetname(in) 361 struct in_addr in; 362 { 363 register char *cp; 364 static char line[50]; 365 struct hostent *hp; 366 struct netent *np; 367 static char domain[MAXHOSTNAMELEN + 1]; 368 static int first = 1; 369 370 if (first && !nflag) { 371 first = 0; 372 if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 373 (cp = index(domain, '.'))) 374 (void) strcpy(domain, cp + 1); 375 else 376 domain[0] = 0; 377 } 378 cp = 0; 379 if (!nflag && in.s_addr != INADDR_ANY) { 380 int net = inet_netof(in); 381 int lna = inet_lnaof(in); 382 383 if (lna == INADDR_ANY) { 384 np = getnetbyaddr(net, AF_INET); 385 if (np) 386 cp = np->n_name; 387 } 388 if (cp == 0) { 389 hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET); 390 if (hp) { 391 if ((cp = index(hp->h_name, '.')) && 392 !strcmp(cp + 1, domain)) 393 *cp = 0; 394 cp = hp->h_name; 395 } 396 } 397 } 398 if (in.s_addr == INADDR_ANY) 399 strcpy(line, "*"); 400 else if (cp) 401 strcpy(line, cp); 402 else { 403 in.s_addr = ntohl(in.s_addr); 404 #define C(x) ((x) & 0xff) 405 sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), 406 C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr)); 407 } 408 return (line); 409 } 410