1 /* $NetBSD: main.c,v 1.8 1995/10/03 21:42:40 thorpej 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 #ifndef lint 37 char copyright[] = 38 "@(#) 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 static char *rcsid = "$NetBSD: main.c,v 1.8 1995/10/03 21:42:40 thorpej 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 <errno.h> 59 #include <kvm.h> 60 #include <limits.h> 61 #include <netdb.h> 62 #include <nlist.h> 63 #include <paths.h> 64 #include <stdio.h> 65 #include <stdlib.h> 66 #include <string.h> 67 #include <unistd.h> 68 #include "netstat.h" 69 70 struct nlist nl[] = { 71 #define N_MBSTAT 0 72 { "_mbstat" }, 73 #define N_IPSTAT 1 74 { "_ipstat" }, 75 #define N_TCBTABLE 2 76 { "_tcbtable" }, 77 #define N_TCPSTAT 3 78 { "_tcpstat" }, 79 #define N_UDBTABLE 4 80 { "_udbtable" }, 81 #define N_UDPSTAT 5 82 { "_udpstat" }, 83 #define N_IFNET 6 84 { "_ifnet" }, 85 #define N_IMP 7 86 { "_imp_softc" }, 87 #define N_ICMPSTAT 8 88 { "_icmpstat" }, 89 #define N_RTSTAT 9 90 { "_rtstat" }, 91 #define N_UNIXSW 10 92 { "_unixsw" }, 93 #define N_IDP 11 94 { "_nspcb"}, 95 #define N_IDPSTAT 12 96 { "_idpstat"}, 97 #define N_SPPSTAT 13 98 { "_spp_istat"}, 99 #define N_NSERR 14 100 { "_ns_errstat"}, 101 #define N_CLNPSTAT 15 102 { "_clnp_stat"}, 103 #define IN_NOTUSED 16 104 { "_tp_inpcb" }, 105 #define ISO_TP 17 106 { "_tp_refinfo" }, 107 #define N_TPSTAT 18 108 { "_tp_stat" }, 109 #define N_ESISSTAT 19 110 { "_esis_stat"}, 111 #define N_NIMP 20 112 { "_nimp"}, 113 #define N_RTREE 21 114 { "_rt_tables"}, 115 #define N_CLTP 22 116 { "_cltb"}, 117 #define N_CLTPSTAT 23 118 { "_cltpstat"}, 119 #define N_NFILE 24 120 { "_nfile" }, 121 #define N_FILE 25 122 { "_file" }, 123 #define N_IGMPSTAT 26 124 { "_igmpstat" }, 125 #define N_MRTPROTO 27 126 { "_ip_mrtproto" }, 127 #define N_MRTSTAT 28 128 { "_mrtstat" }, 129 #define N_MFCHASHTBL 29 130 { "_mfchashtbl" }, 131 #define N_MFCHASH 30 132 { "_mfchash" }, 133 #define N_VIFTABLE 31 134 { "_viftable" }, 135 "", 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)(); /* control blocks printing routine */ 143 void (*pr_stats)(); /* statistics printing routine */ 144 char *pr_name; /* well-known name */ 145 } protox[] = { 146 { N_TCBTABLE, N_TCPSTAT, 1, protopr, 147 tcp_stats, "tcp" }, 148 { N_UDBTABLE, N_UDPSTAT, 1, protopr, 149 udp_stats, "udp" }, 150 { -1, N_IPSTAT, 1, 0, 151 ip_stats, "ip" }, 152 { -1, N_ICMPSTAT, 1, 0, 153 icmp_stats, "icmp" }, 154 { -1, N_IGMPSTAT, 1, 0, 155 igmp_stats, "igmp" }, 156 { -1, -1, 0, 0, 157 0, 0 } 158 }; 159 160 struct protox nsprotox[] = { 161 { N_IDP, N_IDPSTAT, 1, nsprotopr, 162 idp_stats, "idp" }, 163 { N_IDP, N_SPPSTAT, 1, nsprotopr, 164 spp_stats, "spp" }, 165 { -1, N_NSERR, 1, 0, 166 nserr_stats, "ns_err" }, 167 { -1, -1, 0, 0, 168 0, 0 } 169 }; 170 171 struct protox isoprotox[] = { 172 { ISO_TP, N_TPSTAT, 1, iso_protopr, 173 tp_stats, "tp" }, 174 { N_CLTP, N_CLTPSTAT, 1, iso_protopr, 175 cltp_stats, "cltp" }, 176 { -1, N_CLNPSTAT, 1, 0, 177 clnp_stats, "clnp"}, 178 { -1, N_ESISSTAT, 1, 0, 179 esis_stats, "esis"}, 180 { -1, -1, 0, 0, 181 0, 0 } 182 }; 183 184 struct protox *protoprotox[] = { protox, nsprotox, isoprotox, NULL }; 185 186 static void printproto __P((struct protox *, char *)); 187 static void usage __P((void)); 188 static struct protox *name2protox __P((char *)); 189 static struct protox *knownname __P((char *)); 190 191 kvm_t *kvmd; 192 193 int 194 main(argc, argv) 195 int argc; 196 char *argv[]; 197 { 198 extern char *optarg; 199 extern int optind; 200 register struct protoent *p; 201 register struct protox *tp; /* for printing cblocks & stats */ 202 register char *cp; 203 int ch; 204 char *nlistf = NULL, *memf = NULL; 205 char buf[_POSIX2_LINE_MAX]; 206 207 if (cp = rindex(argv[0], '/')) 208 prog = cp + 1; 209 else 210 prog = argv[0]; 211 af = AF_UNSPEC; 212 213 while ((ch = getopt(argc, argv, "Aadf:ghI:iM:mN:np:rstuw:")) != EOF) 214 switch(ch) { 215 case 'A': 216 Aflag = 1; 217 break; 218 case 'a': 219 aflag = 1; 220 break; 221 case 'd': 222 dflag = 1; 223 break; 224 case 'f': 225 if (strcmp(optarg, "ns") == 0) 226 af = AF_NS; 227 else if (strcmp(optarg, "inet") == 0) 228 af = AF_INET; 229 else if (strcmp(optarg, "unix") == 0) 230 af = AF_UNIX; 231 else if (strcmp(optarg, "iso") == 0) 232 af = AF_ISO; 233 else { 234 (void)fprintf(stderr, 235 "%s: %s: unknown address family\n", 236 prog, optarg); 237 exit(1); 238 } 239 break; 240 case 'g': 241 gflag = 1; 242 break; 243 case 'I': { 244 char *cp; 245 246 iflag = 1; 247 for (cp = interface = optarg; isalpha(*cp); cp++) 248 continue; 249 unit = atoi(cp); 250 *cp = '\0'; 251 break; 252 } 253 case 'i': 254 iflag = 1; 255 break; 256 case 'M': 257 memf = optarg; 258 break; 259 case 'm': 260 mflag = 1; 261 break; 262 case 'N': 263 nlistf = optarg; 264 break; 265 case 'n': 266 nflag = 1; 267 break; 268 case 'p': 269 if ((tp = name2protox(optarg)) == NULL) { 270 (void)fprintf(stderr, 271 "%s: %s: unknown or uninstrumented protocol\n", 272 prog, optarg); 273 exit(1); 274 } 275 pflag = 1; 276 break; 277 case 'r': 278 rflag = 1; 279 break; 280 case 's': 281 ++sflag; 282 break; 283 case 't': 284 tflag = 1; 285 break; 286 case 'u': 287 af = AF_UNIX; 288 break; 289 case 'w': 290 interval = atoi(optarg); 291 iflag = 1; 292 break; 293 case '?': 294 default: 295 usage(); 296 } 297 argv += optind; 298 argc -= optind; 299 300 #define BACKWARD_COMPATIBILITY 301 #ifdef BACKWARD_COMPATIBILITY 302 if (*argv) { 303 if (isdigit(**argv)) { 304 interval = atoi(*argv); 305 if (interval <= 0) 306 usage(); 307 ++argv; 308 iflag = 1; 309 } 310 if (*argv) { 311 nlistf = *argv; 312 if (*++argv) 313 memf = *argv; 314 } 315 } 316 #endif 317 318 /* 319 * Discard setgid privileges if not the running kernel so that bad 320 * guys can't print interesting stuff from kernel memory. 321 */ 322 if (nlistf != NULL || memf != NULL) 323 setgid(getgid()); 324 325 if ((kvmd = kvm_open(nlistf, memf, NULL, O_RDONLY, prog)) == NULL) { 326 fprintf(stderr, "%s: kvm_open: %s\n", prog, buf); 327 exit(1); 328 } 329 if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) { 330 if (nlistf) 331 fprintf(stderr, "%s: %s: no namelist\n", prog, nlistf); 332 else 333 fprintf(stderr, "%s: no namelist\n", prog); 334 exit(1); 335 } 336 if (mflag) { 337 mbpr(nl[N_MBSTAT].n_value); 338 exit(0); 339 } 340 if (pflag) { 341 if (tp->pr_stats) 342 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 343 tp->pr_name); 344 else 345 printf("%s: no stats routine\n", tp->pr_name); 346 exit(0); 347 } 348 /* 349 * Keep file descriptors open to avoid overhead 350 * of open/close on each call to get* routines. 351 */ 352 sethostent(1); 353 setnetent(1); 354 if (iflag) { 355 intpr(interval, nl[N_IFNET].n_value); 356 exit(0); 357 } 358 if (rflag) { 359 if (sflag) 360 rt_stats(nl[N_RTSTAT].n_value); 361 else 362 routepr(nl[N_RTREE].n_value); 363 exit(0); 364 } 365 if (gflag) { 366 if (sflag) 367 mrt_stats(nl[N_MRTPROTO].n_value, 368 nl[N_MRTSTAT].n_value); 369 else 370 mroutepr(nl[N_MRTPROTO].n_value, 371 nl[N_MFCHASHTBL].n_value, 372 nl[N_MFCHASH].n_value, 373 nl[N_VIFTABLE].n_value); 374 exit(0); 375 } 376 if (af == AF_INET || af == AF_UNSPEC) { 377 setprotoent(1); 378 setservent(1); 379 /* ugh, this is O(MN) ... why do we do this? */ 380 while (p = getprotoent()) { 381 for (tp = protox; tp->pr_name; tp++) 382 if (strcmp(tp->pr_name, p->p_name) == 0) 383 break; 384 if (tp->pr_name == 0 || tp->pr_wanted == 0) 385 continue; 386 printproto(tp, p->p_name); 387 } 388 endprotoent(); 389 } 390 if (af == AF_NS || af == AF_UNSPEC) 391 for (tp = nsprotox; tp->pr_name; tp++) 392 printproto(tp, tp->pr_name); 393 if (af == AF_ISO || af == AF_UNSPEC) 394 for (tp = isoprotox; tp->pr_name; tp++) 395 printproto(tp, tp->pr_name); 396 if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag) 397 unixpr(nl[N_UNIXSW].n_value); 398 exit(0); 399 } 400 401 /* 402 * Print out protocol statistics or control blocks (per sflag). 403 * If the interface was not specifically requested, and the symbol 404 * is not in the namelist, ignore this one. 405 */ 406 static void 407 printproto(tp, name) 408 register struct protox *tp; 409 char *name; 410 { 411 void (*pr)(); 412 u_long off; 413 414 if (sflag) { 415 pr = tp->pr_stats; 416 off = nl[tp->pr_sindex].n_value; 417 } else { 418 pr = tp->pr_cblocks; 419 off = nl[tp->pr_index].n_value; 420 } 421 if (pr != NULL && (off || af != AF_UNSPEC)) 422 (*pr)(off, name); 423 } 424 425 /* 426 * Read kernel memory, return 0 on success. 427 */ 428 int 429 kread(addr, buf, size) 430 u_long addr; 431 char *buf; 432 int size; 433 { 434 435 if (kvm_read(kvmd, addr, buf, size) != size) { 436 /* XXX this duplicates kvm_read's error printout */ 437 (void)fprintf(stderr, "%s: kvm_read %s\n", prog, 438 kvm_geterr(kvmd)); 439 return (-1); 440 } 441 return (0); 442 } 443 444 char * 445 plural(n) 446 int n; 447 { 448 return (n != 1 ? "s" : ""); 449 } 450 451 char * 452 plurales(n) 453 int n; 454 { 455 return (n != 1 ? "es" : ""); 456 } 457 458 /* 459 * Find the protox for the given "well-known" name. 460 */ 461 static struct protox * 462 knownname(name) 463 char *name; 464 { 465 struct protox **tpp, *tp; 466 467 for (tpp = protoprotox; *tpp; tpp++) 468 for (tp = *tpp; tp->pr_name; tp++) 469 if (strcmp(tp->pr_name, name) == 0) 470 return (tp); 471 return (NULL); 472 } 473 474 /* 475 * Find the protox corresponding to name. 476 */ 477 static struct protox * 478 name2protox(name) 479 char *name; 480 { 481 struct protox *tp; 482 char **alias; /* alias from p->aliases */ 483 struct protoent *p; 484 485 /* 486 * Try to find the name in the list of "well-known" names. If that 487 * fails, check if name is an alias for an Internet protocol. 488 */ 489 if (tp = knownname(name)) 490 return (tp); 491 492 setprotoent(1); /* make protocol lookup cheaper */ 493 while (p = getprotoent()) { 494 /* assert: name not same as p->name */ 495 for (alias = p->p_aliases; *alias; alias++) 496 if (strcmp(name, *alias) == 0) { 497 endprotoent(); 498 return (knownname(p->p_name)); 499 } 500 } 501 endprotoent(); 502 return (NULL); 503 } 504 505 static void 506 usage() 507 { 508 (void)fprintf(stderr, 509 "usage: %s [-Aan] [-f address_family] [-M core] [-N system]\n", prog); 510 (void)fprintf(stderr, 511 " %s [-ghimnrs] [-f address_family] [-M core] [-N system]\n", prog); 512 (void)fprintf(stderr, 513 " %s [-n] [-I interface] [-M core] [-N system] [-w wait]\n", prog); 514 (void)fprintf(stderr, 515 " %s [-M core] [-N system] [-p protocol]\n", prog); 516 exit(1); 517 } 518