From owner-svn-src-all@FreeBSD.ORG Tue Jun 16 08:36:59 2015 Return-Path: Delivered-To: svn-src-all@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id F326930E; Tue, 16 Jun 2015 08:36:58 +0000 (UTC) (envelope-from tuexen@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id DFEA692C; Tue, 16 Jun 2015 08:36:58 +0000 (UTC) (envelope-from tuexen@FreeBSD.org) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t5G8aw4C026359; Tue, 16 Jun 2015 08:36:58 GMT (envelope-from tuexen@FreeBSD.org) Received: (from tuexen@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t5G8awLj026357; Tue, 16 Jun 2015 08:36:58 GMT (envelope-from tuexen@FreeBSD.org) Message-Id: <201506160836.t5G8awLj026357@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: tuexen set sender to tuexen@FreeBSD.org using -f From: Michael Tuexen Date: Tue, 16 Jun 2015 08:36:58 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r284441 - stable/10/usr.bin/sockstat X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 16 Jun 2015 08:36:59 -0000 Author: tuexen Date: Tue Jun 16 08:36:57 2015 New Revision: 284441 URL: https://svnweb.freebsd.org/changeset/base/284441 Log: MFC r284351: Simplify printaddr(). No functional change. MFC r284352: Allow more than one socket entry for a file descriptor. This is needed for supporting 1-to-many style SCTP sockets. For other sochets, there is no functional change. MFC r284353: Allow more than one local or remote address per socket. This is needed to support SCTP (and MPTCP in the future). No functional change for existing protocols. MFC r284354: Add support for SCTP. MFC r284355: When using -L the code skips a socket if the local or foreign address is loopback. So it is shown if both are not loopback. The man page says that it is shown if the local or foreign address is not loopback. Change the man page to reflect the code. Modified: stable/10/usr.bin/sockstat/sockstat.1 stable/10/usr.bin/sockstat/sockstat.c Directory Properties: stable/10/ (props changed) Modified: stable/10/usr.bin/sockstat/sockstat.1 ============================================================================== --- stable/10/usr.bin/sockstat/sockstat.1 Tue Jun 16 08:26:33 2015 (r284440) +++ stable/10/usr.bin/sockstat/sockstat.1 Tue Jun 16 08:36:57 2015 (r284441) @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd April 7, 2015 +.Dd June 13, 2015 .Dt SOCKSTAT 1 .Os .Sh NAME @@ -61,7 +61,7 @@ Show connected sockets. .It Fl j Ar jid Show only sockets belonging to the specified jail ID. .It Fl L -Only show Internet sockets if the local or foreign addresses are not +Only show Internet sockets if the local and foreign addresses are not in the loopback network prefix .Li 127.0.0.0/8 , or do not contain the IPv6 loopback address Modified: stable/10/usr.bin/sockstat/sockstat.c ============================================================================== --- stable/10/usr.bin/sockstat/sockstat.c Tue Jun 16 08:26:33 2015 (r284440) +++ stable/10/usr.bin/sockstat/sockstat.c Tue Jun 16 08:36:57 2015 (r284441) @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -71,7 +72,7 @@ static int opt_v; /* Verbose mode */ /* * Default protocols to use if no -P was defined. */ -static const char *default_protos[] = {"tcp", "udp", "divert" }; +static const char *default_protos[] = {"sctp", "tcp", "udp", "divert" }; static size_t default_numprotos = sizeof(default_protos) / sizeof(default_protos[0]); @@ -84,6 +85,11 @@ static int *ports; #define SET_PORT(p) do { ports[p / INT_BIT] |= 1 << (p % INT_BIT); } while (0) #define CHK_PORT(p) (ports[p / INT_BIT] & (1 << (p % INT_BIT))) +struct addr { + struct sockaddr_storage address; + struct addr *next; +}; + struct sock { void *socket; void *pcb; @@ -92,8 +98,8 @@ struct sock { int family; int proto; const char *protoname; - struct sockaddr_storage laddr; - struct sockaddr_storage faddr; + struct addr *laddr; + struct addr *faddr; struct sock *next; }; @@ -249,6 +255,241 @@ sockaddr(struct sockaddr_storage *sa, in } static void +gather_sctp(void) +{ + struct sock *sock; + struct addr *laddr, *prev_laddr, *faddr, *prev_faddr; + struct xsctp_inpcb *xinpcb; + struct xsctp_tcb *xstcb; + struct xsctp_raddr *xraddr; + struct xsctp_laddr *xladdr; + const char *varname; + size_t len, offset; + char *buf; + int hash, vflag; + int no_stcb, local_all_loopback, foreign_all_loopback; + + vflag = 0; + if (opt_4) + vflag |= INP_IPV4; + if (opt_6) + vflag |= INP_IPV6; + + varname = "net.inet.sctp.assoclist"; + if (sysctlbyname(varname, 0, &len, 0, 0) < 0) { + if (errno != ENOENT) + err(1, "sysctlbyname()"); + return; + } + if ((buf = (char *)malloc(len)) == NULL) { + err(1, "malloc()"); + return; + } + if (sysctlbyname(varname, buf, &len, 0, 0) < 0) { + err(1, "sysctlbyname()"); + free(buf); + return; + } + xinpcb = (struct xsctp_inpcb *)(void *)buf; + offset = sizeof(struct xsctp_inpcb); + while ((offset < len) && (xinpcb->last == 0)) { + if ((sock = calloc(1, sizeof *sock)) == NULL) + err(1, "malloc()"); + sock->socket = xinpcb->socket; + sock->proto = IPPROTO_SCTP; + sock->protoname = "sctp"; + if (xinpcb->flags & SCTP_PCB_FLAGS_BOUND_V6) { + sock->family = AF_INET6; + sock->vflag = INP_IPV6; + } else { + sock->family = AF_INET; + sock->vflag = INP_IPV4; + } + prev_laddr = NULL; + local_all_loopback = 1; + while (offset < len) { + xladdr = (struct xsctp_laddr *)(void *)(buf + offset); + offset += sizeof(struct xsctp_laddr); + if (xladdr->last == 1) + break; + if ((laddr = calloc(1, sizeof(struct addr))) == NULL) + err(1, "malloc()"); + switch (xladdr->address.sa.sa_family) { + case AF_INET: +#define __IN_IS_ADDR_LOOPBACK(pina) \ + ((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) + if (!__IN_IS_ADDR_LOOPBACK(&xladdr->address.sin.sin_addr)) + local_all_loopback = 0; +#undef __IN_IS_ADDR_LOOPBACK + sockaddr(&laddr->address, + AF_INET, + &xladdr->address.sin.sin_addr, + htons(xinpcb->local_port)); + break; + case AF_INET6: + if (!IN6_IS_ADDR_LOOPBACK(&xladdr->address.sin6.sin6_addr)) + local_all_loopback = 0; + sockaddr(&laddr->address, + AF_INET6, + &xladdr->address.sin6.sin6_addr, + htons(xinpcb->local_port)); + break; + default: + errx(1, "adress family %d not supported", + xladdr->address.sa.sa_family); + } + laddr->next = NULL; + if (prev_laddr == NULL) + sock->laddr = laddr; + else + prev_laddr->next = laddr; + prev_laddr = laddr; + } + if (sock->laddr == NULL) { + if ((sock->laddr = calloc(1, sizeof(struct addr))) == NULL) + err(1, "malloc()"); + sock->laddr->address.ss_family = sock->family; + if (sock->family == AF_INET) + sock->laddr->address.ss_len = sizeof(struct sockaddr_in); + else + sock->laddr->address.ss_len = sizeof(struct sockaddr_in); + local_all_loopback = 0; + } + if ((sock->faddr = calloc(1, sizeof(struct addr))) == NULL) + err(1, "malloc()"); + sock->faddr->address.ss_family = sock->family; + if (sock->family == AF_INET) + sock->faddr->address.ss_len = sizeof(struct sockaddr_in); + else + sock->faddr->address.ss_len = sizeof(struct sockaddr_in); + no_stcb = 1; + while (offset < len) { + xstcb = (struct xsctp_tcb *)(void *)(buf + offset); + offset += sizeof(struct xsctp_tcb); + if (no_stcb && + opt_l && + (!opt_L || !local_all_loopback) && + ((xinpcb->flags & SCTP_PCB_FLAGS_UDPTYPE) || + (xstcb->last == 1))) { + hash = (int)((uintptr_t)sock->socket % HASHSIZE); + sock->next = sockhash[hash]; + sockhash[hash] = sock; + } + if (xstcb->last == 1) + break; + no_stcb = 0; + if (opt_c) { + if ((sock = calloc(1, sizeof *sock)) == NULL) + err(1, "malloc()"); + sock->socket = xinpcb->socket; + sock->proto = IPPROTO_SCTP; + sock->protoname = "sctp"; + if (xinpcb->flags & SCTP_PCB_FLAGS_BOUND_V6) { + sock->family = AF_INET6; + sock->vflag = INP_IPV6; + } else { + sock->family = AF_INET; + sock->vflag = INP_IPV4; + } + } + prev_laddr = NULL; + local_all_loopback = 1; + while (offset < len) { + xladdr = (struct xsctp_laddr *)(void *)(buf + offset); + offset += sizeof(struct xsctp_laddr); + if (xladdr->last == 1) + break; + if (!opt_c) + continue; + if ((laddr = calloc(1, sizeof(struct addr))) == NULL) + err(1, "malloc()"); + switch (xladdr->address.sa.sa_family) { + case AF_INET: +#define __IN_IS_ADDR_LOOPBACK(pina) \ + ((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) + if (!__IN_IS_ADDR_LOOPBACK(&xladdr->address.sin.sin_addr)) + local_all_loopback = 0; +#undef __IN_IS_ADDR_LOOPBACK + sockaddr(&laddr->address, + AF_INET, + &xladdr->address.sin.sin_addr, + htons(xstcb->local_port)); + break; + case AF_INET6: + if (!IN6_IS_ADDR_LOOPBACK(&xladdr->address.sin6.sin6_addr)) + local_all_loopback = 0; + sockaddr(&laddr->address, + AF_INET6, + &xladdr->address.sin6.sin6_addr, + htons(xstcb->local_port)); + break; + default: + errx(1, "adress family %d not supported", + xladdr->address.sa.sa_family); + } + laddr->next = NULL; + if (prev_laddr == NULL) + sock->laddr = laddr; + else + prev_laddr->next = laddr; + prev_laddr = laddr; + } + prev_faddr = NULL; + foreign_all_loopback = 1; + while (offset < len) { + xraddr = (struct xsctp_raddr *)(void *)(buf + offset); + offset += sizeof(struct xsctp_raddr); + if (xraddr->last == 1) + break; + if (!opt_c) + continue; + if ((faddr = calloc(1, sizeof(struct addr))) == NULL) + err(1, "malloc()"); + switch (xraddr->address.sa.sa_family) { + case AF_INET: +#define __IN_IS_ADDR_LOOPBACK(pina) \ + ((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) + if (!__IN_IS_ADDR_LOOPBACK(&xraddr->address.sin.sin_addr)) + foreign_all_loopback = 0; +#undef __IN_IS_ADDR_LOOPBACK + sockaddr(&faddr->address, + AF_INET, + &xraddr->address.sin.sin_addr, + htons(xstcb->remote_port)); + break; + case AF_INET6: + if (!IN6_IS_ADDR_LOOPBACK(&xraddr->address.sin6.sin6_addr)) + foreign_all_loopback = 0; + sockaddr(&faddr->address, + AF_INET6, + &xraddr->address.sin6.sin6_addr, + htons(xstcb->remote_port)); + break; + default: + errx(1, "adress family %d not supported", + xraddr->address.sa.sa_family); + } + faddr->next = NULL; + if (prev_faddr == NULL) + sock->faddr = faddr; + else + prev_faddr->next = faddr; + prev_faddr = faddr; + } + if (opt_c && + (!opt_L || !(local_all_loopback || foreign_all_loopback))) { + hash = (int)((uintptr_t)sock->socket % HASHSIZE); + sock->next = sockhash[hash]; + sockhash[hash] = sock; + } + } + xinpcb = (struct xsctp_inpcb *)(void *)(buf + offset); + offset += sizeof(struct xsctp_inpcb); + } + free(buf); +} + +static void gather_inet(int proto) { struct xinpgen *xig, *exig; @@ -257,6 +498,7 @@ gather_inet(int proto) struct inpcb *inp; struct xsocket *so; struct sock *sock; + struct addr *laddr, *faddr; const char *varname, *protoname; size_t len, bufsize; void *buf; @@ -368,21 +610,29 @@ gather_inet(int proto) } if ((sock = calloc(1, sizeof *sock)) == NULL) err(1, "malloc()"); + if ((laddr = calloc(1, sizeof *laddr)) == NULL) + err(1, "malloc()"); + if ((faddr = calloc(1, sizeof *faddr)) == NULL) + err(1, "malloc()"); sock->socket = so->xso_so; sock->proto = proto; if (inp->inp_vflag & INP_IPV4) { sock->family = AF_INET; - sockaddr(&sock->laddr, sock->family, + sockaddr(&laddr->address, sock->family, &inp->inp_laddr, inp->inp_lport); - sockaddr(&sock->faddr, sock->family, + sockaddr(&faddr->address, sock->family, &inp->inp_faddr, inp->inp_fport); } else if (inp->inp_vflag & INP_IPV6) { sock->family = AF_INET6; - sockaddr(&sock->laddr, sock->family, + sockaddr(&laddr->address, sock->family, &inp->in6p_laddr, inp->inp_lport); - sockaddr(&sock->faddr, sock->family, + sockaddr(&faddr->address, sock->family, &inp->in6p_faddr, inp->inp_fport); } + laddr->next = NULL; + faddr->next = NULL; + sock->laddr = laddr; + sock->faddr = faddr; sock->vflag = inp->inp_vflag; sock->protoname = protoname; hash = (int)((uintptr_t)sock->socket % HASHSIZE); @@ -399,6 +649,7 @@ gather_unix(int proto) struct xunpgen *xug, *exug; struct xunpcb *xup; struct sock *sock; + struct addr *laddr, *faddr; const char *varname, *protoname; size_t len, bufsize; void *buf; @@ -457,16 +708,24 @@ gather_unix(int proto) continue; if ((sock = calloc(1, sizeof *sock)) == NULL) err(1, "malloc()"); + if ((laddr = calloc(1, sizeof *laddr)) == NULL) + err(1, "malloc()"); + if ((faddr = calloc(1, sizeof *faddr)) == NULL) + err(1, "malloc()"); sock->socket = xup->xu_socket.xso_so; sock->pcb = xup->xu_unpp; sock->proto = proto; sock->family = AF_UNIX; sock->protoname = protoname; if (xup->xu_unp.unp_addr != NULL) - sock->laddr = + laddr->address = *(struct sockaddr_storage *)(void *)&xup->xu_addr; else if (xup->xu_unp.unp_conn != NULL) - *(void **)&sock->faddr = xup->xu_unp.unp_conn; + *(void **)&(faddr->address) = xup->xu_unp.unp_conn; + laddr->next = NULL; + faddr->next = NULL; + sock->laddr = laddr; + sock->faddr = faddr; hash = (int)((uintptr_t)sock->socket % HASHSIZE); sock->next = sockhash[hash]; sockhash[hash] = sock; @@ -496,14 +755,14 @@ getfiles(void) } static int -printaddr(int af, struct sockaddr_storage *ss) +printaddr(struct sockaddr_storage *ss) { char addrstr[INET6_ADDRSTRLEN] = { '\0', '\0' }; struct sockaddr_un *sun; void *addr = NULL; /* Keep compiler happy. */ int off, port = 0; - switch (af) { + switch (ss->ss_family) { case AF_INET: addr = &((struct sockaddr_in *)ss)->sin_addr; if (inet_lnaof(*(struct in_addr *)addr) == INADDR_ANY) @@ -522,7 +781,7 @@ printaddr(int af, struct sockaddr_storag return (xprintf("%.*s", sun->sun_len - off, sun->sun_path)); } if (addrstr[0] == '\0') - inet_ntop(af, addr, addrstr, sizeof addrstr); + inet_ntop(ss->ss_family, addr, addrstr, sizeof addrstr); if (port == 0) return xprintf("%s:*", addrstr); else @@ -575,23 +834,28 @@ static int check_ports(struct sock *s) { int port; + struct addr *addr; if (ports == NULL) return (1); if ((s->family != AF_INET) && (s->family != AF_INET6)) return (1); - if (s->family == AF_INET) - port = ntohs(((struct sockaddr_in *)(&s->laddr))->sin_port); - else - port = ntohs(((struct sockaddr_in6 *)(&s->laddr))->sin6_port); - if (CHK_PORT(port)) - return (1); - if (s->family == AF_INET) - port = ntohs(((struct sockaddr_in *)(&s->faddr))->sin_port); - else - port = ntohs(((struct sockaddr_in6 *)(&s->faddr))->sin6_port); - if (CHK_PORT(port)) - return (1); + for (addr = s->laddr; addr != NULL; addr = addr->next) { + if (addr->address.ss_family == AF_INET) + port = ntohs(((struct sockaddr_in *)(&addr->address))->sin_port); + else + port = ntohs(((struct sockaddr_in6 *)(&addr->address))->sin6_port); + if (CHK_PORT(port)) + return (1); + } + for (addr = s->faddr; addr != NULL; addr = addr->next) { + if (addr->address.ss_family == AF_INET) + port = ntohs(((struct sockaddr_in *)&(addr->address))->sin_port); + else + port = ntohs(((struct sockaddr_in6 *)&(addr->address))->sin6_port); + if (CHK_PORT(port)) + return (1); + } return (0); } @@ -600,6 +864,7 @@ displaysock(struct sock *s, int pos) { void *p; int hash; + struct addr *laddr, *faddr; while (pos < 29) pos += xprintf(" "); @@ -608,45 +873,65 @@ displaysock(struct sock *s, int pos) pos += xprintf("4 "); if (s->vflag & INP_IPV6) pos += xprintf("6 "); - while (pos < 36) - pos += xprintf(" "); - switch (s->family) { - case AF_INET: - case AF_INET6: - pos += printaddr(s->family, &s->laddr); - if (s->family == AF_INET6 && pos >= 58) + laddr = s->laddr; + faddr = s->faddr; + while (laddr != NULL || faddr != NULL) { + while (pos < 36) pos += xprintf(" "); - while (pos < 58) - pos += xprintf(" "); - pos += printaddr(s->family, &s->faddr); - break; - case AF_UNIX: - /* server */ - if (s->laddr.ss_len > 0) { - pos += printaddr(s->family, &s->laddr); + switch (s->family) { + case AF_INET: + case AF_INET6: + if (laddr != NULL) { + pos += printaddr(&laddr->address); + if (s->family == AF_INET6 && pos >= 58) + pos += xprintf(" "); + } + while (pos < 58) + pos += xprintf(" "); + if (faddr != NULL) + pos += printaddr(&faddr->address); break; - } - /* client */ - p = *(void **)&s->faddr; - if (p == NULL) { - pos += xprintf("(not connected)"); + case AF_UNIX: + if ((laddr == NULL) || (faddr == NULL)) + errx(1, "laddr = %p or faddr = %p is NULL", + (void *)laddr, (void *)faddr); + /* server */ + if (laddr->address.ss_len > 0) { + pos += printaddr(&laddr->address); + break; + } + /* client */ + p = *(void **)&(faddr->address); + if (p == NULL) { + pos += xprintf("(not connected)"); + break; + } + pos += xprintf("-> "); + for (hash = 0; hash < HASHSIZE; ++hash) { + for (s = sockhash[hash]; s != NULL; s = s->next) + if (s->pcb == p) + break; + if (s != NULL) + break; + } + if (s == NULL || + s->laddr == NULL || + s->laddr->address.ss_len == 0) + pos += xprintf("??"); + else + pos += printaddr(&s->laddr->address); break; + default: + abort(); } - pos += xprintf("-> "); - for (hash = 0; hash < HASHSIZE; ++hash) { - for (s = sockhash[hash]; s != NULL; s = s->next) - if (s->pcb == p) - break; - if (s != NULL) - break; + if (laddr != NULL) + laddr = laddr->next; + if (faddr != NULL) + faddr = faddr->next; + if ((laddr != NULL) || (faddr != NULL)) { + xprintf("\n"); + pos = 0; } - if (s == NULL || s->laddr.ss_len == 0) - pos += xprintf("??"); - else - pos += printaddr(s->family, &s->laddr); - break; - default: - abort(); } xprintf("\n"); } @@ -669,29 +954,28 @@ display(void) if (opt_j >= 0 && opt_j != getprocjid(xf->xf_pid)) continue; hash = (int)((uintptr_t)xf->xf_data % HASHSIZE); - for (s = sockhash[hash]; s != NULL; s = s->next) - if ((void *)s->socket == xf->xf_data) - break; - if (s == NULL) - continue; - if (!check_ports(s)) - continue; - s->shown = 1; - pos = 0; - if ((pwd = getpwuid(xf->xf_uid)) == NULL) - pos += xprintf("%lu ", (u_long)xf->xf_uid); - else - pos += xprintf("%s ", pwd->pw_name); - while (pos < 9) - pos += xprintf(" "); - pos += xprintf("%.10s", getprocname(xf->xf_pid)); - while (pos < 20) - pos += xprintf(" "); - pos += xprintf("%lu ", (u_long)xf->xf_pid); - while (pos < 26) - pos += xprintf(" "); - pos += xprintf("%d ", xf->xf_fd); - displaysock(s, pos); + for (s = sockhash[hash]; s != NULL; s = s->next) { + if ((void *)s->socket != xf->xf_data) + continue; + if (!check_ports(s)) + continue; + s->shown = 1; + pos = 0; + if ((pwd = getpwuid(xf->xf_uid)) == NULL) + pos += xprintf("%lu ", (u_long)xf->xf_uid); + else + pos += xprintf("%s ", pwd->pw_name); + while (pos < 9) + pos += xprintf(" "); + pos += xprintf("%.10s", getprocname(xf->xf_pid)); + while (pos < 20) + pos += xprintf(" "); + pos += xprintf("%lu ", (u_long)xf->xf_pid); + while (pos < 26) + pos += xprintf(" "); + pos += xprintf("%d ", xf->xf_fd); + displaysock(s, pos); + } } if (opt_j >= 0) return; @@ -797,7 +1081,10 @@ main(int argc, char *argv[]) if (opt_4 || opt_6) { for (i = 0; i < protos_defined; i++) - gather_inet(protos[i]); + if (protos[i] == IPPROTO_SCTP) + gather_sctp(); + else + gather_inet(protos[i]); } if (opt_u || (protos_defined == -1 && !opt_4 && !opt_6)) {