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