1 #include <assert.h> 2 #include <string.h> 3 #include <unistd.h> 4 #include <netinet/in.h> 5 #include <linux/netlink.h> 6 #include <linux/sock_diag.h> 7 #include <linux/inet_diag.h> 8 9 static int 10 send_query(const int fd, const int family, const int proto) 11 { 12 struct sockaddr_nl nladdr = { 13 .nl_family = AF_NETLINK 14 }; 15 struct { 16 struct nlmsghdr nlh; 17 struct inet_diag_req_v2 idr; 18 } req = { 19 .nlh = { 20 .nlmsg_len = sizeof(req), 21 .nlmsg_type = SOCK_DIAG_BY_FAMILY, 22 .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST 23 }, 24 .idr = { 25 .sdiag_family = family, 26 .sdiag_protocol = proto, 27 .idiag_states = -1 28 } 29 }; 30 struct iovec iov = { 31 .iov_base = &req, 32 .iov_len = sizeof(req) 33 }; 34 struct msghdr msg = { 35 .msg_name = (void*)&nladdr, 36 .msg_namelen = sizeof(nladdr), 37 .msg_iov = &iov, 38 .msg_iovlen = 1 39 }; 40 41 return sendmsg(fd, &msg, 0) > 0; 42 } 43 44 static int 45 check_responses(const int fd) 46 { 47 static char buf[8192]; 48 struct sockaddr_nl nladdr = { 49 .nl_family = AF_NETLINK 50 }; 51 struct iovec iov = { 52 .iov_base = buf, 53 .iov_len = sizeof(buf) 54 }; 55 struct msghdr msg = { 56 .msg_name = (void*)&nladdr, 57 .msg_namelen = sizeof(nladdr), 58 .msg_iov = &iov, 59 .msg_iovlen = 1 60 }; 61 62 ssize_t ret = recvmsg(fd, &msg, 0); 63 if (ret <= 0) 64 return 0; 65 66 struct nlmsghdr *h = (struct nlmsghdr*)buf; 67 return (NLMSG_OK(h, ret) && 68 h->nlmsg_type != NLMSG_ERROR && 69 h->nlmsg_type != NLMSG_DONE) ? 1 : 0; 70 } 71 72 int main(void) 73 { 74 struct sockaddr_in addr; 75 socklen_t len = sizeof(addr); 76 77 memset(&addr, 0, sizeof(addr)); 78 addr.sin_family = AF_INET; 79 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 80 81 close(0); 82 close(1); 83 84 if (socket(PF_INET, SOCK_STREAM, 0) || 85 bind(0, (struct sockaddr *) &addr, len) || 86 listen(0, 5) || 87 socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG) != 1) 88 return 77; 89 90 return (send_query(1, AF_INET, IPPROTO_TCP) && 91 check_responses(1)) ? 0 : 77; 92 } 93