main.c revision 1590
1/* 2 * Copyright (c) 1983, 1988, 1993 3 * Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35char copyright[] = 36"@(#) Copyright (c) 1983, 1988, 1993\n\ 37 Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 3/1/94"; 42#endif /* not lint */ 43 44#include <sys/param.h> 45#include <sys/file.h> 46#include <sys/protosw.h> 47#include <sys/socket.h> 48 49#include <netinet/in.h> 50 51#include <ctype.h> 52#include <errno.h> 53#include <kvm.h> 54#include <limits.h> 55#include <netdb.h> 56#include <nlist.h> 57#include <paths.h> 58#include <stdio.h> 59#include <stdlib.h> 60#include <string.h> 61#include <unistd.h> 62#include "netstat.h" 63 64struct nlist nl[] = { 65#define N_MBSTAT 0 66 { "_mbstat" }, 67#define N_IPSTAT 1 68 { "_ipstat" }, 69#define N_TCB 2 70 { "_tcb" }, 71#define N_TCPSTAT 3 72 { "_tcpstat" }, 73#define N_UDB 4 74 { "_udb" }, 75#define N_UDPSTAT 5 76 { "_udpstat" }, 77#define N_IFNET 6 78 { "_ifnet" }, 79#define N_IMP 7 80 { "_imp_softc" }, 81#define N_ICMPSTAT 8 82 { "_icmpstat" }, 83#define N_RTSTAT 9 84 { "_rtstat" }, 85#define N_UNIXSW 10 86 { "_unixsw" }, 87#define N_IDP 11 88 { "_nspcb"}, 89#define N_IDPSTAT 12 90 { "_idpstat"}, 91#define N_SPPSTAT 13 92 { "_spp_istat"}, 93#define N_NSERR 14 94 { "_ns_errstat"}, 95#define N_CLNPSTAT 15 96 { "_clnp_stat"}, 97#define IN_NOTUSED 16 98 { "_tp_inpcb" }, 99#define ISO_TP 17 100 { "_tp_refinfo" }, 101#define N_TPSTAT 18 102 { "_tp_stat" }, 103#define N_ESISSTAT 19 104 { "_esis_stat"}, 105#define N_NIMP 20 106 { "_nimp"}, 107#define N_RTREE 21 108 { "_rt_tables"}, 109#define N_CLTP 22 110 { "_cltb"}, 111#define N_CLTPSTAT 23 112 { "_cltpstat"}, 113#define N_NFILE 24 114 { "_nfile" }, 115#define N_FILE 25 116 { "_file" }, 117#define N_IGMPSTAT 26 118 { "_igmpstat" }, 119#define N_MRTPROTO 27 120 { "_ip_mrtproto" }, 121#define N_MRTSTAT 28 122 { "_mrtstat" }, 123#define N_MRTTABLE 29 124 { "_mrttable" }, 125#define N_VIFTABLE 30 126 { "_viftable" }, 127 "", 128}; 129 130struct protox { 131 u_char pr_index; /* index into nlist of cb head */ 132 u_char pr_sindex; /* index into nlist of stat block */ 133 u_char pr_wanted; /* 1 if wanted, 0 otherwise */ 134 void (*pr_cblocks)(); /* control blocks printing routine */ 135 void (*pr_stats)(); /* statistics printing routine */ 136 char *pr_name; /* well-known name */ 137} protox[] = { 138 { N_TCB, N_TCPSTAT, 1, protopr, 139 tcp_stats, "tcp" }, 140 { N_UDB, N_UDPSTAT, 1, protopr, 141 udp_stats, "udp" }, 142 { -1, N_IPSTAT, 1, 0, 143 ip_stats, "ip" }, 144 { -1, N_ICMPSTAT, 1, 0, 145 icmp_stats, "icmp" }, 146 { -1, N_IGMPSTAT, 1, 0, 147 igmp_stats, "igmp" }, 148 { -1, -1, 0, 0, 149 0, 0 } 150}; 151 152struct protox nsprotox[] = { 153 { N_IDP, N_IDPSTAT, 1, nsprotopr, 154 idp_stats, "idp" }, 155 { N_IDP, N_SPPSTAT, 1, nsprotopr, 156 spp_stats, "spp" }, 157 { -1, N_NSERR, 1, 0, 158 nserr_stats, "ns_err" }, 159 { -1, -1, 0, 0, 160 0, 0 } 161}; 162 163struct protox isoprotox[] = { 164 { ISO_TP, N_TPSTAT, 1, iso_protopr, 165 tp_stats, "tp" }, 166 { N_CLTP, N_CLTPSTAT, 1, iso_protopr, 167 cltp_stats, "cltp" }, 168 { -1, N_CLNPSTAT, 1, 0, 169 clnp_stats, "clnp"}, 170 { -1, N_ESISSTAT, 1, 0, 171 esis_stats, "esis"}, 172 { -1, -1, 0, 0, 173 0, 0 } 174}; 175 176struct protox *protoprotox[] = { protox, nsprotox, isoprotox, NULL }; 177 178static void printproto __P((struct protox *, char *)); 179static void usage __P((void)); 180static struct protox *name2protox __P((char *)); 181static struct protox *knownname __P((char *)); 182 183kvm_t *kvmd; 184 185int 186main(argc, argv) 187 int argc; 188 char *argv[]; 189{ 190 extern char *optarg; 191 extern int optind; 192 register struct protoent *p; 193 register struct protox *tp; /* for printing cblocks & stats */ 194 register char *cp; 195 int ch; 196 char *nlistf = NULL, *memf = NULL; 197 char buf[_POSIX2_LINE_MAX]; 198 199 if (cp = rindex(argv[0], '/')) 200 prog = cp + 1; 201 else 202 prog = argv[0]; 203 af = AF_UNSPEC; 204 205 while ((ch = getopt(argc, argv, "Aadf:ghI:iM:mN:np:rstuw:")) != EOF) 206 switch(ch) { 207 case 'A': 208 Aflag = 1; 209 break; 210 case 'a': 211 aflag = 1; 212 break; 213 case 'd': 214 dflag = 1; 215 break; 216 case 'f': 217 if (strcmp(optarg, "ns") == 0) 218 af = AF_NS; 219 else if (strcmp(optarg, "inet") == 0) 220 af = AF_INET; 221 else if (strcmp(optarg, "unix") == 0) 222 af = AF_UNIX; 223 else if (strcmp(optarg, "iso") == 0) 224 af = AF_ISO; 225 else { 226 (void)fprintf(stderr, 227 "%s: %s: unknown address family\n", 228 prog, optarg); 229 exit(1); 230 } 231 break; 232 case 'g': 233 gflag = 1; 234 break; 235 case 'I': { 236 char *cp; 237 238 iflag = 1; 239 for (cp = interface = optarg; isalpha(*cp); cp++) 240 continue; 241 unit = atoi(cp); 242 *cp = '\0'; 243 break; 244 } 245 case 'i': 246 iflag = 1; 247 break; 248 case 'M': 249 memf = optarg; 250 break; 251 case 'm': 252 mflag = 1; 253 break; 254 case 'N': 255 nlistf = optarg; 256 break; 257 case 'n': 258 nflag = 1; 259 break; 260 case 'p': 261 if ((tp = name2protox(optarg)) == NULL) { 262 (void)fprintf(stderr, 263 "%s: %s: unknown or uninstrumented protocol\n", 264 prog, optarg); 265 exit(1); 266 } 267 pflag = 1; 268 break; 269 case 'r': 270 rflag = 1; 271 break; 272 case 's': 273 ++sflag; 274 break; 275 case 't': 276 tflag = 1; 277 break; 278 case 'u': 279 af = AF_UNIX; 280 break; 281 case 'w': 282 interval = atoi(optarg); 283 iflag = 1; 284 break; 285 case '?': 286 default: 287 usage(); 288 } 289 argv += optind; 290 argc -= optind; 291 292#define BACKWARD_COMPATIBILITY 293#ifdef BACKWARD_COMPATIBILITY 294 if (*argv) { 295 if (isdigit(**argv)) { 296 interval = atoi(*argv); 297 if (interval <= 0) 298 usage(); 299 ++argv; 300 iflag = 1; 301 } 302 if (*argv) { 303 nlistf = *argv; 304 if (*++argv) 305 memf = *argv; 306 } 307 } 308#endif 309 310 /* 311 * Discard setgid privileges if not the running kernel so that bad 312 * guys can't print interesting stuff from kernel memory. 313 */ 314 if (nlistf != NULL || memf != NULL) 315 setgid(getgid()); 316 317 if ((kvmd = kvm_open(nlistf, memf, NULL, O_RDONLY, prog)) == NULL) { 318 fprintf(stderr, "%s: kvm_open: %s\n", prog, buf); 319 exit(1); 320 } 321 if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) { 322 if (nlistf) 323 fprintf(stderr, "%s: %s: no namelist\n", prog, nlistf); 324 else 325 fprintf(stderr, "%s: no namelist\n", prog); 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_MRTTABLE].n_value, 364 nl[N_VIFTABLE].n_value); 365 exit(0); 366 } 367 if (af == AF_INET || af == AF_UNSPEC) { 368 setprotoent(1); 369 setservent(1); 370 /* ugh, this is O(MN) ... why do we do this? */ 371 while (p = getprotoent()) { 372 for (tp = protox; tp->pr_name; tp++) 373 if (strcmp(tp->pr_name, p->p_name) == 0) 374 break; 375 if (tp->pr_name == 0 || tp->pr_wanted == 0) 376 continue; 377 printproto(tp, p->p_name); 378 } 379 endprotoent(); 380 } 381 if (af == AF_NS || af == AF_UNSPEC) 382 for (tp = nsprotox; tp->pr_name; tp++) 383 printproto(tp, tp->pr_name); 384 if (af == AF_ISO || af == AF_UNSPEC) 385 for (tp = isoprotox; tp->pr_name; tp++) 386 printproto(tp, tp->pr_name); 387 if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag) 388 unixpr(nl[N_UNIXSW].n_value); 389 exit(0); 390} 391 392/* 393 * Print out protocol statistics or control blocks (per sflag). 394 * If the interface was not specifically requested, and the symbol 395 * is not in the namelist, ignore this one. 396 */ 397static void 398printproto(tp, name) 399 register struct protox *tp; 400 char *name; 401{ 402 void (*pr)(); 403 u_long off; 404 405 if (sflag) { 406 pr = tp->pr_stats; 407 off = nl[tp->pr_sindex].n_value; 408 } else { 409 pr = tp->pr_cblocks; 410 off = nl[tp->pr_index].n_value; 411 } 412 if (pr != NULL && (off || af != AF_UNSPEC)) 413 (*pr)(off, name); 414} 415 416/* 417 * Read kernel memory, return 0 on success. 418 */ 419int 420kread(addr, buf, size) 421 u_long addr; 422 char *buf; 423 int size; 424{ 425 426 if (kvm_read(kvmd, addr, buf, size) != size) { 427 /* XXX this duplicates kvm_read's error printout */ 428 (void)fprintf(stderr, "%s: kvm_read %s\n", prog, 429 kvm_geterr(kvmd)); 430 return (-1); 431 } 432 return (0); 433} 434 435char * 436plural(n) 437 int n; 438{ 439 return (n != 1 ? "s" : ""); 440} 441 442char * 443plurales(n) 444 int n; 445{ 446 return (n != 1 ? "es" : ""); 447} 448 449/* 450 * Find the protox for the given "well-known" name. 451 */ 452static struct protox * 453knownname(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 */ 468static struct protox * 469name2protox(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 496static void 497usage() 498{ 499 (void)fprintf(stderr, 500"usage: %s [-Aan] [-f address_family] [-M core] [-N system]\n", prog); 501 (void)fprintf(stderr, 502" %s [-ghimnrs] [-f address_family] [-M core] [-N system]\n", prog); 503 (void)fprintf(stderr, 504" %s [-n] [-I interface] [-M core] [-N system] [-w wait]\n", prog); 505 (void)fprintf(stderr, 506" %s [-M core] [-N system] [-p protocol]\n", prog); 507 exit(1); 508} 509