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