[PATCHv2 2/3] Support unix sockets in -yy option
Masatake YAMATO
yamato at redhat.com
Wed Dec 10 03:55:07 UTC 2014
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.
Signed-off-by: Masatake YAMATO <yamato at redhat.com>
---
linux/unix_diag.h | 25 ++++++++++
socketutils.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 156 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..92bcdbe
--- /dev/null
+++ b/linux/unix_diag.h
@@ -0,0 +1,25 @@
+struct unix_diag_req {
+ __u8 sdiag_family;
+ __u8 sdiag_protocol;
+ __u16 pad;
+ __u32 udiag_states;
+ __u32 udiag_ino;
+ __u32 udiag_show;
+ __u32 udiag_cookie[2];
+};
+
+#define UDIAG_SHOW_NAME 0x00000001
+#define UDIAG_SHOW_PEER 0x00000004
+
+struct unix_diag_msg {
+ __u8 udiag_family;
+ __u8 udiag_type;
+ __u8 udiag_state;
+ __u8 pad;
+
+ __u32 udiag_ino;
+ __u32 udiag_cookie[2];
+};
+
+#define UNIX_DIAG_NAME 0
+#define UNIX_DIAG_PEER 2
diff --git a/socketutils.c b/socketutils.c
index f57c304..e132173 100644
--- a/socketutils.c
+++ b/socketutils.c
@@ -5,9 +5,12 @@
#include <linux/netlink.h>
#include <linux/sock_diag.h>
#include <linux/inet_diag.h>
+#include <linux/unix_diag.h>
+#include <linux/rtnetlink.h> /* rtattr */
+#include <linux/un.h> /* For UNIX_PATH_MAX */
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 +52,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 +99,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 +137,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 +146,127 @@ 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,
+ .sdiag_protocol = 0,
+ .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 rtalen = data_len - NLMSG_LENGTH(sizeof(*diag_msg));
+ struct rtattr *attr;
+ bool r, found_path;
+ char path[UNIX_PATH_MAX + 1];
+ uint32_t peer = 0;
+
+ if (diag_msg->udiag_ino != inode)
+ return false;
+ if (diag_msg->udiag_family != AF_UNIX)
+ return false;
+ if (rtalen <= 0)
+ return false;
+
+ attr = (struct rtattr*) (diag_msg +1);
+ r = false;
+ found_path = false;
+ while(RTA_OK(attr, rtalen))
+ {
+ switch (attr->rta_type)
+ {
+ case UNIX_DIAG_NAME:
+ if (rtalen > 0)
+ {
+ size_t l = RTA_PAYLOAD(attr);
+
+ l = (l < UNIX_PATH_MAX)? l: UNIX_PATH_MAX;
+ memcpy(path, RTA_DATA(attr), l);
+ /* convert to C string */
+ path[l] = '\0';
+ /* make abstract socket printable with adding prefix @*/
+ if (path[0] == '\0')
+ path[0] = '@';
+ found_path = true;
+ r = true;
+ }
+ break;
+ case UNIX_DIAG_PEER:
+ if (RTA_PAYLOAD(attr) >= 4)
+ {
+ peer = *(uint32_t *)RTA_DATA(attr);
+ r = true;
+ }
+ break;
+ }
+ attr = RTA_NEXT(attr, rtalen);
+ }
+
+ /* prints the getting information with following format:
+ "UNIX:[" SELF_INODE [ "->" PEER_INODE ][ "," SOCKET_FILE ] "]" */
+ if (r) {
+ tprintf("UNIX:[%lu", inode);
+ if (peer)
+ tprintf("->%u", peer);
+ if (found_path)
+ tprintf(",%s", path);
+ tprints("]");
+ }
+ return r;
+}
+
+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 +275,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 +288,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
More information about the Strace-devel
mailing list