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