使用 netlink 从旧内核上的套接字获取 inode
Use netlink to get inode from socket on older kernel
我写了一段代码,使用 sock_diag netlink 获取套接字列表及其索引节点。这是发送代码:
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;
}
不幸的是,我们用于构建的其中一台机器仍然是 运行 RHEL6.8 (2.6.32-642) 这意味着它没有 <linux/sock_diag.h>
, SOCK_DIAG_BY_FAMILY
或 inet_diag_req_v2
结构。
查看旧内核的内核头文件和手册页,我可以看到我们有 inet_diag_req
选项,这与更新后的结构非常接近。我试过像这样直接替换:
#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
}
};
.
.
我收到的消息说 NLMSG_ERROR: No such file or directory
。
我正在努力寻找 任何 个例子来说明我正在尝试做的事情。是否可以使用较旧的 inet_diag_req 消息检索基于协议和系列的套接字列表,如果可以,知道我做错了什么吗?
我发布的代码确实按预期工作,但必须在旧机器(内核 < 3)上构建和 运行。我启动了一台真正的 RH6.8 机器,构建并 运行 代码,我得到了正确的响应,但是在内核 >= 3 的机器上它返回了错误。我误解了 docker 并认为我的容器有自己的内核,但实际上使用的是导致一些混乱的主机。
总结:
内核 < 3 使用 inet_diag_req。
内核 >= 3 使用 inet_diag_req_v2.
我写了一段代码,使用 sock_diag netlink 获取套接字列表及其索引节点。这是发送代码:
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;
}
不幸的是,我们用于构建的其中一台机器仍然是 运行 RHEL6.8 (2.6.32-642) 这意味着它没有 <linux/sock_diag.h>
, SOCK_DIAG_BY_FAMILY
或 inet_diag_req_v2
结构。
查看旧内核的内核头文件和手册页,我可以看到我们有 inet_diag_req
选项,这与更新后的结构非常接近。我试过像这样直接替换:
#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
}
};
.
.
我收到的消息说 NLMSG_ERROR: No such file or directory
。
我正在努力寻找 任何 个例子来说明我正在尝试做的事情。是否可以使用较旧的 inet_diag_req 消息检索基于协议和系列的套接字列表,如果可以,知道我做错了什么吗?
我发布的代码确实按预期工作,但必须在旧机器(内核 < 3)上构建和 运行。我启动了一台真正的 RH6.8 机器,构建并 运行 代码,我得到了正确的响应,但是在内核 >= 3 的机器上它返回了错误。我误解了 docker 并认为我的容器有自己的内核,但实际上使用的是导致一些混乱的主机。
总结:
内核 < 3 使用 inet_diag_req。
内核 >= 3 使用 inet_diag_req_v2.