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