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.27 (Berkeley) 01/27/92"; 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_NOTUSED 16 65 { "_tp_inpcb" }, 66 #define ISO_TP 17 67 { "_tp_refinfo" }, 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 { -1, N_IPSTAT, 1, 0, 110 ip_stats, "ip" }, 111 { -1, N_ICMPSTAT, 1, 0, 112 icmp_stats, "icmp" }, 113 { -1, -1, 0, 0, 114 0, 0 } 115 }; 116 117 struct protox nsprotox[] = { 118 { N_IDP, N_IDPSTAT, 1, nsprotopr, 119 idp_stats, "idp" }, 120 { N_IDP, N_SPPSTAT, 1, nsprotopr, 121 spp_stats, "spp" }, 122 { -1, N_NSERR, 1, 0, 123 nserr_stats, "ns_err" }, 124 { -1, -1, 0, 0, 125 0, 0 } 126 }; 127 128 struct protox isoprotox[] = { 129 { ISO_TP, N_TPSTAT, 1, iso_protopr, 130 tp_stats, "tp" }, 131 { N_CLTP, N_CLTPSTAT, 1, iso_protopr, 132 cltp_stats, "cltp" }, 133 { -1, N_CLNPSTAT, 1, 0, 134 clnp_stats, "clnp"}, 135 { -1, N_ESISSTAT, 1, 0, 136 esis_stats, "esis"}, 137 { -1, -1, 0, 0, 138 0, 0 } 139 }; 140 141 struct protox *protoprotox[] = { protox, nsprotox, isoprotox, NULL }; 142 143 char *nlistf; 144 char *memf; 145 int kmem; 146 int kflag; 147 int Aflag; 148 int aflag; 149 int hflag; 150 int iflag; 151 int mflag; 152 int nflag; 153 int pflag; 154 int rflag; 155 int sflag; 156 int tflag; 157 int dflag; 158 int interval; 159 char *interface; 160 int unit; 161 162 int af = AF_UNSPEC; 163 164 main(argc, argv) 165 int argc; 166 char **argv; 167 { 168 extern char *optarg; 169 extern int optind; 170 register struct protoent *p; 171 register struct protox *tp; /* for printing cblocks & stats */ 172 struct protox *name2protox(); /* for -p */ 173 int ch; 174 void usage(); 175 176 while ((ch = getopt(argc, argv, "Aadf:hI:iM:mN:np:rstuw")) != EOF) 177 switch((char)ch) { 178 case 'A': 179 Aflag = 1; 180 break; 181 case 'a': 182 aflag = 1; 183 break; 184 case 'd': 185 dflag = 1; 186 break; 187 case 'f': 188 if (strcmp(optarg, "ns") == 0) 189 af = AF_NS; 190 else if (strcmp(optarg, "inet") == 0) 191 af = AF_INET; 192 else if (strcmp(optarg, "unix") == 0) 193 af = AF_UNIX; 194 else if (strcmp(optarg, "iso") == 0) 195 af = AF_ISO; 196 else { 197 (void)fprintf(stderr, 198 "%s: unknown address family\n", optarg); 199 exit(1); 200 } 201 break; 202 case 'h': 203 hflag = 1; 204 break; 205 case 'I': { 206 char *cp; 207 208 iflag = 1; 209 for (cp = interface = optarg; isalpha(*cp); cp++); 210 unit = atoi(cp); 211 *cp = '\0'; 212 break; 213 } 214 case 'i': 215 iflag = 1; 216 break; 217 case 'M': 218 memf = optarg; 219 kflag = 1; 220 break; 221 case 'm': 222 mflag = 1; 223 break; 224 case 'N': 225 nlistf = optarg; 226 break; 227 case 'n': 228 nflag = 1; 229 break; 230 case 'p': 231 if ((tp = name2protox(optarg)) == NULL) { 232 (void)fprintf(stderr, 233 "%s: unknown or uninstrumented protocol\n", 234 optarg); 235 exit(1); 236 } 237 pflag = 1; 238 break; 239 case 'r': 240 rflag = 1; 241 break; 242 case 's': 243 sflag = 1; 244 break; 245 case 't': 246 tflag = 1; 247 break; 248 case 'u': 249 af = AF_UNIX; 250 break; 251 case 'w': 252 interval = atoi(optarg); 253 break; 254 case '?': 255 default: 256 usage(); 257 } 258 argv += optind; 259 argc -= optind; 260 261 #define BACKWARD_COMPATIBILITY 262 #ifdef BACKWARD_COMPATIBILITY 263 if (*argv) { 264 if (isdigit(**argv)) { 265 interval = atoi(*argv); 266 if (interval <= 0) 267 usage(); 268 ++argv; 269 iflag = 1; 270 } 271 if (*argv) { 272 nlistf = *argv; 273 if (*++argv) { 274 memf = *argv; 275 kflag = 1; 276 } 277 } 278 } 279 #endif 280 /* 281 * Discard setgid privileges if not the running kernel so that bad 282 * guys can't print interesting stuff from kernel memory. 283 */ 284 if (nlistf != NULL || memf != NULL) 285 setgid(getgid()); 286 287 if (kvm_openfiles(nlistf, memf, NULL) == -1) { 288 fprintf(stderr, "netstat: kvm_openfiles: %s\n", kvm_geterr()); 289 exit(1); 290 } 291 if (kvm_nlist(nl) < 0 || nl[0].n_type == 0) { 292 fprintf(stderr, "netstat: no namelist\n"); 293 exit(1); 294 } 295 if (mflag) { 296 mbpr((off_t)nl[N_MBSTAT].n_value); 297 exit(0); 298 } 299 if (pflag) { 300 if (tp->pr_stats) 301 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 302 tp->pr_name); 303 else 304 printf("%s: no stats routine\n", tp->pr_name); 305 exit(0); 306 } 307 if (hflag) { 308 hostpr(nl[N_IMP].n_value, nl[N_NIMP].n_value); 309 exit(0); 310 } 311 /* 312 * Keep file descriptors open to avoid overhead 313 * of open/close on each call to get* routines. 314 */ 315 sethostent(1); 316 setnetent(1); 317 if (iflag) { 318 intpr(interval, nl[N_IFNET].n_value); 319 exit(0); 320 } 321 if (rflag) { 322 if (sflag) 323 rt_stats((off_t)nl[N_RTSTAT].n_value); 324 else 325 routepr((off_t)nl[N_RTREE].n_value); 326 exit(0); 327 } 328 if (af == AF_INET || af == AF_UNSPEC) { 329 setprotoent(1); 330 setservent(1); 331 while (p = getprotoent()) { 332 333 for (tp = protox; tp->pr_name; tp++) 334 if (strcmp(tp->pr_name, p->p_name) == 0) 335 break; 336 if (tp->pr_name == 0 || tp->pr_wanted == 0) 337 continue; 338 if (sflag) { 339 if (tp->pr_stats) 340 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 341 p->p_name); 342 } else 343 if (tp->pr_cblocks) 344 (*tp->pr_cblocks)(nl[tp->pr_index].n_value, 345 p->p_name); 346 } 347 endprotoent(); 348 } 349 if (af == AF_NS || af == AF_UNSPEC) { 350 for (tp = nsprotox; tp->pr_name; tp++) { 351 if (sflag) { 352 if (tp->pr_stats) 353 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 354 tp->pr_name); 355 } else 356 if (tp->pr_cblocks) 357 (*tp->pr_cblocks)(nl[tp->pr_index].n_value, 358 tp->pr_name); 359 } 360 } 361 if (af == AF_ISO || af == AF_UNSPEC) { 362 for (tp = isoprotox; tp->pr_name; tp++) { 363 if (sflag) { 364 if (tp->pr_stats) 365 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 366 tp->pr_name); 367 } else 368 if (tp->pr_cblocks) 369 (*tp->pr_cblocks)(nl[tp->pr_index].n_value, 370 tp->pr_name); 371 } 372 } 373 if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag) 374 unixpr((off_t)nl[N_NFILE].n_value, (off_t)nl[N_FILE].n_value, 375 (struct protosw *)nl[N_UNIXSW].n_value); 376 if (af == AF_UNSPEC && sflag) 377 impstats(nl[N_IMP].n_value, nl[N_NIMP].n_value); 378 exit(0); 379 } 380 381 char * 382 plural(n) 383 int n; 384 { 385 return (n != 1 ? "s" : ""); 386 } 387 388 /* 389 * Find the protox for the given "well-known" name. 390 */ 391 struct protox * 392 knownname(name) 393 char *name; 394 { 395 struct protox **tpp, *tp; 396 397 for (tpp = protoprotox; *tpp; tpp++) 398 for (tp = *tpp; tp->pr_name; tp++) 399 if (strcmp(tp->pr_name, name) == 0) 400 return(tp); 401 return(NULL); 402 } 403 404 /* 405 * Find the protox corresponding to name. 406 */ 407 struct protox * 408 name2protox(name) 409 char *name; 410 { 411 struct protox *tp; 412 char **alias; /* alias from p->aliases */ 413 struct protoent *p; 414 415 /* 416 * Try to find the name in the list of "well-known" names. If that 417 * fails, check if name is an alias for an Internet protocol. 418 */ 419 if (tp = knownname(name)) 420 return(tp); 421 422 setprotoent(1); /* make protocol lookup cheaper */ 423 while (p = getprotoent()) { 424 /* assert: name not same as p->name */ 425 for (alias = p->p_aliases; *alias; alias++) 426 if (strcmp(name, *alias) == 0) { 427 endprotoent(); 428 return(knownname(p->p_name)); 429 } 430 } 431 endprotoent(); 432 return(NULL); 433 } 434 435 void 436 usage() 437 { 438 (void)fprintf(stderr, 439 "usage: netstat [-Aan] [-f address_family] [-M core] [-N system]\n"); 440 (void)fprintf(stderr, 441 " [-himnrs] [-f address_family] [-M core] [-N system]\n"); 442 (void)fprintf(stderr, 443 " [-n] [-I interface] [-M core] [-N system] [-w wait]\n"); 444 (void)fprintf(stderr, 445 " [-M core] [-N system] [-p protocol]\n"); 446 exit(1); 447 } 448