From tataz@tataz.chchile.org  Tue Sep 25 23:13:20 2007
Return-Path: <tataz@tataz.chchile.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 9B34516A419
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 25 Sep 2007 23:13:20 +0000 (UTC)
	(envelope-from tataz@tataz.chchile.org)
Received: from smtp5-g19.free.fr (smtp5-g19.free.fr [212.27.42.35])
	by mx1.freebsd.org (Postfix) with ESMTP id 1EC2913C455
	for <FreeBSD-gnats-submit@freebsd.org>; Tue, 25 Sep 2007 23:13:19 +0000 (UTC)
	(envelope-from tataz@tataz.chchile.org)
Received: from smtp5-g19.free.fr (localhost.localdomain [127.0.0.1])
	by smtp5-g19.free.fr (Postfix) with ESMTP id 76C5287BAE
	for <FreeBSD-gnats-submit@freebsd.org>; Wed, 26 Sep 2007 01:13:18 +0200 (CEST)
Received: from tatooine.tataz.chchile.org (tataz.chchile.org [82.233.239.98])
	by smtp5-g19.free.fr (Postfix) with ESMTP id 4A177878B9
	for <FreeBSD-gnats-submit@freebsd.org>; Wed, 26 Sep 2007 01:13:18 +0200 (CEST)
Received: from obiwan.tataz.chchile.org (unknown [192.168.1.25])
	by tatooine.tataz.chchile.org (Postfix) with ESMTP id C277C9B497;
	Tue, 25 Sep 2007 23:11:36 +0000 (UTC)
Received: by obiwan.tataz.chchile.org (Postfix, from userid 1000)
	id B6515405B; Wed, 26 Sep 2007 01:11:36 +0200 (CEST)
Message-Id: <20070925231136.B6515405B@obiwan.tataz.chchile.org>
Date: Wed, 26 Sep 2007 01:11:36 +0200 (CEST)
From: Jeremie Le Hen <jeremie@le-hen.org>
Reply-To: Jeremie Le Hen <jeremie@le-hen.org>
To: FreeBSD-gnats-submit@freebsd.org
Cc: Jeremie Le Hen <jeremie@le-hen.org>
Subject: [patch] fstat: add INET/INET6 socket details as in NetBSD and OpenBSD
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         116643
>Category:       bin
>Synopsis:       [patch] [request] fstat(1): add INET/INET6 socket details as in NetBSD and OpenBSD
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-net
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Tue Sep 25 23:20:01 GMT 2007
>Closed-Date:    
>Last-Modified:  Wed May  5 16:50:00 UTC 2010
>Originator:     Jeremie Le Hen <jeremie@le-hen.org>
>Release:        FreeBSD 7.0-CURRENT i386
>Organization:
>Environment:
FreeBSD 7.0-CURRENT

>Description:
This patch adds socket details to AF_INET/AF_INET6 output of fstat.
Currently, we have an output like this:
    root     sshd         721    3* internet stream tcp c3f08e10
    tataz    ssh         1271    3* internet stream tcp c4611870
With this patch, we have:
    root     sshd         721    3* internet stream tcp c3f08e10 *:22
    tataz    ssh         1271    3* internet stream tcp c4611870 192.168.1.3:50995 <-> 192.168.1.2:22
>How-To-Repeat:
>Fix:
The patch below implements this behaviour.  It has been ported from
NetBSD and OpenBSD.  Note that due to lack of inet6 connectivity, I
couldn't test the AF_INET6 case.

