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