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 path and socket inode are printed.
About an accepted socket, its socket path, socket inode and peer inode
are printed.
About a client socket, its socket inode and 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:[12592606]>, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
   bind(3<UNIX:[12592606]>, {sa_family=AF_LOCAL, sun_path="/tmp/example.sock"}, 
19) = 0
   listen(3</tmp/example.sock,12592606>, 10) = 0
   accept(3</tmp/example.sock,12592606>, {sa_family=AF_LOCAL, NULL}, [2]) = 
4</tmp/example.sock,12593212->12591974>
   recvfrom(4</tmp/example.sock,12593212->12591974>, "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:[12591974]>, {sa_family=AF_LOCAL, 
sun_path="/tmp/example.sock"}, 19) = 0
   getsockopt(3<12591974->12593212>, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
   INPUT
   ...
   sendto(3<12591974->12593212>, "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.
* linux/rtnetlink.h: New file.

Signed-off-by: Masatake YAMATO <yam...@redhat.com>
---
 linux/rtnetlink.h |  14 ++++++
 linux/unix_diag.h |  25 ++++++++++
 socketutils.c     | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 174 insertions(+), 9 deletions(-)
 create mode 100644 linux/rtnetlink.h
 create mode 100644 linux/unix_diag.h

diff --git a/linux/rtnetlink.h b/linux/rtnetlink.h
new file mode 100644
index 0000000..545846b
--- /dev/null
+++ b/linux/rtnetlink.h
@@ -0,0 +1,14 @@
+struct rtattr {
+       unsigned short  rta_len;
+       unsigned short  rta_type;
+};
+#define RTA_ALIGNTO    4
+#define RTA_ALIGN(len) ( ((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1) )
+#define RTA_OK(rta,len) ((len) >= (int)sizeof(struct rtattr) && \
+                        (rta)->rta_len >= sizeof(struct rtattr) && \
+                        (rta)->rta_len <= (len))
+#define RTA_NEXT(rta,attrlen)  ((attrlen) -= RTA_ALIGN((rta)->rta_len), \
+                                (struct rtattr*)(((char*)(rta)) + 
RTA_ALIGN((rta)->rta_len)))
+#define RTA_LENGTH(len)        (RTA_ALIGN(sizeof(struct rtattr)) + (len))
+#define RTA_DATA(rta)   ((void*)(((char*)(rta)) + RTA_LENGTH(0)))
+#define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
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 3909766..89439e5 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,13 +146,132 @@ receive_responses(const int fd, const unsigned long 
inode)
 static bool
 inet_print(int fd, int family, int protocol, const unsigned long inode)
 {
-       if (!send_query(fd, family, protocol))
+       if (!inet_send_query(fd, family, protocol))
                return false;
-       if (receive_responses(fd, inode))
+       if (receive_responses(fd, inode, inet_parse_response))
                return true;
        return false;
 }
 
+
+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:
+          [SOCKET_FILE,]SELF_INODE[->PEER_INODE] */
+       if (r) {
+               if (found_path)
+                       tprintf("%s,", path);
+               tprintf("%lu", inode);
+               if (peer)
+                       tprintf("->%u", peer);
+       }
+       return r;
+}
+
+static bool
+unix_print(int fd, const unsigned long inode)
+{
+       if (!unix_send_query(fd, inode))
+               return false;
+       if (receive_responses(fd, inode, unix_parse_response))
+               return true;
+       return false;
+}
+
+
 /* Given an inode number of a socket, print out the details
  * of the ip address and port. */
 bool
@@ -156,7 +280,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;
 
@@ -169,6 +293,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};
@@ -178,9 +304,9 @@ print_sockaddr_by_inode(const unsigned long inode, const 
char *proto_name)
 
                for (fi = 0; fi < flen; ++fi) {
                        for (pi = 0; pi < plen; ++pi) {
-                               if (!send_query(fd, families[fi], 
protocols[pi]))
+                               if (!inet_send_query(fd, families[fi], 
protocols[pi]))
                                        continue;
-                               if (receive_responses(fd, inode)) {
+                               if (receive_responses(fd, inode, 
inet_parse_response)) {
                                        r = true;
                                        goto out;
                                }
-- 
1.9.3


------------------------------------------------------------------------------
Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server
from Actuate! Instantly Supercharge Your Business Reports and Dashboards
with Interactivity, Sharing, Native Excel Exports, App Integration & more
Get technology previously reserved for billion-dollar corporations, FREE
http://pubads.g.doubleclick.net/gampad/clk?id=164703151&iu=/4140/ostg.clktrk
_______________________________________________
Strace-devel mailing list
Strace-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/strace-devel

Reply via email to