1/* 2 * Copyright (c) 2014-2015 Dmitry V. Levin <ldv@altlinux.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include <assert.h> 29#include <string.h> 30#include <unistd.h> 31#include <netinet/in.h> 32#include <linux/netlink.h> 33#include <linux/sock_diag.h> 34#include <linux/inet_diag.h> 35 36static int 37send_query(const int fd, const int family, const int proto) 38{ 39 struct sockaddr_nl nladdr = { 40 .nl_family = AF_NETLINK 41 }; 42 struct { 43 struct nlmsghdr nlh; 44 struct inet_diag_req_v2 idr; 45 } req = { 46 .nlh = { 47 .nlmsg_len = sizeof(req), 48 .nlmsg_type = SOCK_DIAG_BY_FAMILY, 49 .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST 50 }, 51 .idr = { 52 .sdiag_family = family, 53 .sdiag_protocol = proto, 54 .idiag_states = -1 55 } 56 }; 57 struct iovec iov = { 58 .iov_base = &req, 59 .iov_len = sizeof(req) 60 }; 61 struct msghdr msg = { 62 .msg_name = (void*)&nladdr, 63 .msg_namelen = sizeof(nladdr), 64 .msg_iov = &iov, 65 .msg_iovlen = 1 66 }; 67 68 return sendmsg(fd, &msg, 0) > 0; 69} 70 71static int 72check_responses(const int fd) 73{ 74 static char buf[8192]; 75 struct sockaddr_nl nladdr = { 76 .nl_family = AF_NETLINK 77 }; 78 struct iovec iov = { 79 .iov_base = buf, 80 .iov_len = sizeof(buf) 81 }; 82 struct msghdr msg = { 83 .msg_name = (void*)&nladdr, 84 .msg_namelen = sizeof(nladdr), 85 .msg_iov = &iov, 86 .msg_iovlen = 1 87 }; 88 89 ssize_t ret = recvmsg(fd, &msg, 0); 90 if (ret <= 0) 91 return 0; 92 93 struct nlmsghdr *h = (struct nlmsghdr*)buf; 94 return (NLMSG_OK(h, ret) && 95 h->nlmsg_type != NLMSG_ERROR && 96 h->nlmsg_type != NLMSG_DONE) ? 1 : 0; 97} 98 99int main(void) 100{ 101 struct sockaddr_in addr; 102 socklen_t len = sizeof(addr); 103 104 memset(&addr, 0, sizeof(addr)); 105 addr.sin_family = AF_INET; 106 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 107 108 close(0); 109 close(1); 110 111 if (socket(PF_INET, SOCK_STREAM, 0) || 112 bind(0, (struct sockaddr *) &addr, len) || 113 listen(0, 5) || 114 socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG) != 1) 115 return 77; 116 117 return (send_query(1, AF_INET, IPPROTO_TCP) && 118 check_responses(1)) ? 0 : 77; 119} 120