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