From owner-freebsd-net@FreeBSD.ORG Wed May 5 16:50:02 2010 Return-Path: Delivered-To: freebsd-net@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id E1C7B1065675 for ; Wed, 5 May 2010 16:50:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [69.147.83.40]) by mx1.freebsd.org (Postfix) with ESMTP id B74CA8FC21 for ; Wed, 5 May 2010 16:50:02 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.4/8.14.4) with ESMTP id o45Go23E037438 for ; Wed, 5 May 2010 16:50:02 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.4/8.14.4/Submit) id o45Go2wL037436; Wed, 5 May 2010 16:50:02 GMT (envelope-from gnats) Date: Wed, 5 May 2010 16:50:02 GMT Message-Id: <201005051650.o45Go2wL037436@freefall.freebsd.org> To: freebsd-net@FreeBSD.org From: Jeremie Le Hen Cc: Subject: Re: bin/116643: [patch] [request] fstat(1): add INET/INET6 socket details as in NetBSD and OpenBSD X-BeenThere: freebsd-net@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Jeremie Le Hen List-Id: Networking and TCP/IP with FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 05 May 2010 16:50:03 -0000 The following reply was made to PR bin/116643; it has been noted by GNATS. From: Jeremie Le Hen 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 #include +#include + #include #include #include @@ -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--