1 /* $NetBSD: main.c,v 1.24 1999/09/15 20:12:18 is Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1988, 1993 5 * 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 #include <sys/cdefs.h> 37 #ifndef lint 38 __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993\n\ 39 Regents of the University of California. All rights reserved.\n"); 40 #endif /* not lint */ 41 42 #ifndef lint 43 #if 0 44 static char sccsid[] = "from: @(#)main.c 8.4 (Berkeley) 3/1/94"; 45 #else 46 __RCSID("$NetBSD: main.c,v 1.24 1999/09/15 20:12:18 is Exp $"); 47 #endif 48 #endif /* not lint */ 49 50 #include <sys/param.h> 51 #include <sys/file.h> 52 #include <sys/protosw.h> 53 #include <sys/socket.h> 54 55 #include <netinet/in.h> 56 57 #include <ctype.h> 58 #include <err.h> 59 #include <errno.h> 60 #include <kvm.h> 61 #include <limits.h> 62 #include <netdb.h> 63 #include <nlist.h> 64 #include <paths.h> 65 #include <stdio.h> 66 #include <stdlib.h> 67 #include <string.h> 68 #include <unistd.h> 69 #include "netstat.h" 70 71 struct nlist nl[] = { 72 #define N_MBSTAT 0 73 { "_mbstat" }, 74 #define N_IPSTAT 1 75 { "_ipstat" }, 76 #define N_TCBTABLE 2 77 { "_tcbtable" }, 78 #define N_TCPSTAT 3 79 { "_tcpstat" }, 80 #define N_UDBTABLE 4 81 { "_udbtable" }, 82 #define N_UDPSTAT 5 83 { "_udpstat" }, 84 #define N_IFNET 6 85 { "_ifnet" }, 86 #define N_IMP 7 87 { "_imp_softc" }, 88 #define N_ICMPSTAT 8 89 { "_icmpstat" }, 90 #define N_RTSTAT 9 91 { "_rtstat" }, 92 #define N_UNIXSW 10 93 { "_unixsw" }, 94 #define N_IDP 11 95 { "_nspcb"}, 96 #define N_IDPSTAT 12 97 { "_idpstat"}, 98 #define N_SPPSTAT 13 99 { "_spp_istat"}, 100 #define N_NSERR 14 101 { "_ns_errstat"}, 102 #define N_CLNPSTAT 15 103 { "_clnp_stat"}, 104 #define IN_NOTUSED 16 105 { "_tp_inpcb" }, 106 #define ISO_TP 17 107 { "_tp_refinfo" }, 108 #define N_TPSTAT 18 109 { "_tp_stat" }, 110 #define N_ESISSTAT 19 111 { "_esis_stat"}, 112 #define N_NIMP 20 113 { "_nimp"}, 114 #define N_RTREE 21 115 { "_rt_tables"}, 116 #define N_CLTP 22 117 { "_cltb"}, 118 #define N_CLTPSTAT 23 119 { "_cltpstat"}, 120 #define N_NFILE 24 121 { "_nfile" }, 122 #define N_FILE 25 123 { "_file" }, 124 #define N_IGMPSTAT 26 125 { "_igmpstat" }, 126 #define N_MRTPROTO 27 127 { "_ip_mrtproto" }, 128 #define N_MRTSTAT 28 129 { "_mrtstat" }, 130 #define N_MFCHASHTBL 29 131 { "_mfchashtbl" }, 132 #define N_MFCHASH 30 133 { "_mfchash" }, 134 #define N_VIFTABLE 31 135 { "_viftable" }, 136 #define N_MSIZE 32 137 { "_msize" }, 138 #define N_MCLBYTES 33 139 { "_mclbytes" }, 140 #define N_DDPSTAT 34 141 { "_ddpstat"}, 142 #define N_DDPCB 35 143 { "_ddpcb"}, 144 #define N_MBPOOL 36 145 { "_mbpool" }, 146 #define N_MCLPOOL 37 147 { "_mclpool" }, 148 #define N_DIVPCB 38 149 { "_divcb"}, 150 #define N_DIVSTAT 39 151 { "_divstat"}, 152 #define N_IP6STAT 40 153 { "_ip6stat" }, 154 #define N_TCB6 41 155 { "_tcb6" }, 156 #define N_TCP6STAT 42 157 { "_tcp6stat" }, 158 #define N_UDB6 43 159 { "_udb6" }, 160 #define N_UDP6STAT 44 161 { "_udp6stat" }, 162 #define N_ICMP6STAT 45 163 { "_icmp6stat" }, 164 #define N_IPSECSTAT 46 165 { "_ipsecstat" }, 166 #define N_IPSEC6STAT 47 167 { "_ipsec6stat" }, 168 #define N_PIM6STAT 48 169 { "_pim6stat" }, 170 #define N_MRT6PROTO 49 171 { "_ip6_mrtproto" }, 172 #define N_MRT6STAT 50 173 { "_mrt6stat" }, 174 #define N_MF6CTABLE 51 175 { "_mf6ctable" }, 176 #define N_MIF6TABLE 52 177 { "_mif6table" }, 178 { "" }, 179 }; 180 181 struct protox { 182 u_char pr_index; /* index into nlist of cb head */ 183 u_char pr_sindex; /* index into nlist of stat block */ 184 u_char pr_wanted; /* 1 if wanted, 0 otherwise */ 185 void (*pr_cblocks) /* control blocks printing routine */ 186 __P((u_long, char *)); 187 void (*pr_stats) /* statistics printing routine */ 188 __P((u_long, char *)); 189 void (*pr_dump) /* PCB state dump routine */ 190 __P((u_long)); 191 char *pr_name; /* well-known name */ 192 } protox[] = { 193 { N_TCBTABLE, N_TCPSTAT, 1, protopr, 194 tcp_stats, tcp_dump, "tcp" }, 195 { N_UDBTABLE, N_UDPSTAT, 1, protopr, 196 udp_stats, 0, "udp" }, 197 { -1, N_IPSTAT, 1, 0, 198 ip_stats, 0, "ip" }, 199 { -1, N_ICMPSTAT, 1, 0, 200 icmp_stats, 0, "icmp" }, 201 { -1, N_IGMPSTAT, 1, 0, 202 igmp_stats, 0, "igmp" }, 203 #ifdef IPSEC 204 { -1, N_IPSECSTAT, 1, 0, 205 ipsec_stats, 0, "ipsec" }, 206 #endif 207 { -1, -1, 0, 0, 208 0, 0, 0 } 209 }; 210 211 #ifdef INET6 212 struct protox ip6protox[] = { 213 { -1, N_IP6STAT, 1, 0, 214 ip6_stats, 0, "ip6" }, 215 { -1, N_ICMP6STAT, 1, 0, 216 icmp6_stats, 0, "icmp6" }, 217 #ifdef TCP6 218 { N_TCB6, N_TCP6STAT, 1, ip6protopr, 219 tcp6_stats, tcp6_dump, "tcp6" }, 220 #else 221 { N_TCB6, N_TCP6STAT, 1, ip6protopr, 222 tcp_stats, tcp_dump, "tcp6" }, 223 #endif 224 { N_UDB6, N_UDP6STAT, 1, ip6protopr, 225 udp6_stats, 0, "udp6" }, 226 #ifdef IPSEC 227 { -1, N_IPSEC6STAT, 1, 0, 228 ipsec_stats, 0, "ipsec6" }, 229 #endif 230 { -1, N_PIM6STAT, 1, 0, 231 pim6_stats, 0, "pim6" }, 232 { -1, -1, 0, 0, 233 0, 0, 0 } 234 }; 235 #endif 236 237 #ifndef SMALL 238 struct protox atalkprotox[] = { 239 { N_DDPCB, N_DDPSTAT, 1, atalkprotopr, 240 ddp_stats, 0, "ddp" }, 241 { -1, -1, 0, 0, 242 0, 0 } 243 }; 244 245 struct protox nsprotox[] = { 246 { N_IDP, N_IDPSTAT, 1, nsprotopr, 247 idp_stats, 0, "idp" }, 248 { N_IDP, N_SPPSTAT, 1, nsprotopr, 249 spp_stats, 0, "spp" }, 250 { -1, N_NSERR, 1, 0, 251 nserr_stats, 0, "ns_err" }, 252 { -1, -1, 0, 0, 253 0, 0 } 254 }; 255 256 struct protox isoprotox[] = { 257 { ISO_TP, N_TPSTAT, 1, iso_protopr, 258 tp_stats, 0, "tp" }, 259 { N_CLTP, N_CLTPSTAT, 1, iso_protopr, 260 cltp_stats, 0, "cltp" }, 261 { -1, N_CLNPSTAT, 1, 0, 262 clnp_stats, 0, "clnp"}, 263 { -1, N_ESISSTAT, 1, 0, 264 esis_stats, 0, "esis"}, 265 { -1, -1, 0, 0, 266 0, 0, 0 } 267 }; 268 #endif 269 270 struct protox *protoprotox[] = { protox, 271 #ifdef INET6 272 ip6protox, 273 #endif 274 #ifndef SMALL 275 atalkprotox, nsprotox, isoprotox, 276 #endif 277 NULL }; 278 279 int main __P((int, char *[])); 280 static void printproto __P((struct protox *, char *)); 281 static void usage __P((void)); 282 static struct protox *name2protox __P((char *)); 283 static struct protox *knownname __P((char *)); 284 285 kvm_t *kvmd; 286 287 int 288 main(argc, argv) 289 int argc; 290 char *argv[]; 291 { 292 extern char *optarg; 293 extern int optind; 294 struct protoent *p; 295 struct protox *tp; /* for printing cblocks & stats */ 296 int ch; 297 char *nlistf = NULL, *memf = NULL; 298 char buf[_POSIX2_LINE_MAX], *cp; 299 u_long pcbaddr; 300 gid_t egid = getegid(); 301 302 (void)setegid(getgid()); 303 tp = NULL; 304 af = AF_UNSPEC; 305 pcbaddr = 0; 306 307 while ((ch = getopt(argc, argv, "Aabdf:ghI:LliM:mN:nP:p:rstuvw:")) 308 != -1) 309 switch(ch) { 310 case 'A': 311 Aflag = 1; 312 break; 313 case 'a': 314 aflag = 1; 315 break; 316 case 'b': 317 bflag = 1; 318 break; 319 case 'd': 320 dflag = 1; 321 break; 322 case 'f': 323 if (strcmp(optarg, "ns") == 0) 324 af = AF_NS; 325 else if (strcmp(optarg, "inet") == 0) 326 af = AF_INET; 327 else if (strcmp(optarg, "inet6") == 0) 328 af = AF_INET6; 329 else if (strcmp(optarg, "unix") == 0 330 || strcmp(optarg, "local") == 0) 331 af = AF_LOCAL; 332 else if (strcmp(optarg, "iso") == 0) 333 af = AF_ISO; 334 else if (strcmp(optarg, "atalk") == 0) 335 af = AF_APPLETALK; 336 else 337 errx(1, "%s: unknown address family", 338 optarg); 339 break; 340 #ifndef SMALL 341 case 'g': 342 gflag = 1; 343 break; 344 #endif 345 case 'I': 346 iflag = 1; 347 interface = optarg; 348 break; 349 case 'i': 350 iflag = 1; 351 break; 352 case 'L': 353 Lflag = 1; 354 break; 355 case 'l': 356 lflag = 1; 357 break; 358 case 'M': 359 memf = optarg; 360 break; 361 case 'm': 362 mflag = 1; 363 break; 364 case 'N': 365 nlistf = optarg; 366 break; 367 case 'n': 368 nflag = 1; 369 break; 370 case 'P': 371 pcbaddr = strtoul(optarg, &cp, 16); 372 if (*cp != '\0' || errno == ERANGE) 373 errx(1, "invalid PCB address %s", 374 optarg); 375 Pflag = 1; 376 break; 377 case 'p': 378 if ((tp = name2protox(optarg)) == NULL) 379 errx(1, "%s: unknown or uninstrumented protocol", 380 optarg); 381 pflag = 1; 382 break; 383 case 'r': 384 rflag = 1; 385 break; 386 case 's': 387 ++sflag; 388 break; 389 case 't': 390 tflag = 1; 391 break; 392 case 'u': 393 af = AF_LOCAL; 394 break; 395 case 'v': 396 vflag = 1; 397 break; 398 case 'w': 399 interval = atoi(optarg); 400 iflag = 1; 401 break; 402 case '?': 403 default: 404 usage(); 405 } 406 argv += optind; 407 argc -= optind; 408 409 #define BACKWARD_COMPATIBILITY 410 #ifdef BACKWARD_COMPATIBILITY 411 if (*argv) { 412 if (isdigit(**argv)) { 413 interval = atoi(*argv); 414 if (interval <= 0) 415 usage(); 416 ++argv; 417 iflag = 1; 418 } 419 if (*argv) { 420 nlistf = *argv; 421 if (*++argv) 422 memf = *argv; 423 } 424 } 425 #endif 426 427 /* 428 * Discard setgid privileges. If not the running kernel, we toss 429 * them away totally so that bad guys can't print interesting stuff 430 * from kernel memory, otherwise switch back to kmem for the 431 * duration of the kvm_openfiles() call. 432 */ 433 if (nlistf != NULL || memf != NULL || Pflag) 434 (void)setgid(getgid()); 435 else 436 (void)setegid(egid); 437 438 if ((kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, 439 buf)) == NULL) 440 errx(1, "%s", buf); 441 442 /* do this now anyway */ 443 if (nlistf == NULL && memf == NULL) 444 (void)setgid(getgid()); 445 446 if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) { 447 if (nlistf) 448 errx(1, "%s: no namelist", nlistf); 449 else 450 errx(1, "no namelist"); 451 } 452 if (mflag) { 453 mbpr(nl[N_MBSTAT].n_value, nl[N_MSIZE].n_value, 454 nl[N_MCLBYTES].n_value, nl[N_MBPOOL].n_value, 455 nl[N_MCLPOOL].n_value); 456 exit(0); 457 } 458 if (Pflag) { 459 if (tp == NULL) { 460 /* Default to TCP. */ 461 tp = name2protox("tcp"); 462 } 463 if (tp->pr_dump) 464 (*tp->pr_dump)(pcbaddr); 465 else 466 printf("%s: no PCB dump routine\n", tp->pr_name); 467 exit(0); 468 } 469 if (pflag) { 470 if (tp->pr_stats) 471 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 472 tp->pr_name); 473 else 474 printf("%s: no stats routine\n", tp->pr_name); 475 exit(0); 476 } 477 /* 478 * Keep file descriptors open to avoid overhead 479 * of open/close on each call to get* routines. 480 */ 481 sethostent(1); 482 setnetent(1); 483 if (iflag) { 484 intpr(interval, nl[N_IFNET].n_value); 485 exit(0); 486 } 487 if (rflag) { 488 if (sflag) 489 rt_stats(nl[N_RTSTAT].n_value); 490 else 491 routepr(nl[N_RTREE].n_value); 492 exit(0); 493 } 494 #ifndef SMALL 495 if (gflag) { 496 if (sflag) { 497 if (af == AF_INET || af == AF_UNSPEC) 498 mrt_stats(nl[N_MRTPROTO].n_value, 499 nl[N_MRTSTAT].n_value); 500 #ifdef INET6 501 if (af == AF_INET6 || af == AF_UNSPEC) 502 mrt6_stats(nl[N_MRT6PROTO].n_value, 503 nl[N_MRT6STAT].n_value); 504 #endif 505 } 506 else { 507 if (af == AF_INET || af == AF_UNSPEC) 508 mroutepr(nl[N_MRTPROTO].n_value, 509 nl[N_MFCHASHTBL].n_value, 510 nl[N_MFCHASH].n_value, 511 nl[N_VIFTABLE].n_value); 512 #ifdef INET6 513 if (af == AF_INET6 || af == AF_UNSPEC) 514 mroute6pr(nl[N_MRT6PROTO].n_value, 515 nl[N_MF6CTABLE].n_value, 516 nl[N_MIF6TABLE].n_value); 517 #endif 518 } 519 exit(0); 520 } 521 #endif 522 if (af == AF_INET || af == AF_UNSPEC) { 523 setprotoent(1); 524 setservent(1); 525 /* ugh, this is O(MN) ... why do we do this? */ 526 while ((p = getprotoent()) != NULL) { 527 for (tp = protox; tp->pr_name; tp++) 528 if (strcmp(tp->pr_name, p->p_name) == 0) 529 break; 530 if (tp->pr_name == 0 || tp->pr_wanted == 0) 531 continue; 532 printproto(tp, p->p_name); 533 tp->pr_wanted = 0; 534 } 535 endprotoent(); 536 for (tp = protox; tp->pr_name; tp++) 537 if (tp->pr_wanted) 538 printproto(tp, tp->pr_name); 539 } 540 #ifdef INET6 541 if (af == AF_INET6 || af == AF_UNSPEC) 542 for (tp = ip6protox; tp->pr_name; tp++) 543 printproto(tp, tp->pr_name); 544 #endif 545 #ifndef SMALL 546 if (af == AF_APPLETALK || af == AF_UNSPEC) 547 for (tp = atalkprotox; tp->pr_name; tp++) 548 printproto(tp, tp->pr_name); 549 if (af == AF_NS || af == AF_UNSPEC) 550 for (tp = nsprotox; tp->pr_name; tp++) 551 printproto(tp, tp->pr_name); 552 if (af == AF_ISO || af == AF_UNSPEC) 553 for (tp = isoprotox; tp->pr_name; tp++) 554 printproto(tp, tp->pr_name); 555 if ((af == AF_LOCAL || af == AF_UNSPEC) && !sflag) 556 unixpr(nl[N_UNIXSW].n_value); 557 #endif 558 exit(0); 559 } 560 561 /* 562 * Print out protocol statistics or control blocks (per sflag). 563 * If the interface was not specifically requested, and the symbol 564 * is not in the namelist, ignore this one. 565 */ 566 static void 567 printproto(tp, name) 568 struct protox *tp; 569 char *name; 570 { 571 void (*pr) __P((u_long, char *)); 572 u_long off; 573 574 if (sflag) { 575 pr = tp->pr_stats; 576 off = nl[tp->pr_sindex].n_value; 577 } else { 578 pr = tp->pr_cblocks; 579 off = nl[tp->pr_index].n_value; 580 } 581 if (pr != NULL && (off || af != AF_UNSPEC)) 582 (*pr)(off, name); 583 } 584 585 /* 586 * Read kernel memory, return 0 on success. 587 */ 588 int 589 kread(addr, buf, size) 590 u_long addr; 591 char *buf; 592 int size; 593 { 594 595 if (kvm_read(kvmd, addr, buf, size) != size) { 596 warnx("%s\n", kvm_geterr(kvmd)); 597 return (-1); 598 } 599 return (0); 600 } 601 602 char * 603 plural(n) 604 int n; 605 { 606 607 return (n != 1 ? "s" : ""); 608 } 609 610 char * 611 plurales(n) 612 int n; 613 { 614 615 return (n != 1 ? "es" : ""); 616 } 617 618 /* 619 * Find the protox for the given "well-known" name. 620 */ 621 static struct protox * 622 knownname(name) 623 char *name; 624 { 625 struct protox **tpp, *tp; 626 627 for (tpp = protoprotox; *tpp; tpp++) 628 for (tp = *tpp; tp->pr_name; tp++) 629 if (strcmp(tp->pr_name, name) == 0) 630 return (tp); 631 return (NULL); 632 } 633 634 /* 635 * Find the protox corresponding to name. 636 */ 637 static struct protox * 638 name2protox(name) 639 char *name; 640 { 641 struct protox *tp; 642 char **alias; /* alias from p->aliases */ 643 struct protoent *p; 644 645 /* 646 * Try to find the name in the list of "well-known" names. If that 647 * fails, check if name is an alias for an Internet protocol. 648 */ 649 if ((tp = knownname(name)) != NULL) 650 return (tp); 651 652 setprotoent(1); /* make protocol lookup cheaper */ 653 while ((p = getprotoent()) != NULL) { 654 /* assert: name not same as p->name */ 655 for (alias = p->p_aliases; *alias; alias++) 656 if (strcmp(name, *alias) == 0) { 657 endprotoent(); 658 return (knownname(p->p_name)); 659 } 660 } 661 endprotoent(); 662 return (NULL); 663 } 664 665 static void 666 usage() 667 { 668 (void)fprintf(stderr, 669 "usage: %s [-Aan] [-f address_family] [-M core] [-N system]\n", __progname); 670 (void)fprintf(stderr, 671 " %s [-gimnrsv] [-f address_family] [-M core] [-N system]\n", 672 __progname); 673 (void)fprintf(stderr, 674 " %s [-n] [-I interface] [-M core] [-N system] [-w wait]\n", __progname); 675 (void)fprintf(stderr, 676 " %s [-M core] [-N system] [-p protocol]\n", __progname); 677 (void)fprintf(stderr, 678 " %s [-M core] [-N system] [-p protocol] -P pcbaddr\n", __progname); 679 exit(1); 680 } 681