--- //depot/yahoo/ybsd_6/src/usr.bin/netstat/inet.c 2007/05/14 16:20:51 +++ //depot/jhb/bsd6/src/usr.bin/netstat/inet.c 2007/07/06 14:39:45 @@ -91,42 +91,28 @@ static int udp_done, tcp_done; #endif /* INET6 */ -/* - * Print a summary of connections related to an Internet - * protocol. For TCP, also give state of connection. - * Listening processes (aflag) are suppressed unless the - * -a (all) flag is specified. - */ -void -protopr(u_long proto, /* for sysctl version we pass proto # */ - const char *name, int af1) +static int +pcb_read_sysctl(u_long proto, const char *name, char **bufp, int *istcp) { - int istcp; - static int first = 1; + const char *mibvar; char *buf; - const char *mibvar, *vchar; - struct tcpcb *tp = NULL; - struct inpcb *inp; - struct xinpgen *xig, *oxig; - struct xsocket *so; size_t len; - istcp = 0; switch (proto) { case IPPROTO_TCP: #ifdef INET6 if (tcp_done != 0) - return; + return (0); else tcp_done = 1; #endif - istcp = 1; + *istcp = 1; mibvar = "net.inet.tcp.pcblist"; break; case IPPROTO_UDP: #ifdef INET6 if (udp_done != 0) - return; + return (0); else udp_done = 1; #endif @@ -139,20 +125,214 @@ mibvar = "net.inet.raw.pcblist"; break; } + len = 0; if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) { if (errno != ENOENT) warn("sysctl: %s", mibvar); - return; + return (0); } if ((buf = malloc(len)) == 0) { warnx("malloc %lu bytes", (u_long)len); - return; + return (0); } if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) { warn("sysctl: %s", mibvar); free(buf); - return; + 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; +} + +static void +sotoxsocket(struct socket *so, struct xsocket *xso) +{ + 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; + 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); +} + +static int +pcb_read_kvm(u_long off, const char *name, 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 (strcmp(name, "tcp") == 0) { + *istcp = 1; +#ifdef INET6 + if (tcp_done != 0) + return (0); + else + tcp_done = 1; + } else if (strcmp(name, "udp") == 0) { + if (udp_done != 0) + return (0); + else + udp_done = 1; +#endif + } + + 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.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)); + sotoxsocket(&so, xso); + } else + bzero(xso, sizeof(*xso)); + 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. + * Listening processes (aflag) are suppressed unless the + * -a (all) flag is specified. + */ +void +protopr(u_long proto, /* for sysctl version we pass proto # */ + const char *name, int af1) +{ + int istcp; + static int first = 1; + char *buf; + const char *vchar; + struct tcpcb *tp = NULL; + struct inpcb *inp; + struct xinpgen *xig, *oxig; + struct xsocket *so; + + istcp = 0; + if (live) { + if (!pcb_read_sysctl(proto, name, &buf, &istcp)) + return; + } else { + if (!pcb_read_kvm(proto, name, &buf, &istcp)) + return; } oxig = xig = (struct xinpgen *)buf; @@ -171,7 +351,7 @@ } /* Ignore sockets for protocols other than the desired one. */ - if (so->xso_protocol != (int)proto) + if (live && so->xso_protocol != (int)proto) continue; /* Ignore PCBs which were freed during copyout. */ @@ -391,18 +571,10 @@ * 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) { 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) @@ -411,6 +583,17 @@ 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) \ @@ -527,20 +710,12 @@ * 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) { 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; @@ -548,6 +723,17 @@ 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)) @@ -586,13 +772,19 @@ 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); @@ -626,18 +818,21 @@ * 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) { 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); @@ -731,26 +926,23 @@ * 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) { 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); @@ -802,30 +994,35 @@ #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) { 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); @@ -855,13 +1052,19 @@ 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); --- //depot/yahoo/ybsd_6/src/usr.bin/netstat/main.c 2007/05/03 11:31:05 +++ //depot/jhb/bsd6/src/usr.bin/netstat/main.c 2007/07/06 14:51:14 @@ -148,12 +148,30 @@ { "_espstat" }, #define N_IPCOMPSTAT 38 { "_ipcompstat" }, +#define N_TCPSTAT 39 + { "_tcpstat" }, +#define N_UDPSTAT 40 + { "_udpstat" }, +#define N_IPSTAT 41 + { "_ipstat" }, +#define N_ICMPSTAT 42 + { "_icmpstat" }, +#define N_IGMPSTAT 43 + { "_igmpstat" }, +#define N_PIMSTAT 44 + { "_pimstat" }, +#define N_TCBINFO 45 + { "_tcbinfo" }, +#define N_UDBINFO 46 + { "_udbinfo" }, +#define N_DIVCBINFO 47 + { "_divcbinfo" }, { "" }, }; 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); /* control blocks printing routine */ @@ -163,37 +181,37 @@ const char *pr_name; /* well-known name */ u_long pr_usesysctl; /* non-zero if we use sysctl, not kvm */ } protox[] = { - { -1, -1, 1, protopr, + { N_TCBINFO, N_TCPSTAT, 1, protopr, tcp_stats, NULL, "tcp", IPPROTO_TCP }, - { -1, -1, 1, protopr, + { N_UDBINFO, N_UDPSTAT, 1, protopr, udp_stats, NULL, "udp", IPPROTO_UDP }, - { -1, -1, 1, protopr, + { N_DIVCBINFO, -1, 1, protopr, NULL, NULL, "divert",IPPROTO_DIVERT }, - { -1, -1, 1, protopr, + { -1, N_IPSTAT, 1, protopr, ip_stats, NULL, "ip", IPPROTO_RAW }, - { -1, -1, 1, protopr, + { -1, N_ICMPSTAT, 1, protopr, icmp_stats, NULL, "icmp", IPPROTO_ICMP }, - { -1, -1, 1, protopr, + { -1, N_IGMPSTAT, 1, protopr, igmp_stats, NULL, "igmp", IPPROTO_IGMP }, #ifdef IPSEC { -1, N_IPSECSTAT, 1, NULL, ipsec_stats, NULL, "ipsec", 0}, #ifdef FAST_IPSEC - { -1, N_FAST_IPSECSTAT, 1, 0, + { -1, N_FAST_IPSECSTAT, 1, NULL, ipsec_stats_new, NULL, "fastipsec", 0}, - { -1, N_AHSTAT, 1, 0, + { -1, N_AHSTAT, 1, NULL, ah_stats, NULL, "ah", 0}, - { -1, N_ESPSTAT, 1, 0, + { -1, N_ESPSTAT, 1, NULL, esp_stats, NULL, "esp", 0}, - { -1, N_IPCOMPSTAT, 1, 0, + { -1, N_IPCOMPSTAT, 1, NULL, ipcomp_stats, NULL, "ipcomp", 0}, #endif #endif { -1, -1, 1, NULL, bdg_stats, NULL, "bdg", 1 /* bridging... */ }, - { -1, -1, 1, protopr, + { -1, N_PIMSTAT, 1, protopr, pim_stats, NULL, "pim", IPPROTO_PIM }, - { -1, N_CARPSTAT, 1, 0, + { -1, N_CARPSTAT, 1, NULL, carp_stats, NULL, "carp", 0}, { -1, -1, 1, NULL, pfsync_stats, NULL, "pfsync", 1}, @@ -213,7 +231,7 @@ icmp6_stats, icmp6_ifstats, "icmp6",IPPROTO_ICMPV6 }, #ifdef IPSEC { -1, N_IPSEC6STAT, 1, NULL, - ipsec_stats, NULL, "ipsec6",0 }, + ipsec_stats, NULL, "ipsec6", 0 }, #endif #ifdef notyet { -1, N_PIM6STAT, 1, NULL, @@ -307,6 +325,7 @@ 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[]) @@ -458,7 +477,8 @@ * 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) { @@ -467,7 +487,7 @@ } 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); @@ -487,13 +507,12 @@ * 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 @@ -501,7 +520,6 @@ exit(0); } if (gflag) { - kread(0, 0, 0); if (sflag) { if (af == AF_INET || af == AF_UNSPEC) mrt_stats(nl[N_MRTSTAT].n_value); @@ -523,7 +541,6 @@ exit(0); } - kread(0, 0, 0); if (tp) { #ifdef FAST_IPSEC /* @@ -558,7 +575,6 @@ printproto(tp, tp->pr_name); #endif /*IPSEC*/ if (af == AF_IPX || af == AF_UNSPEC) { - kread(0, 0, 0); for (tp = ipxprotox; tp->pr_name; tp++) printproto(tp, tp->pr_name); } @@ -595,8 +611,7 @@ printf("%s: no per-interface stats routine\n", tp->pr_name); return; - } - else { + } else { pr = tp->pr_stats; if (!pr) { if (pflag) @@ -604,8 +619,16 @@ tp->pr_name); return; } - off = tp->pr_usesysctl ? tp->pr_usesysctl - : nl[tp->pr_sindex].n_value; + if (tp->pr_usesysctl && live) + off = tp->pr_usesysctl; + 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; @@ -614,8 +637,16 @@ 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 = tp->pr_usesysctl; + 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); @@ -625,17 +656,16 @@ * 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 @@ -643,13 +673,13 @@ } 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); } } --- //depot/yahoo/ybsd_6/src/usr.bin/netstat/netstat.h 2007/05/03 11:31:05 +++ //depot/jhb/bsd6/src/usr.bin/netstat/netstat.h 2007/07/06 12:15:54 @@ -60,8 +60,9 @@ 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(int); const char *plurales(int); const char *pluralies(int);