Date: Sat, 19 Oct 2019 19:52:20 +0000 (UTC) From: Jeremie Le Hen <jlh@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r353769 - head/usr.bin/fstat Message-ID: <201910191952.x9JJqKHk011308@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: jlh Date: Sat Oct 19 19:52:19 2019 New Revision: 353769 URL: https://svnweb.freebsd.org/changeset/base/353769 Log: Add the fstat -s option to display socket information. Reviewed by: jilles MFC after: 1 week Relnotes: yes Differential Revision: https://reviews.freebsd.org/D21880 Modified: head/usr.bin/fstat/fstat.1 head/usr.bin/fstat/fstat.c Modified: head/usr.bin/fstat/fstat.1 ============================================================================== --- head/usr.bin/fstat/fstat.1 Sat Oct 19 19:38:53 2019 (r353768) +++ head/usr.bin/fstat/fstat.1 Sat Oct 19 19:52:19 2019 (r353769) @@ -28,7 +28,7 @@ .\" @(#)fstat.1 8.3 (Berkeley) 2/25/94 .\" $FreeBSD$ .\" -.Dd September 28, 2011 +.Dd October 19, 2019 .Dt FSTAT 1 .Os .Sh NAME @@ -36,7 +36,7 @@ .Nd identify active files .Sh SYNOPSIS .Nm -.Op Fl fmnv +.Op Fl fmnsv .Op Fl M Ar core .Op Fl N Ar system .Op Fl p Ar pid @@ -85,6 +85,8 @@ in and print the mode of the file in octal instead of symbolic form. .It Fl p Report all files open by the specified process. +.It Fl s +Print socket endpoint information. .It Fl u Report all files open by the specified user. .It Fl v @@ -199,9 +201,6 @@ For tcp, it is the address of the tcpcb, and for udp, For unix domain sockets, its the address of the socket pcb and the address of the connected pcb (if connected). Otherwise the protocol number and address of the socket itself are printed. -The attempt is to make enough information available to -permit further analysis without duplicating -.Xr netstat 1 . .Pp For example, the addresses mentioned above are the addresses which the .Dq Li netstat -A @@ -211,6 +210,15 @@ 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 +When the +.Fl s +flag is used, socket endpoint information is shown after the address of the +socket. +For internet sockets the local and remote address are shown, separated with +a double arrow (``<->''). +For unix/local sockets either the local or remote address is shown, depending +on which one is available. .Sh SEE ALSO .Xr netstat 1 , .Xr nfsstat 1 , Modified: head/usr.bin/fstat/fstat.c ============================================================================== --- head/usr.bin/fstat/fstat.c Sat Oct 19 19:38:53 2019 (r353768) +++ head/usr.bin/fstat/fstat.c Sat Oct 19 19:52:19 2019 (r353769) @@ -40,9 +40,12 @@ __FBSDID("$FreeBSD$"); #include <sys/socketvar.h> #include <sys/sysctl.h> #include <sys/queue.h> +#include <sys/un.h> #include <netinet/in.h> +#include <arpa/inet.h> + #include <assert.h> #include <ctype.h> #include <err.h> @@ -61,6 +64,7 @@ __FBSDID("$FreeBSD$"); static int fsflg, /* show files on same filesystem as file(s) argument */ pflg, /* show files open by a particular pid */ + sflg, /* show socket details */ uflg; /* show files open by a particular (effective) user */ static int checkfile; /* restrict to particular files or filesystems */ static int nflg; /* (numerical) display f.s. and rdev as dev_t */ @@ -108,7 +112,7 @@ do_fstat(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, "fmnp:su:vN:M:")) != -1) switch((char)ch) { case 'f': fsflg = 1; @@ -135,6 +139,9 @@ do_fstat(int argc, char **argv) what = KERN_PROC_PID; arg = atoi(optarg); break; + case 's': + sflg = 1; + break; case 'u': if (uflg++) usage(); @@ -314,6 +321,55 @@ print_file_info(struct procstat *procstat, struct file putchar('\n'); } +static char * +addr_to_string(struct sockaddr_storage *ss, char *buffer, int buflen) +{ + char buffer2[INET6_ADDRSTRLEN]; + struct sockaddr_in6 *sin6; + struct sockaddr_in *sin; + struct sockaddr_un *sun; + + switch (ss->ss_family) { + case AF_LOCAL: + sun = (struct sockaddr_un *)ss; + if (strlen(sun->sun_path) == 0) + strlcpy(buffer, "-", buflen); + else + strlcpy(buffer, sun->sun_path, buflen); + break; + + case AF_INET: + sin = (struct sockaddr_in *)ss; + if (sin->sin_addr.s_addr == INADDR_ANY) + snprintf(buffer, buflen, "%s:%d", "*", + ntohs(sin->sin_port)); + else if (inet_ntop(AF_INET, &sin->sin_addr, buffer2, + sizeof(buffer2)) != NULL) + snprintf(buffer, buflen, "%s:%d", buffer2, + ntohs(sin->sin_port)); + break; + + case AF_INET6: + sin6 = (struct sockaddr_in6 *)ss; + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) + snprintf(buffer, buflen, "%s.%d", "*", + ntohs(sin6->sin6_port)); + else if (inet_ntop(AF_INET6, &sin6->sin6_addr, buffer2, + sizeof(buffer2)) != NULL) + snprintf(buffer, buflen, "%s.%d", buffer2, + ntohs(sin6->sin6_port)); + else + strlcpy(buffer, "-", buflen); + break; + + default: + strlcpy(buffer, "", buflen); + break; + } + return buffer; +} + + static void print_socket_info(struct procstat *procstat, struct filestat *fst) { @@ -329,6 +385,8 @@ print_socket_info(struct procstat *procstat, struct fi struct sockstat sock; struct protoent *pe; char errbuf[_POSIX2_LINE_MAX]; + char src_addr[PATH_MAX], dst_addr[PATH_MAX]; + struct sockaddr_un *sun; int error; static int isopen; @@ -368,6 +426,11 @@ print_socket_info(struct procstat *procstat, struct fi } else if (sock.so_pcb != 0) printf(" %lx", (u_long)sock.so_pcb); + if (!sflg) + break; + printf(" %s <-> %s", + addr_to_string(&sock.sa_local, src_addr, sizeof(src_addr)), + addr_to_string(&sock.sa_peer, dst_addr, sizeof(dst_addr))); break; case AF_UNIX: /* print address of pcb and connected pcb */ @@ -385,8 +448,25 @@ print_socket_info(struct procstat *procstat, struct fi *cp = '\0'; printf(" %s %lx", shoconn, (u_long)sock.unp_conn); - } + } } + if (!sflg) + break; + sun = (struct sockaddr_un *)&sock.sa_local; + /* + * While generally we like to print two addresses, + * local and peer, for sockets, it turns out to be + * more useful to print the first non-null address for + * local sockets, as typically they aren't bound and + * connected, and the path strings can get long. + */ + if (sun->sun_path[0] != 0) + addr_to_string(&sock.sa_local, + src_addr, sizeof(src_addr)); + else + addr_to_string(&sock.sa_peer, + src_addr, sizeof(src_addr)); + printf(" %s", src_addr); break; default: /* print protocol number and socket address */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201910191952.x9JJqKHk011308>