From: Fabien Siron Date: Tue, 17 May 2016 10:08:47 +0000 (+0000) Subject: Add netlink domain sockets support to socketutils X-Git-Tag: v4.12~114 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=814c0d575d068121b6063ff91d056c49f4a43917;p=strace Add netlink domain sockets support to socketutils * linux/netlink_diag.h: New file. * Makefile.am (EXTRA_DIST): Add it. * socketutils.c: Include it and "xlat/netlink_protocols.h". (netlink_send_query, netlink_parse_response, netlink_print): New functions. (print_sockaddr_by_inode): Hook up netlink_print. --- diff --git a/Makefile.am b/Makefile.am index c389c79d..4b66b045 100644 --- a/Makefile.am +++ b/Makefile.am @@ -436,6 +436,7 @@ EXTRA_DIST = \ linux/mips/syscallent.h \ linux/mips/userent.h \ linux/mtd-abi.h \ + linux/netlink_diag.h \ linux/nios2/arch_regs.c \ linux/nios2/get_error.c \ linux/nios2/get_scno.c \ diff --git a/linux/netlink_diag.h b/linux/netlink_diag.h new file mode 100644 index 00000000..276baa7f --- /dev/null +++ b/linux/netlink_diag.h @@ -0,0 +1,24 @@ +struct netlink_diag_req { + uint8_t sdiag_family; + uint8_t sdiag_protocol; + uint16_t pad; + uint32_t ndiag_ino; + uint32_t ndiag_show; + uint32_t ndiag_cookie[2]; +}; + +struct netlink_diag_msg { + uint8_t ndiag_family; + uint8_t ndiag_type; + uint8_t ndiag_protocol; + uint8_t ndiag_state; + + uint32_t ndiag_portid; + uint32_t ndiag_dst_portid; + uint32_t ndiag_dst_group; + uint32_t ndiag_ino; + uint32_t ndiag_cookie[2]; +}; + +#define NDIAG_SHOW_MEMINFO 0x00000001 +#define NDIAG_PROTO_ALL ((uint8_t) ~0) diff --git a/socketutils.c b/socketutils.c index 88511984..a0d9310d 100644 --- a/socketutils.c +++ b/socketutils.c @@ -34,7 +34,9 @@ #include #include #include +#include #include +#include "xlat/netlink_protocols.h" #if !defined NETLINK_SOCK_DIAG && defined NETLINK_INET_DIAG # define NETLINK_SOCK_DIAG NETLINK_INET_DIAG @@ -334,6 +336,65 @@ unix_parse_response(const char *proto_name, const void *data, return cache_and_print_inode_details(inode, details); } +static bool +netlink_send_query(const int fd, const unsigned long inode) +{ + struct { + const struct nlmsghdr nlh; + const struct netlink_diag_req ndr; + } req = { + .nlh = { + .nlmsg_len = sizeof(req), + .nlmsg_type = SOCK_DIAG_BY_FAMILY, + .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST + }, + .ndr = { + .sdiag_family = AF_NETLINK, + .sdiag_protocol = NDIAG_PROTO_ALL, + .ndiag_show = NDIAG_SHOW_MEMINFO + } + }; + return send_query(fd, &req, sizeof(req)); +} + +static int +netlink_parse_response(const char *proto_name, const void *data, + const int data_len, const unsigned long inode) +{ + const struct netlink_diag_msg *const diag_msg = data; + const char *netlink_proto; + char *details; + + if (data_len < (int) NLMSG_LENGTH(sizeof(*diag_msg))) + return -1; + if (diag_msg->ndiag_ino != inode) + return 0; + + if (diag_msg->ndiag_family != AF_NETLINK) + return -1; + + netlink_proto = xlookup(netlink_protocols, + diag_msg->ndiag_protocol); + + if (netlink_proto) { + static const char netlink_prefix[] = "NETLINK_"; + const size_t netlink_prefix_len = + sizeof(netlink_prefix) -1; + if (strncmp(netlink_proto, netlink_prefix, + netlink_prefix_len) == 0) + netlink_proto += netlink_prefix_len; + if (asprintf(&details, "%s:[%s:%u]", proto_name, + netlink_proto, diag_msg->ndiag_portid) < 0) + return -1; + } else { + if (asprintf(&details, "%s:[%u]", proto_name, + (unsigned) diag_msg->ndiag_protocol) < 0) + return -1; + } + + return cache_and_print_inode_details(inode, details); +} + static bool unix_print(const int fd, const unsigned long inode) { @@ -365,6 +426,14 @@ udp_v6_print(const int fd, const unsigned long inode) return inet_print(fd, AF_INET6, IPPROTO_UDP, inode, "UDPv6"); } +static bool +netlink_print(const int fd, const unsigned long inode) +{ + return netlink_send_query(fd, inode) + && receive_responses(fd, inode, "NETLINK", + netlink_parse_response); +} + /* Given an inode number of a socket, print out the details * of the ip address and port. */ bool @@ -378,7 +447,8 @@ print_sockaddr_by_inode(const unsigned long inode, const char *const proto_name) { "UDP", udp_v4_print }, { "TCPv6", tcp_v6_print }, { "UDPv6", udp_v6_print }, - { "UNIX", unix_print } + { "UNIX", unix_print }, + { "NETLINK", netlink_print } }; const int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);