This patch extends -yy option; the peer address of a unix socket can be printed like an inet socket.
About a listening socket, its socket inode and socket path are printed. About an accepted socket, its socket inode, the peer inode, and the socket path are printed. About a client socket, its socket inode and the peer inode are printed. An example of server side with netcat: $ ./strace -yy -e network nc -l -U /tmp/example.sock socket(PF_LOCAL, SOCK_STREAM, 0) = 3 setsockopt(3<UNIX:[14728348]>, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 bind(3<UNIX:[14728348]>, {sa_family=AF_LOCAL, sun_path="/tmp/example.sock"}, 19) = 0 listen(3<UNIX:[14728348,"/tmp/example.sock"]>, 10) = 0 accept(3<UNIX:[14728348,"/tmp/example.sock"]>, {sa_family=AF_LOCAL, NULL}, [2]) = 4<UNIX:[14727246->14727245,"/tmp/example.sock"]> recvfrom(4<UNIX:[14727246->14727245,"/tmp/example.sock"]>, "INPUT\n", 8192, 0, NULL, NULL) = 6 INPUT An example of client side with netcat: $ ./strace -yy -e network nc -U /tmp/example.sock socket(PF_LOCAL, SOCK_STREAM, 0) = 3 connect(3<UNIX:[14727245]>, {sa_family=AF_LOCAL, sun_path="/tmp/example.sock"}, 19) = 0 getsockopt(3<UNIX:[14727245]>, SOL_SOCKET, SO_ERROR, [0], [4]) = 0 INPUT ... sendto(3<UNIX:[14727245->14727246]>, "INPUT\n", 6, 0, NULL, 0) = 6 * socketutils.c (unix_print): New function. (unix_send_query): New function. (inet_send_query): Rename send_query. (unix_parse_response): New function. (inet_parse_response): Rename parse_response. (print_sockaddr_by_inode): Call unix_print. Replace NETLINK_INET_DIAG with NETLINK_SOCK_DIAG. The values of the both names are the same but NETLINK_SOCK_DIAG impresses people as more generic name. (receive_responses): Add a new argument named parser. parser deals with the protocol specific evaluation of data parts of diag messages. * linux/unix_diag.h: New file. changes in v2 patch: * Change the output format, * Remove shrunk version of rtnelink.h. changes in v3 patch: * Use uintN_t instead of _uN (N = 8, 16, and 32) in unix_diag_req definition. * Remove incorrect comment about including file. * Define UNIX_PATH_MAX as an value calculated from sockaddr_un. * Remove unnecessary code for initizliing a field in structure literal. * Surround "or" operators with spaces. * Unify the variable name convention (s/rtalen/rta_len/). * Remove redundant local variables in unix_parse_response. * Remove redundant branch in unix_parse_response. * Put brances on line after. * Rename local variable `l' to `path_len'. * Decode a path for abstract unix socket in the same way as in `printsock' does'. Signed-off-by: Masatake YAMATO <yam...@redhat.com> --- linux/unix_diag.h | 25 +++++++++++ socketutils.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 148 insertions(+), 7 deletions(-) create mode 100644 linux/unix_diag.h diff --git a/linux/unix_diag.h b/linux/unix_diag.h new file mode 100644 index 0000000..3329ccb --- /dev/null +++ b/linux/unix_diag.h @@ -0,0 +1,25 @@ +struct unix_diag_req { + uint8_t sdiag_family; + uint8_t sdiag_protocol; + uint16_t pad; + uint32_t udiag_states; + uint32_t udiag_ino; + uint32_t udiag_show; + uint32_t udiag_cookie[2]; +}; + +#define UDIAG_SHOW_NAME 0x00000001 +#define UDIAG_SHOW_PEER 0x00000004 + +struct unix_diag_msg { + uint8_t udiag_family; + uint8_t udiag_type; + uint8_t udiag_state; + uint8_t pad; + + uint32_t udiag_ino; + uint32_t udiag_cookie[2]; +}; + +#define UNIX_DIAG_NAME 0 +#define UNIX_DIAG_PEER 2 diff --git a/socketutils.c b/socketutils.c index f57c304..fbc8515 100644 --- a/socketutils.c +++ b/socketutils.c @@ -5,9 +5,16 @@ #include <linux/netlink.h> #include <linux/sock_diag.h> #include <linux/inet_diag.h> +#include <linux/unix_diag.h> +#include <linux/rtnetlink.h> + +#include <sys/un.h> +#ifndef UNIX_PATH_MAX +#define UNIX_PATH_MAX sizeof(((struct sockaddr_un *)0)->sun_path) +#endif static bool -send_query(const int fd, const int family, const int proto) +inet_send_query(const int fd, const int family, const int proto) { struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK @@ -49,8 +56,9 @@ send_query(const int fd, const int family, const int proto) } static bool -parse_response(const struct inet_diag_msg *diag_msg, const unsigned long inode) +inet_parse_response(const void *data, int data_len, const unsigned long inode) { + const struct inet_diag_msg *diag_msg = data; static const char zero_addr[sizeof(struct in6_addr)]; socklen_t addr_size, text_size; @@ -95,7 +103,8 @@ parse_response(const struct inet_diag_msg *diag_msg, const unsigned long inode) } static bool -receive_responses(const int fd, const unsigned long inode) +receive_responses(const int fd, const unsigned long inode, + bool (* parser) (const void*, int, const unsigned long)) { static char buf[8192]; struct sockaddr_nl nladdr = { @@ -132,7 +141,7 @@ receive_responses(const int fd, const unsigned long inode) case NLMSG_ERROR: return false; } - if (parse_response(NLMSG_DATA(h), inode)) + if (parser(NLMSG_DATA(h), h->nlmsg_len, inode)) return true; } } @@ -141,10 +150,115 @@ receive_responses(const int fd, const unsigned long inode) static bool inet_print(int fd, int family, int protocol, const unsigned long inode) { - return send_query(fd, family, protocol) - && receive_responses(fd, inode); + return inet_send_query(fd, family, protocol) + && receive_responses(fd, inode, inet_parse_response); +} + + +static bool +unix_send_query(const int fd, const unsigned long inode) +{ + struct sockaddr_nl nladdr = { + .nl_family = AF_NETLINK + }; + struct { + struct nlmsghdr nlh; + struct unix_diag_req udr; + } req = { + .nlh = { + .nlmsg_len = sizeof(req), + .nlmsg_type = SOCK_DIAG_BY_FAMILY, + .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST + }, + .udr = { + .sdiag_family = AF_UNIX, + .udiag_ino = inode, + .udiag_states = -1, + .udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER, + } + }; + struct iovec iov = { + .iov_base = &req, + .iov_len = sizeof(req) + }; + struct msghdr msg = { + .msg_name = (void*)&nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1 + }; + + for (;;) { + if (sendmsg(fd, &msg, 0) < 0) { + if (errno == EINTR) + continue; + return false; + } + return true; + } +} + +static bool +unix_parse_response(const void *data, int data_len, const unsigned long inode) +{ + const struct unix_diag_msg *diag_msg = data; + int rta_len = data_len - NLMSG_LENGTH(sizeof(*diag_msg)); + struct rtattr *attr; + size_t path_len = 0; + char path[UNIX_PATH_MAX + 1] = { [0] = '\0' }; + + uint32_t peer = 0; + if (diag_msg->udiag_ino != inode) + return false; + if (diag_msg->udiag_family != AF_UNIX) + return false; + + attr = (struct rtattr*) (diag_msg +1); + while (RTA_OK(attr, rta_len)) { + switch (attr->rta_type) { + case UNIX_DIAG_NAME: + if (!path_len) { + path_len = RTA_PAYLOAD(attr); + if (path_len > UNIX_PATH_MAX) + path_len = UNIX_PATH_MAX; + memcpy(path, RTA_DATA(attr), path_len); + break; + } + case UNIX_DIAG_PEER: + if (RTA_PAYLOAD(attr) >= 4) + peer = *(uint32_t *)RTA_DATA(attr); + break; + } + attr = RTA_NEXT(attr, rta_len); + } + + /* prints the getting information with following format: + * "UNIX:[" SELF_INODE [ "->" PEER_INODE ][ "," SOCKET_FILE ] "]" */ + if (peer || path_len) { + tprintf("UNIX:[%lu", inode); + if (peer) + tprintf("->%u", peer); + if (path_len) { + if (path[0] == '\0') + tprintf(",@\"%s\"", path + 1); + else + tprintf(",\"%s\"", path); + } + tprints("]"); + return true; + } + else + return false; +} + +static bool +unix_print(int fd, const unsigned long inode) +{ + return unix_send_query(fd, inode) + && receive_responses(fd, inode, unix_parse_response); } + /* Given an inode number of a socket, print out the details * of the ip address and port. */ bool @@ -153,7 +267,7 @@ print_sockaddr_by_inode(const unsigned long inode, const char *proto_name) int fd; bool r = false; - fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG); + fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG); if (fd < 0) return false; @@ -166,6 +280,8 @@ print_sockaddr_by_inode(const unsigned long inode, const char *proto_name) r = inet_print(fd, AF_INET6, IPPROTO_TCP, inode); else if (strcmp(proto_name, "UDPv6") == 0) r = inet_print(fd, AF_INET6, IPPROTO_UDP, inode); + else if (strcmp(proto_name, "UNIX") == 0) + r = unix_print(fd, inode); } else { const int families[] = {AF_INET, AF_INET6}; const int protocols[] = {IPPROTO_TCP, IPPROTO_UDP}; -- 1.9.3 ------------------------------------------------------------------------------ Dive into the World of Parallel Programming! The Go Parallel Website, sponsored by Intel and developed in partnership with Slashdot Media, is your hub for all things parallel software development, from weekly thought leadership blogs to news, videos, case studies, tutorials and more. Take a look and join the conversation now. http://goparallel.sourceforge.net _______________________________________________ Strace-devel mailing list Strace-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/strace-devel