diff options
Diffstat (limited to 'usr.bin/netstat/unix.c')
-rw-r--r-- | usr.bin/netstat/unix.c | 152 |
1 files changed, 133 insertions, 19 deletions
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); |