[PATCH v5] Print ip and port associated with descriptor with -yy

zubin.mithra at gmail.com zubin.mithra at gmail.com
Mon Aug 11 08:51:01 UTC 2014


From: Zubin Mithra <zubin.mithra at gmail.com>

* Makefile.am (strace_SOURCES): Add socketutils.c.
* configure.ac (AC_CHECK_HEADERS): Add linux/inet_diag.h,
  linux/netlink.h, linux/sock_diag.h.
(AC_CHECK_TYPES): Add inet_diag_req_v2.
* defs.h (get_pagesize): Add declaration.
(printsockdetails): Add declaration.
* mem.c (get_pagesize): Remove static keyword.
* socketutils.c (printsockdetails): New function.
(send_query): New function.
(receive_responses): New function to receive msg responses.
(parse_response): New function to parse a received response.
* util.c (printfd): Modify to use printsockdetails.
* strace.c (usage): Update to add -yy option.
* strace.1: Add description of -yy option.

Signed-off-by: Zubin Mithra <zubin.mithra at gmail.com>
---
 Makefile.am   |   1 +
 configure.ac  |   5 ++
 defs.h        |   3 +-
 mem.c         |   2 +-
 socketutils.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 strace.1      |   3 +
 strace.c      |   1 +
 util.c        |  25 ++++++--
 8 files changed, 213 insertions(+), 6 deletions(-)
 create mode 100644 socketutils.c

diff --git a/Makefile.am b/Makefile.am
index be05946..ae01416 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -45,6 +45,7 @@ strace_SOURCES =	\
 	scsi.c		\
 	signal.c	\
 	sock.c		\
+	socketutils.c	\
 	strace.c	\
 	stream.c	\
 	syscall.c	\
