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