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