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