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