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