1 /* $OpenBSD: main.c,v 1.17 1999/03/01 01:28:13 d Exp $ */ 2 /* $NetBSD: main.c,v 1.9 1996/05/07 02:55:02 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 1983, 1988, 1993 6 * Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 char copyright[] = 39 "@(#) Copyright (c) 1983, 1988, 1993\n\ 40 Regents of the University of California. All rights reserved.\n"; 41 #endif /* not lint */ 42 43 #ifndef lint 44 #if 0 45 static char sccsid[] = "from: @(#)main.c 8.4 (Berkeley) 3/1/94"; 46 #else 47 static char *rcsid = "$OpenBSD: main.c,v 1.17 1999/03/01 01:28:13 d Exp $"; 48 #endif 49 #endif /* not lint */ 50 51 #include <sys/param.h> 52 #include <sys/file.h> 53 #include <sys/protosw.h> 54 #include <sys/socket.h> 55 56 #include <netinet/in.h> 57 58 #include <ctype.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_IPX 32 137 { "_ipxcbtable"}, 138 #define N_IPXSTAT 33 139 { "_ipxstat"}, 140 #define N_SPXSTAT 34 141 { "_spx_istat"}, 142 #define N_IPXERR 35 143 { "_ipx_errstat"}, 144 #define N_AHSTAT 36 145 { "_ahstat"}, 146 #define N_ESPSTAT 37 147 { "_espstat"}, 148 #define N_IP4STAT 38 149 { "_ip4stat"}, 150 #define N_DDPSTAT 39 151 { "_ddpstat"}, 152 #define N_DDPCB 40 153 { "_ddpcb"}, 154 { ""}, 155 }; 156 157 struct protox { 158 u_char pr_index; /* index into nlist of cb head */ 159 u_char pr_sindex; /* index into nlist of stat block */ 160 u_char pr_wanted; /* 1 if wanted, 0 otherwise */ 161 void (*pr_cblocks)(); /* control blocks printing routine */ 162 void (*pr_stats)(); /* statistics printing routine */ 163 char *pr_name; /* well-known name */ 164 } protox[] = { 165 { N_TCBTABLE, N_TCPSTAT, 1, protopr, 166 tcp_stats, "tcp" }, 167 { N_UDBTABLE, N_UDPSTAT, 1, protopr, 168 udp_stats, "udp" }, 169 { -1, N_IPSTAT, 1, 0, 170 ip_stats, "ip" }, 171 { -1, N_ICMPSTAT, 1, 0, 172 icmp_stats, "icmp" }, 173 { -1, N_IGMPSTAT, 1, 0, 174 igmp_stats, "igmp" }, 175 { -1, N_AHSTAT, 1, 0, 176 ah_stats, "ah" }, 177 { -1, N_ESPSTAT, 1, 0, 178 esp_stats, "esp" }, 179 { -1, N_IP4STAT, 1, 0, 180 ip4_stats, "ipencap" }, 181 { -1, -1, 0, 0, 182 0, 0 } 183 }; 184 185 struct protox ipxprotox[] = { 186 { N_IPX, N_IPXSTAT, 1, ipxprotopr, 187 ipx_stats, "ipx" }, 188 { N_IPX, N_SPXSTAT, 1, ipxprotopr, 189 spx_stats, "spx" }, 190 { -1, N_IPXERR, 1, 0, 191 ipxerr_stats, "ipx_err" }, 192 { -1, -1, 0, 0, 193 0, 0 } 194 }; 195 196 struct protox nsprotox[] = { 197 { N_IDP, N_IDPSTAT, 1, nsprotopr, 198 idp_stats, "idp" }, 199 { N_IDP, N_SPPSTAT, 1, nsprotopr, 200 spp_stats, "spp" }, 201 { -1, N_NSERR, 1, 0, 202 nserr_stats, "ns_err" }, 203 { -1, -1, 0, 0, 204 0, 0 } 205 }; 206 207 struct protox isoprotox[] = { 208 { ISO_TP, N_TPSTAT, 1, iso_protopr, 209 tp_stats, "tp" }, 210 { N_CLTP, N_CLTPSTAT, 1, iso_protopr, 211 cltp_stats, "cltp" }, 212 { -1, N_CLNPSTAT, 1, 0, 213 clnp_stats, "clnp"}, 214 { -1, N_ESISSTAT, 1, 0, 215 esis_stats, "esis"}, 216 { -1, -1, 0, 0, 217 0, 0 } 218 }; 219 220 struct protox atalkprotox[] = { 221 { N_DDPCB, N_DDPSTAT, 1, atalkprotopr, 222 ddp_stats, "ddp" }, 223 { -1, -1, 0, 0, 224 0, 0 } 225 }; 226 227 struct protox *protoprotox[] = { protox, ipxprotox, nsprotox, isoprotox, atalkprotox, NULL }; 228 229 static void printproto __P((struct protox *, char *)); 230 static void usage __P((void)); 231 static struct protox *name2protox __P((char *)); 232 static struct protox *knownname __P((char *)); 233 234 kvm_t *kvmd; 235 236 int 237 main(argc, argv) 238 int argc; 239 char *argv[]; 240 { 241 extern char *optarg; 242 extern int optind; 243 register struct protoent *p; 244 register struct protox *tp; /* for printing cblocks & stats */ 245 int ch; 246 char *nlistf = NULL, *memf = NULL; 247 char buf[_POSIX2_LINE_MAX]; 248 249 af = AF_UNSPEC; 250 251 while ((ch = getopt(argc, argv, "Aadf:gI:iM:mN:np:rstuvw:")) != -1) 252 switch(ch) { 253 case 'A': 254 Aflag = 1; 255 break; 256 case 'a': 257 aflag = 1; 258 break; 259 case 'd': 260 dflag = 1; 261 break; 262 case 'f': 263 if (strcmp(optarg, "inet") == 0) 264 af = AF_INET; 265 else if (strcmp(optarg, "local") == 0) 266 af = AF_LOCAL; 267 else if (strcmp(optarg, "unix") == 0) 268 af = AF_UNIX; 269 else if (strcmp(optarg, "ipx") == 0) 270 af = AF_IPX; 271 else if (strcmp(optarg, "ns") == 0) 272 af = AF_NS; 273 else if (strcmp(optarg, "iso") == 0) 274 af = AF_ISO; 275 else if (strcmp(optarg, "encap") == 0) 276 af = PF_KEY; 277 else if (strcmp(optarg, "atalk") == 0) 278 af = AF_APPLETALK; 279 else { 280 (void)fprintf(stderr, 281 "%s: %s: unknown address family\n", 282 __progname, optarg); 283 exit(1); 284 } 285 break; 286 case 'g': 287 gflag = 1; 288 break; 289 case 'I': 290 iflag = 1; 291 interface = optarg; 292 break; 293 case 'i': 294 iflag = 1; 295 break; 296 case 'M': 297 memf = optarg; 298 break; 299 case 'm': 300 mflag = 1; 301 break; 302 case 'N': 303 nlistf = optarg; 304 break; 305 case 'n': 306 nflag = 1; 307 break; 308 case 'p': 309 if ((tp = name2protox(optarg)) == NULL) { 310 (void)fprintf(stderr, 311 "%s: %s: unknown or uninstrumented protocol\n", 312 __progname, optarg); 313 exit(1); 314 } 315 pflag = 1; 316 break; 317 case 'r': 318 rflag = 1; 319 break; 320 case 's': 321 ++sflag; 322 break; 323 case 't': 324 tflag = 1; 325 break; 326 case 'u': 327 af = AF_UNIX; 328 break; 329 case 'v': 330 vflag = 1; 331 break; 332 case 'w': 333 interval = atoi(optarg); 334 iflag = 1; 335 break; 336 case '?': 337 default: 338 usage(); 339 } 340 argv += optind; 341 argc -= optind; 342 343 #define BACKWARD_COMPATIBILITY 344 #ifdef BACKWARD_COMPATIBILITY 345 if (*argv) { 346 if (isdigit(**argv)) { 347 interval = atoi(*argv); 348 if (interval <= 0) 349 usage(); 350 ++argv; 351 iflag = 1; 352 } 353 if (*argv) { 354 nlistf = *argv; 355 if (*++argv) 356 memf = *argv; 357 } 358 } 359 #endif 360 361 /* 362 * Discard setgid privileges if not the running kernel so that bad 363 * guys can't print interesting stuff from kernel memory. 364 */ 365 if (nlistf != NULL || memf != NULL) { 366 setegid(getgid()); 367 setgid(getgid()); 368 } 369 370 if ((kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, 371 buf)) == NULL) { 372 fprintf(stderr, "%s: kvm_open: %s\n", __progname, buf); 373 exit(1); 374 } 375 setegid(getgid()); 376 setgid(getgid()); 377 378 if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) { 379 if (nlistf) 380 fprintf(stderr, "%s: %s: no namelist\n", __progname, 381 nlistf); 382 else 383 fprintf(stderr, "%s: no namelist\n", __progname); 384 exit(1); 385 } 386 if (mflag) { 387 mbpr(nl[N_MBSTAT].n_value); 388 exit(0); 389 } 390 if (pflag) { 391 if (tp->pr_stats) 392 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 393 tp->pr_name); 394 else 395 printf("%s: no stats routine\n", tp->pr_name); 396 exit(0); 397 } 398 /* 399 * Keep file descriptors open to avoid overhead 400 * of open/close on each call to get* routines. 401 */ 402 sethostent(1); 403 setnetent(1); 404 if (iflag) { 405 intpr(interval, nl[N_IFNET].n_value); 406 exit(0); 407 } 408 if (rflag) { 409 if (sflag) 410 rt_stats(nl[N_RTSTAT].n_value); 411 else 412 routepr(nl[N_RTREE].n_value); 413 exit(0); 414 } 415 if (gflag) { 416 if (sflag) 417 mrt_stats(nl[N_MRTPROTO].n_value, 418 nl[N_MRTSTAT].n_value); 419 else 420 mroutepr(nl[N_MRTPROTO].n_value, 421 nl[N_MFCHASHTBL].n_value, 422 nl[N_MFCHASH].n_value, 423 nl[N_VIFTABLE].n_value); 424 exit(0); 425 } 426 if (af == AF_INET || af == AF_UNSPEC) { 427 setprotoent(1); 428 setservent(1); 429 /* ugh, this is O(MN) ... why do we do this? */ 430 while ((p = getprotoent())) { 431 for (tp = protox; tp->pr_name; tp++) 432 if (strcmp(tp->pr_name, p->p_name) == 0) 433 break; 434 if (tp->pr_name == 0 || tp->pr_wanted == 0) 435 continue; 436 printproto(tp, p->p_name); 437 } 438 endprotoent(); 439 } 440 if (af == AF_IPX || af == AF_UNSPEC) 441 for (tp = ipxprotox; tp->pr_name; tp++) 442 printproto(tp, tp->pr_name); 443 if (af == AF_NS || af == AF_UNSPEC) 444 for (tp = nsprotox; tp->pr_name; tp++) 445 printproto(tp, tp->pr_name); 446 if (af == AF_ISO || af == AF_UNSPEC) 447 for (tp = isoprotox; tp->pr_name; tp++) 448 printproto(tp, tp->pr_name); 449 if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag) 450 unixpr(nl[N_UNIXSW].n_value); 451 if (af == AF_APPLETALK || af == AF_UNSPEC) 452 for (tp = atalkprotox; tp->pr_name; tp++) 453 printproto(tp, tp->pr_name); 454 exit(0); 455 } 456 457 /* 458 * Print out protocol statistics or control blocks (per sflag). 459 * If the interface was not specifically requested, and the symbol 460 * is not in the namelist, ignore this one. 461 */ 462 static void 463 printproto(tp, name) 464 register struct protox *tp; 465 char *name; 466 { 467 void (*pr)(); 468 u_long off; 469 470 if (sflag) { 471 pr = tp->pr_stats; 472 off = nl[tp->pr_sindex].n_value; 473 } else { 474 pr = tp->pr_cblocks; 475 off = nl[tp->pr_index].n_value; 476 } 477 if (pr != NULL && (off || af != AF_UNSPEC)) 478 (*pr)(off, name); 479 } 480 481 /* 482 * Read kernel memory, return 0 on success. 483 */ 484 int 485 kread(addr, buf, size) 486 u_long addr; 487 char *buf; 488 int size; 489 { 490 491 if (kvm_read(kvmd, addr, buf, size) != size) { 492 (void)fprintf(stderr, "%s: %s\n", __progname, 493 kvm_geterr(kvmd)); 494 return (-1); 495 } 496 return (0); 497 } 498 499 char * 500 plural(n) 501 int n; 502 { 503 return (n != 1 ? "s" : ""); 504 } 505 506 char * 507 plurales(n) 508 int n; 509 { 510 return (n != 1 ? "es" : ""); 511 } 512 513 /* 514 * Find the protox for the given "well-known" name. 515 */ 516 static struct protox * 517 knownname(name) 518 char *name; 519 { 520 struct protox **tpp, *tp; 521 522 for (tpp = protoprotox; *tpp; tpp++) 523 for (tp = *tpp; tp->pr_name; tp++) 524 if (strcmp(tp->pr_name, name) == 0) 525 return (tp); 526 return (NULL); 527 } 528 529 /* 530 * Find the protox corresponding to name. 531 */ 532 static struct protox * 533 name2protox(name) 534 char *name; 535 { 536 struct protox *tp; 537 char **alias; /* alias from p->aliases */ 538 struct protoent *p; 539 540 /* 541 * Try to find the name in the list of "well-known" names. If that 542 * fails, check if name is an alias for an Internet protocol. 543 */ 544 if ((tp = knownname(name))) 545 return (tp); 546 547 setprotoent(1); /* make protocol lookup cheaper */ 548 while ((p = getprotoent())) { 549 /* assert: name not same as p->name */ 550 for (alias = p->p_aliases; *alias; alias++) 551 if (strcmp(name, *alias) == 0) { 552 endprotoent(); 553 return (knownname(p->p_name)); 554 } 555 } 556 endprotoent(); 557 return (NULL); 558 } 559 560 static void 561 usage() 562 { 563 (void)fprintf(stderr, 564 "usage: %s [-Aan] [-f address_family] [-M core] [-N system]\n", __progname); 565 (void)fprintf(stderr, 566 " %s [-gimnrs] [-f address_family] [-M core] [-N system]\n", __progname); 567 (void)fprintf(stderr, 568 " %s [-n] [-I interface] [-M core] [-N system] [-w wait]\n", __progname); 569 (void)fprintf(stderr, 570 " %s [-M core] [-N system] [-p protocol]\n", __progname); 571 exit(1); 572 } 573