blob: ff0255941b12ab29f61e4379cd9d455db1d5ccb3 [file] [log] [blame]
Dmitry V. Levin38a34c92015-12-17 17:56:48 +00001/*
2 * Copyright (c) 2014 Zubin Mithra <zubin.mithra@gmail.com>
Dmitry V. Levin3c86e0e2016-01-30 23:50:54 +00003 * Copyright (c) 2014-2016 Dmitry V. Levin <ldv@altlinux.org>
Dmitry V. Levin38a34c92015-12-17 17:56:48 +00004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +000029#include "defs.h"
30#include <netinet/in.h>
31#include <sys/socket.h>
32#include <arpa/inet.h>
33#include <linux/netlink.h>
34#include <linux/sock_diag.h>
35#include <linux/inet_diag.h>
Masatake YAMATO120e5db2014-12-24 20:59:31 +090036#include <linux/unix_diag.h>
Fabien Siron814c0d52016-05-17 10:08:47 +000037#include <linux/netlink_diag.h>
Masatake YAMATO120e5db2014-12-24 20:59:31 +090038#include <linux/rtnetlink.h>
Fabien Siron814c0d52016-05-17 10:08:47 +000039#include "xlat/netlink_protocols.h"
Masatake YAMATO120e5db2014-12-24 20:59:31 +090040
Dmitry V. Levind9f7e7a2015-01-09 03:03:39 +000041#if !defined NETLINK_SOCK_DIAG && defined NETLINK_INET_DIAG
42# define NETLINK_SOCK_DIAG NETLINK_INET_DIAG
43#endif
44
Masatake YAMATO120e5db2014-12-24 20:59:31 +090045#include <sys/un.h>
46#ifndef UNIX_PATH_MAX
47# define UNIX_PATH_MAX sizeof(((struct sockaddr_un *) 0)->sun_path)
48#endif
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +000049
Dmitry V. Levin3c17d1b2016-02-01 23:14:59 +000050typedef struct {
51 unsigned long inode;
52 char *details;
53} cache_entry;
54
55#define CACHE_SIZE 1024U
56static cache_entry cache[CACHE_SIZE];
57#define CACHE_MASK (CACHE_SIZE - 1)
58
59static int
Dmitry V. Levinea218232016-02-10 17:43:09 +000060cache_and_print_inode_details(const unsigned long inode, char *const details)
Dmitry V. Levin3c17d1b2016-02-01 23:14:59 +000061{
62 cache_entry *e = &cache[inode & CACHE_MASK];
63 free(e->details);
64 e->inode = inode;
65 e->details = details;
66
67 tprints(details);
68 return 1;
69}
70
71bool
72print_sockaddr_by_inode_cached(const unsigned long inode)
73{
Dmitry V. Levinea218232016-02-10 17:43:09 +000074 const cache_entry *const e = &cache[inode & CACHE_MASK];
Dmitry V. Levin3c17d1b2016-02-01 23:14:59 +000075 if (e && inode == e->inode) {
76 tprints(e->details);
77 return true;
78 }
79 return false;
80}
81
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +000082static bool
Fabien Siron071b9272016-05-08 10:45:52 +000083send_query(const int fd, void *req, size_t req_size)
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +000084{
Dmitry V. Levinaf534b82014-11-21 19:59:16 +000085 struct sockaddr_nl nladdr = {
86 .nl_family = AF_NETLINK
87 };
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +000088 struct iovec iov = {
Fabien Siron071b9272016-05-08 10:45:52 +000089 .iov_base = req,
90 .iov_len = req_size
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +000091 };
Dmitry V. Levinea218232016-02-10 17:43:09 +000092 const struct msghdr msg = {
93 .msg_name = &nladdr,
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +000094 .msg_namelen = sizeof(nladdr),
95 .msg_iov = &iov,
96 .msg_iovlen = 1
97 };
98
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +000099 for (;;) {
100 if (sendmsg(fd, &msg, 0) < 0) {
101 if (errno == EINTR)
102 continue;
103 return false;
104 }
105 return true;
106 }
107}
108
Fabien Siron071b9272016-05-08 10:45:52 +0000109static bool
110inet_send_query(const int fd, const int family, const int proto)
111{
112 struct {
113 const struct nlmsghdr nlh;
114 const struct inet_diag_req_v2 idr;
115 } req = {
116 .nlh = {
117 .nlmsg_len = sizeof(req),
118 .nlmsg_type = SOCK_DIAG_BY_FAMILY,
119 .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST
120 },
121 .idr = {
122 .sdiag_family = family,
123 .sdiag_protocol = proto,
124 .idiag_states = -1
125 }
126 };
127 return send_query(fd, &req, sizeof(req));
128}
129
Dmitry V. Levin3c86e0e2016-01-30 23:50:54 +0000130static int
Dmitry V. Levinea218232016-02-10 17:43:09 +0000131inet_parse_response(const char *const proto_name, const void *const data,
Dmitry V. Levin3c86e0e2016-01-30 23:50:54 +0000132 const int data_len, const unsigned long inode)
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000133{
Dmitry V. Levinea218232016-02-10 17:43:09 +0000134 const struct inet_diag_msg *const diag_msg = data;
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000135 static const char zero_addr[sizeof(struct in6_addr)];
136 socklen_t addr_size, text_size;
137
Dmitry V. Levincc09ba12016-01-28 23:46:56 +0000138 if (data_len < (int) NLMSG_LENGTH(sizeof(*diag_msg)))
Dmitry V. Levin3c86e0e2016-01-30 23:50:54 +0000139 return -1;
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000140 if (diag_msg->idiag_inode != inode)
Dmitry V. Levin3c86e0e2016-01-30 23:50:54 +0000141 return 0;
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000142
143 switch(diag_msg->idiag_family) {
144 case AF_INET:
145 addr_size = sizeof(struct in_addr);
146 text_size = INET_ADDRSTRLEN;
147 break;
148 case AF_INET6:
149 addr_size = sizeof(struct in6_addr);
150 text_size = INET6_ADDRSTRLEN;
151 break;
152 default:
Dmitry V. Levin3c86e0e2016-01-30 23:50:54 +0000153 return -1;
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000154 }
155
156 char src_buf[text_size];
Dmitry V. Levin3c17d1b2016-02-01 23:14:59 +0000157 char *details;
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000158
159 if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_src,
160 src_buf, text_size))
Dmitry V. Levin3c86e0e2016-01-30 23:50:54 +0000161 return -1;
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000162
163 if (diag_msg->id.idiag_dport ||
164 memcmp(zero_addr, diag_msg->id.idiag_dst, addr_size)) {
165 char dst_buf[text_size];
166
167 if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_dst,
168 dst_buf, text_size))
Dmitry V. Levin3c86e0e2016-01-30 23:50:54 +0000169 return -1;
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000170
Dmitry V. Levin3c17d1b2016-02-01 23:14:59 +0000171 if (asprintf(&details, "%s:[%s:%u->%s:%u]", proto_name,
172 src_buf, ntohs(diag_msg->id.idiag_sport),
173 dst_buf, ntohs(diag_msg->id.idiag_dport)) < 0)
174 return false;
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000175 } else {
Dmitry V. Levin3c17d1b2016-02-01 23:14:59 +0000176 if (asprintf(&details, "%s:[%s:%u]", proto_name, src_buf,
177 ntohs(diag_msg->id.idiag_sport)) < 0)
178 return false;
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000179 }
180
Dmitry V. Levin3c17d1b2016-02-01 23:14:59 +0000181 return cache_and_print_inode_details(inode, details);
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000182}
183
184static bool
Masatake YAMATO120e5db2014-12-24 20:59:31 +0900185receive_responses(const int fd, const unsigned long inode,
Dmitry V. Levin959205c2014-12-26 23:29:26 +0000186 const char *proto_name,
Dmitry V. Levin3c86e0e2016-01-30 23:50:54 +0000187 int (* parser) (const char *, const void *,
188 int, unsigned long))
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000189{
Dmitry V. Levin7b697972016-05-19 01:23:40 +0000190 static union {
191 struct nlmsghdr hdr;
192 long buf[8192 / sizeof(long)];
193 } hdr_buf;
194
Dmitry V. Levinaf534b82014-11-21 19:59:16 +0000195 struct sockaddr_nl nladdr = {
196 .nl_family = AF_NETLINK
197 };
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000198 struct iovec iov = {
Dmitry V. Levin7b697972016-05-19 01:23:40 +0000199 .iov_base = hdr_buf.buf,
200 .iov_len = sizeof(hdr_buf.buf)
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000201 };
Dmitry V. Levin2215c3e2016-01-27 21:35:50 +0000202 int flags = 0;
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000203
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000204 for (;;) {
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000205 struct msghdr msg = {
Dmitry V. Levinea218232016-02-10 17:43:09 +0000206 .msg_name = &nladdr,
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000207 .msg_namelen = sizeof(nladdr),
208 .msg_iov = &iov,
Dmitry V. Levinaf534b82014-11-21 19:59:16 +0000209 .msg_iovlen = 1
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000210 };
211
Dmitry V. Levinea218232016-02-10 17:43:09 +0000212 ssize_t ret = recvmsg(fd, &msg, flags);
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000213 if (ret < 0) {
214 if (errno == EINTR)
215 continue;
216 return false;
217 }
Dmitry V. Levin3c86e0e2016-01-30 23:50:54 +0000218
Dmitry V. Levin7b697972016-05-19 01:23:40 +0000219 const struct nlmsghdr *h = &hdr_buf.hdr;
Dmitry V. Levin3c86e0e2016-01-30 23:50:54 +0000220 if (!NLMSG_OK(h, ret))
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000221 return false;
Dmitry V. Levin3c86e0e2016-01-30 23:50:54 +0000222 for (; NLMSG_OK(h, ret); h = NLMSG_NEXT(h, ret)) {
223 if (h->nlmsg_type != SOCK_DIAG_BY_FAMILY)
224 return false;
Dmitry V. Levinea218232016-02-10 17:43:09 +0000225 const int rc = parser(proto_name, NLMSG_DATA(h),
226 h->nlmsg_len, inode);
Dmitry V. Levin3c86e0e2016-01-30 23:50:54 +0000227 if (rc > 0)
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000228 return true;
Dmitry V. Levin3c86e0e2016-01-30 23:50:54 +0000229 if (rc < 0)
230 return false;
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000231 }
Dmitry V. Levin2215c3e2016-01-27 21:35:50 +0000232 flags = MSG_DONTWAIT;
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000233 }
234}
235
Masatake YAMATOf605e922014-12-10 12:55:06 +0900236static bool
Dmitry V. Levin959205c2014-12-26 23:29:26 +0000237inet_print(const int fd, const int family, const int protocol,
238 const unsigned long inode, const char *proto_name)
Masatake YAMATOf605e922014-12-10 12:55:06 +0900239{
Masatake YAMATO120e5db2014-12-24 20:59:31 +0900240 return inet_send_query(fd, family, protocol)
Dmitry V. Levin959205c2014-12-26 23:29:26 +0000241 && receive_responses(fd, inode, proto_name, inet_parse_response);
Masatake YAMATO120e5db2014-12-24 20:59:31 +0900242}
243
244static bool
245unix_send_query(const int fd, const unsigned long inode)
246{
Masatake YAMATO120e5db2014-12-24 20:59:31 +0900247 struct {
Dmitry V. Levinea218232016-02-10 17:43:09 +0000248 const struct nlmsghdr nlh;
249 const struct unix_diag_req udr;
Masatake YAMATO120e5db2014-12-24 20:59:31 +0900250 } req = {
251 .nlh = {
252 .nlmsg_len = sizeof(req),
253 .nlmsg_type = SOCK_DIAG_BY_FAMILY,
Dmitry V. Levin10c61e32016-02-19 01:30:34 +0000254 .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST
Masatake YAMATO120e5db2014-12-24 20:59:31 +0900255 },
256 .udr = {
257 .sdiag_family = AF_UNIX,
258 .udiag_ino = inode,
259 .udiag_states = -1,
Dmitry V. Levin10c61e32016-02-19 01:30:34 +0000260 .udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER
Masatake YAMATO120e5db2014-12-24 20:59:31 +0900261 }
262 };
Fabien Siron071b9272016-05-08 10:45:52 +0000263 return send_query(fd, &req, sizeof(req));
Masatake YAMATO120e5db2014-12-24 20:59:31 +0900264}
265
Dmitry V. Levin3c86e0e2016-01-30 23:50:54 +0000266static int
267unix_parse_response(const char *proto_name, const void *data,
268 const int data_len, const unsigned long inode)
Masatake YAMATO120e5db2014-12-24 20:59:31 +0900269{
270 const struct unix_diag_msg *diag_msg = data;
271 struct rtattr *attr;
272 int rta_len = data_len - NLMSG_LENGTH(sizeof(*diag_msg));
273 uint32_t peer = 0;
274 size_t path_len = 0;
275 char path[UNIX_PATH_MAX + 1];
276
Dmitry V. Levin3d0f55e2016-01-24 01:46:40 +0300277 if (rta_len < 0)
Dmitry V. Levin3c86e0e2016-01-30 23:50:54 +0000278 return -1;
Masatake YAMATO120e5db2014-12-24 20:59:31 +0900279 if (diag_msg->udiag_ino != inode)
Dmitry V. Levin3c86e0e2016-01-30 23:50:54 +0000280 return 0;
Masatake YAMATO120e5db2014-12-24 20:59:31 +0900281 if (diag_msg->udiag_family != AF_UNIX)
Dmitry V. Levin3c86e0e2016-01-30 23:50:54 +0000282 return -1;
Masatake YAMATO120e5db2014-12-24 20:59:31 +0900283
284 for (attr = (struct rtattr *) (diag_msg + 1);
285 RTA_OK(attr, rta_len);
286 attr = RTA_NEXT(attr, rta_len)) {
287 switch (attr->rta_type) {
288 case UNIX_DIAG_NAME:
289 if (!path_len) {
290 path_len = RTA_PAYLOAD(attr);
291 if (path_len > UNIX_PATH_MAX)
292 path_len = UNIX_PATH_MAX;
293 memcpy(path, RTA_DATA(attr), path_len);
294 path[path_len] = '\0';
295 }
296 break;
297 case UNIX_DIAG_PEER:
298 if (RTA_PAYLOAD(attr) >= 4)
Dmitry V. Levin3c86e0e2016-01-30 23:50:54 +0000299 peer = *(uint32_t *) RTA_DATA(attr);
Masatake YAMATO120e5db2014-12-24 20:59:31 +0900300 break;
301 }
302 }
303
304 /*
305 * print obtained information in the following format:
306 * "UNIX:[" SELF_INODE [ "->" PEER_INODE ][ "," SOCKET_FILE ] "]"
307 */
Dmitry V. Levin3c17d1b2016-02-01 23:14:59 +0000308 if (!peer && !path_len)
Dmitry V. Levin3c86e0e2016-01-30 23:50:54 +0000309 return -1;
Dmitry V. Levin3c17d1b2016-02-01 23:14:59 +0000310
311 char peer_str[3 + sizeof(peer) * 3];
312 if (peer)
313 snprintf(peer_str, sizeof(peer_str), "->%u", peer);
314 else
315 peer_str[0] = '\0';
316
317 const char *path_str;
318 if (path_len) {
319 char *outstr = alloca(4 * path_len + 4);
320
321 outstr[0] = ',';
322 if (path[0] == '\0') {
323 outstr[1] = '@';
324 string_quote(path + 1, outstr + 2,
325 path_len - 1, QUOTE_0_TERMINATED);
326 } else {
327 string_quote(path, outstr + 1,
328 path_len, QUOTE_0_TERMINATED);
329 }
330 path_str = outstr;
331 } else {
332 path_str = "";
333 }
334
335 char *details;
336 if (asprintf(&details, "%s:[%lu%s%s]", proto_name, inode,
337 peer_str, path_str) < 0)
338 return -1;
339
340 return cache_and_print_inode_details(inode, details);
Masatake YAMATO120e5db2014-12-24 20:59:31 +0900341}
342
343static bool
Fabien Siron814c0d52016-05-17 10:08:47 +0000344netlink_send_query(const int fd, const unsigned long inode)
345{
346 struct {
347 const struct nlmsghdr nlh;
348 const struct netlink_diag_req ndr;
349 } req = {
350 .nlh = {
351 .nlmsg_len = sizeof(req),
352 .nlmsg_type = SOCK_DIAG_BY_FAMILY,
353 .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST
354 },
355 .ndr = {
356 .sdiag_family = AF_NETLINK,
357 .sdiag_protocol = NDIAG_PROTO_ALL,
358 .ndiag_show = NDIAG_SHOW_MEMINFO
359 }
360 };
361 return send_query(fd, &req, sizeof(req));
362}
363
364static int
365netlink_parse_response(const char *proto_name, const void *data,
366 const int data_len, const unsigned long inode)
367{
368 const struct netlink_diag_msg *const diag_msg = data;
369 const char *netlink_proto;
370 char *details;
371
372 if (data_len < (int) NLMSG_LENGTH(sizeof(*diag_msg)))
373 return -1;
374 if (diag_msg->ndiag_ino != inode)
375 return 0;
376
377 if (diag_msg->ndiag_family != AF_NETLINK)
378 return -1;
379
380 netlink_proto = xlookup(netlink_protocols,
381 diag_msg->ndiag_protocol);
382
383 if (netlink_proto) {
384 static const char netlink_prefix[] = "NETLINK_";
385 const size_t netlink_prefix_len =
386 sizeof(netlink_prefix) -1;
387 if (strncmp(netlink_proto, netlink_prefix,
388 netlink_prefix_len) == 0)
389 netlink_proto += netlink_prefix_len;
390 if (asprintf(&details, "%s:[%s:%u]", proto_name,
391 netlink_proto, diag_msg->ndiag_portid) < 0)
392 return -1;
393 } else {
394 if (asprintf(&details, "%s:[%u]", proto_name,
395 (unsigned) diag_msg->ndiag_protocol) < 0)
396 return -1;
397 }
398
399 return cache_and_print_inode_details(inode, details);
400}
401
402static bool
Dmitry V. Levinea218232016-02-10 17:43:09 +0000403unix_print(const int fd, const unsigned long inode)
Masatake YAMATO120e5db2014-12-24 20:59:31 +0900404{
405 return unix_send_query(fd, inode)
Dmitry V. Levin959205c2014-12-26 23:29:26 +0000406 && receive_responses(fd, inode, "UNIX", unix_parse_response);
Masatake YAMATOf605e922014-12-10 12:55:06 +0900407}
408
Dmitry V. Levinbcf59752016-02-10 17:39:57 +0000409static bool
410tcp_v4_print(const int fd, const unsigned long inode)
411{
412 return inet_print(fd, AF_INET, IPPROTO_TCP, inode, "TCP");
413}
414
415static bool
416udp_v4_print(const int fd, const unsigned long inode)
417{
418 return inet_print(fd, AF_INET, IPPROTO_UDP, inode, "UDP");
419}
420
421static bool
422tcp_v6_print(const int fd, const unsigned long inode)
423{
424 return inet_print(fd, AF_INET6, IPPROTO_TCP, inode, "TCPv6");
425}
426
427static bool
428udp_v6_print(const int fd, const unsigned long inode)
429{
430 return inet_print(fd, AF_INET6, IPPROTO_UDP, inode, "UDPv6");
431}
432
Fabien Siron814c0d52016-05-17 10:08:47 +0000433static bool
434netlink_print(const int fd, const unsigned long inode)
435{
436 return netlink_send_query(fd, inode)
437 && receive_responses(fd, inode, "NETLINK",
438 netlink_parse_response);
439}
440
Fabien Siron802cc282016-06-17 16:29:53 +0000441static const struct {
442 const char *const name;
443 bool (*const print)(int, unsigned long);
444} protocols[] = {
445 [SOCK_PROTO_UNIX] = { "UNIX", unix_print },
446 [SOCK_PROTO_TCP] = { "TCP", tcp_v4_print },
447 [SOCK_PROTO_UDP] = { "UDP", udp_v4_print },
448 [SOCK_PROTO_TCPv6] = { "TCPv6", tcp_v6_print },
449 [SOCK_PROTO_UDPv6] = { "UDPv6", udp_v6_print },
450 [SOCK_PROTO_NETLINK] = { "NETLINK", netlink_print }
451};
452
453enum sock_proto
454get_proto_by_name(const char *const name)
455{
456 unsigned int i;
457 for (i = (unsigned int) SOCK_PROTO_UNKNOWN + 1;
458 i < ARRAY_SIZE(protocols); ++i) {
459 if (protocols[i].name && !strcmp(name, protocols[i].name))
460 return (enum sock_proto) i;
461 }
462 return SOCK_PROTO_UNKNOWN;
463}
464
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000465/* Given an inode number of a socket, print out the details
466 * of the ip address and port. */
Fabien Siron802cc282016-06-17 16:29:53 +0000467
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000468bool
Fabien Siron802cc282016-06-17 16:29:53 +0000469print_sockaddr_by_inode(const unsigned long inode, const enum sock_proto proto)
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000470{
Fabien Siron802cc282016-06-17 16:29:53 +0000471 if ((unsigned int) proto >= ARRAY_SIZE(protocols) ||
472 (proto != SOCK_PROTO_UNKNOWN && !protocols[proto].print))
473 return false;
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000474
Dmitry V. Levinbcf59752016-02-10 17:39:57 +0000475 const int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000476 if (fd < 0)
477 return false;
Dmitry V. Levinbcf59752016-02-10 17:39:57 +0000478 bool r = false;
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000479
Fabien Siron802cc282016-06-17 16:29:53 +0000480 if (proto != SOCK_PROTO_UNKNOWN) {
481 r = protocols[proto].print(fd, inode);
Dmitry V. Levinea8b8e32016-01-23 16:35:02 +0000482 if (!r) {
Fabien Siron802cc282016-06-17 16:29:53 +0000483 tprintf("%s:[%lu]", protocols[proto].name, inode);
Dmitry V. Levinea8b8e32016-01-23 16:35:02 +0000484 r = true;
485 }
Masatake YAMATOf605e922014-12-10 12:55:06 +0900486 } else {
Fabien Siron802cc282016-06-17 16:29:53 +0000487 unsigned int i;
488 for (i = (unsigned int) SOCK_PROTO_UNKNOWN + 1;
489 i < ARRAY_SIZE(protocols); ++i) {
490 if (!protocols[i].print)
491 continue;
492 r = protocols[i].print(fd, inode);
493 if (r)
Dmitry V. Levin959205c2014-12-26 23:29:26 +0000494 break;
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000495 }
496 }
Dmitry V. Levin959205c2014-12-26 23:29:26 +0000497
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000498 close(fd);
Masatake YAMATOf605e922014-12-10 12:55:06 +0900499 return r;
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000500}