main.c revision 12316
1132718Skan/* 2132718Skan * Copyright (c) 1983, 1988, 1993 3132718Skan * Regents of the University of California. All rights reserved. 452284Sobrien * 552284Sobrien * Redistribution and use in source and binary forms, with or without 652284Sobrien * modification, are permitted provided that the following conditions 752284Sobrien * are met: 852284Sobrien * 1. Redistributions of source code must retain the above copyright 952284Sobrien * notice, this list of conditions and the following disclaimer. 1052284Sobrien * 2. Redistributions in binary form must reproduce the above copyright 11132718Skan * notice, this list of conditions and the following disclaimer in the 1252284Sobrien * documentation and/or other materials provided with the distribution. 13132718Skan * 3. All advertising materials mentioning features or use of this software 1452284Sobrien * must display the following acknowledgement: 1552284Sobrien * This product includes software developed by the University of 1652284Sobrien * California, Berkeley and its contributors. 1752284Sobrien * 4. Neither the name of the University nor the names of its contributors 18132718Skan * may be used to endorse or promote products derived from this software 1952284Sobrien * without specific prior written permission. 2052284Sobrien * 2152284Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2252284Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2352284Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24132718Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2752284Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2890075Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2952284Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30117395Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31117395Skan * SUCH DAMAGE. 3252284Sobrien */ 3352284Sobrien 34117395Skan#ifndef lint 3552284Sobrienchar copyright[] = 3652284Sobrien"@(#) Copyright (c) 1983, 1988, 1993\n\ 3752284Sobrien Regents of the University of California. All rights reserved.\n"; 3852284Sobrien#endif /* not lint */ 39132718Skan 40132718Skan#ifndef lint 4190075Sobrienstatic char sccsid[] = "@(#)main.c 8.4 (Berkeley) 3/1/94"; 4290075Sobrien#endif /* not lint */ 4352284Sobrien 44132718Skan#include <sys/param.h> 4552284Sobrien#include <sys/file.h> 4652284Sobrien#include <sys/protosw.h> 4752284Sobrien#include <sys/socket.h> 4852284Sobrien 4952284Sobrien#include <netinet/in.h> 5052284Sobrien 5152284Sobrien#include <ctype.h> 5252284Sobrien#include <errno.h> 5352284Sobrien#include <kvm.h> 5452284Sobrien#include <limits.h> 5552284Sobrien#include <netdb.h> 5652284Sobrien#include <nlist.h> 57169689Skan#include <paths.h> 58169689Skan#include <stdio.h> 5952284Sobrien#include <stdlib.h> 60117395Skan#include <string.h> 61117395Skan#include <unistd.h> 62117395Skan#include <err.h> 63117395Skan#include "netstat.h" 64117395Skan 65117395Skanstruct nlist nl[] = { 66117395Skan#define N_MBSTAT 0 67117395Skan { "_mbstat" }, 68117395Skan#define N_IPSTAT 1 69117395Skan { "_ipstat" }, 70117395Skan#define N_TCB 2 71117395Skan { "_tcb" }, 72117395Skan#define N_TCPSTAT 3 73117395Skan { "_tcpstat" }, 74117395Skan#define N_UDB 4 75117395Skan { "_udb" }, 76132718Skan#define N_UDPSTAT 5 77117395Skan { "_udpstat" }, 78132718Skan#define N_IFNET 6 79117395Skan { "_ifnet" }, 80117395Skan#define N_IMP 7 81117395Skan { "_imp_softc" }, 82117395Skan#define N_ICMPSTAT 8 8352284Sobrien { "_icmpstat" }, 8452284Sobrien#define N_RTSTAT 9 8552284Sobrien { "_rtstat" }, 8652284Sobrien#define N_UNIXSW 10 87169689Skan { "_localsw" }, 8852284Sobrien#define N_IDP 11 89117395Skan { "_nspcb"}, 9090075Sobrien#define N_IDPSTAT 12 9152284Sobrien { "_idpstat"}, 9252284Sobrien#define N_SPPSTAT 13 9352284Sobrien { "_spp_istat"}, 9452284Sobrien#define N_NSERR 14 9552284Sobrien { "_ns_errstat"}, 9690075Sobrien#define N_CLNPSTAT 15 97132718Skan { "_clnp_stat"}, 98132718Skan#define IN_NOTUSED 16 9952284Sobrien { "_tp_inpcb" }, 10052284Sobrien#define ISO_TP 17 10152284Sobrien { "_tp_refinfo" }, 10252284Sobrien#define N_TPSTAT 18 10352284Sobrien { "_tp_stat" }, 10452284Sobrien#define N_ESISSTAT 19 10552284Sobrien { "_esis_stat"}, 10652284Sobrien#define N_NIMP 20 10752284Sobrien { "_nimp"}, 10852284Sobrien#define N_RTREE 21 10952284Sobrien { "_rt_tables"}, 11052284Sobrien#define N_CLTP 22 11152284Sobrien { "_cltb"}, 11252284Sobrien#define N_CLTPSTAT 23 11352284Sobrien { "_cltpstat"}, 11452284Sobrien#define N_NFILE 24 11552284Sobrien { "_nfile" }, 11652284Sobrien#define N_FILE 25 11752284Sobrien { "_file" }, 11852284Sobrien#define N_IGMPSTAT 26 11952284Sobrien { "_igmpstat" }, 12052284Sobrien#define N_MRTPROTO 27 12152284Sobrien { "_ip_mrtproto" }, 12252284Sobrien#define N_MRTSTAT 28 12352284Sobrien { "_mrtstat" }, 12452284Sobrien#define N_MFCTABLE 29 12552284Sobrien { "_mfctable" }, 12652284Sobrien#define N_VIFTABLE 30 12752284Sobrien { "_viftable" }, 12852284Sobrien#define N_IPX 31 12952284Sobrien { "_ipxpcb"}, 13052284Sobrien#define N_IPXSTAT 32 13152284Sobrien { "_ipxstat"}, 13252284Sobrien#define N_SPXSTAT 33 13352284Sobrien { "_spx_istat"}, 13452284Sobrien#define N_IPXERR 34 13552284Sobrien { "_ipx_errstat"}, 13652284Sobrien "", 13752284Sobrien}; 13890075Sobrien 13952284Sobrienstruct protox { 14052284Sobrien u_char pr_index; /* index into nlist of cb head */ 14152284Sobrien u_char pr_sindex; /* index into nlist of stat block */ 14252284Sobrien u_char pr_wanted; /* 1 if wanted, 0 otherwise */ 14352284Sobrien void (*pr_cblocks)(); /* control blocks printing routine */ 14452284Sobrien void (*pr_stats)(); /* statistics printing routine */ 145132718Skan char *pr_name; /* well-known name */ 14652284Sobrien} protox[] = { 14752284Sobrien { N_TCB, N_TCPSTAT, 1, protopr, 14852284Sobrien tcp_stats, "tcp" }, 14952284Sobrien { N_UDB, N_UDPSTAT, 1, protopr, 150132718Skan udp_stats, "udp" }, 15190075Sobrien { -1, N_IPSTAT, 1, 0, 152132718Skan ip_stats, "ip" }, 15390075Sobrien { -1, N_ICMPSTAT, 1, 0, 15452284Sobrien icmp_stats, "icmp" }, 15552284Sobrien { -1, N_IGMPSTAT, 1, 0, 156132718Skan igmp_stats, "igmp" }, 15752284Sobrien { -1, -1, 0, 0, 15852284Sobrien 0, 0 } 15952284Sobrien}; 16052284Sobrien 16152284Sobrienstruct protox ipxprotox[] = { 16252284Sobrien { N_IPX, N_IPXSTAT, 1, ipxprotopr, 16352284Sobrien ipx_stats, "ipx" }, 16452284Sobrien { N_IPX, N_SPXSTAT, 1, ipxprotopr, 16552284Sobrien spx_stats, "spx" }, 16652284Sobrien { -1, N_IPXERR, 1, 0, 16752284Sobrien ipxerr_stats, "ipx_err" }, 16852284Sobrien { -1, -1, 0, 0, 16952284Sobrien 0, 0 } 17052284Sobrien}; 17152284Sobrien 17252284Sobrienstruct protox nsprotox[] = { 17352284Sobrien { N_IDP, N_IDPSTAT, 1, nsprotopr, 17452284Sobrien idp_stats, "idp" }, 17552284Sobrien { N_IDP, N_SPPSTAT, 1, nsprotopr, 17652284Sobrien spp_stats, "spp" }, 17752284Sobrien { -1, N_NSERR, 1, 0, 17852284Sobrien nserr_stats, "ns_err" }, 17952284Sobrien { -1, -1, 0, 0, 18052284Sobrien 0, 0 } 18152284Sobrien}; 18252284Sobrien 18352284Sobrienstruct protox isoprotox[] = { 18452284Sobrien { ISO_TP, N_TPSTAT, 1, iso_protopr, 18552284Sobrien tp_stats, "tp" }, 186132718Skan { N_CLTP, N_CLTPSTAT, 1, iso_protopr, 18790075Sobrien cltp_stats, "cltp" }, 188132718Skan { -1, N_CLNPSTAT, 1, 0, 189132718Skan clnp_stats, "clnp"}, 19052284Sobrien { -1, N_ESISSTAT, 1, 0, 19152284Sobrien esis_stats, "esis"}, 192132718Skan { -1, -1, 0, 0, 19352284Sobrien 0, 0 } 19452284Sobrien}; 19552284Sobrien 19652284Sobrienstruct protox *protoprotox[] = { protox, ipxprotox, nsprotox, isoprotox, NULL }; 19752284Sobrien 19852284Sobrienstatic void printproto __P((struct protox *, char *)); 19952284Sobrienstatic void usage __P((void)); 20090075Sobrienstatic struct protox *name2protox __P((char *)); 20152284Sobrienstatic struct protox *knownname __P((char *)); 20252284Sobrien 20352284Sobrienkvm_t *kvmd; 20452284Sobrien 20552284Sobrienint 20652284Sobrienmain(argc, argv) 20752284Sobrien int argc; 20852284Sobrien char *argv[]; 20952284Sobrien{ 21052284Sobrien extern char *optarg; 21152284Sobrien extern int optind; 21252284Sobrien register struct protoent *p; 21352284Sobrien register struct protox *tp; /* for printing cblocks & stats */ 21452284Sobrien register char *cp; 21552284Sobrien int ch; 21652284Sobrien char *nlistf = NULL, *memf = NULL; 21752284Sobrien char buf[_POSIX2_LINE_MAX]; 21852284Sobrien char buf2[_POSIX2_LINE_MAX]; 21952284Sobrien 22052284Sobrien if (cp = rindex(argv[0], '/')) 22152284Sobrien prog = cp + 1; 22252284Sobrien else 22352284Sobrien prog = argv[0]; 22452284Sobrien af = AF_UNSPEC; 22552284Sobrien 22690075Sobrien while ((ch = getopt(argc, argv, "Aabdf:ghI:iM:mN:np:rstuw:")) != EOF) 22752284Sobrien switch(ch) { 22852284Sobrien case 'A': 22952284Sobrien Aflag = 1; 23052284Sobrien break; 23152284Sobrien case 'a': 23252284Sobrien aflag = 1; 23352284Sobrien break; 23452284Sobrien case 'b': 235117395Skan bflag = 1; 236117395Skan break; 237117395Skan case 'd': 238117395Skan dflag = 1; 239117395Skan break; 240117395Skan case 'f': 241132718Skan if (strcmp(optarg, "ns") == 0) 242132718Skan af = AF_NS; 243132718Skan else if (strcmp(optarg, "ipx") == 0) 244132718Skan af = AF_IPX; 245132718Skan else if (strcmp(optarg, "inet") == 0) 246132718Skan af = AF_INET; 247132718Skan else if (strcmp(optarg, "unix") == 0) 248132718Skan af = AF_UNIX; 249132718Skan else if (strcmp(optarg, "iso") == 0) 250132718Skan af = AF_ISO; 251132718Skan else { 252132718Skan errx(1, "%s: unknown address family", optarg); 253132718Skan } 254132718Skan break; 255132718Skan case 'g': 256132718Skan gflag = 1; 257132718Skan break; 258132718Skan case 'I': { 259132718Skan char *cp; 260132718Skan 261132718Skan iflag = 1; 262132718Skan for (cp = interface = optarg; isalpha(*cp); cp++) 26396263Sobrien continue; 26452284Sobrien unit = atoi(cp); 265117395Skan break; 26652284Sobrien } 26752284Sobrien case 'i': 26852284Sobrien iflag = 1; 26952284Sobrien break; 27052284Sobrien case 'M': 27152284Sobrien memf = optarg; 27252284Sobrien break; 27390075Sobrien case 'm': 27452284Sobrien mflag = 1; 27552284Sobrien break; 27690075Sobrien case 'N': 27752284Sobrien nlistf = optarg; 27852284Sobrien break; 27952284Sobrien case 'n': 28052284Sobrien nflag = 1; 28190075Sobrien break; 28252284Sobrien case 'p': 28352284Sobrien if ((tp = name2protox(optarg)) == NULL) { 28452284Sobrien errx(1, 28552284Sobrien "%s: unknown or uninstrumented protocol", 28652284Sobrien optarg); 28752284Sobrien } 28852284Sobrien pflag = 1; 28952284Sobrien break; 29052284Sobrien case 'r': 29152284Sobrien rflag = 1; 29252284Sobrien break; 29352284Sobrien case 's': 29452284Sobrien ++sflag; 29590075Sobrien break; 29652284Sobrien case 't': 29752284Sobrien tflag = 1; 29852284Sobrien break; 29952284Sobrien case 'u': 30052284Sobrien af = AF_UNIX; 30152284Sobrien break; 30252284Sobrien case 'w': 30352284Sobrien interval = atoi(optarg); 30452284Sobrien iflag = 1; 30552284Sobrien break; 30652284Sobrien case '?': 30752284Sobrien default: 30852284Sobrien usage(); 30952284Sobrien } 31052284Sobrien argv += optind; 31152284Sobrien argc -= optind; 31252284Sobrien 31390075Sobrien#define BACKWARD_COMPATIBILITY 31490075Sobrien#ifdef BACKWARD_COMPATIBILITY 31552284Sobrien if (*argv) { 31652284Sobrien if (isdigit(**argv)) { 31752284Sobrien interval = atoi(*argv); 31852284Sobrien if (interval <= 0) 31952284Sobrien usage(); 32052284Sobrien ++argv; 32152284Sobrien iflag = 1; 32252284Sobrien } 32352284Sobrien if (*argv) { 32452284Sobrien nlistf = *argv; 32552284Sobrien if (*++argv) 32652284Sobrien memf = *argv; 327117395Skan } 32852284Sobrien } 329117395Skan#endif 330117395Skan 331117395Skan /* 332117395Skan * Discard setgid privileges if not the running kernel so that bad 33352284Sobrien * guys can't print interesting stuff from kernel memory. 33452284Sobrien */ 33552284Sobrien if (nlistf != NULL || memf != NULL) 33652284Sobrien setgid(getgid()); 33790075Sobrien 33852284Sobrien kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf); 339169689Skan if (kvmd == NULL) { 340169689Skan errx(1, "kvm_open: %s", buf); 34152284Sobrien } 342132718Skan if (kvm_nlist(kvmd, nl) < 0) { 343117395Skan if(nlistf) 344169689Skan errx(1, "%s: kvm_nlist: %s", nlistf, kvm_geterr(kvmd)); 34552284Sobrien else 34652284Sobrien errx(1, "kvm_nlist: %s", kvm_geterr(kvmd)); 34796263Sobrien } 34852284Sobrien 34990075Sobrien if (nl[0].n_type == 0) { 35090075Sobrien if(nlistf) 35152284Sobrien errx(1, "%s: no namelist", nlistf); 35290075Sobrien else 35352284Sobrien errx(1, "no namelist"); 35452284Sobrien } 35590075Sobrien if (mflag) { 35652284Sobrien mbpr(nl[N_MBSTAT].n_value); 35752284Sobrien exit(0); 358132718Skan } 35996263Sobrien if (pflag) { 36096263Sobrien if (tp->pr_stats) 36196263Sobrien (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 36296263Sobrien tp->pr_name); 36396263Sobrien else 36496263Sobrien printf("%s: no stats routine\n", tp->pr_name); 36596263Sobrien exit(0); 366 } 367 /* 368 * Keep file descriptors open to avoid overhead 369 * of open/close on each call to get* routines. 370 */ 371 sethostent(1); 372 setnetent(1); 373 if (iflag) { 374 intpr(interval, nl[N_IFNET].n_value); 375 exit(0); 376 } 377 if (rflag) { 378 if (sflag) 379 rt_stats(nl[N_RTSTAT].n_value); 380 else 381 routepr(nl[N_RTREE].n_value); 382 exit(0); 383 } 384 if (gflag) { 385 if (sflag) 386 mrt_stats(nl[N_MRTPROTO].n_value, 387 nl[N_MRTSTAT].n_value); 388 else 389 mroutepr(nl[N_MRTPROTO].n_value, 390 nl[N_MFCTABLE].n_value, 391 nl[N_VIFTABLE].n_value); 392 exit(0); 393 } 394 if (af == AF_INET || af == AF_UNSPEC) { 395 setprotoent(1); 396 setservent(1); 397 /* ugh, this is O(MN) ... why do we do this? */ 398 while (p = getprotoent()) { 399 for (tp = protox; tp->pr_name; tp++) 400 if (strcmp(tp->pr_name, p->p_name) == 0) 401 break; 402 if (tp->pr_name == 0 || tp->pr_wanted == 0) 403 continue; 404 printproto(tp, p->p_name); 405 } 406 endprotoent(); 407 } 408 if (af == AF_IPX || af == AF_UNSPEC) 409 for (tp = ipxprotox; tp->pr_name; tp++) 410 printproto(tp, tp->pr_name); 411 if (af == AF_NS || af == AF_UNSPEC) 412 for (tp = nsprotox; tp->pr_name; tp++) 413 printproto(tp, tp->pr_name); 414 if (af == AF_ISO || af == AF_UNSPEC) 415 for (tp = isoprotox; tp->pr_name; tp++) 416 printproto(tp, tp->pr_name); 417 if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag) 418 unixpr(nl[N_UNIXSW].n_value); 419 exit(0); 420} 421 422/* 423 * Print out protocol statistics or control blocks (per sflag). 424 * If the interface was not specifically requested, and the symbol 425 * is not in the namelist, ignore this one. 426 */ 427static void 428printproto(tp, name) 429 register struct protox *tp; 430 char *name; 431{ 432 void (*pr)(); 433 u_long off; 434 435 if (sflag) { 436 pr = tp->pr_stats; 437 off = nl[tp->pr_sindex].n_value; 438 } else { 439 pr = tp->pr_cblocks; 440 off = nl[tp->pr_index].n_value; 441 } 442 if (pr != NULL && (off || af != AF_UNSPEC)) 443 (*pr)(off, name); 444} 445 446/* 447 * Read kernel memory, return 0 on success. 448 */ 449int 450kread(addr, buf, size) 451 u_long addr; 452 char *buf; 453 int size; 454{ 455 456 if (kvm_read(kvmd, addr, buf, size) != size) { 457 warnx("%s", kvm_geterr(kvmd)); 458 return (-1); 459 } 460 return (0); 461} 462 463char * 464plural(n) 465 int n; 466{ 467 return (n != 1 ? "s" : ""); 468} 469 470char * 471plurales(n) 472 int n; 473{ 474 return (n != 1 ? "es" : ""); 475} 476 477/* 478 * Find the protox for the given "well-known" name. 479 */ 480static struct protox * 481knownname(name) 482 char *name; 483{ 484 struct protox **tpp, *tp; 485 486 for (tpp = protoprotox; *tpp; tpp++) 487 for (tp = *tpp; tp->pr_name; tp++) 488 if (strcmp(tp->pr_name, name) == 0) 489 return (tp); 490 return (NULL); 491} 492 493/* 494 * Find the protox corresponding to name. 495 */ 496static struct protox * 497name2protox(name) 498 char *name; 499{ 500 struct protox *tp; 501 char **alias; /* alias from p->aliases */ 502 struct protoent *p; 503 504 /* 505 * Try to find the name in the list of "well-known" names. If that 506 * fails, check if name is an alias for an Internet protocol. 507 */ 508 if (tp = knownname(name)) 509 return (tp); 510 511 setprotoent(1); /* make protocol lookup cheaper */ 512 while (p = getprotoent()) { 513 /* assert: name not same as p->name */ 514 for (alias = p->p_aliases; *alias; alias++) 515 if (strcmp(name, *alias) == 0) { 516 endprotoent(); 517 return (knownname(p->p_name)); 518 } 519 } 520 endprotoent(); 521 return (NULL); 522} 523 524static void 525usage() 526{ 527 (void)fprintf(stderr, 528"usage: %s [-Aan] [-f address_family] [-M core] [-N system]\n", prog); 529 (void)fprintf(stderr, 530" %s [-bdghimnrs] [-f address_family] [-M core] [-N system]\n", prog); 531 (void)fprintf(stderr, 532" %s [-bdn] [-I interface] [-M core] [-N system] [-w wait]\n", prog); 533 (void)fprintf(stderr, 534" %s [-M core] [-N system] [-p protocol]\n", prog); 535 exit(1); 536} 537