1 /* $NetBSD: main.c,v 1.9 1996/05/07 02:55:02 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.9 1996/05/07 02:55:02 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 af = AF_UNSPEC; 208 209 while ((ch = getopt(argc, argv, "Aadf:ghI:iM:mN:np:rstuw:")) != EOF) 210 switch(ch) { 211 case 'A': 212 Aflag = 1; 213 break; 214 case 'a': 215 aflag = 1; 216 break; 217 case 'd': 218 dflag = 1; 219 break; 220 case 'f': 221 if (strcmp(optarg, "ns") == 0) 222 af = AF_NS; 223 else if (strcmp(optarg, "inet") == 0) 224 af = AF_INET; 225 else if (strcmp(optarg, "unix") == 0) 226 af = AF_UNIX; 227 else if (strcmp(optarg, "iso") == 0) 228 af = AF_ISO; 229 else { 230 (void)fprintf(stderr, 231 "%s: %s: unknown address family\n", 232 __progname, optarg); 233 exit(1); 234 } 235 break; 236 case 'g': 237 gflag = 1; 238 break; 239 case 'I': 240 iflag = 1; 241 interface = optarg; 242 break; 243 case 'i': 244 iflag = 1; 245 break; 246 case 'M': 247 memf = optarg; 248 break; 249 case 'm': 250 mflag = 1; 251 break; 252 case 'N': 253 nlistf = optarg; 254 break; 255 case 'n': 256 nflag = 1; 257 break; 258 case 'p': 259 if ((tp = name2protox(optarg)) == NULL) { 260 (void)fprintf(stderr, 261 "%s: %s: unknown or uninstrumented protocol\n", 262 __progname, optarg); 263 exit(1); 264 } 265 pflag = 1; 266 break; 267 case 'r': 268 rflag = 1; 269 break; 270 case 's': 271 ++sflag; 272 break; 273 case 't': 274 tflag = 1; 275 break; 276 case 'u': 277 af = AF_UNIX; 278 break; 279 case 'w': 280 interval = atoi(optarg); 281 iflag = 1; 282 break; 283 case '?': 284 default: 285 usage(); 286 } 287 argv += optind; 288 argc -= optind; 289 290 #define BACKWARD_COMPATIBILITY 291 #ifdef BACKWARD_COMPATIBILITY 292 if (*argv) { 293 if (isdigit(**argv)) { 294 interval = atoi(*argv); 295 if (interval <= 0) 296 usage(); 297 ++argv; 298 iflag = 1; 299 } 300 if (*argv) { 301 nlistf = *argv; 302 if (*++argv) 303 memf = *argv; 304 } 305 } 306 #endif 307 308 /* 309 * Discard setgid privileges if not the running kernel so that bad 310 * guys can't print interesting stuff from kernel memory. 311 */ 312 if (nlistf != NULL || memf != NULL) 313 setgid(getgid()); 314 315 if ((kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, 316 buf)) == NULL) { 317 fprintf(stderr, "%s: kvm_open: %s\n", __progname, buf); 318 exit(1); 319 } 320 if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) { 321 if (nlistf) 322 fprintf(stderr, "%s: %s: no namelist\n", __progname, 323 nlistf); 324 else 325 fprintf(stderr, "%s: no namelist\n", __progname); 326 exit(1); 327 } 328 if (mflag) { 329 mbpr(nl[N_MBSTAT].n_value); 330 exit(0); 331 } 332 if (pflag) { 333 if (tp->pr_stats) 334 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 335 tp->pr_name); 336 else 337 printf("%s: no stats routine\n", tp->pr_name); 338 exit(0); 339 } 340 /* 341 * Keep file descriptors open to avoid overhead 342 * of open/close on each call to get* routines. 343 */ 344 sethostent(1); 345 setnetent(1); 346 if (iflag) { 347 intpr(interval, nl[N_IFNET].n_value); 348 exit(0); 349 } 350 if (rflag) { 351 if (sflag) 352 rt_stats(nl[N_RTSTAT].n_value); 353 else 354 routepr(nl[N_RTREE].n_value); 355 exit(0); 356 } 357 if (gflag) { 358 if (sflag) 359 mrt_stats(nl[N_MRTPROTO].n_value, 360 nl[N_MRTSTAT].n_value); 361 else 362 mroutepr(nl[N_MRTPROTO].n_value, 363 nl[N_MFCHASHTBL].n_value, 364 nl[N_MFCHASH].n_value, 365 nl[N_VIFTABLE].n_value); 366 exit(0); 367 } 368 if (af == AF_INET || af == AF_UNSPEC) { 369 setprotoent(1); 370 setservent(1); 371 /* ugh, this is O(MN) ... why do we do this? */ 372 while (p = getprotoent()) { 373 for (tp = protox; tp->pr_name; tp++) 374 if (strcmp(tp->pr_name, p->p_name) == 0) 375 break; 376 if (tp->pr_name == 0 || tp->pr_wanted == 0) 377 continue; 378 printproto(tp, p->p_name); 379 } 380 endprotoent(); 381 } 382 if (af == AF_NS || af == AF_UNSPEC) 383 for (tp = nsprotox; tp->pr_name; tp++) 384 printproto(tp, tp->pr_name); 385 if (af == AF_ISO || af == AF_UNSPEC) 386 for (tp = isoprotox; tp->pr_name; tp++) 387 printproto(tp, tp->pr_name); 388 if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag) 389 unixpr(nl[N_UNIXSW].n_value); 390 exit(0); 391 } 392 393 /* 394 * Print out protocol statistics or control blocks (per sflag). 395 * If the interface was not specifically requested, and the symbol 396 * is not in the namelist, ignore this one. 397 */ 398 static void 399 printproto(tp, name) 400 register struct protox *tp; 401 char *name; 402 { 403 void (*pr)(); 404 u_long off; 405 406 if (sflag) { 407 pr = tp->pr_stats; 408 off = nl[tp->pr_sindex].n_value; 409 } else { 410 pr = tp->pr_cblocks; 411 off = nl[tp->pr_index].n_value; 412 } 413 if (pr != NULL && (off || af != AF_UNSPEC)) 414 (*pr)(off, name); 415 } 416 417 /* 418 * Read kernel memory, return 0 on success. 419 */ 420 int 421 kread(addr, buf, size) 422 u_long addr; 423 char *buf; 424 int size; 425 { 426 427 if (kvm_read(kvmd, addr, buf, size) != size) { 428 (void)fprintf(stderr, "%s: %s\n", __progname, 429 kvm_geterr(kvmd)); 430 return (-1); 431 } 432 return (0); 433 } 434 435 char * 436 plural(n) 437 int n; 438 { 439 return (n != 1 ? "s" : ""); 440 } 441 442 char * 443 plurales(n) 444 int n; 445 { 446 return (n != 1 ? "es" : ""); 447 } 448 449 /* 450 * Find the protox for the given "well-known" name. 451 */ 452 static struct protox * 453 knownname(name) 454 char *name; 455 { 456 struct protox **tpp, *tp; 457 458 for (tpp = protoprotox; *tpp; tpp++) 459 for (tp = *tpp; tp->pr_name; tp++) 460 if (strcmp(tp->pr_name, name) == 0) 461 return (tp); 462 return (NULL); 463 } 464 465 /* 466 * Find the protox corresponding to name. 467 */ 468 static struct protox * 469 name2protox(name) 470 char *name; 471 { 472 struct protox *tp; 473 char **alias; /* alias from p->aliases */ 474 struct protoent *p; 475 476 /* 477 * Try to find the name in the list of "well-known" names. If that 478 * fails, check if name is an alias for an Internet protocol. 479 */ 480 if (tp = knownname(name)) 481 return (tp); 482 483 setprotoent(1); /* make protocol lookup cheaper */ 484 while (p = getprotoent()) { 485 /* assert: name not same as p->name */ 486 for (alias = p->p_aliases; *alias; alias++) 487 if (strcmp(name, *alias) == 0) { 488 endprotoent(); 489 return (knownname(p->p_name)); 490 } 491 } 492 endprotoent(); 493 return (NULL); 494 } 495 496 static void 497 usage() 498 { 499 (void)fprintf(stderr, 500 "usage: %s [-Aan] [-f address_family] [-M core] [-N system]\n", __progname); 501 (void)fprintf(stderr, 502 " %s [-ghimnrs] [-f address_family] [-M core] [-N system]\n", __progname); 503 (void)fprintf(stderr, 504 " %s [-n] [-I interface] [-M core] [-N system] [-w wait]\n", __progname); 505 (void)fprintf(stderr, 506 " %s [-M core] [-N system] [-p protocol]\n", __progname); 507 exit(1); 508 } 509