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 const 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 #if 0 42 static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 3/1/94"; 43 #endif 44 static const char rcsid[] = 45 "$Id$"; 46 #endif /* not lint */ 47 48 #include <sys/param.h> 49 #include <sys/file.h> 50 #include <sys/protosw.h> 51 #include <sys/socket.h> 52 53 #include <netinet/in.h> 54 55 #include <ctype.h> 56 #include <err.h> 57 #include <errno.h> 58 #include <kvm.h> 59 #include <limits.h> 60 #include <netdb.h> 61 #include <nlist.h> 62 #include <paths.h> 63 #include <stdio.h> 64 #include <stdlib.h> 65 #include <string.h> 66 #include <unistd.h> 67 #include "netstat.h" 68 69 struct nlist nl[] = { 70 #define N_MBSTAT 0 71 { "_mbstat" }, 72 #define N_IPSTAT 1 73 { "_ipstat" }, 74 #define N_TCB 2 75 { "_tcb" }, 76 #define N_TCPSTAT 3 77 { "_tcpstat" }, 78 #define N_UDB 4 79 { "_udb" }, 80 #define N_UDPSTAT 5 81 { "_udpstat" }, 82 #define N_IFNET 6 83 { "_ifnet" }, 84 #define N_IMP 7 85 { "_imp_softc" }, 86 #define N_ICMPSTAT 8 87 { "_icmpstat" }, 88 #define N_RTSTAT 9 89 { "_rtstat" }, 90 #define N_UNIXSW 10 91 { "_localsw" }, 92 #define N_IDP 11 93 { "_nspcb"}, 94 #define N_IDPSTAT 12 95 { "_idpstat"}, 96 #define N_SPPSTAT 13 97 { "_spp_istat"}, 98 #define N_NSERR 14 99 { "_ns_errstat"}, 100 #define N_CLNPSTAT 15 101 { "_clnp_stat"}, 102 #define IN_NOTUSED 16 103 { "_tp_inpcb" }, 104 #define ISO_TP 17 105 { "_tp_refinfo" }, 106 #define N_TPSTAT 18 107 { "_tp_stat" }, 108 #define N_ESISSTAT 19 109 { "_esis_stat"}, 110 #define N_NIMP 20 111 { "_nimp"}, 112 #define N_RTREE 21 113 { "_rt_tables"}, 114 #define N_CLTP 22 115 { "_cltb"}, 116 #define N_CLTPSTAT 23 117 { "_cltpstat"}, 118 #define N_NFILE 24 119 { "_nfile" }, 120 #define N_FILE 25 121 { "_file" }, 122 #define N_IGMPSTAT 26 123 { "_igmpstat" }, 124 #define N_MRTPROTO 27 125 { "_ip_mrtproto" }, 126 #define N_MRTSTAT 28 127 { "_mrtstat" }, 128 #define N_MFCTABLE 29 129 { "_mfctable" }, 130 #define N_VIFTABLE 30 131 { "_viftable" }, 132 #define N_IPX 31 133 { "_ipxpcb"}, 134 #define N_IPXSTAT 32 135 { "_ipxstat"}, 136 #define N_SPXSTAT 33 137 { "_spx_istat"}, 138 #define N_DDPSTAT 34 139 { "_ddpstat"}, 140 #define N_DDPCB 35 141 { "_ddpcb"}, 142 #define N_DIVPCB 36 143 { "_divcb"}, 144 #define N_DIVSTAT 37 145 { "_divstat"}, 146 { "" }, 147 }; 148 149 struct protox { 150 u_char pr_index; /* index into nlist of cb head */ 151 u_char pr_sindex; /* index into nlist of stat block */ 152 u_char pr_wanted; /* 1 if wanted, 0 otherwise */ 153 void (*pr_cblocks)(); /* control blocks printing routine */ 154 void (*pr_stats)(); /* statistics printing routine */ 155 char *pr_name; /* well-known name */ 156 } protox[] = { 157 { N_TCB, N_TCPSTAT, 1, protopr, 158 tcp_stats, "tcp" }, 159 { N_UDB, N_UDPSTAT, 1, protopr, 160 udp_stats, "udp" }, 161 { N_DIVPCB, N_DIVSTAT, 1, protopr, 162 NULL, "divert" }, /* no stat structure yet */ 163 { -1, N_IPSTAT, 1, 0, 164 ip_stats, "ip" }, 165 { -1, N_ICMPSTAT, 1, 0, 166 icmp_stats, "icmp" }, 167 { -1, N_IGMPSTAT, 1, 0, 168 igmp_stats, "igmp" }, 169 { -1, -1, 0, 0, 170 0, 0 } 171 }; 172 173 struct protox atalkprotox[] = { 174 { N_DDPCB, N_DDPSTAT, 1, atalkprotopr, 175 ddp_stats, "ddp" }, 176 { -1, -1, 0, 0, 177 0, 0 } 178 }; 179 180 struct protox ipxprotox[] = { 181 { N_IPX, N_IPXSTAT, 1, ipxprotopr, 182 ipx_stats, "ipx" }, 183 { N_IPX, N_SPXSTAT, 1, ipxprotopr, 184 spx_stats, "spx" }, 185 { -1, -1, 0, 0, 186 0, 0 } 187 }; 188 189 #ifdef NS 190 struct protox nsprotox[] = { 191 { N_IDP, N_IDPSTAT, 1, nsprotopr, 192 idp_stats, "idp" }, 193 { N_IDP, N_SPPSTAT, 1, nsprotopr, 194 spp_stats, "spp" }, 195 { -1, N_NSERR, 1, 0, 196 nserr_stats, "ns_err" }, 197 { -1, -1, 0, 0, 198 0, 0 } 199 }; 200 #endif 201 202 #ifdef ISO 203 struct protox isoprotox[] = { 204 { ISO_TP, N_TPSTAT, 1, iso_protopr, 205 tp_stats, "tp" }, 206 { N_CLTP, N_CLTPSTAT, 1, iso_protopr, 207 cltp_stats, "cltp" }, 208 { -1, N_CLNPSTAT, 1, 0, 209 clnp_stats, "clnp"}, 210 { -1, N_ESISSTAT, 1, 0, 211 esis_stats, "esis"}, 212 { -1, -1, 0, 0, 213 0, 0 } 214 }; 215 #endif 216 217 struct protox *protoprotox[] = { protox, ipxprotox, atalkprotox, 218 #ifdef NS 219 nsprotox, 220 #endif 221 #ifdef ISO 222 isoprotox, 223 #endif 224 NULL }; 225 226 static void printproto __P((struct protox *, char *)); 227 static void usage __P((void)); 228 static struct protox *name2protox __P((char *)); 229 static struct protox *knownname __P((char *)); 230 231 kvm_t *kvmd; 232 233 int 234 main(argc, argv) 235 int argc; 236 char *argv[]; 237 { 238 register struct protoent *p; 239 register struct protox *tp; /* for printing cblocks & stats */ 240 int ch; 241 char *nlistf = NULL, *memf = NULL; 242 char buf[_POSIX2_LINE_MAX]; 243 244 af = AF_UNSPEC; 245 246 while ((ch = getopt(argc, argv, "Aabdf:ghI:iM:mN:np:rstuw:")) != -1) 247 switch(ch) { 248 case 'A': 249 Aflag = 1; 250 break; 251 case 'a': 252 aflag = 1; 253 break; 254 case 'b': 255 bflag = 1; 256 break; 257 case 'd': 258 dflag = 1; 259 break; 260 case 'f': 261 #ifdef NS 262 if (strcmp(optarg, "ns") == 0) 263 af = AF_NS; 264 else 265 #endif 266 if (strcmp(optarg, "ipx") == 0) 267 af = AF_IPX; 268 else if (strcmp(optarg, "inet") == 0) 269 af = AF_INET; 270 else if (strcmp(optarg, "unix") == 0) 271 af = AF_UNIX; 272 else if (strcmp(optarg, "atalk") == 0) 273 af = AF_APPLETALK; 274 #ifdef ISO 275 else if (strcmp(optarg, "iso") == 0) 276 af = AF_ISO; 277 #endif 278 else { 279 errx(1, "%s: unknown address family", optarg); 280 } 281 break; 282 case 'g': 283 gflag = 1; 284 break; 285 case 'I': { 286 char *cp; 287 288 iflag = 1; 289 for (cp = interface = optarg; isalpha(*cp); cp++) 290 continue; 291 unit = atoi(cp); 292 break; 293 } 294 case 'i': 295 iflag = 1; 296 break; 297 case 'M': 298 memf = optarg; 299 break; 300 case 'm': 301 mflag = 1; 302 break; 303 case 'N': 304 nlistf = optarg; 305 break; 306 case 'n': 307 nflag = 1; 308 break; 309 case 'p': 310 if ((tp = name2protox(optarg)) == NULL) { 311 errx(1, 312 "%s: unknown or uninstrumented protocol", 313 optarg); 314 } 315 pflag = 1; 316 break; 317 case 'r': 318 rflag = 1; 319 break; 320 case 's': 321 ++sflag; 322 break; 323 case 't': 324 tflag = 1; 325 break; 326 case 'u': 327 af = AF_UNIX; 328 break; 329 case 'w': 330 interval = atoi(optarg); 331 iflag = 1; 332 break; 333 case '?': 334 default: 335 usage(); 336 } 337 argv += optind; 338 argc -= optind; 339 340 #define BACKWARD_COMPATIBILITY 341 #ifdef BACKWARD_COMPATIBILITY 342 if (*argv) { 343 if (isdigit(**argv)) { 344 interval = atoi(*argv); 345 if (interval <= 0) 346 usage(); 347 ++argv; 348 iflag = 1; 349 } 350 if (*argv) { 351 nlistf = *argv; 352 if (*++argv) 353 memf = *argv; 354 } 355 } 356 #endif 357 358 /* 359 * Discard setgid privileges if not the running kernel so that bad 360 * guys can't print interesting stuff from kernel memory. 361 */ 362 if (nlistf != NULL || memf != NULL) 363 setgid(getgid()); 364 365 kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf); 366 if (kvmd == NULL) { 367 errx(1, "kvm_open: %s", buf); 368 } 369 if (kvm_nlist(kvmd, nl) < 0) { 370 if(nlistf) 371 errx(1, "%s: kvm_nlist: %s", nlistf, kvm_geterr(kvmd)); 372 else 373 errx(1, "kvm_nlist: %s", kvm_geterr(kvmd)); 374 } 375 376 if (nl[0].n_type == 0) { 377 if(nlistf) 378 errx(1, "%s: no namelist", nlistf); 379 else 380 errx(1, "no namelist"); 381 } 382 if (mflag) { 383 mbpr(nl[N_MBSTAT].n_value); 384 exit(0); 385 } 386 if (pflag) { 387 if (tp->pr_stats) 388 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 389 tp->pr_name); 390 else 391 printf("%s: no stats routine\n", tp->pr_name); 392 exit(0); 393 } 394 #if 0 395 /* 396 * Keep file descriptors open to avoid overhead 397 * of open/close on each call to get* routines. 398 */ 399 sethostent(1); 400 setnetent(1); 401 #else 402 /* 403 * This does not make sense any more with DNS being default over 404 * the files. Doing a setXXXXent(1) causes a tcp connection to be 405 * used for the queries, which is slower. 406 */ 407 #endif 408 if (iflag) { 409 intpr(interval, nl[N_IFNET].n_value); 410 exit(0); 411 } 412 if (rflag) { 413 if (sflag) 414 rt_stats(nl[N_RTSTAT].n_value); 415 else 416 routepr(nl[N_RTREE].n_value); 417 exit(0); 418 } 419 if (gflag) { 420 if (sflag) 421 mrt_stats(nl[N_MRTPROTO].n_value, 422 nl[N_MRTSTAT].n_value); 423 else 424 mroutepr(nl[N_MRTPROTO].n_value, 425 nl[N_MFCTABLE].n_value, 426 nl[N_VIFTABLE].n_value); 427 exit(0); 428 } 429 if (af == AF_INET || af == AF_UNSPEC) { 430 setprotoent(1); 431 setservent(1); 432 /* ugh, this is O(MN) ... why do we do this? */ 433 while ((p = getprotoent())) { 434 for (tp = protox; tp->pr_name; tp++) 435 if (strcmp(tp->pr_name, p->p_name) == 0) 436 break; 437 if (tp->pr_name == 0 || tp->pr_wanted == 0) 438 continue; 439 printproto(tp, p->p_name); 440 } 441 endprotoent(); 442 } 443 if (af == AF_IPX || af == AF_UNSPEC) 444 for (tp = ipxprotox; tp->pr_name; tp++) 445 printproto(tp, tp->pr_name); 446 if (af == AF_APPLETALK || af == AF_UNSPEC) 447 for (tp = atalkprotox; tp->pr_name; tp++) 448 printproto(tp, tp->pr_name); 449 #ifdef NS 450 if (af == AF_NS || af == AF_UNSPEC) 451 for (tp = nsprotox; tp->pr_name; tp++) 452 printproto(tp, tp->pr_name); 453 #endif 454 #ifdef ISO 455 if (af == AF_ISO || af == AF_UNSPEC) 456 for (tp = isoprotox; tp->pr_name; tp++) 457 printproto(tp, tp->pr_name); 458 #endif 459 if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag) 460 unixpr(nl[N_UNIXSW].n_value); 461 exit(0); 462 } 463 464 /* 465 * Print out protocol statistics or control blocks (per sflag). 466 * If the interface was not specifically requested, and the symbol 467 * is not in the namelist, ignore this one. 468 */ 469 static void 470 printproto(tp, name) 471 register struct protox *tp; 472 char *name; 473 { 474 void (*pr)(); 475 u_long off; 476 477 if (sflag) { 478 pr = tp->pr_stats; 479 off = nl[tp->pr_sindex].n_value; 480 } else { 481 pr = tp->pr_cblocks; 482 off = nl[tp->pr_index].n_value; 483 } 484 if (pr != NULL && (off || af != AF_UNSPEC)) 485 (*pr)(off, name); 486 } 487 488 /* 489 * Read kernel memory, return 0 on success. 490 */ 491 int 492 kread(addr, buf, size) 493 u_long addr; 494 char *buf; 495 int size; 496 { 497 498 if (kvm_read(kvmd, addr, buf, size) != size) { 499 warnx("%s", kvm_geterr(kvmd)); 500 return (-1); 501 } 502 return (0); 503 } 504 505 char * 506 plural(n) 507 int n; 508 { 509 return (n != 1 ? "s" : ""); 510 } 511 512 char * 513 plurales(n) 514 int n; 515 { 516 return (n != 1 ? "es" : ""); 517 } 518 519 /* 520 * Find the protox for the given "well-known" name. 521 */ 522 static struct protox * 523 knownname(name) 524 char *name; 525 { 526 struct protox **tpp, *tp; 527 528 for (tpp = protoprotox; *tpp; tpp++) 529 for (tp = *tpp; tp->pr_name; tp++) 530 if (strcmp(tp->pr_name, name) == 0) 531 return (tp); 532 return (NULL); 533 } 534 535 /* 536 * Find the protox corresponding to name. 537 */ 538 static struct protox * 539 name2protox(name) 540 char *name; 541 { 542 struct protox *tp; 543 char **alias; /* alias from p->aliases */ 544 struct protoent *p; 545 546 /* 547 * Try to find the name in the list of "well-known" names. If that 548 * fails, check if name is an alias for an Internet protocol. 549 */ 550 if ((tp = knownname(name))) 551 return (tp); 552 553 setprotoent(1); /* make protocol lookup cheaper */ 554 while ((p = getprotoent())) { 555 /* assert: name not same as p->name */ 556 for (alias = p->p_aliases; *alias; alias++) 557 if (strcmp(name, *alias) == 0) { 558 endprotoent(); 559 return (knownname(p->p_name)); 560 } 561 } 562 endprotoent(); 563 return (NULL); 564 } 565 566 static void 567 usage() 568 { 569 (void)fprintf(stderr, "%s\n%s\n%s\n%s\n", 570 "usage: netstat [-Aan] [-f address_family] [-M core] [-N system]", 571 " netstat [-bdghimnrs] [-f address_family] [-M core] [-N system]", 572 " netstat [-bdn] [-I interface] [-M core] [-N system] [-w wait]", 573 " netstat [-M core] [-N system] [-p protocol]"); 574 exit(1); 575 } 576 577 void 578 trimdomain(cp) 579 char *cp; 580 { 581 static char domain[MAXHOSTNAMELEN + 1]; 582 static int first = 1; 583 char *s; 584 585 if (first) { 586 first = 0; 587 if (gethostname(domain, MAXHOSTNAMELEN) == 0 && 588 (s = strchr(domain, '.'))) 589 (void) strcpy(domain, s + 1); 590 else 591 domain[0] = 0; 592 } 593 594 if (domain[0]) { 595 while ((cp = strchr(cp, '.'))) { 596 if (!strcasecmp(cp + 1, domain)) { 597 *cp = 0; /* hit it */ 598 break; 599 } else { 600 cp++; 601 } 602 } 603 } 604 } 605 606