1 /* 2 * Copyright (c) 1983, 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 char copyright[] = 20 "@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\ 21 All rights reserved.\n"; 22 #endif /* not lint */ 23 24 #ifndef lint 25 static char sccsid[] = "@(#)main.c 5.16 (Berkeley) 09/25/89"; 26 #endif /* not lint */ 27 28 #include <sys/param.h> 29 #include <sys/vmmac.h> 30 #include <sys/socket.h> 31 #include <sys/file.h> 32 #include <machine/pte.h> 33 #include <ctype.h> 34 #include <errno.h> 35 #include <netdb.h> 36 #include <nlist.h> 37 #include <stdio.h> 38 #include <paths.h> 39 40 struct nlist nl[] = { 41 #define N_MBSTAT 0 42 { "_mbstat" }, 43 #define N_IPSTAT 1 44 { "_ipstat" }, 45 #define N_TCB 2 46 { "_tcb" }, 47 #define N_TCPSTAT 3 48 { "_tcpstat" }, 49 #define N_UDB 4 50 { "_udb" }, 51 #define N_UDPSTAT 5 52 { "_udpstat" }, 53 #define N_RAWCB 6 54 { "_rawcb" }, 55 #define N_SYSMAP 7 56 { "_Sysmap" }, 57 #define N_SYSSIZE 8 58 { "_Syssize" }, 59 #define N_IFNET 9 60 { "_ifnet" }, 61 #define N_IMP 10 62 { "_imp_softc" }, 63 #define N_RTHOST 11 64 { "_rthost" }, 65 #define N_RTNET 12 66 { "_rtnet" }, 67 #define N_ICMPSTAT 13 68 { "_icmpstat" }, 69 #define N_RTSTAT 14 70 { "_rtstat" }, 71 #define N_NFILE 15 72 { "_nfile" }, 73 #define N_FILE 16 74 { "_file" }, 75 #define N_UNIXSW 17 76 { "_unixsw" }, 77 #define N_RTHASHSIZE 18 78 { "_rthashsize" }, 79 #define N_IDP 19 80 { "_nspcb"}, 81 #define N_IDPSTAT 20 82 { "_idpstat"}, 83 #define N_SPPSTAT 21 84 { "_spp_istat"}, 85 #define N_NSERR 22 86 { "_ns_errstat"}, 87 #define N_CLNPSTAT 23 88 { "_clnp_stat"}, 89 #define IN_TP 24 90 { "_tp_inpcb" }, 91 #define ISO_TP 25 92 { "_tp_isopcb" }, 93 #define ISO_X25 26 94 { "_x25_isopcb" }, 95 #define N_TPSTAT 27 96 { "_tp_stat" }, 97 #define N_X25STAT 28 98 { "_x25_stat" }, 99 #define N_ESISSTAT 29 100 { "_esis_stat"}, 101 #define N_NIMP 30 102 { "_nimp"}, 103 #define N_RTREE 31 104 { "_radix_node_head"}, 105 "", 106 }; 107 108 /* internet protocols */ 109 extern int protopr(); 110 extern int tcp_stats(), udp_stats(), ip_stats(), icmp_stats(); 111 /* ns protocols */ 112 extern int nsprotopr(); 113 extern int spp_stats(), idp_stats(), nserr_stats(); 114 /* iso protocols */ 115 extern int iso_protopr(); 116 extern int tp_stats(), esis_stats(), clnp_stats(); 117 118 #define NULLPROTOX ((struct protox *) 0) 119 struct protox { 120 u_char pr_index; /* index into nlist of cb head */ 121 u_char pr_sindex; /* index into nlist of stat block */ 122 u_char pr_wanted; /* 1 if wanted, 0 otherwise */ 123 int (*pr_cblocks)(); /* control blocks printing routine */ 124 int (*pr_stats)(); /* statistics printing routine */ 125 char *pr_name; /* well-known name */ 126 } protox[] = { 127 { N_TCB, N_TCPSTAT, 1, protopr, 128 tcp_stats, "tcp" }, 129 { N_UDB, N_UDPSTAT, 1, protopr, 130 udp_stats, "udp" }, 131 { IN_TP, N_TPSTAT, 1, protopr, 132 tp_stats, "tpip" }, 133 { -1, N_IPSTAT, 1, 0, 134 ip_stats, "ip" }, 135 { -1, N_ICMPSTAT, 1, 0, 136 icmp_stats, "icmp" }, 137 { -1, -1, 0, 0, 138 0, 0 } 139 }; 140 141 struct protox nsprotox[] = { 142 { N_IDP, N_IDPSTAT, 1, nsprotopr, 143 idp_stats, "idp" }, 144 { N_IDP, N_SPPSTAT, 1, nsprotopr, 145 spp_stats, "spp" }, 146 { -1, N_NSERR, 1, 0, 147 nserr_stats, "ns_err" }, 148 { -1, -1, 0, 0, 149 0, 0 } 150 }; 151 152 struct protox isoprotox[] = { 153 { ISO_TP, N_TPSTAT, 1, iso_protopr, 154 tp_stats, "tp" }, 155 #ifdef notdef 156 { ISO_X25, N_X25STAT, 1, x25_protopr, 157 x25_stats, "x25" }, 158 #endif 159 { -1, N_CLNPSTAT, 1, 0, 160 clnp_stats, "clnp"}, 161 { -1, N_ESISSTAT, 1, 0, 162 esis_stats, "esis"}, 163 { -1, -1, 0, 0, 164 0, 0 } 165 }; 166 167 struct protox *protoprotox[] = { protox, nsprotox, isoprotox, NULLPROTOX }; 168 169 struct pte *Sysmap; 170 171 char *system = _PATH_UNIX; 172 char *kmemf = _PATH_KMEM; 173 int kmem; 174 int kflag; 175 int Aflag; 176 int aflag; 177 int hflag; 178 int iflag; 179 int mflag; 180 int nflag; 181 int pflag; 182 int rflag; 183 int sflag; 184 int tflag; 185 int dflag; 186 int interval; 187 char *interface; 188 int unit; 189 190 int af = AF_UNSPEC; 191 192 extern char *malloc(); 193 extern off_t lseek(); 194 195 main(argc, argv) 196 int argc; 197 char *argv[]; 198 { 199 extern char *optarg; 200 extern int optind; 201 register struct protoent *p; 202 register struct protox *tp; /* for printing cblocks & stats */ 203 struct protox *name2protox(); /* for -p */ 204 int ch; 205 206 while ((ch = getopt(argc, argv, "AI:af:himnp:drstu")) != EOF) 207 switch((char)ch) { 208 case 'A': 209 Aflag++; 210 break; 211 case 'I': { 212 char *cp; 213 214 iflag++; 215 for (cp = interface = optarg; isalpha(*cp); cp++); 216 unit = atoi(cp); 217 *cp = '\0'; 218 break; 219 } 220 case 'a': 221 aflag++; 222 break; 223 case 'd': 224 dflag++; 225 break; 226 case 'f': 227 if (strcmp(optarg, "ns") == 0) 228 af = AF_NS; 229 else if (strcmp(optarg, "inet") == 0) 230 af = AF_INET; 231 else if (strcmp(optarg, "unix") == 0) 232 af = AF_UNIX; 233 else if (strcmp(optarg, "iso") == 0) 234 af = AF_ISO; 235 else { 236 fprintf(stderr, "%s: unknown address family\n", optarg); 237 exit(10); 238 } 239 break; 240 case 'h': 241 hflag++; 242 break; 243 case 'i': 244 iflag++; 245 break; 246 case 'm': 247 mflag++; 248 break; 249 case 'n': 250 nflag++; 251 break; 252 case 'p': 253 if ((tp = name2protox(optarg)) == NULLPROTOX) { 254 fprintf(stderr, "%s: unknown or uninstrumented protocol\n", optarg); 255 exit(10); 256 } 257 pflag++; 258 break; 259 case 'r': 260 rflag++; 261 break; 262 case 's': 263 sflag++; 264 break; 265 case 't': 266 tflag++; 267 break; 268 case 'u': 269 af = AF_UNIX; 270 break; 271 case '?': 272 default: 273 usage(); 274 } 275 argv += optind; 276 argc -= optind; 277 278 if (argc > 0) { 279 if (isdigit(argv[0][0])) { 280 interval = atoi(argv[0]); 281 if (interval <= 0) 282 usage(); 283 argv++, argc--; 284 iflag++; 285 } 286 if (argc > 0) { 287 system = *argv; 288 argv++, argc--; 289 if (argc > 0) { 290 kmemf = *argv; 291 kflag++; 292 } 293 } 294 } 295 if (nlist(system, nl) < 0 || nl[0].n_type == 0) { 296 fprintf(stderr, "%s: no namelist\n", system); 297 exit(1); 298 } 299 kmem = open(kmemf, O_RDONLY); 300 if (kmem < 0) { 301 perror(kmemf); 302 exit(1); 303 } 304 if (kflag) { 305 off_t off; 306 307 Sysmap = (struct pte *) 308 malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte))); 309 if (!Sysmap) { 310 fputs("netstat: can't get memory for Sysmap.\n", stderr); 311 exit(1); 312 } 313 off = nl[N_SYSMAP].n_value & ~KERNBASE; 314 (void)lseek(kmem, off, L_SET); 315 (void)read(kmem, (char *)Sysmap, 316 (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte))); 317 } 318 if (mflag) { 319 mbpr((off_t)nl[N_MBSTAT].n_value); 320 exit(0); 321 } 322 if (pflag) { 323 if (tp->pr_stats) 324 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 325 tp->pr_name); 326 else 327 printf("%s: no stats routine\n", tp->pr_name); 328 exit(0); 329 } 330 if (hflag) { 331 hostpr(nl[N_IMP].n_value, nl[N_NIMP].n_value); 332 exit(0); 333 } 334 /* 335 * Keep file descriptors open to avoid overhead 336 * of open/close on each call to get* routines. 337 */ 338 sethostent(1); 339 setnetent(1); 340 if (iflag) { 341 intpr(interval, nl[N_IFNET].n_value); 342 exit(0); 343 } 344 if (rflag) { 345 if (sflag) 346 rt_stats((off_t)nl[N_RTSTAT].n_value); 347 else 348 routepr((off_t)nl[N_RTHOST].n_value, 349 (off_t)nl[N_RTNET].n_value, 350 (off_t)nl[N_RTHASHSIZE].n_value, 351 (off_t)nl[N_RTREE].n_value); 352 exit(0); 353 } 354 if (af == AF_INET || af == AF_UNSPEC) { 355 setprotoent(1); 356 setservent(1); 357 while (p = getprotoent()) { 358 359 for (tp = protox; tp->pr_name; tp++) 360 if (strcmp(tp->pr_name, p->p_name) == 0) 361 break; 362 if (tp->pr_name == 0 || tp->pr_wanted == 0) 363 continue; 364 if (sflag) { 365 if (tp->pr_stats) 366 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 367 p->p_name); 368 } else 369 if (tp->pr_cblocks) 370 (*tp->pr_cblocks)(nl[tp->pr_index].n_value, 371 p->p_name); 372 } 373 endprotoent(); 374 } 375 if (af == AF_NS || af == AF_UNSPEC) { 376 for (tp = nsprotox; tp->pr_name; tp++) { 377 if (sflag) { 378 if (tp->pr_stats) 379 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 380 tp->pr_name); 381 } else 382 if (tp->pr_cblocks) 383 (*tp->pr_cblocks)(nl[tp->pr_index].n_value, 384 tp->pr_name); 385 } 386 } 387 if (af == AF_ISO || af == AF_UNSPEC) { 388 for (tp = isoprotox; tp->pr_name; tp++) { 389 if (sflag) { 390 if (tp->pr_stats) 391 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 392 tp->pr_name); 393 } else 394 if (tp->pr_cblocks) 395 (*tp->pr_cblocks)(nl[tp->pr_index].n_value, 396 tp->pr_name); 397 } 398 } 399 if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag) 400 unixpr((off_t)nl[N_NFILE].n_value, (off_t)nl[N_FILE].n_value, 401 (struct protosw *)nl[N_UNIXSW].n_value); 402 if (af == AF_UNSPEC && sflag) 403 impstats(nl[N_IMP].n_value, nl[N_NIMP].n_value); 404 exit(0); 405 } 406 407 /* 408 * Seek into the kernel for a value. 409 */ 410 off_t 411 klseek(fd, base, off) 412 int fd, off; 413 off_t base; 414 { 415 if (kflag) { 416 /* get kernel pte */ 417 base &= ~KERNBASE; 418 base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET); 419 } 420 return (lseek(fd, base, off)); 421 } 422 423 char * 424 plural(n) 425 int n; 426 { 427 428 return (n != 1 ? "s" : ""); 429 } 430 431 /* 432 * Find the protox for the given "well-known" name. 433 */ 434 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(NULLPROTOX); 445 } 446 447 /* 448 * Find the protox corresponding to name. 449 */ 450 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(NULLPROTOX); 476 } 477 478 usage() 479 { 480 fputs("usage: netstat [-Aan] [-f address_family] [system] [core]\n [-himnrs] [-f address_family] [system] [core]\n [-n] [-I interface] interval [system] [core]\n", stderr); 481 exit(1); 482 } 483