26 const std::string& src_ip, std::uint16_t src_port,
27 const std::string& dst_ip, std::uint16_t dst_port)
29 int fd = ::socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_SOCK_DIAG);
30 if (fd < 0)
return std::nullopt;
36 tv.tv_usec = 100 * 1000;
37 ::setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv,
sizeof(tv));
42 struct inet_diag_req_v2 req;
45 msg.nlh.nlmsg_len = NLMSG_LENGTH(
sizeof(msg.req));
46 msg.nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
47 msg.nlh.nlmsg_flags = NLM_F_REQUEST;
48 msg.nlh.nlmsg_seq = 1;
50 msg.req.sdiag_family =
static_cast<std::uint8_t
>(family);
51 msg.req.sdiag_protocol =
static_cast<std::uint8_t
>(protocol);
56 msg.req.idiag_states = 0xFFFFFFFFu;
57 msg.req.idiag_ext = 0;
61 msg.req.id.idiag_sport = htons(src_port);
62 msg.req.id.idiag_dport = htons(dst_port);
63 msg.req.id.idiag_if = 0;
64 msg.req.id.idiag_cookie[0] = INET_DIAG_NOCOOKIE;
65 msg.req.id.idiag_cookie[1] = INET_DIAG_NOCOOKIE;
69 if (inet_pton(
AF_INET, src_ip.c_str(), &sa) != 1 ||
70 inet_pton(
AF_INET, dst_ip.c_str(), &da) != 1) {
71 ::close(fd);
return std::nullopt;
73 std::memcpy(msg.req.id.idiag_src, &sa.s_addr, 4);
74 std::memcpy(msg.req.id.idiag_dst, &da.s_addr, 4);
77 if (inet_pton(
AF_INET6, src_ip.c_str(), &sa) != 1 ||
78 inet_pton(
AF_INET6, dst_ip.c_str(), &da) != 1) {
79 ::close(fd);
return std::nullopt;
81 std::memcpy(msg.req.id.idiag_src, &sa.s6_addr, 16);
82 std::memcpy(msg.req.id.idiag_dst, &da.s6_addr, 16);
86 struct sockaddr_nl dest{};
87 dest.nl_family = AF_NETLINK;
88 const auto sent = ::sendto(fd, &msg, msg.nlh.nlmsg_len, 0,
89 reinterpret_cast<struct sockaddr*
>(&dest),
sizeof(dest));
90 if (sent < 0) { ::close(fd);
return std::nullopt; }
94 const auto rcv = ::recv(fd, buf,
sizeof(buf), 0);
96 if (rcv <= 0)
return std::nullopt;
99 auto n =
static_cast<unsigned int>(rcv);
101 struct nlmsghdr* nh =
reinterpret_cast<struct nlmsghdr*
>(buf);
102 for (; NLMSG_OK(nh, n); nh = NLMSG_NEXT(nh, n)) {
103 if (nh->nlmsg_type == NLMSG_DONE)
break;
104 if (nh->nlmsg_type == NLMSG_ERROR)
return std::nullopt;
105 if (nh->nlmsg_type != SOCK_DIAG_BY_FAMILY)
continue;
107 auto* diag =
reinterpret_cast<struct inet_diag_msg*
>(NLMSG_DATA(nh));
109 info.
inode = diag->idiag_inode;
110 info.
uid = diag->idiag_uid;
111 if (info.
inode != 0)
return info;