bin/164081: sockstat not reporting all open sockets

Jilles Tjoelker jilles at stack.nl
Sun Jan 22 22:10:12 UTC 2012


The following reply was made to PR bin/164081; it has been noted by GNATS.

From: Jilles Tjoelker <jilles at stack.nl>
To: Jim Pirzyk <pirzyk at FreeBSD.org>, des at FreeBSD.org
Cc: bug-followup at 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 at 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


More information about the freebsd-bugs mailing list