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.14 (Berkeley) 06/29/88"; 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 39 struct nlist nl[] = { 40 #define N_MBSTAT 0 41 { "_mbstat" }, 42 #define N_IPSTAT 1 43 { "_ipstat" }, 44 #define N_TCB 2 45 { "_tcb" }, 46 #define N_TCPSTAT 3 47 { "_tcpstat" }, 48 #define N_UDB 4 49 { "_udb" }, 50 #define N_UDPSTAT 5 51 { "_udpstat" }, 52 #define N_RAWCB 6 53 { "_rawcb" }, 54 #define N_SYSMAP 7 55 { "_Sysmap" }, 56 #define N_SYSSIZE 8 57 { "_Syssize" }, 58 #define N_IFNET 9 59 { "_ifnet" }, 60 #define N_IMP 10 61 { "_imp_softc" }, 62 #define N_RTHOST 11 63 { "_rthost" }, 64 #define N_RTNET 12 65 { "_rtnet" }, 66 #define N_ICMPSTAT 13 67 { "_icmpstat" }, 68 #define N_RTSTAT 14 69 { "_rtstat" }, 70 #define N_NFILE 15 71 { "_nfile" }, 72 #define N_FILE 16 73 { "_file" }, 74 #define N_UNIXSW 17 75 { "_unixsw" }, 76 #define N_RTHASHSIZE 18 77 { "_rthashsize" }, 78 #define N_IDP 19 79 { "_nspcb"}, 80 #define N_IDPSTAT 20 81 { "_idpstat"}, 82 #define N_SPPSTAT 21 83 { "_spp_istat"}, 84 #define N_NSERR 22 85 { "_ns_errstat"}, 86 #define N_NIMP 23 87 { "_nimp"}, 88 "", 89 }; 90 91 /* internet protocols */ 92 extern int protopr(); 93 extern int tcp_stats(), udp_stats(), ip_stats(), icmp_stats(); 94 /* ns protocols */ 95 extern int nsprotopr(); 96 extern int spp_stats(), idp_stats(), nserr_stats(); 97 98 #define NULLPROTOX ((struct protox *) 0) 99 struct protox { 100 u_char pr_index; /* index into nlist of cb head */ 101 u_char pr_sindex; /* index into nlist of stat block */ 102 u_char pr_wanted; /* 1 if wanted, 0 otherwise */ 103 int (*pr_cblocks)(); /* control blocks printing routine */ 104 int (*pr_stats)(); /* statistics printing routine */ 105 char *pr_name; /* well-known name */ 106 } protox[] = { 107 { N_TCB, N_TCPSTAT, 1, protopr, 108 tcp_stats, "tcp" }, 109 { N_UDB, N_UDPSTAT, 1, protopr, 110 udp_stats, "udp" }, 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 pte *Sysmap; 131 132 char *system = "/vmunix"; 133 char *kmemf = "/dev/kmem"; 134 int kmem; 135 int kflag; 136 int Aflag; 137 int aflag; 138 int hflag; 139 int iflag; 140 int mflag; 141 int nflag; 142 int pflag; 143 int rflag; 144 int sflag; 145 int tflag; 146 int dflag; 147 int interval; 148 char *interface; 149 int unit; 150 151 int af = AF_UNSPEC; 152 153 extern char *malloc(); 154 extern off_t lseek(); 155 156 main(argc, argv) 157 int argc; 158 char *argv[]; 159 { 160 extern char *optarg; 161 extern int optind; 162 register struct protoent *p; 163 register struct protox *tp; /* for printing cblocks & stats */ 164 struct protox *name2protox(); /* for -p */ 165 int ch; 166 167 while ((ch = getopt(argc, argv, "AI:af:himnp:drstu")) != EOF) 168 switch((char)ch) { 169 case 'A': 170 Aflag++; 171 break; 172 case 'I': { 173 char *cp; 174 175 iflag++; 176 for (cp = interface = optarg; isalpha(*cp); cp++); 177 unit = atoi(cp); 178 *cp = '\0'; 179 break; 180 } 181 case 'a': 182 aflag++; 183 break; 184 case 'd': 185 dflag++; 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 { 195 fprintf(stderr, "%s: unknown address family\n", optarg); 196 exit(10); 197 } 198 break; 199 case 'h': 200 hflag++; 201 break; 202 case 'i': 203 iflag++; 204 break; 205 case 'm': 206 mflag++; 207 break; 208 case 'n': 209 nflag++; 210 break; 211 case 'p': 212 if ((tp = name2protox(optarg)) == NULLPROTOX) { 213 fprintf(stderr, "%s: unknown or uninstrumented protocol\n", optarg); 214 exit(10); 215 } 216 pflag++; 217 break; 218 case 'r': 219 rflag++; 220 break; 221 case 's': 222 sflag++; 223 break; 224 case 't': 225 tflag++; 226 break; 227 case 'u': 228 af = AF_UNIX; 229 break; 230 case '?': 231 default: 232 usage(); 233 } 234 argv += optind; 235 argc -= optind; 236 237 if (argc > 0) { 238 if (isdigit(argv[0][0])) { 239 interval = atoi(argv[0]); 240 if (interval <= 0) 241 usage(); 242 argv++, argc--; 243 iflag++; 244 } 245 if (argc > 0) { 246 system = *argv; 247 argv++, argc--; 248 if (argc > 0) { 249 kmemf = *argv; 250 kflag++; 251 } 252 } 253 } 254 if (nlist(system, nl) < 0 || nl[0].n_type == 0) { 255 fprintf(stderr, "%s: no namelist\n", system); 256 exit(1); 257 } 258 kmem = open(kmemf, O_RDONLY); 259 if (kmem < 0) { 260 perror(kmemf); 261 exit(1); 262 } 263 if (kflag) { 264 off_t off; 265 266 Sysmap = (struct pte *) 267 malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte))); 268 if (!Sysmap) { 269 fputs("netstat: can't get memory for Sysmap.\n", stderr); 270 exit(1); 271 } 272 off = nl[N_SYSMAP].n_value & ~KERNBASE; 273 (void)lseek(kmem, off, L_SET); 274 (void)read(kmem, (char *)Sysmap, 275 (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte))); 276 } 277 if (mflag) { 278 mbpr((off_t)nl[N_MBSTAT].n_value); 279 exit(0); 280 } 281 if (pflag) { 282 if (tp->pr_stats) 283 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 284 tp->pr_name); 285 else 286 printf("%s: no stats routine\n", tp->pr_name); 287 exit(0); 288 } 289 if (hflag) { 290 hostpr(nl[N_IMP].n_value, nl[N_NIMP].n_value); 291 exit(0); 292 } 293 /* 294 * Keep file descriptors open to avoid overhead 295 * of open/close on each call to get* routines. 296 */ 297 sethostent(1); 298 setnetent(1); 299 if (iflag) { 300 intpr(interval, nl[N_IFNET].n_value); 301 exit(0); 302 } 303 if (rflag) { 304 if (sflag) 305 rt_stats((off_t)nl[N_RTSTAT].n_value); 306 else 307 routepr((off_t)nl[N_RTHOST].n_value, 308 (off_t)nl[N_RTNET].n_value, 309 (off_t)nl[N_RTHASHSIZE].n_value); 310 exit(0); 311 } 312 if (af == AF_INET || af == AF_UNSPEC) { 313 setprotoent(1); 314 setservent(1); 315 while (p = getprotoent()) { 316 317 for (tp = protox; tp->pr_name; tp++) 318 if (strcmp(tp->pr_name, p->p_name) == 0) 319 break; 320 if (tp->pr_name == 0 || tp->pr_wanted == 0) 321 continue; 322 if (sflag) { 323 if (tp->pr_stats) 324 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 325 p->p_name); 326 } else 327 if (tp->pr_cblocks) 328 (*tp->pr_cblocks)(nl[tp->pr_index].n_value, 329 p->p_name); 330 } 331 endprotoent(); 332 } 333 if (af == AF_NS || af == AF_UNSPEC) { 334 for (tp = nsprotox; tp->pr_name; tp++) { 335 if (sflag) { 336 if (tp->pr_stats) 337 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, 338 tp->pr_name); 339 } else 340 if (tp->pr_cblocks) 341 (*tp->pr_cblocks)(nl[tp->pr_index].n_value, 342 tp->pr_name); 343 } 344 } 345 if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag) 346 unixpr((off_t)nl[N_NFILE].n_value, (off_t)nl[N_FILE].n_value, 347 (struct protosw *)nl[N_UNIXSW].n_value); 348 if (af == AF_UNSPEC && sflag) 349 impstats(nl[N_IMP].n_value, nl[N_NIMP].n_value); 350 exit(0); 351 } 352 353 /* 354 * Seek into the kernel for a value. 355 */ 356 off_t 357 klseek(fd, base, off) 358 int fd, off; 359 off_t base; 360 { 361 if (kflag) { 362 /* get kernel pte */ 363 base &= ~KERNBASE; 364 base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET); 365 } 366 return (lseek(fd, base, off)); 367 } 368 369 char * 370 plural(n) 371 int n; 372 { 373 374 return (n != 1 ? "s" : ""); 375 } 376 377 /* 378 * Find the protox for the given "well-known" name. 379 */ 380 struct protox * 381 knownname(name) 382 char *name; 383 { 384 struct protox *tp; 385 386 for (tp = protox; tp->pr_name; tp++) 387 if (strcmp(tp->pr_name, name) == 0) 388 return(tp); 389 for (tp = nsprotox; tp->pr_name; tp++) 390 if (strcmp(tp->pr_name, name) == 0) 391 return(tp); 392 return(NULLPROTOX); 393 } 394 395 /* 396 * Find the protox corresponding to name. 397 */ 398 struct protox * 399 name2protox(name) 400 char *name; 401 { 402 struct protox *tp; 403 char **alias; /* alias from p->aliases */ 404 struct protoent *p; 405 406 /* 407 * Try to find the name in the list of "well-known" names. If that 408 * fails, check if name is an alias for an Internet protocol. 409 */ 410 if (tp = knownname(name)) 411 return(tp); 412 413 setprotoent(1); /* make protocol lookup cheaper */ 414 while (p = getprotoent()) { 415 /* assert: name not same as p->name */ 416 for (alias = p->p_aliases; *alias; alias++) 417 if (strcmp(name, *alias) == 0) { 418 endprotoent(); 419 return(knownname(p->p_name)); 420 } 421 } 422 endprotoent(); 423 return(NULLPROTOX); 424 } 425 426 usage() 427 { 428 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); 429 exit(1); 430 } 431