1 #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 #include <linux/unix_diag.h>
9 #include <linux/rtnetlink.h>
10 
11 #if !defined NETLINK_SOCK_DIAG && defined NETLINK_INET_DIAG
12 # define NETLINK_SOCK_DIAG NETLINK_INET_DIAG
13 #endif
14 
15 #include <sys/un.h>
16 #ifndef UNIX_PATH_MAX
17 # define UNIX_PATH_MAX sizeof(((struct sockaddr_un *) 0)->sun_path)
18 #endif
19 
20 static bool
inet_send_query(const int fd,const int family,const int proto)21 inet_send_query(const int fd, const int family, const int proto)
22 {
23 	struct sockaddr_nl nladdr = {
24 		.nl_family = AF_NETLINK
25 	};
26 	struct {
27 		struct nlmsghdr nlh;
28 		struct inet_diag_req_v2 idr;
29 	} req = {
30 		.nlh = {
31 			.nlmsg_len = sizeof(req),
32 			.nlmsg_type = SOCK_DIAG_BY_FAMILY,
33 			.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST
34 		},
35 		.idr = {
36 			.sdiag_family = family,
37 			.sdiag_protocol = proto,
38 			.idiag_states = -1
39 		}
40 	};
41 	struct iovec iov = {
42 		.iov_base = &req,
43 		.iov_len = sizeof(req)
44 	};
45 	struct msghdr msg = {
46 		.msg_name = (void*)&nladdr,
47 		.msg_namelen = sizeof(nladdr),
48 		.msg_iov = &iov,
49 		.msg_iovlen = 1
50 	};
51 
52 	for (;;) {
53 		if (sendmsg(fd, &msg, 0) < 0) {
54 			if (errno == EINTR)
55 				continue;
56 			return false;
57 		}
58 		return true;
59 	}
60 }
61 
62 static bool
inet_parse_response(const char * proto_name,const void * data,int data_len,const unsigned long inode)63 inet_parse_response(const char *proto_name, const void *data, int data_len,
64 		    const unsigned long inode)
65 {
66 	const struct inet_diag_msg *diag_msg = data;
67 	static const char zero_addr[sizeof(struct in6_addr)];
68 	socklen_t addr_size, text_size;
69 
70 	if (diag_msg->idiag_inode != inode)
71 		return false;
72 
73 	switch(diag_msg->idiag_family) {
74 		case AF_INET:
75 			addr_size = sizeof(struct in_addr);
76 			text_size = INET_ADDRSTRLEN;
77 			break;
78 		case AF_INET6:
79 			addr_size = sizeof(struct in6_addr);
80 			text_size = INET6_ADDRSTRLEN;
81 			break;
82 		default:
83 			return false;
84 	}
85 
86 	char src_buf[text_size];
87 
88 	if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_src,
89 		       src_buf, text_size))
90 		return false;
91 
92 	if (diag_msg->id.idiag_dport ||
93 	    memcmp(zero_addr, diag_msg->id.idiag_dst, addr_size)) {
94 		char dst_buf[text_size];
95 
96 		if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_dst,
97 			       dst_buf, text_size))
98 			return false;
99 
100 		tprintf("%s:[%s:%u->%s:%u]",
101 			proto_name,
102 			src_buf, ntohs(diag_msg->id.idiag_sport),
103 			dst_buf, ntohs(diag_msg->id.idiag_dport));
104 	} else {
105 		tprintf("%s:[%s:%u]", proto_name, src_buf,
106 			ntohs(diag_msg->id.idiag_sport));
107 	}
108 
109 	return true;
110 }
111 
112 static bool
receive_responses(const int fd,const unsigned long inode,const char * proto_name,bool (* parser)(const char *,const void *,int,const unsigned long))113 receive_responses(const int fd, const unsigned long inode,
114 		  const char *proto_name,
115 		  bool (* parser) (const char *, const void *, int, const unsigned long))
116 {
117 	static long buf[8192 / sizeof(long)];
118 	struct sockaddr_nl nladdr = {
119 		.nl_family = AF_NETLINK
120 	};
121 	struct iovec iov = {
122 		.iov_base = buf,
123 		.iov_len = sizeof(buf)
124 	};
125 
126 	for (;;) {
127 		ssize_t ret;
128 		struct nlmsghdr *h;
129 		struct msghdr msg = {
130 			.msg_name = (void*)&nladdr,
131 			.msg_namelen = sizeof(nladdr),
132 			.msg_iov = &iov,
133 			.msg_iovlen = 1
134 		};
135 
136 		ret = recvmsg(fd, &msg, 0);
137 		if (ret < 0) {
138 			if (errno == EINTR)
139 				continue;
140 			return false;
141 		}
142 		if (!ret)
143 			return false;
144 		for (h = (struct nlmsghdr*)buf;
145 		     NLMSG_OK(h, ret);
146 		     h = NLMSG_NEXT(h, ret)) {
147 			switch (h->nlmsg_type) {
148 				case NLMSG_DONE:
149 				case NLMSG_ERROR:
150 					return false;
151 			}
152 			if (parser(proto_name, NLMSG_DATA(h), h->nlmsg_len, inode))
153 				return true;
154 		}
155 	}
156 }
157 
158 static bool
inet_print(const int fd,const int family,const int protocol,const unsigned long inode,const char * proto_name)159 inet_print(const int fd, const int family, const int protocol,
160 	   const unsigned long inode, const char *proto_name)
161 {
162 	return inet_send_query(fd, family, protocol)
163 		&& receive_responses(fd, inode, proto_name, inet_parse_response);
164 }
165 
166 static bool
unix_send_query(const int fd,const unsigned long inode)167 unix_send_query(const int fd, const unsigned long inode)
168 {
169 	struct sockaddr_nl nladdr = {
170 		.nl_family = AF_NETLINK
171 	};
172 	struct {
173 		struct nlmsghdr nlh;
174 		struct unix_diag_req udr;
175 	} req = {
176 		.nlh = {
177 			.nlmsg_len = sizeof(req),
178 			.nlmsg_type = SOCK_DIAG_BY_FAMILY,
179 			.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST
180 		},
181 		.udr = {
182 			.sdiag_family = AF_UNIX,
183 			.udiag_ino = inode,
184 			.udiag_states = -1,
185 			.udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER
186 		}
187 	};
188 	struct iovec iov = {
189 		.iov_base = &req,
190 		.iov_len = sizeof(req)
191 	};
192 	struct msghdr msg = {
193 		.msg_name = (void*)&nladdr,
194 		.msg_namelen = sizeof(nladdr),
195 		.msg_iov = &iov,
196 		.msg_iovlen = 1
197 	};
198 
199 	for (;;) {
200 		if (sendmsg(fd, &msg, 0) < 0) {
201 			if (errno == EINTR)
202 				continue;
203 			return false;
204 		}
205 		return true;
206 	}
207 }
208 
209 static bool
unix_parse_response(const char * proto_name,const void * data,int data_len,const unsigned long inode)210 unix_parse_response(const char *proto_name, const void *data, int data_len,
211 		    const unsigned long inode)
212 {
213 	const struct unix_diag_msg *diag_msg = data;
214 	struct rtattr *attr;
215 	int rta_len = data_len - NLMSG_LENGTH(sizeof(*diag_msg));
216 	uint32_t peer = 0;
217 	size_t path_len = 0;
218 	char path[UNIX_PATH_MAX + 1];
219 
220 	if (diag_msg->udiag_ino != inode)
221 		return false;
222 	if (diag_msg->udiag_family != AF_UNIX)
223 		return false;
224 
225 	for (attr = (struct rtattr *) (diag_msg + 1);
226 	     RTA_OK(attr, rta_len);
227 	     attr = RTA_NEXT(attr, rta_len)) {
228 		switch (attr->rta_type) {
229 		case UNIX_DIAG_NAME:
230 			if (!path_len) {
231 				path_len = RTA_PAYLOAD(attr);
232 				if (path_len > UNIX_PATH_MAX)
233 					path_len = UNIX_PATH_MAX;
234 				memcpy(path, RTA_DATA(attr), path_len);
235 				path[path_len] = '\0';
236 			}
237 			break;
238 		case UNIX_DIAG_PEER:
239 			if (RTA_PAYLOAD(attr) >= 4)
240 				peer = *(uint32_t *)RTA_DATA(attr);
241 			break;
242 		}
243 	}
244 
245 	/*
246 	 * print obtained information in the following format:
247 	 * "UNIX:[" SELF_INODE [ "->" PEER_INODE ][ "," SOCKET_FILE ] "]"
248 	 */
249 	if (peer || path_len) {
250 		tprintf("%s:[%lu", proto_name, inode);
251 		if (peer)
252 			tprintf("->%u", peer);
253 		if (path_len) {
254 			if (path[0] == '\0') {
255 				tprints(",@");
256 				print_quoted_string(path + 1, path_len,
257 						    QUOTE_0_TERMINATED);
258 			} else {
259 				tprints(",");
260 				print_quoted_string(path, path_len + 1,
261 						    QUOTE_0_TERMINATED);
262 			}
263 		}
264 		tprints("]");
265 		return true;
266 	}
267 	else
268 		return false;
269 }
270 
271 static bool
unix_print(int fd,const unsigned long inode)272 unix_print(int fd, const unsigned long inode)
273 {
274 	return unix_send_query(fd, inode)
275 		&& receive_responses(fd, inode, "UNIX", unix_parse_response);
276 }
277 
278 /* Given an inode number of a socket, print out the details
279  * of the ip address and port. */
280 bool
print_sockaddr_by_inode(const unsigned long inode,const char * proto_name)281 print_sockaddr_by_inode(const unsigned long inode, const char *proto_name)
282 {
283 	int fd;
284 	bool r = false;
285 
286 	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
287 	if (fd < 0)
288 		return false;
289 
290 	if (proto_name) {
291 		if (strcmp(proto_name, "TCP") == 0)
292 			r = inet_print(fd, AF_INET, IPPROTO_TCP, inode, "TCP");
293 		else if (strcmp(proto_name, "UDP") == 0)
294 			r = inet_print(fd, AF_INET, IPPROTO_UDP, inode, "UDP");
295 		else if (strcmp(proto_name, "TCPv6") == 0)
296 			r = inet_print(fd, AF_INET6, IPPROTO_TCP, inode, "TCPv6");
297 		else if (strcmp(proto_name, "UDPv6") == 0)
298 			r = inet_print(fd, AF_INET6, IPPROTO_UDP, inode, "UDPv6");
299 		else if (strcmp(proto_name, "UNIX") == 0)
300 			r = unix_print(fd, inode);
301 	} else {
302 		const struct {
303 			const int family;
304 			const int protocol;
305 			const char *name;
306 		} protocols[] = {
307 			{ AF_INET, IPPROTO_TCP, "TCP" },
308 			{ AF_INET, IPPROTO_UDP, "UDP" },
309 			{ AF_INET6, IPPROTO_TCP, "TCPv6" },
310 			{ AF_INET6, IPPROTO_UDP, "UDPv6" }
311 		};
312 		size_t i;
313 
314 		for (i = 0; i < ARRAY_SIZE(protocols); ++i) {
315 			if ((r = inet_print(fd, protocols[i].family,
316 					    protocols[i].protocol, inode,
317 					    protocols[i].name)))
318 				break;
319 		}
320 	}
321 
322 	close(fd);
323 	return r;
324 }
325