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