2 #include <netinet/in.h>
3 #include <sys/socket.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>
13 # define UNIX_PATH_MAX sizeof(((struct sockaddr_un *) 0)->sun_path)
17 inet_send_query(const int fd, const int family, const int proto)
19 struct sockaddr_nl nladdr = {
20 .nl_family = AF_NETLINK
24 struct inet_diag_req_v2 idr;
27 .nlmsg_len = sizeof(req),
28 .nlmsg_type = SOCK_DIAG_BY_FAMILY,
29 .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST
32 .sdiag_family = family,
33 .sdiag_protocol = proto,
39 .iov_len = sizeof(req)
42 .msg_name = (void*)&nladdr,
43 .msg_namelen = sizeof(nladdr),
49 if (sendmsg(fd, &msg, 0) < 0) {
59 inet_parse_response(const void *data, int data_len, const unsigned long inode)
61 const struct inet_diag_msg *diag_msg = data;
62 static const char zero_addr[sizeof(struct in6_addr)];
63 socklen_t addr_size, text_size;
65 if (diag_msg->idiag_inode != inode)
68 switch(diag_msg->idiag_family) {
70 addr_size = sizeof(struct in_addr);
71 text_size = INET_ADDRSTRLEN;
74 addr_size = sizeof(struct in6_addr);
75 text_size = INET6_ADDRSTRLEN;
81 char src_buf[text_size];
83 if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_src,
87 if (diag_msg->id.idiag_dport ||
88 memcmp(zero_addr, diag_msg->id.idiag_dst, addr_size)) {
89 char dst_buf[text_size];
91 if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_dst,
95 tprintf("%s:%u->%s:%u",
96 src_buf, ntohs(diag_msg->id.idiag_sport),
97 dst_buf, ntohs(diag_msg->id.idiag_dport));
99 tprintf("%s:%u", src_buf, ntohs(diag_msg->id.idiag_sport));
106 receive_responses(const int fd, const unsigned long inode,
107 bool (* parser) (const void*, int, const unsigned long))
109 static char buf[8192];
110 struct sockaddr_nl nladdr = {
111 .nl_family = AF_NETLINK
115 .iov_len = sizeof(buf)
121 struct msghdr msg = {
122 .msg_name = (void*)&nladdr,
123 .msg_namelen = sizeof(nladdr),
128 ret = recvmsg(fd, &msg, 0);
136 for (h = (struct nlmsghdr*)buf;
138 h = NLMSG_NEXT(h, ret)) {
139 switch (h->nlmsg_type) {
144 if (parser(NLMSG_DATA(h), h->nlmsg_len, inode))
151 inet_print(int fd, int family, int protocol, const unsigned long inode)
153 return inet_send_query(fd, family, protocol)
154 && receive_responses(fd, inode, inet_parse_response);
158 unix_send_query(const int fd, const unsigned long inode)
160 struct sockaddr_nl nladdr = {
161 .nl_family = AF_NETLINK
165 struct unix_diag_req udr;
168 .nlmsg_len = sizeof(req),
169 .nlmsg_type = SOCK_DIAG_BY_FAMILY,
170 .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST
173 .sdiag_family = AF_UNIX,
176 .udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER
181 .iov_len = sizeof(req)
183 struct msghdr msg = {
184 .msg_name = (void*)&nladdr,
185 .msg_namelen = sizeof(nladdr),
191 if (sendmsg(fd, &msg, 0) < 0) {
201 unix_parse_response(const void *data, int data_len, const unsigned long inode)
203 const struct unix_diag_msg *diag_msg = data;
205 int rta_len = data_len - NLMSG_LENGTH(sizeof(*diag_msg));
208 char path[UNIX_PATH_MAX + 1];
210 if (diag_msg->udiag_ino != inode)
212 if (diag_msg->udiag_family != AF_UNIX)
215 for (attr = (struct rtattr *) (diag_msg + 1);
216 RTA_OK(attr, rta_len);
217 attr = RTA_NEXT(attr, rta_len)) {
218 switch (attr->rta_type) {
221 path_len = RTA_PAYLOAD(attr);
222 if (path_len > UNIX_PATH_MAX)
223 path_len = UNIX_PATH_MAX;
224 memcpy(path, RTA_DATA(attr), path_len);
225 path[path_len] = '\0';
229 if (RTA_PAYLOAD(attr) >= 4)
230 peer = *(uint32_t *)RTA_DATA(attr);
236 * print obtained information in the following format:
237 * "UNIX:[" SELF_INODE [ "->" PEER_INODE ][ "," SOCKET_FILE ] "]"
239 if (peer || path_len) {
240 tprintf("UNIX:[%lu", inode);
242 tprintf("->%u", peer);
244 if (path[0] == '\0') {
245 char *outstr = alloca(4 * path_len - 1);
246 string_quote(path + 1, outstr, -1, path_len);
247 tprintf(",@%s", outstr);
249 char *outstr = alloca(4 * path_len + 3);
250 string_quote(path, outstr, -1, path_len + 1);
251 tprintf(",%s", outstr);
262 unix_print(int fd, const unsigned long inode)
264 return unix_send_query(fd, inode)
265 && receive_responses(fd, inode, unix_parse_response);
268 /* Given an inode number of a socket, print out the details
269 * of the ip address and port. */
271 print_sockaddr_by_inode(const unsigned long inode, const char *proto_name)
276 fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
281 if (strcmp(proto_name, "TCP") == 0)
282 r = inet_print(fd, AF_INET, IPPROTO_TCP, inode);
283 else if (strcmp(proto_name, "UDP") == 0)
284 r = inet_print(fd, AF_INET, IPPROTO_UDP, inode);
285 else if (strcmp(proto_name, "TCPv6") == 0)
286 r = inet_print(fd, AF_INET6, IPPROTO_TCP, inode);
287 else if (strcmp(proto_name, "UDPv6") == 0)
288 r = inet_print(fd, AF_INET6, IPPROTO_UDP, inode);
289 else if (strcmp(proto_name, "UNIX") == 0)
290 r = unix_print(fd, inode);
292 const int families[] = {AF_INET, AF_INET6};
293 const int protocols[] = {IPPROTO_TCP, IPPROTO_UDP};
294 const size_t flen = ARRAY_SIZE(families);
295 const size_t plen = ARRAY_SIZE(protocols);
298 for (fi = 0; fi < flen; ++fi) {
299 for (pi = 0; pi < plen; ++pi) {
300 if ((r = inet_print(fd, families[fi], protocols[pi], inode)))