--- fstat_inetsock_detail.diff begins here ---
Index: fstat.c
===================================================================
RCS file: /mnt/octobre/space/freebsd-cvs/src/usr.bin/fstat/fstat.c,v
retrieving revision 1.64
diff -u -p -r1.64 fstat.c
--- fstat.c	9 Mar 2007 16:21:40 -0000	1.64
+++ fstat.c	25 Sep 2007 23:04:31 -0000
@@ -86,6 +86,8 @@ __FBSDID("$FreeBSD: src/usr.bin/fstat/fs
 #include <netinet/ip.h>
 #include <netinet/in_pcb.h>
 
+#include <arpa/inet.h>
+
 #include <ctype.h>
 #include <err.h>
 #include <fcntl.h>
@@ -151,6 +153,7 @@ int  nfs_filestat(struct vnode *vp, stru
 int  devfs_filestat(struct vnode *vp, struct filestat *fsp);
 char *getmnton(struct mount *m);
 void pipetrans(struct pipe *pi, int i, int flag);
+const char *inet6_addrstr(struct in6_addr *);
 void socktrans(struct socket *sock, int i);
 void getinetproto(int number);
 int  getfname(const char *filename);
@@ -757,6 +760,31 @@ bad:
 	printf("* error\n");
 }
 
+const char *
+inet6_addrstr(struct in6_addr *p)
+{
+	struct sockaddr_in6 sin6;
+	static char hbuf[NI_MAXHOST];
+	const int niflags = NI_NUMERICHOST;
+
+	memset(&sin6, 0, sizeof(sin6));
+	sin6.sin6_family = AF_INET6;
+	sin6.sin6_len = sizeof(struct sockaddr_in6);
+	sin6.sin6_addr = *p;
+	if (IN6_IS_ADDR_LINKLOCAL(p) &&
+	    *(u_int16_t *)&sin6.sin6_addr.s6_addr[2] != 0) {
+		sin6.sin6_scope_id =
+		    ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
+		sin6.sin6_addr.s6_addr[2] = sin6.sin6_addr.s6_addr[3] = 0;
+	    }
+
+	    if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
+		hbuf, sizeof(hbuf), NULL, 0, niflags))
+		    return "invalid";
+
+	    return hbuf;
+}
+
 void
 socktrans(struct socket *sock, int i)
 {
@@ -776,6 +804,7 @@ socktrans(struct socket *sock, int i)
 	struct unpcb	unpcb;
 	int len;
 	char dname[32];
+	char xaddrbuf[NI_MAXHOST + 2];
 
 	PREFIX(i);
 
@@ -826,19 +855,68 @@ socktrans(struct socket *sock, int i)
 	 */
 	switch(dom.dom_family) {
 	case AF_INET:
+		getinetproto(proto.pr_protocol);
+		if (proto.pr_protocol == IPPROTO_TCP ||
+		    proto.pr_protocol == IPPROTO_UDP) {
+			if (so.so_pcb == NULL)
+				break;
+			if (kvm_read(kd, (u_long)so.so_pcb,
+			    (char *)&inpcb, sizeof(struct inpcb))
+			    != sizeof(struct inpcb)) {
+				dprintf(stderr,
+				    "can't read inpcb at %p\n",
+				    (void *)so.so_pcb);
+				goto bad;
+			}
+			if (proto.pr_protocol == IPPROTO_TCP)
+				printf(" %lx", (u_long)inpcb.inp_ppcb);
+			else
+				printf(" %lx", (u_long)so.so_pcb);
+			printf(" %s:%hu",
+			    inpcb.inp_laddr.s_addr == INADDR_ANY ? "*" :
+			    inet_ntoa(inpcb.inp_laddr),
+			    ntohs(inpcb.inp_lport));
+			if (inpcb.inp_fport) {
+				printf(" <-> %s:%hu",
+				    inpcb.inp_faddr.s_addr == INADDR_ANY ?
+				    "*" : inet_ntoa(inpcb.inp_faddr),
+				    ntohs(inpcb.inp_fport));
+			}
+		}
+		else if (so.so_pcb)
+			printf(" %lx", (u_long)so.so_pcb);
+		break;
 	case AF_INET6:
 		getinetproto(proto.pr_protocol);
-		if (proto.pr_protocol == IPPROTO_TCP ) {
-			if (so.so_pcb) {
-				if (kvm_read(kd, (u_long)so.so_pcb,
-				    (char *)&inpcb, sizeof(struct inpcb))
-				    != sizeof(struct inpcb)) {
-					dprintf(stderr,
-					    "can't read inpcb at %p\n",
-					    (void *)so.so_pcb);
-					goto bad;
-				}
+		if (proto.pr_protocol == IPPROTO_TCP ||
+		    proto.pr_protocol == IPPROTO_UDP) {
+			if (so.so_pcb == NULL)
+				break;
+			if (kvm_read(kd, (u_long)so.so_pcb,
+			    (char *)&inpcb, sizeof(struct inpcb))
+			    != sizeof(struct inpcb)) {
+				dprintf(stderr,
+				    "can't read inpcb at %p\n",
+				    (void *)so.so_pcb);
+				goto bad;
+			}
+			if (proto.pr_protocol == IPPROTO_TCP)
 				printf(" %lx", (u_long)inpcb.inp_ppcb);
+			else
+				printf(" %lx", (u_long)so.so_pcb);
+			snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
+			    inet6_addrstr(&inpcb.in6p_laddr));
+			printf(" %s:%hu",
+			    IN6_IS_ADDR_UNSPECIFIED(&inpcb.in6p_laddr) ?
+			    "*" : xaddrbuf,
+			    ntohs(inpcb.in6p_lport));
+			if (inpcb.in6p_fport) {
+				snprintf(xaddrbuf, sizeof(xaddrbuf),
+				    "[%s]", inet6_addrstr(&inpcb.in6p_faddr));
+				printf(" <-> %s:%hu",
+				    IN6_IS_ADDR_UNSPECIFIED(&inpcb.in6p_faddr)?
+				    "*" : xaddrbuf,
+				    ntohs(inpcb.in6p_fport));
 			}
 		}
 		else if (so.so_pcb)
--- fstat_inetsock_detail.diff ends here ---


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->freebsd-net 
Responsible-Changed-By: remko 
Responsible-Changed-When: Wed Sep 26 06:39:25 UTC 2007 
Responsible-Changed-Why:  
This looks like something for the -net team. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=116643 
State-Changed-From-To: open->feedback 
State-Changed-By: bz 
State-Changed-When: Fri Oct 17 14:03:39 UTC 2008 
State-Changed-Why:  
See what the submitetr thinks on staying with fstat and using sockstat. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=116643 
Responsible-Changed-From-To: freebsd-net->bz 
Responsible-Changed-By: bz 
Responsible-Changed-When: Fri Oct 17 14:04:47 UTC 2008 
Responsible-Changed-Why:  
Assign to me for the follow-up. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=116643 

From: "Bjoern A. Zeeb" <bz@FreeBSD.org>
To: bug-followup@FreeBSD.org, jeremie@le-hen.org
Cc:  
Subject: Re: bin/116643: [patch] [request] fstat(1): add INET/INET6 socket
 details as in NetBSD and OpenBSD
Date: Fri, 17 Oct 2008 14:03:22 +0000 (UTC)

 Hi,
 
 I have the feeling that we should not change fstat for this. we have
 socksts which gives the information already. In addition you can
 actually get the pointers from fstat easily for debugging and fstat
 does not have the line wrapping problems sockstat has with long ipv6
 addresses.
 
 What do you think?
 
 -- 
 Bjoern A. Zeeb              Stop bit received. Insert coin for new game.

From: Jeremie Le Hen <jeremie@le-hen.org>
To: "Bjoern A. Zeeb" <bz@FreeBSD.org>
Cc: bug-followup@FreeBSD.org, jeremie@le-hen.org
Subject: Re: bin/116643: [patch] [request] fstat(1): add INET/INET6 socket
	details as in NetBSD and OpenBSD
Date: Wed, 22 Oct 2008 14:27:36 +0200

 Hi Bjoern,
 
 On Fri, Oct 17, 2008 at 02:03:22PM +0000, Bjoern A. Zeeb wrote:
 >  I have the feeling that we should not change fstat for this. we have
 >  socksts which gives the information already. In addition you can
 >  actually get the pointers from fstat easily for debugging and fstat
 >  does not have the line wrapping problems sockstat has with long ipv6
 >  addresses.
 > 
 >  What do you think?
 
 I suppose you meant sockstat(1), didn't you?  I agree that it actually
 provides the information.  But I noticed that I often install lsof from
 ports because it can match processes by pid and uid and displays
 detailled information about sockets.  So I created this patch to
 FreeBSD's fstat(1).  Additionally, it makes its output closer to the
 other BSD's.
 
 Line wrapping is certainly a problem, I wasn't aware of this.  However
 I'm not sure the current fstat(1) is free from line wrapping problems.
 On my 6.2 box (nothing else available right now) with a 80 columns
 terminal, the longest line is 85 chars long.
 
 Regards,
 -- 
 Jeremie Le Hen
 < jeremie at le-hen dot org >< ttz at chchile dot org >
State-Changed-From-To: feedback->open 
State-Changed-By: bz 
State-Changed-When: Wed Oct 22 18:12:03 UTC 2008 
State-Changed-Why:  
Feedback received. 


Responsible-Changed-From-To: bz->freebsd-net 
Responsible-Changed-By: bz 
Responsible-Changed-When: Wed Oct 22 18:12:03 UTC 2008 
Responsible-Changed-Why:  
Assign it bck to the masses; I think this needs further discussion. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=116643 

From: Jeremie Le Hen <jeremie@le-hen.org>
To: bug-followup@FreeBSD.org
Cc: bz@FreeBSD.org, freebsd-net@FreeBSD.org, jeremie@le-hen.org
Subject: Re: bin/116643: [patch] [request] fstat(1): add INET/INET6 socket
 details as in NetBSD and OpenBSD
Date: Wed, 5 May 2010 18:40:34 +0200

 --XOIedfhf+7KOe/yw
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 
 Hi,
 
 I've updated the patch so it compiles with -CURRENT.  Also the proposed
 behaviour is opt-in through the -i option.
 
 This PR has been waiting for two years and a half.  I propose that we
 try to find a consensus whether it is useful or not and then close it,
 no matter if it has been accepted or not.
 
 Regards,
 -- 
 Jeremie Le Hen
 
 Humans are born free and equal.  But some are more equal than others.
 					    Coluche
 
 --XOIedfhf+7KOe/yw
 Content-Type: text/x-diff; charset=us-ascii
 Content-Disposition: attachment; filename="fstat-i.diff"
 
 Index: fstat.1
 ===================================================================
 RCS file: /mnt/repos/freebsd-cvsroot/src/usr.bin/fstat/fstat.1,v
 retrieving revision 1.28
 diff -u -p -u -p -r1.28 fstat.1
 --- fstat.1	9 Jul 2009 16:40:00 -0000	1.28
 +++ fstat.1	5 May 2010 16:39:49 -0000
 @@ -40,7 +40,7 @@
  .Nd identify active files
  .Sh SYNOPSIS
  .Nm
 -.Op Fl fmnv
 +.Op Fl fimnv
  .Op Fl M Ar core
  .Op Fl N Ar system
  .Op Fl p Ar pid
 @@ -68,6 +68,8 @@ directory
  .Pa /usr/src
  resides, type
  .Dq Li fstat -f /usr/src .
 +.It Fl i
 +Print extended socket informations for internet sockets.
  .It Fl M
  Extract values associated with the name list from the specified core
  instead of the default
 @@ -213,6 +215,16 @@ connected unix domain stream socket.
  A unidirectional unix domain socket indicates the direction of flow with
  an arrow (``<-'' or ``->''), and a full duplex socket shows a double arrow
  (``<->'').
 +.Pp
 +For internet sockets,
 +the
 +.Fl i
 +flag will make
 +.Nm
 +mimic other BSDs behaviour that is attempt to print the internet address and
 +port for the local connection.
 +If a socket is connected it also prints the remote internet address and port.
 +An asterisk (``*'') is used to indicate an INADDR_ANY binding.
  .Sh SEE ALSO
  .Xr netstat 1 ,
  .Xr nfsstat 1 ,
 Index: fstat.c
 ===================================================================
 RCS file: /mnt/repos/freebsd-cvsroot/src/usr.bin/fstat/fstat.c,v
 retrieving revision 1.72
 diff -u -p -u -p -r1.72 fstat.c
 --- fstat.c	20 Aug 2009 10:57:14 -0000	1.72
 +++ fstat.c	5 May 2010 16:26:45 -0000
 @@ -87,6 +87,8 @@ __FBSDID("$FreeBSD: src/usr.bin/fstat/fs
  #include <netinet/ip.h>
  #include <netinet/in_pcb.h>
  
 +#include <arpa/inet.h>
 +
  #include <ctype.h>
  #include <err.h>
  #include <fcntl.h>
 @@ -126,6 +128,7 @@ int 	checkfile; /* true if restricting t
  int	nflg;	/* (numerical) display f.s. and rdev as dev_t */
  int	vflg;	/* display errors in locating kernel data objects etc... */
  int	mflg;	/* include memory-mapped files */
 +int	iflg;	/* display inet socket details */
  
  
  struct file **ofiles;	/* buffer of pointers to file structures */
 @@ -153,6 +156,7 @@ int  nfs_filestat(struct vnode *vp, stru
  int  devfs_filestat(struct vnode *vp, struct filestat *fsp);
  char *getmnton(struct mount *m);
  void pipetrans(struct pipe *pi, int i, int flag);
 +const char *inet6_addrstr(struct in6_addr *);
  void socktrans(struct socket *sock, int i);
  void ptstrans(struct tty *tp, int i, int flag);
  void getinetproto(int number);
 @@ -169,11 +173,14 @@ main(int argc, char **argv)
  	arg = 0;
  	what = KERN_PROC_PROC;
  	nlistf = memf = NULL;
 -	while ((ch = getopt(argc, argv, "fmnp:u:vN:M:")) != -1)
 +	while ((ch = getopt(argc, argv, "fimnp:u:vN:M:")) != -1)
  		switch((char)ch) {
  		case 'f':
  			fsflg = 1;
  			break;
 +		case 'i':
 +			iflg = 1;
 +			break;
  		case 'M':
  			memf = optarg;
  			break;
 @@ -772,6 +779,31 @@ bad:
  	printf("* error\n");
  }
  
 +const char *
 +inet6_addrstr(struct in6_addr *p)
 +{
 +	struct sockaddr_in6 sin6;
 +	static char hbuf[NI_MAXHOST];
 +	const int niflags = NI_NUMERICHOST;
 +
 +	memset(&sin6, 0, sizeof(sin6));
 +	sin6.sin6_family = AF_INET6;
 +	sin6.sin6_len = sizeof(struct sockaddr_in6);
 +	sin6.sin6_addr = *p;
 +	if (IN6_IS_ADDR_LINKLOCAL(p) &&
 +	    *(u_int16_t *)&sin6.sin6_addr.s6_addr[2] != 0) {
 +		sin6.sin6_scope_id =
 +		    ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
 +		sin6.sin6_addr.s6_addr[2] = sin6.sin6_addr.s6_addr[3] = 0;
 +	    }
 +
 +	    if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
 +		hbuf, sizeof(hbuf), NULL, 0, niflags))
 +		    return "invalid";
 +
 +	    return hbuf;
 +}
 +
  void
  socktrans(struct socket *sock, int i)
  {
 @@ -791,6 +823,7 @@ socktrans(struct socket *sock, int i)
  	struct unpcb	unpcb;
  	int len;
  	char dname[32];
 +	char xaddrbuf[NI_MAXHOST + 2];
  
  	PREFIX(i);
  
 @@ -841,19 +874,72 @@ socktrans(struct socket *sock, int i)
  	 */
  	switch(dom.dom_family) {
  	case AF_INET:
 +		getinetproto(proto.pr_protocol);
 +		if (proto.pr_protocol == IPPROTO_TCP ||
 +		    proto.pr_protocol == IPPROTO_UDP) {
 +			if (so.so_pcb == NULL)
 +				break;
 +			if (kvm_read(kd, (u_long)so.so_pcb,
 +			    (char *)&inpcb, sizeof(struct inpcb))
 +			    != sizeof(struct inpcb)) {
 +				dprintf(stderr,
 +				    "can't read inpcb at %p\n",
 +				    (void *)so.so_pcb);
 +				goto bad;
 +			}
 +			if (proto.pr_protocol == IPPROTO_TCP)
 +				printf(" %lx", (u_long)inpcb.inp_ppcb);
 +			else
 +				printf(" %lx", (u_long)so.so_pcb);
 +			if (!iflg)
 +				break;
 +			printf(" %s:%hu",
 +			    inpcb.inp_laddr.s_addr == INADDR_ANY ? "*" :
 +			    inet_ntoa(inpcb.inp_laddr),
 +			    ntohs(inpcb.inp_lport));
 +			if (inpcb.inp_fport) {
 +				printf(" <-> %s:%hu",
 +				    inpcb.inp_faddr.s_addr == INADDR_ANY ?
 +				    "*" : inet_ntoa(inpcb.inp_faddr),
 +				    ntohs(inpcb.inp_fport));
 +			}
 +		}
 +		else if (so.so_pcb)
 +			printf(" %lx", (u_long)so.so_pcb);
 +		break;
  	case AF_INET6:
  		getinetproto(proto.pr_protocol);
 -		if (proto.pr_protocol == IPPROTO_TCP ) {
 -			if (so.so_pcb) {
 -				if (kvm_read(kd, (u_long)so.so_pcb,
 -				    (char *)&inpcb, sizeof(struct inpcb))
 -				    != sizeof(struct inpcb)) {
 -					dprintf(stderr,
 -					    "can't read inpcb at %p\n",
 -					    (void *)so.so_pcb);
 -					goto bad;
 -				}
 +		if (proto.pr_protocol == IPPROTO_TCP ||
 +		    proto.pr_protocol == IPPROTO_UDP) {
 +			if (so.so_pcb == NULL)
 +				break;
 +			if (kvm_read(kd, (u_long)so.so_pcb,
 +			    (char *)&inpcb, sizeof(struct inpcb))
 +			    != sizeof(struct inpcb)) {
 +				dprintf(stderr,
 +				    "can't read inpcb at %p\n",
 +				    (void *)so.so_pcb);
 +				goto bad;
 +			}
 +			if (proto.pr_protocol == IPPROTO_TCP)
  				printf(" %lx", (u_long)inpcb.inp_ppcb);
 +			else
 +				printf(" %lx", (u_long)so.so_pcb);
 +			if (!iflg)
 +				break;
 +			snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
 +			    inet6_addrstr(&inpcb.in6p_laddr));
 +			printf(" %s:%hu",
 +			    IN6_IS_ADDR_UNSPECIFIED(&inpcb.in6p_laddr) ?
 +			    "*" : xaddrbuf,
 +			    ntohs(inpcb.inp_lport));
 +			if (inpcb.inp_fport) {
 +				snprintf(xaddrbuf, sizeof(xaddrbuf),
 +				    "[%s]", inet6_addrstr(&inpcb.in6p_faddr));
 +				printf(" <-> %s:%hu",
 +				    IN6_IS_ADDR_UNSPECIFIED(&inpcb.in6p_faddr)?
 +				    "*" : xaddrbuf,
 +				    ntohs(inpcb.inp_fport));
  			}
  		}
  		else if (so.so_pcb)
 
 --XOIedfhf+7KOe/yw--
>Unformatted:
