Index: head/usr.bin/netstat/if.c =================================================================== --- head/usr.bin/netstat/if.c (revision 311391) +++ head/usr.bin/netstat/if.c (revision 311392) @@ -1,655 +1,655 @@ /*- * Copyright (c) 2013 Gleb Smirnoff * Copyright (c) 1983, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static char sccsid[] = "@(#)if.c 8.3 (Berkeley) 4/28/95"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #ifdef PF #include #include #endif #include #include #include #include #ifdef INET6 #include #endif #include #include #include #include #include #include #include #include #include #include "netstat.h" static void sidewaysintpr(void); #ifdef PF static const char* pfsyncacts[] = { /* PFSYNC_ACT_CLR */ "clear all request", /* PFSYNC_ACT_INS */ "state insert", /* PFSYNC_ACT_INS_ACK */ "state inserted ack", /* PFSYNC_ACT_UPD */ "state update", /* PFSYNC_ACT_UPD_C */ "compressed state update", /* PFSYNC_ACT_UPD_REQ */ "uncompressed state request", /* PFSYNC_ACT_DEL */ "state delete", /* PFSYNC_ACT_DEL_C */ "compressed state delete", /* PFSYNC_ACT_INS_F */ "fragment insert", /* PFSYNC_ACT_DEL_F */ "fragment delete", /* PFSYNC_ACT_BUS */ "bulk update mark", /* PFSYNC_ACT_TDB */ "TDB replay counter update", /* PFSYNC_ACT_EOF */ "end of frame mark", }; static const char* pfsyncacts_name[] = { /* PFSYNC_ACT_CLR */ "clear-all-request", /* PFSYNC_ACT_INS */ "state-insert", /* PFSYNC_ACT_INS_ACK */ "state-inserted-ack", /* PFSYNC_ACT_UPD */ "state-update", /* PFSYNC_ACT_UPD_C */ "compressed-state-update", /* PFSYNC_ACT_UPD_REQ */ "uncompressed-state-request", /* PFSYNC_ACT_DEL */ "state-delete", /* PFSYNC_ACT_DEL_C */ "compressed-state-delete", /* PFSYNC_ACT_INS_F */ "fragment-insert", /* PFSYNC_ACT_DEL_F */ "fragment-delete", /* PFSYNC_ACT_BUS */ "bulk-update-mark", /* PFSYNC_ACT_TDB */ "TDB-replay-counter-update", /* PFSYNC_ACT_EOF */ "end-of-frame-mark", }; static void pfsync_acts_stats(const char *list, const char *desc, uint64_t *a) { int i; xo_open_list(list); for (i = 0; i < PFSYNC_ACT_MAX; i++, a++) { if (*a || sflag <= 1) { xo_open_instance(list); xo_emit("\t\t{e:name}{:count/%ju} {N:/%s%s %s}\n", pfsyncacts_name[i], (uintmax_t)(*a), pfsyncacts[i], plural(*a), desc); xo_close_instance(list); } } xo_close_list(list); } /* * Dump pfsync statistics structure. */ void pfsync_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct pfsyncstats pfsyncstat; if (fetch_stats("net.pfsync.stats", off, &pfsyncstat, sizeof(pfsyncstat), kread) != 0) return; xo_emit("{T:/%s}:\n", name); xo_open_container(name); #define p(f, m) if (pfsyncstat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)pfsyncstat.f, plural(pfsyncstat.f)) p(pfsyncs_ipackets, "\t{:received-inet-packets/%ju} " "{N:/packet%s received (IPv4)}\n"); p(pfsyncs_ipackets6, "\t{:received-inet6-packets/%ju} " "{N:/packet%s received (IPv6)}\n"); pfsync_acts_stats("input-histogram", "received", &pfsyncstat.pfsyncs_iacts[0]); p(pfsyncs_badif, "\t\t/{:dropped-bad-interface/%ju} " "{N:/packet%s discarded for bad interface}\n"); p(pfsyncs_badttl, "\t\t{:dropped-bad-ttl/%ju} " "{N:/packet%s discarded for bad ttl}\n"); p(pfsyncs_hdrops, "\t\t{:dropped-short-header/%ju} " "{N:/packet%s shorter than header}\n"); p(pfsyncs_badver, "\t\t{:dropped-bad-version/%ju} " "{N:/packet%s discarded for bad version}\n"); p(pfsyncs_badauth, "\t\t{:dropped-bad-auth/%ju} " "{N:/packet%s discarded for bad HMAC}\n"); p(pfsyncs_badact,"\t\t{:dropped-bad-action/%ju} " "{N:/packet%s discarded for bad action}\n"); p(pfsyncs_badlen, "\t\t{:dropped-short/%ju} " "{N:/packet%s discarded for short packet}\n"); p(pfsyncs_badval, "\t\t{:dropped-bad-values/%ju} " "{N:/state%s discarded for bad values}\n"); p(pfsyncs_stale, "\t\t{:dropped-stale-state/%ju} " "{N:/stale state%s}\n"); p(pfsyncs_badstate, "\t\t{:dropped-failed-lookup/%ju} " "{N:/failed state lookup\\/insert%s}\n"); p(pfsyncs_opackets, "\t{:sent-inet-packets/%ju} " "{N:/packet%s sent (IPv4})\n"); p(pfsyncs_opackets6, "\t{:send-inet6-packets/%ju} " "{N:/packet%s sent (IPv6})\n"); pfsync_acts_stats("output-histogram", "sent", &pfsyncstat.pfsyncs_oacts[0]); p(pfsyncs_onomem, "\t\t{:discarded-no-memory/%ju} " "{N:/failure%s due to mbuf memory error}\n"); p(pfsyncs_oerrors, "\t\t{:send-errors/%ju} " "{N:/send error%s}\n"); #undef p xo_close_container(name); } #endif /* PF */ /* * Display a formatted value, or a '-' in the same space. */ static void show_stat(const char *fmt, int width, const char *name, u_long value, short showvalue, int div1000) { const char *lsep, *rsep; char newfmt[64]; lsep = ""; if (strncmp(fmt, "LS", 2) == 0) { lsep = " "; fmt += 2; } rsep = " "; if (strncmp(fmt, "NRS", 3) == 0) { rsep = ""; fmt += 3; } if (showvalue == 0) { /* Print just dash. */ xo_emit("{P:/%s}{D:/%*s}{P:/%s}", lsep, width, "-", rsep); return; } /* * XXX: workaround {P:} modifier can't be empty and doesn't seem to * take args... so we need to conditionally include it in the format. */ #define maybe_pad(pad) do { \ if (strlen(pad)) { \ snprintf(newfmt, sizeof(newfmt), "{P:%s}", pad); \ xo_emit(newfmt); \ } \ } while (0) if (hflag) { char buf[5]; /* Format in human readable form. */ humanize_number(buf, sizeof(buf), (int64_t)value, "", HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL | \ ((div1000) ? HN_DIVISOR_1000 : 0)); maybe_pad(lsep); snprintf(newfmt, sizeof(newfmt), "{:%s/%%%ds}", name, width); xo_emit(newfmt, buf); maybe_pad(rsep); } else { /* Construct the format string. */ maybe_pad(lsep); snprintf(newfmt, sizeof(newfmt), "{:%s/%%%d%s}", name, width, fmt); xo_emit(newfmt, value); maybe_pad(rsep); } } /* * Find next multiaddr for a given interface name. */ static struct ifmaddrs * next_ifma(struct ifmaddrs *ifma, const char *name, const sa_family_t family) { for(; ifma != NULL; ifma = ifma->ifma_next) { struct sockaddr_dl *sdl; sdl = (struct sockaddr_dl *)ifma->ifma_name; if (ifma->ifma_addr->sa_family == family && strcmp(sdl->sdl_data, name) == 0) break; } return (ifma); } /* * Print a description of the network interfaces. */ void intpr(void (*pfunc)(char *), int af) { struct ifaddrs *ifap, *ifa; struct ifmaddrs *ifmap, *ifma; u_int ifn_len_max = 5, ifn_len; u_int has_ipv6 = 0, net_len = 13, addr_len = 17; if (interval) return sidewaysintpr(); if (getifaddrs(&ifap) != 0) err(EX_OSERR, "getifaddrs"); if (aflag && getifmaddrs(&ifmap) != 0) err(EX_OSERR, "getifmaddrs"); if (Wflag) { for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if (interface != NULL && strcmp(ifa->ifa_name, interface) != 0) continue; if (af != AF_UNSPEC && ifa->ifa_addr->sa_family != af) continue; ifn_len = strlen(ifa->ifa_name); if ((ifa->ifa_flags & IFF_UP) == 0) ++ifn_len; ifn_len_max = MAX(ifn_len_max, ifn_len); if (ifa->ifa_addr->sa_family == AF_INET6) has_ipv6 = 1; } if (has_ipv6) { net_len = 24; addr_len = 39; } else net_len = 18; } xo_open_list("interface"); if (!pfunc) { xo_emit("{T:/%-*.*s}", ifn_len_max, ifn_len_max, "Name"); xo_emit(" {T:/%5.5s} {T:/%-*.*s} {T:/%-*.*s} {T:/%8.8s} " "{T:/%5.5s} {T:/%5.5s}", "Mtu", net_len, net_len, "Network", addr_len, addr_len, "Address", "Ipkts", "Ierrs", "Idrop"); if (bflag) xo_emit(" {T:/%10.10s}","Ibytes"); xo_emit(" {T:/%8.8s} {T:/%5.5s}", "Opkts", "Oerrs"); if (bflag) xo_emit(" {T:/%10.10s}","Obytes"); xo_emit(" {T:/%5s}", "Coll"); if (dflag) xo_emit(" {T:/%5.5s}", "Drop"); xo_emit("\n"); } for (ifa = ifap; ifa; ifa = ifa->ifa_next) { bool network = false, link = false; char *name, *xname, buf[IFNAMSIZ+1]; const char *nn, *rn; if (interface != NULL && strcmp(ifa->ifa_name, interface) != 0) continue; name = ifa->ifa_name; if (pfunc) { (*pfunc)(name); /* * Skip all ifaddrs belonging to same interface. */ while(ifa->ifa_next != NULL && (strcmp(ifa->ifa_next->ifa_name, name) == 0)) { ifa = ifa->ifa_next; } continue; } if (af != AF_UNSPEC && ifa->ifa_addr->sa_family != af) continue; xo_open_instance("interface"); if ((ifa->ifa_flags & IFF_UP) == 0) { xname = stpcpy(buf, name); *xname++ = '*'; *xname = '\0'; xname = buf; } else xname = name; xo_emit("{d:/%-*.*s}{etk:name}{eq:flags/0x%x}", ifn_len_max, ifn_len_max, xname, name, ifa->ifa_flags); #define IFA_MTU(ifa) (((struct if_data *)(ifa)->ifa_data)->ifi_mtu) show_stat("lu", 6, "mtu", IFA_MTU(ifa), IFA_MTU(ifa), 0); #undef IFA_MTU switch (ifa->ifa_addr->sa_family) { case AF_UNSPEC: xo_emit("{:network/%-*.*s} ", net_len, net_len, "none"); xo_emit("{:address/%-*.*s} ", addr_len, addr_len, "none"); break; case AF_INET: #ifdef INET6 case AF_INET6: #endif /* INET6 */ nn = netname(ifa->ifa_addr, ifa->ifa_netmask); rn = routename(ifa->ifa_addr, numeric_addr); if (Wflag) { xo_emit("{t:network/%-*s} ", net_len, nn); xo_emit("{t:address/%-*s} ", addr_len, rn); } else { xo_emit("{d:network/%-*.*s}{et:network} ", net_len, net_len, nn, nn); xo_emit("{d:address/%-*.*s}{et:address} ", addr_len, addr_len, rn, rn); } network = true; break; case AF_LINK: { struct sockaddr_dl *sdl; - char linknum[10]; + char linknum[sizeof("")]; sdl = (struct sockaddr_dl *)ifa->ifa_addr; - sprintf(linknum, "", sdl->sdl_index); + snprintf(linknum, sizeof(linknum), "", sdl->sdl_index); xo_emit("{t:network/%-*.*s} ", net_len, net_len, linknum); if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && sdl->sdl_slen == 0) xo_emit("{P:/%*s} ", addr_len, ""); else xo_emit("{t:address/%-*.*s} ", addr_len, addr_len, routename(ifa->ifa_addr, 1)); link = true; break; } } #define IFA_STAT(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s) show_stat("lu", 8, "received-packets", IFA_STAT(ipackets), link|network, 1); show_stat("lu", 5, "received-errors", IFA_STAT(ierrors), link, 1); show_stat("lu", 5, "dropped-packets", IFA_STAT(iqdrops), link, 1); if (bflag) show_stat("lu", 10, "received-bytes", IFA_STAT(ibytes), link|network, 0); show_stat("lu", 8, "sent-packets", IFA_STAT(opackets), link|network, 1); show_stat("lu", 5, "send-errors", IFA_STAT(oerrors), link, 1); if (bflag) show_stat("lu", 10, "sent-bytes", IFA_STAT(obytes), link|network, 0); show_stat("NRSlu", 5, "collisions", IFA_STAT(collisions), link, 1); if (dflag) show_stat("LSlu", 5, "dropped-packets", IFA_STAT(oqdrops), link, 1); xo_emit("\n"); if (!aflag) { xo_close_instance("interface"); continue; } /* * Print family's multicast addresses. */ xo_open_list("multicast-address"); for (ifma = next_ifma(ifmap, ifa->ifa_name, ifa->ifa_addr->sa_family); ifma != NULL; ifma = next_ifma(ifma, ifa->ifa_name, ifa->ifa_addr->sa_family)) { const char *fmt = NULL; xo_open_instance("multicast-address"); switch (ifma->ifma_addr->sa_family) { case AF_LINK: { struct sockaddr_dl *sdl; sdl = (struct sockaddr_dl *)ifma->ifma_addr; if (sdl->sdl_type != IFT_ETHER && sdl->sdl_type != IFT_FDDI) break; } /* FALLTHROUGH */ case AF_INET: #ifdef INET6 case AF_INET6: #endif /* INET6 */ fmt = routename(ifma->ifma_addr, numeric_addr); break; } if (fmt) { if (Wflag) xo_emit("{P:/%27s }" "{t:address/%-17s/}", "", fmt); else xo_emit("{P:/%25s }" "{t:address/%-17.17s/}", "", fmt); if (ifma->ifma_addr->sa_family == AF_LINK) { xo_emit(" {:received-packets/%8lu}", IFA_STAT(imcasts)); xo_emit("{P:/%*s}", bflag? 17 : 6, ""); xo_emit(" {:sent-packets/%8lu}", IFA_STAT(omcasts)); } xo_emit("\n"); } xo_close_instance("multicast-address"); ifma = ifma->ifma_next; } xo_close_list("multicast-address"); xo_close_instance("interface"); } xo_close_list("interface"); freeifaddrs(ifap); if (aflag) freeifmaddrs(ifmap); } struct iftot { u_long ift_ip; /* input packets */ u_long ift_ie; /* input errors */ u_long ift_id; /* input drops */ u_long ift_op; /* output packets */ u_long ift_oe; /* output errors */ u_long ift_od; /* output drops */ u_long ift_co; /* collisions */ u_long ift_ib; /* input bytes */ u_long ift_ob; /* output bytes */ }; /* * Obtain stats for interface(s). */ static void fill_iftot(struct iftot *st) { struct ifaddrs *ifap, *ifa; bool found = false; if (getifaddrs(&ifap) != 0) xo_err(EX_OSERR, "getifaddrs"); bzero(st, sizeof(*st)); for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family != AF_LINK) continue; if (interface) { if (strcmp(ifa->ifa_name, interface) == 0) found = true; else continue; } st->ift_ip += IFA_STAT(ipackets); st->ift_ie += IFA_STAT(ierrors); st->ift_id += IFA_STAT(iqdrops); st->ift_ib += IFA_STAT(ibytes); st->ift_op += IFA_STAT(opackets); st->ift_oe += IFA_STAT(oerrors); st->ift_od += IFA_STAT(oqdrops); st->ift_ob += IFA_STAT(obytes); st->ift_co += IFA_STAT(collisions); } if (interface && found == false) xo_err(EX_DATAERR, "interface %s not found", interface); freeifaddrs(ifap); } /* * Set a flag to indicate that a signal from the periodic itimer has been * caught. */ static sig_atomic_t signalled; static void catchalarm(int signo __unused) { signalled = true; } /* * Print a running summary of interface statistics. * Repeat display every interval seconds, showing statistics * collected over that interval. Assumes that interval is non-zero. * First line printed at top of screen is always cumulative. */ static void sidewaysintpr(void) { struct iftot ift[2], *new, *old; struct itimerval interval_it; int oldmask, line; new = &ift[0]; old = &ift[1]; fill_iftot(old); (void)signal(SIGALRM, catchalarm); signalled = false; interval_it.it_interval.tv_sec = interval; interval_it.it_interval.tv_usec = 0; interval_it.it_value = interval_it.it_interval; setitimer(ITIMER_REAL, &interval_it, NULL); xo_open_list("interface-statistics"); banner: xo_emit("{T:/%17s} {T:/%14s} {T:/%16s}\n", "input", interface != NULL ? interface : "(Total)", "output"); xo_emit("{T:/%10s} {T:/%5s} {T:/%5s} {T:/%10s} {T:/%10s} {T:/%5s} " "{T:/%10s} {T:/%5s}", "packets", "errs", "idrops", "bytes", "packets", "errs", "bytes", "colls"); if (dflag) xo_emit(" {T:/%5.5s}", "drops"); xo_emit("\n"); xo_flush(); line = 0; loop: if ((noutputs != 0) && (--noutputs == 0)) { xo_close_list("interface-statistics"); return; } oldmask = sigblock(sigmask(SIGALRM)); while (!signalled) sigpause(0); signalled = false; sigsetmask(oldmask); line++; fill_iftot(new); xo_open_instance("stats"); show_stat("lu", 10, "received-packets", new->ift_ip - old->ift_ip, 1, 1); show_stat("lu", 5, "received-errors", new->ift_ie - old->ift_ie, 1, 1); show_stat("lu", 5, "dropped-packets", new->ift_id - old->ift_id, 1, 1); show_stat("lu", 10, "received-bytes", new->ift_ib - old->ift_ib, 1, 0); show_stat("lu", 10, "sent-packets", new->ift_op - old->ift_op, 1, 1); show_stat("lu", 5, "send-errors", new->ift_oe - old->ift_oe, 1, 1); show_stat("lu", 10, "sent-bytes", new->ift_ob - old->ift_ob, 1, 0); show_stat("NRSlu", 5, "collisions", new->ift_co - old->ift_co, 1, 1); if (dflag) show_stat("LSlu", 5, "dropped-packets", new->ift_od - old->ift_od, 1, 1); xo_close_instance("stats"); xo_emit("\n"); xo_flush(); if (new == &ift[0]) { new = &ift[1]; old = &ift[0]; } else { new = &ift[0]; old = &ift[1]; } if (line == 21) goto banner; else goto loop; /* NOTREACHED */ } Index: head/usr.bin/netstat/inet.c =================================================================== --- head/usr.bin/netstat/inet.c (revision 311391) +++ head/usr.bin/netstat/inet.c (revision 311392) @@ -1,1488 +1,1494 @@ /*- * Copyright (c) 1983, 1988, 1993, 1995 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static char sccsid[] = "@(#)inet.c 8.5 (Berkeley) 5/24/95"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef INET6 #include #endif /* INET6 */ #include #include #include #include #include #include #include #include #include #define TCPSTATES #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "netstat.h" #include "nl_defs.h" -char *inetname(struct in_addr *); void inetprint(const char *, struct in_addr *, int, const char *, int, const int); #ifdef INET6 static int udp_done, tcp_done, sdp_done; #endif /* INET6 */ static int pcblist_sysctl(int proto, const char *name, char **bufp, int istcp __unused) { 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; } if (strncmp(name, "sdp", 3) == 0) mibvar = "net.inet.sdp.pcblist"; len = 0; if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) { if (errno != ENOENT) xo_warn("sysctl: %s", mibvar); return (0); } if ((buf = malloc(len)) == NULL) { xo_warnx("malloc %lu bytes", (u_long)len); return (0); } if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) { xo_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_ccc; xsb->sb_hiwat = sb->sb_hiwat; xsb->sb_mbcnt = sb->sb_mbcnt; xsb->sb_mcnt = sb->sb_mcnt; xsb->sb_ccnt = sb->sb_ccnt; 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)) == NULL) { xo_warnx("malloc %lu bytes", (u_long)len); return (0); } p = buf; #define COPYOUT(obj, size) do { \ if (len < (size)) { \ xo_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_flags & 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. * Listening processes (aflag) are suppressed unless the * -a (all) flag is specified. */ void protopr(u_long off, const char *name, int af1, int proto) { 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; struct xtcp_timer *timer; istcp = 0; switch (proto) { case IPPROTO_TCP: #ifdef INET6 if (strncmp(name, "sdp", 3) != 0) { if (tcp_done != 0) return; else tcp_done = 1; } else { if (sdp_done != 0) return; else sdp_done = 1; } #endif istcp = 1; break; case IPPROTO_UDP: #ifdef INET6 if (udp_done != 0) return; else udp_done = 1; #endif break; } if (live) { if (!pcblist_sysctl(proto, name, &buf, istcp)) return; } else { if (!pcblist_kvm(off, &buf, istcp)) return; } oxig = xig = (struct xinpgen *)buf; for (xig = (struct xinpgen *)((char *)xig + xig->xig_len); xig->xig_len > sizeof(struct xinpgen); xig = (struct xinpgen *)((char *)xig + xig->xig_len)) { if (istcp) { timer = &((struct xtcpcb *)xig)->xt_timer; tp = &((struct xtcpcb *)xig)->xt_tp; inp = &((struct xtcpcb *)xig)->xt_inp; so = &((struct xtcpcb *)xig)->xt_socket; } else { inp = &((struct xinpcb *)xig)->xi_inp; so = &((struct xinpcb *)xig)->xi_socket; timer = NULL; } /* Ignore sockets for protocols other than the desired one. */ if (so->xso_protocol != proto) continue; /* Ignore PCBs which were freed during copyout. */ if (inp->inp_gencnt > oxig->xig_gen) continue; if ((af1 == AF_INET && (inp->inp_vflag & INP_IPV4) == 0) #ifdef INET6 || (af1 == AF_INET6 && (inp->inp_vflag & INP_IPV6) == 0) #endif /* INET6 */ || (af1 == AF_UNSPEC && ((inp->inp_vflag & INP_IPV4) == 0 #ifdef INET6 && (inp->inp_vflag & INP_IPV6) == 0 #endif /* INET6 */ )) ) continue; if (!aflag && ( (istcp && tp->t_state == TCPS_LISTEN) || (af1 == AF_INET && inet_lnaof(inp->inp_laddr) == INADDR_ANY) #ifdef INET6 || (af1 == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) #endif /* INET6 */ || (af1 == AF_UNSPEC && (((inp->inp_vflag & INP_IPV4) != 0 && inet_lnaof(inp->inp_laddr) == INADDR_ANY) #ifdef INET6 || ((inp->inp_vflag & INP_IPV6) != 0 && IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) #endif )) )) continue; if (first) { if (!Lflag) { xo_emit("Active Internet connections"); if (aflag) xo_emit(" (including servers)"); } else xo_emit( "Current listen queue sizes (qlen/incqlen/maxqlen)"); xo_emit("\n"); if (Aflag) xo_emit("{T:/%-*s} ", 2 * (int)sizeof(void *), "Tcpcb"); if (Lflag) xo_emit((Aflag && !Wflag) ? "{T:/%-5.5s} {T:/%-32.32s} {T:/%-18.18s}" : ((!Wflag || af1 == AF_INET) ? "{T:/%-5.5s} {T:/%-32.32s} {T:/%-22.22s}" : "{T:/%-5.5s} {T:/%-32.32s} {T:/%-45.45s}"), "Proto", "Listen", "Local Address"); else if (Tflag) xo_emit((Aflag && !Wflag) ? "{T:/%-5.5s} {T:/%-6.6s} {T:/%-6.6s} {T:/%-6.6s} {T:/%-18.18s} {T:/%s}" : ((!Wflag || af1 == AF_INET) ? "{T:/%-5.5s} {T:/%-6.6s} {T:/%-6.6s} {T:/%-6.6s} {T:/%-22.22s} {T:/%s}" : "{T:/%-5.5s} {T:/%-6.6s} {T:/%-6.6s} {T:/%-6.6s} {T:/%-45.45s} {T:/%s}"), "Proto", "Rexmit", "OOORcv", "0-win", "Local Address", "Foreign Address"); else { xo_emit((Aflag && !Wflag) ? "{T:/%-5.5s} {T:/%-6.6s} {T:/%-6.6s} {T:/%-18.18s} {T:/%-18.18s}" : ((!Wflag || af1 == AF_INET) ? "{T:/%-5.5s} {T:/%-6.6s} {T:/%-6.6s} {T:/%-22.22s} {T:/%-22.22s}" : "{T:/%-5.5s} {T:/%-6.6s} {T:/%-6.6s} {T:/%-45.45s} {T:/%-45.45s}"), "Proto", "Recv-Q", "Send-Q", "Local Address", "Foreign Address"); if (!xflag && !Rflag) xo_emit(" (state)"); } if (xflag) { xo_emit(" {T:/%-6.6s} {T:/%-6.6s} {T:/%-6.6s} " "{T:/%-6.6s} {T:/%-6.6s} {T:/%-6.6s} " "{T:/%-6.6s} {T:/%-6.6s} {T:/%-6.6s} " "{T:/%-6.6s} {T:/%-6.6s} {T:/%-6.6s}", "R-MBUF", "S-MBUF", "R-CLUS", "S-CLUS", "R-HIWA", "S-HIWA", "R-LOWA", "S-LOWA", "R-BCNT", "S-BCNT", "R-BMAX", "S-BMAX"); xo_emit(" {T:/%7.7s} {T:/%7.7s} {T:/%7.7s} " "{T:/%7.7s} {T:/%7.7s} {T:/%7.7s}", "rexmt", "persist", "keep", "2msl", "delack", "rcvtime"); } else if (Rflag) { xo_emit(" {T:/%8.8s} {T:/%5.5s}", "flowid", "ftype"); } xo_emit("\n"); first = 0; } if (Lflag && so->so_qlimit == 0) continue; xo_open_instance("socket"); if (Aflag) { if (istcp) xo_emit("{q:address/%*lx} ", 2 * (int)sizeof(void *), (u_long)inp->inp_ppcb); else xo_emit("{q:adddress/%*lx} ", 2 * (int)sizeof(void *), (u_long)so->so_pcb); } #ifdef INET6 if ((inp->inp_vflag & INP_IPV6) != 0) vchar = ((inp->inp_vflag & INP_IPV4) != 0) ? "46" : "6"; else #endif vchar = ((inp->inp_vflag & INP_IPV4) != 0) ? "4" : ""; if (istcp && (tp->t_flags & TF_TOE) != 0) xo_emit("{:protocol/%-3.3s%-2.2s/%s%s} ", "toe", vchar); else xo_emit("{:protocol/%-3.3s%-2.2s/%s%s} ", name, vchar); if (Lflag) { char buf1[33]; snprintf(buf1, sizeof buf1, "%u/%u/%u", so->so_qlen, so->so_incqlen, so->so_qlimit); xo_emit("{:listen-queue-sizes/%-32.32s} ", buf1); } else if (Tflag) { if (istcp) xo_emit("{:sent-retransmit-packets/%6u} " "{:received-out-of-order-packets/%6u} " "{:sent-zero-window/%6u} ", tp->t_sndrexmitpack, tp->t_rcvoopack, tp->t_sndzerowin); else xo_emit("{P:/%21s}", ""); } else { xo_emit("{:receive-bytes-waiting/%6u} " "{:send-bytes-waiting/%6u} ", so->so_rcv.sb_cc, so->so_snd.sb_cc); } if (numeric_port) { if (inp->inp_vflag & INP_IPV4) { inetprint("local", &inp->inp_laddr, (int)inp->inp_lport, name, 1, af1); if (!Lflag) inetprint("remote", &inp->inp_faddr, (int)inp->inp_fport, name, 1, af1); } #ifdef INET6 else if (inp->inp_vflag & INP_IPV6) { inet6print("local", &inp->in6p_laddr, (int)inp->inp_lport, name, 1); if (!Lflag) inet6print("remote", &inp->in6p_faddr, (int)inp->inp_fport, name, 1); } /* else nothing printed now */ #endif /* INET6 */ } else if (inp->inp_flags & INP_ANONPORT) { if (inp->inp_vflag & INP_IPV4) { inetprint("local", &inp->inp_laddr, (int)inp->inp_lport, name, 1, af1); if (!Lflag) inetprint("remote", &inp->inp_faddr, (int)inp->inp_fport, name, 0, af1); } #ifdef INET6 else if (inp->inp_vflag & INP_IPV6) { inet6print("local", &inp->in6p_laddr, (int)inp->inp_lport, name, 1); if (!Lflag) inet6print("remote", &inp->in6p_faddr, (int)inp->inp_fport, name, 0); } /* else nothing printed now */ #endif /* INET6 */ } else { if (inp->inp_vflag & INP_IPV4) { inetprint("local", &inp->inp_laddr, (int)inp->inp_lport, name, 0, af1); if (!Lflag) inetprint("remote", &inp->inp_faddr, (int)inp->inp_fport, name, inp->inp_lport != inp->inp_fport, af1); } #ifdef INET6 else if (inp->inp_vflag & INP_IPV6) { inet6print("local", &inp->in6p_laddr, (int)inp->inp_lport, name, 0); if (!Lflag) inet6print("remote", &inp->in6p_faddr, (int)inp->inp_fport, name, inp->inp_lport != inp->inp_fport); } /* else nothing printed now */ #endif /* INET6 */ } if (xflag) { xo_emit("{:receive-mbufs/%6u} {:send-mbufs/%6u} " "{:receive-clusters/%6u} {:send-clusters/%6u} " "{:receive-high-water/%6u} {:send-high-water/%6u} " "{:receive-low-water/%6u} {:send-low-water/%6u} " "{:receive-mbuf-bytes/%6u} {:send-mbuf-bytes/%6u} " "{:receive-mbuf-bytes-max/%6u} " "{:send-mbuf-bytes-max/%6u}", so->so_rcv.sb_mcnt, so->so_snd.sb_mcnt, so->so_rcv.sb_ccnt, so->so_snd.sb_ccnt, so->so_rcv.sb_hiwat, so->so_snd.sb_hiwat, so->so_rcv.sb_lowat, so->so_snd.sb_lowat, so->so_rcv.sb_mbcnt, so->so_snd.sb_mbcnt, so->so_rcv.sb_mbmax, so->so_snd.sb_mbmax); if (timer != NULL) xo_emit(" {:retransmit-timer/%4d.%02d} " "{:persist-timer/%4d.%02d} " "{:keepalive-timer/%4d.%02d} " "{:msl2-timer/%4d.%02d} " "{:delay-ack-timer/%4d.%02d} " "{:inactivity-timer/%4d.%02d}", timer->tt_rexmt / 1000, (timer->tt_rexmt % 1000) / 10, timer->tt_persist / 1000, (timer->tt_persist % 1000) / 10, timer->tt_keep / 1000, (timer->tt_keep % 1000) / 10, timer->tt_2msl / 1000, (timer->tt_2msl % 1000) / 10, timer->tt_delack / 1000, (timer->tt_delack % 1000) / 10, timer->t_rcvtime / 1000, (timer->t_rcvtime % 1000) / 10); } if (istcp && !Lflag && !xflag && !Tflag && !Rflag) { if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES) xo_emit("{:tcp-state/%d}", tp->t_state); else { xo_emit("{:tcp-state/%s}", tcpstates[tp->t_state]); #if defined(TF_NEEDSYN) && defined(TF_NEEDFIN) /* Show T/TCP `hidden state' */ if (tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN)) xo_emit("{:need-syn-or-fin/*}"); #endif /* defined(TF_NEEDSYN) && defined(TF_NEEDFIN) */ } } if (Rflag) { /* XXX: is this right Alfred */ xo_emit(" {:flow-id/%08x} {:flow-type/%5d}", inp->inp_flowid, inp->inp_flowtype); } xo_emit("\n"); xo_close_instance("socket"); } if (xig != oxig && xig->xig_gen != oxig->xig_gen) { if (oxig->xig_count > xig->xig_count) { xo_emit("Some {d:lost/%s} sockets may have been " "deleted.\n", name); } else if (oxig->xig_count < xig->xig_count) { xo_emit("Some {d:created/%s} sockets may have been " "created.\n", name); } else { xo_emit("Some {d:changed/%s} sockets may have been " "created or deleted.\n", name); } } free(buf); } /* * Dump TCP statistics structure. */ void tcp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct tcpstat tcpstat; uint64_t tcps_states[TCP_NSTATES]; #ifdef INET6 if (tcp_done != 0) return; else tcp_done = 1; #endif if (fetch_stats("net.inet.tcp.stats", off, &tcpstat, sizeof(tcpstat), kread_counters) != 0) return; if (fetch_stats_ro("net.inet.tcp.states", nl[N_TCPS_STATES].n_value, &tcps_states, sizeof(tcps_states), kread_counters) != 0) return; xo_open_container("tcp"); xo_emit("{T:/%s}:\n", name); #define p(f, m) if (tcpstat.f || sflag <= 1) \ xo_emit(m, (uintmax_t )tcpstat.f, plural(tcpstat.f)) #define p1a(f, m) if (tcpstat.f || sflag <= 1) \ xo_emit(m, (uintmax_t )tcpstat.f) #define p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \ xo_emit(m, (uintmax_t )tcpstat.f1, plural(tcpstat.f1), \ (uintmax_t )tcpstat.f2, plural(tcpstat.f2)) #define p2a(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \ xo_emit(m, (uintmax_t )tcpstat.f1, plural(tcpstat.f1), \ (uintmax_t )tcpstat.f2) #define p3(f, m) if (tcpstat.f || sflag <= 1) \ xo_emit(m, (uintmax_t )tcpstat.f, pluralies(tcpstat.f)) p(tcps_sndtotal, "\t{:sent-packets/%ju} {N:/packet%s sent}\n"); p2(tcps_sndpack,tcps_sndbyte, "\t\t{:sent-data-packets/%ju} " "{N:/data packet%s} ({:sent-data-bytes/%ju} {N:/byte%s})\n"); p2(tcps_sndrexmitpack, tcps_sndrexmitbyte, "\t\t" "{:sent-retransmitted-packets/%ju} {N:/data packet%s} " "({:sent-retransmitted-bytes/%ju} {N:/byte%s}) " "{N:retransmitted}\n"); p(tcps_sndrexmitbad, "\t\t" "{:sent-unnecessary-retransmitted-packets/%ju} " "{N:/data packet%s unnecessarily retransmitted}\n"); p(tcps_mturesent, "\t\t{:sent-resends-by-mtu-discovery/%ju} " "{N:/resend%s initiated by MTU discovery}\n"); p2a(tcps_sndacks, tcps_delack, "\t\t{:sent-ack-only-packets/%ju} " "{N:/ack-only packet%s/} ({:sent-packets-delayed/%ju} " "{N:delayed})\n"); p(tcps_sndurg, "\t\t{:sent-urg-only-packets/%ju} " "{N:/URG only packet%s}\n"); p(tcps_sndprobe, "\t\t{:sent-window-probe-packets/%ju} " "{N:/window probe packet%s}\n"); p(tcps_sndwinup, "\t\t{:sent-window-update-packets/%ju} " "{N:/window update packet%s}\n"); p(tcps_sndctrl, "\t\t{:sent-control-packets/%ju} " "{N:/control packet%s}\n"); p(tcps_rcvtotal, "\t{:received-packets/%ju} " "{N:/packet%s received}\n"); p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t" "{:received-ack-packets/%ju} {N:/ack%s} " "{N:(for} {:received-ack-bytes/%ju} {N:/byte%s})\n"); p(tcps_rcvdupack, "\t\t{:received-duplicate-acks/%ju} " "{N:/duplicate ack%s}\n"); p(tcps_rcvacktoomuch, "\t\t{:received-acks-for-unsent-data/%ju} " "{N:/ack%s for unsent data}\n"); p2(tcps_rcvpack, tcps_rcvbyte, "\t\t" "{:received-in-sequence-packets/%ju} {N:/packet%s} " "({:received-in-sequence-bytes/%ju} {N:/byte%s}) " "{N:received in-sequence}\n"); p2(tcps_rcvduppack, tcps_rcvdupbyte, "\t\t" "{:received-completely-duplicate-packets/%ju} " "{N:/completely duplicate packet%s} " "({:received-completely-duplicate-bytes/%ju} {N:/byte%s})\n"); p(tcps_pawsdrop, "\t\t{:received-old-duplicate-packets/%ju} " "{N:/old duplicate packet%s}\n"); p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte, "\t\t" "{:received-some-duplicate-packets/%ju} " "{N:/packet%s with some dup. data} " "({:received-some-duplicate-bytes/%ju} {N:/byte%s duped/})\n"); p2(tcps_rcvoopack, tcps_rcvoobyte, "\t\t{:received-out-of-order/%ju} " "{N:/out-of-order packet%s} " "({:received-out-of-order-bytes/%ju} {N:/byte%s})\n"); p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin, "\t\t" "{:received-after-window-packets/%ju} {N:/packet%s} " "({:received-after-window-bytes/%ju} {N:/byte%s}) " "{N:of data after window}\n"); p(tcps_rcvwinprobe, "\t\t{:received-window-probes/%ju} " "{N:/window probe%s}\n"); p(tcps_rcvwinupd, "\t\t{:receive-window-update-packets/%ju} " "{N:/window update packet%s}\n"); p(tcps_rcvafterclose, "\t\t{:received-after-close-packets/%ju} " "{N:/packet%s received after close}\n"); p(tcps_rcvbadsum, "\t\t{:discard-bad-checksum/%ju} " "{N:/discarded for bad checksum%s}\n"); p(tcps_rcvbadoff, "\t\t{:discard-bad-header-offset/%ju} " "{N:/discarded for bad header offset field%s}\n"); p1a(tcps_rcvshort, "\t\t{:discard-too-short/%ju} " "{N:discarded because packet too short}\n"); p1a(tcps_rcvmemdrop, "\t\t{:discard-memory-problems/%ju} " "{N:discarded due to memory problems}\n"); p(tcps_connattempt, "\t{:connection-requests/%ju} " "{N:/connection request%s}\n"); p(tcps_accepts, "\t{:connections-accepts/%ju} " "{N:/connection accept%s}\n"); p(tcps_badsyn, "\t{:bad-connection-attempts/%ju} " "{N:/bad connection attempt%s}\n"); p(tcps_listendrop, "\t{:listen-queue-overflows/%ju} " "{N:/listen queue overflow%s}\n"); p(tcps_badrst, "\t{:ignored-in-window-resets/%ju} " "{N:/ignored RSTs in the window%s}\n"); p(tcps_connects, "\t{:connections-established/%ju} " "{N:/connection%s established (including accepts)}\n"); p(tcps_usedrtt, "\t\t{:connections-hostcache-rtt/%ju} " "{N:/time%s used RTT from hostcache}\n"); p(tcps_usedrttvar, "\t\t{:connections-hostcache-rttvar/%ju} " "{N:/time%s used RTT variance from hostcache}\n"); p(tcps_usedssthresh, "\t\t{:connections-hostcache-ssthresh/%ju} " "{N:/time%s used slow-start threshold from hostcache}\n"); p2(tcps_closed, tcps_drops, "\t{:connections-closed/%ju} " "{N:/connection%s closed (including} " "{:connection-drops/%ju} {N:/drop%s})\n"); p(tcps_cachedrtt, "\t\t{:connections-updated-rtt-on-close/%ju} " "{N:/connection%s updated cached RTT on close}\n"); p(tcps_cachedrttvar, "\t\t" "{:connections-updated-variance-on-close/%ju} " "{N:/connection%s updated cached RTT variance on close}\n"); p(tcps_cachedssthresh, "\t\t" "{:connections-updated-ssthresh-on-close/%ju} " "{N:/connection%s updated cached ssthresh on close}\n"); p(tcps_conndrops, "\t{:embryonic-connections-dropped/%ju} " "{N:/embryonic connection%s dropped}\n"); p2(tcps_rttupdated, tcps_segstimed, "\t{:segments-updated-rtt/%ju} " "{N:/segment%s updated rtt (of} " "{:segment-update-attempts/%ju} {N:/attempt%s})\n"); p(tcps_rexmttimeo, "\t{:retransmit-timeouts/%ju} " "{N:/retransmit timeout%s}\n"); p(tcps_timeoutdrop, "\t\t" "{:connections-dropped-by-retransmit-timeout/%ju} " "{N:/connection%s dropped by rexmit timeout}\n"); p(tcps_persisttimeo, "\t{:persist-timeout/%ju} " "{N:/persist timeout%s}\n"); p(tcps_persistdrop, "\t\t" "{:connections-dropped-by-persist-timeout/%ju} " "{N:/connection%s dropped by persist timeout}\n"); p(tcps_finwait2_drops, "\t" "{:connections-dropped-by-finwait2-timeout/%ju} " "{N:/Connection%s (fin_wait_2) dropped because of timeout}\n"); p(tcps_keeptimeo, "\t{:keepalive-timeout/%ju} " "{N:/keepalive timeout%s}\n"); p(tcps_keepprobe, "\t\t{:keepalive-probes/%ju} " "{N:/keepalive probe%s sent}\n"); p(tcps_keepdrops, "\t\t{:connections-dropped-by-keepalives/%ju} " "{N:/connection%s dropped by keepalive}\n"); p(tcps_predack, "\t{:ack-header-predictions/%ju} " "{N:/correct ACK header prediction%s}\n"); p(tcps_preddat, "\t{:data-packet-header-predictions/%ju} " "{N:/correct data packet header prediction%s}\n"); xo_open_container("syncache"); p3(tcps_sc_added, "\t{:entries-added/%ju} " "{N:/syncache entr%s added}\n"); p1a(tcps_sc_retransmitted, "\t\t{:retransmitted/%ju} " "{N:/retransmitted}\n"); p1a(tcps_sc_dupsyn, "\t\t{:duplicates/%ju} {N:/dupsyn}\n"); p1a(tcps_sc_dropped, "\t\t{:dropped/%ju} {N:/dropped}\n"); p1a(tcps_sc_completed, "\t\t{:completed/%ju} {N:/completed}\n"); p1a(tcps_sc_bucketoverflow, "\t\t{:bucket-overflow/%ju} " "{N:/bucket overflow}\n"); p1a(tcps_sc_cacheoverflow, "\t\t{:cache-overflow/%ju} " "{N:/cache overflow}\n"); p1a(tcps_sc_reset, "\t\t{:reset/%ju} {N:/reset}\n"); p1a(tcps_sc_stale, "\t\t{:stale/%ju} {N:/stale}\n"); p1a(tcps_sc_aborted, "\t\t{:aborted/%ju} {N:/aborted}\n"); p1a(tcps_sc_badack, "\t\t{:bad-ack/%ju} {N:/badack}\n"); p1a(tcps_sc_unreach, "\t\t{:unreachable/%ju} {N:/unreach}\n"); p(tcps_sc_zonefail, "\t\t{:zone-failures/%ju} {N:/zone failure%s}\n"); p(tcps_sc_sendcookie, "\t{:sent-cookies/%ju} {N:/cookie%s sent}\n"); p(tcps_sc_recvcookie, "\t{:receivd-cookies/%ju} " "{N:/cookie%s received}\n"); xo_close_container("syncache"); xo_open_container("hostcache"); p3(tcps_hc_added, "\t{:entries-added/%ju} " "{N:/hostcache entr%s added}\n"); p1a(tcps_hc_bucketoverflow, "\t\t{:buffer-overflows/%ju} " "{N:/bucket overflow}\n"); xo_close_container("hostcache"); xo_open_container("sack"); p(tcps_sack_recovery_episode, "\t{:recovery-episodes/%ju} " "{N:/SACK recovery episode%s}\n"); p(tcps_sack_rexmits, "\t{:segment-retransmits/%ju} " "{N:/segment rexmit%s in SACK recovery episodes}\n"); p(tcps_sack_rexmit_bytes, "\t{:byte-retransmits/%ju} " "{N:/byte rexmit%s in SACK recovery episodes}\n"); p(tcps_sack_rcv_blocks, "\t{:received-blocks/%ju} " "{N:/SACK option%s (SACK blocks) received}\n"); p(tcps_sack_send_blocks, "\t{:sent-option-blocks/%ju} " "{N:/SACK option%s (SACK blocks) sent}\n"); p1a(tcps_sack_sboverflow, "\t{:scoreboard-overflows/%ju} " "{N:/SACK scoreboard overflow}\n"); xo_close_container("sack"); xo_open_container("ecn"); p(tcps_ecn_ce, "\t{:ce-packets/%ju} " "{N:/packet%s with ECN CE bit set}\n"); p(tcps_ecn_ect0, "\t{:ect0-packets/%ju} " "{N:/packet%s with ECN ECT(0) bit set}\n"); p(tcps_ecn_ect1, "\t{:ect1-packets/%ju} " "{N:/packet%s with ECN ECT(1) bit set}\n"); p(tcps_ecn_shs, "\t{:handshakes/%ju} " "{N:/successful ECN handshake%s}\n"); p(tcps_ecn_rcwnd, "\t{:congestion-reductions/%ju} " "{N:/time%s ECN reduced the congestion window}\n"); #undef p #undef p1a #undef p2 #undef p2a #undef p3 xo_close_container("ecn"); xo_open_container("TCP connection count by state"); xo_emit("{T:/TCP connection count by state}:\n"); for (int i = 0; i < TCP_NSTATES; i++) { /* * XXXGL: is there a way in libxo to use %s * in the "content string" of a format * string? I failed to do that, that's why * a temporary buffer is used to construct * format string for xo_emit(). */ char fmtbuf[80]; if (sflag > 1 && tcps_states[i] == 0) continue; snprintf(fmtbuf, sizeof(fmtbuf), "\t{:%s/%%ju} " "{Np:/connection ,connections} in %s state\n", tcpstates[i], tcpstates[i]); xo_emit(fmtbuf, (uintmax_t )tcps_states[i]); } xo_close_container("TCP connection count by state"); xo_close_container("tcp"); } /* * Dump UDP statistics structure. */ void udp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct udpstat udpstat; uint64_t delivered; #ifdef INET6 if (udp_done != 0) return; else udp_done = 1; #endif if (fetch_stats("net.inet.udp.stats", off, &udpstat, sizeof(udpstat), kread_counters) != 0) return; xo_open_container("udp"); xo_emit("{T:/%s}:\n", name); #define p(f, m) if (udpstat.f || sflag <= 1) \ xo_emit("\t" m, (uintmax_t)udpstat.f, plural(udpstat.f)) #define p1a(f, m) if (udpstat.f || sflag <= 1) \ xo_emit("\t" m, (uintmax_t)udpstat.f) p(udps_ipackets, "{:received-datagrams/%ju} " "{N:/datagram%s received}\n"); p1a(udps_hdrops, "{:dropped-incomplete-headers/%ju} " "{N:/with incomplete header}\n"); p1a(udps_badlen, "{:dropped-bad-data-length/%ju} " "{N:/with bad data length field}\n"); p1a(udps_badsum, "{:dropped-bad-checksum/%ju} " "{N:/with bad checksum}\n"); p1a(udps_nosum, "{:dropped-no-checksum/%ju} " "{N:/with no checksum}\n"); p1a(udps_noport, "{:dropped-no-socket/%ju} " "{N:/dropped due to no socket}\n"); p(udps_noportbcast, "{:dropped-broadcast-multicast/%ju} " "{N:/broadcast\\/multicast datagram%s undelivered}\n"); p1a(udps_fullsock, "{:dropped-full-socket-buffer/%ju} " "{N:/dropped due to full socket buffers}\n"); p1a(udpps_pcbhashmiss, "{:not-for-hashed-pcb/%ju} " "{N:/not for hashed pcb}\n"); delivered = udpstat.udps_ipackets - udpstat.udps_hdrops - udpstat.udps_badlen - udpstat.udps_badsum - udpstat.udps_noport - udpstat.udps_noportbcast - udpstat.udps_fullsock; if (delivered || sflag <= 1) xo_emit("\t{:delivered-packets/%ju} {N:/delivered}\n", (uint64_t)delivered); p(udps_opackets, "{:output-packets/%ju} {N:/datagram%s output}\n"); /* the next statistic is cumulative in udps_noportbcast */ p(udps_filtermcast, "{:multicast-source-filter-matches/%ju} " "{N:/time%s multicast source filter matched}\n"); #undef p #undef p1a xo_close_container("udp"); } /* * Dump CARP statistics structure. */ void carp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct carpstats carpstat; if (fetch_stats("net.inet.carp.stats", off, &carpstat, sizeof(carpstat), kread_counters) != 0) return; xo_open_container(name); xo_emit("{T:/%s}:\n", name); #define p(f, m) if (carpstat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)carpstat.f, plural(carpstat.f)) #define p2(f, m) if (carpstat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)carpstat.f) p(carps_ipackets, "\t{:received-inet-packets/%ju} " "{N:/packet%s received (IPv4)}\n"); p(carps_ipackets6, "\t{:received-inet6-packets/%ju} " "{N:/packet%s received (IPv6)}\n"); p(carps_badttl, "\t\t{:dropped-wrong-ttl/%ju} " "{N:/packet%s discarded for wrong TTL}\n"); p(carps_hdrops, "\t\t{:dropped-short-header/%ju} " "{N:/packet%s shorter than header}\n"); p(carps_badsum, "\t\t{:dropped-bad-checksum/%ju} " "{N:/discarded for bad checksum%s}\n"); p(carps_badver, "\t\t{:dropped-bad-version/%ju} " "{N:/discarded packet%s with a bad version}\n"); p2(carps_badlen, "\t\t{:dropped-short-packet/%ju} " "{N:/discarded because packet too short}\n"); p2(carps_badauth, "\t\t{:dropped-bad-authentication/%ju} " "{N:/discarded for bad authentication}\n"); p2(carps_badvhid, "\t\t{:dropped-bad-vhid/%ju} " "{N:/discarded for bad vhid}\n"); p2(carps_badaddrs, "\t\t{:dropped-bad-address-list/%ju} " "{N:/discarded because of a bad address list}\n"); p(carps_opackets, "\t{:sent-inet-packets/%ju} " "{N:/packet%s sent (IPv4)}\n"); p(carps_opackets6, "\t{:sent-inet6-packets/%ju} " "{N:/packet%s sent (IPv6)}\n"); p2(carps_onomem, "\t\t{:send-failed-memory-error/%ju} " "{N:/send failed due to mbuf memory error}\n"); #if notyet p(carps_ostates, "\t\t{:send-state-updates/%s} " "{N:/state update%s sent}\n"); #endif #undef p #undef p2 xo_close_container(name); } /* * Dump IP statistics structure. */ void ip_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct ipstat ipstat; if (fetch_stats("net.inet.ip.stats", off, &ipstat, sizeof(ipstat), kread_counters) != 0) return; xo_open_container(name); xo_emit("{T:/%s}:\n", name); #define p(f, m) if (ipstat.f || sflag <= 1) \ xo_emit(m, (uintmax_t )ipstat.f, plural(ipstat.f)) #define p1a(f, m) if (ipstat.f || sflag <= 1) \ xo_emit(m, (uintmax_t )ipstat.f) p(ips_total, "\t{:received-packets/%ju} " "{N:/total packet%s received}\n"); p(ips_badsum, "\t{:dropped-bad-checksum/%ju} " "{N:/bad header checksum%s}\n"); p1a(ips_toosmall, "\t{:dropped-below-minimum-size/%ju} " "{N:/with size smaller than minimum}\n"); p1a(ips_tooshort, "\t{:dropped-short-packets/%ju} " "{N:/with data size < data length}\n"); p1a(ips_toolong, "\t{:dropped-too-long/%ju} " "{N:/with ip length > max ip packet size}\n"); p1a(ips_badhlen, "\t{:dropped-short-header-length/%ju} " "{N:/with header length < data size}\n"); p1a(ips_badlen, "\t{:dropped-short-data/%ju} " "{N:/with data length < header length}\n"); p1a(ips_badoptions, "\t{:dropped-bad-options/%ju} " "{N:/with bad options}\n"); p1a(ips_badvers, "\t{:dropped-bad-version/%ju} " "{N:/with incorrect version number}\n"); p(ips_fragments, "\t{:received-fragments/%ju} " "{N:/fragment%s received}\n"); p(ips_fragdropped, "\t{:dropped-fragments/%ju} " "{N:/fragment%s dropped (dup or out of space)}\n"); p(ips_fragtimeout, "\t{:dropped-fragments-after-timeout/%ju} " "{N:/fragment%s dropped after timeout}\n"); p(ips_reassembled, "\t{:reassembled-packets/%ju} " "{N:/packet%s reassembled ok}\n"); p(ips_delivered, "\t{:received-local-packets/%ju} " "{N:/packet%s for this host}\n"); p(ips_noproto, "\t{:dropped-unknown-protocol/%ju} " "{N:/packet%s for unknown\\/unsupported protocol}\n"); p(ips_forward, "\t{:forwarded-packets/%ju} " "{N:/packet%s forwarded}"); p(ips_fastforward, " ({:fast-forwarded-packets/%ju} " "{N:/packet%s fast forwarded})"); if (ipstat.ips_forward || sflag <= 1) xo_emit("\n"); p(ips_cantforward, "\t{:packets-cannot-forward/%ju} " "{N:/packet%s not forwardable}\n"); p(ips_notmember, "\t{:received-unknown-multicast-group/%ju} " "{N:/packet%s received for unknown multicast group}\n"); p(ips_redirectsent, "\t{:redirects-sent/%ju} " "{N:/redirect%s sent}\n"); p(ips_localout, "\t{:sent-packets/%ju} " "{N:/packet%s sent from this host}\n"); p(ips_rawout, "\t{:send-packets-fabricated-header/%ju} " "{N:/packet%s sent with fabricated ip header}\n"); p(ips_odropped, "\t{:discard-no-mbufs/%ju} " "{N:/output packet%s dropped due to no bufs, etc.}\n"); p(ips_noroute, "\t{:discard-no-route/%ju} " "{N:/output packet%s discarded due to no route}\n"); p(ips_fragmented, "\t{:sent-fragments/%ju} " "{N:/output datagram%s fragmented}\n"); p(ips_ofragments, "\t{:fragments-created/%ju} " "{N:/fragment%s created}\n"); p(ips_cantfrag, "\t{:discard-cannot-fragment/%ju} " "{N:/datagram%s that can't be fragmented}\n"); p(ips_nogif, "\t{:discard-tunnel-no-gif/%ju} " "{N:/tunneling packet%s that can't find gif}\n"); p(ips_badaddr, "\t{:discard-bad-address/%ju} " "{N:/datagram%s with bad address in header}\n"); #undef p #undef p1a xo_close_container(name); } /* * Dump ARP statistics structure. */ void arp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct arpstat arpstat; if (fetch_stats("net.link.ether.arp.stats", off, &arpstat, sizeof(arpstat), kread_counters) != 0) return; xo_open_container(name); xo_emit("{T:/%s}:\n", name); #define p(f, m) if (arpstat.f || sflag <= 1) \ xo_emit("\t" m, (uintmax_t)arpstat.f, plural(arpstat.f)) #define p2(f, m) if (arpstat.f || sflag <= 1) \ xo_emit("\t" m, (uintmax_t)arpstat.f, pluralies(arpstat.f)) p(txrequests, "{:sent-requests/%ju} {N:/ARP request%s sent}\n"); p2(txreplies, "{:sent-replies/%ju} {N:/ARP repl%s sent}\n"); p(rxrequests, "{:received-requests/%ju} " "{N:/ARP request%s received}\n"); p2(rxreplies, "{:received-replies/%ju} " "{N:/ARP repl%s received}\n"); p(received, "{:received-packers/%ju} " "{N:/ARP packet%s received}\n"); p(dropped, "{:dropped-no-entry/%ju} " "{N:/total packet%s dropped due to no ARP entry}\n"); p(timeouts, "{:entries-timeout/%ju} " "{N:/ARP entry%s timed out}\n"); p(dupips, "{:dropped-duplicate-address/%ju} " "{N:/Duplicate IP%s seen}\n"); #undef p #undef p2 xo_close_container(name); } static const char *icmpnames[ICMP_MAXTYPE + 1] = { "echo reply", /* RFC 792 */ "#1", "#2", "destination unreachable", /* RFC 792 */ "source quench", /* RFC 792 */ "routing redirect", /* RFC 792 */ "#6", "#7", "echo", /* RFC 792 */ "router advertisement", /* RFC 1256 */ "router solicitation", /* RFC 1256 */ "time exceeded", /* RFC 792 */ "parameter problem", /* RFC 792 */ "time stamp", /* RFC 792 */ "time stamp reply", /* RFC 792 */ "information request", /* RFC 792 */ "information request reply", /* RFC 792 */ "address mask request", /* RFC 950 */ "address mask reply", /* RFC 950 */ "#19", "#20", "#21", "#22", "#23", "#24", "#25", "#26", "#27", "#28", "#29", "icmp traceroute", /* RFC 1393 */ "datagram conversion error", /* RFC 1475 */ "mobile host redirect", "IPv6 where-are-you", "IPv6 i-am-here", "mobile registration req", "mobile registration reply", "domain name request", /* RFC 1788 */ "domain name reply", /* RFC 1788 */ "icmp SKIP", "icmp photuris", /* RFC 2521 */ }; /* * Dump ICMP statistics. */ void icmp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct icmpstat icmpstat; size_t len; int i, first; if (fetch_stats("net.inet.icmp.stats", off, &icmpstat, sizeof(icmpstat), kread_counters) != 0) return; xo_open_container(name); xo_emit("{T:/%s}:\n", name); #define p(f, m) if (icmpstat.f || sflag <= 1) \ xo_emit(m, icmpstat.f, plural(icmpstat.f)) #define p1a(f, m) if (icmpstat.f || sflag <= 1) \ xo_emit(m, icmpstat.f) #define p2(f, m) if (icmpstat.f || sflag <= 1) \ xo_emit(m, icmpstat.f, plurales(icmpstat.f)) p(icps_error, "\t{:icmp-calls/%lu} " "{N:/call%s to icmp_error}\n"); p(icps_oldicmp, "\t{:errors-not-from-message/%lu} " "{N:/error%s not generated in response to an icmp message}\n"); for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++) { if (icmpstat.icps_outhist[i] != 0) { if (first) { xo_open_list("output-histogram"); xo_emit("\tOutput histogram:\n"); first = 0; } xo_open_instance("output-histogram"); if (icmpnames[i] != NULL) xo_emit("\t\t{k:name/%s}: {:count/%lu}\n", icmpnames[i], icmpstat.icps_outhist[i]); else xo_emit("\t\tunknown ICMP #{k:name/%d}: " "{:count/%lu}\n", i, icmpstat.icps_outhist[i]); xo_close_instance("output-histogram"); } } if (!first) xo_close_list("output-histogram"); p(icps_badcode, "\t{:dropped-bad-code/%lu} " "{N:/message%s with bad code fields}\n"); p(icps_tooshort, "\t{:dropped-too-short/%lu} " "{N:/message%s less than the minimum length}\n"); p(icps_checksum, "\t{:dropped-bad-checksum/%lu} " "{N:/message%s with bad checksum}\n"); p(icps_badlen, "\t{:dropped-bad-length/%lu} " "{N:/message%s with bad length}\n"); p1a(icps_bmcastecho, "\t{:dropped-multicast-echo/%lu} " "{N:/multicast echo requests ignored}\n"); p1a(icps_bmcasttstamp, "\t{:dropped-multicast-timestamp/%lu} " "{N:/multicast timestamp requests ignored}\n"); for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++) { if (icmpstat.icps_inhist[i] != 0) { if (first) { xo_open_list("input-histogram"); xo_emit("\tInput histogram:\n"); first = 0; } xo_open_instance("input-histogram"); if (icmpnames[i] != NULL) xo_emit("\t\t{k:name/%s}: {:count/%lu}\n", icmpnames[i], icmpstat.icps_inhist[i]); else xo_emit( "\t\tunknown ICMP #{k:name/%d}: {:count/%lu}\n", i, icmpstat.icps_inhist[i]); xo_close_instance("input-histogram"); } } if (!first) xo_close_list("input-histogram"); p(icps_reflect, "\t{:sent-packets/%lu} " "{N:/message response%s generated}\n"); p2(icps_badaddr, "\t{:discard-invalid-return-address/%lu} " "{N:/invalid return address%s}\n"); p(icps_noroute, "\t{:discard-no-route/%lu} " "{N:/no return route%s}\n"); #undef p #undef p1a #undef p2 if (live) { len = sizeof i; if (sysctlbyname("net.inet.icmp.maskrepl", &i, &len, NULL, 0) < 0) return; xo_emit("\tICMP address mask responses are " "{q:icmp-address-responses/%sabled}\n", i ? "en" : "dis"); } xo_close_container(name); } /* * Dump IGMP statistics structure. */ void igmp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct igmpstat igmpstat; if (fetch_stats("net.inet.igmp.stats", 0, &igmpstat, sizeof(igmpstat), kread) != 0) return; if (igmpstat.igps_version != IGPS_VERSION_3) { xo_warnx("%s: version mismatch (%d != %d)", __func__, igmpstat.igps_version, IGPS_VERSION_3); } if (igmpstat.igps_len != IGPS_VERSION3_LEN) { xo_warnx("%s: size mismatch (%d != %d)", __func__, igmpstat.igps_len, IGPS_VERSION3_LEN); } xo_open_container(name); xo_emit("{T:/%s}:\n", name); #define p64(f, m) if (igmpstat.f || sflag <= 1) \ xo_emit(m, (uintmax_t) igmpstat.f, plural(igmpstat.f)) #define py64(f, m) if (igmpstat.f || sflag <= 1) \ xo_emit(m, (uintmax_t) igmpstat.f, pluralies(igmpstat.f)) p64(igps_rcv_total, "\t{:received-messages/%ju} " "{N:/message%s received}\n"); p64(igps_rcv_tooshort, "\t{:dropped-too-short/%ju} " "{N:/message%s received with too few bytes}\n"); p64(igps_rcv_badttl, "\t{:dropped-wrong-ttl/%ju} " "{N:/message%s received with wrong TTL}\n"); p64(igps_rcv_badsum, "\t{:dropped-bad-checksum/%ju} " "{N:/message%s received with bad checksum}\n"); py64(igps_rcv_v1v2_queries, "\t{:received-membership-queries/%ju} " "{N:/V1\\/V2 membership quer%s received}\n"); py64(igps_rcv_v3_queries, "\t{:received-v3-membership-queries/%ju} " "{N:/V3 membership quer%s received}\n"); py64(igps_rcv_badqueries, "\t{:dropped-membership-queries/%ju} " "{N:/membership quer%s received with invalid field(s)}\n"); py64(igps_rcv_gen_queries, "\t{:received-general-queries/%ju} " "{N:/general quer%s received}\n"); py64(igps_rcv_group_queries, "\t{:received-group-queries/%ju} " "{N:/group quer%s received}\n"); py64(igps_rcv_gsr_queries, "\t{:received-group-source-queries/%ju} " "{N:/group-source quer%s received}\n"); py64(igps_drop_gsr_queries, "\t{:dropped-group-source-queries/%ju} " "{N:/group-source quer%s dropped}\n"); p64(igps_rcv_reports, "\t{:received-membership-requests/%ju} " "{N:/membership report%s received}\n"); p64(igps_rcv_badreports, "\t{:dropped-membership-reports/%ju} " "{N:/membership report%s received with invalid field(s)}\n"); p64(igps_rcv_ourreports, "\t" "{:received-membership-reports-matching/%ju} " "{N:/membership report%s received for groups to which we belong}" "\n"); p64(igps_rcv_nora, "\t{:received-v3-reports-no-router-alert/%ju} " "{N:/V3 report%s received without Router Alert}\n"); p64(igps_snd_reports, "\t{:sent-membership-reports/%ju} " "{N:/membership report%s sent}\n"); #undef p64 #undef py64 xo_close_container(name); } /* * Dump PIM statistics structure. */ void pim_stats(u_long off __unused, const char *name, int af1 __unused, int proto __unused) { struct pimstat pimstat; if (fetch_stats("net.inet.pim.stats", off, &pimstat, sizeof(pimstat), kread_counters) != 0) return; xo_open_container(name); xo_emit("{T:/%s}:\n", name); #define p(f, m) if (pimstat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)pimstat.f, plural(pimstat.f)) #define py(f, m) if (pimstat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)pimstat.f, pimstat.f != 1 ? "ies" : "y") p(pims_rcv_total_msgs, "\t{:received-messages/%ju} " "{N:/message%s received}\n"); p(pims_rcv_total_bytes, "\t{:received-bytes/%ju} " "{N:/byte%s received}\n"); p(pims_rcv_tooshort, "\t{:dropped-too-short/%ju} " "{N:/message%s received with too few bytes}\n"); p(pims_rcv_badsum, "\t{:dropped-bad-checksum/%ju} " "{N:/message%s received with bad checksum}\n"); p(pims_rcv_badversion, "\t{:dropped-bad-version/%ju} " "{N:/message%s received with bad version}\n"); p(pims_rcv_registers_msgs, "\t{:received-data-register-messages/%ju} " "{N:/data register message%s received}\n"); p(pims_rcv_registers_bytes, "\t{:received-data-register-bytes/%ju} " "{N:/data register byte%s received}\n"); p(pims_rcv_registers_wrongiif, "\t" "{:received-data-register-wrong-interface/%ju} " "{N:/data register message%s received on wrong iif}\n"); p(pims_rcv_badregisters, "\t{:received-bad-registers/%ju} " "{N:/bad register%s received}\n"); p(pims_snd_registers_msgs, "\t{:sent-data-register-messages/%ju} " "{N:/data register message%s sent}\n"); p(pims_snd_registers_bytes, "\t{:sent-data-register-bytes/%ju} " "{N:/data register byte%s sent}\n"); #undef p #undef py xo_close_container(name); } /* * Pretty print an Internet address (net address + port). */ void inetprint(const char *container, struct in_addr *in, int port, const char *proto, int num_port, const int af1) { struct servent *sp = 0; char line[80], *cp; int width; + size_t alen, plen; if (container) xo_open_container(container); if (Wflag) - sprintf(line, "%s.", inetname(in)); + snprintf(line, sizeof(line), "%s.", inetname(in)); else - sprintf(line, "%.*s.", (Aflag && !num_port) ? 12 : 16, inetname(in)); - cp = strchr(line, '\0'); + snprintf(line, sizeof(line), "%.*s.", + (Aflag && !num_port) ? 12 : 16, inetname(in)); + alen = strlen(line); + cp = line + alen; if (!num_port && port) sp = getservbyport((int)port, proto); if (sp || port == 0) - sprintf(cp, "%.15s ", sp ? sp->s_name : "*"); + snprintf(cp, sizeof(line) - alen, + "%.15s ", sp ? sp->s_name : "*"); else - sprintf(cp, "%d ", ntohs((u_short)port)); + snprintf(cp, sizeof(line) - alen, + "%d ", ntohs((u_short)port)); width = (Aflag && !Wflag) ? 18 : ((!Wflag || af1 == AF_INET) ? 22 : 45); if (Wflag) xo_emit("{d:target/%-*s} ", width, line); else xo_emit("{d:target/%-*.*s} ", width, width, line); - int alen = cp - line - 1, plen = strlen(cp) - 1; + plen = strlen(cp) - 1; + alen--; xo_emit("{e:address/%*.*s}{e:port/%*.*s}", alen, alen, line, plen, plen, cp); if (container) xo_close_container(container); } /* * Construct an Internet address representation. * If numeric_addr has been supplied, give * numeric value, otherwise try for symbolic name. */ char * inetname(struct in_addr *inp) { char *cp; static char line[MAXHOSTNAMELEN]; struct hostent *hp; struct netent *np; cp = 0; if (!numeric_addr && inp->s_addr != INADDR_ANY) { int net = inet_netof(*inp); int lna = inet_lnaof(*inp); if (lna == INADDR_ANY) { np = getnetbyaddr(net, AF_INET); if (np) cp = np->n_name; } if (cp == NULL) { hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET); if (hp) { cp = hp->h_name; trimdomain(cp, strlen(cp)); } } } if (inp->s_addr == INADDR_ANY) strcpy(line, "*"); else if (cp) { strlcpy(line, cp, sizeof(line)); } else { inp->s_addr = ntohl(inp->s_addr); #define C(x) ((u_int)((x) & 0xff)) - sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24), - C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr)); + snprintf(line, sizeof(line), "%u.%u.%u.%u", + C(inp->s_addr >> 24), C(inp->s_addr >> 16), + C(inp->s_addr >> 8), C(inp->s_addr)); } return (line); } Index: head/usr.bin/netstat/inet6.c =================================================================== --- head/usr.bin/netstat/inet6.c (revision 311391) +++ head/usr.bin/netstat/inet6.c (revision 311392) @@ -1,1348 +1,1352 @@ /* BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp */ /*- * Copyright (c) 1983, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static char sccsid[] = "@(#)inet6.c 8.4 (Berkeley) 4/20/94"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #ifdef INET6 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "netstat.h" -char *inet6name(struct in6_addr *); - static char ntop_buf[INET6_ADDRSTRLEN]; static const char *ip6nh[] = { "hop by hop", "ICMP", "IGMP", "#3", "IP", "#5", "TCP", "#7", "#8", "#9", "#10", "#11", "#12", "#13", "#14", "#15", "#16", "UDP", "#18", "#19", "#20", "#21", "IDP", "#23", "#24", "#25", "#26", "#27", "#28", "TP", "#30", "#31", "#32", "#33", "#34", "#35", "#36", "#37", "#38", "#39", "#40", "IP6", "#42", "routing", "fragment", "#45", "#46", "#47", "#48", "#49", "ESP", "AH", "#52", "#53", "#54", "#55", "#56", "#57", "ICMP6", "no next header", "destination option", "#61", "mobility", "#63", "#64", "#65", "#66", "#67", "#68", "#69", "#70", "#71", "#72", "#73", "#74", "#75", "#76", "#77", "#78", "#79", "ISOIP", "#81", "#82", "#83", "#84", "#85", "#86", "#87", "#88", "OSPF", "#80", "#91", "#92", "#93", "#94", "#95", "#96", "Ethernet", "#98", "#99", "#100", "#101", "#102", "PIM", "#104", "#105", "#106", "#107", "#108", "#109", "#110", "#111", "#112", "#113", "#114", "#115", "#116", "#117", "#118", "#119", "#120", "#121", "#122", "#123", "#124", "#125", "#126", "#127", "#128", "#129", "#130", "#131", "SCTP", "#133", "#134", "#135", "UDPLite", "#137", "#138", "#139", "#140", "#141", "#142", "#143", "#144", "#145", "#146", "#147", "#148", "#149", "#150", "#151", "#152", "#153", "#154", "#155", "#156", "#157", "#158", "#159", "#160", "#161", "#162", "#163", "#164", "#165", "#166", "#167", "#168", "#169", "#170", "#171", "#172", "#173", "#174", "#175", "#176", "#177", "#178", "#179", "#180", "#181", "#182", "#183", "#184", "#185", "#186", "#187", "#188", "#189", "#180", "#191", "#192", "#193", "#194", "#195", "#196", "#197", "#198", "#199", "#200", "#201", "#202", "#203", "#204", "#205", "#206", "#207", "#208", "#209", "#210", "#211", "#212", "#213", "#214", "#215", "#216", "#217", "#218", "#219", "#220", "#221", "#222", "#223", "#224", "#225", "#226", "#227", "#228", "#229", "#230", "#231", "#232", "#233", "#234", "#235", "#236", "#237", "#238", "#239", "#240", "#241", "#242", "#243", "#244", "#245", "#246", "#247", "#248", "#249", "#250", "#251", "#252", "#253", "#254", "#255", }; static const char *srcrule_str[] = { "first candidate", "same address", "appropriate scope", "deprecated address", "home address", "outgoing interface", "matching label", "public/temporary address", "alive interface", "better virtual status", "preferred source", "rule #11", "rule #12", "rule #13", "longest match", "rule #15", }; /* * Dump IP6 statistics structure. */ void ip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct ip6stat ip6stat; int first, i; if (fetch_stats("net.inet6.ip6.stats", off, &ip6stat, sizeof(ip6stat), kread_counters) != 0) return; xo_open_container(name); xo_emit("{T:/%s}:\n", name); #define p(f, m) if (ip6stat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)ip6stat.f, plural(ip6stat.f)) #define p1a(f, m) if (ip6stat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)ip6stat.f) p(ip6s_total, "\t{:received-packets/%ju} " "{N:/total packet%s received}\n"); p1a(ip6s_toosmall, "\t{:dropped-below-minimum-size/%ju} " "{N:/with size smaller than minimum}\n"); p1a(ip6s_tooshort, "\t{:dropped-short-packets/%ju} " "{N:/with data size < data length}\n"); p1a(ip6s_badoptions, "\t{:dropped-bad-options/%ju} " "{N:/with bad options}\n"); p1a(ip6s_badvers, "\t{:dropped-bad-version/%ju} " "{N:/with incorrect version number}\n"); p(ip6s_fragments, "\t{:received-fragments/%ju} " "{N:/fragment%s received}\n"); p(ip6s_fragdropped, "\t{:dropped-fragment/%ju} " "{N:/fragment%s dropped (dup or out of space)}\n"); p(ip6s_fragtimeout, "\t{:dropped-fragment-after-timeout/%ju} " "{N:/fragment%s dropped after timeout}\n"); p(ip6s_fragoverflow, "\t{:dropped-fragments-overflow/%ju} " "{N:/fragment%s that exceeded limit}\n"); p(ip6s_reassembled, "\t{:reassembled-packets/%ju} " "{N:/packet%s reassembled ok}\n"); p(ip6s_delivered, "\t{:received-local-packets/%ju} " "{N:/packet%s for this host}\n"); p(ip6s_forward, "\t{:forwarded-packets/%ju} " "{N:/packet%s forwarded}\n"); p(ip6s_cantforward, "\t{:packets-not-forwardable/%ju} " "{N:/packet%s not forwardable}\n"); p(ip6s_redirectsent, "\t{:sent-redirects/%ju} " "{N:/redirect%s sent}\n"); p(ip6s_localout, "\t{:sent-packets/%ju} " "{N:/packet%s sent from this host}\n"); p(ip6s_rawout, "\t{:send-packets-fabricated-header/%ju} " "{N:/packet%s sent with fabricated ip header}\n"); p(ip6s_odropped, "\t{:discard-no-mbufs/%ju} " "{N:/output packet%s dropped due to no bufs, etc.}\n"); p(ip6s_noroute, "\t{:discard-no-route/%ju} " "{N:/output packet%s discarded due to no route}\n"); p(ip6s_fragmented, "\t{:sent-fragments/%ju} " "{N:/output datagram%s fragmented}\n"); p(ip6s_ofragments, "\t{:fragments-created/%ju} " "{N:/fragment%s created}\n"); p(ip6s_cantfrag, "\t{:discard-cannot-fragment/%ju} " "{N:/datagram%s that can't be fragmented}\n"); p(ip6s_badscope, "\t{:discard-scope-violations/%ju} " "{N:/packet%s that violated scope rules}\n"); p(ip6s_notmember, "\t{:multicast-no-join-packets/%ju} " "{N:/multicast packet%s which we don't join}\n"); for (first = 1, i = 0; i < IP6S_HDRCNT; i++) if (ip6stat.ip6s_nxthist[i] != 0) { if (first) { xo_emit("\t{T:Input histogram}:\n"); xo_open_list("input-histogram"); first = 0; } xo_open_instance("input-histogram"); xo_emit("\t\t{k:name/%s}: {:count/%ju}\n", ip6nh[i], (uintmax_t)ip6stat.ip6s_nxthist[i]); xo_close_instance("input-histogram"); } if (!first) xo_close_list("input-histogram"); xo_open_container("mbuf-statistics"); xo_emit("\t{T:Mbuf statistics}:\n"); xo_emit("\t\t{:one-mbuf/%ju} {N:/one mbuf}\n", (uintmax_t)ip6stat.ip6s_m1); for (first = 1, i = 0; i < IP6S_M2MMAX; i++) { char ifbuf[IFNAMSIZ]; if (ip6stat.ip6s_m2m[i] != 0) { if (first) { xo_emit("\t\t{N:two or more mbuf}:\n"); xo_open_list("mbuf-data"); first = 0; } xo_open_instance("mbuf-data"); xo_emit("\t\t\t{k:name/%s}= {:count/%ju}\n", if_indextoname(i, ifbuf), (uintmax_t)ip6stat.ip6s_m2m[i]); xo_close_instance("mbuf-data"); } } if (!first) xo_close_list("mbuf-data"); xo_emit("\t\t{:one-extra-mbuf/%ju} {N:one ext mbuf}\n", (uintmax_t)ip6stat.ip6s_mext1); xo_emit("\t\t{:two-or-more-extra-mbufs/%ju} " "{N:/two or more ext mbuf}\n", (uintmax_t)ip6stat.ip6s_mext2m); xo_close_container("mbuf-statistics"); p(ip6s_exthdrtoolong, "\t{:dropped-header-too-long/%ju} " "{N:/packet%s whose headers are not contiguous}\n"); p(ip6s_nogif, "\t{:discard-tunnel-no-gif/%ju} " "{N:/tunneling packet%s that can't find gif}\n"); p(ip6s_toomanyhdr, "\t{:dropped-too-many-headers/%ju} " "{N:/packet%s discarded because of too many headers}\n"); /* for debugging source address selection */ #define PRINT_SCOPESTAT(s,i) do {\ switch(i) { /* XXX hardcoding in each case */\ case 1:\ p(s, "\t\t{ke:name/interface-locals}{:count/%ju} " \ "{N:/interface-local%s}\n"); \ break;\ case 2:\ p(s,"\t\t{ke:name/link-locals}{:count/%ju} " \ "{N:/link-local%s}\n"); \ break;\ case 5:\ p(s,"\t\t{ke:name/site-locals}{:count/%ju} " \ "{N:/site-local%s}\n");\ break;\ case 14:\ p(s,"\t\t{ke:name/globals}{:count/%ju} " \ "{N:/global%s}\n");\ break;\ default:\ xo_emit("\t\t{qke:name/%#x}{:count/%ju} " \ "{N:/addresses scope=%#x}\n",\ i, (uintmax_t)ip6stat.s, i); \ }\ } while (0); xo_open_container("source-address-selection"); p(ip6s_sources_none, "\t{:address-selection-failures/%ju} " "{N:/failure%s of source address selection}\n"); for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) { if (ip6stat.ip6s_sources_sameif[i]) { if (first) { xo_open_list("outgoing-interface"); xo_emit("\tsource addresses on an outgoing " "I/F\n"); first = 0; } xo_open_instance("outgoing-interface"); PRINT_SCOPESTAT(ip6s_sources_sameif[i], i); xo_close_instance("outgoing-interface"); } } if (!first) xo_close_list("outgoing-interface"); for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) { if (ip6stat.ip6s_sources_otherif[i]) { if (first) { xo_open_list("non-outgoing-interface"); xo_emit("\tsource addresses on a non-outgoing " "I/F\n"); first = 0; } xo_open_instance("non-outgoing-interface"); PRINT_SCOPESTAT(ip6s_sources_otherif[i], i); xo_close_instance("non-outgoing-interface"); } } if (!first) xo_close_list("non-outgoing-interface"); for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) { if (ip6stat.ip6s_sources_samescope[i]) { if (first) { xo_open_list("same-source"); xo_emit("\tsource addresses of same scope\n"); first = 0; } xo_open_instance("same-source"); PRINT_SCOPESTAT(ip6s_sources_samescope[i], i); xo_close_instance("same-source"); } } if (!first) xo_close_list("same-source"); for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) { if (ip6stat.ip6s_sources_otherscope[i]) { if (first) { xo_open_list("different-scope"); xo_emit("\tsource addresses of a different " "scope\n"); first = 0; } xo_open_instance("different-scope"); PRINT_SCOPESTAT(ip6s_sources_otherscope[i], i); xo_close_instance("different-scope"); } } if (!first) xo_close_list("different-scope"); for (first = 1, i = 0; i < IP6S_SCOPECNT; i++) { if (ip6stat.ip6s_sources_deprecated[i]) { if (first) { xo_open_list("deprecated-source"); xo_emit("\tdeprecated source addresses\n"); first = 0; } xo_open_instance("deprecated-source"); PRINT_SCOPESTAT(ip6s_sources_deprecated[i], i); xo_close_instance("deprecated-source"); } } if (!first) xo_close_list("deprecated-source"); for (first = 1, i = 0; i < IP6S_RULESMAX; i++) { if (ip6stat.ip6s_sources_rule[i]) { if (first) { xo_open_list("rules-applied"); xo_emit("\t{T:Source addresses selection " "rule applied}:\n"); first = 0; } xo_open_instance("rules-applied"); xo_emit("\t\t{ke:name/%s}{:count/%ju} {d:name/%s}\n", srcrule_str[i], (uintmax_t)ip6stat.ip6s_sources_rule[i], srcrule_str[i]); xo_close_instance("rules-applied"); } } if (!first) xo_close_list("rules-applied"); xo_close_container("source-address-selection"); #undef p #undef p1a xo_close_container(name); } /* * Dump IPv6 per-interface statistics based on RFC 2465. */ void ip6_ifstats(char *ifname) { struct in6_ifreq ifr; int s; #define p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)ifr.ifr_ifru.ifru_stat.f, \ plural(ifr.ifr_ifru.ifru_stat.f)) if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { xo_warn("Warning: socket(AF_INET6)"); return; } strcpy(ifr.ifr_name, ifname); if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) { if (errno != EPFNOSUPPORT) xo_warn("Warning: ioctl(SIOCGIFSTAT_IN6)"); goto end; } xo_emit("{T:/ip6 on %s}:\n", ifr.ifr_name); xo_open_instance("ip6-interface-statistics"); xo_emit("{ke:name/%s}", ifr.ifr_name); p(ifs6_in_receive, "\t{:received-packets/%ju} " "{N:/total input datagram%s}\n"); p(ifs6_in_hdrerr, "\t{:dropped-invalid-header/%ju} " "{N:/datagram%s with invalid header received}\n"); p(ifs6_in_toobig, "\t{:dropped-mtu-exceeded/%ju} " "{N:/datagram%s exceeded MTU received}\n"); p(ifs6_in_noroute, "\t{:dropped-no-route/%ju} " "{N:/datagram%s with no route received}\n"); p(ifs6_in_addrerr, "\t{:dropped-invalid-destination/%ju} " "{N:/datagram%s with invalid dst received}\n"); p(ifs6_in_protounknown, "\t{:dropped-unknown-protocol/%ju} " "{N:/datagram%s with unknown proto received}\n"); p(ifs6_in_truncated, "\t{:dropped-truncated/%ju} " "{N:/truncated datagram%s received}\n"); p(ifs6_in_discard, "\t{:dropped-discarded/%ju} " "{N:/input datagram%s discarded}\n"); p(ifs6_in_deliver, "\t{:received-valid-packets/%ju} " "{N:/datagram%s delivered to an upper layer protocol}\n"); p(ifs6_out_forward, "\t{:sent-forwarded/%ju} " "{N:/datagram%s forwarded to this interface}\n"); p(ifs6_out_request, "\t{:sent-packets/%ju} " "{N:/datagram%s sent from an upper layer protocol}\n"); p(ifs6_out_discard, "\t{:discard-packets/%ju} " "{N:/total discarded output datagram%s}\n"); p(ifs6_out_fragok, "\t{:discard-fragments/%ju} " "{N:/output datagram%s fragmented}\n"); p(ifs6_out_fragfail, "\t{:fragments-failed/%ju} " "{N:/output datagram%s failed on fragment}\n"); p(ifs6_out_fragcreat, "\t{:fragments-created/%ju} " "{N:/output datagram%s succeeded on fragment}\n"); p(ifs6_reass_reqd, "\t{:reassembly-required/%ju} " "{N:/incoming datagram%s fragmented}\n"); p(ifs6_reass_ok, "\t{:reassembled-packets/%ju} " "{N:/datagram%s reassembled}\n"); p(ifs6_reass_fail, "\t{:reassembly-failed/%ju} " "{N:/datagram%s failed on reassembly}\n"); p(ifs6_in_mcast, "\t{:received-multicast/%ju} " "{N:/multicast datagram%s received}\n"); p(ifs6_out_mcast, "\t{:sent-multicast/%ju} " "{N:/multicast datagram%s sent}\n"); end: xo_close_instance("ip6-interface-statistics"); close(s); #undef p } static const char *icmp6names[] = { "#0", "unreach", "packet too big", "time exceed", "parameter problem", "#5", "#6", "#7", "#8", "#9", "#10", "#11", "#12", "#13", "#14", "#15", "#16", "#17", "#18", "#19", "#20", "#21", "#22", "#23", "#24", "#25", "#26", "#27", "#28", "#29", "#30", "#31", "#32", "#33", "#34", "#35", "#36", "#37", "#38", "#39", "#40", "#41", "#42", "#43", "#44", "#45", "#46", "#47", "#48", "#49", "#50", "#51", "#52", "#53", "#54", "#55", "#56", "#57", "#58", "#59", "#60", "#61", "#62", "#63", "#64", "#65", "#66", "#67", "#68", "#69", "#70", "#71", "#72", "#73", "#74", "#75", "#76", "#77", "#78", "#79", "#80", "#81", "#82", "#83", "#84", "#85", "#86", "#87", "#88", "#89", "#80", "#91", "#92", "#93", "#94", "#95", "#96", "#97", "#98", "#99", "#100", "#101", "#102", "#103", "#104", "#105", "#106", "#107", "#108", "#109", "#110", "#111", "#112", "#113", "#114", "#115", "#116", "#117", "#118", "#119", "#120", "#121", "#122", "#123", "#124", "#125", "#126", "#127", "echo", "echo reply", "multicast listener query", "MLDv1 listener report", "MLDv1 listener done", "router solicitation", "router advertisement", "neighbor solicitation", "neighbor advertisement", "redirect", "router renumbering", "node information request", "node information reply", "inverse neighbor solicitation", "inverse neighbor advertisement", "MLDv2 listener report", "#144", "#145", "#146", "#147", "#148", "#149", "#150", "#151", "#152", "#153", "#154", "#155", "#156", "#157", "#158", "#159", "#160", "#161", "#162", "#163", "#164", "#165", "#166", "#167", "#168", "#169", "#170", "#171", "#172", "#173", "#174", "#175", "#176", "#177", "#178", "#179", "#180", "#181", "#182", "#183", "#184", "#185", "#186", "#187", "#188", "#189", "#180", "#191", "#192", "#193", "#194", "#195", "#196", "#197", "#198", "#199", "#200", "#201", "#202", "#203", "#204", "#205", "#206", "#207", "#208", "#209", "#210", "#211", "#212", "#213", "#214", "#215", "#216", "#217", "#218", "#219", "#220", "#221", "#222", "#223", "#224", "#225", "#226", "#227", "#228", "#229", "#230", "#231", "#232", "#233", "#234", "#235", "#236", "#237", "#238", "#239", "#240", "#241", "#242", "#243", "#244", "#245", "#246", "#247", "#248", "#249", "#250", "#251", "#252", "#253", "#254", "#255", }; /* * Dump ICMP6 statistics. */ void icmp6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct icmp6stat icmp6stat; int i, first; if (fetch_stats("net.inet6.icmp6.stats", off, &icmp6stat, sizeof(icmp6stat), kread_counters) != 0) return; xo_emit("{T:/%s}:\n", name); xo_open_container(name); #define p(f, m) if (icmp6stat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)icmp6stat.f, plural(icmp6stat.f)) #define p_5(f, m) if (icmp6stat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)icmp6stat.f) p(icp6s_error, "\t{:icmp6-calls/%ju} " "{N:/call%s to icmp6_error}\n"); p(icp6s_canterror, "\t{:errors-not-generated-from-message/%ju} " "{N:/error%s not generated in response to an icmp6 message}\n"); p(icp6s_toofreq, "\t{:errors-discarded-by-rate-limitation/%ju} " "{N:/error%s not generated because of rate limitation}\n"); #define NELEM (int)(sizeof(icmp6stat.icp6s_outhist)/sizeof(icmp6stat.icp6s_outhist[0])) for (first = 1, i = 0; i < NELEM; i++) if (icmp6stat.icp6s_outhist[i] != 0) { if (first) { xo_open_list("output-histogram"); xo_emit("\t{T:Output histogram}:\n"); first = 0; } xo_open_instance("output-histogram"); xo_emit("\t\t{k:name/%s}: {:count/%ju}\n", icmp6names[i], (uintmax_t)icmp6stat.icp6s_outhist[i]); xo_close_instance("output-histogram"); } if (!first) xo_close_list("output-histogram"); #undef NELEM p(icp6s_badcode, "\t{:dropped-bad-code/%ju} " "{N:/message%s with bad code fields}\n"); p(icp6s_tooshort, "\t{:dropped-too-short/%ju} " "{N:/message%s < minimum length}\n"); p(icp6s_checksum, "\t{:dropped-bad-checksum/%ju} " "{N:/bad checksum%s}\n"); p(icp6s_badlen, "\t{:dropped-bad-length/%ju} " "{N:/message%s with bad length}\n"); #define NELEM (int)(sizeof(icmp6stat.icp6s_inhist)/sizeof(icmp6stat.icp6s_inhist[0])) for (first = 1, i = 0; i < NELEM; i++) if (icmp6stat.icp6s_inhist[i] != 0) { if (first) { xo_open_list("input-histogram"); xo_emit("\t{T:Input histogram}:\n"); first = 0; } xo_open_instance("input-histogram"); xo_emit("\t\t{k:name/%s}: {:count/%ju}\n", icmp6names[i], (uintmax_t)icmp6stat.icp6s_inhist[i]); xo_close_instance("input-histogram"); } if (!first) xo_close_list("input-histogram"); #undef NELEM xo_emit("\t{T:Histogram of error messages to be generated}:\n"); xo_open_container("errors"); p_5(icp6s_odst_unreach_noroute, "\t\t{:no-route/%ju} " "{N:/no route}\n"); p_5(icp6s_odst_unreach_admin, "\t\t{:admin-prohibited/%ju} " "{N:/administratively prohibited}\n"); p_5(icp6s_odst_unreach_beyondscope, "\t\t{:beyond-scope/%ju} " "{N:/beyond scope}\n"); p_5(icp6s_odst_unreach_addr, "\t\t{:address-unreachable/%ju} " "{N:/address unreachable}\n"); p_5(icp6s_odst_unreach_noport, "\t\t{:port-unreachable/%ju} " "{N:/port unreachable}\n"); p_5(icp6s_opacket_too_big, "\t\t{:packet-too-big/%ju} " "{N:/packet too big}\n"); p_5(icp6s_otime_exceed_transit, "\t\t{:time-exceed-transmit/%ju} " "{N:/time exceed transit}\n"); p_5(icp6s_otime_exceed_reassembly, "\t\t{:time-exceed-reassembly/%ju} " "{N:/time exceed reassembly}\n"); p_5(icp6s_oparamprob_header, "\t\t{:bad-header/%ju} " "{N:/erroneous header field}\n"); p_5(icp6s_oparamprob_nextheader, "\t\t{:bad-next-header/%ju} " "{N:/unrecognized next header}\n"); p_5(icp6s_oparamprob_option, "\t\t{:bad-option/%ju} " "{N:/unrecognized option}\n"); p_5(icp6s_oredirect, "\t\t{:redirects/%ju} " "{N:/redirect}\n"); p_5(icp6s_ounknown, "\t\t{:unknown/%ju} {N:unknown}\n"); p(icp6s_reflect, "\t{:reflect/%ju} " "{N:/message response%s generated}\n"); p(icp6s_nd_toomanyopt, "\t{:too-many-nd-options/%ju} " "{N:/message%s with too many ND options}\n"); p(icp6s_nd_badopt, "\t{:bad-nd-options/%ju} " "{N:/message%s with bad ND options}\n"); p(icp6s_badns, "\t{:bad-neighbor-solicitation/%ju} " "{N:/bad neighbor solicitation message%s}\n"); p(icp6s_badna, "\t{:bad-neighbor-advertisement/%ju} " "{N:/bad neighbor advertisement message%s}\n"); p(icp6s_badrs, "\t{:bad-router-solicitation/%ju} " "{N:/bad router solicitation message%s}\n"); p(icp6s_badra, "\t{:bad-router-advertisement/%ju} " "{N:/bad router advertisement message%s}\n"); p(icp6s_badredirect, "\t{:bad-redirect/%ju} " "{N:/bad redirect message%s}\n"); xo_close_container("errors"); p(icp6s_pmtuchg, "\t{:path-mtu-changes/%ju} {N:/path MTU change%s}\n"); #undef p #undef p_5 xo_close_container(name); } /* * Dump ICMPv6 per-interface statistics based on RFC 2466. */ void icmp6_ifstats(char *ifname) { struct in6_ifreq ifr; int s; #define p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f, \ plural(ifr.ifr_ifru.ifru_icmp6stat.f)) #define p2(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)ifr.ifr_ifru.ifru_icmp6stat.f, \ pluralies(ifr.ifr_ifru.ifru_icmp6stat.f)) if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { xo_warn("Warning: socket(AF_INET6)"); return; } strcpy(ifr.ifr_name, ifname); if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) { if (errno != EPFNOSUPPORT) xo_warn("Warning: ioctl(SIOCGIFSTAT_ICMP6)"); goto end; } xo_emit("{T:/icmp6 on %s}:\n", ifr.ifr_name); xo_open_instance("icmp6-interface-statistics"); xo_emit("{ke:name/%s}", ifr.ifr_name); p(ifs6_in_msg, "\t{:received-packets/%ju} " "{N:/total input message%s}\n"); p(ifs6_in_error, "\t{:received-errors/%ju} " "{N:/total input error message%s}\n"); p(ifs6_in_dstunreach, "\t{:received-destination-unreachable/%ju} " "{N:/input destination unreachable error%s}\n"); p(ifs6_in_adminprohib, "\t{:received-admin-prohibited/%ju} " "{N:/input administratively prohibited error%s}\n"); p(ifs6_in_timeexceed, "\t{:received-time-exceeded/%ju} " "{N:/input time exceeded error%s}\n"); p(ifs6_in_paramprob, "\t{:received-bad-parameter/%ju} " "{N:/input parameter problem error%s}\n"); p(ifs6_in_pkttoobig, "\t{:received-packet-too-big/%ju} " "{N:/input packet too big error%s}\n"); p(ifs6_in_echo, "\t{:received-echo-requests/%ju} " "{N:/input echo request%s}\n"); p2(ifs6_in_echoreply, "\t{:received-echo-replies/%ju} " "{N:/input echo repl%s}\n"); p(ifs6_in_routersolicit, "\t{:received-router-solicitation/%ju} " "{N:/input router solicitation%s}\n"); p(ifs6_in_routeradvert, "\t{:received-router-advertisement/%ju} " "{N:/input router advertisement%s}\n"); p(ifs6_in_neighborsolicit, "\t{:received-neighbor-solicitation/%ju} " "{N:/input neighbor solicitation%s}\n"); p(ifs6_in_neighboradvert, "\t{:received-neighbor-advertisement/%ju} " "{N:/input neighbor advertisement%s}\n"); p(ifs6_in_redirect, "\t{received-redirects/%ju} " "{N:/input redirect%s}\n"); p2(ifs6_in_mldquery, "\t{:received-mld-queries/%ju} " "{N:/input MLD quer%s}\n"); p(ifs6_in_mldreport, "\t{:received-mld-reports/%ju} " "{N:/input MLD report%s}\n"); p(ifs6_in_mlddone, "\t{:received-mld-done/%ju} " "{N:/input MLD done%s}\n"); p(ifs6_out_msg, "\t{:sent-packets/%ju} " "{N:/total output message%s}\n"); p(ifs6_out_error, "\t{:sent-errors/%ju} " "{N:/total output error message%s}\n"); p(ifs6_out_dstunreach, "\t{:sent-destination-unreachable/%ju} " "{N:/output destination unreachable error%s}\n"); p(ifs6_out_adminprohib, "\t{:sent-admin-prohibited/%ju} " "{N:/output administratively prohibited error%s}\n"); p(ifs6_out_timeexceed, "\t{:sent-time-exceeded/%ju} " "{N:/output time exceeded error%s}\n"); p(ifs6_out_paramprob, "\t{:sent-bad-parameter/%ju} " "{N:/output parameter problem error%s}\n"); p(ifs6_out_pkttoobig, "\t{:sent-packet-too-big/%ju} " "{N:/output packet too big error%s}\n"); p(ifs6_out_echo, "\t{:sent-echo-requests/%ju} " "{N:/output echo request%s}\n"); p2(ifs6_out_echoreply, "\t{:sent-echo-replies/%ju} " "{N:/output echo repl%s}\n"); p(ifs6_out_routersolicit, "\t{:sent-router-solicitation/%ju} " "{N:/output router solicitation%s}\n"); p(ifs6_out_routeradvert, "\t{:sent-router-advertisement/%ju} " "{N:/output router advertisement%s}\n"); p(ifs6_out_neighborsolicit, "\t{:sent-neighbor-solicitation/%ju} " "{N:/output neighbor solicitation%s}\n"); p(ifs6_out_neighboradvert, "\t{:sent-neighbor-advertisement/%ju} " "{N:/output neighbor advertisement%s}\n"); p(ifs6_out_redirect, "\t{:sent-redirects/%ju} " "{N:/output redirect%s}\n"); p2(ifs6_out_mldquery, "\t{:sent-mld-queries/%ju} " "{N:/output MLD quer%s}\n"); p(ifs6_out_mldreport, "\t{:sent-mld-reports/%ju} " "{N:/output MLD report%s}\n"); p(ifs6_out_mlddone, "\t{:sent-mld-dones/%ju} " "{N:/output MLD done%s}\n"); end: xo_close_instance("icmp6-interface-statistics"); close(s); #undef p } /* * Dump PIM statistics structure. */ void pim6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct pim6stat pim6stat; if (fetch_stats("net.inet6.pim.stats", off, &pim6stat, sizeof(pim6stat), kread) != 0) return; xo_emit("{T:/%s}:\n", name); xo_open_container(name); #define p(f, m) if (pim6stat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)pim6stat.f, plural(pim6stat.f)) p(pim6s_rcv_total, "\t{:received-packets/%ju} " "{N:/message%s received}\n"); p(pim6s_rcv_tooshort, "\t{:dropped-too-short/%ju} " "{N:/message%s received with too few bytes}\n"); p(pim6s_rcv_badsum, "\t{:dropped-bad-checksum/%ju} " "{N:/message%s received with bad checksum}\n"); p(pim6s_rcv_badversion, "\t{:dropped-bad-version/%ju} " "{N:/message%s received with bad version}\n"); p(pim6s_rcv_registers, "\t{:received-registers/%ju} " "{N:/register%s received}\n"); p(pim6s_rcv_badregisters, "\t{:received-bad-registers/%ju} " "{N:/bad register%s received}\n"); p(pim6s_snd_registers, "\t{:sent-registers/%ju} " "{N:/register%s sent}\n"); #undef p xo_close_container(name); } /* * Dump raw ip6 statistics structure. */ void rip6_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct rip6stat rip6stat; u_quad_t delivered; if (fetch_stats("net.inet6.ip6.rip6stats", off, &rip6stat, sizeof(rip6stat), kread_counters) != 0) return; xo_emit("{T:/%s}:\n", name); xo_open_container(name); #define p(f, m) if (rip6stat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)rip6stat.f, plural(rip6stat.f)) p(rip6s_ipackets, "\t{:received-packets/%ju} " "{N:/message%s received}\n"); p(rip6s_isum, "\t{:input-checksum-computation/%ju} " "{N:/checksum calculation%s on inbound}\n"); p(rip6s_badsum, "\t{:received-bad-checksum/%ju} " "{N:/message%s with bad checksum}\n"); p(rip6s_nosock, "\t{:dropped-no-socket/%ju} " "{N:/message%s dropped due to no socket}\n"); p(rip6s_nosockmcast, "\t{:dropped-multicast-no-socket/%ju} " "{N:/multicast message%s dropped due to no socket}\n"); p(rip6s_fullsock, "\t{:dropped-full-socket-buffer/%ju} " "{N:/message%s dropped due to full socket buffers}\n"); delivered = rip6stat.rip6s_ipackets - rip6stat.rip6s_badsum - rip6stat.rip6s_nosock - rip6stat.rip6s_nosockmcast - rip6stat.rip6s_fullsock; if (delivered || sflag <= 1) xo_emit("\t{:delivered-packets/%ju} {N:/delivered}\n", (uintmax_t)delivered); p(rip6s_opackets, "\t{:sent-packets/%ju} " "{N:/datagram%s output}\n"); #undef p xo_close_container(name); } /* * Pretty print an Internet address (net address + port). * Take numeric_addr and numeric_port into consideration. */ #define GETSERVBYPORT6(port, proto, ret)\ {\ if (strcmp((proto), "tcp6") == 0)\ (ret) = getservbyport((int)(port), "tcp");\ else if (strcmp((proto), "udp6") == 0)\ (ret) = getservbyport((int)(port), "udp");\ else\ (ret) = getservbyport((int)(port), (proto));\ }; void inet6print(const char *container, struct in6_addr *in6, int port, const char *proto, int numeric) { struct servent *sp = 0; char line[80], *cp; int width; + size_t alen, plen; if (container) xo_open_container(container); - sprintf(line, "%.*s.", Wflag ? 39 : (Aflag && !numeric) ? 12 : 16, + snprintf(line, sizeof(line), "%.*s.", + Wflag ? 39 : (Aflag && !numeric) ? 12 : 16, inet6name(in6)); - cp = strchr(line, '\0'); + alen = strlen(line); + cp = line + alen; if (!numeric && port) GETSERVBYPORT6(port, proto, sp); if (sp || port == 0) - sprintf(cp, "%.15s", sp ? sp->s_name : "*"); + snprintf(cp, sizeof(line) - alen, + "%.15s", sp ? sp->s_name : "*"); else - sprintf(cp, "%d", ntohs((u_short)port)); + snprintf(cp, sizeof(line) - alen, + "%d", ntohs((u_short)port)); width = Wflag ? 45 : Aflag ? 18 : 22; xo_emit("{d:target/%-*.*s} ", width, width, line); - int alen = cp - line - 1, plen = strlen(cp) - 1; + plen = strlen(cp) - 1; + alen--; xo_emit("{e:address/%*.*s}{e:port/%*.*s}", alen, alen, line, plen, plen, cp); if (container) xo_close_container(container); } /* * Construct an Internet address representation. * If the numeric_addr has been supplied, give * numeric value, otherwise try for symbolic name. */ char * inet6name(struct in6_addr *in6p) { struct sockaddr_in6 sin6; char hbuf[NI_MAXHOST], *cp; - static char line[50]; + static char line[NI_MAXHOST]; static char domain[MAXHOSTNAMELEN]; static int first = 1; int flags, error; if (IN6_IS_ADDR_UNSPECIFIED(in6p)) { strcpy(line, "*"); return (line); } if (first && !numeric_addr) { first = 0; - if (gethostname(domain, MAXHOSTNAMELEN) == 0 && + if (gethostname(domain, sizeof(domain)) == 0 && (cp = strchr(domain, '.'))) - (void) strcpy(domain, cp + 1); + strlcpy(domain, cp + 1, sizeof(domain)); else domain[0] = 0; } memset(&sin6, 0, sizeof(sin6)); memcpy(&sin6.sin6_addr, in6p, sizeof(*in6p)); sin6.sin6_family = AF_INET6; /* XXX: in6p.s6_addr[2] can contain scopeid. */ in6_fillscopeid(&sin6); flags = (numeric_addr) ? NI_NUMERICHOST : 0; error = getnameinfo((struct sockaddr *)&sin6, sizeof(sin6), hbuf, sizeof(hbuf), NULL, 0, flags); if (error == 0) { if ((flags & NI_NUMERICHOST) == 0 && (cp = strchr(hbuf, '.')) && !strcmp(cp + 1, domain)) *cp = 0; - strcpy(line, hbuf); + strlcpy(line, hbuf, sizeof(line)); } else { /* XXX: this should not happen. */ - sprintf(line, "%s", + snprintf(line, sizeof(line), "%s", inet_ntop(AF_INET6, (void *)&sin6.sin6_addr, ntop_buf, sizeof(ntop_buf))); } return (line); } #endif /*INET6*/ Index: head/usr.bin/netstat/mroute.c =================================================================== --- head/usr.bin/netstat/mroute.c (revision 311391) +++ head/usr.bin/netstat/mroute.c (revision 311392) @@ -1,454 +1,458 @@ /*- * Copyright (c) 1989 Stephen Deering * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Stephen Deering of Stanford University. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)mroute.c 8.2 (Berkeley) 4/28/95 */ #include __FBSDID("$FreeBSD$"); /* * Print multicast routing structures and statistics. * * MROUTING 1.0 */ #include #include #include #include #include #include #include #include #include #include #include #include #define _KERNEL 1 #include #undef _KERNEL #include #include #include #include #include #include #include #include "netstat.h" #include "nl_defs.h" static void print_bw_meter(struct bw_meter *, int *); static void print_mfc(struct mfc *, int, int *); static void print_bw_meter(struct bw_meter *bw_meter, int *banner_printed) { char s1[256], s2[256], s3[256]; struct timeval now, end, delta; gettimeofday(&now, NULL); if (! *banner_printed) { xo_open_list("bandwidth-meter"); xo_emit(" {T:Bandwidth Meters}\n"); xo_emit(" {T:/%-30s}", "Measured(Start|Packets|Bytes)"); xo_emit(" {T:/%s}", "Type"); xo_emit(" {T:/%-30s}", "Thresh(Interval|Packets|Bytes)"); xo_emit(" {T:Remain}"); xo_emit("\n"); *banner_printed = 1; } xo_open_instance("bandwidth-meter"); /* The measured values */ if (bw_meter->bm_flags & BW_METER_UNIT_PACKETS) { - sprintf(s1, "%ju", (uintmax_t)bw_meter->bm_measured.b_packets); + snprintf(s1, sizeof(s1), "%ju", + (uintmax_t)bw_meter->bm_measured.b_packets); xo_emit("{e:measured-packets/%ju}", (uintmax_t)bw_meter->bm_measured.b_packets); } else - sprintf(s1, "?"); + strcpy(s1, "?"); if (bw_meter->bm_flags & BW_METER_UNIT_BYTES) { - sprintf(s2, "%ju", (uintmax_t)bw_meter->bm_measured.b_bytes); + snprintf(s2, sizeof(s2), "%ju", + (uintmax_t)bw_meter->bm_measured.b_bytes); xo_emit("{e:measured-bytes/%ju}", (uintmax_t)bw_meter->bm_measured.b_bytes); } else - sprintf(s2, "?"); + strcpy(s2, "?"); xo_emit(" {[:-30}{:start-time/%lu.%06lu}|{q:measured-packets/%s}" "|{q:measured-bytes%s}{]:}", (u_long)bw_meter->bm_start_time.tv_sec, (u_long)bw_meter->bm_start_time.tv_usec, s1, s2); /* The type of entry */ xo_emit(" {t:type/%-3s}", (bw_meter->bm_flags & BW_METER_GEQ) ? ">=" : (bw_meter->bm_flags & BW_METER_LEQ) ? "<=" : "?"); /* The threshold values */ if (bw_meter->bm_flags & BW_METER_UNIT_PACKETS) { - sprintf(s1, "%ju", (uintmax_t)bw_meter->bm_threshold.b_packets); + snprintf(s1, sizeof(s1), "%ju", + (uintmax_t)bw_meter->bm_threshold.b_packets); xo_emit("{e:threshold-packets/%ju}", (uintmax_t)bw_meter->bm_threshold.b_packets); } else - sprintf(s1, "?"); + strcpy(s1, "?"); if (bw_meter->bm_flags & BW_METER_UNIT_BYTES) { - sprintf(s2, "%ju", (uintmax_t)bw_meter->bm_threshold.b_bytes); + snprintf(s2, sizeof(s2), "%ju", + (uintmax_t)bw_meter->bm_threshold.b_bytes); xo_emit("{e:threshold-bytes/%ju}", (uintmax_t)bw_meter->bm_threshold.b_bytes); } else - sprintf(s2, "?"); + strcpy(s2, "?"); xo_emit(" {[:-30}{:threshold-time/%lu.%06lu}|{q:threshold-packets/%s}" "|{q:threshold-bytes%s}{]:}", (u_long)bw_meter->bm_threshold.b_time.tv_sec, (u_long)bw_meter->bm_threshold.b_time.tv_usec, s1, s2); /* Remaining time */ timeradd(&bw_meter->bm_start_time, &bw_meter->bm_threshold.b_time, &end); if (timercmp(&now, &end, <=)) { timersub(&end, &now, &delta); - sprintf(s3, "%lu.%06lu", + snprintf(s3, sizeof(s3), "%lu.%06lu", (u_long)delta.tv_sec, (u_long)delta.tv_usec); } else { /* Negative time */ timersub(&now, &end, &delta); - sprintf(s3, "-%lu.06%lu", + snprintf(s3, sizeof(s3), "-%lu.06%lu", (u_long)delta.tv_sec, (u_long)delta.tv_usec); } xo_emit(" {:remaining-time/%s}", s3); xo_open_instance("bandwidth-meter"); xo_emit("\n"); } static void print_mfc(struct mfc *m, int maxvif, int *banner_printed) { struct sockaddr_in sin; struct sockaddr *sa = (struct sockaddr *)&sin; struct bw_meter bw_meter, *bwm; int bw_banner_printed; int error; vifi_t vifi; bw_banner_printed = 0; memset(&sin, 0, sizeof(sin)); sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; if (! *banner_printed) { xo_open_list("multicast-forwarding-entry"); xo_emit("\n{T:IPv4 Multicast Forwarding Table}\n" " {T:Origin} {T:Group} " " {T:Packets In-Vif} {T:Out-Vifs:Ttls}\n"); *banner_printed = 1; } memcpy(&sin.sin_addr, &m->mfc_origin, sizeof(sin.sin_addr)); xo_emit(" {:origin-address/%-15.15s}", routename(sa, numeric_addr)); memcpy(&sin.sin_addr, &m->mfc_mcastgrp, sizeof(sin.sin_addr)); xo_emit(" {:group-address/%-15.15s}", routename(sa, numeric_addr)); xo_emit(" {:sent-packets/%9lu}", m->mfc_pkt_cnt); xo_emit(" {:parent/%3d} ", m->mfc_parent); xo_open_list("vif-ttl"); for (vifi = 0; vifi <= maxvif; vifi++) { if (m->mfc_ttls[vifi] > 0) { xo_open_instance("vif-ttl"); xo_emit(" {k:vif/%u}:{:ttl/%u}", vifi, m->mfc_ttls[vifi]); xo_close_instance("vif-ttl"); } } xo_close_list("vif-ttl"); xo_emit("\n"); /* * XXX We break the rules and try to use KVM to read the * bandwidth meters, they are not retrievable via sysctl yet. */ bwm = m->mfc_bw_meter; while (bwm != NULL) { error = kread((u_long)bwm, (char *)&bw_meter, sizeof(bw_meter)); if (error) break; print_bw_meter(&bw_meter, &bw_banner_printed); bwm = bw_meter.bm_mfc_next; } if (banner_printed) xo_close_list("bandwidth-meter"); } void mroutepr() { struct sockaddr_in sin; struct sockaddr *sa = (struct sockaddr *)&sin; struct vif viftable[MAXVIFS]; struct vif *v; struct mfc *m; u_long pmfchashtbl, pmfctablesize, pviftbl; int banner_printed; int saved_numeric_addr; size_t len; vifi_t vifi, maxvif; saved_numeric_addr = numeric_addr; numeric_addr = 1; memset(&sin, 0, sizeof(sin)); sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; /* * TODO: * The VIF table will move to hanging off the struct if_info for * each IPv4 configured interface. Currently it is statically * allocated, and retrieved either using KVM or an opaque SYSCTL. * * This can't happen until the API documented in multicast(4) * is itself refactored. The historical reason why VIFs use * a separate ifindex space is entirely due to the legacy * capability of the MROUTING code to create IPIP tunnels on * the fly to support DVMRP. When gif(4) became available, this * functionality was deprecated, as PIM does not use it. */ maxvif = 0; pmfchashtbl = pmfctablesize = pviftbl = 0; len = sizeof(viftable); if (live) { if (sysctlbyname("net.inet.ip.viftable", viftable, &len, NULL, 0) < 0) { xo_warn("sysctl: net.inet.ip.viftable"); return; } } else { pmfchashtbl = nl[N_MFCHASHTBL].n_value; pmfctablesize = nl[N_MFCTABLESIZE].n_value; pviftbl = nl[N_VIFTABLE].n_value; if (pmfchashtbl == 0 || pmfctablesize == 0 || pviftbl == 0) { xo_warnx("No IPv4 MROUTING kernel support."); return; } kread(pviftbl, (char *)viftable, sizeof(viftable)); } banner_printed = 0; for (vifi = 0, v = viftable; vifi < MAXVIFS; ++vifi, ++v) { if (v->v_lcl_addr.s_addr == 0) continue; maxvif = vifi; if (!banner_printed) { xo_emit("\n{T:IPv4 Virtual Interface Table\n" " Vif Thresh Local-Address " "Remote-Address Pkts-In Pkts-Out}\n"); banner_printed = 1; xo_open_list("vif"); } xo_open_instance("vif"); memcpy(&sin.sin_addr, &v->v_lcl_addr, sizeof(sin.sin_addr)); xo_emit(" {:vif/%2u} {:threshold/%6u} {:route/%-15.15s}", /* opposite math of add_vif() */ vifi, v->v_threshold, routename(sa, numeric_addr)); memcpy(&sin.sin_addr, &v->v_rmt_addr, sizeof(sin.sin_addr)); xo_emit(" {:source/%-15.15s}", (v->v_flags & VIFF_TUNNEL) ? routename(sa, numeric_addr) : ""); xo_emit(" {:received-packets/%9lu} {:sent-packets/%9lu}\n", v->v_pkt_in, v->v_pkt_out); xo_close_instance("vif"); } if (banner_printed) xo_close_list("vif"); else xo_emit("\n{T:IPv4 Virtual Interface Table is empty}\n"); banner_printed = 0; /* * TODO: * The MFC table will move into the AF_INET radix trie in future. * In 8.x, it becomes a dynamically allocated structure referenced * by a hashed LIST, allowing more than 256 entries w/o kernel tuning. * * If retrieved via opaque SYSCTL, the kernel will coalesce it into * a static table for us. * If retrieved via KVM, the hash list pointers must be followed. */ if (live) { struct mfc *mfctable; len = 0; if (sysctlbyname("net.inet.ip.mfctable", NULL, &len, NULL, 0) < 0) { xo_warn("sysctl: net.inet.ip.mfctable"); return; } mfctable = malloc(len); if (mfctable == NULL) { xo_warnx("malloc %lu bytes", (u_long)len); return; } if (sysctlbyname("net.inet.ip.mfctable", mfctable, &len, NULL, 0) < 0) { free(mfctable); xo_warn("sysctl: net.inet.ip.mfctable"); return; } m = mfctable; while (len >= sizeof(*m)) { print_mfc(m++, maxvif, &banner_printed); len -= sizeof(*m); } if (banner_printed) xo_close_list("multicast-forwarding-entry"); if (len != 0) xo_warnx("print_mfc: %lu trailing bytes", (u_long)len); free(mfctable); } else { LIST_HEAD(, mfc) *mfchashtbl; u_long i, mfctablesize; struct mfc mfc; int error; error = kread(pmfctablesize, (char *)&mfctablesize, sizeof(u_long)); if (error) { xo_warn("kread: mfctablesize"); return; } len = sizeof(*mfchashtbl) * mfctablesize; mfchashtbl = malloc(len); if (mfchashtbl == NULL) { xo_warnx("malloc %lu bytes", (u_long)len); return; } kread(pmfchashtbl, (char *)&mfchashtbl, len); for (i = 0; i < mfctablesize; i++) { LIST_FOREACH(m, &mfchashtbl[i], mfc_hash) { kread((u_long)m, (char *)&mfc, sizeof(mfc)); print_mfc(m, maxvif, &banner_printed); } } if (banner_printed) xo_close_list("multicast-forwarding-entry"); free(mfchashtbl); } if (!banner_printed) xo_emit("\n{T:IPv4 Multicast Forwarding Table is empty}\n"); xo_emit("\n"); numeric_addr = saved_numeric_addr; } void mrt_stats() { struct mrtstat mrtstat; u_long mstaddr; mstaddr = nl[N_MRTSTAT].n_value; if (mstaddr == 0) { fprintf(stderr, "No IPv4 MROUTING kernel support.\n"); return; } if (fetch_stats("net.inet.ip.mrtstat", mstaddr, &mrtstat, sizeof(mrtstat), kread_counters) != 0) return; xo_emit("{T:IPv4 multicast forwarding}:\n"); #define p(f, m) if (mrtstat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)mrtstat.f, plural(mrtstat.f)) #define p2(f, m) if (mrtstat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)mrtstat.f, plurales(mrtstat.f)) xo_open_container("multicast-statistics"); p(mrts_mfc_lookups, "\t{:cache-lookups/%ju} " "{N:/multicast forwarding cache lookup%s}\n"); p2(mrts_mfc_misses, "\t{:cache-misses/%ju} " "{N:/multicast forwarding cache miss%s}\n"); p(mrts_upcalls, "\t{:upcalls-total/%ju} " "{N:/upcall%s to multicast routing daemon}\n"); p(mrts_upq_ovflw, "\t{:upcall-overflows/%ju} " "{N:/upcall queue overflow%s}\n"); p(mrts_upq_sockfull, "\t{:upcalls-dropped-full-buffer/%ju} " "{N:/upcall%s dropped due to full socket buffer}\n"); p(mrts_cache_cleanups, "\t{:cache-cleanups/%ju} " "{N:/cache cleanup%s}\n"); p(mrts_no_route, "\t{:dropped-no-origin/%ju} " "{N:/datagram%s with no route for origin}\n"); p(mrts_bad_tunnel, "\t{:dropped-bad-tunnel/%ju} " "{N:/datagram%s arrived with bad tunneling}\n"); p(mrts_cant_tunnel, "\t{:dropped-could-not-tunnel/%ju} " "{N:/datagram%s could not be tunneled}\n"); p(mrts_wrong_if, "\t{:dropped-wrong-incoming-interface/%ju} " "{N:/datagram%s arrived on wrong interface}\n"); p(mrts_drop_sel, "\t{:dropped-selectively/%ju} " "{N:/datagram%s selectively dropped}\n"); p(mrts_q_overflow, "\t{:dropped-queue-overflow/%ju} " "{N:/datagram%s dropped due to queue overflow}\n"); p(mrts_pkt2large, "\t{:dropped-too-large/%ju} " "{N:/datagram%s dropped for being too large}\n"); #undef p2 #undef p } Index: head/usr.bin/netstat/netstat.h =================================================================== --- head/usr.bin/netstat/netstat.h (revision 311391) +++ head/usr.bin/netstat/netstat.h (revision 311392) @@ -1,148 +1,157 @@ /*- * Copyright (c) 1992, 1993 * Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)netstat.h 8.2 (Berkeley) 1/4/94 * $FreeBSD$ */ #include #define satosin(sa) ((struct sockaddr_in *)(sa)) #define satosin6(sa) ((struct sockaddr_in6 *)(sa)) #define sin6tosa(sin6) ((struct sockaddr *)(sin6)) extern int Aflag; /* show addresses of protocol control block */ extern int aflag; /* show all sockets (including servers) */ extern int bflag; /* show i/f total bytes in/out */ extern int dflag; /* show i/f dropped packets */ extern int gflag; /* show group (multicast) routing or stats */ extern int hflag; /* show counters in human readable format */ extern int iflag; /* show interfaces */ extern int Lflag; /* show size of listen queues */ extern int mflag; /* show memory stats */ extern int noutputs; /* how much outputs before we exit */ extern int numeric_addr; /* show addresses numerically */ extern int numeric_port; /* show ports numerically */ extern int rflag; /* show routing tables (or routing stats) */ extern int Rflag; /* show flowid / RSS information */ extern int sflag; /* show protocol statistics */ extern int Tflag; /* show TCP control block info */ extern int Wflag; /* wide display */ extern int xflag; /* extended display, includes all socket buffer info */ extern int zflag; /* zero stats */ extern int interval; /* repeat interval for i/f stats */ extern char *interface; /* desired i/f for stats, or NULL for all i/fs */ extern int unit; /* unit number for above */ extern int live; /* true if we are examining a live system */ typedef int kreadfn_t(u_long, void *, size_t); int fetch_stats(const char *, u_long, void *, size_t, kreadfn_t); int fetch_stats_ro(const char *, u_long, void *, size_t, kreadfn_t); int kread(u_long addr, void *buf, size_t size); uint64_t kread_counter(u_long addr); int kread_counters(u_long addr, void *buf, size_t size); void kset_dpcpu(u_int); const char *plural(uintmax_t); const char *plurales(uintmax_t); const char *pluralies(uintmax_t); struct sockaddr; struct socket; struct xsocket; 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, int); void sctp_stats(u_long, const char *, int, int); #endif void arp_stats(u_long, const char *, int, 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, 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 INET +struct in_addr; + +char *inetname(struct in_addr *); +#endif + #ifdef INET6 +struct in6_addr; + +char *inet6name(struct in6_addr *); void ip6_stats(u_long, const char *, int, int); void ip6_ifstats(char *); void icmp6_stats(u_long, const char *, int, int); void icmp6_ifstats(char *); void pim6_stats(u_long, const char *, int, int); void rip6_stats(u_long, const char *, int, int); void mroute6pr(void); void mrt6_stats(void); struct sockaddr_in6; struct in6_addr; void in6_fillscopeid(struct sockaddr_in6 *); void inet6print(const char *, struct in6_addr *, int, const char *, int); #endif /*INET6*/ #ifdef IPSEC void pfkey_stats(u_long, const char *, int, int); #endif void mbpr(void *, u_long); void netisr_stats(void); void hostpr(u_long, u_long); void impstats(u_long, u_long); void intpr(void (*)(char *), int); void pr_family(int); void rt_stats(void); void flowtable_stats(void); char *routename(struct sockaddr *, int); const char *netname(struct sockaddr *, struct sockaddr *); void routepr(int, int); #ifdef NETGRAPH void netgraphprotopr(u_long, const char *, int, int); #endif void unixpr(u_long, u_long, u_long, u_long, u_long, bool *); void mroutepr(void); void mrt_stats(void); void bpf_stats(char *); Index: head/usr.bin/netstat/route.c =================================================================== --- head/usr.bin/netstat/route.c (revision 311391) +++ head/usr.bin/netstat/route.c (revision 311392) @@ -1,789 +1,799 @@ /*- * Copyright (c) 1983, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static char sccsid[] = "From: @(#)route.c 8.6 (Berkeley) 4/28/95"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include "netstat.h" #include "nl_defs.h" /* * Definitions for showing gateway flags. */ static struct bits { u_long b_mask; char b_val; const char *b_name; } bits[] = { { RTF_UP, 'U', "up" }, { RTF_GATEWAY, 'G', "gateway" }, { RTF_HOST, 'H', "host" }, { RTF_REJECT, 'R', "reject" }, { RTF_DYNAMIC, 'D', "dynamic" }, { RTF_MODIFIED, 'M', "modified" }, { RTF_DONE, 'd', "done" }, /* Completed -- for routing msgs only */ { RTF_XRESOLVE, 'X', "xresolve" }, { RTF_STATIC, 'S', "static" }, { RTF_PROTO1, '1', "proto1" }, { RTF_PROTO2, '2', "proto2" }, { RTF_PROTO3, '3', "proto3" }, { RTF_BLACKHOLE,'B', "blackhole" }, { RTF_BROADCAST,'b', "broadcast" }, #ifdef RTF_LLINFO { RTF_LLINFO, 'L', "llinfo" }, #endif { 0 , 0, NULL } }; struct ifmap_entry { char ifname[IFNAMSIZ]; }; static struct ifmap_entry *ifmap; static int ifmap_size; static struct timespec uptime; static const char *netname4(in_addr_t, in_addr_t); #ifdef INET6 static const char *netname6(struct sockaddr_in6 *, struct sockaddr_in6 *); #endif static void p_rtable_sysctl(int, int); static void p_rtentry_sysctl(const char *name, struct rt_msghdr *); static int p_sockaddr(const char *name, struct sockaddr *, struct sockaddr *, int, int); static const char *fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags); static void p_flags(int, const char *); static const char *fmt_flags(int f); -static void domask(char *, in_addr_t, u_long); +static void domask(char *, size_t, u_long); /* * Print routing tables. */ void routepr(int fibnum, int af) { size_t intsize; int numfibs; if (live == 0) return; intsize = sizeof(int); if (fibnum == -1 && sysctlbyname("net.my_fibnum", &fibnum, &intsize, NULL, 0) == -1) fibnum = 0; if (sysctlbyname("net.fibs", &numfibs, &intsize, NULL, 0) == -1) numfibs = 1; if (fibnum < 0 || fibnum > numfibs - 1) errx(EX_USAGE, "%d: invalid fib", fibnum); /* * Since kernel & userland use different timebase * (time_uptime vs time_second) and we are reading kernel memory * directly we should do rt_expire --> expire_time conversion. */ if (clock_gettime(CLOCK_UPTIME, &uptime) < 0) err(EX_OSERR, "clock_gettime() failed"); xo_open_container("route-information"); xo_emit("{T:Routing tables}"); if (fibnum) xo_emit(" ({L:fib}: {:fib/%d})", fibnum); xo_emit("\n"); p_rtable_sysctl(fibnum, af); xo_close_container("route-information"); } /* * Print address family header before a section of the routing table. */ void pr_family(int af1) { const char *afname; switch (af1) { case AF_INET: afname = "Internet"; break; #ifdef INET6 case AF_INET6: afname = "Internet6"; break; #endif /*INET6*/ case AF_ISO: afname = "ISO"; break; case AF_CCITT: afname = "X.25"; break; case AF_NETGRAPH: afname = "Netgraph"; break; default: afname = NULL; break; } if (afname) xo_emit("\n{k:address-family/%s}:\n", afname); else xo_emit("\n{L:Protocol Family} {k:address-family/%d}:\n", af1); } /* column widths; each followed by one space */ #ifndef INET6 #define WID_DST_DEFAULT(af) 18 /* width of destination column */ #define WID_GW_DEFAULT(af) 18 /* width of gateway column */ #define WID_IF_DEFAULT(af) (Wflag ? 10 : 8) /* width of netif column */ #else #define WID_DST_DEFAULT(af) \ ((af) == AF_INET6 ? (numeric_addr ? 33: 18) : 18) #define WID_GW_DEFAULT(af) \ ((af) == AF_INET6 ? (numeric_addr ? 29 : 18) : 18) #define WID_IF_DEFAULT(af) ((af) == AF_INET6 ? 8 : (Wflag ? 10 : 8)) #endif /*INET6*/ static int wid_dst; static int wid_gw; static int wid_flags; static int wid_pksent; static int wid_mtu; static int wid_if; static int wid_expire; /* * Print header for routing table columns. */ static void pr_rthdr(int af1 __unused) { if (Wflag) { xo_emit("{T:/%-*.*s} {T:/%-*.*s} {T:/%-*.*s} {T:/%*.*s} " "{T:/%*.*s} {T:/%*.*s} {T:/%*s}\n", wid_dst, wid_dst, "Destination", wid_gw, wid_gw, "Gateway", wid_flags, wid_flags, "Flags", wid_pksent, wid_pksent, "Use", wid_mtu, wid_mtu, "Mtu", wid_if, wid_if, "Netif", wid_expire, "Expire"); } else { xo_emit("{T:/%-*.*s} {T:/%-*.*s} {T:/%-*.*s} {T:/%*.*s} " "{T:/%*s}\n", wid_dst, wid_dst, "Destination", wid_gw, wid_gw, "Gateway", wid_flags, wid_flags, "Flags", wid_if, wid_if, "Netif", wid_expire, "Expire"); } } static void p_rtable_sysctl(int fibnum, int af) { size_t needed; int mib[7]; char *buf, *next, *lim; struct rt_msghdr *rtm; struct sockaddr *sa; int fam = AF_UNSPEC, ifindex = 0, size; int need_table_close = false; struct ifaddrs *ifap, *ifa; struct sockaddr_dl *sdl; /* * Retrieve interface list at first * since we need #ifindex -> if_xname match */ if (getifaddrs(&ifap) != 0) err(EX_OSERR, "getifaddrs"); for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family != AF_LINK) continue; sdl = (struct sockaddr_dl *)ifa->ifa_addr; ifindex = sdl->sdl_index; if (ifindex >= ifmap_size) { size = roundup(ifindex + 1, 32) * sizeof(struct ifmap_entry); if ((ifmap = realloc(ifmap, size)) == NULL) errx(2, "realloc(%d) failed", size); memset(&ifmap[ifmap_size], 0, size - ifmap_size * sizeof(struct ifmap_entry)); ifmap_size = roundup(ifindex + 1, 32); } if (*ifmap[ifindex].ifname != '\0') continue; strlcpy(ifmap[ifindex].ifname, ifa->ifa_name, IFNAMSIZ); } freeifaddrs(ifap); mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = af; mib[4] = NET_RT_DUMP; mib[5] = 0; mib[6] = fibnum; if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0) err(EX_OSERR, "sysctl: net.route.0.%d.dump.%d estimate", af, fibnum); if ((buf = malloc(needed)) == NULL) errx(2, "malloc(%lu)", (unsigned long)needed); if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) err(1, "sysctl: net.route.0.%d.dump.%d", af, fibnum); lim = buf + needed; xo_open_container("route-table"); xo_open_list("rt-family"); for (next = buf; next < lim; next += rtm->rtm_msglen) { rtm = (struct rt_msghdr *)next; if (rtm->rtm_version != RTM_VERSION) continue; /* * Peek inside header to determine AF */ sa = (struct sockaddr *)(rtm + 1); /* Only print family first time. */ if (fam != sa->sa_family) { if (need_table_close) { xo_close_list("rt-entry"); xo_close_instance("rt-family"); } need_table_close = true; fam = sa->sa_family; wid_dst = WID_DST_DEFAULT(fam); wid_gw = WID_GW_DEFAULT(fam); wid_flags = 6; wid_pksent = 8; wid_mtu = 6; wid_if = WID_IF_DEFAULT(fam); wid_expire = 6; xo_open_instance("rt-family"); pr_family(fam); xo_open_list("rt-entry"); pr_rthdr(fam); } p_rtentry_sysctl("rt-entry", rtm); } if (need_table_close) { xo_close_list("rt-entry"); xo_close_instance("rt-family"); } xo_close_list("rt-family"); xo_close_container("route-table"); free(buf); } static void p_rtentry_sysctl(const char *name, struct rt_msghdr *rtm) { struct sockaddr *sa, *addr[RTAX_MAX]; char buffer[128]; char prettyname[128]; int i, protrusion; xo_open_instance(name); sa = (struct sockaddr *)(rtm + 1); for (i = 0; i < RTAX_MAX; i++) { if (rtm->rtm_addrs & (1 << i)) addr[i] = sa; sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa)); } protrusion = p_sockaddr("destination", addr[RTAX_DST], addr[RTAX_NETMASK], rtm->rtm_flags, wid_dst); protrusion = p_sockaddr("gateway", addr[RTAX_GATEWAY], NULL, RTF_HOST, wid_gw - protrusion); snprintf(buffer, sizeof(buffer), "{[:-%d}{:flags/%%s}{]:} ", wid_flags - protrusion); p_flags(rtm->rtm_flags, buffer); if (Wflag) { xo_emit("{t:use/%*lu} ", wid_pksent, rtm->rtm_rmx.rmx_pksent); if (rtm->rtm_rmx.rmx_mtu != 0) xo_emit("{t:mtu/%*lu} ", wid_mtu, rtm->rtm_rmx.rmx_mtu); else xo_emit("{P:/%*s} ", wid_mtu, ""); } memset(prettyname, 0, sizeof(prettyname)); if (rtm->rtm_index < ifmap_size) { strlcpy(prettyname, ifmap[rtm->rtm_index].ifname, sizeof(prettyname)); if (*prettyname == '\0') strlcpy(prettyname, "---", sizeof(prettyname)); } if (Wflag) xo_emit("{t:interface-name/%*s}", wid_if, prettyname); else xo_emit("{t:interface-name/%*.*s}", wid_if, wid_if, prettyname); if (rtm->rtm_rmx.rmx_expire) { time_t expire_time; if ((expire_time = rtm->rtm_rmx.rmx_expire - uptime.tv_sec) > 0) xo_emit(" {:expire-time/%*d}", wid_expire, (int)expire_time); } xo_emit("\n"); xo_close_instance(name); } static int p_sockaddr(const char *name, struct sockaddr *sa, struct sockaddr *mask, int flags, int width) { const char *cp; char buf[128]; int protrusion; cp = fmt_sockaddr(sa, mask, flags); if (width < 0) { snprintf(buf, sizeof(buf), "{:%s/%%s} ", name); xo_emit(buf, cp); protrusion = 0; } else { if (Wflag != 0 || numeric_addr) { snprintf(buf, sizeof(buf), "{[:%d}{:%s/%%s}{]:} ", -width, name); xo_emit(buf, cp); protrusion = strlen(cp) - width; if (protrusion < 0) protrusion = 0; } else { snprintf(buf, sizeof(buf), "{[:%d}{:%s/%%-.*s}{]:} ", -width, name); xo_emit(buf, width, cp); protrusion = 0; } } return (protrusion); } static const char * fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags) { static char buf[128]; const char *cp; if (sa == NULL) return ("null"); switch(sa->sa_family) { #ifdef INET6 case AF_INET6: /* * The sa6->sin6_scope_id must be filled here because * this sockaddr is extracted from kmem(4) directly * and has KAME-specific embedded scope id in * sa6->sin6_addr.s6_addr[2]. */ in6_fillscopeid(satosin6(sa)); /* FALLTHROUGH */ #endif /*INET6*/ case AF_INET: if (flags & RTF_HOST) cp = routename(sa, numeric_addr); else if (mask) cp = netname(sa, mask); else cp = netname(sa, NULL); break; case AF_NETGRAPH: { strlcpy(buf, ((struct sockaddr_ng *)sa)->sg_data, sizeof(buf)); cp = buf; break; } case AF_LINK: { #if 0 struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; /* Interface route. */ if (sdl->sdl_nlen) cp = sdl->sdl_data; else #endif cp = routename(sa, 1); break; } default: { u_char *s = (u_char *)sa->sa_data, *slim; char *cq, *cqlim; cq = buf; slim = sa->sa_len + (u_char *) sa; - cqlim = cq + sizeof(buf) - 6; - cq += sprintf(cq, "(%d)", sa->sa_family); + cqlim = cq + sizeof(buf) - sizeof(" ffff"); + snprintf(cq, sizeof(cq), "(%d)", sa->sa_family); + cq += strlen(cq); while (s < slim && cq < cqlim) { - cq += sprintf(cq, " %02x", *s++); - if (s < slim) - cq += sprintf(cq, "%02x", *s++); + snprintf(cq, sizeof(" ff"), " %02x", *s++); + cq += strlen(cq); + if (s < slim) { + snprintf(cq, sizeof("ff"), "%02x", *s++); + cq += strlen(cq); + } } cp = buf; } } return (cp); } static void p_flags(int f, const char *format) { struct bits *p; xo_emit(format, fmt_flags(f)); xo_open_list("flags_pretty"); for (p = bits; p->b_mask; p++) if (p->b_mask & f) xo_emit("{le:flags_pretty/%s}", p->b_name); xo_close_list("flags_pretty"); } static const char * fmt_flags(int f) { static char name[33]; char *flags; struct bits *p = bits; for (flags = name; p->b_mask; p++) if (p->b_mask & f) *flags++ = p->b_val; *flags = '\0'; return (name); } char * routename(struct sockaddr *sa, int flags) { static char line[NI_MAXHOST]; int error, f; f = (flags) ? NI_NUMERICHOST : 0; error = getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, f); if (error) { const void *src; switch (sa->sa_family) { #ifdef INET case AF_INET: src = &satosin(sa)->sin_addr; break; #endif /* INET */ #ifdef INET6 case AF_INET6: src = &satosin6(sa)->sin6_addr; break; #endif /* INET6 */ default: return(line); } inet_ntop(sa->sa_family, src, line, sizeof(line) - 1); return (line); } trimdomain(line, strlen(line)); return (line); } #define NSHIFT(m) ( \ (m) == IN_CLASSA_NET ? IN_CLASSA_NSHIFT : \ (m) == IN_CLASSB_NET ? IN_CLASSB_NSHIFT : \ (m) == IN_CLASSC_NET ? IN_CLASSC_NSHIFT : \ 0) static void -domask(char *dst, in_addr_t addr __unused, u_long mask) +domask(char *dst, size_t buflen, u_long mask) { int b, i; if (mask == 0) { *dst = '\0'; return; } i = 0; for (b = 0; b < 32; b++) if (mask & (1 << b)) { int bb; i = b; for (bb = b+1; bb < 32; bb++) if (!(mask & (1 << bb))) { i = -1; /* noncontig */ break; } break; } if (i == -1) - sprintf(dst, "&0x%lx", mask); + snprintf(dst, buflen, "&0x%lx", mask); else - sprintf(dst, "/%d", 32-i); + snprintf(dst, buflen, "/%d", 32-i); } /* * Return the name of the network whose address is given. */ const char * netname(struct sockaddr *sa, struct sockaddr *mask) { switch (sa->sa_family) { case AF_INET: if (mask != NULL) return (netname4(satosin(sa)->sin_addr.s_addr, satosin(mask)->sin_addr.s_addr)); else return (netname4(satosin(sa)->sin_addr.s_addr, INADDR_ANY)); break; #ifdef INET6 case AF_INET6: return (netname6(satosin6(sa), satosin6(mask))); #endif /* INET6 */ default: return (NULL); } } static const char * netname4(in_addr_t in, in_addr_t mask) { char *cp = 0; - static char line[MAXHOSTNAMELEN + sizeof("/xx")]; + static char line[MAXHOSTNAMELEN + sizeof("&0xffffffff")]; char nline[INET_ADDRSTRLEN]; struct netent *np = 0; in_addr_t i; if (in == INADDR_ANY && mask == 0) { strlcpy(line, "default", sizeof(line)); return (line); } /* It is ok to supply host address. */ in &= mask; i = ntohl(in); if (!numeric_addr && i) { np = getnetbyaddr(i >> NSHIFT(ntohl(mask)), AF_INET); if (np != NULL) { cp = np->n_name; trimdomain(cp, strlen(cp)); } } if (cp != NULL) strlcpy(line, cp, sizeof(line)); else { inet_ntop(AF_INET, &in, nline, sizeof(nline)); strlcpy(line, nline, sizeof(line)); - domask(line + strlen(line), i, ntohl(mask)); + domask(line + strlen(line), sizeof(line) - strlen(line), ntohl(mask)); } return (line); } #undef NSHIFT #ifdef INET6 void in6_fillscopeid(struct sockaddr_in6 *sa6) { #if defined(__KAME__) /* * XXX: This is a special workaround for KAME kernels. * sin6_scope_id field of SA should be set in the future. */ if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) || IN6_IS_ADDR_MC_NODELOCAL(&sa6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr)) { if (sa6->sin6_scope_id == 0) sa6->sin6_scope_id = ntohs(*(u_int16_t *)&sa6->sin6_addr.s6_addr[2]); sa6->sin6_addr.s6_addr[2] = sa6->sin6_addr.s6_addr[3] = 0; } #endif } /* Mask to length table. To check an invalid value, (length + 1) is used. */ -static int masktolen[256] = { +static const u_char masktolen[256] = { [0xff] = 8 + 1, [0xfe] = 7 + 1, [0xfc] = 6 + 1, [0xf8] = 5 + 1, [0xf0] = 4 + 1, [0xe0] = 3 + 1, [0xc0] = 2 + 1, [0x80] = 1 + 1, [0x00] = 0 + 1, }; static const char * netname6(struct sockaddr_in6 *sa6, struct sockaddr_in6 *mask) { static char line[NI_MAXHOST + sizeof("/xxx") - 1]; struct sockaddr_in6 addr; char nline[NI_MAXHOST]; + char maskbuf[sizeof("/xxx")]; u_char *p, *lim; - int masklen, illegal = 0, i; + u_char masklen; + int i; + bool illegal = false; if (mask) { p = (u_char *)&mask->sin6_addr; for (masklen = 0, lim = p + 16; p < lim; p++) { - if (masktolen[*p] > 0) + if (masktolen[*p] > 0) { /* -1 is required. */ - masklen += masktolen[*p] - 1; - else - illegal++; + masklen += (masktolen[*p] - 1); + } else + illegal = true; } if (illegal) xo_error("illegal prefixlen\n"); memcpy(&addr, sa6, sizeof(addr)); for (i = 0; i < 16; ++i) addr.sin6_addr.s6_addr[i] &= mask->sin6_addr.s6_addr[i]; sa6 = &addr; } else masklen = 128; if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr)) return("default"); getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, nline, sizeof(nline), NULL, 0, NI_NUMERICHOST); if (numeric_addr) strlcpy(line, nline, sizeof(line)); else getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line), NULL, 0, 0); - if (numeric_addr || strcmp(line, nline) == 0) - sprintf(&line[strlen(line)], "/%d", masklen); + if (numeric_addr || strcmp(line, nline) == 0) { + snprintf(maskbuf, sizeof(maskbuf), "/%d", masklen); + strlcat(line, maskbuf, sizeof(line)); + } return (line); } #endif /*INET6*/ /* * Print routing statistics */ void rt_stats(void) { struct rtstat rtstat; u_long rtsaddr, rttaddr; int rttrash; if ((rtsaddr = nl[N_RTSTAT].n_value) == 0) { xo_emit("{W:rtstat: symbol not in namelist}\n"); return; } if ((rttaddr = nl[N_RTTRASH].n_value) == 0) { xo_emit("{W:rttrash: symbol not in namelist}\n"); return; } kread(rtsaddr, (char *)&rtstat, sizeof (rtstat)); kread(rttaddr, (char *)&rttrash, sizeof (rttrash)); xo_emit("{T:routing}:\n"); #define p(f, m) if (rtstat.f || sflag <= 1) \ xo_emit(m, rtstat.f, plural(rtstat.f)) p(rts_badredirect, "\t{:bad-redirects/%hu} " "{N:/bad routing redirect%s}\n"); p(rts_dynamic, "\t{:dynamically-created/%hu} " "{N:/dynamically created route%s}\n"); p(rts_newgateway, "\t{:new-gateways/%hu} " "{N:/new gateway%s due to redirects}\n"); p(rts_unreach, "\t{:unreachable-destination/%hu} " "{N:/destination%s found unreachable}\n"); p(rts_wildcard, "\t{:wildcard-uses/%hu} " "{N:/use%s of a wildcard route}\n"); #undef p if (rttrash || sflag <= 1) xo_emit("\t{:unused-but-not-freed/%u} " "{N:/route%s not in table but not freed}\n", rttrash, plural(rttrash)); } Index: head/usr.bin/netstat/sctp.c =================================================================== --- head/usr.bin/netstat/sctp.c (revision 311391) +++ head/usr.bin/netstat/sctp.c (revision 311392) @@ -1,843 +1,841 @@ /*- * Copyright (c) 2001-2007, by Weongyo Jeong. All rights reserved. * Copyright (c) 2011, by Michael Tuexen. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * a) Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * b) Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the distribution. * * c) Neither the name of Cisco Systems, Inc. nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #if 0 #ifndef lint static char sccsid[] = "@(#)sctp.c 0.1 (Berkeley) 4/18/2007"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "netstat.h" #include #ifdef SCTP static void sctp_statesprint(uint32_t state); #define NETSTAT_SCTP_STATES_CLOSED 0x0 #define NETSTAT_SCTP_STATES_BOUND 0x1 #define NETSTAT_SCTP_STATES_LISTEN 0x2 #define NETSTAT_SCTP_STATES_COOKIE_WAIT 0x3 #define NETSTAT_SCTP_STATES_COOKIE_ECHOED 0x4 #define NETSTAT_SCTP_STATES_ESTABLISHED 0x5 #define NETSTAT_SCTP_STATES_SHUTDOWN_SENT 0x6 #define NETSTAT_SCTP_STATES_SHUTDOWN_RECEIVED 0x7 #define NETSTAT_SCTP_STATES_SHUTDOWN_ACK_SENT 0x8 #define NETSTAT_SCTP_STATES_SHUTDOWN_PENDING 0x9 static const char *sctpstates[] = { "CLOSED", "BOUND", "LISTEN", "COOKIE_WAIT", "COOKIE_ECHOED", "ESTABLISHED", "SHUTDOWN_SENT", "SHUTDOWN_RECEIVED", "SHUTDOWN_ACK_SENT", "SHUTDOWN_PENDING" }; static LIST_HEAD(xladdr_list, xladdr_entry) xladdr_head; struct xladdr_entry { struct xsctp_laddr *xladdr; LIST_ENTRY(xladdr_entry) xladdr_entries; }; static LIST_HEAD(xraddr_list, xraddr_entry) xraddr_head; struct xraddr_entry { struct xsctp_raddr *xraddr; LIST_ENTRY(xraddr_entry) xraddr_entries; }; -#ifdef INET -char * -inetname(struct in_addr *inp); -#endif - -#ifdef INET6 -char * -inet6name(struct in6_addr *in6p); -#endif - static void sctp_print_address(const char *container, union sctp_sockstore *address, int port, int num_port) { struct servent *sp = 0; char line[80], *cp; int width; + size_t alen, plen; if (container) xo_open_container(container); switch (address->sa.sa_family) { #ifdef INET case AF_INET: - sprintf(line, "%.*s.", Wflag ? 39 : 16, inetname(&address->sin.sin_addr)); + snprintf(line, sizeof(line), "%.*s.", + Wflag ? 39 : 16, inetname(&address->sin.sin_addr)); break; #endif #ifdef INET6 case AF_INET6: - sprintf(line, "%.*s.", Wflag ? 39 : 16, inet6name(&address->sin6.sin6_addr)); + snprintf(line, sizeof(line), "%.*s.", + Wflag ? 39 : 16, inet6name(&address->sin6.sin6_addr)); break; #endif default: - sprintf(line, "%.*s.", Wflag ? 39 : 16, ""); + snprintf(line, sizeof(line), "%.*s.", + Wflag ? 39 : 16, ""); break; } - cp = strchr(line, '\0'); + alen = strlen(line); + cp = line + alen; if (!num_port && port) sp = getservbyport((int)port, "sctp"); if (sp || port == 0) - sprintf(cp, "%.15s ", sp ? sp->s_name : "*"); + snprintf(cp, sizeof(line) - alen, + "%.15s ", sp ? sp->s_name : "*"); else - sprintf(cp, "%d ", ntohs((u_short)port)); + snprintf(cp, sizeof(line) - alen, + "%d ", ntohs((u_short)port)); width = Wflag ? 45 : 22; xo_emit("{d:target/%-*.*s} ", width, width, line); - int alen = cp - line - 1, plen = strlen(cp) - 1; + plen = strlen(cp) - 1; + alen--; xo_emit("{e:address/%*.*s}{e:port/%*.*s}", alen, alen, line, plen, plen, cp); if (container) xo_close_container(container); } static int sctp_skip_xinpcb_ifneed(char *buf, const size_t buflen, size_t *offset) { int exist_tcb = 0; struct xsctp_tcb *xstcb; struct xsctp_raddr *xraddr; struct xsctp_laddr *xladdr; while (*offset < buflen) { xladdr = (struct xsctp_laddr *)(buf + *offset); *offset += sizeof(struct xsctp_laddr); if (xladdr->last == 1) break; } while (*offset < buflen) { xstcb = (struct xsctp_tcb *)(buf + *offset); *offset += sizeof(struct xsctp_tcb); if (xstcb->last == 1) break; exist_tcb = 1; while (*offset < buflen) { xladdr = (struct xsctp_laddr *)(buf + *offset); *offset += sizeof(struct xsctp_laddr); if (xladdr->last == 1) break; } while (*offset < buflen) { xraddr = (struct xsctp_raddr *)(buf + *offset); *offset += sizeof(struct xsctp_raddr); if (xraddr->last == 1) break; } } /* * If Lflag is set, we don't care about the return value. */ if (Lflag) return 0; return exist_tcb; } static void sctp_process_tcb(struct xsctp_tcb *xstcb, char *buf, const size_t buflen, size_t *offset, int *indent) { int i, xl_total = 0, xr_total = 0, x_max; struct xsctp_raddr *xraddr; struct xsctp_laddr *xladdr; struct xladdr_entry *prev_xl = NULL, *xl = NULL, *xl_tmp; struct xraddr_entry *prev_xr = NULL, *xr = NULL, *xr_tmp; LIST_INIT(&xladdr_head); LIST_INIT(&xraddr_head); /* * Make `struct xladdr_list' list and `struct xraddr_list' list * to handle the address flexibly. */ while (*offset < buflen) { xladdr = (struct xsctp_laddr *)(buf + *offset); *offset += sizeof(struct xsctp_laddr); if (xladdr->last == 1) break; prev_xl = xl; xl = malloc(sizeof(struct xladdr_entry)); if (xl == NULL) { xo_warnx("malloc %lu bytes", (u_long)sizeof(struct xladdr_entry)); goto out; } xl->xladdr = xladdr; if (prev_xl == NULL) LIST_INSERT_HEAD(&xladdr_head, xl, xladdr_entries); else LIST_INSERT_AFTER(prev_xl, xl, xladdr_entries); xl_total++; } while (*offset < buflen) { xraddr = (struct xsctp_raddr *)(buf + *offset); *offset += sizeof(struct xsctp_raddr); if (xraddr->last == 1) break; prev_xr = xr; xr = malloc(sizeof(struct xraddr_entry)); if (xr == NULL) { xo_warnx("malloc %lu bytes", (u_long)sizeof(struct xraddr_entry)); goto out; } xr->xraddr = xraddr; if (prev_xr == NULL) LIST_INSERT_HEAD(&xraddr_head, xr, xraddr_entries); else LIST_INSERT_AFTER(prev_xr, xr, xraddr_entries); xr_total++; } /* * Let's print the address infos. */ xo_open_list("address"); xl = LIST_FIRST(&xladdr_head); xr = LIST_FIRST(&xraddr_head); x_max = MAX(xl_total, xr_total); for (i = 0; i < x_max; i++) { xo_open_instance("address"); if (((*indent == 0) && i > 0) || *indent > 0) xo_emit("{P:/%-12s} ", " "); if (xl != NULL) { sctp_print_address("local", &(xl->xladdr->address), htons(xstcb->local_port), numeric_port); } else { if (Wflag) { xo_emit("{P:/%-45s} ", " "); } else { xo_emit("{P:/%-22s} ", " "); } } if (xr != NULL && !Lflag) { sctp_print_address("remote", &(xr->xraddr->address), htons(xstcb->remote_port), numeric_port); } if (xl != NULL) xl = LIST_NEXT(xl, xladdr_entries); if (xr != NULL) xr = LIST_NEXT(xr, xraddr_entries); if (i == 0 && !Lflag) sctp_statesprint(xstcb->state); if (i < x_max) xo_emit("\n"); xo_close_instance("address"); } out: /* * Free the list which be used to handle the address. */ xl = LIST_FIRST(&xladdr_head); while (xl != NULL) { xl_tmp = LIST_NEXT(xl, xladdr_entries); free(xl); xl = xl_tmp; } xr = LIST_FIRST(&xraddr_head); while (xr != NULL) { xr_tmp = LIST_NEXT(xr, xraddr_entries); free(xr); xr = xr_tmp; } } static void sctp_process_inpcb(struct xsctp_inpcb *xinpcb, char *buf, const size_t buflen, size_t *offset) { int indent = 0, xladdr_total = 0, is_listening = 0; static int first = 1; const char *tname, *pname; struct xsctp_tcb *xstcb; struct xsctp_laddr *xladdr; size_t offset_laddr; int process_closed; if (xinpcb->maxqlen > 0) is_listening = 1; if (first) { if (!Lflag) { xo_emit("Active SCTP associations"); if (aflag) xo_emit(" (including servers)"); } else xo_emit("Current listen queue sizes (qlen/maxqlen)"); xo_emit("\n"); if (Lflag) xo_emit("{T:/%-6.6s} {T:/%-5.5s} {T:/%-8.8s} " "{T:/%-22.22s}\n", "Proto", "Type", "Listen", "Local Address"); else if (Wflag) xo_emit("{T:/%-6.6s} {T:/%-5.5s} {T:/%-45.45s} " "{T:/%-45.45s} {T:/%s}\n", "Proto", "Type", "Local Address", "Foreign Address", "(state)"); else xo_emit("{T:/%-6.6s} {T:/%-5.5s} {T:/%-22.22s} " "{T:/%-22.22s} {T:/%s}\n", "Proto", "Type", "Local Address", "Foreign Address", "(state)"); first = 0; } xladdr = (struct xsctp_laddr *)(buf + *offset); if ((!aflag && is_listening) || (Lflag && !is_listening)) { sctp_skip_xinpcb_ifneed(buf, buflen, offset); return; } if (xinpcb->flags & SCTP_PCB_FLAGS_BOUND_V6) { /* Can't distinguish between sctp46 and sctp6 */ pname = "sctp46"; } else { pname = "sctp4"; } if (xinpcb->flags & SCTP_PCB_FLAGS_TCPTYPE) tname = "1to1"; else if (xinpcb->flags & SCTP_PCB_FLAGS_UDPTYPE) tname = "1toN"; else tname = "????"; if (Lflag) { char buf1[22]; snprintf(buf1, sizeof buf1, "%u/%u", xinpcb->qlen, xinpcb->maxqlen); xo_emit("{:protocol/%-6.6s/%s} {:type/%-5.5s/%s} ", pname, tname); xo_emit("{d:queues/%-8.8s}{e:queue-len/%hu}" "{e:max-queue-len/%hu} ", buf1, xinpcb->qlen, xinpcb->maxqlen); } offset_laddr = *offset; process_closed = 0; xo_open_list("local-address"); retry: while (*offset < buflen) { xladdr = (struct xsctp_laddr *)(buf + *offset); *offset += sizeof(struct xsctp_laddr); if (xladdr->last) { if (aflag && !Lflag && (xladdr_total == 0) && process_closed) { xo_open_instance("local-address"); xo_emit("{:protocol/%-6.6s/%s} " "{:type/%-5.5s/%s} ", pname, tname); if (Wflag) { xo_emit("{P:/%-91.91s/%s} " "{:state/CLOSED}", " "); } else { xo_emit("{P:/%-45.45s/%s} " "{:state/CLOSED}", " "); } xo_close_instance("local-address"); } if (process_closed || is_listening) { xo_emit("\n"); } break; } if (!Lflag && !is_listening && !process_closed) continue; xo_open_instance("local-address"); if (xladdr_total == 0) { if (!Lflag) { xo_emit("{:protocol/%-6.6s/%s} " "{:type/%-5.5s/%s} ", pname, tname); } } else { xo_emit("\n"); xo_emit(Lflag ? "{P:/%-21.21s} " : "{P:/%-12.12s} ", " "); } sctp_print_address("local", &(xladdr->address), htons(xinpcb->local_port), numeric_port); if (aflag && !Lflag && xladdr_total == 0) { if (Wflag) { if (process_closed) { xo_emit("{P:/%-45.45s} " "{:state/CLOSED}", " "); } else { xo_emit("{P:/%-45.45s} " "{:state/LISTEN}", " "); } } else { if (process_closed) { xo_emit("{P:/%-22.22s} " "{:state/CLOSED}", " "); } else { xo_emit("{P:/%-22.22s} " "{:state/LISTEN}", " "); } } } xladdr_total++; xo_close_instance("local-address"); } xstcb = (struct xsctp_tcb *)(buf + *offset); *offset += sizeof(struct xsctp_tcb); if (aflag && (xladdr_total == 0) && xstcb->last && !process_closed) { process_closed = 1; *offset = offset_laddr; goto retry; } while (xstcb->last == 0 && *offset < buflen) { xo_emit("{:protocol/%-6.6s/%s} {:type/%-5.5s/%s} ", pname, tname); sctp_process_tcb(xstcb, buf, buflen, offset, &indent); indent++; xstcb = (struct xsctp_tcb *)(buf + *offset); *offset += sizeof(struct xsctp_tcb); } xo_close_list("local-address"); } /* * Print a summary of SCTP connections related to an Internet * protocol. */ void sctp_protopr(u_long off __unused, const char *name __unused, int af1 __unused, int proto) { char *buf; const char *mibvar = "net.inet.sctp.assoclist"; size_t offset = 0; size_t len = 0; struct xsctp_inpcb *xinpcb; if (proto != IPPROTO_SCTP) return; if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) { if (errno != ENOENT) xo_warn("sysctl: %s", mibvar); return; } if ((buf = malloc(len)) == NULL) { xo_warnx("malloc %lu bytes", (u_long)len); return; } if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) { xo_warn("sysctl: %s", mibvar); free(buf); return; } xinpcb = (struct xsctp_inpcb *)(buf + offset); offset += sizeof(struct xsctp_inpcb); while (xinpcb->last == 0 && offset < len) { sctp_process_inpcb(xinpcb, buf, (const size_t)len, &offset); xinpcb = (struct xsctp_inpcb *)(buf + offset); offset += sizeof(struct xsctp_inpcb); } free(buf); } static void sctp_statesprint(uint32_t state) { int idx; switch (state) { case SCTP_CLOSED: idx = NETSTAT_SCTP_STATES_CLOSED; break; case SCTP_BOUND: idx = NETSTAT_SCTP_STATES_BOUND; break; case SCTP_LISTEN: idx = NETSTAT_SCTP_STATES_LISTEN; break; case SCTP_COOKIE_WAIT: idx = NETSTAT_SCTP_STATES_COOKIE_WAIT; break; case SCTP_COOKIE_ECHOED: idx = NETSTAT_SCTP_STATES_COOKIE_ECHOED; break; case SCTP_ESTABLISHED: idx = NETSTAT_SCTP_STATES_ESTABLISHED; break; case SCTP_SHUTDOWN_SENT: idx = NETSTAT_SCTP_STATES_SHUTDOWN_SENT; break; case SCTP_SHUTDOWN_RECEIVED: idx = NETSTAT_SCTP_STATES_SHUTDOWN_RECEIVED; break; case SCTP_SHUTDOWN_ACK_SENT: idx = NETSTAT_SCTP_STATES_SHUTDOWN_ACK_SENT; break; case SCTP_SHUTDOWN_PENDING: idx = NETSTAT_SCTP_STATES_SHUTDOWN_PENDING; break; default: xo_emit("UNKNOWN {:state/0x%08x}", state); return; } xo_emit("{:state/%s}", sctpstates[idx]); } /* * Dump SCTP statistics structure. */ void sctp_stats(u_long off, const char *name, int af1 __unused, int proto __unused) { struct sctpstat sctpstat; if (fetch_stats("net.inet.sctp.stats", off, &sctpstat, sizeof(sctpstat), kread) != 0) return; xo_open_container(name); xo_emit("{T:/%s}:\n", name); #define p(f, m) if (sctpstat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)sctpstat.f, plural(sctpstat.f)) #define p1a(f, m) if (sctpstat.f || sflag <= 1) \ xo_emit(m, (uintmax_t)sctpstat.f) /* * input statistics */ p(sctps_recvpackets, "\t{:received-packets/%ju} " "{N:/input packet%s}\n"); p(sctps_recvdatagrams, "\t\t{:received-datagrams/%ju} " "{N:/datagram%s}\n"); p(sctps_recvpktwithdata, "\t\t{:received-with-data/%ju} " "{N:/packet%s that had data}\n"); p(sctps_recvsacks, "\t\t{:received-sack-chunks/%ju} " "{N:/input SACK chunk%s}\n"); p(sctps_recvdata, "\t\t{:received-data-chunks/%ju} " "{N:/input DATA chunk%s}\n"); p(sctps_recvdupdata, "\t\t{:received-duplicate-data-chunks/%ju} " "{N:/duplicate DATA chunk%s}\n"); p(sctps_recvheartbeat, "\t\t{:received-hb-chunks/%ju} " "{N:/input HB chunk%s}\n"); p(sctps_recvheartbeatack, "\t\t{:received-hb-ack-chunks/%ju} " "{N:/HB-ACK chunk%s}\n"); p(sctps_recvecne, "\t\t{:received-ecne-chunks/%ju} " "{N:/input ECNE chunk%s}\n"); p(sctps_recvauth, "\t\t{:received-auth-chunks/%ju} " "{N:/input AUTH chunk%s}\n"); p(sctps_recvauthmissing, "\t\t{:dropped-missing-auth/%ju} " "{N:/chunk%s missing AUTH}\n"); p(sctps_recvivalhmacid, "\t\t{:dropped-invalid-hmac/%ju} " "{N:/invalid HMAC id%s received}\n"); p(sctps_recvivalkeyid, "\t\t{:dropped-invalid-secret/%ju} " "{N:/invalid secret id%s received}\n"); p1a(sctps_recvauthfailed, "\t\t{:dropped-auth-failed/%ju} " "{N:/auth failed}\n"); p1a(sctps_recvexpress, "\t\t{:received-fast-path/%ju} " "{N:/fast path receives all one chunk}\n"); p1a(sctps_recvexpressm, "\t\t{:receives-fast-path-multipart/%ju} " "{N:/fast path multi-part data}\n"); /* * output statistics */ p(sctps_sendpackets, "\t{:sent-packets/%ju} " "{N:/output packet%s}\n"); p(sctps_sendsacks, "\t\t{:sent-sacks/%ju} " "{N:/output SACK%s}\n"); p(sctps_senddata, "\t\t{:sent-data-chunks/%ju} " "{N:/output DATA chunk%s}\n"); p(sctps_sendretransdata, "\t\t{:sent-retransmitted-data-chunks/%ju} " "{N:/retransmitted DATA chunk%s}\n"); p(sctps_sendfastretrans, "\t\t" "{:sent-fast-retransmitted-data-chunks/%ju} " "{N:/fast retransmitted DATA chunk%s}\n"); p(sctps_sendmultfastretrans, "\t\t" "{:sent-fast-retransmitted-data-chunk-multiple-times/%ju} " "{N:/FR'%s that happened more than once to same chunk}\n"); p(sctps_sendheartbeat, "\t\t{:sent-hb-chunks/%ju} " "{N:/output HB chunk%s}\n"); p(sctps_sendecne, "\t\t{:sent-ecne-chunks/%ju} " "{N:/output ECNE chunk%s}\n"); p(sctps_sendauth, "\t\t{:sent-auth-chunks/%ju} " "{N:/output AUTH chunk%s}\n"); p1a(sctps_senderrors, "\t\t{:send-errors/%ju} " "{N:/ip_output error counter}\n"); /* * PCKDROPREP statistics */ xo_emit("\t{T:Packet drop statistics}:\n"); xo_open_container("drop-statistics"); p1a(sctps_pdrpfmbox, "\t\t{:middle-box/%ju} " "{N:/from middle box}\n"); p1a(sctps_pdrpfehos, "\t\t{:end-host/%ju} " "{N:/from end host}\n"); p1a(sctps_pdrpmbda, "\t\t{:with-data/%ju} " "{N:/with data}\n"); p1a(sctps_pdrpmbct, "\t\t{:non-data/%ju} " "{N:/non-data, non-endhost}\n"); p1a(sctps_pdrpbwrpt, "\t\t{:non-endhost/%ju} " "{N:/non-endhost, bandwidth rep only}\n"); p1a(sctps_pdrpcrupt, "\t\t{:short-header/%ju} " "{N:/not enough for chunk header}\n"); p1a(sctps_pdrpnedat, "\t\t{:short-data/%ju} " "{N:/not enough data to confirm}\n"); p1a(sctps_pdrppdbrk, "\t\t{:chunk-break/%ju} " "{N:/where process_chunk_drop said break}\n"); p1a(sctps_pdrptsnnf, "\t\t{:tsn-not-found/%ju} " "{N:/failed to find TSN}\n"); p1a(sctps_pdrpdnfnd, "\t\t{:reverse-tsn/%ju} " "{N:/attempt reverse TSN lookup}\n"); p1a(sctps_pdrpdiwnp, "\t\t{:confirmed-zero-window/%ju} " "{N:/e-host confirms zero-rwnd}\n"); p1a(sctps_pdrpdizrw, "\t\t{:middle-box-no-space/%ju} " "{N:/midbox confirms no space}\n"); p1a(sctps_pdrpbadd, "\t\t{:bad-data/%ju} " "{N:/data did not match TSN}\n"); p(sctps_pdrpmark, "\t\t{:tsn-marked-fast-retransmission/%ju} " "{N:/TSN'%s marked for Fast Retran}\n"); xo_close_container("drop-statistics"); /* * Timeouts */ xo_emit("\t{T:Timeouts}:\n"); xo_open_container("timeouts"); p(sctps_timoiterator, "\t\t{:iterator/%ju} " "{N:/iterator timer%s fired}\n"); p(sctps_timodata, "\t\t{:t3-data/%ju} " "{N:/T3 data time out%s}\n"); p(sctps_timowindowprobe, "\t\t{:window-probe/%ju} " "{N:/window probe (T3) timer%s fired}\n"); p(sctps_timoinit, "\t\t{:init-timer/%ju} " "{N:/INIT timer%s fired}\n"); p(sctps_timosack, "\t\t{:sack-timer/%ju} " "{N:/sack timer%s fired}\n"); p(sctps_timoshutdown, "\t\t{:shutdown-timer/%ju} " "{N:/shutdown timer%s fired}\n"); p(sctps_timoheartbeat, "\t\t{:heartbeat-timer/%ju} " "{N:/heartbeat timer%s fired}\n"); p1a(sctps_timocookie, "\t\t{:cookie-timer/%ju} " "{N:/a cookie timeout fired}\n"); p1a(sctps_timosecret, "\t\t{:endpoint-changed-cookie/%ju} " "{N:/an endpoint changed its cook}ie" "secret\n"); p(sctps_timopathmtu, "\t\t{:pmtu-timer/%ju} " "{N:/PMTU timer%s fired}\n"); p(sctps_timoshutdownack, "\t\t{:shutdown-timer/%ju} " "{N:/shutdown ack timer%s fired}\n"); p(sctps_timoshutdownguard, "\t\t{:shutdown-guard-timer/%ju} " "{N:/shutdown guard timer%s fired}\n"); p(sctps_timostrmrst, "\t\t{:stream-reset-timer/%ju} " "{N:/stream reset timer%s fired}\n"); p(sctps_timoearlyfr, "\t\t{:early-fast-retransmission-timer/%ju} " "{N:/early FR timer%s fired}\n"); p1a(sctps_timoasconf, "\t\t{:asconf-timer/%ju} " "{N:/an asconf timer fired}\n"); p1a(sctps_timoautoclose, "\t\t{:auto-close-timer/%ju} " "{N:/auto close timer fired}\n"); p(sctps_timoassockill, "\t\t{:asoc-free-timer/%ju} " "{N:/asoc free timer%s expired}\n"); p(sctps_timoinpkill, "\t\t{:input-free-timer/%ju} " "{N:/inp free timer%s expired}\n"); xo_close_container("timeouts"); #if 0 /* * Early fast retransmission counters */ p(sctps_earlyfrstart, "\t%ju TODO:sctps_earlyfrstart\n"); p(sctps_earlyfrstop, "\t%ju TODO:sctps_earlyfrstop\n"); p(sctps_earlyfrmrkretrans, "\t%ju TODO:sctps_earlyfrmrkretrans\n"); p(sctps_earlyfrstpout, "\t%ju TODO:sctps_earlyfrstpout\n"); p(sctps_earlyfrstpidsck1, "\t%ju TODO:sctps_earlyfrstpidsck1\n"); p(sctps_earlyfrstpidsck2, "\t%ju TODO:sctps_earlyfrstpidsck2\n"); p(sctps_earlyfrstpidsck3, "\t%ju TODO:sctps_earlyfrstpidsck3\n"); p(sctps_earlyfrstpidsck4, "\t%ju TODO:sctps_earlyfrstpidsck4\n"); p(sctps_earlyfrstrid, "\t%ju TODO:sctps_earlyfrstrid\n"); p(sctps_earlyfrstrout, "\t%ju TODO:sctps_earlyfrstrout\n"); p(sctps_earlyfrstrtmr, "\t%ju TODO:sctps_earlyfrstrtmr\n"); #endif /* * Others */ p1a(sctps_hdrops, "\t{:dropped-too-short/%ju} " "{N:/packet shorter than header}\n"); p1a(sctps_badsum, "\t{:dropped-bad-checksum/%ju} " "{N:/checksum error}\n"); p1a(sctps_noport, "\t{:dropped-no-endpoint/%ju} " "{N:/no endpoint for port}\n"); p1a(sctps_badvtag, "\t{:dropped-bad-v-tag/%ju} " "{N:/bad v-tag}\n"); p1a(sctps_badsid, "\t{:dropped-bad-sid/%ju} " "{N:/bad SID}\n"); p1a(sctps_nomem, "\t{:dropped-no-memory/%ju} " "{N:/no memory}\n"); p1a(sctps_fastretransinrtt, "\t{:multiple-fast-retransmits-in-rtt/%ju} " "{N:/number of multiple FR in a RT}T window\n"); #if 0 p(sctps_markedretrans, "\t%ju TODO:sctps_markedretrans\n"); #endif p1a(sctps_naglesent, "\t{:rfc813-sent/%ju} " "{N:/RFC813 allowed sending}\n"); p1a(sctps_naglequeued, "\t{:rfc813-queued/%ju} " "{N:/RFC813 does not allow sending}\n"); p1a(sctps_maxburstqueued, "\t{:max-burst-queued/%ju} " "{N:/times max burst prohibited sending}\n"); p1a(sctps_ifnomemqueued, "\t{:no-memory-in-interface/%ju} " "{N:/look ahead tells us no memory in interface}\n"); p(sctps_windowprobed, "\t{:sent-window-probes/%ju} " "{N:/number%s of window probes sent}\n"); p(sctps_lowlevelerr, "\t{:low-level-err/%ju} " "{N:/time%s an output error to clamp down on next user send}\n"); p(sctps_lowlevelerrusr, "\t{:low-level-user-error/%ju} " "{N:/time%s sctp_senderrors were caused from a user}\n"); p(sctps_datadropchklmt, "\t{:dropped-chunk-limit/%ju} " "{N:/number of in data drop%s due to chunk limit reached}\n"); p(sctps_datadroprwnd, "\t{:dropped-rwnd-limit/%ju} " "{N:/number of in data drop%s due to rwnd limit reached}\n"); p(sctps_ecnereducedcwnd, "\t{:ecn-reduced-cwnd/%ju} " "{N:/time%s a ECN reduced the cwnd}\n"); p1a(sctps_vtagexpress, "\t{:v-tag-express-lookup/%ju} " "{N:/used express lookup via vtag}\n"); p1a(sctps_vtagbogus, "\t{:v-tag-collision/%ju} " "{N:/collision in express lookup}\n"); p(sctps_primary_randry, "\t{:sender-ran-dry/%ju} " "{N:/time%s the sender ran dry of user data on primary}\n"); p1a(sctps_cmt_randry, "\t{:cmt-ran-dry/%ju} " "{N:/same for above}\n"); p(sctps_slowpath_sack, "\t{:slow-path-sack/%ju} " "{N:/sack%s the slow way}\n"); p(sctps_wu_sacks_sent, "\t{:sent-window-update-only-sack/%ju} " "{N:/window update only sack%s sent}\n"); p(sctps_sends_with_flags, "\t{:sent-with-sinfo/%ju} " "{N:/send%s with sinfo_flags !=0}\n"); p(sctps_sends_with_unord, "\t{:sent-with-unordered/%ju} " "{N:/unordered send%s}\n"); p(sctps_sends_with_eof, "\t{:sent-with-eof/%ju} " "{N:/send%s with EOF flag set}\n"); p(sctps_sends_with_abort, "\t{:sent-with-abort/%ju} " "{N:/send%s with ABORT flag set}\n"); p(sctps_protocol_drain_calls, "\t{:protocol-drain-called/%ju} " "{N:/time%s protocol drain called}\n"); p(sctps_protocol_drains_done, "\t{:protocol-drain/%ju} " "{N:/time%s we did a protocol drain}\n"); p(sctps_read_peeks, "\t{:read-with-peek/%ju} " "{N:/time%s recv was called with peek}\n"); p(sctps_cached_chk, "\t{:cached-chunks/%ju} " "{N:/cached chunk%s used}\n"); p1a(sctps_cached_strmoq, "\t{:cached-output-queue-used/%ju} " "{N:/cached stream oq's used}\n"); p(sctps_left_abandon, "\t{:messages-abandoned/%ju} " "{N:/unread message%s abandonded by close}\n"); p1a(sctps_send_burst_avoid, "\t{:send-burst-avoidance/%ju} " "{N:/send burst avoidance, already max burst inflight to net}\n"); p1a(sctps_send_cwnd_avoid, "\t{:send-cwnd-avoidance/%ju} " "{N:/send cwnd full avoidance, already max burst inflight " "to net}\n"); p(sctps_fwdtsn_map_over, "\t{:tsn-map-overruns/%ju} " "{N:/number of map array over-run%s via fwd-tsn's}\n"); #undef p #undef p1a xo_close_container(name); } #endif /* SCTP */ Index: head/usr.bin/netstat/unix.c =================================================================== --- head/usr.bin/netstat/unix.c (revision 311391) +++ head/usr.bin/netstat/unix.c (revision 311392) @@ -1,331 +1,331 @@ /*- * Copyright (c) 1983, 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static char sccsid[] = "@(#)unix.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); /* * Display protocol blocks in the unix domain. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "netstat.h" static void unixdomainpr(struct xunpcb *, struct xsocket *); static const char *const socktype[] = { "#0", "stream", "dgram", "raw", "rdm", "seqpacket" }; static int pcblist_sysctl(int type, char **bufp) { char *buf; size_t len; char mibvar[sizeof "net.local.seqpacket.pcblist"]; - sprintf(mibvar, "net.local.%s.pcblist", socktype[type]); + snprintf(mibvar, sizeof(mibvar), "net.local.%s.pcblist", socktype[type]); len = 0; if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) { if (errno != ENOENT) xo_warn("sysctl: %s", mibvar); return (-1); } if ((buf = malloc(len)) == NULL) { xo_warnx("malloc %lu bytes", (u_long)len); return (-2); } if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) { xo_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)) == NULL) { xo_warnx("malloc %lu bytes", (u_long)len); return (-2); } p = buf; #define COPYOUT(obj, size) do { \ if (len < (size)) { \ xo_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); /* 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 (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); } } 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, u_long sphead_off, bool *first) { char *buf; int ret, type; struct xsocket *so; struct xunpgen *xug, *oxug; struct xunpcb *xunp; u_long head_off; buf = NULL; for (type = SOCK_STREAM; type <= SOCK_SEQPACKET; type++) { if (live) ret = pcblist_sysctl(type, &buf); else { head_off = 0; switch (type) { case SOCK_STREAM: head_off = shead_off; break; case SOCK_DGRAM: head_off = dhead_off; break; case SOCK_SEQPACKET: head_off = sphead_off; break; } ret = pcblist_kvm(count_off, gencnt_off, head_off, &buf); } if (ret == -1) continue; if (ret < 0) return; oxug = xug = (struct xunpgen *)buf; for (xug = (struct xunpgen *)((char *)xug + xug->xug_len); xug->xug_len > sizeof(struct xunpgen); xug = (struct xunpgen *)((char *)xug + xug->xug_len)) { xunp = (struct xunpcb *)xug; so = &xunp->xu_socket; /* Ignore PCBs which were freed during copyout. */ if (xunp->xu_unp.unp_gencnt > oxug->xug_gen) continue; if (*first) { xo_open_list("socket"); *first = false; } xo_open_instance("socket"); unixdomainpr(xunp, so); xo_close_instance("socket"); } if (xug != oxug && xug->xug_gen != oxug->xug_gen) { if (oxug->xug_count > xug->xug_count) { xo_emit("Some {:type/%s} sockets may have " "been {:action/deleted}.\n", socktype[type]); } else if (oxug->xug_count < xug->xug_count) { xo_emit("Some {:type/%s} sockets may have " "been {:action/created}.\n", socktype[type]); } else { xo_emit("Some {:type/%s} sockets may have " "been {:action/created or deleted}", socktype[type]); } } free(buf); } } static void unixdomainpr(struct xunpcb *xunp, struct xsocket *so) { struct unpcb *unp; struct sockaddr_un *sa; static int first = 1; char buf1[33]; static const char *titles[2] = { "{T:/%-8.8s} {T:/%-6.6s} {T:/%-6.6s} {T:/%-6.6s} {T:/%8.8s} " "{T:/%8.8s} {T:/%8.8s} {T:/%8.8s} {T:Addr}\n", "{T:/%-16.16s} {T:/%-6.6s} {T:/%-6.6s} {T:/%-6.6s} {T:/%16.16s} " "{T:/%16.16s} {T:/%16.16s} {T:/%16.16s} {T:Addr}\n" }; static const char *format[2] = { "{q:address/%8lx} {t:type/%-6.6s} " "{:receive-bytes-waiting/%6u} " "{:send-bytes-waiting/%6u} " "{q:vnode/%8lx} {q:connection/%8lx} " "{q:first-reference/%8lx} {q:next-reference/%8lx}", "{q:address/%16lx} {t:type/%-6.6s} " "{:receive-bytes-waiting/%6u} " "{:send-bytes-waiting/%6u} " "{q:vnode/%16lx} {q:connection/%16lx} " "{q:first-reference/%16lx} {q:next-reference/%16lx}" }; int fmt = (sizeof(void *) == 8) ? 1 : 0; unp = &xunp->xu_unp; if (unp->unp_addr) sa = &xunp->xu_addr; else sa = (struct sockaddr_un *)0; if (first && !Lflag) { xo_emit("{T:Active UNIX domain sockets}\n"); xo_emit(titles[fmt], "Address", "Type", "Recv-Q", "Send-Q", "Inode", "Conn", "Refs", "Nextref"); first = 0; } if (Lflag && so->so_qlimit == 0) return; if (Lflag) { snprintf(buf1, sizeof buf1, "%u/%u/%u", so->so_qlen, so->so_incqlen, so->so_qlimit); xo_emit("unix {d:socket/%-32.32s}{e:queue-length/%u}" "{e:incomplete-queue-length/%u}{e:queue-limit/%u}", buf1, so->so_qlen, so->so_incqlen, so->so_qlimit); } else { xo_emit(format[fmt], (long)so->so_pcb, socktype[so->so_type], so->so_rcv.sb_cc, so->so_snd.sb_cc, (long)unp->unp_vnode, (long)unp->unp_conn, (long)LIST_FIRST(&unp->unp_refs), (long)LIST_NEXT(unp, unp_reflink)); } if (sa) xo_emit(" {:path/%.*s}", (int)(sa->sun_len - offsetof(struct sockaddr_un, sun_path)), sa->sun_path); xo_emit("\n"); }