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