main.c revision 142215
1/* 2 * Copyright (c) 1983, 1988, 1993 3 * 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 35char const copyright[] = 36"@(#) Copyright (c) 1983, 1988, 1993\n\ 37 Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#if 0 41#ifndef lint 42static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 3/1/94"; 43#endif /* not lint */ 44#endif 45 46#include <sys/cdefs.h> 47__FBSDID("$FreeBSD: head/usr.bin/netstat/main.c 142215 2005-02-22 13:04:05Z glebius $"); 48 49#include <sys/param.h> 50#include <sys/file.h> 51#include <sys/protosw.h> 52#include <sys/socket.h> 53 54#include <netinet/in.h> 55 56#include <netgraph/ng_socket.h> 57 58#include <ctype.h> 59#include <err.h> 60#include <errno.h> 61#include <kvm.h> 62#include <limits.h> 63#include <netdb.h> 64#include <nlist.h> 65#include <paths.h> 66#include <stdio.h> 67#include <stdlib.h> 68#include <string.h> 69#include <unistd.h> 70#include "netstat.h" 71 72static struct nlist nl[] = { 73#define N_IFNET 0 74 { "_ifnet" }, 75#define N_RTSTAT 1 76 { "_rtstat" }, 77#define N_RTREE 2 78 { "_rt_tables"}, 79#define N_MRTSTAT 3 80 { "_mrtstat" }, 81#define N_MFCTABLE 4 82 { "_mfctable" }, 83#define N_VIFTABLE 5 84 { "_viftable" }, 85#define N_IPX 6 86 { "_ipxpcb_list"}, 87#define N_IPXSTAT 7 88 { "_ipxstat"}, 89#define N_SPXSTAT 8 90 { "_spx_istat"}, 91#define N_DDPSTAT 9 92 { "_ddpstat"}, 93#define N_DDPCB 10 94 { "_ddpcb"}, 95#define N_NGSOCKS 11 96 { "_ngsocklist"}, 97#define N_IP6STAT 12 98 { "_ip6stat" }, 99#define N_ICMP6STAT 13 100 { "_icmp6stat" }, 101#define N_IPSECSTAT 14 102 { "_ipsecstat" }, 103#define N_IPSEC6STAT 15 104 { "_ipsec6stat" }, 105#define N_PIM6STAT 16 106 { "_pim6stat" }, 107#define N_MRT6STAT 17 108 { "_mrt6stat" }, 109#define N_MF6CTABLE 18 110 { "_mf6ctable" }, 111#define N_MIF6TABLE 19 112 { "_mif6table" }, 113#define N_PFKEYSTAT 20 114 { "_pfkeystat" }, 115#define N_MBSTAT 21 116 { "_mbstat" }, 117#define N_MBTYPES 22 118 { "_mbtypes" }, 119#define N_NMBCLUSTERS 23 120 { "_nmbclusters" }, 121#define N_NMBUFS 24 122 { "_nmbufs" }, 123#define N_MBHI 25 124 { "_mbuf_hiwm" }, 125#define N_CLHI 26 126 { "_clust_hiwm" }, 127#define N_NCPUS 27 128 { "_smp_cpus" }, 129#define N_PAGESZ 28 130 { "_pagesize" }, 131#define N_MBPSTAT 29 132 { "_mb_statpcpu" }, 133#define N_RTTRASH 30 134 { "_rttrash" }, 135#define N_MBLO 31 136 { "_mbuf_lowm" }, 137#define N_CLLO 32 138 { "_clust_lowm" }, 139#define N_CARPSTAT 33 140 { "_carpstats" }, 141 { "" }, 142}; 143 144struct protox { 145 u_char pr_index; /* index into nlist of cb head */ 146 u_char pr_sindex; /* index into nlist of stat block */ 147 u_char pr_wanted; /* 1 if wanted, 0 otherwise */ 148 void (*pr_cblocks)(u_long, const char *, int); 149 /* control blocks printing routine */ 150 void (*pr_stats)(u_long, const char *, int); 151 /* statistics printing routine */ 152 void (*pr_istats)(char *); /* per/if statistics printing routine */ 153 const char *pr_name; /* well-known name */ 154 u_long pr_usesysctl; /* non-zero if we use sysctl, not kvm */ 155} protox[] = { 156 { -1, -1, 1, protopr, 157 tcp_stats, NULL, "tcp", IPPROTO_TCP }, 158 { -1, -1, 1, protopr, 159 udp_stats, NULL, "udp", IPPROTO_UDP }, 160 { -1, -1, 1, protopr, 161 NULL, NULL, "divert",IPPROTO_DIVERT }, 162 { -1, -1, 1, protopr, 163 ip_stats, NULL, "ip", IPPROTO_RAW }, 164 { -1, -1, 1, protopr, 165 icmp_stats, NULL, "icmp", IPPROTO_ICMP }, 166 { -1, -1, 1, protopr, 167 igmp_stats, NULL, "igmp", IPPROTO_IGMP }, 168#ifdef IPSEC 169 { -1, N_IPSECSTAT, 1, NULL, 170 ipsec_stats, NULL, "ipsec", 0}, 171#endif 172 { -1, -1, 1, NULL, 173 bdg_stats, NULL, "bdg", 1 /* bridging... */ }, 174 { -1, -1, 1, protopr, 175 pim_stats, NULL, "pim", IPPROTO_PIM }, 176 { -1, N_CARPSTAT, 1, 0, 177 carp_stats, NULL, "carp", 0}, 178 { -1, -1, 0, NULL, 179 NULL, NULL, NULL, 0 } 180}; 181 182#ifdef INET6 183struct protox ip6protox[] = { 184 { -1, -1, 1, protopr, 185 tcp_stats, NULL, "tcp", IPPROTO_TCP }, 186 { -1, -1, 1, protopr, 187 udp_stats, NULL, "udp", IPPROTO_UDP }, 188 { -1, N_IP6STAT, 1, protopr, 189 ip6_stats, ip6_ifstats, "ip6", IPPROTO_RAW }, 190 { -1, N_ICMP6STAT, 1, protopr, 191 icmp6_stats, icmp6_ifstats, "icmp6",IPPROTO_ICMPV6 }, 192#ifdef IPSEC 193 { -1, N_IPSEC6STAT, 1, NULL, 194 ipsec_stats, NULL, "ipsec6",0 }, 195#endif 196#ifdef notyet 197 { -1, N_PIM6STAT, 1, NULL, 198 pim6_stats, NULL, "pim6", 0 }, 199#endif 200 { -1, -1, 1, NULL, 201 rip6_stats, NULL, "rip6", 0 }, 202 { -1, -1, 1, NULL, 203 bdg_stats, NULL, "bdg", 1 /* bridging... */ }, 204 { -1, -1, 0, NULL, 205 NULL, NULL, NULL, 0 } 206}; 207#endif /*INET6*/ 208 209#ifdef IPSEC 210struct protox pfkeyprotox[] = { 211 { -1, N_PFKEYSTAT, 1, NULL, 212 pfkey_stats, NULL, "pfkey", 0 }, 213 { -1, -1, 0, NULL, 214 NULL, NULL, NULL, 0 } 215}; 216#endif 217 218struct protox atalkprotox[] = { 219 { N_DDPCB, N_DDPSTAT, 1, atalkprotopr, 220 ddp_stats, NULL, "ddp", 0 }, 221 { -1, -1, 0, NULL, 222 NULL, NULL, NULL, 0 } 223}; 224 225struct protox netgraphprotox[] = { 226 { N_NGSOCKS, -1, 1, netgraphprotopr, 227 NULL, NULL, "ctrl", 0 }, 228 { N_NGSOCKS, -1, 1, netgraphprotopr, 229 NULL, NULL, "data", 0 }, 230 { -1, -1, 0, NULL, 231 NULL, NULL, NULL, 0 } 232}; 233 234struct protox ipxprotox[] = { 235 { N_IPX, N_IPXSTAT, 1, ipxprotopr, 236 ipx_stats, NULL, "ipx", 0 }, 237 { N_IPX, N_SPXSTAT, 1, ipxprotopr, 238 spx_stats, NULL, "spx", 0 }, 239 { -1, -1, 0, NULL, 240 NULL, NULL, 0, 0 } 241}; 242 243struct protox *protoprotox[] = { 244 protox, 245#ifdef INET6 246 ip6protox, 247#endif 248#ifdef IPSEC 249 pfkeyprotox, 250#endif 251 ipxprotox, atalkprotox, NULL }; 252 253const char *pluralies(int); 254static void printproto(struct protox *, const char *); 255static void usage(void); 256static struct protox *name2protox(char *); 257static struct protox *knownname(char *); 258 259static kvm_t *kvmd; 260static char *nlistf = NULL, *memf = NULL; 261 262int Aflag; /* show addresses of protocol control block */ 263int aflag; /* show all sockets (including servers) */ 264int bflag; /* show i/f total bytes in/out */ 265int dflag; /* show i/f dropped packets */ 266int gflag; /* show group (multicast) routing or stats */ 267int iflag; /* show interfaces */ 268int Lflag; /* show size of listen queues */ 269int mflag; /* show memory stats */ 270int numeric_addr; /* show addresses numerically */ 271int numeric_port; /* show ports numerically */ 272static int pflag; /* show given protocol */ 273int rflag; /* show routing tables (or routing stats) */ 274int sflag; /* show protocol statistics */ 275int tflag; /* show i/f watchdog timers */ 276int Wflag; /* wide display */ 277int zflag; /* zero stats */ 278 279int interval; /* repeat interval for i/f stats */ 280 281char *interface; /* desired i/f for stats, or NULL for all i/fs */ 282int unit; /* unit number for above */ 283 284int af; /* address family */ 285 286int 287main(int argc, char *argv[]) 288{ 289 struct protox *tp = NULL; /* for printing cblocks & stats */ 290 int ch; 291 292 af = AF_UNSPEC; 293 294 while ((ch = getopt(argc, argv, "Aabdf:gI:iLlM:mN:np:rSstuWw:z")) != -1) 295 switch(ch) { 296 case 'A': 297 Aflag = 1; 298 break; 299 case 'a': 300 aflag = 1; 301 break; 302 case 'b': 303 bflag = 1; 304 break; 305 case 'd': 306 dflag = 1; 307 break; 308 case 'f': 309 if (strcmp(optarg, "ipx") == 0) 310 af = AF_IPX; 311 else if (strcmp(optarg, "inet") == 0) 312 af = AF_INET; 313#ifdef INET6 314 else if (strcmp(optarg, "inet6") == 0) 315 af = AF_INET6; 316#endif /*INET6*/ 317#ifdef INET6 318 else if (strcmp(optarg, "pfkey") == 0) 319 af = PF_KEY; 320#endif /*INET6*/ 321 else if (strcmp(optarg, "unix") == 0) 322 af = AF_UNIX; 323 else if (strcmp(optarg, "atalk") == 0) 324 af = AF_APPLETALK; 325 else if (strcmp(optarg, "ng") == 0 326 || strcmp(optarg, "netgraph") == 0) 327 af = AF_NETGRAPH; 328 else if (strcmp(optarg, "link") == 0) 329 af = AF_LINK; 330 else { 331 errx(1, "%s: unknown address family", optarg); 332 } 333 break; 334 case 'g': 335 gflag = 1; 336 break; 337 case 'I': { 338 char *cp; 339 340 iflag = 1; 341 for (cp = interface = optarg; isalpha(*cp); cp++) 342 continue; 343 unit = atoi(cp); 344 break; 345 } 346 case 'i': 347 iflag = 1; 348 break; 349 case 'L': 350 Lflag = 1; 351 break; 352 case 'M': 353 memf = optarg; 354 break; 355 case 'm': 356 mflag = 1; 357 break; 358 case 'N': 359 nlistf = optarg; 360 break; 361 case 'n': 362 numeric_addr = numeric_port = 1; 363 break; 364 case 'p': 365 if ((tp = name2protox(optarg)) == NULL) { 366 errx(1, 367 "%s: unknown or uninstrumented protocol", 368 optarg); 369 } 370 pflag = 1; 371 break; 372 case 'r': 373 rflag = 1; 374 break; 375 case 's': 376 ++sflag; 377 break; 378 case 'S': 379 numeric_addr = 1; 380 break; 381 case 't': 382 tflag = 1; 383 break; 384 case 'u': 385 af = AF_UNIX; 386 break; 387 case 'W': 388 case 'l': 389 Wflag = 1; 390 break; 391 case 'w': 392 interval = atoi(optarg); 393 iflag = 1; 394 break; 395 case 'z': 396 zflag = 1; 397 break; 398 case '?': 399 default: 400 usage(); 401 } 402 argv += optind; 403 argc -= optind; 404 405#define BACKWARD_COMPATIBILITY 406#ifdef BACKWARD_COMPATIBILITY 407 if (*argv) { 408 if (isdigit(**argv)) { 409 interval = atoi(*argv); 410 if (interval <= 0) 411 usage(); 412 ++argv; 413 iflag = 1; 414 } 415 if (*argv) { 416 nlistf = *argv; 417 if (*++argv) 418 memf = *argv; 419 } 420 } 421#endif 422 423 /* 424 * Discard setgid privileges if not the running kernel so that bad 425 * guys can't print interesting stuff from kernel memory. 426 */ 427 if (nlistf != NULL || memf != NULL) 428 setgid(getgid()); 429 430 if (mflag) { 431 if (memf != NULL) { 432 if (kread(0, 0, 0) == 0) 433 mbpr(nl[N_MBSTAT].n_value, 434 nl[N_MBTYPES].n_value, 435 nl[N_NMBCLUSTERS].n_value, 436 nl[N_NMBUFS].n_value, 437 nl[N_MBHI].n_value, 438 nl[N_CLHI].n_value, 439 nl[N_MBLO].n_value, 440 nl[N_CLLO].n_value, 441 nl[N_NCPUS].n_value, 442 nl[N_PAGESZ].n_value, 443 nl[N_MBPSTAT].n_value); 444 } else 445 mbpr(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 446 exit(0); 447 } 448#if 0 449 /* 450 * Keep file descriptors open to avoid overhead 451 * of open/close on each call to get* routines. 452 */ 453 sethostent(1); 454 setnetent(1); 455#else 456 /* 457 * This does not make sense any more with DNS being default over 458 * the files. Doing a setXXXXent(1) causes a tcp connection to be 459 * used for the queries, which is slower. 460 */ 461#endif 462 if (iflag && !sflag) { 463 kread(0, 0, 0); 464 intpr(interval, nl[N_IFNET].n_value, NULL); 465 exit(0); 466 } 467 if (rflag) { 468 kread(0, 0, 0); 469 if (sflag) 470 rt_stats(nl[N_RTSTAT].n_value, nl[N_RTTRASH].n_value); 471 else 472 routepr(nl[N_RTREE].n_value); 473 exit(0); 474 } 475 if (gflag) { 476 kread(0, 0, 0); 477 if (sflag) { 478 if (af == AF_INET || af == AF_UNSPEC) 479 mrt_stats(nl[N_MRTSTAT].n_value); 480#ifdef INET6 481 if (af == AF_INET6 || af == AF_UNSPEC) 482 mrt6_stats(nl[N_MRT6STAT].n_value); 483#endif 484 } else { 485 if (af == AF_INET || af == AF_UNSPEC) 486 mroutepr(nl[N_MFCTABLE].n_value, 487 nl[N_VIFTABLE].n_value); 488#ifdef INET6 489 if (af == AF_INET6 || af == AF_UNSPEC) 490 mroute6pr(nl[N_MF6CTABLE].n_value, 491 nl[N_MIF6TABLE].n_value); 492#endif 493 } 494 ifmalist_dump(); 495 exit(0); 496 } 497 498 kread(0, 0, 0); 499 if (tp) { 500 printproto(tp, tp->pr_name); 501 exit(0); 502 } 503 if (af == AF_INET || af == AF_UNSPEC) 504 for (tp = protox; tp->pr_name; tp++) 505 printproto(tp, tp->pr_name); 506#ifdef INET6 507 if (af == AF_INET6 || af == AF_UNSPEC) 508 for (tp = ip6protox; tp->pr_name; tp++) 509 printproto(tp, tp->pr_name); 510#endif /*INET6*/ 511#ifdef IPSEC 512 if (af == PF_KEY || af == AF_UNSPEC) 513 for (tp = pfkeyprotox; tp->pr_name; tp++) 514 printproto(tp, tp->pr_name); 515#endif /*IPSEC*/ 516 if (af == AF_IPX || af == AF_UNSPEC) { 517 kread(0, 0, 0); 518 for (tp = ipxprotox; tp->pr_name; tp++) 519 printproto(tp, tp->pr_name); 520 } 521 if (af == AF_APPLETALK || af == AF_UNSPEC) 522 for (tp = atalkprotox; tp->pr_name; tp++) 523 printproto(tp, tp->pr_name); 524 if (af == AF_NETGRAPH || af == AF_UNSPEC) 525 for (tp = netgraphprotox; tp->pr_name; tp++) 526 printproto(tp, tp->pr_name); 527 if ((af == AF_UNIX || af == AF_UNSPEC) && !Lflag && !sflag) 528 unixpr(); 529 exit(0); 530} 531 532/* 533 * Print out protocol statistics or control blocks (per sflag). 534 * If the interface was not specifically requested, and the symbol 535 * is not in the namelist, ignore this one. 536 */ 537static void 538printproto(tp, name) 539 struct protox *tp; 540 const char *name; 541{ 542 void (*pr)(u_long, const char *, int); 543 u_long off; 544 545 if (sflag) { 546 if (iflag) { 547 if (tp->pr_istats) 548 intpr(interval, nl[N_IFNET].n_value, 549 tp->pr_istats); 550 else if (pflag) 551 printf("%s: no per-interface stats routine\n", 552 tp->pr_name); 553 return; 554 } 555 else { 556 pr = tp->pr_stats; 557 if (!pr) { 558 if (pflag) 559 printf("%s: no stats routine\n", 560 tp->pr_name); 561 return; 562 } 563 off = tp->pr_usesysctl ? tp->pr_usesysctl 564 : nl[tp->pr_sindex].n_value; 565 } 566 } else { 567 pr = tp->pr_cblocks; 568 if (!pr) { 569 if (pflag) 570 printf("%s: no PCB routine\n", tp->pr_name); 571 return; 572 } 573 off = tp->pr_usesysctl ? tp->pr_usesysctl 574 : nl[tp->pr_index].n_value; 575 } 576 if (pr != NULL && (off || af != AF_UNSPEC)) 577 (*pr)(off, name, af); 578} 579 580/* 581 * Read kernel memory, return 0 on success. 582 */ 583int 584kread(u_long addr, char *buf, int size) 585{ 586 if (kvmd == 0) { 587 /* 588 * XXX. 589 */ 590 kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf); 591 setgid(getgid()); 592 if (kvmd != NULL) { 593 if (kvm_nlist(kvmd, nl) < 0) { 594 if(nlistf) 595 errx(1, "%s: kvm_nlist: %s", nlistf, 596 kvm_geterr(kvmd)); 597 else 598 errx(1, "kvm_nlist: %s", kvm_geterr(kvmd)); 599 } 600 601 if (nl[0].n_type == 0) { 602 if(nlistf) 603 errx(1, "%s: no namelist", nlistf); 604 else 605 errx(1, "no namelist"); 606 } 607 } else { 608 warnx("kvm not available"); 609 return(-1); 610 } 611 } 612 if (!buf) 613 return (0); 614 if (kvm_read(kvmd, addr, buf, size) != size) { 615 warnx("%s", kvm_geterr(kvmd)); 616 return (-1); 617 } 618 return (0); 619} 620 621const char * 622plural(int n) 623{ 624 return (n != 1 ? "s" : ""); 625} 626 627const char * 628plurales(int n) 629{ 630 return (n != 1 ? "es" : ""); 631} 632 633const char * 634pluralies(int n) 635{ 636 return (n != 1 ? "ies" : "y"); 637} 638 639/* 640 * Find the protox for the given "well-known" name. 641 */ 642static struct protox * 643knownname(char *name) 644{ 645 struct protox **tpp, *tp; 646 647 for (tpp = protoprotox; *tpp; tpp++) 648 for (tp = *tpp; tp->pr_name; tp++) 649 if (strcmp(tp->pr_name, name) == 0) 650 return (tp); 651 return (NULL); 652} 653 654/* 655 * Find the protox corresponding to name. 656 */ 657static struct protox * 658name2protox(char *name) 659{ 660 struct protox *tp; 661 char **alias; /* alias from p->aliases */ 662 struct protoent *p; 663 664 /* 665 * Try to find the name in the list of "well-known" names. If that 666 * fails, check if name is an alias for an Internet protocol. 667 */ 668 if ((tp = knownname(name)) != NULL) 669 return (tp); 670 671 setprotoent(1); /* make protocol lookup cheaper */ 672 while ((p = getprotoent()) != NULL) { 673 /* assert: name not same as p->name */ 674 for (alias = p->p_aliases; *alias; alias++) 675 if (strcmp(name, *alias) == 0) { 676 endprotoent(); 677 return (knownname(p->p_name)); 678 } 679 } 680 endprotoent(); 681 return (NULL); 682} 683 684static void 685usage(void) 686{ 687 (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", 688"usage: netstat [-AaLnSW] [-f protocol_family | -p protocol]\n" 689" [-M core] [-N system]", 690" netstat -i | -I interface [-abdnt] [-f address_family]\n" 691" [-M core] [-N system]", 692" netstat -w wait [-I interface] [-d] [-M core] [-N system]", 693" netstat -s [-s] [-z] [-f protocol_family | -p protocol] [-M core]", 694" netstat -i | -I interface -s [-f protocol_family | -p protocol]\n" 695" [-M core] [-N system]", 696" netstat -m [-M core] [-N system]", 697" netstat -r [-AenW] [-f address_family] [-M core] [-N system]", 698" netstat -rs [-s] [-M core] [-N system]", 699" netstat -g [-W] [-f address_family] [-M core] [-N system]", 700" netstat -gs [-s] [-f address_family] [-M core] [-N system]"); 701 exit(1); 702} 703