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.3 (Berkeley) 01/04/94"; 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, "Aadf:ghI: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 'd': 188 dflag = 1; 189 break; 190 case 'f': 191 if (strcmp(optarg, "ns") == 0) 192 af = AF_NS; 193 else if (strcmp(optarg, "inet") == 0) 194 af = AF_INET; 195 else if (strcmp(optarg, "unix") == 0) 196 af = AF_UNIX; 197 else if (strcmp(optarg, "iso") == 0) 198 af = AF_ISO; 199 else { 200 (void)fprintf(stderr, 201 "%s: %s: unknown address family\n", 202 prog, optarg); 203 exit(1); 204 } 205 break; 206 case 'g': 207 gflag = 1; 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 iflag = 1; 258 break; 259 case '?': 260 default: 261 usage(); 262 } 263 argv += optind; 264 argc -= optind; 265 266 #define BACKWARD_COMPATIBILITY 267 #ifdef BACKWARD_COMPATIBILITY 268 if (*argv) { 269 if (isdigit(**argv)) { 270 interval = atoi(*argv); 271 if (interval <= 0) 272 usage(); 273 ++argv; 274 iflag = 1; 275 } 276 if (*argv) { 277 nlistf = *argv; 278 if (*++argv) 279 memf = *argv; 280 } 281 } 282 #endif 283 284 /* 285 * Discard setgid privileges if not the running kernel so that bad 286 * guys can't print interesting stuff from kernel memory. 287 */ 288 if (nlistf != NULL || memf != NULL) 289 setgid(getgid()); 290 291 if ((kvmd = kvm_open(nlistf, memf, NULL, O_RDONLY, prog)) == NULL) { 292 fprintf(stderr, "%s: kvm_open: %s\n", prog, buf); 293 exit(1); 294 } 295 if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) { 296 if (nlistf) 297 fprintf(stderr, "%s: %s: no namelist\n", prog, nlistf); 298 else 299 fprintf(stderr, "%s: no namelist\n", prog); 300 exit(1); 301 } 302 if (mflag) { 303 mbpr(nl[N_MBSTAT].n_value); 304 exit(0); 305 } 306 if (pflag) { 307 if (tp->pr_stats) 308 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 309 tp->pr_name); 310 else 311 printf("%s: no stats routine\n", tp->pr_name); 312 exit(0); 313 } 314 /* 315 * Keep file descriptors open to avoid overhead 316 * of open/close on each call to get* routines. 317 */ 318 sethostent(1); 319 setnetent(1); 320 if (iflag) { 321 intpr(interval, nl[N_IFNET].n_value); 322 exit(0); 323 } 324 if (rflag) { 325 if (sflag) 326 rt_stats(nl[N_RTSTAT].n_value); 327 else 328 routepr(nl[N_RTREE].n_value); 329 exit(0); 330 } 331 if (gflag) { 332 if (sflag) 333 mrt_stats(nl[N_MRTPROTO].n_value, 334 nl[N_MRTSTAT].n_value); 335 else 336 mroutepr(nl[N_MRTPROTO].n_value, 337 nl[N_MRTTABLE].n_value, 338 nl[N_VIFTABLE].n_value); 339 exit(0); 340 } 341 if (af == AF_INET || af == AF_UNSPEC) { 342 setprotoent(1); 343 setservent(1); 344 /* ugh, this is O(MN) ... why do we do this? */ 345 while (p = getprotoent()) { 346 for (tp = protox; tp->pr_name; tp++) 347 if (strcmp(tp->pr_name, p->p_name) == 0) 348 break; 349 if (tp->pr_name == 0 || tp->pr_wanted == 0) 350 continue; 351 printproto(tp, p->p_name); 352 } 353 endprotoent(); 354 } 355 if (af == AF_NS || af == AF_UNSPEC) 356 for (tp = nsprotox; tp->pr_name; tp++) 357 printproto(tp, tp->pr_name); 358 if (af == AF_ISO || af == AF_UNSPEC) 359 for (tp = isoprotox; tp->pr_name; tp++) 360 printproto(tp, tp->pr_name); 361 if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag) 362 unixpr(nl[N_UNIXSW].n_value); 363 exit(0); 364 } 365 366 /* 367 * Print out protocol statistics or control blocks (per sflag). 368 * If the interface was not specifically requested, and the symbol 369 * is not in the namelist, ignore this one. 370 */ 371 static void 372 printproto(tp, name) 373 register struct protox *tp; 374 char *name; 375 { 376 void (*pr)(); 377 u_long off; 378 379 if (sflag) { 380 pr = tp->pr_stats; 381 off = nl[tp->pr_sindex].n_value; 382 } else { 383 pr = tp->pr_cblocks; 384 off = nl[tp->pr_index].n_value; 385 } 386 if (pr != NULL && (off || af != AF_UNSPEC)) 387 (*pr)(off, name); 388 } 389 390 /* 391 * Read kernel memory, return 0 on success. 392 */ 393 int 394 kread(addr, buf, size) 395 u_long addr; 396 char *buf; 397 int size; 398 { 399 400 if (kvm_read(kvmd, addr, buf, size) != size) { 401 /* XXX this duplicates kvm_read's error printout */ 402 (void)fprintf(stderr, "%s: kvm_read %s\n", prog, 403 kvm_geterr(kvmd)); 404 return (-1); 405 } 406 return (0); 407 } 408 409 char * 410 plural(n) 411 int n; 412 { 413 return (n != 1 ? "s" : ""); 414 } 415 416 char * 417 plurales(n) 418 int n; 419 { 420 return (n != 1 ? "es" : ""); 421 } 422 423 /* 424 * Find the protox for the given "well-known" name. 425 */ 426 static struct protox * 427 knownname(name) 428 char *name; 429 { 430 struct protox **tpp, *tp; 431 432 for (tpp = protoprotox; *tpp; tpp++) 433 for (tp = *tpp; tp->pr_name; tp++) 434 if (strcmp(tp->pr_name, name) == 0) 435 return (tp); 436 return (NULL); 437 } 438 439 /* 440 * Find the protox corresponding to name. 441 */ 442 static struct protox * 443 name2protox(name) 444 char *name; 445 { 446 struct protox *tp; 447 char **alias; /* alias from p->aliases */ 448 struct protoent *p; 449 450 /* 451 * Try to find the name in the list of "well-known" names. If that 452 * fails, check if name is an alias for an Internet protocol. 453 */ 454 if (tp = knownname(name)) 455 return (tp); 456 457 setprotoent(1); /* make protocol lookup cheaper */ 458 while (p = getprotoent()) { 459 /* assert: name not same as p->name */ 460 for (alias = p->p_aliases; *alias; alias++) 461 if (strcmp(name, *alias) == 0) { 462 endprotoent(); 463 return (knownname(p->p_name)); 464 } 465 } 466 endprotoent(); 467 return (NULL); 468 } 469 470 static void 471 usage() 472 { 473 (void)fprintf(stderr, 474 "usage: %s [-Aan] [-f address_family] [-M core] [-N system]\n", prog); 475 (void)fprintf(stderr, 476 " [-ghimnrs] [-f address_family] [-M core] [-N system]\n"); 477 (void)fprintf(stderr, 478 " [-n] [-I interface] [-M core] [-N system] [-w wait]\n"); 479 (void)fprintf(stderr, 480 " [-M core] [-N system] [-p protocol]\n"); 481 exit(1); 482 } 483