1 /* 2 * Copyright (c) 1983, 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static char sccsid[] = "@(#)inet.c 8.4 (Berkeley) 4/20/94"; 36 #endif /* not lint */ 37 38 #include <sys/param.h> 39 #include <sys/socket.h> 40 #include <sys/socketvar.h> 41 #include <sys/mbuf.h> 42 #include <sys/protosw.h> 43 44 #include <net/route.h> 45 #include <netinet/in.h> 46 #include <netinet/in_systm.h> 47 #include <netinet/ip.h> 48 #include <netinet/in_pcb.h> 49 #include <netinet/ip_icmp.h> 50 #include <netinet/icmp_var.h> 51 #include <netinet/igmp_var.h> 52 #include <netinet/ip_var.h> 53 #include <netinet/tcp.h> 54 #include <netinet/tcpip.h> 55 #include <netinet/tcp_seq.h> 56 #define TCPSTATES 57 #include <netinet/tcp_fsm.h> 58 #include <netinet/tcp_timer.h> 59 #include <netinet/tcp_var.h> 60 #include <netinet/tcp_debug.h> 61 #include <netinet/udp.h> 62 #include <netinet/udp_var.h> 63 64 #include <arpa/inet.h> 65 #include <netdb.h> 66 #include <stdio.h> 67 #include <string.h> 68 #include <unistd.h> 69 #include "netstat.h" 70 71 struct inpcb inpcb; 72 struct tcpcb tcpcb; 73 struct socket sockb; 74 75 char *inetname __P((struct in_addr *)); 76 void inetprint __P((struct in_addr *, int, char *)); 77 78 /* 79 * Print a summary of connections related to an Internet 80 * protocol. For TCP, also give state of connection. 81 * Listening processes (aflag) are suppressed unless the 82 * -a (all) flag is specified. 83 */ 84 void 85 protopr(off, name) 86 u_long off; 87 char *name; 88 { 89 struct inpcb cb; 90 register struct inpcb *prev, *next; 91 int istcp; 92 static int first = 1; 93 94 if (off == 0) 95 return; 96 istcp = strcmp(name, "tcp") == 0; 97 kread(off, (char *)&cb, sizeof (struct inpcb)); 98 inpcb = cb; 99 prev = (struct inpcb *)off; 100 if (inpcb.inp_next == (struct inpcb *)off) 101 return; 102 while (inpcb.inp_next != (struct inpcb *)off) { 103 next = inpcb.inp_next; 104 kread((u_long)next, (char *)&inpcb, sizeof (inpcb)); 105 if (inpcb.inp_prev != prev) { 106 printf("???\n"); 107 break; 108 } 109 if (!aflag && 110 inet_lnaof(inpcb.inp_laddr) == INADDR_ANY) { 111 prev = next; 112 continue; 113 } 114 kread((u_long)inpcb.inp_socket, (char *)&sockb, sizeof (sockb)); 115 if (istcp) { 116 kread((u_long)inpcb.inp_ppcb, 117 (char *)&tcpcb, sizeof (tcpcb)); 118 } 119 if (first) { 120 printf("Active Internet connections"); 121 if (aflag) 122 printf(" (including servers)"); 123 putchar('\n'); 124 if (Aflag) 125 printf("%-8.8s ", "PCB"); 126 printf(Aflag ? 127 "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" : 128 "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n", 129 "Proto", "Recv-Q", "Send-Q", 130 "Local Address", "Foreign Address", "(state)"); 131 first = 0; 132 } 133 if (Aflag) 134 if (istcp) 135 printf("%8x ", inpcb.inp_ppcb); 136 else 137 printf("%8x ", next); 138 printf("%-5.5s %6d %6d ", name, sockb.so_rcv.sb_cc, 139 sockb.so_snd.sb_cc); 140 inetprint(&inpcb.inp_laddr, (int)inpcb.inp_lport, name); 141 inetprint(&inpcb.inp_faddr, (int)inpcb.inp_fport, name); 142 if (istcp) { 143 if (tcpcb.t_state < 0 || tcpcb.t_state >= TCP_NSTATES) 144 printf(" %d", tcpcb.t_state); 145 else { 146 printf(" %s", tcpstates[tcpcb.t_state]); 147 #if defined(TF_NEEDSYN) && defined(TF_NEEDSYN) 148 /* Show T/TCP `hidden state' */ 149 if (tcpcb.t_flags & (TF_NEEDSYN|TF_NEEDFIN)) 150 putchar('*'); 151 #endif /* defined(TF_NEEDSYN) && defined(TF_NEEDSYN) */ 152 } 153 } 154 putchar('\n'); 155 prev = next; 156 } 157 } 158 159 /* 160 * Dump TCP statistics structure. 161 */ 162 void 163 tcp_stats(off, name) 164 u_long off; 165 char *name; 166 { 167 struct tcpstat tcpstat; 168 169 if (off == 0) 170 return; 171 printf ("%s:\n", name); 172 kread(off, (char *)&tcpstat, sizeof (tcpstat)); 173 174 #define p(f, m) if (tcpstat.f || sflag <= 1) \ 175 printf(m, tcpstat.f, plural(tcpstat.f)) 176 #define p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \ 177 printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2, plural(tcpstat.f2)) 178 #define p3(f, m) if (tcpstat.f || sflag <= 1) \ 179 printf(m, tcpstat.f, plurales(tcpstat.f)) 180 181 p(tcps_sndtotal, "\t%d packet%s sent\n"); 182 p2(tcps_sndpack,tcps_sndbyte, 183 "\t\t%d data packet%s (%d byte%s)\n"); 184 p2(tcps_sndrexmitpack, tcps_sndrexmitbyte, 185 "\t\t%d data packet%s (%d byte%s) retransmitted\n"); 186 p2(tcps_sndacks, tcps_delack, 187 "\t\t%d ack-only packet%s (%d delayed)\n"); 188 p(tcps_sndurg, "\t\t%d URG only packet%s\n"); 189 p(tcps_sndprobe, "\t\t%d window probe packet%s\n"); 190 p(tcps_sndwinup, "\t\t%d window update packet%s\n"); 191 p(tcps_sndctrl, "\t\t%d control packet%s\n"); 192 p(tcps_rcvtotal, "\t%d packet%s received\n"); 193 p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%d ack%s (for %d byte%s)\n"); 194 p(tcps_rcvdupack, "\t\t%d duplicate ack%s\n"); 195 p(tcps_rcvacktoomuch, "\t\t%d ack%s for unsent data\n"); 196 p2(tcps_rcvpack, tcps_rcvbyte, 197 "\t\t%d packet%s (%d byte%s) received in-sequence\n"); 198 p2(tcps_rcvduppack, tcps_rcvdupbyte, 199 "\t\t%d completely duplicate packet%s (%d byte%s)\n"); 200 p(tcps_pawsdrop, "\t\t%d old duplicate packet%s\n"); 201 p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte, 202 "\t\t%d packet%s with some dup. data (%d byte%s duped)\n"); 203 p2(tcps_rcvoopack, tcps_rcvoobyte, 204 "\t\t%d out-of-order packet%s (%d byte%s)\n"); 205 p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin, 206 "\t\t%d packet%s (%d byte%s) of data after window\n"); 207 p(tcps_rcvwinprobe, "\t\t%d window probe%s\n"); 208 p(tcps_rcvwinupd, "\t\t%d window update packet%s\n"); 209 p(tcps_rcvafterclose, "\t\t%d packet%s received after close\n"); 210 p(tcps_rcvbadsum, "\t\t%d discarded for bad checksum%s\n"); 211 p(tcps_rcvbadoff, "\t\t%d discarded for bad header offset field%s\n"); 212 p(tcps_rcvshort, "\t\t%d discarded because packet too short\n"); 213 p(tcps_connattempt, "\t%d connection request%s\n"); 214 p(tcps_accepts, "\t%d connection accept%s\n"); 215 p(tcps_connects, "\t%d connection%s established (including accepts)\n"); 216 p2(tcps_closed, tcps_drops, 217 "\t%d connection%s closed (including %d drop%s)\n"); 218 p(tcps_conndrops, "\t%d embryonic connection%s dropped\n"); 219 p2(tcps_rttupdated, tcps_segstimed, 220 "\t%d segment%s updated rtt (of %d attempt%s)\n"); 221 p(tcps_rexmttimeo, "\t%d retransmit timeout%s\n"); 222 p(tcps_timeoutdrop, "\t\t%d connection%s dropped by rexmit timeout\n"); 223 p(tcps_persisttimeo, "\t%d persist timeout%s\n"); 224 p(tcps_keeptimeo, "\t%d keepalive timeout%s\n"); 225 p(tcps_keepprobe, "\t\t%d keepalive probe%s sent\n"); 226 p(tcps_keepdrops, "\t\t%d connection%s dropped by keepalive\n"); 227 p(tcps_predack, "\t%d correct ACK header prediction%s\n"); 228 p(tcps_preddat, "\t%d correct data packet header prediction%s\n"); 229 p3(tcps_pcbcachemiss, "\t%d PCB cache miss%s\n"); 230 #undef p 231 #undef p2 232 #undef p3 233 } 234 235 /* 236 * Dump UDP statistics structure. 237 */ 238 void 239 udp_stats(off, name) 240 u_long off; 241 char *name; 242 { 243 struct udpstat udpstat; 244 u_long delivered; 245 246 if (off == 0) 247 return; 248 kread(off, (char *)&udpstat, sizeof (udpstat)); 249 printf("%s:\n", name); 250 #define p(f, m) if (udpstat.f || sflag <= 1) \ 251 printf(m, udpstat.f, plural(udpstat.f)) 252 p(udps_ipackets, "\t%u datagram%s received\n"); 253 p(udps_hdrops, "\t%u with incomplete header\n"); 254 p(udps_badlen, "\t%u with bad data length field\n"); 255 p(udps_badsum, "\t%u with bad checksum\n"); 256 p(udps_noport, "\t%u dropped due to no socket\n"); 257 p(udps_noportbcast, "\t%u broadcast/multicast datagram%s dropped due to no socket\n"); 258 p(udps_fullsock, "\t%u dropped due to full socket buffers\n"); 259 delivered = udpstat.udps_ipackets - 260 udpstat.udps_hdrops - 261 udpstat.udps_badlen - 262 udpstat.udps_badsum - 263 udpstat.udps_noport - 264 udpstat.udps_noportbcast - 265 udpstat.udps_fullsock; 266 if (delivered || sflag <= 1) 267 printf("\t%u delivered\n", delivered); 268 p(udps_opackets, "\t%u datagram%s output\n"); 269 #undef p 270 } 271 272 /* 273 * Dump IP statistics structure. 274 */ 275 void 276 ip_stats(off, name) 277 u_long off; 278 char *name; 279 { 280 struct ipstat ipstat; 281 282 if (off == 0) 283 return; 284 kread(off, (char *)&ipstat, sizeof (ipstat)); 285 printf("%s:\n", name); 286 287 #define p(f, m) if (ipstat.f || sflag <= 1) \ 288 printf(m, ipstat.f, plural(ipstat.f)) 289 290 p(ips_total, "\t%u total packet%s received\n"); 291 p(ips_badsum, "\t%u bad header checksum%s\n"); 292 p(ips_toosmall, "\t%u with size smaller than minimum\n"); 293 p(ips_tooshort, "\t%u with data size < data length\n"); 294 p(ips_badhlen, "\t%u with header length < data size\n"); 295 p(ips_badlen, "\t%u with data length < header length\n"); 296 p(ips_badoptions, "\t%u with bad options\n"); 297 p(ips_badvers, "\t%u with incorrect version number\n"); 298 p(ips_fragments, "\t%u fragment%s received\n"); 299 p(ips_fragdropped, "\t%u fragment%s dropped (dup or out of space)\n"); 300 p(ips_fragtimeout, "\t%u fragment%s dropped after timeout\n"); 301 p(ips_reassembled, "\t%u packet%s reassembled ok\n"); 302 p(ips_delivered, "\t%u packet%s for this host\n"); 303 p(ips_noproto, "\t%u packet%s for unknown/unsupported protocol\n"); 304 p(ips_forward, "\t%u packet%s forwarded\n"); 305 p(ips_cantforward, "\t%u packet%s not forwardable\n"); 306 p(ips_redirectsent, "\t%u redirect%s sent\n"); 307 p(ips_localout, "\t%u packet%s sent from this host\n"); 308 p(ips_rawout, "\t%u packet%s sent with fabricated ip header\n"); 309 p(ips_odropped, "\t%u output packet%s dropped due to no bufs, etc.\n"); 310 p(ips_noroute, "\t%u output packet%s discarded due to no route\n"); 311 p(ips_fragmented, "\t%u output datagram%s fragmented\n"); 312 p(ips_ofragments, "\t%u fragment%s created\n"); 313 p(ips_cantfrag, "\t%u datagram%s that can't be fragmented\n"); 314 #undef p 315 } 316 317 static char *icmpnames[] = { 318 "echo reply", 319 "#1", 320 "#2", 321 "destination unreachable", 322 "source quench", 323 "routing redirect", 324 "#6", 325 "#7", 326 "echo", 327 "router advertisement", 328 "router solicitation", 329 "time exceeded", 330 "parameter problem", 331 "time stamp", 332 "time stamp reply", 333 "information request", 334 "information request reply", 335 "address mask request", 336 "address mask reply", 337 }; 338 339 /* 340 * Dump ICMP statistics. 341 */ 342 void 343 icmp_stats(off, name) 344 u_long off; 345 char *name; 346 { 347 struct icmpstat icmpstat; 348 register int i, first; 349 350 if (off == 0) 351 return; 352 kread(off, (char *)&icmpstat, sizeof (icmpstat)); 353 printf("%s:\n", name); 354 355 #define p(f, m) if (icmpstat.f || sflag <= 1) \ 356 printf(m, icmpstat.f, plural(icmpstat.f)) 357 358 p(icps_error, "\t%u call%s to icmp_error\n"); 359 p(icps_oldicmp, 360 "\t%u error%s not generated 'cuz old message was icmp\n"); 361 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++) 362 if (icmpstat.icps_outhist[i] != 0) { 363 if (first) { 364 printf("\tOutput histogram:\n"); 365 first = 0; 366 } 367 printf("\t\t%s: %u\n", icmpnames[i], 368 icmpstat.icps_outhist[i]); 369 } 370 p(icps_badcode, "\t%u message%s with bad code fields\n"); 371 p(icps_tooshort, "\t%u message%s < minimum length\n"); 372 p(icps_checksum, "\t%u bad checksum%s\n"); 373 p(icps_badlen, "\t%u message%s with bad length\n"); 374 for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++) 375 if (icmpstat.icps_inhist[i] != 0) { 376 if (first) { 377 printf("\tInput histogram:\n"); 378 first = 0; 379 } 380 printf("\t\t%s: %u\n", icmpnames[i], 381 icmpstat.icps_inhist[i]); 382 } 383 p(icps_reflect, "\t%u message response%s generated\n"); 384 #undef p 385 } 386 387 /* 388 * Dump IGMP statistics structure. 389 */ 390 void 391 igmp_stats(off, name) 392 u_long off; 393 char *name; 394 { 395 struct igmpstat igmpstat; 396 397 if (off == 0) 398 return; 399 kread(off, (char *)&igmpstat, sizeof (igmpstat)); 400 printf("%s:\n", name); 401 402 #define p(f, m) if (igmpstat.f || sflag <= 1) \ 403 printf(m, igmpstat.f, plural(igmpstat.f)) 404 #define py(f, m) if (igmpstat.f || sflag <= 1) \ 405 printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y") 406 p(igps_rcv_total, "\t%u message%s received\n"); 407 p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n"); 408 p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n"); 409 py(igps_rcv_queries, "\t%u membership quer%s received\n"); 410 py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n"); 411 p(igps_rcv_reports, "\t%u membership report%s received\n"); 412 p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n"); 413 p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n"); 414 p(igps_snd_reports, "\t%u membership report%s sent\n"); 415 #undef p 416 #undef py 417 } 418 419 /* 420 * Pretty print an Internet address (net address + port). 421 * If the nflag was specified, use numbers instead of names. 422 */ 423 void 424 inetprint(in, port, proto) 425 register struct in_addr *in; 426 int port; 427 char *proto; 428 { 429 struct servent *sp = 0; 430 char line[80], *cp; 431 int width; 432 433 sprintf(line, "%.*s.", (Aflag && !nflag) ? 12 : 16, inetname(in)); 434 cp = index(line, '\0'); 435 if (!nflag && port) 436 sp = getservbyport((int)port, proto); 437 if (sp || port == 0) 438 sprintf(cp, "%.8s", sp ? sp->s_name : "*"); 439 else 440 sprintf(cp, "%d", ntohs((u_short)port)); 441 width = Aflag ? 18 : 22; 442 printf(" %-*.*s", width, width, line); 443 } 444 445 /* 446 * Construct an Internet address representation. 447 * If the nflag has been supplied, give 448 * numeric value, otherwise try for symbolic name. 449 */ 450 char * 451 inetname(inp) 452 struct in_addr *inp; 453 { 454 register char *cp; 455 static char line[50]; 456 struct hostent *hp; 457 struct netent *np; 458 static char domain[MAXHOSTNAMELEN + 1]; 459 static int first = 1; 460 461 if (first && !nflag) { 462 first = 0; 463 if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 464 (cp = index(domain, '.'))) 465 (void) strcpy(domain, cp + 1); 466 else 467 domain[0] = 0; 468 } 469 cp = 0; 470 if (!nflag && inp->s_addr != INADDR_ANY) { 471 int net = inet_netof(*inp); 472 int lna = inet_lnaof(*inp); 473 474 if (lna == INADDR_ANY) { 475 np = getnetbyaddr(net, AF_INET); 476 if (np) 477 cp = np->n_name; 478 } 479 if (cp == 0) { 480 hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET); 481 if (hp) { 482 if ((cp = index(hp->h_name, '.')) && 483 !strcmp(cp + 1, domain)) 484 *cp = 0; 485 cp = hp->h_name; 486 } 487 } 488 } 489 if (inp->s_addr == INADDR_ANY) 490 strcpy(line, "*"); 491 else if (cp) 492 strcpy(line, cp); 493 else { 494 inp->s_addr = ntohl(inp->s_addr); 495 #define C(x) ((x) & 0xff) 496 sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24), 497 C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr)); 498 } 499 return (line); 500 } 501