blob: 80abed55b318abb88106647cc0381ee41936b4c3 [file] [log] [blame]
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +00001#include "defs.h"
2#include <netinet/in.h>
3#include <sys/socket.h>
4#include <arpa/inet.h>
5#include <linux/netlink.h>
6#include <linux/sock_diag.h>
7#include <linux/inet_diag.h>
8
9static bool
10send_query(const int fd, const int family, const int proto)
11{
Dmitry V. Levinaf534b82014-11-21 19:59:16 +000012 struct sockaddr_nl nladdr = {
13 .nl_family = AF_NETLINK
14 };
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +000015 struct {
16 struct nlmsghdr nlh;
17 struct inet_diag_req_v2 idr;
Dmitry V. Levinaf534b82014-11-21 19:59:16 +000018 } 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 };
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +000030 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
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +000041 for (;;) {
42 if (sendmsg(fd, &msg, 0) < 0) {
43 if (errno == EINTR)
44 continue;
45 return false;
46 }
47 return true;
48 }
49}
50
51static bool
52parse_response(const struct inet_diag_msg *diag_msg, const unsigned long inode)
53{
54 static const char zero_addr[sizeof(struct in6_addr)];
55 socklen_t addr_size, text_size;
56
57 if (diag_msg->idiag_inode != inode)
58 return false;
59
60 switch(diag_msg->idiag_family) {
61 case AF_INET:
62 addr_size = sizeof(struct in_addr);
63 text_size = INET_ADDRSTRLEN;
64 break;
65 case AF_INET6:
66 addr_size = sizeof(struct in6_addr);
67 text_size = INET6_ADDRSTRLEN;
68 break;
69 default:
70 return false;
71 }
72
73 char src_buf[text_size];
74
75 if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_src,
76 src_buf, text_size))
77 return false;
78
79 if (diag_msg->id.idiag_dport ||
80 memcmp(zero_addr, diag_msg->id.idiag_dst, addr_size)) {
81 char dst_buf[text_size];
82
83 if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_dst,
84 dst_buf, text_size))
85 return false;
86
87 tprintf("%s:%u->%s:%u",
88 src_buf, ntohs(diag_msg->id.idiag_sport),
89 dst_buf, ntohs(diag_msg->id.idiag_dport));
90 } else {
91 tprintf("%s:%u", src_buf, ntohs(diag_msg->id.idiag_sport));
92 }
93
94 return true;
95}
96
97static bool
98receive_responses(const int fd, const unsigned long inode)
99{
100 static char buf[8192];
Dmitry V. Levinaf534b82014-11-21 19:59:16 +0000101 struct sockaddr_nl nladdr = {
102 .nl_family = AF_NETLINK
103 };
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000104 struct iovec iov = {
105 .iov_base = buf,
106 .iov_len = sizeof(buf)
107 };
108
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000109 for (;;) {
110 ssize_t ret;
111 struct nlmsghdr *h;
112 struct msghdr msg = {
113 .msg_name = (void*)&nladdr,
114 .msg_namelen = sizeof(nladdr),
115 .msg_iov = &iov,
Dmitry V. Levinaf534b82014-11-21 19:59:16 +0000116 .msg_iovlen = 1
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000117 };
118
119 ret = recvmsg(fd, &msg, 0);
120 if (ret < 0) {
121 if (errno == EINTR)
122 continue;
123 return false;
124 }
125 if (!ret)
126 return false;
127 for (h = (struct nlmsghdr*)buf;
128 NLMSG_OK(h, ret);
129 h = NLMSG_NEXT(h, ret)) {
130 switch (h->nlmsg_type) {
131 case NLMSG_DONE:
132 case NLMSG_ERROR:
133 return false;
134 }
135 if (parse_response(NLMSG_DATA(h), inode))
136 return true;
137 }
138 }
139}
140
141/* Given an inode number of a socket, print out the details
142 * of the ip address and port. */
143bool
144print_sockaddr_by_inode(const unsigned long inode)
145{
146 const int families[] = {AF_INET, AF_INET6};
147 const int protocols[] = {IPPROTO_TCP, IPPROTO_UDP};
148 const size_t flen = ARRAY_SIZE(families);
149 const size_t plen = ARRAY_SIZE(protocols);
150 size_t fi, pi;
151 int fd;
152
153 fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG);
154 if (fd < 0)
155 return false;
156
157 for (fi = 0; fi < flen; ++fi) {
158 for (pi = 0; pi < plen; ++pi) {
159 if (!send_query(fd, families[fi], protocols[pi]))
160 continue;
161 if (receive_responses(fd, inode)) {
162 close(fd);
163 return true;
164 }
165 }
166 }
167
168 close(fd);
169 return false;
170}