From: <zub...@gm...> - 2014-08-04 14:06:05
|
From: Zubin Mithra <zub...@gm...> * defs.h: Add header files netinet/in.h, sys/socket.h and arpa/inet.h. (init): change type of show_fd_path to unsigned int. * util.c (print_remote_ipport): New function. (printsockdetails): New function. (printfd): Modify to use printsockdetails. Signed-off-by: Zubin Mithra <zub...@gm...> --- defs.h | 5 +++- strace.c | 4 ++-- util.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 86 insertions(+), 4 deletions(-) diff --git a/defs.h b/defs.h index 1a3b483..f0fb79a 100644 --- a/defs.h +++ b/defs.h @@ -67,6 +67,9 @@ #include <time.h> #include <sys/time.h> #include <sys/syscall.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <arpa/inet.h> #ifndef HAVE_STRERROR const char *strerror(int); @@ -562,7 +565,7 @@ extern bool iflag; extern bool count_wallclock; extern unsigned int qflag; extern bool not_failing_only; -extern bool show_fd_path; +extern unsigned int show_fd_path; extern bool hide_log_until_execve; /* are we filtering traces based on paths? */ extern const char **paths_selected; diff --git a/strace.c b/strace.c index 4154cde..2bc5c67 100644 --- a/strace.c +++ b/strace.c @@ -129,7 +129,7 @@ static int post_attach_sigstop = TCB_IGNORE_ONE_SIGSTOP; bool not_failing_only = 0; /* Show path associated with fd arguments */ -bool show_fd_path = 0; +unsigned int show_fd_path = 0; static bool detach_on_execve = 0; /* Are we "strace PROG" and need to skip detach on first execve? */ @@ -1734,7 +1734,7 @@ init(int argc, char *argv[]) xflag++; break; case 'y': - show_fd_path = 1; + show_fd_path++; break; case 'v': qualify("abbrev=none"); diff --git a/util.c b/util.c index 33482d5..502f572 100644 --- a/util.c +++ b/util.c @@ -404,13 +404,92 @@ printnum_int(struct tcb *tcp, long addr, const char *fmt) tprints("]"); } +static bool +print_remote_ipport(int linenr, const char *line, int inodenr) +{ + unsigned long rxq, txq, time_len, retr, inode; + int local_port, rem_port, d, state, uid, timer_run, timeout; + char rem_addr[128], local_addr[128], more[512]; + struct sockaddr_in remaddr; + if (linenr == 0) + return 1; + + sscanf(line, + "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n", + &d, local_addr, &local_port, rem_addr, &rem_port, &state, + &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); + + if (inodenr != inode) + return 1; + + if (strlen(rem_addr) > 8) { + // We have an ipv6 address + struct in6_addr in6; + sscanf(rem_addr, "%08X%08X%08X%08X", + &in6.s6_addr32[0], &in6.s6_addr32[1], + &in6.s6_addr32[2], &in6.s6_addr32[3]); + tprintf("%s:%d", inet_ntoa(remaddr.sin_addr), + rem_port); + } + else { + // We have an ipv4 address + sscanf(rem_addr, "%X", &((struct sockaddr_in *) &remaddr)->sin_addr.s_addr); + tprintf("%s:%d", inet_ntoa(remaddr.sin_addr), rem_port); + } + return 0; +} + +/* Given an inode number of a socket, print out the details + * of the remote ip address and remote port */ +int +printsockdetails(int inodenr) +{ + FILE *fp; + char buffer[8192]; + int linenr = 0; + bool flag = 1; + + fp = fopen("/proc/net/tcp", "r"); + if (fp == NULL) { + return -1; + } + + do { + if (fgets(buffer, sizeof(buffer), fp)) + flag = print_remote_ipport(linenr++, buffer, inodenr); + if (!flag) break; + } while (!feof(fp)); + fclose(fp); + if (flag) + return -1; + return 0; +} + void printfd(struct tcb *tcp, int fd) { char path[PATH_MAX + 1]; - if (show_fd_path && getfdpath(tcp, fd, path, sizeof(path)) >= 0) + if (show_fd_path == 1 && getfdpath(tcp, fd, path, sizeof(path)) >= 0) tprintf("%d<%s>", fd, path); + else if (show_fd_path > 1 && getfdpath(tcp, fd, path, sizeof(path)) >= 0) { + char *ptr = NULL; + int inodenr; + ptr = strstr(path, "socket:["); + if (ptr != path) { + tprintf("%d<%s>", fd, path); + } + else { + int retval; + ptr = path + 8; + path[strlen(path)-1] = '\0'; + inodenr = strtol(ptr, NULL, 10); + tprintf("%d<", fd); + retval = printsockdetails(inodenr); + if (retval == -1) tprintf("socket:[%d]",inodenr); + tprints(">"); + } + } else tprintf("%d", fd); } -- 1.8.4 |
From: <zub...@gm...> - 2014-08-05 13:53:36
|
From: Zubin Mithra <zub...@gm...> * defs.h: Add header files netinet/in.h, sys/socket.h and arpa/inet.h. (init): change type of show_fd_path to unsigned int. * util.c (print_remote_ipport): New function. (check_netfile): New function. (printsockdetails): New function. (printfd): Modify to use printsockdetails. Signed-off-by: Zubin Mithra <zub...@gm...> --- defs.h | 5 +++- strace.c | 4 +-- util.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 104 insertions(+), 4 deletions(-) diff --git a/defs.h b/defs.h index 1a3b483..f0fb79a 100644 --- a/defs.h +++ b/defs.h @@ -67,6 +67,9 @@ #include <time.h> #include <sys/time.h> #include <sys/syscall.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <arpa/inet.h> #ifndef HAVE_STRERROR const char *strerror(int); @@ -562,7 +565,7 @@ extern bool iflag; extern bool count_wallclock; extern unsigned int qflag; extern bool not_failing_only; -extern bool show_fd_path; +extern unsigned int show_fd_path; extern bool hide_log_until_execve; /* are we filtering traces based on paths? */ extern const char **paths_selected; diff --git a/strace.c b/strace.c index 4154cde..2bc5c67 100644 --- a/strace.c +++ b/strace.c @@ -129,7 +129,7 @@ static int post_attach_sigstop = TCB_IGNORE_ONE_SIGSTOP; bool not_failing_only = 0; /* Show path associated with fd arguments */ -bool show_fd_path = 0; +unsigned int show_fd_path = 0; static bool detach_on_execve = 0; /* Are we "strace PROG" and need to skip detach on first execve? */ @@ -1734,7 +1734,7 @@ init(int argc, char *argv[]) xflag++; break; case 'y': - show_fd_path = 1; + show_fd_path++; break; case 'v': qualify("abbrev=none"); diff --git a/util.c b/util.c index 33482d5..5403d0e 100644 --- a/util.c +++ b/util.c @@ -404,13 +404,110 @@ printnum_int(struct tcb *tcp, long addr, const char *fmt) tprints("]"); } +static bool +print_remote_ipport(int linenr, const char *line, int inodenr) +{ + unsigned long rxq, txq, time_len, retr, inode; + int local_port, rem_port, d, state, uid, timer_run, timeout; + char rem_addr[128], local_addr[128], more[512]; + if (linenr == 0) + return 1; + + sscanf(line, + "%d: %64[0-9A-Fa-f]:%X %64[0-9A-Fa-f]:%X %X %lX:%lX %X:%lX %lX %d %d %ld %512s\n", + &d, local_addr, &local_port, rem_addr, &rem_port, &state, + &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); + + if (inodenr != inode) + return 1; + + if (strlen(rem_addr) > 8) { + // We have an ipv6 address + struct in6_addr in6; + char addr6[INET6_ADDRSTRLEN]; + sscanf(rem_addr, "%08X%08X%08X%08X", + &in6.s6_addr32[0], &in6.s6_addr32[1], + &in6.s6_addr32[2], &in6.s6_addr32[3]); + inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6)); + tprintf("%s:%d", addr6, rem_port); + } + else { + // We have an ipv4 address + struct sockaddr_in in4; + sscanf(rem_addr, "%X", &((struct sockaddr_in *) &in4)->sin_addr.s_addr); + tprintf("%s:%d", inet_ntoa(in4.sin_addr), rem_port); + } + return 0; +} + +int +check_netfile(const char *filename, int inodenr) { + FILE *fp; + char buffer[8192]; + int linenr = 0; + bool flag = 1; + + fp = fopen(filename, "r"); + if (fp == NULL) { + return -1; + } + + do { + if (fgets(buffer, sizeof(buffer), fp)) + flag = print_remote_ipport(linenr++, buffer, inodenr); + if (!flag) break; + } while (!feof(fp)); + fclose(fp); + if (flag) + return -1; + return 0; +} + +/* Given an inode number of a socket, print out the details + * of the remote ip address and remote port */ +int +printsockdetails(int inodenr) +{ + if ((check_netfile("/proc/net/tcp", inodenr)) == 0) { + return 0; + } + if ((check_netfile("/proc/net/tcp6", inodenr)) == 0) { + return 0; + } + if ((check_netfile("/proc/net/udp", inodenr)) == 0) { + return 0; + } + if ((check_netfile("/proc/net/udp6", inodenr)) == 0) { + return 0; + } + return -1; +} + void printfd(struct tcb *tcp, int fd) { char path[PATH_MAX + 1]; - if (show_fd_path && getfdpath(tcp, fd, path, sizeof(path)) >= 0) + if (show_fd_path == 1 && getfdpath(tcp, fd, path, sizeof(path)) >= 0) tprintf("%d<%s>", fd, path); + else if (show_fd_path > 1 && getfdpath(tcp, fd, path, sizeof(path)) >= 0) { + char *ptr = NULL; + int inodenr; + ptr = strstr(path, "socket:["); + if (ptr != path) { + tprintf("%d<%s>", fd, path); + } + else { + int retval; + ptr = path + 8; + path[strlen(path)-1] = '\0'; + inodenr = strtol(ptr, NULL, 10); + tprintf("%d<", fd); + retval = printsockdetails(inodenr); + if (retval == -1) tprintf("socket:[%d]",inodenr); + tprints(">"); + } + } else tprintf("%d", fd); } -- 1.8.4 |
From: <zub...@gm...> - 2014-08-07 12:47:39
|
From: Zubin Mithra <zub...@gm...> * defs.h: Add Add header files netinet/in.h, sys/socket.h, arpa/inet.h, linux/netlink.h and linux/inet_diag.h. Change type of show_fd_path to unsigned int. Add macros SOCK_DIAG_BY_FAMILY, SOCKET_BUFFER_SIZE. Add structs sock_diag_req, inet_diag_req_v2. * strace.c (init): Change usage of show_fd_path. * util.c (parse_response): New function to parse and print ip, port from a message response. (send_query): New function. (receive_responses): New function. (printsockdetails): New function. (printfd): Modified to use printsockdetails. Signed-off-by: Zubin Mithra <zub...@gm...> --- defs.h | 24 ++++++++++- strace.c | 4 +- util.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 164 insertions(+), 4 deletions(-) diff --git a/defs.h b/defs.h index 1a3b483..6959cdb 100644 --- a/defs.h +++ b/defs.h @@ -67,6 +67,11 @@ #include <time.h> #include <sys/time.h> #include <sys/syscall.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <linux/netlink.h> +#include <linux/inet_diag.h> #ifndef HAVE_STRERROR const char *strerror(int); @@ -562,7 +567,7 @@ extern bool iflag; extern bool count_wallclock; extern unsigned int qflag; extern bool not_failing_only; -extern bool show_fd_path; +extern unsigned int show_fd_path; extern bool hide_log_until_execve; /* are we filtering traces based on paths? */ extern const char **paths_selected; @@ -580,6 +585,23 @@ extern unsigned os_release; #undef KERNEL_VERSION #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#define SOCK_DIAG_BY_FAMILY 20 +#define SOCKET_BUFFER_SIZE (getpagesize() < 8192L ? getpagesize() : 8192L) + +struct sock_diag_req { + __u8 sdiag_family; + __u8 sdiag_protocol; +}; + +struct inet_diag_req_v2 { + __u8 sdiag_family; + __u8 sdiag_protocol; + __u8 idiag_ext; + __u8 pad; + __u32 idiag_states; + struct inet_diag_sockid id; +}; + enum bitness_t { BITNESS_CURRENT = 0, BITNESS_32 }; void error_msg(const char *fmt, ...) __attribute__ ((format(printf, 1, 2))); diff --git a/strace.c b/strace.c index 4154cde..2bc5c67 100644 --- a/strace.c +++ b/strace.c @@ -129,7 +129,7 @@ static int post_attach_sigstop = TCB_IGNORE_ONE_SIGSTOP; bool not_failing_only = 0; /* Show path associated with fd arguments */ -bool show_fd_path = 0; +unsigned int show_fd_path = 0; static bool detach_on_execve = 0; /* Are we "strace PROG" and need to skip detach on first execve? */ @@ -1734,7 +1734,7 @@ init(int argc, char *argv[]) xflag++; break; case 'y': - show_fd_path = 1; + show_fd_path++; break; case 'v': qualify("abbrev=none"); diff --git a/util.c b/util.c index 33482d5..0065eb9 100644 --- a/util.c +++ b/util.c @@ -404,13 +404,151 @@ printnum_int(struct tcb *tcp, long addr, const char *fmt) tprints("]"); } +int +parse_response(struct inet_diag_msg *diag_msg, int inodenr) { + char remote_addr_buf[INET6_ADDRSTRLEN]; + int rport; + + if (diag_msg->idiag_inode != inodenr) + return -1; + + memset(remote_addr_buf, 0, sizeof(remote_addr_buf)); + + if (diag_msg->idiag_family == AF_INET) + inet_ntop(AF_INET, (struct in_addr*) &(diag_msg->id.idiag_dst), + remote_addr_buf, INET_ADDRSTRLEN); + else if (diag_msg->idiag_family == AF_INET6) + inet_ntop(AF_INET6, (struct in_addr6*) &(diag_msg->id.idiag_dst), + remote_addr_buf, INET6_ADDRSTRLEN); + else + 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[4]; + + 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 +parse_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(int inodenr) +{ + int sockfd; + int i, j; + int protocols[] = {IPPROTO_TCP, IPPROTO_UDP}; + int families[] = {AF_INET, AF_INET6}; + + //Create the monitoring socket + if((sockfd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_INET_DIAG)) == -1) + return -1; + + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + if (send_query(sockfd, protocols[i], families[j]) < 0) { + close(sockfd); + return -1; + } + if (parse_responses(sockfd, inodenr) == 0) { + close(sockfd); + return 0; + } + } + } + close(sockfd); + return -1; +} + void printfd(struct tcb *tcp, int fd) { char path[PATH_MAX + 1]; - if (show_fd_path && getfdpath(tcp, fd, path, sizeof(path)) >= 0) + if (show_fd_path == 1 && getfdpath(tcp, fd, path, sizeof(path)) >= 0) tprintf("%d<%s>", fd, path); + else if (show_fd_path > 1 && getfdpath(tcp, fd, path, sizeof(path)) >= 0) { + char *ptr = NULL; + int inodenr; + ptr = strstr(path, "socket:["); + if (ptr != path) { + tprintf("%d<%s>", fd, path); + } + else { + int retval; + ptr = path + 8; + path[strlen(path)-1] = '\0'; + inodenr = strtol(ptr, NULL, 10); + tprintf("%d<", fd); + retval = printsockdetails(inodenr); + if (retval == -1) tprintf("socket:[%d]",inodenr); + tprints(">"); + } + } else tprintf("%d", fd); } -- 1.8.4 |
From: Masatake Y. <ya...@re...> - 2014-08-07 13:28:49
|
> From: Zubin Mithra <zub...@gm...> > > * defs.h: Add Add header files netinet/in.h, sys/socket.h, > arpa/inet.h, linux/netlink.h and linux/inet_diag.h. > Change type of show_fd_path to unsigned int. > Add macros SOCK_DIAG_BY_FAMILY, SOCKET_BUFFER_SIZE. > Add structs sock_diag_req, inet_diag_req_v2. > * strace.c (init): Change usage of show_fd_path. > * util.c (parse_response): New function to parse and > print ip, port from a message response. > (send_query): New function. > (receive_responses): New function. > (printsockdetails): New function. > (printfd): Modified to use printsockdetails. Wow! The feature looks important. People including I may want extend to handle more families and get information. It is nice if you prepare a test case, too. See code/tests/. On Thu, 7 Aug 2014 18:17:12 +0530, zub...@gm... wrote: > + if (diag_msg->idiag_family == AF_INET) > + inet_ntop(AF_INET, (struct in_addr*) &(diag_msg->id.idiag_dst), > + remote_addr_buf, INET_ADDRSTRLEN); > + else if (diag_msg->idiag_family == AF_INET6) > + inet_ntop(AF_INET6, (struct in_addr6*) &(diag_msg->id.idiag_dst), > + remote_addr_buf, INET6_ADDRSTRLEN); > + else > + return -1; To make adding more families a bit easier how do you think use switch/case instead of if/else? Like: switch (diag_msg->idiag_family) { case AF_INET: ... case AF_INET6: ... } On Thu, 7 Aug 2014 18:17:12 +0530, zub...@gm... wrote: > +/* Given an inode number of a socket, print out the details > + * of the remote ip address and remote port */ > +int > +printsockdetails(int inodenr) > +{ > + int sockfd; > + int i, j; > + int protocols[] = {IPPROTO_TCP, IPPROTO_UDP}; > + int families[] = {AF_INET, AF_INET6}; > + > + //Create the monitoring socket > + if((sockfd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_INET_DIAG)) == -1) > + return -1; Do we have to create a netlink socket each time printsockdetails is inovked? How do you think cache the response from the netlink socket? System calls that adding and removing a socket from fd table of process are enumerable. So you can cache the response from the netlink socket safely if the target program is not multi-threaded. * adding + socket + accept + passing * removing + close + shutdown? Could the technique I used in commit 1d78d22058da04eac7bf726c059d5c3fb193da08 help you? > + > + for (i = 0; i < 2; i++) { "2" is hardcoded here. sizeof(families)/sizeof(families[0]) may be better because it makes adding more families a bit easier. On Thu, 7 Aug 2014 18:17:12 +0530, zub...@gm... wrote: > void > printfd(struct tcb *tcp, int fd) > { > char path[PATH_MAX + 1]; > > - if (show_fd_path && getfdpath(tcp, fd, path, sizeof(path)) >= 0) > + if (show_fd_path == 1 && getfdpath(tcp, fd, path, sizeof(path)) >= 0) > tprintf("%d<%s>", fd, path); > + else if (show_fd_path > 1 && getfdpath(tcp, fd, path, sizeof(path)) >= 0) { > + char *ptr = NULL; > + int inodenr; > + ptr = strstr(path, "socket:["); > + if (ptr != path) { > + tprintf("%d<%s>", fd, path); > + } > + else { > + int retval; > + ptr = path + 8; > + path[strlen(path)-1] = '\0'; > + inodenr = strtol(ptr, NULL, 10); > + tprintf("%d<", fd); > + retval = printsockdetails(inodenr); > + if (retval == -1) tprintf("socket:[%d]",inodenr); > + tprints(">"); > + } > + } > else > tprintf("%d", fd); I cannot show even pseudo code but if possible, could you consider adding code to handle other fd type like pipe, device? Masatake YAMATO |
From: Zubin M. <zub...@gm...> - 2014-08-07 13:49:55
|
Hi Masatake ! Thank you for reviewing the patch! > > It is nice if you prepare a test case, too. See code/tests/. > Sure, I'll check out how tests are done and add relevant tests. > To make adding more families a bit easier how do you think use switch/case > instead of if/else? Like: > > switch (diag_msg->idiag_family) { > case AF_INET: > ... > case AF_INET6: > ... > } > Indeed, I'll make this improvement. > On Thu, 7 Aug 2014 18:17:12 +0530, zub...@gm... wrote: >> +/* Given an inode number of a socket, print out the details >> + * of the remote ip address and remote port */ >> +int >> +printsockdetails(int inodenr) >> +{ >> + int sockfd; >> + int i, j; >> + int protocols[] = {IPPROTO_TCP, IPPROTO_UDP}; >> + int families[] = {AF_INET, AF_INET6}; >> + >> + //Create the monitoring socket >> + if((sockfd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_INET_DIAG)) == -1) >> + return -1; > > Do we have to create a netlink socket each time printsockdetails is inovked? > How do you think cache the response from the netlink socket? This is interesting -- perhaps I could work on adding this in as part of a second patch? I could also add in the option to resolve ports and ip addresses along with that patch. That way it would be easier to review(and improve upon the patch). Caching sounds useful too, especially in cases where there are lots of connections. In effect, I'd need a fast lookup from inode number to an ip address and port(I dont have to keep all ips/ports in memory, just the ones corresponding to the inode number I've looked up, I guess). > > System calls that adding and removing a socket from fd table of process are > enumerable. So you can cache the response from the netlink socket safely > if the target program is not multi-threaded. > > * adding > > + socket > + accept > + passing > > * removing > > + close > + shutdown? > > > Could the technique I used in commit 1d78d22058da04eac7bf726c059d5c3fb193da08 > help you? I'll check this commit out and reply asap. > >> + >> + for (i = 0; i < 2; i++) { > > "2" is hardcoded here. sizeof(families)/sizeof(families[0]) may be better > because it makes adding more families a bit easier. Thanks, I'll fix this. > > On Thu, 7 Aug 2014 18:17:12 +0530, zub...@gm... wrote: >> void >> printfd(struct tcb *tcp, int fd) >> { >> char path[PATH_MAX + 1]; >> >> - if (show_fd_path && getfdpath(tcp, fd, path, sizeof(path)) >= 0) >> + if (show_fd_path == 1 && getfdpath(tcp, fd, path, sizeof(path)) >= 0) >> tprintf("%d<%s>", fd, path); >> + else if (show_fd_path > 1 && getfdpath(tcp, fd, path, sizeof(path)) >= 0) { >> + char *ptr = NULL; >> + int inodenr; >> + ptr = strstr(path, "socket:["); >> + if (ptr != path) { >> + tprintf("%d<%s>", fd, path); >> + } >> + else { >> + int retval; >> + ptr = path + 8; >> + path[strlen(path)-1] = '\0'; >> + inodenr = strtol(ptr, NULL, 10); >> + tprintf("%d<", fd); >> + retval = printsockdetails(inodenr); >> + if (retval == -1) tprintf("socket:[%d]",inodenr); >> + tprints(">"); >> + } >> + } >> else >> tprintf("%d", fd); > > I cannot show even pseudo code but if possible, could you consider > adding code to handle other fd type like pipe, device? Sounds interesting, sure, I could consider doing this too. Thanks! -- zm |
From: Masatake Y. <ya...@re...> - 2014-08-07 14:24:16
|
Hi, On Thu, 7 Aug 2014 19:19:47 +0530, Zubin Mithra <zub...@gm...> wrote: >> >> System calls that adding and removing a socket from fd table of process are >> enumerable. So you can cache the response from the netlink socket safely >> if the target program is not multi-threaded. >> >> * adding >> >> + socket >> + accept >> + passing >> >> * removing >> >> + close >> + shutdown? >> >> >> Could the technique I used in commit 1d78d22058da04eac7bf726c059d5c3fb193da08 >> help you? > > I'll check this commit out and reply asap. After thinking, you may not have to track the adding. Not in a long span, we can use inode number of socket can be used as a key for search information from cache. The inode number can be used as an identifier in system global. Nice. close() and shutdown() must be tracked to avoid overflowing of cache area. consider stracing following broken code: while (1) { n = socket (...); close(n); } In the latest linux What I checked are linux/net/socket.c::sock_alloc inode->i_ino = get_next_ino(); fs/inode.c::get_next_ino *p = ++res; put_cpu_var(last_ino); return res; Masatake YAMATO |
From: <zub...@gm...> - 2014-08-08 06:39:43
|
From: Zubin Mithra <zub...@gm...> * defs.h: Add Add header files netinet/in.h, sys/socket.h, arpa/inet.h, linux/netlink.h and linux/inet_diag.h. Change type of show_fd_path to unsigned int. Add macros SOCK_DIAG_BY_FAMILY, SOCKET_BUFFER_SIZE. Add structs sock_diag_req, inet_diag_req_v2. * strace.c (init): Change usage of show_fd_path. * util.c (parse_response): New function to parse and print ip, port from a message response. (send_query): New function. (receive_responses): New function. (printsockdetails): New function. (printfd): Modified to use printsockdetails. Signed-off-by: Zubin Mithra <zub...@gm...> --- defs.h | 24 ++++++++++- strace.c | 4 +- util.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 172 insertions(+), 4 deletions(-) diff --git a/defs.h b/defs.h index 1a3b483..6959cdb 100644 --- a/defs.h +++ b/defs.h @@ -67,6 +67,11 @@ #include <time.h> #include <sys/time.h> #include <sys/syscall.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <linux/netlink.h> +#include <linux/inet_diag.h> #ifndef HAVE_STRERROR const char *strerror(int); @@ -562,7 +567,7 @@ extern bool iflag; extern bool count_wallclock; extern unsigned int qflag; extern bool not_failing_only; -extern bool show_fd_path; +extern unsigned int show_fd_path; extern bool hide_log_until_execve; /* are we filtering traces based on paths? */ extern const char **paths_selected; @@ -580,6 +585,23 @@ extern unsigned os_release; #undef KERNEL_VERSION #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#define SOCK_DIAG_BY_FAMILY 20 +#define SOCKET_BUFFER_SIZE (getpagesize() < 8192L ? getpagesize() : 8192L) + +struct sock_diag_req { + __u8 sdiag_family; + __u8 sdiag_protocol; +}; + +struct inet_diag_req_v2 { + __u8 sdiag_family; + __u8 sdiag_protocol; + __u8 idiag_ext; + __u8 pad; + __u32 idiag_states; + struct inet_diag_sockid id; +}; + enum bitness_t { BITNESS_CURRENT = 0, BITNESS_32 }; void error_msg(const char *fmt, ...) __attribute__ ((format(printf, 1, 2))); diff --git a/strace.c b/strace.c index 4154cde..2bc5c67 100644 --- a/strace.c +++ b/strace.c @@ -129,7 +129,7 @@ static int post_attach_sigstop = TCB_IGNORE_ONE_SIGSTOP; bool not_failing_only = 0; /* Show path associated with fd arguments */ -bool show_fd_path = 0; +unsigned int show_fd_path = 0; static bool detach_on_execve = 0; /* Are we "strace PROG" and need to skip detach on first execve? */ @@ -1734,7 +1734,7 @@ init(int argc, char *argv[]) xflag++; break; case 'y': - show_fd_path = 1; + show_fd_path++; break; case 'v': qualify("abbrev=none"); diff --git a/util.c b/util.c index 33482d5..5608449 100644 --- a/util.c +++ b/util.c @@ -404,13 +404,159 @@ printnum_int(struct tcb *tcp, long addr, const char *fmt) tprints("]"); } +int +parse_response(struct inet_diag_msg *diag_msg, int inodenr) { + char remote_addr_buf[INET6_ADDRSTRLEN]; + int rport; + + if (diag_msg->idiag_inode != inodenr) + return -1; + + memset(remote_addr_buf, 0, sizeof(remote_addr_buf)); + + switch(diag_msg->idiag_family) { + case AF_INET: + inet_ntop(diag_msg->idiag_family, + (struct in_addr*) &(diag_msg->id.idiag_dst), + remote_addr_buf, INET_ADDRSTRLEN); + break; + case AF_INET6: + inet_ntop(diag_msg->idiag_family, + (struct in_addr*) &(diag_msg->id.idiag_dst), + remote_addr_buf, INET6_ADDRSTRLEN); + break; + default: + 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[4]; + + 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 +parse_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(int inodenr) +{ + int sockfd; + int i, j; + int protocols[] = {IPPROTO_TCP, IPPROTO_UDP}; + int families[] = {AF_INET, AF_INET6}; + int plen = sizeof(protocols)/sizeof(protocols[0]); + int flen = sizeof(families)/sizeof(families[0]); + + //Create the monitoring socket + if((sockfd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_INET_DIAG)) == -1) + return -1; + + for (i = 0; i < plen; i++) { + for (j = 0; j < flen; j++) { + if (send_query(sockfd, protocols[i], families[j]) < 0) { + close(sockfd); + return -1; + } + if (parse_responses(sockfd, inodenr) == 0) { + close(sockfd); + return 0; + } + } + } + close(sockfd); + return -1; +} + void printfd(struct tcb *tcp, int fd) { char path[PATH_MAX + 1]; - if (show_fd_path && getfdpath(tcp, fd, path, sizeof(path)) >= 0) + if (show_fd_path == 1 && getfdpath(tcp, fd, path, sizeof(path)) >= 0) tprintf("%d<%s>", fd, path); + else if (show_fd_path > 1 && getfdpath(tcp, fd, path, sizeof(path)) >= 0) { + char *ptr = NULL; + int inodenr; + ptr = strstr(path, "socket:["); + if (ptr != path) { + tprintf("%d<%s>", fd, path); + } + else { + int retval; + ptr = path + 8; + path[strlen(path)-1] = '\0'; + inodenr = strtol(ptr, NULL, 10); + tprintf("%d<", fd); + retval = printsockdetails(inodenr); + if (retval == -1) tprintf("socket:[%d]",inodenr); + tprints(">"); + } + } else tprintf("%d", fd); } -- 1.8.4 |
From: Dmitry V. L. <ld...@al...> - 2014-08-09 11:12:15
|
On Fri, Aug 08, 2014 at 12:09:20PM +0530, zub...@gm... wrote: > * defs.h: Add Add header files netinet/in.h, sys/socket.h, > arpa/inet.h, linux/netlink.h and linux/inet_diag.h. > Change type of show_fd_path to unsigned int. > Add macros SOCK_DIAG_BY_FAMILY, SOCKET_BUFFER_SIZE. > Add structs sock_diag_req, inet_diag_req_v2. > * strace.c (init): Change usage of show_fd_path. > * util.c (parse_response): New function to parse and > print ip, port from a message response. > (send_query): New function. > (receive_responses): New function. > (printsockdetails): New function. > (printfd): Modified to use printsockdetails. > > Signed-off-by: Zubin Mithra <zub...@gm...> > --- > defs.h | 24 ++++++++++- > strace.c | 4 +- > util.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- > 3 files changed, 172 insertions(+), 4 deletions(-) > > diff --git a/defs.h b/defs.h > index 1a3b483..6959cdb 100644 > --- a/defs.h > +++ b/defs.h > @@ -67,6 +67,11 @@ > #include <time.h> > #include <sys/time.h> > #include <sys/syscall.h> > +#include <netinet/in.h> > +#include <sys/socket.h> > +#include <arpa/inet.h> > +#include <linux/netlink.h> > +#include <linux/inet_diag.h> defs.h is included by every translation unit, so please do not include new headers there. > @@ -580,6 +585,23 @@ extern unsigned os_release; > #undef KERNEL_VERSION > #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) > > +#define SOCK_DIAG_BY_FAMILY 20 This macro is defined by <linux/sock_diag.h> > +#define SOCKET_BUFFER_SIZE (getpagesize() < 8192L ? getpagesize() : 8192L) We have get_pagesize() defined in mem.c - please export and use it instead. > +struct sock_diag_req { > + __u8 sdiag_family; > + __u8 sdiag_protocol; > +}; This structure is defined by <linux/sock_diag.h> > +struct inet_diag_req_v2 { > + __u8 sdiag_family; > + __u8 sdiag_protocol; > + __u8 idiag_ext; > + __u8 pad; > + __u32 idiag_states; > + struct inet_diag_sockid id; > +}; This structure is defined by <linux/inet_diag.h> > diff --git a/util.c b/util.c > index 33482d5..5608449 100644 > --- a/util.c > +++ b/util.c > @@ -404,13 +404,159 @@ printnum_int(struct tcb *tcp, long addr, const char *fmt) > tprints("]"); > } > > +int > +parse_response(struct inet_diag_msg *diag_msg, int inodenr) { [...] > +int > +send_query(int sockfd, int proto, int family) { [...] > +int > +parse_responses(int sockfd, int inodenr) { [...] > +/* Given an inode number of a socket, print out the details > + * of the remote ip address and remote port */ > +int > +printsockdetails(int inodenr) [...] Please create a new translation unit and move all this new code (functions and declarations for them) there. Note that idiag_inode has type uint32_t. > void > printfd(struct tcb *tcp, int fd) > { > char path[PATH_MAX + 1]; > > - if (show_fd_path && getfdpath(tcp, fd, path, sizeof(path)) >= 0) > + if (show_fd_path == 1 && getfdpath(tcp, fd, path, sizeof(path)) >= 0) > tprintf("%d<%s>", fd, path); > + else if (show_fd_path > 1 && getfdpath(tcp, fd, path, sizeof(path)) >= 0) { 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); -- ldv |
From: Mike F. <va...@ge...> - 2014-08-09 14:04:17
Attachments:
signature.asc
|
On Fri 08 Aug 2014 12:09:20 zub...@gm... wrote: > --- a/defs.h > +++ b/defs.h > @@ -67,6 +67,11 @@ > #include <time.h> > #include <sys/time.h> > #include <sys/syscall.h> > +#include <netinet/in.h> > +#include <sys/socket.h> > +#include <arpa/inet.h> > +#include <linux/netlink.h> > +#include <linux/inet_diag.h> strace isn't linux specific, so any linux-specific code has to be behind LINUX checks > +int > +parse_response(struct inet_diag_msg *diag_msg, int inodenr) { uncuddle the brace for funcs > + char remote_addr_buf[INET6_ADDRSTRLEN]; > + int rport; > + > + if (diag_msg->idiag_inode != inodenr) > + return -1; > + > + memset(remote_addr_buf, 0, sizeof(remote_addr_buf)); do you really need to clear the whole thing every time ? can't you check return values of inet_ntop below instead ? > +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[4]; down below you use iov[0] and iov[1] ... do you need [2] and [3] ? > + memset(&msg, 0, sizeof(msg)); > + memset(&sa, 0, sizeof(sa)); > + memset(&nlh, 0, sizeof(nlh)); > + memset(&conn_req, 0, sizeof(conn_req)); do you need to zero these out when you initialize their content below ? > + > +/* Given an inode number of a socket, print out the details > + * of the remote ip address and remote port */ > +int > +printsockdetails(int inodenr) > +{ > + int sockfd; > + int i, j; > + int protocols[] = {IPPROTO_TCP, IPPROTO_UDP}; > + int families[] = {AF_INET, AF_INET6}; > + int plen = sizeof(protocols)/sizeof(protocols[0]); > + int flen = sizeof(families)/sizeof(families[0]); use ARRAY_SIZE i think i/j/plen/flen should be size_t > + //Create the monitoring socket we use /* Comments. */ > + if((sockfd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_INET_DIAG)) == -1) split the assignment out to a line by itself > + return -1; > + > + for (i = 0; i < plen; i++) { > + for (j = 0; j < flen; j++) { > + if (send_query(sockfd, protocols[i], families[j]) < 0) { > + close(sockfd); > + return -1; > + } > + if (parse_responses(sockfd, inodenr) == 0) { > + close(sockfd); > + return 0; > + } > + } > + } > + close(sockfd); > + return -1; i'd set up a return value, set it to -1 at the top of the loop, and then only set it to 0 when things succeed. then the add a label to the close/return at the end, and change the other close/return statements to a goto. -mike |
From: Zubin M. <zub...@gm...> - 2014-08-11 07:58:29
|
Hi, Thank you for the review, Dmitry, Mike! I'll send out a patch soon. > > > + memset(&msg, 0, sizeof(msg)); > > + memset(&sa, 0, sizeof(sa)); > > + memset(&nlh, 0, sizeof(nlh)); > > + memset(&conn_req, 0, sizeof(conn_req)); > > do you need to zero these out when you initialize their content below ? > Indeed, the calls do seem to fail when they are not initialised. Thank you! Zubin |
From: <zub...@gm...> - 2014-08-11 08:47:39
|
From: Zubin Mithra <zub...@gm...> * 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 <zub...@gm...> --- 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 |
From: Zubin M. <zub...@gm...> - 2014-08-11 08:55:13
|
Hello all, This is the latest patch for extended socket fd decoding. A few points :- > + > +#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 > Unless I'm mistaken this header is present on all linux systems in /usr/include even with the dev packages installed. > + > +#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 > > inet_diag_req_v2 is not present on all Linux systems. Thanks, -- zm |
From: Zubin M. <zub...@gm...> - 2014-08-11 09:07:14
|
> > >> >> > Unless I'm mistaken this header is present on all linux systems in > /usr/include even with the dev packages installed. > > Typo, sorry. "this header is *not* present on all...." Thanks, -- zm |
From: <zub...@gm...> - 2014-08-11 08:51:22
|
From: Zubin Mithra <zub...@gm...> * 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 <zub...@gm...> --- 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 |
From: Dmitry V. L. <ld...@al...> - 2014-08-20 22:53:54
|
On Mon, Aug 11, 2014 at 02:21:01PM +0530, zub...@gm... wrote: [...] > 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]) It has to be <linux/inet_diag.h>, otherwise HAVE_STRUCT_INET_DIAG_REQ_V2 is never going to be defined. [...] > 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> What is <netlink/netlink.h>? I suppose this header is not needed. > +#ifdef HAVE_LINUX_NETLINK_H > +# include <linux/netlink.h> > +#endif You are conditionally include <linux/netlink.h> here, but later unconditionally use constants defined in that header. I think you can safely assume that <linux/netlink.h> is available. The only feasible alternative is to define dummy printsockdetails() when <linux/netlink.h> is not available. > +#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 We do not use kernel specific types, please use uint8_t instead. Since you have to define SOCK_DIAG_BY_FAMILY and sock_diag_req anyway (<linux/sock_diag.h> may not be available before linux 3.3), why not just create linux/sock_diag.h file? > +#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 All that was said about <linux/sock_diag.h> is also applicable to this case. > +int > +parse_response(struct inet_diag_msg *diag_msg, int inodenr) This function has to be static. diag_msg could be declared const. inodenr has to be the same type all over the code. > +{ > + char remote_addr_buf[INET6_ADDRSTRLEN]; > + int rport; rport has to be uint16_t. > + char *ret; This has to be const. > + > + 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; These two inet_ntop calls differ by one socklen_t argument, so you could write this shorter: socklen_t size; switch(diag_msg->idiag_family) { case AF_INET: size = INET_ADDRSTRLEN; break; case AF_INET6: size = INET6_ADDRSTRLEN; break; default: return -1; } if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_dst, remote_addr_buf, size) || !remote_addr_buf[0]) return -1; > + rport = ntohs(diag_msg->id.idiag_dport); > + tprintf("%s:%d", remote_addr_buf, rport); This has to be %u. > + 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; I tested this patch on a x86_64 system with a fresh kernel. It always returns NLMSG_ERROR. I suppose something in send_query() is wrong. -- ldv |
From: Zubin M. <zub...@gm...> - 2014-08-24 08:06:05
Attachments:
signature.asc
|
On Thu, Aug 21, 2014 at 02:53:46AM +0400, Dmitry V. Levin wrote: > On Mon, Aug 11, 2014 at 02:21:01PM +0530, zub...@gm... wrote: [...] > if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_dst, > remote_addr_buf, size) || !remote_addr_buf[0]) > return -1; Also note for unconnected sockets idiag_dst/idiag_dport are zero, and idiag_src/idiag_sport have to be used instead. -- ldv ------------------------------------------------------------------------------ Slashdot TV. Video for Nerds. Stuff that matters. http://tv.slashdot.org/_______________________________________________ Strace-devel mailing list Str...@li... https://lists.sourceforge.net/lists/listinfo/strace-devel |
From: Dmitry V. L. <ld...@al...> - 2014-08-21 02:23:28
|
On Thu, Aug 21, 2014 at 02:53:46AM +0400, Dmitry V. Levin wrote: [...] > > + else if (nlh->nlmsg_type == NLMSG_ERROR) > > + return -1; > > > I tested this patch on a x86_64 system with a fresh kernel. > It always returns NLMSG_ERROR. > I suppose something in send_query() is wrong. Actually, it is quite linux specific: SOCK_DIAG_BY_FAMILY needs tcp_diag kernel module to handle IPPROTO_TCP, and udp_diag - for IPPROTO_UDP sockets. -- ldv |
From: Dmitry V. L. <ld...@al...> - 2014-08-21 02:27:17
|
On Thu, Aug 21, 2014 at 02:53:46AM +0400, Dmitry V. Levin wrote: > On Mon, Aug 11, 2014 at 02:21:01PM +0530, zub...@gm... wrote: [...] > if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_dst, > remote_addr_buf, size) || !remote_addr_buf[0]) > return -1; Also note for unconnected sockets idiag_dst/idiag_dport are zero, and idiag_src/idiag_sport have to be used instead. -- ldv |
From: Zubin M. <zub...@gm...> - 2014-08-24 14:39:01
Attachments:
signature.asc
|
Hi Dmitry, > Actually, it is quite linux specific: SOCK_DIAG_BY_FAMILY needs tcp_diag > kernel module to handle IPPROTO_TCP, and udp_diag - for IPPROTO_UDP > sockets. I’m not sure I understand the problem here — could you tell me which kernel version you had used so that I could try compiling that kernel here at my end? Thanks, -- zm |
From: Zubin M. <zub...@gm...> - 2014-08-24 14:44:33
Attachments:
signature.asc
|
Hi Dmitry, On 21-Aug-2014, at 4:27, Dmitry V. Levin <ld...@al...> wrote: > On Thu, Aug 21, 2014 at 02:53:46AM +0400, Dmitry V. Levin wrote: >> On Mon, Aug 11, 2014 at 02:21:01PM +0530, zub...@gm... wrote: > [...] >> if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_dst, >> remote_addr_buf, size) || !remote_addr_buf[0]) >> return -1; > > Also note for unconnected sockets idiag_dst/idiag_dport are zero, and > idiag_src/idiag_sport have to be used instead. Currently for unconnected sockets, it would print out the socket inode number(indicating that the socket is unconnected). Would printing idiag_sport instead be confusing? Thanks, -- zm |
From: Dmitry V. L. <ld...@al...> - 2014-08-25 17:15:04
|
On Sun, Aug 24, 2014 at 04:44:23PM +0200, Zubin Mithra wrote: > On 21-Aug-2014, at 4:27, Dmitry V. Levin <ld...@al...> wrote: > > On Thu, Aug 21, 2014 at 02:53:46AM +0400, Dmitry V. Levin wrote: > >> On Mon, Aug 11, 2014 at 02:21:01PM +0530, zub...@gm... wrote: > > [...] > >> if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_dst, > >> remote_addr_buf, size) || !remote_addr_buf[0]) > >> return -1; > > > > Also note for unconnected sockets idiag_dst/idiag_dport are zero, and > > idiag_src/idiag_sport have to be used instead. > > Currently for unconnected sockets, it would print out the socket inode number(indicating that the socket is unconnected). Would printing idiag_sport instead be confusing? There are sockets with zero dst address:port and non-zero src address:port. For example, in your snapshot (https://gist.github.com/eQu1NoX/5fe4d144a6d818382399): accept(3<0.0.0.0:0>, {sa_family=AF_INET, sin_port=htons(48435), sin_addr=inet_addr("127.0.0.1")}, [16]) = 4 I think it would be less confusing to print both src and dst address:port when dst address:port is non-zero, for example: accept(3<0.0.0.0:7171>, {sa_family=AF_INET, sin_port=htons(48435), sin_addr=inet_addr("127.0.0.1")}, [16]) = 4<127.0.0.1:7171->127.0.0.1:48435> static bool parse_response(const struct inet_diag_msg *diag_msg, const unsigned long inode) { static const char zero_addr[sizeof(struct in6_addr)]; size_t addr_size; socklen_t text_size; if (diag_msg->idiag_inode != inode) return false; switch(diag_msg->idiag_family) { case AF_INET: addr_size = sizeof(struct in_addr); text_size = INET_ADDRSTRLEN; break; case AF_INET6: addr_size = sizeof(struct in6_addr); text_size = INET6_ADDRSTRLEN; break; default: return false; } char src_buf[text_size]; if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_src, src_buf, text_size)) return false; if (diag_msg->id.idiag_dport || memcmp(zero_addr, diag_msg->id.idiag_dst, addr_size)) { char dst_buf[text_size]; if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_dst, dst_buf, text_size)) return false; tprintf("%s:%u->%s:%u", src_buf, ntohs(diag_msg->id.idiag_sport), dst_buf, ntohs(diag_msg->id.idiag_dport)); } else { tprintf("%s:%u", src_buf, ntohs(diag_msg->id.idiag_sport)); } return true; } -- ldv |
From: Dmitry V. L. <ld...@al...> - 2014-08-25 17:20:35
|
On Sun, Aug 24, 2014 at 04:38:51PM +0200, Zubin Mithra wrote: > Hi Dmitry, > > > Actually, it is quite linux specific: SOCK_DIAG_BY_FAMILY needs tcp_diag > > kernel module to handle IPPROTO_TCP, and udp_diag - for IPPROTO_UDP > > sockets. > > I’m not sure I understand the problem here — could you tell me which kernel version you had used so that I could try compiling that kernel here at my end? The problem, if you call this situation a problem, is that SOCK_DIAG_BY_FAMILY is usually implemented by tcp_diag and udp_diag kernel modules, and when these modules are not loaded and automatic loading is not enabled (as it happened in my case), strace -yy feature won't work. -- ldv |
From: Zubin M. <zub...@gm...> - 2014-08-26 16:28:56
Attachments:
signature.asc
|
> I think it would be less confusing to print both src and dst address:port > when dst address:port is non-zero, for example: > accept(3<0.0.0.0:7171>, {sa_family=AF_INET, sin_port=htons(48435), sin_addr=inet_addr("127.0.0.1")}, [16]) = 4<127.0.0.1:7171->127.0.0.1:48435> > Got it, thanks Dmitry, I’ll send over a patch soon. -- zm |
From: Zubin M. <zub...@gm...> - 2014-08-26 16:30:19
Attachments:
signature.asc
|
>> Hi Dmitry, >> >>> Actually, it is quite linux specific: SOCK_DIAG_BY_FAMILY needs tcp_diag >>> kernel module to handle IPPROTO_TCP, and udp_diag - for IPPROTO_UDP >>> sockets. >> >> I’m not sure I understand the problem here — could you tell me which kernel version you had used so that I could try compiling that kernel here at my end? > > The problem, if you call this situation a problem, is that > SOCK_DIAG_BY_FAMILY is usually implemented by tcp_diag and udp_diag kernel > modules, and when these modules are not loaded and automatic loading is > not enabled (as it happened in my case), strace -yy feature won't work. > I see, should we document this somewhere?(Readme-hacking?) Thanks, -- zm |
From: Dmitry V. L. <ld...@al...> - 2014-08-26 18:23:21
|
On Tue, Aug 26, 2014 at 06:30:10PM +0200, Zubin Mithra wrote: > >> Hi Dmitry, > >> > >>> Actually, it is quite linux specific: SOCK_DIAG_BY_FAMILY needs tcp_diag > >>> kernel module to handle IPPROTO_TCP, and udp_diag - for IPPROTO_UDP > >>> sockets. > >> > >> I’m not sure I understand the problem here — could you tell me which kernel version you had used so that I could try compiling that kernel here at my end? > > > > The problem, if you call this situation a problem, is that > > SOCK_DIAG_BY_FAMILY is usually implemented by tcp_diag and udp_diag kernel > > modules, and when these modules are not loaded and automatic loading is > > not enabled (as it happened in my case), strace -yy feature won't work. > > I see, should we document this somewhere?(Readme-hacking?) I'd prefer the manual page. :) -- ldv |