From owner-freebsd-bugs@FreeBSD.ORG Sun Jan 22 22:10:11 2012 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id F17DE106564A for ; Sun, 22 Jan 2012 22:10:11 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id DC3508FC08 for ; Sun, 22 Jan 2012 22:10:11 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.5/8.14.5) with ESMTP id q0MMABZL027858 for ; Sun, 22 Jan 2012 22:10:11 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.5/8.14.5/Submit) id q0MMABeD027857; Sun, 22 Jan 2012 22:10:11 GMT (envelope-from gnats) Date: Sun, 22 Jan 2012 22:10:11 GMT Message-Id: <201201222210.q0MMABeD027857@freefall.freebsd.org> To: freebsd-bugs@FreeBSD.org From: Jilles Tjoelker Cc: Subject: Re: bin/164081: sockstat not reporting all open sockets X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Jilles Tjoelker List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 22 Jan 2012 22:10:12 -0000 The following reply was made to PR bin/164081; it has been noted by GNATS. From: Jilles Tjoelker To: Jim Pirzyk , des@FreeBSD.org Cc: bug-followup@FreeBSD.org Subject: Re: bin/164081: sockstat not reporting all open sockets Date: Sun, 22 Jan 2012 23:01:30 +0100 On Tue, Jan 17, 2012 at 08:13:59AM -0500, Jim Pirzyk wrote: > On Jan 13, 2012, at 7:03 PM, Jilles Tjoelker wrote: > >> [netstat reports sockets that sockstat does not] > > The sockstat utility checks all file descriptors open by all processes > > looking for sockets, while netstat shows all kernel-level sockets. This > > may mismatch in many ways: a process may have closed its descriptor but > > TCP still needs to maintain some state like TIME_WAIT (as mentioned in > > the sockstat(1) man page), multiple descriptors may exist for a single > > socket and kernel code (like nlockmgr) may use the socket(9) API > > directly so there is no descriptor. However, any socket file descriptor > > shown by sockstat must correspond to a kernel-level socket shown by > > netstat. > > This does appear to be intended, although it is surprising and not > > documented very well. > So maybe in light of that, we should change this ticket to update the > man page to document this case too? I looked in the code and tried to make sockstat show sockets that are not associated with any open file. This turned out to be fairly easy. I have tested this on 10-current and 8-stable. On 8-stable there will be a conflict in sockstat.1 which can safely be ignored (it is because r200779 was not MFCed). On a machine that runs UDP nfsd it adds at least two lines to the output: ? ? ? ? udp6 *:2049 *:* ? ? ? ? udp4 *:2049 *:* DES, what do you think of this? Index: usr.bin/sockstat/sockstat.1 =================================================================== --- usr.bin/sockstat/sockstat.1 (revision 230388) +++ usr.bin/sockstat/sockstat.1 (working copy) @@ -136,20 +136,6 @@ The address the foreign end of the socket is bound to (see .Xr getpeername 2 ) . .El -.Pp -Note that TCP sockets in the -.Dv AF_INET -or -.Dv AF_INET6 -domains that are not in one of the -.Dv LISTEN , SYN_SENT , -or -.Dv ESTABLISHED -states may not be shown by -.Nm ; -use -.Xr netstat 1 -to examine them instead. .Sh SEE ALSO .Xr fstat 1 , .Xr netstat 1 , @@ -167,10 +153,3 @@ .Nm command and this manual page were written by .An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org . -.Sh BUGS -Unlike -.Xr netstat 1 , -.Nm -lists sockets by walking file descriptor tables and will not output -the ones owned by the kernel, e.g. NLM sockets created by -.Xr rpc.lockd 8 . Index: usr.bin/sockstat/sockstat.c =================================================================== --- usr.bin/sockstat/sockstat.c (revision 230388) +++ usr.bin/sockstat/sockstat.c (working copy) @@ -86,6 +86,7 @@ struct sock { void *socket; void *pcb; + int shown; int vflag; int family; int proto; @@ -571,12 +572,67 @@ } static void +displaysock(struct sock *s, int pos) +{ + void *p; + int hash; + + while (pos < 29) + pos += xprintf(" "); + pos += xprintf("%s", s->protoname); + if (s->vflag & INP_IPV4) + 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) + 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); + break; + } + /* client */ + p = *(void **)&s->faddr; + 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.ss_len == 0) + pos += xprintf("??"); + else + pos += printaddr(s->family, &s->laddr); + break; + default: + abort(); + } + xprintf("\n"); +} + +static void display(void) { struct passwd *pwd; struct xfile *xf; struct sock *s; - void *p; int hash, n, pos; printf("%-8s %-10s %-5s %-2s %-6s %-21s %-21s\n", @@ -594,6 +650,7 @@ 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); @@ -608,54 +665,19 @@ while (pos < 26) pos += xprintf(" "); pos += xprintf("%d ", xf->xf_fd); - while (pos < 29) - pos += xprintf(" "); - pos += xprintf("%s", s->protoname); - if (s->vflag & INP_IPV4) - 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) - 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); - break; - } - /* client */ - p = *(void **)&s->faddr; - 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.ss_len == 0) - pos += xprintf("??"); - else - pos += printaddr(s->family, &s->laddr); - break; - default: - abort(); + displaysock(s, pos); + } + for (hash = 0; hash < HASHSIZE; hash++) { + for (s = sockhash[hash]; s != NULL; s = s->next) { + if (s->shown) + continue; + if (!check_ports(s)) + continue; + pos = 0; + pos += xprintf("%-8s %-10s %-5s %-2s ", + "?", "?", "?", "?"); + displaysock(s, pos); } - xprintf("\n"); } } -- Jilles Tjoelker