blob: d5cddf0c7f71ab73b12a027fa7da9e424b80bef5 [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{
12 struct sockaddr_nl nladdr;
13 struct {
14 struct nlmsghdr nlh;
15 struct inet_diag_req_v2 idr;
16 } req;
17 struct iovec iov = {
18 .iov_base = &req,
19 .iov_len = sizeof(req)
20 };
21 struct msghdr msg = {
22 .msg_name = (void*)&nladdr,
23 .msg_namelen = sizeof(nladdr),
24 .msg_iov = &iov,
25 .msg_iovlen = 1
26 };
27
28 memset(&nladdr, 0, sizeof(nladdr));
29 nladdr.nl_family = AF_NETLINK;
30
31 memset(&req, 0, sizeof(req));
32 req.nlh.nlmsg_len = sizeof(req);
33 req.nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
34 req.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
35 req.idr.sdiag_family = family;
36 req.idr.sdiag_protocol = proto;
37 req.idr.idiag_states = -1;
38
39 for (;;) {
40 if (sendmsg(fd, &msg, 0) < 0) {
41 if (errno == EINTR)
42 continue;
43 return false;
44 }
45 return true;
46 }
47}
48
49static bool
50parse_response(const struct inet_diag_msg *diag_msg, const unsigned long inode)
51{
52 static const char zero_addr[sizeof(struct in6_addr)];
53 socklen_t addr_size, text_size;
54
55 if (diag_msg->idiag_inode != inode)
56 return false;
57
58 switch(diag_msg->idiag_family) {
59 case AF_INET:
60 addr_size = sizeof(struct in_addr);
61 text_size = INET_ADDRSTRLEN;
62 break;
63 case AF_INET6:
64 addr_size = sizeof(struct in6_addr);
65 text_size = INET6_ADDRSTRLEN;
66 break;
67 default:
68 return false;
69 }
70
71 char src_buf[text_size];
72
73 if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_src,
74 src_buf, text_size))
75 return false;
76
77 if (diag_msg->id.idiag_dport ||
78 memcmp(zero_addr, diag_msg->id.idiag_dst, addr_size)) {
79 char dst_buf[text_size];
80
81 if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_dst,
82 dst_buf, text_size))
83 return false;
84
85 tprintf("%s:%u->%s:%u",
86 src_buf, ntohs(diag_msg->id.idiag_sport),
87 dst_buf, ntohs(diag_msg->id.idiag_dport));
88 } else {
89 tprintf("%s:%u", src_buf, ntohs(diag_msg->id.idiag_sport));
90 }
91
92 return true;
93}
94
95static bool
96receive_responses(const int fd, const unsigned long inode)
97{
98 static char buf[8192];
99 struct sockaddr_nl nladdr;
100 struct iovec iov = {
101 .iov_base = buf,
102 .iov_len = sizeof(buf)
103 };
104
105 memset(&nladdr, 0, sizeof(nladdr));
106 nladdr.nl_family = AF_NETLINK;
107
108 for (;;) {
109 ssize_t ret;
110 struct nlmsghdr *h;
111 struct msghdr msg = {
112 .msg_name = (void*)&nladdr,
113 .msg_namelen = sizeof(nladdr),
114 .msg_iov = &iov,
115 .msg_iovlen = 1,
116 .msg_control = NULL,
117 .msg_controllen = 0,
118 .msg_flags = 0
119 };
120
121 ret = recvmsg(fd, &msg, 0);
122 if (ret < 0) {
123 if (errno == EINTR)
124 continue;
125 return false;
126 }
127 if (!ret)
128 return false;
129 for (h = (struct nlmsghdr*)buf;
130 NLMSG_OK(h, ret);
131 h = NLMSG_NEXT(h, ret)) {
132 switch (h->nlmsg_type) {
133 case NLMSG_DONE:
134 case NLMSG_ERROR:
135 return false;
136 }
137 if (parse_response(NLMSG_DATA(h), inode))
138 return true;
139 }
140 }
141}
142
143/* Given an inode number of a socket, print out the details
144 * of the ip address and port. */
145bool
146print_sockaddr_by_inode(const unsigned long inode)
147{
148 const int families[] = {AF_INET, AF_INET6};
149 const int protocols[] = {IPPROTO_TCP, IPPROTO_UDP};
150 const size_t flen = ARRAY_SIZE(families);
151 const size_t plen = ARRAY_SIZE(protocols);
152 size_t fi, pi;
153 int fd;
154
155 fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG);
156 if (fd < 0)
157 return false;
158
159 for (fi = 0; fi < flen; ++fi) {
160 for (pi = 0; pi < plen; ++pi) {
161 if (!send_query(fd, families[fi], protocols[pi]))
162 continue;
163 if (receive_responses(fd, inode)) {
164 close(fd);
165 return true;
166 }
167 }
168 }
169
170 close(fd);
171 return false;
172}