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