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