diff --git a/configure.ac b/configure.ac
index 9aeb3a6..21dcc0e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -228,8 +228,11 @@ AC_CHECK_HEADERS(m4_normalize([
 	inttypes.h
 	ioctls.h
 	linux/capability.h
+	linux/inet_diag.h
+	linux/netlink.h
 	linux/perf_event.h
 	linux/ptrace.h
+	linux/sock_diag.h
 	linux/utsname.h
 	mqueue.h
 	netinet/sctp.h
@@ -258,6 +261,8 @@ AC_CHECK_HEADERS([netinet/tcp.h netinet/udp.h],,, [#include <netinet/in.h>])
 
 AC_CHECK_MEMBERS([struct msghdr.msg_control],,, [#include <sys/socket.h>])
 
+AC_CHECK_TYPES([struct inet_diag_req_v2],,, [#include <linux/inet_diag.h])
+
 AC_CHECK_TYPES([struct __old_kernel_stat],,, [#include <asm/stat.h>])
 
 AC_CHECK_TYPES([struct pt_all_user_regs, struct ia64_fpreg, struct ptrace_peeksiginfo_args],,,
diff --git a/defs.h b/defs.h
index 625cac6..e0e9f77 100644
--- a/defs.h
+++ b/defs.h
@@ -67,7 +67,6 @@
 #include <time.h>
 #include <sys/time.h>
 #include <sys/syscall.h>
-
 #ifndef HAVE_STRERROR
 const char *strerror(int);
 #endif
@@ -605,6 +604,7 @@ extern void print_pc(struct tcb *);
 extern int trace_syscall(struct tcb *);
 extern void count_syscall(struct tcb *, const struct timeval *);
 extern void call_summary(FILE *);
+extern unsigned long get_pagesize();
 
 #if defined(AVR32) \
  || defined(I386) \
@@ -694,6 +694,7 @@ extern void printsiginfo(siginfo_t *, int);
 extern void printsiginfo_at(struct tcb *tcp, long addr);
 #endif
 extern void printfd(struct tcb *, int);
+extern int printsockdetails(uint32_t);
 extern void print_dirfd(struct tcb *, int);
 extern void printsock(struct tcb *, long, int);
 extern void print_sock_optmgmt(struct tcb *, long, int);
diff --git a/mem.c b/mem.c
index 6ecd363..356c54e 100644
--- a/mem.c
+++ b/mem.c
@@ -34,7 +34,7 @@
 #include <asm/mman.h>
 #include <sys/mman.h>
 
-static unsigned long
+unsigned long
 get_pagesize()
 {
 	static unsigned long pagesize;
diff --git a/socketutils.c b/socketutils.c
new file mode 100644
index 0000000..79e4d07
--- /dev/null
+++ b/socketutils.c
@@ -0,0 +1,179 @@
+#include "defs.h"
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netlink/netlink.h>
+
+#ifdef HAVE_LINUX_NETLINK_H
+# include <linux/netlink.h>
+#endif
+
+#ifdef HAVE_LINUX_SOCK_DIAG_H
+# include <linux/sock_diag.h>
+#else
+# define SOCK_DIAG_BY_FAMILY 20
+  struct sock_diag_req {
+	  __u8    sdiag_family;
+	  __u8    sdiag_protocol;
+  };
+#endif
+
+#define SOCKET_BUFFER_SIZE (getpagesize() < 8192L ? getpagesize() : 8192L)
+
+#ifdef HAVE_LINUX_INET_DIAG_H
+# include <linux/inet_diag.h>
+#else
+  struct inet_diag_sockid {
+	  __be16  idiag_sport;
+	  __be16  idiag_dport;
+	  __be32  idiag_src[4];
+	  __be32  idiag_dst[4];
+	  __u32   idiag_if;
+	  __u32   idiag_cookie[2];
+  #define INET_DIAG_NOCOOKIE (~0U)
+  };
+#endif
+
+/* Not all linux/inet_diag.h have v2 */
+#ifndef HAVE_STRUCT_INET_DIAG_REQ_V2
+  struct inet_diag_req_v2 {
+	  __u8	sdiag_family;
+	  __u8	sdiag_protocol;
+	  __u8	idiag_ext;
+	  __u8	pad;
+	  __u32	idiag_states;
+	  struct inet_diag_sockid id;
+  };
+#endif
+
+int
+parse_response(struct inet_diag_msg *diag_msg, int inodenr)
+{
+	char remote_addr_buf[INET6_ADDRSTRLEN];
+	int rport;
+	char *ret;
+
+	if (diag_msg->idiag_inode != inodenr)
+		return -1;
+
+	switch(diag_msg->idiag_family) {
+		case AF_INET:
+			ret = inet_ntop(diag_msg->idiag_family,
+			  (struct in_addr*) &(diag_msg->id.idiag_dst),
+			  remote_addr_buf, INET_ADDRSTRLEN);
+			break;
+		case AF_INET6:
+			ret = inet_ntop(diag_msg->idiag_family,
+			  (struct in_addr*) &(diag_msg->id.idiag_dst),
+			  remote_addr_buf, INET6_ADDRSTRLEN);
+			break;
+		default:
+			return -1;
+	}
+
+	if (!ret)
+		return -1;
+
+	if (remote_addr_buf[0] == 0)
+		return -1;
+	rport = ntohs(diag_msg->id.idiag_dport);
+	tprintf("%s:%d", remote_addr_buf, rport);
+	return 0;
+}
+
+int
+send_query(int sockfd, int proto, int family)
+{
+	struct msghdr msg;
+	struct nlmsghdr nlh;
+	struct inet_diag_req_v2 conn_req;
+	struct sockaddr_nl sa;
+	struct iovec iov[2];
+
+	memset(&msg, 0, sizeof(msg));
+	memset(&sa, 0, sizeof(sa));
+	memset(&nlh, 0, sizeof(nlh));
+	memset(&conn_req, 0, sizeof(conn_req));
+
+	sa.nl_family = AF_NETLINK;
+	conn_req.sdiag_family = family;
+	conn_req.sdiag_protocol = proto;
+	conn_req.idiag_states = -1;
+
+	nlh.nlmsg_len = NLMSG_LENGTH(sizeof(conn_req));
+	nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
+
+	nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
+	iov[0].iov_base = (void*) &nlh;
+	iov[0].iov_len = sizeof(nlh);
+	iov[1].iov_base = (void*) &conn_req;
+	iov[1].iov_len = sizeof(conn_req);
+
+	msg.msg_name = (void*) &sa;
+	msg.msg_namelen = sizeof(sa);
+	msg.msg_iov = iov;
+	msg.msg_iovlen = 2;
+
+	return sendmsg(sockfd, &msg, 0);
+}
+
+int
+receive_responses(int sockfd, int inodenr)
+{
+	char recv_buf[SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+	struct inet_diag_msg *diag_msg;
+	int numbytes = 0;
+	while (1) {
+		numbytes = recv(sockfd, recv_buf, sizeof(recv_buf), 0);
+		nlh = (struct nlmsghdr*) recv_buf;
+
+		while (NLMSG_OK(nlh, numbytes)) {
+			if (nlh->nlmsg_type == NLMSG_DONE)
+				return -1;
+
+			else if (nlh->nlmsg_type == NLMSG_ERROR)
+				return -1;
+
+			diag_msg = (struct inet_diag_msg*) NLMSG_DATA(nlh);
+			if (parse_response(diag_msg, inodenr) == 0)
+				return 0;
+
+			nlh = NLMSG_NEXT(nlh, numbytes);
+		}
+	}
+	return -1;
+}
+
+/* Given an inode number of a socket, print out the details
+ * of the remote ip address and remote port */
+int
+printsockdetails(uint32_t inodenr)
+{
+	int sockfd, retval = -1;
+	size_t i, j;
+	int protocols[] = {IPPROTO_TCP, IPPROTO_UDP};
+	int families[] = {AF_INET, AF_INET6};
+	size_t plen = ARRAY_SIZE(protocols);
+	size_t flen = ARRAY_SIZE(families);
+
+	/* Create the monitoring socket */
+	sockfd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_INET_DIAG);
+	if (sockfd == -1)
+		return -1;
+
+	for (i = 0; i < plen; i++) {
+		for (j = 0; j < flen; j++) {
+			if (send_query(sockfd, protocols[i], families[j]) < 0) {
+				goto end;
+			}
+			if (receive_responses(sockfd, inodenr) == 0) {
+				retval = 0;
+				goto end;
+			}
+		}
+	}
+end:
+	close(sockfd);
+	return retval;
+}
diff --git a/strace.1 b/strace.1
index 2a24c38..57d6cc1 100644
--- a/strace.1
+++ b/strace.1
@@ -321,6 +321,9 @@ Print all strings in hexadecimal string format.
 .B \-y
 Print paths associated with file descriptor arguments.
 .TP
+.B \-yy
+Print extended decoded paths for socket file descriptors.
+.TP
 .BI "\-a " column
 Align return values in a specific column (default column 40).
 .TP
diff --git a/strace.c b/strace.c
index 2bc5c67..7973922 100644
--- a/strace.c
+++ b/strace.c
@@ -216,6 +216,7 @@ usage: strace [-CdffhiqrtttTvVxxy] [-I n] [-e expr]...\n\
 -v -- verbose mode: print unabbreviated argv, stat, termios, etc. args\n\
 -x -- print non-ascii strings in hex, -xx -- print all strings in hex\n\
 -y -- print paths associated with file descriptor arguments\n\
+-yy -- print paths associated with file descriptor arguments\n\
 -h -- print help message, -V -- print version\n\
 -a column -- alignment COLUMN for printing syscall results (default %d)\n\
 -b execve -- detach on this syscall\n\
diff --git a/util.c b/util.c
index c78e962..446a619 100644
--- a/util.c
+++ b/util.c
@@ -404,10 +404,27 @@ void
 printfd(struct tcb *tcp, int fd)
 {
 	char path[PATH_MAX + 1];
-
-	if (show_fd_path && getfdpath(tcp, fd, path, sizeof(path)) >= 0)
-		tprintf("%d<%s>", fd, path);
-	else
+	if (show_fd_path && getfdpath(tcp, fd, path, sizeof(path)) >= 0) {
+		static const char socket_prefix[] = "socket:[";
+		const size_t socket_prefix_len = sizeof(socket_prefix) - 1;
+		size_t path_len;
+
+		if (show_fd_path > 1 &&
+		    strncmp(path, socket_prefix, socket_prefix_len) == 0 &&
+		    path[(path_len = strlen(path)) - 1] == ']') {
+			unsigned long inodenr;
+			path[path_len - 1] = '\0';
+			inodenr = strtoul(path + socket_prefix_len, NULL, 10);
+			tprintf("%d<", fd);
+			if (printsockdetails(inodenr) < 0) {
+				path[path_len - 1] = ']';
+				tprints(path);
+			}
+			tprints(">");
+		} else {
+			tprintf("%d<%s>", fd, path);
+		}
+	} else
 		tprintf("%d", fd);
 }
 
-- 
1.8.4





More information about the Strace-devel mailing list