121988Sdist /*
263410Sbostic * Copyright (c) 1983, 1988, 1993
363410Sbostic * Regents of the University of California. All rights reserved.
433451Skarels *
542748Sbostic * %sccs.include.redist.c%
621988Sdist */
721988Sdist
87907Ssam #ifndef lint
921988Sdist char copyright[] =
1063410Sbostic "@(#) Copyright (c) 1983, 1988, 1993\n\
1163410Sbostic Regents of the University of California. All rights reserved.\n";
1233623Sbostic #endif /* not lint */
137907Ssam
1421988Sdist #ifndef lint
15*66291Sbostic static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 03/01/94";
1633623Sbostic #endif /* not lint */
1721988Sdist
187907Ssam #include <sys/param.h>
1954721Ssklower #include <sys/file.h>
2053698Ssklower #include <sys/protosw.h>
2124301Ssklower #include <sys/socket.h>
2254721Ssklower
2354721Ssklower #include <netinet/in.h>
2454721Ssklower
2554721Ssklower #include <ctype.h>
267907Ssam #include <errno.h>
2754721Ssklower #include <kvm.h>
2854721Ssklower #include <limits.h>
297907Ssam #include <netdb.h>
307907Ssam #include <nlist.h>
3154721Ssklower #include <paths.h>
327907Ssam #include <stdio.h>
3348576Sbostic #include <stdlib.h>
3448576Sbostic #include <string.h>
3554721Ssklower #include <unistd.h>
3653698Ssklower #include "netstat.h"
377907Ssam
387907Ssam struct nlist nl[] = {
397907Ssam #define N_MBSTAT 0
407907Ssam { "_mbstat" },
417907Ssam #define N_IPSTAT 1
427907Ssam { "_ipstat" },
437907Ssam #define N_TCB 2
447907Ssam { "_tcb" },
457907Ssam #define N_TCPSTAT 3
467907Ssam { "_tcpstat" },
477907Ssam #define N_UDB 4
487907Ssam { "_udb" },
497907Ssam #define N_UDPSTAT 5
507907Ssam { "_udpstat" },
5148576Sbostic #define N_IFNET 6
527907Ssam { "_ifnet" },
5348576Sbostic #define N_IMP 7
5433450Skarels { "_imp_softc" },
5550681Skarels #define N_ICMPSTAT 8
5611536Ssam { "_icmpstat" },
5750681Skarels #define N_RTSTAT 9
5812839Ssam { "_rtstat" },
5950681Skarels #define N_UNIXSW 10
6016561Ssam { "_unixsw" },
6150681Skarels #define N_IDP 11
6224301Ssklower { "_nspcb"},
6350681Skarels #define N_IDPSTAT 12
6424301Ssklower { "_idpstat"},
6550681Skarels #define N_SPPSTAT 13
6624301Ssklower { "_spp_istat"},
6750681Skarels #define N_NSERR 14
6824301Ssklower { "_ns_errstat"},
6950681Skarels #define N_CLNPSTAT 15
7039213Ssklower { "_clnp_stat"},
7152248Ssklower #define IN_NOTUSED 16
7239213Ssklower { "_tp_inpcb" },
7350681Skarels #define ISO_TP 17
7452248Ssklower { "_tp_refinfo" },
7550681Skarels #define N_TPSTAT 18
7639213Ssklower { "_tp_stat" },
7750681Skarels #define N_ESISSTAT 19
7839213Ssklower { "_esis_stat"},
7950681Skarels #define N_NIMP 20
8033450Skarels { "_nimp"},
8150681Skarels #define N_RTREE 21
8250884Ssklower { "_rt_tables"},
8350681Skarels #define N_CLTP 22
8440838Ssklower { "_cltb"},
8550681Skarels #define N_CLTPSTAT 23
8640838Ssklower { "_cltpstat"},
8754721Ssklower #define N_NFILE 24
8854721Ssklower { "_nfile" },
8954721Ssklower #define N_FILE 25
9054721Ssklower { "_file" },
9154721Ssklower #define N_IGMPSTAT 26
9254721Ssklower { "_igmpstat" },
9354721Ssklower #define N_MRTPROTO 27
9454721Ssklower { "_ip_mrtproto" },
9554721Ssklower #define N_MRTSTAT 28
9654721Ssklower { "_mrtstat" },
9754721Ssklower #define N_MRTTABLE 29
9854721Ssklower { "_mrttable" },
9954721Ssklower #define N_VIFTABLE 30
10054721Ssklower { "_viftable" },
10111536Ssam "",
1027907Ssam };
1037907Ssam
1047907Ssam struct protox {
1059569Ssam u_char pr_index; /* index into nlist of cb head */
1069569Ssam u_char pr_sindex; /* index into nlist of stat block */
1079569Ssam u_char pr_wanted; /* 1 if wanted, 0 otherwise */
10853698Ssklower void (*pr_cblocks)(); /* control blocks printing routine */
10953698Ssklower void (*pr_stats)(); /* statistics printing routine */
1109569Ssam char *pr_name; /* well-known name */
11125917Skarels } protox[] = {
1129569Ssam { N_TCB, N_TCPSTAT, 1, protopr,
1139569Ssam tcp_stats, "tcp" },
1149569Ssam { N_UDB, N_UDPSTAT, 1, protopr,
1159569Ssam udp_stats, "udp" },
1169569Ssam { -1, N_IPSTAT, 1, 0,
1179569Ssam ip_stats, "ip" },
11811536Ssam { -1, N_ICMPSTAT, 1, 0,
11911536Ssam icmp_stats, "icmp" },
12058024Sandrew { -1, N_IGMPSTAT, 1, 0,
12158024Sandrew igmp_stats, "igmp" },
1229569Ssam { -1, -1, 0, 0,
1239569Ssam 0, 0 }
1247907Ssam };
1257907Ssam
12624301Ssklower struct protox nsprotox[] = {
12724301Ssklower { N_IDP, N_IDPSTAT, 1, nsprotopr,
12824301Ssklower idp_stats, "idp" },
12924301Ssklower { N_IDP, N_SPPSTAT, 1, nsprotopr,
13024301Ssklower spp_stats, "spp" },
13124301Ssklower { -1, N_NSERR, 1, 0,
13224301Ssklower nserr_stats, "ns_err" },
13324301Ssklower { -1, -1, 0, 0,
13424301Ssklower 0, 0 }
13524301Ssklower };
13624301Ssklower
13739213Ssklower struct protox isoprotox[] = {
13839213Ssklower { ISO_TP, N_TPSTAT, 1, iso_protopr,
13939213Ssklower tp_stats, "tp" },
14040838Ssklower { N_CLTP, N_CLTPSTAT, 1, iso_protopr,
14140838Ssklower cltp_stats, "cltp" },
14239213Ssklower { -1, N_CLNPSTAT, 1, 0,
14339213Ssklower clnp_stats, "clnp"},
14439213Ssklower { -1, N_ESISSTAT, 1, 0,
14539213Ssklower esis_stats, "esis"},
14639213Ssklower { -1, -1, 0, 0,
14739213Ssklower 0, 0 }
14839213Ssklower };
14939213Ssklower
15048576Sbostic struct protox *protoprotox[] = { protox, nsprotox, isoprotox, NULL };
15139213Ssklower
15253698Ssklower static void printproto __P((struct protox *, char *));
153*66291Sbostic static void usage __P((void));
15453698Ssklower static struct protox *name2protox __P((char *));
15553698Ssklower static struct protox *knownname __P((char *));
1567907Ssam
15753698Ssklower kvm_t *kvmd;
15827886Skarels
15953698Ssklower int
main(argc,argv)1607907Ssam main(argc, argv)
1617907Ssam int argc;
162*66291Sbostic char *argv[];
1637907Ssam {
16433623Sbostic extern char *optarg;
16533623Sbostic extern int optind;
1667907Ssam register struct protoent *p;
16729754Skupfer register struct protox *tp; /* for printing cblocks & stats */
16853698Ssklower register char *cp;
16933623Sbostic int ch;
17053698Ssklower char *nlistf = NULL, *memf = NULL;
17153698Ssklower char buf[_POSIX2_LINE_MAX];
1727907Ssam
17353698Ssklower if (cp = rindex(argv[0], '/'))
17453698Ssklower prog = cp + 1;
17553698Ssklower else
17653698Ssklower prog = argv[0];
17753698Ssklower af = AF_UNSPEC;
17853698Ssklower
17965395Sbostic while ((ch = getopt(argc, argv, "Aadf:ghI:iM:mN:np:rstuw:")) != EOF)
18055010Sbostic switch(ch) {
1817907Ssam case 'A':
18248576Sbostic Aflag = 1;
1837907Ssam break;
1847907Ssam case 'a':
18548576Sbostic aflag = 1;
1867907Ssam break;
18734270Skarels case 'd':
18848576Sbostic dflag = 1;
18934270Skarels break;
19033623Sbostic case 'f':
19133623Sbostic if (strcmp(optarg, "ns") == 0)
19233623Sbostic af = AF_NS;
19333623Sbostic else if (strcmp(optarg, "inet") == 0)
19433623Sbostic af = AF_INET;
19533623Sbostic else if (strcmp(optarg, "unix") == 0)
19633623Sbostic af = AF_UNIX;
19739213Ssklower else if (strcmp(optarg, "iso") == 0)
19839213Ssklower af = AF_ISO;
19933623Sbostic else {
20048576Sbostic (void)fprintf(stderr,
20153698Ssklower "%s: %s: unknown address family\n",
20253698Ssklower prog, optarg);
20348576Sbostic exit(1);
20433623Sbostic }
20533623Sbostic break;
20665395Sbostic case 'g':
20765395Sbostic gflag = 1;
20865395Sbostic break;
20948576Sbostic case 'I': {
21048576Sbostic char *cp;
21148576Sbostic
21248576Sbostic iflag = 1;
21353698Ssklower for (cp = interface = optarg; isalpha(*cp); cp++)
21453698Ssklower continue;
21548576Sbostic unit = atoi(cp);
21648576Sbostic *cp = '\0';
21748576Sbostic break;
21848576Sbostic }
2197907Ssam case 'i':
22048576Sbostic iflag = 1;
2217907Ssam break;
22248576Sbostic case 'M':
22352252Sbostic memf = optarg;
22448576Sbostic break;
2257907Ssam case 'm':
22648576Sbostic mflag = 1;
2277907Ssam break;
22848576Sbostic case 'N':
22952252Sbostic nlistf = optarg;
23048576Sbostic break;
2317907Ssam case 'n':
23248576Sbostic nflag = 1;
2337907Ssam break;
23433623Sbostic case 'p':
23548576Sbostic if ((tp = name2protox(optarg)) == NULL) {
23648576Sbostic (void)fprintf(stderr,
23753698Ssklower "%s: %s: unknown or uninstrumented protocol\n",
23853698Ssklower prog, optarg);
23948576Sbostic exit(1);
24033623Sbostic }
24148576Sbostic pflag = 1;
24233623Sbostic break;
2437907Ssam case 'r':
24448576Sbostic rflag = 1;
2457907Ssam break;
2467907Ssam case 's':
24753698Ssklower ++sflag;
2487907Ssam break;
2497907Ssam case 't':
25048576Sbostic tflag = 1;
2517907Ssam break;
25216561Ssam case 'u':
25327886Skarels af = AF_UNIX;
25416561Ssam break;
25548576Sbostic case 'w':
25648576Sbostic interval = atoi(optarg);
25765329Sbostic iflag = 1;
25848576Sbostic break;
25933623Sbostic case '?':
26033623Sbostic default:
26133623Sbostic usage();
26233623Sbostic }
26333623Sbostic argv += optind;
26433623Sbostic argc -= optind;
26516561Ssam
26648576Sbostic #define BACKWARD_COMPATIBILITY
26748576Sbostic #ifdef BACKWARD_COMPATIBILITY
26848576Sbostic if (*argv) {
26948576Sbostic if (isdigit(**argv)) {
27048576Sbostic interval = atoi(*argv);
27133623Sbostic if (interval <= 0)
27233623Sbostic usage();
27348576Sbostic ++argv;
27448576Sbostic iflag = 1;
27533623Sbostic }
27648576Sbostic if (*argv) {
27752252Sbostic nlistf = *argv;
27853698Ssklower if (*++argv)
27952252Sbostic memf = *argv;
2807907Ssam }
2817907Ssam }
28248576Sbostic #endif
28353698Ssklower
28452252Sbostic /*
28552252Sbostic * Discard setgid privileges if not the running kernel so that bad
28652252Sbostic * guys can't print interesting stuff from kernel memory.
28752252Sbostic */
28852252Sbostic if (nlistf != NULL || memf != NULL)
28952252Sbostic setgid(getgid());
29052252Sbostic
29153698Ssklower if ((kvmd = kvm_open(nlistf, memf, NULL, O_RDONLY, prog)) == NULL) {
29253698Ssklower fprintf(stderr, "%s: kvm_open: %s\n", prog, buf);
2937907Ssam exit(1);
2947907Ssam }
29553698Ssklower if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) {
29653698Ssklower if (nlistf)
29753698Ssklower fprintf(stderr, "%s: %s: no namelist\n", prog, nlistf);
29853698Ssklower else
29953698Ssklower fprintf(stderr, "%s: no namelist\n", prog);
3007907Ssam exit(1);
3017907Ssam }
3027907Ssam if (mflag) {
30354761Ssklower mbpr(nl[N_MBSTAT].n_value);
3047907Ssam exit(0);
3057907Ssam }
30629754Skupfer if (pflag) {
30729754Skupfer if (tp->pr_stats)
30833623Sbostic (*tp->pr_stats)(nl[tp->pr_sindex].n_value,
30929754Skupfer tp->pr_name);
31029754Skupfer else
31129754Skupfer printf("%s: no stats routine\n", tp->pr_name);
31229754Skupfer exit(0);
31329754Skupfer }
3147907Ssam /*
3157907Ssam * Keep file descriptors open to avoid overhead
3167907Ssam * of open/close on each call to get* routines.
3177907Ssam */
3187907Ssam sethostent(1);
3197907Ssam setnetent(1);
3208331Ssam if (iflag) {
3218331Ssam intpr(interval, nl[N_IFNET].n_value);
3228331Ssam exit(0);
3238331Ssam }
3247907Ssam if (rflag) {
32512839Ssam if (sflag)
32654761Ssklower rt_stats(nl[N_RTSTAT].n_value);
32712839Ssam else
32854761Ssklower routepr(nl[N_RTREE].n_value);
3297907Ssam exit(0);
3307907Ssam }
33165395Sbostic if (gflag) {
33254721Ssklower if (sflag)
33354761Ssklower mrt_stats(nl[N_MRTPROTO].n_value,
33454761Ssklower nl[N_MRTSTAT].n_value);
33554721Ssklower else
33654761Ssklower mroutepr(nl[N_MRTPROTO].n_value,
33754761Ssklower nl[N_MRTTABLE].n_value,
33854761Ssklower nl[N_VIFTABLE].n_value);
33954721Ssklower exit(0);
34054721Ssklower }
34153698Ssklower if (af == AF_INET || af == AF_UNSPEC) {
34253698Ssklower setprotoent(1);
34353698Ssklower setservent(1);
34453698Ssklower /* ugh, this is O(MN) ... why do we do this? */
34553698Ssklower while (p = getprotoent()) {
34653698Ssklower for (tp = protox; tp->pr_name; tp++)
34753698Ssklower if (strcmp(tp->pr_name, p->p_name) == 0)
34853698Ssklower break;
34953698Ssklower if (tp->pr_name == 0 || tp->pr_wanted == 0)
35053698Ssklower continue;
35153698Ssklower printproto(tp, p->p_name);
35253698Ssklower }
35353698Ssklower endprotoent();
35453698Ssklower }
35553698Ssklower if (af == AF_NS || af == AF_UNSPEC)
35653698Ssklower for (tp = nsprotox; tp->pr_name; tp++)
35753698Ssklower printproto(tp, tp->pr_name);
35853698Ssklower if (af == AF_ISO || af == AF_UNSPEC)
35953698Ssklower for (tp = isoprotox; tp->pr_name; tp++)
36053698Ssklower printproto(tp, tp->pr_name);
36153698Ssklower if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
36254761Ssklower unixpr(nl[N_UNIXSW].n_value);
36353698Ssklower exit(0);
36453698Ssklower }
3657907Ssam
36653698Ssklower /*
36753698Ssklower * Print out protocol statistics or control blocks (per sflag).
36853698Ssklower * If the interface was not specifically requested, and the symbol
36953698Ssklower * is not in the namelist, ignore this one.
37053698Ssklower */
37153698Ssklower static void
printproto(tp,name)37253698Ssklower printproto(tp, name)
37353698Ssklower register struct protox *tp;
37453698Ssklower char *name;
37553698Ssklower {
37653698Ssklower void (*pr)();
37754761Ssklower u_long off;
37853698Ssklower
37953698Ssklower if (sflag) {
38053698Ssklower pr = tp->pr_stats;
38153698Ssklower off = nl[tp->pr_sindex].n_value;
38253698Ssklower } else {
38353698Ssklower pr = tp->pr_cblocks;
38453698Ssklower off = nl[tp->pr_index].n_value;
3857907Ssam }
38653698Ssklower if (pr != NULL && (off || af != AF_UNSPEC))
38753698Ssklower (*pr)(off, name);
38853698Ssklower }
38953698Ssklower
39053698Ssklower /*
39153698Ssklower * Read kernel memory, return 0 on success.
39253698Ssklower */
39353698Ssklower int
kread(addr,buf,size)39453698Ssklower kread(addr, buf, size)
39554761Ssklower u_long addr;
39653698Ssklower char *buf;
39753698Ssklower int size;
39853698Ssklower {
39953698Ssklower
40053698Ssklower if (kvm_read(kvmd, addr, buf, size) != size) {
40153698Ssklower /* XXX this duplicates kvm_read's error printout */
40253698Ssklower (void)fprintf(stderr, "%s: kvm_read %s\n", prog,
40353698Ssklower kvm_geterr(kvmd));
40453698Ssklower return (-1);
40524301Ssklower }
40653698Ssklower return (0);
4077907Ssam }
4087907Ssam
40912839Ssam char *
plural(n)41012839Ssam plural(n)
41112839Ssam int n;
41212839Ssam {
41312839Ssam return (n != 1 ? "s" : "");
41412839Ssam }
41529754Skupfer
41654721Ssklower char *
plurales(n)41754721Ssklower plurales(n)
41854721Ssklower int n;
41954721Ssklower {
42054721Ssklower return (n != 1 ? "es" : "");
42154721Ssklower }
42254721Ssklower
42329754Skupfer /*
42429754Skupfer * Find the protox for the given "well-known" name.
42529754Skupfer */
42653698Ssklower static struct protox *
knownname(name)42729754Skupfer knownname(name)
42829754Skupfer char *name;
42929754Skupfer {
43039213Ssklower struct protox **tpp, *tp;
43133623Sbostic
43239213Ssklower for (tpp = protoprotox; *tpp; tpp++)
43353698Ssklower for (tp = *tpp; tp->pr_name; tp++)
43453698Ssklower if (strcmp(tp->pr_name, name) == 0)
43553698Ssklower return (tp);
43653698Ssklower return (NULL);
43729754Skupfer }
43829754Skupfer
43929754Skupfer /*
44029754Skupfer * Find the protox corresponding to name.
44129754Skupfer */
44253698Ssklower static struct protox *
name2protox(name)44329754Skupfer name2protox(name)
44429754Skupfer char *name;
44529754Skupfer {
44629754Skupfer struct protox *tp;
44729754Skupfer char **alias; /* alias from p->aliases */
44829754Skupfer struct protoent *p;
44933623Sbostic
45029754Skupfer /*
45129754Skupfer * Try to find the name in the list of "well-known" names. If that
45229754Skupfer * fails, check if name is an alias for an Internet protocol.
45329754Skupfer */
45429754Skupfer if (tp = knownname(name))
45553698Ssklower return (tp);
45633623Sbostic
45729754Skupfer setprotoent(1); /* make protocol lookup cheaper */
45829754Skupfer while (p = getprotoent()) {
45929754Skupfer /* assert: name not same as p->name */
46029754Skupfer for (alias = p->p_aliases; *alias; alias++)
46129754Skupfer if (strcmp(name, *alias) == 0) {
46229754Skupfer endprotoent();
46353698Ssklower return (knownname(p->p_name));
46429754Skupfer }
46529754Skupfer }
46629754Skupfer endprotoent();
46753698Ssklower return (NULL);
46829754Skupfer }
46933623Sbostic
47053698Ssklower static void
usage()47133623Sbostic usage()
47233623Sbostic {
47348576Sbostic (void)fprintf(stderr,
47453698Ssklower "usage: %s [-Aan] [-f address_family] [-M core] [-N system]\n", prog);
47548576Sbostic (void)fprintf(stderr,
476*66291Sbostic " %s [-ghimnrs] [-f address_family] [-M core] [-N system]\n", prog);
47748576Sbostic (void)fprintf(stderr,
478*66291Sbostic " %s [-n] [-I interface] [-M core] [-N system] [-w wait]\n", prog);
47948576Sbostic (void)fprintf(stderr,
480*66291Sbostic " %s [-M core] [-N system] [-p protocol]\n", prog);
48133623Sbostic exit(1);
48233623Sbostic }
483