diff options
author | jhb <jhb@FreeBSD.org> | 2007-07-16 17:15:55 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2007-07-16 17:15:55 +0000 |
commit | 27187e7f6bd04a94e9ada0ca994e7c828abb4514 (patch) | |
tree | 165174828db97bceab2299030940226f1b6620cf /usr.bin | |
parent | 5a67dd7c20118e6593c9e3904b775b2274c2757b (diff) | |
download | FreeBSD-src-27187e7f6bd04a94e9ada0ca994e7c828abb4514.zip FreeBSD-src-27187e7f6bd04a94e9ada0ca994e7c828abb4514.tar.gz |
Restore netstat -M functionality for most statistics on core dumps. In
general, when support was added to netstat for fetching data using sysctl,
no provision was left for fetching equivalent data from a core dump, and
in fact, netstat would _always_ fetch data from the live kernel using
sysctl even when -M was specified resulting in the user believing they
were getting data from coredumps when they actually weren't. Some specific
changes:
- Add a global 'live' variable that is true if netstat is running against
the live kernel and false if -M has been specified.
- Stop abusing the sysctl flag in the protocol tables to hold the protocol
number. Instead, the protocol is now its own field in the tables, and
it is passed as a separate parameter to the PCB and stat routines rather
than overloading the KVM offset parameter.
- Don't run PCB or stats functions who don't have a namelist offset if we
are being run against a crash dump (!live).
- For the inet and unix PCB routines, we generate the same buffer from KVM
that the sysctl usually generates complete with the header and trailer.
- Don't run bpf stats for !live (before it would just silently always run
live).
- kread() no longer trashes memory when opening the buffer if there is an
error on open and the passed in buffer is smaller than _POSIX2_LINE_MAX.
- The multicast routing code doesn't fallback to kvm on live kernels if
the sysctl fails. Keeping this made the code rather hairy, and netstat
is already tied to the kernel ABI anyway (even when using sysctl's since
things like xinpcb contain an inpcb) so any kernels this is run against
that have the multicast routing stuff should have the sysctls.
- Don't try to dig around in the kernel linker in the netgraph PCB routine
for core dumps.
Other notes:
- sctp's PCB routine only works on live kernels, it looked rather
complicated to generate all the same stuff via KVM. Someone can always
add it later if desired though.
- Fix the ipsec removal bug where N_xxx for IPSEC stats weren't renumbered.
- Use sysctlbyname() everywhere rather than hardcoded mib values.
MFC after: 1 week
Approved by: re (rwatson)
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/netstat/atalk.c | 6 | ||||
-rw-r--r-- | usr.bin/netstat/bpf.c | 1 | ||||
-rw-r--r-- | usr.bin/netstat/if.c | 22 | ||||
-rw-r--r-- | usr.bin/netstat/inet.c | 403 | ||||
-rw-r--r-- | usr.bin/netstat/inet6.c | 94 | ||||
-rw-r--r-- | usr.bin/netstat/ipsec.c | 10 | ||||
-rw-r--r-- | usr.bin/netstat/ipx.c | 8 | ||||
-rw-r--r-- | usr.bin/netstat/main.c | 217 | ||||
-rw-r--r-- | usr.bin/netstat/mbuf.c | 4 | ||||
-rw-r--r-- | usr.bin/netstat/mcast.c | 1 | ||||
-rw-r--r-- | usr.bin/netstat/mroute.c | 43 | ||||
-rw-r--r-- | usr.bin/netstat/mroute6.c | 42 | ||||
-rw-r--r-- | usr.bin/netstat/netgraph.c | 7 | ||||
-rw-r--r-- | usr.bin/netstat/netstat.h | 78 | ||||
-rw-r--r-- | usr.bin/netstat/pfkey.c | 4 | ||||
-rw-r--r-- | usr.bin/netstat/route.c | 1 | ||||
-rw-r--r-- | usr.bin/netstat/sctp.c | 23 | ||||
-rw-r--r-- | usr.bin/netstat/unix.c | 152 |
18 files changed, 750 insertions, 366 deletions
diff --git a/usr.bin/netstat/atalk.c b/usr.bin/netstat/atalk.c index 8353e13..7c19c56 100644 --- a/usr.bin/netstat/atalk.c +++ b/usr.bin/netstat/atalk.c @@ -217,7 +217,8 @@ atalk_print2(struct sockaddr *sa, struct sockaddr *mask, int what) } void -atalkprotopr(u_long off __unused, const char *name, int af1 __unused) +atalkprotopr(u_long off __unused, const char *name, int af1 __unused, + int proto __unused) { struct ddpcb *this, *next; @@ -266,7 +267,8 @@ atalkprotopr(u_long off __unused, const char *name, int af1 __unused) * Dump DDP statistics structure. */ void -ddp_stats(u_long off __unused, const char *name, int af1 __unused) +ddp_stats(u_long off __unused, const char *name, int af1 __unused, + int proto __unused) { struct ddpstat ddpstat; diff --git a/usr.bin/netstat/bpf.c b/usr.bin/netstat/bpf.c index 90fa623d..73cc018 100644 --- a/usr.bin/netstat/bpf.c +++ b/usr.bin/netstat/bpf.c @@ -28,6 +28,7 @@ #include <sys/types.h> #include <sys/protosw.h> #include <sys/socket.h> +#include <sys/socketvar.h> #include <sys/sysctl.h> #include <sys/param.h> #include <sys/user.h> diff --git a/usr.bin/netstat/if.c b/usr.bin/netstat/if.c index dc280eb..9acd37c 100644 --- a/usr.bin/netstat/if.c +++ b/usr.bin/netstat/if.c @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include <sys/types.h> #include <sys/protosw.h> #include <sys/socket.h> +#include <sys/socketvar.h> #include <sys/sysctl.h> #include <sys/time.h> @@ -85,19 +86,22 @@ static char ntop_buf[INET6_ADDRSTRLEN]; /* for inet_ntop() */ * Dump pfsync statistics structure. */ void -pfsync_stats(u_long off __unused, const char *name, int af1 __unused) +pfsync_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct pfsyncstats pfsyncstat, zerostat; size_t len = sizeof(struct pfsyncstats); - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet.pfsync.stats", &pfsyncstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - if (errno != ENOENT) - warn("sysctl: net.inet.pfsync.stats"); - return; - } + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet.pfsync.stats", &pfsyncstat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + if (errno != ENOENT) + warn("sysctl: net.inet.pfsync.stats"); + return; + } + } else + kread(off, &pfsyncstat, len); printf("%s:\n", name); diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c index 1be7b87..eee2fef 100644 --- a/usr.bin/netstat/inet.c +++ b/usr.bin/netstat/inet.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/queue.h> +#include <sys/domain.h> #include <sys/socket.h> #include <sys/socketvar.h> #include <sys/sysctl.h> @@ -90,6 +91,208 @@ void inetprint (struct in_addr *, int, const char *, int); static int udp_done, tcp_done; #endif /* INET6 */ +static int +pcblist_sysctl(int proto, char **bufp, int istcp) +{ + const char *mibvar; + char *buf; + size_t len; + + switch (proto) { + case IPPROTO_TCP: + mibvar = "net.inet.tcp.pcblist"; + break; + case IPPROTO_UDP: + mibvar = "net.inet.udp.pcblist"; + break; + case IPPROTO_DIVERT: + mibvar = "net.inet.divert.pcblist"; + break; + default: + mibvar = "net.inet.raw.pcblist"; + break; + } + + len = 0; + if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) { + if (errno != ENOENT) + warn("sysctl: %s", mibvar); + return (0); + } + if ((buf = malloc(len)) == 0) { + warnx("malloc %lu bytes", (u_long)len); + return (0); + } + if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) { + warn("sysctl: %s", mibvar); + free(buf); + return (0); + } + *bufp = buf; + return (1); +} + +/* + * Copied directly from uipc_socket2.c. We leave out some fields that are in + * nested structures that aren't used to avoid extra work. + */ +static void +sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb) +{ + xsb->sb_cc = sb->sb_cc; + xsb->sb_hiwat = sb->sb_hiwat; + xsb->sb_mbcnt = sb->sb_mbcnt; + xsb->sb_mbmax = sb->sb_mbmax; + xsb->sb_lowat = sb->sb_lowat; + xsb->sb_flags = sb->sb_flags; + xsb->sb_timeo = sb->sb_timeo; +} + +int +sotoxsocket(struct socket *so, struct xsocket *xso) +{ + struct protosw proto; + struct domain domain; + + bzero(xso, sizeof *xso); + xso->xso_len = sizeof *xso; + xso->xso_so = so; + xso->so_type = so->so_type; + xso->so_options = so->so_options; + xso->so_linger = so->so_linger; + xso->so_state = so->so_state; + xso->so_pcb = so->so_pcb; + if (kread((uintptr_t)so->so_proto, &proto, sizeof(proto)) != 0) + return (-1); + xso->xso_protocol = proto.pr_protocol; + if (kread((uintptr_t)proto.pr_domain, &domain, sizeof(domain)) != 0) + return (-1); + xso->xso_family = domain.dom_family; + xso->so_qlen = so->so_qlen; + xso->so_incqlen = so->so_incqlen; + xso->so_qlimit = so->so_qlimit; + xso->so_timeo = so->so_timeo; + xso->so_error = so->so_error; + xso->so_oobmark = so->so_oobmark; + sbtoxsockbuf(&so->so_snd, &xso->so_snd); + sbtoxsockbuf(&so->so_rcv, &xso->so_rcv); + return (0); +} + +static int +pcblist_kvm(u_long off, char **bufp, int istcp) +{ + struct inpcbinfo pcbinfo; + struct inpcbhead listhead; + struct inpcb *inp; + struct xinpcb xi; + struct xinpgen xig; + struct xtcpcb xt; + struct socket so; + struct xsocket *xso; + char *buf, *p; + size_t len; + + if (off == 0) + return (0); + kread(off, &pcbinfo, sizeof(pcbinfo)); + if (istcp) + len = 2 * sizeof(xig) + + (pcbinfo.ipi_count + pcbinfo.ipi_count / 8) * + sizeof(struct xtcpcb); + else + len = 2 * sizeof(xig) + + (pcbinfo.ipi_count + pcbinfo.ipi_count / 8) * + sizeof(struct xinpcb); + if ((buf = malloc(len)) == 0) { + warnx("malloc %lu bytes", (u_long)len); + return (0); + } + p = buf; + +#define COPYOUT(obj, size) do { \ + if (len < (size)) { \ + warnx("buffer size exceeded"); \ + goto fail; \ + } \ + bcopy((obj), p, (size)); \ + len -= (size); \ + p += (size); \ +} while (0) + +#define KREAD(off, buf, len) do { \ + if (kread((uintptr_t)(off), (buf), (len)) != 0) \ + goto fail; \ +} while (0) + + /* Write out header. */ + xig.xig_len = sizeof xig; + xig.xig_count = pcbinfo.ipi_count; + xig.xig_gen = pcbinfo.ipi_gencnt; + xig.xig_sogen = 0; + COPYOUT(&xig, sizeof xig); + + /* Walk the PCB list. */ + xt.xt_len = sizeof xt; + xi.xi_len = sizeof xi; + if (istcp) + xso = &xt.xt_socket; + else + xso = &xi.xi_socket; + KREAD(pcbinfo.ipi_listhead, &listhead, sizeof(listhead)); + LIST_FOREACH(inp, &listhead, inp_list) { + if (istcp) { + KREAD(inp, &xt.xt_inp, sizeof(*inp)); + inp = &xt.xt_inp; + } else { + KREAD(inp, &xi.xi_inp, sizeof(*inp)); + inp = &xi.xi_inp; + } + + if (inp->inp_gencnt > pcbinfo.ipi_gencnt) + continue; + + if (istcp) { + if (inp->inp_ppcb == NULL) + bzero(&xt.xt_tp, sizeof xt.xt_tp); + else if (inp->inp_vflag & INP_TIMEWAIT) { + bzero(&xt.xt_tp, sizeof xt.xt_tp); + xt.xt_tp.t_state = TCPS_TIME_WAIT; + } else + KREAD(inp->inp_ppcb, &xt.xt_tp, + sizeof xt.xt_tp); + } + if (inp->inp_socket) { + KREAD(inp->inp_socket, &so, sizeof(so)); + if (sotoxsocket(&so, xso) != 0) + goto fail; + } else { + bzero(xso, sizeof(*xso)); + if (istcp) + xso->xso_protocol = IPPROTO_TCP; + } + if (istcp) + COPYOUT(&xt, sizeof xt); + else + COPYOUT(&xi, sizeof xi); + } + + /* Reread the pcbinfo and write out the footer. */ + kread(off, &pcbinfo, sizeof(pcbinfo)); + xig.xig_count = pcbinfo.ipi_count; + xig.xig_gen = pcbinfo.ipi_gencnt; + COPYOUT(&xig, sizeof xig); + + *bufp = buf; + return (1); + +fail: + free(buf); + return (0); +#undef COPYOUT +#undef KREAD +} + /* * Print a summary of connections related to an Internet * protocol. For TCP, also give state of connection. @@ -97,18 +300,16 @@ static int udp_done, tcp_done; * -a (all) flag is specified. */ void -protopr(u_long proto, /* for sysctl version we pass proto # */ - const char *name, int af1) +protopr(u_long off, const char *name, int af1, int proto) { int istcp; static int first = 1; char *buf; - const char *mibvar, *vchar; + const char *vchar; struct tcpcb *tp = NULL; struct inpcb *inp; struct xinpgen *xig, *oxig; struct xsocket *so; - size_t len; istcp = 0; switch (proto) { @@ -120,7 +321,6 @@ protopr(u_long proto, /* for sysctl version we pass proto # */ tcp_done = 1; #endif istcp = 1; - mibvar = "net.inet.tcp.pcblist"; break; case IPPROTO_UDP: #ifdef INET6 @@ -129,29 +329,14 @@ protopr(u_long proto, /* for sysctl version we pass proto # */ else udp_done = 1; #endif - mibvar = "net.inet.udp.pcblist"; - break; - case IPPROTO_DIVERT: - mibvar = "net.inet.divert.pcblist"; - break; - default: - mibvar = "net.inet.raw.pcblist"; break; } - len = 0; - if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) { - if (errno != ENOENT) - warn("sysctl: %s", mibvar); - return; - } - if ((buf = malloc(len)) == 0) { - warnx("malloc %lu bytes", (u_long)len); - return; - } - if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) { - warn("sysctl: %s", mibvar); - free(buf); - return; + if (live) { + if (!pcblist_sysctl(proto, &buf, istcp)) + return; + } else { + if (!pcblist_kvm(off, &buf, istcp)) + return; } oxig = xig = (struct xinpgen *)buf; @@ -168,7 +353,7 @@ protopr(u_long proto, /* for sysctl version we pass proto # */ } /* Ignore sockets for protocols other than the desired one. */ - if (so->xso_protocol != (int)proto) + if (so->xso_protocol != proto) continue; /* Ignore PCBs which were freed during copyout. */ @@ -347,18 +532,10 @@ protopr(u_long proto, /* for sysctl version we pass proto # */ * Dump TCP statistics structure. */ void -tcp_stats(u_long off __unused, const char *name, int af1 __unused) +tcp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct tcpstat tcpstat, zerostat; size_t len = sizeof tcpstat; - - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - warn("sysctl: net.inet.tcp.stats"); - return; - } #ifdef INET6 if (tcp_done != 0) @@ -367,6 +544,17 @@ tcp_stats(u_long off __unused, const char *name, int af1 __unused) tcp_done = 1; #endif + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + warn("sysctl: net.inet.tcp.stats"); + return; + } + } else + kread(off, &tcpstat, len); + printf ("%s:\n", name); #define p(f, m) if (tcpstat.f || sflag <= 1) \ @@ -480,20 +668,12 @@ tcp_stats(u_long off __unused, const char *name, int af1 __unused) * Dump UDP statistics structure. */ void -udp_stats(u_long off __unused, const char *name, int af1 __unused) +udp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct udpstat udpstat, zerostat; size_t len = sizeof udpstat; u_long delivered; - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet.udp.stats", &udpstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - warn("sysctl: net.inet.udp.stats"); - return; - } - #ifdef INET6 if (udp_done != 0) return; @@ -501,6 +681,17 @@ udp_stats(u_long off __unused, const char *name, int af1 __unused) udp_done = 1; #endif + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet.udp.stats", &udpstat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + warn("sysctl: net.inet.udp.stats"); + return; + } + } else + kread(off, &udpstat, len); + printf("%s:\n", name); #define p(f, m) if (udpstat.f || sflag <= 1) \ printf(m, udpstat.f, plural(udpstat.f)) @@ -537,18 +728,24 @@ udp_stats(u_long off __unused, const char *name, int af1 __unused) * Dump CARP statistics structure. */ void -carp_stats(u_long off __unused, const char *name, int af1 __unused) +carp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct carpstats carpstat, zerostat; size_t len = sizeof(struct carpstats); - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet.carp.stats", &carpstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - if (errno != ENOENT) - warn("sysctl: net.inet.carp.stats"); - return; + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet.carp.stats", &carpstat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + if (errno != ENOENT) + warn("sysctl: net.inet.carp.stats"); + return; + } + } else { + if (off == 0) + return; + kread(off, &carpstat, len); } printf("%s:\n", name); @@ -582,18 +779,21 @@ carp_stats(u_long off __unused, const char *name, int af1 __unused) * Dump IP statistics structure. */ void -ip_stats(u_long off __unused, const char *name, int af1 __unused) +ip_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct ipstat ipstat, zerostat; size_t len = sizeof ipstat; - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet.ip.stats", &ipstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - warn("sysctl: net.inet.ip.stats"); - return; - } + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet.ip.stats", &ipstat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + warn("sysctl: net.inet.ip.stats"); + return; + } + } else + kread(off, &ipstat, len); printf("%s:\n", name); @@ -687,26 +887,23 @@ static const char *icmpnames[ICMP_MAXTYPE + 1] = { * Dump ICMP statistics. */ void -icmp_stats(u_long off __unused, const char *name, int af1 __unused) +icmp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct icmpstat icmpstat, zerostat; int i, first; - int mib[4]; /* CTL_NET + PF_INET + IPPROTO_ICMP + req */ size_t len; - mib[0] = CTL_NET; - mib[1] = PF_INET; - mib[2] = IPPROTO_ICMP; - mib[3] = ICMPCTL_STATS; - len = sizeof icmpstat; - if (zflag) - memset(&zerostat, 0, len); - if (sysctl(mib, 4, &icmpstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - warn("sysctl: net.inet.icmp.stats"); - return; - } + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet.icmp.stats", &icmpstat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + warn("sysctl: net.inet.icmp.stats"); + return; + } + } else + kread(off, &icmpstat, len); printf("%s:\n", name); @@ -758,30 +955,35 @@ icmp_stats(u_long off __unused, const char *name, int af1 __unused) #undef p #undef p1a #undef p2 - mib[3] = ICMPCTL_MASKREPL; - len = sizeof i; - if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0) - return; - printf("\tICMP address mask responses are %sabled\n", - i ? "en" : "dis"); + if (live) { + len = sizeof i; + if (sysctlbyname("net.inet.icmp.maskrepl", &i, &len, NULL, 0) < + 0) + return; + printf("\tICMP address mask responses are %sabled\n", + i ? "en" : "dis"); + } } /* * Dump IGMP statistics structure. */ void -igmp_stats(u_long off __unused, const char *name, int af1 __unused) +igmp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct igmpstat igmpstat, zerostat; size_t len = sizeof igmpstat; - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet.igmp.stats", &igmpstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - warn("sysctl: net.inet.igmp.stats"); - return; - } + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet.igmp.stats", &igmpstat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + warn("sysctl: net.inet.igmp.stats"); + return; + } + } else + kread(off, &igmpstat, len); printf("%s:\n", name); @@ -806,18 +1008,25 @@ igmp_stats(u_long off __unused, const char *name, int af1 __unused) * Dump PIM statistics structure. */ void -pim_stats(u_long off __unused, const char *name, int af1 __unused) +pim_stats(u_long off __unused, const char *name, int af1 __unused, + int proto __unused) { struct pimstat pimstat, zerostat; size_t len = sizeof pimstat; - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet.pim.stats", &pimstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - if (errno != ENOENT) - warn("sysctl: net.inet.pim.stats"); - return; + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet.pim.stats", &pimstat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + if (errno != ENOENT) + warn("sysctl: net.inet.pim.stats"); + return; + } + } else { + if (off == 0) + return; + kread(off, &pimstat, len); } printf("%s:\n", name); diff --git a/usr.bin/netstat/inet6.c b/usr.bin/netstat/inet6.c index 7b4f54d..945075c 100644 --- a/usr.bin/netstat/inet6.c +++ b/usr.bin/netstat/inet6.c @@ -362,22 +362,24 @@ static char *srcrule_str[] = { * Dump IP6 statistics structure. */ void -ip6_stats(u_long off __unused, const char *name, int af1 __unused) +ip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct ip6stat ip6stat; int first, i; - int mib[4]; size_t len; - mib[0] = CTL_NET; - mib[1] = PF_INET6; - mib[2] = IPPROTO_IPV6; - mib[3] = IPV6CTL_STATS; - len = sizeof ip6stat; - memset(&ip6stat, 0, len); - if (sysctl(mib, 4, &ip6stat, &len, (void *)0, 0) < 0) - return; + if (live) { + memset(&ip6stat, 0, len); + if (sysctlbyname("net.inet6.ip6.stats", &ip6stat, &len, NULL, + 0) < 0) { + if (errno != ENOENT) + warn("sysctl: net.inet6.ip6.stats"); + return; + } + } else + kread(off, &ip6stat, len); + printf("%s:\n", name); #define p(f, m) if (ip6stat.f || sflag <= 1) \ @@ -842,22 +844,24 @@ static const char *icmp6names[] = { * Dump ICMP6 statistics. */ void -icmp6_stats(u_long off __unused, const char *name, int af1 __unused) +icmp6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct icmp6stat icmp6stat; int i, first; - int mib[4]; size_t len; - mib[0] = CTL_NET; - mib[1] = PF_INET6; - mib[2] = IPPROTO_ICMPV6; - mib[3] = ICMPV6CTL_STATS; - len = sizeof icmp6stat; - memset(&icmp6stat, 0, len); - if (sysctl(mib, 4, &icmp6stat, &len, (void *)0, 0) < 0) - return; + if (live) { + memset(&icmp6stat, 0, len); + if (sysctlbyname("net.inet6.icmp6.stats", &icmp6stat, &len, + NULL, 0) < 0) { + if (errno != ENOENT) + warn("sysctl: net.inet6.icmp6.stats"); + return; + } + } else + kread(off, &icmp6stat, len); + printf("%s:\n", name); #define p(f, m) if (icmp6stat.f || sflag <= 1) \ @@ -994,20 +998,26 @@ icmp6_ifstats(char *ifname) * Dump PIM statistics structure. */ void -pim6_stats(u_long off __unused, const char *name, int af1 __unused) +pim6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct pim6stat pim6stat, zerostat; size_t len = sizeof pim6stat; - /* TODO put back the KVM functionality for -M switch ie coredumps. */ - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet6.pim.stats", &pim6stat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - if (errno != ENOENT) - warn("sysctl: net.inet6.pim.stats"); - return; + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet6.pim.stats", &pim6stat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + if (errno != ENOENT) + warn("sysctl: net.inet6.pim.stats"); + return; + } + } else { + if (off == 0) + return; + kread(off, &pim6stat, len); } + printf("%s:\n", name); #define p(f, m) if (pim6stat.f || sflag <= 1) \ @@ -1026,24 +1036,22 @@ pim6_stats(u_long off __unused, const char *name, int af1 __unused) * Dump raw ip6 statistics structure. */ void -rip6_stats(u_long off __unused, const char *name, int af1 __unused) +rip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct rip6stat rip6stat; u_quad_t delivered; - int mib[4]; - size_t l; + size_t len; - mib[0] = CTL_NET; - mib[1] = PF_INET6; - mib[2] = IPPROTO_IPV6; - mib[3] = IPV6CTL_RIP6STATS; - l = sizeof(rip6stat); - if (sysctl(mib, 4, &rip6stat, &l, NULL, 0) < 0) { - /* Just shut up if the kernel doesn't have ipv6. */ - if (errno != ENOENT) - perror("Warning: sysctl(net.inet6.ip6.rip6stats)"); - return; - } + len = sizeof(rip6stat); + if (live) { + if (sysctlbyname("net.inet6.ip6.rip6stats", &rip6stat, &len, + NULL, 0) < 0) { + if (errno != ENOENT) + warn("sysctl: net.inet6.ip6.rip6stats"); + return; + } + } else + kread(off, &rip6stat, len); printf("%s:\n", name); diff --git a/usr.bin/netstat/ipsec.c b/usr.bin/netstat/ipsec.c index 2dc6410..ef3e78f 100644 --- a/usr.bin/netstat/ipsec.c +++ b/usr.bin/netstat/ipsec.c @@ -101,6 +101,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/queue.h> #include <sys/socket.h> +#include <sys/socketvar.h> #include <netinet/in.h> @@ -267,7 +268,7 @@ print_ipsecstats(const struct ipsecstat *ipsecstat) } void -ipsec_stats(u_long off, const char *name, int af1 __unused) +ipsec_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct ipsecstat ipsecstat; @@ -355,7 +356,7 @@ print_ahstats(const struct ahstat *ahstat) } void -ah_stats(u_long off, const char *name, int family __unused) +ah_stats(u_long off, const char *name, int family __unused, int proto __unused) { struct ahstat ahstat; @@ -405,7 +406,7 @@ print_espstats(const struct espstat *espstat) } void -esp_stats(u_long off, const char *name, int family __unused) +esp_stats(u_long off, const char *name, int family __unused, int proto __unused) { struct espstat espstat; @@ -450,7 +451,8 @@ print_ipcompstats(const struct ipcompstat *ipcompstat) } void -ipcomp_stats(u_long off, const char *name, int family __unused) +ipcomp_stats(u_long off, const char *name, int family __unused, + int proto __unused) { struct ipcompstat ipcompstat; diff --git a/usr.bin/netstat/ipx.c b/usr.bin/netstat/ipx.c index b8f50e3..dad5ae8 100644 --- a/usr.bin/netstat/ipx.c +++ b/usr.bin/netstat/ipx.c @@ -82,7 +82,7 @@ extern char *tcpstates[]; */ void -ipxprotopr(u_long off, const char *name, int af1 __unused) +ipxprotopr(u_long off, const char *name, int af1 __unused, int proto __unused) { struct ipxpcbhead cb; struct ipxpcb *ipxp; @@ -155,7 +155,7 @@ ipxprotopr(u_long off, const char *name, int af1 __unused) * Dump SPX statistics structure. */ void -spx_stats(u_long off, const char *name, int af1 __unused) +spx_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct spx_istat spx_istat; #define spxstat spx_istat.newstats @@ -231,7 +231,7 @@ spx_stats(u_long off, const char *name, int af1 __unused) * Dump IPX statistics structure. */ void -ipx_stats(u_long off, const char *name, int af1 __unused) +ipx_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct ipxstat ipxstat; @@ -274,7 +274,7 @@ static struct { */ /*ARGSUSED*/ void -ipxerr_stats(u_long off, const char *name, int af __unused) +ipxerr_stats(u_long off, const char *name, int af __unused, int proto __unused) { struct ipx_errstat ipx_errstat; int j; diff --git a/usr.bin/netstat/main.c b/usr.bin/netstat/main.c index 434121f8..c1decb7 100644 --- a/usr.bin/netstat/main.c +++ b/usr.bin/netstat/main.c @@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$"); #include <sys/file.h> #include <sys/protosw.h> #include <sys/socket.h> +#include <sys/socketvar.h> #include <netinet/in.h> @@ -141,121 +142,154 @@ static struct nlist nl[] = { { .n_name = "_carpstats" }, #define N_PFSYNCSTAT 34 { .n_name = "_pfsyncstats" }, -#define N_AHSTAT 36 +#define N_AHSTAT 35 { .n_name = "_ahstat" }, -#define N_ESPSTAT 37 +#define N_ESPSTAT 36 { .n_name = "_espstat" }, -#define N_IPCOMPSTAT 38 +#define N_IPCOMPSTAT 37 { .n_name = "_ipcompstat" }, +#define N_TCPSTAT 38 + { .n_name = "_tcpstat" }, +#define N_UDPSTAT 39 + { .n_name = "_udpstat" }, +#define N_IPSTAT 40 + { .n_name = "_ipstat" }, +#define N_ICMPSTAT 41 + { .n_name = "_icmpstat" }, +#define N_IGMPSTAT 42 + { .n_name = "_igmpstat" }, +#define N_PIMSTAT 43 + { .n_name = "_pimstat" }, +#define N_TCBINFO 44 + { .n_name = "_tcbinfo" }, +#define N_UDBINFO 45 + { .n_name = "_udbinfo" }, +#define N_DIVCBINFO 46 + { .n_name = "_divcbinfo" }, +#define N_RIPCBINFO 47 + { .n_name = "_ripcbinfo" }, +#define N_UNP_COUNT 48 + { .n_name = "_unp_count" }, +#define N_UNP_GENCNT 49 + { .n_name = "_unp_gencnt" }, +#define N_UNP_DHEAD 50 + { .n_name = "_unp_dhead" }, +#define N_UNP_SHEAD 51 + { .n_name = "_unp_shead" }, +#define N_RIP6STAT 52 + { .n_name = "_rip6stat" }, +#define N_SCTPSTAT 53 + { .n_name = "_sctpstat" }, { .n_name = NULL }, }; struct protox { - u_char pr_index; /* index into nlist of cb head */ - u_char pr_sindex; /* index into nlist of stat block */ + int pr_index; /* index into nlist of cb head */ + int pr_sindex; /* index into nlist of stat block */ u_char pr_wanted; /* 1 if wanted, 0 otherwise */ - void (*pr_cblocks)(u_long, const char *, int); + void (*pr_cblocks)(u_long, const char *, int, int); /* control blocks printing routine */ - void (*pr_stats)(u_long, const char *, int); + void (*pr_stats)(u_long, const char *, int, int); /* statistics printing routine */ void (*pr_istats)(char *); /* per/if statistics printing routine */ const char *pr_name; /* well-known name */ u_long pr_usesysctl; /* non-zero if we use sysctl, not kvm */ + int pr_protocol; } protox[] = { - { -1, -1, 1, protopr, - tcp_stats, NULL, "tcp", IPPROTO_TCP }, - { -1, -1, 1, protopr, - udp_stats, NULL, "udp", IPPROTO_UDP }, + { N_TCBINFO, N_TCPSTAT, 1, protopr, + tcp_stats, NULL, "tcp", 1, IPPROTO_TCP }, + { N_UDBINFO, N_UDPSTAT, 1, protopr, + udp_stats, NULL, "udp", 1, IPPROTO_UDP }, #ifdef SCTP - { -1, -1, 1, sctp_protopr, - sctp_stats, NULL, "sctp", IPPROTO_SCTP }, + { -1, N_SCTPSTAT, 1, sctp_protopr, + sctp_stats, NULL, "sctp", 1, IPPROTO_SCTP }, #endif - { -1, -1, 1, protopr, - NULL, NULL, "divert",IPPROTO_DIVERT }, - { -1, -1, 1, protopr, - ip_stats, NULL, "ip", IPPROTO_RAW }, - { -1, -1, 1, protopr, - icmp_stats, NULL, "icmp", IPPROTO_ICMP }, - { -1, -1, 1, protopr, - igmp_stats, NULL, "igmp", IPPROTO_IGMP }, + { N_DIVCBINFO, -1, 1, protopr, + NULL, NULL, "divert", 1, IPPROTO_DIVERT }, + { N_RIPCBINFO, N_IPSTAT, 1, protopr, + ip_stats, NULL, "ip", 1, IPPROTO_RAW }, + { N_RIPCBINFO, N_ICMPSTAT, 1, protopr, + icmp_stats, NULL, "icmp", 1, IPPROTO_ICMP }, + { N_RIPCBINFO, N_IGMPSTAT, 1, protopr, + igmp_stats, NULL, "igmp", 1, IPPROTO_IGMP }, #ifdef IPSEC { -1, N_IPSECSTAT, 1, NULL, /* keep as compat */ - ipsec_stats, NULL, "ipsec", 0}, + ipsec_stats, NULL, "ipsec", 0, 0}, { -1, N_AHSTAT, 1, NULL, - ah_stats, NULL, "ah", 0}, + ah_stats, NULL, "ah", 0, 0}, { -1, N_ESPSTAT, 1, NULL, - esp_stats, NULL, "esp", 0}, + esp_stats, NULL, "esp", 0, 0}, { -1, N_IPCOMPSTAT, 1, NULL, - ipcomp_stats, NULL, "ipcomp", 0}, + ipcomp_stats, NULL, "ipcomp", 0, 0}, #endif - { -1, -1, 1, protopr, - pim_stats, NULL, "pim", IPPROTO_PIM }, - { -1, N_CARPSTAT, 1, 0, - carp_stats, NULL, "carp", 0}, - { -1, -1, 1, NULL, - pfsync_stats, NULL, "pfsync", 1}, + { N_RIPCBINFO, N_PIMSTAT, 1, protopr, + pim_stats, NULL, "pim", 1, IPPROTO_PIM }, + { -1, N_CARPSTAT, 1, NULL, + carp_stats, NULL, "carp", 1, 0 }, + { -1, N_PFSYNCSTAT, 1, NULL, + pfsync_stats, NULL, "pfsync", 1, 0 }, { -1, -1, 0, NULL, - NULL, NULL, NULL, 0 } + NULL, NULL, NULL, 0, 0 } }; #ifdef INET6 struct protox ip6protox[] = { - { -1, -1, 1, protopr, - tcp_stats, NULL, "tcp", IPPROTO_TCP }, - { -1, -1, 1, protopr, - udp_stats, NULL, "udp", IPPROTO_UDP }, - { -1, N_IP6STAT, 1, protopr, - ip6_stats, ip6_ifstats, "ip6", IPPROTO_RAW }, - { -1, N_ICMP6STAT, 1, protopr, - icmp6_stats, icmp6_ifstats, "icmp6",IPPROTO_ICMPV6 }, + { N_TCBINFO, N_TCPSTAT, 1, protopr, + tcp_stats, NULL, "tcp", 1, IPPROTO_TCP }, + { N_UDBINFO, N_UDPSTAT, 1, protopr, + udp_stats, NULL, "udp", 1, IPPROTO_UDP }, + { N_RIPCBINFO, N_IP6STAT, 1, protopr, + ip6_stats, ip6_ifstats, "ip6", 1, IPPROTO_RAW }, + { N_RIPCBINFO, N_ICMP6STAT, 1, protopr, + icmp6_stats, icmp6_ifstats, "icmp6", 1, IPPROTO_ICMPV6 }, #ifdef IPSEC { -1, N_IPSEC6STAT, 1, NULL, - ipsec_stats, NULL, "ipsec6",0 }, + ipsec_stats, NULL, "ipsec6", 0, 0 }, #endif #ifdef notyet { -1, N_PIM6STAT, 1, NULL, - pim6_stats, NULL, "pim6", 0 }, + pim6_stats, NULL, "pim6", 1, 0 }, #endif - { -1, -1, 1, NULL, - rip6_stats, NULL, "rip6", 0 }, + { -1, N_RIP6STAT, 1, NULL, + rip6_stats, NULL, "rip6", 1, 0 }, { -1, -1, 0, NULL, - NULL, NULL, NULL, 0 } + NULL, NULL, NULL, 0, 0 } }; #endif /*INET6*/ #ifdef IPSEC struct protox pfkeyprotox[] = { { -1, N_PFKEYSTAT, 1, NULL, - pfkey_stats, NULL, "pfkey", 0 }, + pfkey_stats, NULL, "pfkey", 0, 0 }, { -1, -1, 0, NULL, - NULL, NULL, NULL, 0 } + NULL, NULL, NULL, 0, 0 } }; #endif struct protox atalkprotox[] = { { N_DDPCB, N_DDPSTAT, 1, atalkprotopr, - ddp_stats, NULL, "ddp", 0 }, + ddp_stats, NULL, "ddp", 0, 0 }, { -1, -1, 0, NULL, - NULL, NULL, NULL, 0 } + NULL, NULL, NULL, 0, 0 } }; struct protox netgraphprotox[] = { { N_NGSOCKS, -1, 1, netgraphprotopr, - NULL, NULL, "ctrl", 0 }, + NULL, NULL, "ctrl", 0, 0 }, { N_NGSOCKS, -1, 1, netgraphprotopr, - NULL, NULL, "data", 0 }, + NULL, NULL, "data", 0, 0 }, { -1, -1, 0, NULL, - NULL, NULL, NULL, 0 } + NULL, NULL, NULL, 0, 0 } }; #ifdef IPX struct protox ipxprotox[] = { { N_IPX, N_IPXSTAT, 1, ipxprotopr, - ipx_stats, NULL, "ipx", 0 }, + ipx_stats, NULL, "ipx", 0, 0 }, { N_IPX, N_SPXSTAT, 1, ipxprotopr, - spx_stats, NULL, "spx", 0 }, + spx_stats, NULL, "spx", 0, 0 }, { -1, -1, 0, NULL, - NULL, NULL, 0, 0 } + NULL, NULL, 0, 0, 0 } }; #endif @@ -305,6 +339,7 @@ char *interface; /* desired i/f for stats, or NULL for all i/fs */ int unit; /* unit number for above */ int af; /* address family */ +int live; /* true if we are examining a live system */ int main(int argc, char *argv[]) @@ -453,16 +488,19 @@ main(int argc, char *argv[]) * Discard setgid privileges if not the running kernel so that bad * guys can't print interesting stuff from kernel memory. */ - if (nlistf != NULL || memf != NULL) + live = (nlistf == NULL && memf == NULL); + if (!live) setgid(getgid()); if (Bflag) { + if (!live) + usage(); bpf_stats(interface); exit(0); } if (mflag) { if (memf != NULL) { - if (kread(0, 0, 0) == 0) + if (kread(0, NULL, 0) == 0) mbpr(kvmd, nl[N_MBSTAT].n_value); } else mbpr(NULL, 0); @@ -482,13 +520,12 @@ main(int argc, char *argv[]) * used for the queries, which is slower. */ #endif + kread(0, NULL, 0); if (iflag && !sflag) { - kread(0, 0, 0); intpr(interval, nl[N_IFNET].n_value, NULL); exit(0); } if (rflag) { - kread(0, 0, 0); if (sflag) rt_stats(nl[N_RTSTAT].n_value, nl[N_RTTRASH].n_value); else @@ -496,7 +533,6 @@ main(int argc, char *argv[]) exit(0); } if (gflag) { - kread(0, 0, 0); if (sflag) { if (af == AF_INET || af == AF_UNSPEC) mrt_stats(nl[N_MRTSTAT].n_value); @@ -518,7 +554,6 @@ main(int argc, char *argv[]) exit(0); } - kread(0, 0, 0); if (tp) { printproto(tp, tp->pr_name); exit(0); @@ -538,7 +573,6 @@ main(int argc, char *argv[]) #endif /*IPSEC*/ #ifdef IPX if (af == AF_IPX || af == AF_UNSPEC) { - kread(0, 0, 0); for (tp = ipxprotox; tp->pr_name; tp++) printproto(tp, tp->pr_name); } @@ -550,7 +584,8 @@ main(int argc, char *argv[]) for (tp = netgraphprotox; tp->pr_name; tp++) printproto(tp, tp->pr_name); if ((af == AF_UNIX || af == AF_UNSPEC) && !Lflag && !sflag) - unixpr(); + unixpr(nl[N_UNP_COUNT].n_value, nl[N_UNP_GENCNT].n_value, + nl[N_UNP_DHEAD].n_value, nl[N_UNP_SHEAD].n_value); exit(0); } @@ -564,7 +599,7 @@ printproto(tp, name) struct protox *tp; const char *name; { - void (*pr)(u_long, const char *, int); + void (*pr)(u_long, const char *, int, int); u_long off; if (sflag) { @@ -576,17 +611,24 @@ printproto(tp, name) printf("%s: no per-interface stats routine\n", tp->pr_name); return; - } - else { + } else { pr = tp->pr_stats; if (!pr) { if (pflag) printf("%s: no stats routine\n", tp->pr_name); return; - } - off = tp->pr_usesysctl ? tp->pr_usesysctl - : nl[tp->pr_sindex].n_value; + } + if (tp->pr_usesysctl && live) + off = 0; + else if (tp->pr_sindex < 0) { + if (pflag) + printf( + "%s: stats routine doesn't work on cores\n", + tp->pr_name); + return; + } else + off = nl[tp->pr_sindex].n_value; } } else { pr = tp->pr_cblocks; @@ -595,28 +637,36 @@ printproto(tp, name) printf("%s: no PCB routine\n", tp->pr_name); return; } - off = tp->pr_usesysctl ? tp->pr_usesysctl - : nl[tp->pr_index].n_value; + if (tp->pr_usesysctl && live) + off = 0; + else if (tp->pr_index < 0) { + if (pflag) + printf( + "%s: PCB routine doesn't work on cores\n", + tp->pr_name); + return; + } else + off = nl[tp->pr_index].n_value; } - if (pr != NULL && (off || af != AF_UNSPEC)) - (*pr)(off, name, af); + if (pr != NULL && (off || (live && tp->pr_usesysctl) || + af != AF_UNSPEC)) + (*pr)(off, name, af, tp->pr_protocol); } /* * Read kernel memory, return 0 on success. */ int -kread(u_long addr, char *buf, int size) +kread(u_long addr, void *buf, size_t size) { - if (kvmd == 0) { - /* - * XXX. - */ - kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf); + char errbuf[_POSIX2_LINE_MAX]; + + if (kvmd == NULL) { + kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); setgid(getgid()); if (kvmd != NULL) { if (kvm_nlist(kvmd, nl) < 0) { - if(nlistf) + if (nlistf) errx(1, "%s: kvm_nlist: %s", nlistf, kvm_geterr(kvmd)); else @@ -624,20 +674,21 @@ kread(u_long addr, char *buf, int size) } if (nl[0].n_type == 0) { - if(nlistf) + if (nlistf) errx(1, "%s: no namelist", nlistf); else errx(1, "no namelist"); } } else { - warnx("kvm not available"); + warnx("kvm not available: %s", errbuf); return(-1); } } if (!buf) return (0); - if (kvm_read(kvmd, addr, buf, size) != size) { + if (kvm_read(kvmd, addr, buf, size) != (ssize_t)size) { warnx("%s", kvm_geterr(kvmd)); + abort(); return (-1); } return (0); diff --git a/usr.bin/netstat/mbuf.c b/usr.bin/netstat/mbuf.c index 911fc1f..7e09a1e 100644 --- a/usr.bin/netstat/mbuf.c +++ b/usr.bin/netstat/mbuf.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include <sys/mbuf.h> #include <sys/protosw.h> #include <sys/socket.h> +#include <sys/socketvar.h> #include <sys/sysctl.h> #include <err.h> @@ -80,9 +81,8 @@ mbpr(void *kvmd, u_long mbaddr) int nsfbufs, nsfbufspeak, nsfbufsused; struct mbstat mbstat; size_t mlen; - int error, live; + int error; - live = (kvmd == NULL); mtlp = memstat_mtl_alloc(); if (mtlp == NULL) { warn("memstat_mtl_alloc"); diff --git a/usr.bin/netstat/mcast.c b/usr.bin/netstat/mcast.c index ce0d042..7348934 100644 --- a/usr.bin/netstat/mcast.c +++ b/usr.bin/netstat/mcast.c @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include <sys/types.h> #include <sys/socket.h> +#include <sys/socketvar.h> #include <net/if.h> #include <net/if_var.h> diff --git a/usr.bin/netstat/mroute.c b/usr.bin/netstat/mroute.c index acf6ddc..d3cf740 100644 --- a/usr.bin/netstat/mroute.c +++ b/usr.bin/netstat/mroute.c @@ -84,32 +84,24 @@ mroutepr(u_long mfcaddr, u_long vifaddr) size_t len; len = sizeof(mfctable); - if (sysctlbyname("net.inet.ip.mfctable", mfctable, &len, NULL, 0) < 0) { - warn("sysctl: net.inet.ip.mfctable"); - if (mfcaddr == 0) { - printf("No IPv4 multicast forwarding configured in " - "the running system.\n"); + if (live) { + if (sysctlbyname("net.inet.ip.mfctable", mfctable, &len, NULL, + 0) < 0) { + warn("sysctl: net.inet.ip.mfctable"); return; } - /* - * XXX: Try KVM if the module is neither compiled nor loaded. - * The correct behaviour would be to always use KVM if - * the -M option is specified to netstat(1). - */ + } else kread(mfcaddr, (char *)mfctable, sizeof(mfctable)); - } len = sizeof(viftable); - if (sysctlbyname("net.inet.ip.viftable", viftable, &len, NULL, 0) < 0) { - warn("sysctl: net.inet.ip.viftable"); - if (vifaddr == 0) { - printf("No IPv4 multicast forwarding configured in " - "the running system.\n"); + if (live) { + if (sysctlbyname("net.inet.ip.viftable", viftable, &len, NULL, + 0) < 0) { + warn("sysctl: net.inet.ip.viftable"); return; } - /* XXX KVM */ + } else kread(vifaddr, (char *)viftable, sizeof(viftable)); - } saved_numeric_addr = numeric_addr; numeric_addr = 1; @@ -276,18 +268,15 @@ mrt_stats(u_long mstaddr) struct mrtstat mrtstat; size_t len = sizeof mrtstat; - if (sysctlbyname("net.inet.ip.mrtstat", &mrtstat, &len, - NULL, 0) < 0) { - warn("sysctl: net.inet.ip.mrtstat"); - /* Compatability with older kernels - candidate for removal */ - if (mstaddr == 0) { - printf("No IPv4 multicast forwarding configured in " - "the running system.\n"); + if (live) { + if (sysctlbyname("net.inet.ip.mrtstat", &mrtstat, &len, NULL, + 0) < 0) { + warn("sysctl: net.inet.ip.mrtstat"); return; } - /* XXX KVM */ + } else kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat)); - } + printf("IPv4 multicast forwarding:\n"); #define p(f, m) if (mrtstat.f || sflag <= 1) \ diff --git a/usr.bin/netstat/mroute6.c b/usr.bin/netstat/mroute6.c index f071b5b..6b4230d 100644 --- a/usr.bin/netstat/mroute6.c +++ b/usr.bin/netstat/mroute6.c @@ -116,16 +116,14 @@ mroute6pr(u_long mfcaddr, u_long mifaddr) size_t len; len = sizeof(mif6table); - if (sysctlbyname("net.inet6.ip6.mif6table", mif6table, &len, - NULL, 0) < 0) { - warn("sysctl: net.inet6.ip6.mif6table"); - if (mifaddr == 0) { - printf("No IPv6 multicast forwarding configured in " - "the running system.\n"); + if (live) { + if (sysctlbyname("net.inet6.ip6.mif6table", mif6table, &len, + NULL, 0) < 0) { + warn("sysctl: net.inet6.ip6.mif6table"); return; } + } else kread(mifaddr, (char *)mif6table, sizeof(mif6table)); - } saved_numeric_addr = numeric_addr; numeric_addr = 1; @@ -161,21 +159,14 @@ mroute6pr(u_long mfcaddr, u_long mifaddr) printf("\nIPv6 Multicast Interface Table is empty\n"); len = sizeof(mf6ctable); - if (sysctlbyname("net.inet6.ip6.mf6ctable", mf6ctable, &len, - NULL, 0) < 0) { - warn("sysctl: net.inet6.ip6.mf6ctable"); - if (mfcaddr == 0) { - printf("No IPv6 multicast forwarding configured in " - "the running system.\n"); + if (live) { + if (sysctlbyname("net.inet6.ip6.mf6ctable", mf6ctable, &len, + NULL, 0) < 0) { + warn("sysctl: net.inet6.ip6.mf6ctable"); return; } - /* - * XXX: Try KVM if the module is neither compiled nor loaded. - * The correct behaviour would be to always use KVM if - * the -M option is specified to netstat(1). - */ + } else kread(mfcaddr, (char *)mf6ctable, sizeof(mf6ctable)); - } banner_printed = 0; @@ -232,16 +223,15 @@ mrt6_stats(u_long mstaddr) struct mrt6stat mrtstat; size_t len = sizeof mrtstat; - if (sysctlbyname("net.inet6.ip6.mrt6stat", &mrtstat, &len, - NULL, 0) < 0) { - warn("sysctl: net.inet6.ip6.mrt6stat"); - if (mstaddr == 0) { - printf("No IPv6 multicast forwarding configured in the " - "running system.\n"); + if (live) { + if (sysctlbyname("net.inet6.ip6.mrt6stat", &mrtstat, &len, + NULL, 0) < 0) { + warn("sysctl: net.inet6.ip6.mrt6stat"); return; } + } else kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat)); - } + printf("IPv6 multicast forwarding:\n"); #define p(f, m) if (mrtstat.f || sflag <= 1) \ diff --git a/usr.bin/netstat/netgraph.c b/usr.bin/netstat/netgraph.c index 77db23f..8ca9e5c 100644 --- a/usr.bin/netstat/netgraph.c +++ b/usr.bin/netstat/netgraph.c @@ -62,7 +62,8 @@ static int first = 1; static int csock = -1; void -netgraphprotopr(u_long off, const char *name, int af1 __unused) +netgraphprotopr(u_long off, const char *name, int af1 __unused, + int proto __unused) { struct ngpcb *this, *next; struct ngpcb ngpcb; @@ -81,6 +82,10 @@ netgraphprotopr(u_long off, const char *name, int af1 __unused) struct kld_file_stat ks; int fileid; + /* Can't do this for core dumps. */ + if (!live) + return; + /* See if module is loaded */ if ((fileid = kldfind(modname)) < 0) { if (debug) diff --git a/usr.bin/netstat/netstat.h b/usr.bin/netstat/netstat.h index a2df187..0c6f733 100644 --- a/usr.bin/netstat/netstat.h +++ b/usr.bin/netstat/netstat.h @@ -59,39 +59,41 @@ extern char *interface; /* desired i/f for stats, or NULL for all i/fs */ extern int unit; /* unit number for above */ extern int af; /* address family */ +extern int live; /* true if we are examining a live system */ -int kread(u_long addr, char *buf, int size); +int kread(u_long addr, void *buf, size_t size); const char *plural(uintmax_t); const char *plurales(uintmax_t); const char *pluralies(uintmax_t); -void protopr(u_long, const char *, int); -void tcp_stats(u_long, const char *, int); -void udp_stats(u_long, const char *, int); +int sotoxsocket(struct socket *, struct xsocket *); +void protopr(u_long, const char *, int, int); +void tcp_stats(u_long, const char *, int, int); +void udp_stats(u_long, const char *, int, int); #ifdef SCTP -void sctp_protopr(u_long, const char *, int); -void sctp_stats(u_long, const char *, int); +void sctp_protopr(u_long, const char *, int, int); +void sctp_stats(u_long, const char *, int, int); #endif -void ip_stats(u_long, const char *, int); -void icmp_stats(u_long, const char *, int); -void igmp_stats(u_long, const char *, int); -void pim_stats(u_long, const char *, int); -void carp_stats (u_long, const char *, int); -void pfsync_stats (u_long, const char *, int); +void ip_stats(u_long, const char *, int, int); +void icmp_stats(u_long, const char *, int, int); +void igmp_stats(u_long, const char *, int, int); +void pim_stats(u_long, const char *, int, int); +void carp_stats (u_long, const char *, int, int); +void pfsync_stats (u_long, const char *, int, int); #ifdef IPSEC -void ipsec_stats(u_long, const char *, int); -void esp_stats (u_long, const char *, int); -void ah_stats (u_long, const char *, int); -void ipcomp_stats (u_long, const char *, int); +void ipsec_stats(u_long, const char *, int, int); +void esp_stats (u_long, const char *, int, int); +void ah_stats (u_long, const char *, int, int); +void ipcomp_stats (u_long, const char *, int, int); #endif #ifdef INET6 -void ip6_stats(u_long, const char *, int); +void ip6_stats(u_long, const char *, int, int); void ip6_ifstats(char *); -void icmp6_stats(u_long, const char *, int); +void icmp6_stats(u_long, const char *, int, int); void icmp6_ifstats(char *); -void pim6_stats(u_long, const char *, int); -void rip6_stats(u_long, const char *, int); +void pim6_stats(u_long, const char *, int, int); +void rip6_stats(u_long, const char *, int, int); void mroute6pr(u_long, u_long); void mrt6_stats(u_long); @@ -103,7 +105,7 @@ void inet6print(struct in6_addr *, int, const char *, int); #endif /*INET6*/ #ifdef IPSEC -void pfkey_stats(u_long, const char *, int); +void pfkey_stats(u_long, const char *, int, int); #endif void mbpr(void *, u_long); @@ -129,29 +131,29 @@ char *ipx_print(struct sockaddr *); char *ns_print(struct sockaddr *); void routepr(u_long); -void ipxprotopr(u_long, const char *, int); -void spx_stats(u_long, const char *, int); -void ipx_stats(u_long, const char *, int); -void ipxerr_stats(u_long, const char *, int); +void ipxprotopr(u_long, const char *, int, int); +void spx_stats(u_long, const char *, int, int); +void ipx_stats(u_long, const char *, int, int); +void ipxerr_stats(u_long, const char *, int, int); -void nsprotopr(u_long, const char *, int); -void spp_stats(u_long, const char *, int); -void idp_stats(u_long, const char *, int); -void nserr_stats(u_long, const char *, int); +void nsprotopr(u_long, const char *, int, int); +void spp_stats(u_long, const char *, int, int); +void idp_stats(u_long, const char *, int, int); +void nserr_stats(u_long, const char *, int, int); -void atalkprotopr(u_long, const char *, int); -void ddp_stats(u_long, const char *, int); +void atalkprotopr(u_long, const char *, int, int); +void ddp_stats(u_long, const char *, int, int); -void netgraphprotopr(u_long, const char *, int); +void netgraphprotopr(u_long, const char *, int, int); -void unixpr(void); +void unixpr(u_long, u_long, u_long, u_long); -void esis_stats(u_long, const char *, int); -void clnp_stats(u_long, const char *, int); -void cltp_stats(u_long, const char *, int); -void iso_protopr(u_long, const char *, int); +void esis_stats(u_long, const char *, int, int); +void clnp_stats(u_long, const char *, int, int); +void cltp_stats(u_long, const char *, int, int); +void iso_protopr(u_long, const char *, int, int); void iso_protopr1(u_long, int); -void tp_protopr(u_long, const char *, int); +void tp_protopr(u_long, const char *, int, int); void tp_inproto(u_long); void tp_stats(caddr_t, caddr_t); diff --git a/usr.bin/netstat/pfkey.c b/usr.bin/netstat/pfkey.c index ad22ae8..47fccb7 100644 --- a/usr.bin/netstat/pfkey.c +++ b/usr.bin/netstat/pfkey.c @@ -76,6 +76,7 @@ static const char rcsid[] = #include <sys/param.h> #include <sys/queue.h> #include <sys/socket.h> +#include <sys/socketvar.h> #include <netinet/in.h> @@ -116,7 +117,8 @@ pfkey_msgtype_names(int x) } void -pfkey_stats(u_long off, const char *name, int family __unused) +pfkey_stats(u_long off, const char *name, int family __unused, + int proto __unused) { struct pfkeystat pfkeystat; unsigned first, type; diff --git a/usr.bin/netstat/route.c b/usr.bin/netstat/route.c index f13dff8..a0a8990 100644 --- a/usr.bin/netstat/route.c +++ b/usr.bin/netstat/route.c @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/protosw.h> #include <sys/socket.h> +#include <sys/socketvar.h> #include <sys/time.h> #include <net/ethernet.h> diff --git a/usr.bin/netstat/sctp.c b/usr.bin/netstat/sctp.c index b3038d3..feb9a25 100644 --- a/usr.bin/netstat/sctp.c +++ b/usr.bin/netstat/sctp.c @@ -432,8 +432,8 @@ sctp_process_inpcb(struct xsctp_inpcb *xinpcb, const char *name, * protocol. */ void -sctp_protopr(u_long proto, - const char *name, int af1) +sctp_protopr(u_long off __unused, + const char *name, int af1, int proto) { char *buf; const char *mibvar = "net.inet.sctp.assoclist"; @@ -511,18 +511,21 @@ sctp_statesprint(uint32_t state) * Dump SCTP statistics structure. */ void -sctp_stats(u_long off __unused, const char *name, int af1 __unused) +sctp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct sctpstat sctpstat, zerostat; size_t len = sizeof(sctpstat); - if (zflag) - memset(&zerostat, 0, len); - if (sysctlbyname("net.inet.sctp.stats", &sctpstat, &len, - zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { - warn("sysctl: net.inet.sctp.stats"); - return; - } + if (live) { + if (zflag) + memset(&zerostat, 0, len); + if (sysctlbyname("net.inet.sctp.stats", &sctpstat, &len, + zflag ? &zerostat : NULL, zflag ? len : 0) < 0) { + warn("sysctl: net.inet.sctp.stats"); + return; + } + } else + kread(off, &sctpstat, len); printf ("%s:\n", name); diff --git a/usr.bin/netstat/unix.c b/usr.bin/netstat/unix.c index be70d5b..03bef85 100644 --- a/usr.bin/netstat/unix.c +++ b/usr.bin/netstat/unix.c @@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$"); #include <stdint.h> #include <stdio.h> #include <stdlib.h> +#include <strings.h> #include <kvm.h> #include "netstat.h" @@ -69,35 +70,148 @@ static void unixdomainpr (struct xunpcb *, struct xsocket *); static const char *const socktype[] = { "#0", "stream", "dgram", "raw", "rdm", "seqpacket" }; -void -unixpr(void) +static int +pcblist_sysctl(int type, char **bufp) { char *buf; - int type; size_t len; - struct xsocket *so; - struct xunpgen *xug, *oxug; - struct xunpcb *xunp; char mibvar[sizeof "net.local.seqpacket.pcblist"]; - for (type = SOCK_STREAM; type <= SOCK_SEQPACKET; type++) { - sprintf(mibvar, "net.local.%s.pcblist", socktype[type]); + sprintf(mibvar, "net.local.%s.pcblist", socktype[type]); + + len = 0; + if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) { + if (errno != ENOENT) + warn("sysctl: %s", mibvar); + return (-1); + } + if ((buf = malloc(len)) == 0) { + warnx("malloc %lu bytes", (u_long)len); + return (-2); + } + if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) { + warn("sysctl: %s", mibvar); + free(buf); + return (-2); + } + *bufp = buf; + return (0); +} + +static int +pcblist_kvm(u_long count_off, u_long gencnt_off, u_long head_off, char **bufp) +{ + struct unp_head head; + struct unpcb *unp, unp_conn; + u_char sun_len; + struct socket so; + struct xunpgen xug; + struct xunpcb xu; + unp_gen_t unp_gencnt; + u_int unp_count; + char *buf, *p; + size_t len; + + if (count_off == 0 || gencnt_off == 0) + return (-2); + if (head_off == 0) + return (-1); + kread(count_off, &unp_count, sizeof(unp_count)); + len = 2 * sizeof(xug) + (unp_count + unp_count / 8) * sizeof(xu); + if ((buf = malloc(len)) == 0) { + warnx("malloc %lu bytes", (u_long)len); + return (-2); + } + p = buf; + +#define COPYOUT(obj, size) do { \ + if (len < (size)) { \ + warnx("buffer size exceeded"); \ + goto fail; \ + } \ + bcopy((obj), p, (size)); \ + len -= (size); \ + p += (size); \ +} while (0) + +#define KREAD(off, buf, len) do { \ + if (kread((uintptr_t)(off), (buf), (len)) != 0) \ + goto fail; \ +} while (0) + + /* Write out header. */ + kread(gencnt_off, &unp_gencnt, sizeof(unp_gencnt)); + xug.xug_len = sizeof xug; + xug.xug_count = unp_count; + xug.xug_gen = unp_gencnt; + xug.xug_sogen = 0; + COPYOUT(&xug, sizeof xug); - len = 0; - if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) { - if (errno != ENOENT) - warn("sysctl: %s", mibvar); + /* Walk the PCB list. */ + xu.xu_len = sizeof xu; + KREAD(head_off, &head, sizeof(head)); + LIST_FOREACH(unp, &head, unp_link) { + xu.xu_unpp = unp; + KREAD(unp, &xu.xu_unp, sizeof (*unp)); + unp = &xu.xu_unp; + + if (unp->unp_gencnt > unp_gencnt) continue; + if (unp->unp_addr != NULL) { + KREAD(unp->unp_addr, &sun_len, sizeof(sun_len)); + KREAD(unp->unp_addr, &xu.xu_addr, sun_len); } - if ((buf = malloc(len)) == 0) { - warnx("malloc %lu bytes", (u_long)len); - return; + if (unp->unp_conn != NULL) { + KREAD(unp->unp_conn, &unp_conn, sizeof(unp_conn)); + if (unp_conn.unp_addr != NULL) { + KREAD(unp_conn.unp_addr, &sun_len, + sizeof(sun_len)); + KREAD(unp_conn.unp_addr, &xu.xu_caddr, sun_len); + } } - if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) { - warn("sysctl: %s", mibvar); - free(buf); + KREAD(unp->unp_socket, &so, sizeof(so)); + if (sotoxsocket(&so, &xu.xu_socket) != 0) + goto fail; + COPYOUT(&xu, sizeof(xu)); + } + + /* Reread the counts and write the footer. */ + kread(count_off, &unp_count, sizeof(unp_count)); + kread(gencnt_off, &unp_gencnt, sizeof(unp_gencnt)); + xug.xug_count = unp_count; + xug.xug_gen = unp_gencnt; + COPYOUT(&xug, sizeof xug); + + *bufp = buf; + return (0); + +fail: + free(buf); + return (-1); +#undef COPYOUT +#undef KREAD +} + +void +unixpr(u_long count_off, u_long gencnt_off, u_long dhead_off, u_long shead_off) +{ + char *buf; + int ret, type; + struct xsocket *so; + struct xunpgen *xug, *oxug; + struct xunpcb *xunp; + + for (type = SOCK_STREAM; type <= SOCK_SEQPACKET; type++) { + if (live) + ret = pcblist_sysctl(type, &buf); + else + ret = pcblist_kvm(count_off, gencnt_off, + type == SOCK_STREAM ? shead_off : + (type == SOCK_DGRAM ? dhead_off : 0), &buf); + if (ret == -1) + continue; + if (ret < 0) return; - } oxug = xug = (struct xunpgen *)buf; for (xug = (struct xunpgen *)((char *)xug + xug->xug_len); |