I wrote a piece of code to get a list of sockets and their inodes using sock_diag netlink. Here is the send code:
struct {
nlmsghdr nlh;
inet_diag_req_v2 id_req;
} req = {
.nlh = {
.nlmsg_len = sizeof(req),
.nlmsg_type = SOCK_DIAG_BY_FAMILY,
.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP
},
.id_req = {
.sdiag_family = AF_INET,
.sdiag_protocol = IPPROTO_TCP,
.idiag_ext = uint8_t(0),
.pad = uint8_t(0),
.idiag_states = UINT32_MAX // Everything
}
};
struct sockaddr_nl nladdr = {
.nl_family = AF_NETLINK
};
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
};
// Send message to kernel
for (;;) {
if (sendmsg(query_fd_, &msg, 0) < 0) {
if (errno == EINTR)
continue;
perror("sendmsg");
return false;
}
return;
}
Unfortunately, one of the machines we use for building is still running RHEL6.8 (2.6.32-642) which means it doesn't have <linux/sock_diag.h>
, SOCK_DIAG_BY_FAMILY
or inet_diag_req_v2
struct.
Looking through the kernel headers and man pages of the older kernel I can see we have the option of inet_diag_req
which is fairly close to the updated struct. I tried a direct replace like so:
#define SOCK_DIAG_BY_FAMILY 20
struct {
nlmsghdr nlh;
inet_diag_req id_req;
} req = {
.nlh = {
.nlmsg_len = sizeof(req),
.nlmsg_type = SOCK_DIAG_BY_FAMILY,
.nlmsg_flags = NLM_F_REQUEST
},
.id_req = {
.idiag_family = AF_INET,
.idiag_src_len = uint8_t(0),
.idiag_dst_len = uint8_t(0),
.idiag_ext = uint8_t(0),
.id = {},
.idiag_states = UINT32_MAX // Everything
}
};
.
.
The message I get back states NLMSG_ERROR: No such file or directory
.
I am struggling to find ANY examples of what I am trying to do. Is it possible to retrieve a list of sockets based on protocol and family using the older inet_diag_req message and if so, any idea what I am doing wrong?