1 /* $OpenBSD: main.c,v 1.4 1996/08/16 09:29:33 mickey 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.4 1996/08/16 09:29:33 mickey 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 "", 145 }; 146 147 struct protox { 148 u_char pr_index; /* index into nlist of cb head */ 149 u_char pr_sindex; /* index into nlist of stat block */ 150 u_char pr_wanted; /* 1 if wanted, 0 otherwise */ 151 void (*pr_cblocks)(); /* control blocks printing routine */ 152 void (*pr_stats)(); /* statistics printing routine */ 153 char *pr_name; /* well-known name */ 154 } protox[] = { 155 { N_TCBTABLE, N_TCPSTAT, 1, protopr, 156 tcp_stats, "tcp" }, 157 { N_UDBTABLE, N_UDPSTAT, 1, protopr, 158 udp_stats, "udp" }, 159 { -1, N_IPSTAT, 1, 0, 160 ip_stats, "ip" }, 161 { -1, N_ICMPSTAT, 1, 0, 162 icmp_stats, "icmp" }, 163 { -1, N_IGMPSTAT, 1, 0, 164 igmp_stats, "igmp" }, 165 { -1, -1, 0, 0, 166 0, 0 } 167 }; 168 169 struct protox ipxprotox[] = { 170 { N_IPX, N_IPXSTAT, 1, ipxprotopr, 171 ipx_stats, "ipx" }, 172 { N_IPX, N_SPXSTAT, 1, ipxprotopr, 173 spx_stats, "spx" }, 174 { -1, N_IPXERR, 1, 0, 175 ipxerr_stats, "ipx_err" }, 176 { -1, -1, 0, 0, 177 0, 0 } 178 }; 179 180 struct protox nsprotox[] = { 181 { N_IDP, N_IDPSTAT, 1, nsprotopr, 182 idp_stats, "idp" }, 183 { N_IDP, N_SPPSTAT, 1, nsprotopr, 184 spp_stats, "spp" }, 185 { -1, N_NSERR, 1, 0, 186 nserr_stats, "ns_err" }, 187 { -1, -1, 0, 0, 188 0, 0 } 189 }; 190 191 struct protox isoprotox[] = { 192 { ISO_TP, N_TPSTAT, 1, iso_protopr, 193 tp_stats, "tp" }, 194 { N_CLTP, N_CLTPSTAT, 1, iso_protopr, 195 cltp_stats, "cltp" }, 196 { -1, N_CLNPSTAT, 1, 0, 197 clnp_stats, "clnp"}, 198 { -1, N_ESISSTAT, 1, 0, 199 esis_stats, "esis"}, 200 { -1, -1, 0, 0, 201 0, 0 } 202 }; 203 204 struct protox *protoprotox[] = { protox, ipxprotox, nsprotox, isoprotox, NULL }; 205 206 static void printproto __P((struct protox *, char *)); 207 static void usage __P((void)); 208 static struct protox *name2protox __P((char *)); 209 static struct protox *knownname __P((char *)); 210 211 kvm_t *kvmd; 212 213 int 214 main(argc, argv) 215 int argc; 216 char *argv[]; 217 { 218 extern char *optarg; 219 extern int optind; 220 register struct protoent *p; 221 register struct protox *tp; /* for printing cblocks & stats */ 222 register char *cp; 223 int ch; 224 char *nlistf = NULL, *memf = NULL; 225 char buf[_POSIX2_LINE_MAX]; 226 227 af = AF_UNSPEC; 228 229 while ((ch = getopt(argc, argv, "Aadf:ghI:iM:mN:np:rstuw:")) != EOF) 230 switch(ch) { 231 case 'A': 232 Aflag = 1; 233 break; 234 case 'a': 235 aflag = 1; 236 break; 237 case 'd': 238 dflag = 1; 239 break; 240 case 'f': 241 if (strcmp(optarg, "inet") == 0) 242 af = AF_INET; 243 else if (strcmp(optarg, "unix") == 0) 244 af = AF_UNIX; 245 else if (strcmp(optarg, "ipx") == 0) 246 af = AF_IPX; 247 else if (strcmp(optarg, "ns") == 0) 248 af = AF_NS; 249 else if (strcmp(optarg, "iso") == 0) 250 af = AF_ISO; 251 else { 252 (void)fprintf(stderr, 253 "%s: %s: unknown address family\n", 254 __progname, optarg); 255 exit(1); 256 } 257 break; 258 case 'g': 259 gflag = 1; 260 break; 261 case 'I': 262 iflag = 1; 263 interface = optarg; 264 break; 265 case 'i': 266 iflag = 1; 267 break; 268 case 'M': 269 memf = optarg; 270 break; 271 case 'm': 272 mflag = 1; 273 break; 274 case 'N': 275 nlistf = optarg; 276 break; 277 case 'n': 278 nflag = 1; 279 break; 280 case 'p': 281 if ((tp = name2protox(optarg)) == NULL) { 282 (void)fprintf(stderr, 283 "%s: %s: unknown or uninstrumented protocol\n", 284 __progname, optarg); 285 exit(1); 286 } 287 pflag = 1; 288 break; 289 case 'r': 290 rflag = 1; 291 break; 292 case 's': 293 ++sflag; 294 break; 295 case 't': 296 tflag = 1; 297 break; 298 case 'u': 299 af = AF_UNIX; 300 break; 301 case 'w': 302 interval = atoi(optarg); 303 iflag = 1; 304 break; 305 case '?': 306 default: 307 usage(); 308 } 309 argv += optind; 310 argc -= optind; 311 312 #define BACKWARD_COMPATIBILITY 313 #ifdef BACKWARD_COMPATIBILITY 314 if (*argv) { 315 if (isdigit(**argv)) { 316 interval = atoi(*argv); 317 if (interval <= 0) 318 usage(); 319 ++argv; 320 iflag = 1; 321 } 322 if (*argv) { 323 nlistf = *argv; 324 if (*++argv) 325 memf = *argv; 326 } 327 } 328 #endif 329 330 /* 331 * Discard setgid privileges if not the running kernel so that bad 332 * guys can't print interesting stuff from kernel memory. 333 */ 334 if (nlistf != NULL || memf != NULL) 335 setgid(getgid()); 336 337 if ((kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, 338 buf)) == NULL) { 339 fprintf(stderr, "%s: kvm_open: %s\n", __progname, buf); 340 exit(1); 341 } 342 if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) { 343 if (nlistf) 344 fprintf(stderr, "%s: %s: no namelist\n", __progname, 345 nlistf); 346 else 347 fprintf(stderr, "%s: no namelist\n", __progname); 348 exit(1); 349 } 350 if (mflag) { 351 mbpr(nl[N_MBSTAT].n_value); 352 exit(0); 353 } 354 if (pflag) { 355 if (tp->pr_stats) 356 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 357 tp->pr_name); 358 else 359 printf("%s: no stats routine\n", tp->pr_name); 360 exit(0); 361 } 362 /* 363 * Keep file descriptors open to avoid overhead 364 * of open/close on each call to get* routines. 365 */ 366 sethostent(1); 367 setnetent(1); 368 if (iflag) { 369 intpr(interval, nl[N_IFNET].n_value); 370 exit(0); 371 } 372 if (rflag) { 373 if (sflag) 374 rt_stats(nl[N_RTSTAT].n_value); 375 else 376 routepr(nl[N_RTREE].n_value); 377 exit(0); 378 } 379 if (gflag) { 380 if (sflag) 381 mrt_stats(nl[N_MRTPROTO].n_value, 382 nl[N_MRTSTAT].n_value); 383 else 384 mroutepr(nl[N_MRTPROTO].n_value, 385 nl[N_MFCHASHTBL].n_value, 386 nl[N_MFCHASH].n_value, 387 nl[N_VIFTABLE].n_value); 388 exit(0); 389 } 390 if (af == AF_INET || af == AF_UNSPEC) { 391 setprotoent(1); 392 setservent(1); 393 /* ugh, this is O(MN) ... why do we do this? */ 394 while (p = getprotoent()) { 395 for (tp = protox; tp->pr_name; tp++) 396 if (strcmp(tp->pr_name, p->p_name) == 0) 397 break; 398 if (tp->pr_name == 0 || tp->pr_wanted == 0) 399 continue; 400 printproto(tp, p->p_name); 401 } 402 endprotoent(); 403 } 404 if (af == AF_IPX || af == AF_UNSPEC) 405 for (tp = ipxprotox; tp->pr_name; tp++) 406 printproto(tp, tp->pr_name); 407 if (af == AF_NS || af == AF_UNSPEC) 408 for (tp = nsprotox; tp->pr_name; tp++) 409 printproto(tp, tp->pr_name); 410 if (af == AF_ISO || af == AF_UNSPEC) 411 for (tp = isoprotox; tp->pr_name; tp++) 412 printproto(tp, tp->pr_name); 413 if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag) 414 unixpr(nl[N_UNIXSW].n_value); 415 exit(0); 416 } 417 418 /* 419 * Print out protocol statistics or control blocks (per sflag). 420 * If the interface was not specifically requested, and the symbol 421 * is not in the namelist, ignore this one. 422 */ 423 static void 424 printproto(tp, name) 425 register struct protox *tp; 426 char *name; 427 { 428 void (*pr)(); 429 u_long off; 430 431 if (sflag) { 432 pr = tp->pr_stats; 433 off = nl[tp->pr_sindex].n_value; 434 } else { 435 pr = tp->pr_cblocks; 436 off = nl[tp->pr_index].n_value; 437 } 438 if (pr != NULL && (off || af != AF_UNSPEC)) 439 (*pr)(off, name); 440 } 441 442 /* 443 * Read kernel memory, return 0 on success. 444 */ 445 int 446 kread(addr, buf, size) 447 u_long addr; 448 char *buf; 449 int size; 450 { 451 452 if (kvm_read(kvmd, addr, buf, size) != size) { 453 (void)fprintf(stderr, "%s: %s\n", __progname, 454 kvm_geterr(kvmd)); 455 return (-1); 456 } 457 return (0); 458 } 459 460 char * 461 plural(n) 462 int n; 463 { 464 return (n != 1 ? "s" : ""); 465 } 466 467 char * 468 plurales(n) 469 int n; 470 { 471 return (n != 1 ? "es" : ""); 472 } 473 474 /* 475 * Find the protox for the given "well-known" name. 476 */ 477 static struct protox * 478 knownname(name) 479 char *name; 480 { 481 struct protox **tpp, *tp; 482 483 for (tpp = protoprotox; *tpp; tpp++) 484 for (tp = *tpp; tp->pr_name; tp++) 485 if (strcmp(tp->pr_name, name) == 0) 486 return (tp); 487 return (NULL); 488 } 489 490 /* 491 * Find the protox corresponding to name. 492 */ 493 static struct protox * 494 name2protox(name) 495 char *name; 496 { 497 struct protox *tp; 498 char **alias; /* alias from p->aliases */ 499 struct protoent *p; 500 501 /* 502 * Try to find the name in the list of "well-known" names. If that 503 * fails, check if name is an alias for an Internet protocol. 504 */ 505 if (tp = knownname(name)) 506 return (tp); 507 508 setprotoent(1); /* make protocol lookup cheaper */ 509 while (p = getprotoent()) { 510 /* assert: name not same as p->name */ 511 for (alias = p->p_aliases; *alias; alias++) 512 if (strcmp(name, *alias) == 0) { 513 endprotoent(); 514 return (knownname(p->p_name)); 515 } 516 } 517 endprotoent(); 518 return (NULL); 519 } 520 521 static void 522 usage() 523 { 524 (void)fprintf(stderr, 525 "usage: %s [-Aan] [-f address_family] [-M core] [-N system]\n", __progname); 526 (void)fprintf(stderr, 527 " %s [-ghimnrs] [-f address_family] [-M core] [-N system]\n", __progname); 528 (void)fprintf(stderr, 529 " %s [-n] [-I interface] [-M core] [-N system] [-w wait]\n", __progname); 530 (void)fprintf(stderr, 531 " %s [-M core] [-N system] [-p protocol]\n", __progname); 532 exit(1); 533 } 534