]> granicus.if.org Git - strace/blob - socketutils.c
rtnl_link: print pad field in the struct ifla_port_vsi decoder
[strace] / socketutils.c
1 /*
2  * Copyright (c) 2014 Zubin Mithra <zubin.mithra@gmail.com>
3  * Copyright (c) 2014-2016 Dmitry V. Levin <ldv@altlinux.org>
4  * Copyright (c) 2014-2018 The strace developers.
5  * All rights reserved.
6  *
7  * SPDX-License-Identifier: LGPL-2.1-or-later
8  */
9
10 #include "defs.h"
11 #include <netinet/in.h>
12 #include <sys/socket.h>
13 #include <arpa/inet.h>
14 #include "netlink.h"
15 #include <linux/sock_diag.h>
16 #include <linux/inet_diag.h>
17 #include <linux/unix_diag.h>
18 #include <linux/netlink_diag.h>
19 #include <linux/rtnetlink.h>
20 #include <linux/genetlink.h>
21
22 #include <sys/un.h>
23 #ifndef UNIX_PATH_MAX
24 # define UNIX_PATH_MAX sizeof(((struct sockaddr_un *) 0)->sun_path)
25 #endif
26
27 #include "xstring.h"
28
29 #define XLAT_MACROS_ONLY
30 #include "xlat/inet_protocols.h"
31 #undef XLAT_MACROS_ONLY
32
33 typedef struct {
34         unsigned long inode;
35         char *details;
36 } cache_entry;
37
38 #define CACHE_SIZE 1024U
39 static cache_entry cache[CACHE_SIZE];
40 #define CACHE_MASK (CACHE_SIZE - 1)
41
42 static int
43 cache_inode_details(const unsigned long inode, char *const details)
44 {
45         cache_entry *e = &cache[inode & CACHE_MASK];
46         free(e->details);
47         e->inode = inode;
48         e->details = details;
49
50         return 1;
51 }
52
53 static const char *
54 get_sockaddr_by_inode_cached(const unsigned long inode)
55 {
56         const cache_entry *const e = &cache[inode & CACHE_MASK];
57         return (e && inode == e->inode) ? e->details : NULL;
58 }
59
60 static bool
61 print_sockaddr_by_inode_cached(const unsigned long inode)
62 {
63         const char *const details = get_sockaddr_by_inode_cached(inode);
64         if (details) {
65                 tprints(details);
66                 return true;
67         }
68         return false;
69 }
70
71 static bool
72 send_query(struct tcb *tcp, const int fd, void *req, size_t req_size)
73 {
74         struct sockaddr_nl nladdr = {
75                 .nl_family = AF_NETLINK
76         };
77         struct iovec iov = {
78                 .iov_base = req,
79                 .iov_len = req_size
80         };
81         const struct msghdr msg = {
82                 .msg_name = &nladdr,
83                 .msg_namelen = sizeof(nladdr),
84                 .msg_iov = &iov,
85                 .msg_iovlen = 1
86         };
87
88         for (;;) {
89                 if (sendmsg(fd, &msg, 0) < 0) {
90                         if (errno == EINTR)
91                                 continue;
92                         return false;
93                 }
94                 return true;
95         }
96 }
97
98 static bool
99 inet_send_query(struct tcb *tcp, const int fd, const int family,
100                 const int proto)
101 {
102         struct {
103                 const struct nlmsghdr nlh;
104                 const struct inet_diag_req_v2 idr;
105         } req = {
106                 .nlh = {
107                         .nlmsg_len = sizeof(req),
108                         .nlmsg_type = SOCK_DIAG_BY_FAMILY,
109                         .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST
110                 },
111                 .idr = {
112                         .sdiag_family = family,
113                         .sdiag_protocol = proto,
114                         .idiag_states = -1
115                 }
116         };
117         return send_query(tcp, fd, &req, sizeof(req));
118 }
119
120 static int
121 inet_parse_response(const void *const data, const int data_len,
122                     const unsigned long inode, void *opaque_data)
123 {
124         const char *const proto_name = opaque_data;
125         const struct inet_diag_msg *const diag_msg = data;
126         static const char zero_addr[sizeof(struct in6_addr)];
127         socklen_t addr_size, text_size;
128
129         if (data_len < (int) NLMSG_LENGTH(sizeof(*diag_msg)))
130                 return -1;
131         if (diag_msg->idiag_inode != inode)
132                 return 0;
133
134         switch (diag_msg->idiag_family) {
135                 case AF_INET:
136                         addr_size = sizeof(struct in_addr);
137                         text_size = INET_ADDRSTRLEN;
138                         break;
139                 case AF_INET6:
140                         addr_size = sizeof(struct in6_addr);
141                         text_size = INET6_ADDRSTRLEN;
142                         break;
143                 default:
144                         return -1;
145         }
146
147         char src_buf[text_size];
148         char *details;
149
150         /* open/closing brackets for IPv6 addresses */
151         const char *ob = diag_msg->idiag_family == AF_INET6 ? "[" : "";
152         const char *cb = diag_msg->idiag_family == AF_INET6 ? "]" : "";
153
154         if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_src,
155                        src_buf, text_size))
156                 return -1;
157
158         if (diag_msg->id.idiag_dport ||
159             memcmp(zero_addr, diag_msg->id.idiag_dst, addr_size)) {
160                 char dst_buf[text_size];
161
162                 if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_dst,
163                                dst_buf, text_size))
164                         return -1;
165
166                 if (asprintf(&details, "%s:[%s%s%s:%u->%s%s%s:%u]", proto_name,
167                              ob, src_buf, cb, ntohs(diag_msg->id.idiag_sport),
168                              ob, dst_buf, cb, ntohs(diag_msg->id.idiag_dport))
169                     < 0)
170                         return false;
171         } else {
172                 if (asprintf(&details, "%s:[%s%s%s:%u]",
173                              proto_name, ob, src_buf, cb,
174                              ntohs(diag_msg->id.idiag_sport)) < 0)
175                         return false;
176         }
177
178         return cache_inode_details(inode, details);
179 }
180
181 static bool
182 receive_responses(struct tcb *tcp, const int fd, const unsigned long inode,
183                   const unsigned long expected_msg_type,
184                   int (*parser)(const void *, int,
185                                 unsigned long, void *),
186                   void *opaque_data)
187 {
188         static union {
189                 struct nlmsghdr hdr;
190                 long buf[8192 / sizeof(long)];
191         } hdr_buf;
192
193         struct sockaddr_nl nladdr = {
194                 .nl_family = AF_NETLINK
195         };
196         struct iovec iov = {
197                 .iov_base = hdr_buf.buf,
198                 .iov_len = sizeof(hdr_buf.buf)
199         };
200         int flags = 0;
201
202         for (;;) {
203                 struct msghdr msg = {
204                         .msg_name = &nladdr,
205                         .msg_namelen = sizeof(nladdr),
206                         .msg_iov = &iov,
207                         .msg_iovlen = 1
208                 };
209
210                 ssize_t ret = recvmsg(fd, &msg, flags);
211                 if (ret < 0) {
212                         if (errno == EINTR)
213                                 continue;
214                         return false;
215                 }
216
217                 const struct nlmsghdr *h = &hdr_buf.hdr;
218                 if (!is_nlmsg_ok(h, ret))
219                         return false;
220                 for (; is_nlmsg_ok(h, ret); h = NLMSG_NEXT(h, ret)) {
221                         if (h->nlmsg_type != expected_msg_type)
222                                 return false;
223                         const int rc = parser(NLMSG_DATA(h),
224                                               h->nlmsg_len, inode, opaque_data);
225                         if (rc > 0)
226                                 return true;
227                         if (rc < 0)
228                                 return false;
229                 }
230                 flags = MSG_DONTWAIT;
231         }
232 }
233
234 static bool
235 unix_send_query(struct tcb *tcp, const int fd, const unsigned long inode)
236 {
237         /*
238          * The kernel bug was fixed in mainline by commit v4.5-rc6~35^2~11
239          * and backported to stable/linux-4.4.y by commit v4.4.4~297.
240          */
241         const uint16_t dump_flag =
242                 os_release < KERNEL_VERSION(4, 4, 4) ? NLM_F_DUMP : 0;
243
244         struct {
245                 const struct nlmsghdr nlh;
246                 const struct unix_diag_req udr;
247         } req = {
248                 .nlh = {
249                         .nlmsg_len = sizeof(req),
250                         .nlmsg_type = SOCK_DIAG_BY_FAMILY,
251                         .nlmsg_flags = NLM_F_REQUEST | dump_flag
252                 },
253                 .udr = {
254                         .sdiag_family = AF_UNIX,
255                         .udiag_ino = inode,
256                         .udiag_states = -1,
257                         .udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER,
258                         .udiag_cookie = { ~0U, ~0U }
259                 }
260         };
261         return send_query(tcp, fd, &req, sizeof(req));
262 }
263
264 static int
265 unix_parse_response(const void *data, const int data_len,
266                     const unsigned long inode, void *opaque_data)
267 {
268         const char *proto_name = opaque_data;
269         const struct unix_diag_msg *diag_msg = data;
270         struct rtattr *attr;
271         int rta_len = data_len - NLMSG_LENGTH(sizeof(*diag_msg));
272         uint32_t peer = 0;
273         size_t path_len = 0;
274         char path[UNIX_PATH_MAX + 1];
275
276         if (rta_len < 0)
277                 return -1;
278         if (diag_msg->udiag_ino != inode)
279                 return 0;
280         if (diag_msg->udiag_family != AF_UNIX)
281                 return -1;
282
283         for (attr = (struct rtattr *) (diag_msg + 1);
284              RTA_OK(attr, rta_len);
285              attr = RTA_NEXT(attr, rta_len)) {
286                 switch (attr->rta_type) {
287                 case UNIX_DIAG_NAME:
288                         if (!path_len) {
289                                 path_len = RTA_PAYLOAD(attr);
290                                 if (path_len > UNIX_PATH_MAX)
291                                         path_len = UNIX_PATH_MAX;
292                                 memcpy(path, RTA_DATA(attr), path_len);
293                                 path[path_len] = '\0';
294                         }
295                         break;
296                 case UNIX_DIAG_PEER:
297                         if (RTA_PAYLOAD(attr) >= 4)
298                                 peer = *(uint32_t *) RTA_DATA(attr);
299                         break;
300                 }
301         }
302
303         /*
304          * print obtained information in the following format:
305          * "UNIX:[" SELF_INODE [ "->" PEER_INODE ][ "," SOCKET_FILE ] "]"
306          */
307         if (!peer && !path_len)
308                 return -1;
309
310         char peer_str[3 + sizeof(peer) * 3];
311         if (peer)
312                 xsprintf(peer_str, "->%u", peer);
313         else
314                 peer_str[0] = '\0';
315
316         const char *path_str;
317         if (path_len) {
318                 char *outstr = alloca(4 * path_len + 4);
319
320                 outstr[0] = ',';
321                 if (path[0] == '\0') {
322                         outstr[1] = '@';
323                         string_quote(path + 1, outstr + 2,
324                                      path_len - 1, QUOTE_0_TERMINATED, NULL);
325                 } else {
326                         string_quote(path, outstr + 1,
327                                      path_len, QUOTE_0_TERMINATED, NULL);
328                 }
329                 path_str = outstr;
330         } else {
331                 path_str = "";
332         }
333
334         char *details;
335         if (asprintf(&details, "%s:[%lu%s%s]", proto_name, inode,
336                      peer_str, path_str) < 0)
337                 return -1;
338
339         return cache_inode_details(inode, details);
340 }
341
342 static bool
343 netlink_send_query(struct tcb *tcp, const int fd, const unsigned long inode)
344 {
345         struct {
346                 const struct nlmsghdr nlh;
347                 const struct netlink_diag_req ndr;
348         } req = {
349                 .nlh = {
350                         .nlmsg_len = sizeof(req),
351                         .nlmsg_type = SOCK_DIAG_BY_FAMILY,
352                         .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST
353                 },
354                 .ndr = {
355                         .sdiag_family = AF_NETLINK,
356                         .sdiag_protocol = NDIAG_PROTO_ALL
357                 }
358         };
359         return send_query(tcp, fd, &req, sizeof(req));
360 }
361
362 static int
363 netlink_parse_response(const void *data, const int data_len,
364                        const unsigned long inode, void *opaque_data)
365 {
366         const char *proto_name = opaque_data;
367         const struct netlink_diag_msg *const diag_msg = data;
368         const char *netlink_proto;
369         char *details;
370
371         if (data_len < (int) NLMSG_LENGTH(sizeof(*diag_msg)))
372                 return -1;
373         if (diag_msg->ndiag_ino != inode)
374                 return 0;
375
376         if (diag_msg->ndiag_family != AF_NETLINK)
377                 return -1;
378
379         netlink_proto = xlookup(netlink_protocols,
380                                 diag_msg->ndiag_protocol);
381
382         if (netlink_proto) {
383                 netlink_proto = STR_STRIP_PREFIX(netlink_proto, "NETLINK_");
384                 if (asprintf(&details, "%s:[%s:%u]", proto_name,
385                              netlink_proto, diag_msg->ndiag_portid) < 0)
386                         return -1;
387         } else {
388                 if (asprintf(&details, "%s:[%u]", proto_name,
389                              (unsigned) diag_msg->ndiag_protocol) < 0)
390                         return -1;
391         }
392
393         return cache_inode_details(inode, details);
394 }
395
396 static const char *
397 unix_get(struct tcb *tcp, const int fd, const int family, const int proto,
398          const unsigned long inode, const char *name)
399 {
400         return unix_send_query(tcp, fd, inode)
401                 && receive_responses(tcp, fd, inode, SOCK_DIAG_BY_FAMILY,
402                                      unix_parse_response, (void *) name)
403                 ? get_sockaddr_by_inode_cached(inode) : NULL;
404 }
405
406 static const char *
407 inet_get(struct tcb *tcp, const int fd, const int family, const int protocol,
408          const unsigned long inode, const char *proto_name)
409 {
410         return inet_send_query(tcp, fd, family, protocol)
411                 && receive_responses(tcp, fd, inode, SOCK_DIAG_BY_FAMILY,
412                                      inet_parse_response, (void *) proto_name)
413                 ? get_sockaddr_by_inode_cached(inode) : NULL;
414 }
415
416 static const char *
417 netlink_get(struct tcb *tcp, const int fd, const int family, const int protocol,
418             const unsigned long inode, const char *proto_name)
419 {
420         return netlink_send_query(tcp, fd, inode)
421                 && receive_responses(tcp, fd, inode, SOCK_DIAG_BY_FAMILY,
422                                      netlink_parse_response,
423                                      (void *) proto_name)
424                 ? get_sockaddr_by_inode_cached(inode) : NULL;
425 }
426
427 static const struct {
428         const char *const name;
429         const char * (*const get)(struct tcb *, int fd, int family,
430                                   int protocol, unsigned long inode,
431                                   const char *proto_name);
432         int family;
433         int proto;
434 } protocols[] = {
435         [SOCK_PROTO_UNIX]       = { "UNIX",     unix_get,       AF_UNIX},
436         /*
437          * inet_diag handlers are currently implemented only for TCP,
438          * UDP(lite), SCTP, RAW, and DCCP, but we try to resolve it for all
439          * protocols anyway, just in case.
440          */
441         [SOCK_PROTO_TCP]        =
442                 { "TCP",        inet_get, AF_INET,  IPPROTO_TCP },
443         [SOCK_PROTO_UDP]        =
444                 { "UDP",        inet_get, AF_INET,  IPPROTO_UDP },
445         [SOCK_PROTO_UDPLITE]    =
446                 { "UDPLITE",    inet_get, AF_INET,  IPPROTO_UDPLITE },
447         [SOCK_PROTO_DCCP]       =
448                 { "DCCP",       inet_get, AF_INET,  IPPROTO_DCCP },
449         [SOCK_PROTO_SCTP]       =
450                 { "SCTP",       inet_get, AF_INET,  IPPROTO_SCTP },
451         [SOCK_PROTO_L2TP_IP]    =
452                 { "L2TP/IP",    inet_get, AF_INET,  IPPROTO_L2TP },
453         [SOCK_PROTO_PING]       =
454                 { "PING",       inet_get, AF_INET,  IPPROTO_ICMP },
455         [SOCK_PROTO_RAW]        =
456                 { "RAW",        inet_get, AF_INET,  IPPROTO_RAW },
457         [SOCK_PROTO_TCPv6]      =
458                 { "TCPv6",      inet_get, AF_INET6, IPPROTO_TCP },
459         [SOCK_PROTO_UDPv6]      =
460                 { "UDPv6",      inet_get, AF_INET6, IPPROTO_UDP },
461         [SOCK_PROTO_UDPLITEv6]  =
462                 { "UDPLITEv6",  inet_get, AF_INET6, IPPROTO_UDPLITE },
463         [SOCK_PROTO_DCCPv6]     =
464                 { "DCCPv6",     inet_get, AF_INET6, IPPROTO_DCCP },
465         [SOCK_PROTO_SCTPv6]     =
466                 { "SCTPv6",     inet_get, AF_INET6, IPPROTO_SCTP },
467         [SOCK_PROTO_L2TP_IPv6]  =
468                 { "L2TP/IPv6",  inet_get, AF_INET6, IPPROTO_L2TP },
469         [SOCK_PROTO_PINGv6]     =
470                 { "PINGv6",     inet_get, AF_INET6, IPPROTO_ICMP },
471         [SOCK_PROTO_RAWv6]      =
472                 { "RAWv6",      inet_get, AF_INET6, IPPROTO_RAW },
473         [SOCK_PROTO_NETLINK]    = { "NETLINK",  netlink_get,    AF_NETLINK },
474 };
475
476 enum sock_proto
477 get_proto_by_name(const char *const name)
478 {
479         unsigned int i;
480         for (i = (unsigned int) SOCK_PROTO_UNKNOWN + 1;
481              i < ARRAY_SIZE(protocols); ++i) {
482                 if (protocols[i].name && !strcmp(name, protocols[i].name))
483                         return (enum sock_proto) i;
484         }
485         return SOCK_PROTO_UNKNOWN;
486 }
487
488 int
489 get_family_by_proto(enum sock_proto proto)
490 {
491         if ((size_t) proto < ARRAY_SIZE(protocols))
492                 return protocols[proto].family;
493
494         return AF_UNSPEC;
495 }
496
497 static const char *
498 get_sockaddr_by_inode_uncached(struct tcb *tcp, const unsigned long inode,
499                                const enum sock_proto proto)
500 {
501         if ((unsigned int) proto >= ARRAY_SIZE(protocols) ||
502             (proto != SOCK_PROTO_UNKNOWN && !protocols[proto].get))
503                 return NULL;
504
505         const int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
506         if (fd < 0)
507                 return NULL;
508         const char *details = NULL;
509
510         if (proto != SOCK_PROTO_UNKNOWN) {
511                 details = protocols[proto].get(tcp, fd, protocols[proto].family,
512                                                protocols[proto].proto, inode,
513                                                protocols[proto].name);
514         } else {
515                 unsigned int i;
516                 for (i = (unsigned int) SOCK_PROTO_UNKNOWN + 1;
517                      i < ARRAY_SIZE(protocols); ++i) {
518                         if (!protocols[i].get)
519                                 continue;
520                         details = protocols[i].get(tcp, fd,
521                                                    protocols[proto].family,
522                                                    protocols[proto].proto,
523                                                    inode,
524                                                    protocols[proto].name);
525                         if (details)
526                                 break;
527                 }
528         }
529
530         close(fd);
531         return details;
532 }
533
534 static bool
535 print_sockaddr_by_inode_uncached(struct tcb *tcp, const unsigned long inode,
536                                  const enum sock_proto proto)
537 {
538         const char *details = get_sockaddr_by_inode_uncached(tcp, inode, proto);
539
540         if (details) {
541                 tprints(details);
542                 return true;
543         }
544
545         if ((unsigned int) proto < ARRAY_SIZE(protocols) &&
546             protocols[proto].name) {
547                 tprintf("%s:[%lu]", protocols[proto].name, inode);
548                 return true;
549         }
550
551         return false;
552 }
553
554 /* Given an inode number of a socket, return its protocol details.  */
555 const char *
556 get_sockaddr_by_inode(struct tcb *const tcp, const int fd,
557                       const unsigned long inode)
558 {
559         const char *details = get_sockaddr_by_inode_cached(inode);
560         return details ? details :
561                 get_sockaddr_by_inode_uncached(tcp, inode, getfdproto(tcp, fd));
562 }
563
564 /* Given an inode number of a socket, print out its protocol details.  */
565 bool
566 print_sockaddr_by_inode(struct tcb *const tcp, const int fd,
567                         const unsigned long inode)
568 {
569         return print_sockaddr_by_inode_cached(inode) ? true :
570                 print_sockaddr_by_inode_uncached(tcp, inode,
571                                                  getfdproto(tcp, fd));
572 }
573
574 /*
575  * Managing the cache for decoding communications of Netlink GENERIC protocol
576  *
577  * As name shown Netlink GENERIC protocol is generic protocol. The
578  * numbers of msg types used in the protocol are not defined
579  * statically. Kernel defines them on demand.  So the xlat converted
580  * from header files doesn't help for decoding the protocol. Following
581  * codes are building xlat(dyxlat) at runtime.
582  */
583 static bool
584 genl_send_dump_families(struct tcb *tcp, const int fd)
585 {
586         struct {
587                 const struct nlmsghdr nlh;
588                 struct genlmsghdr gnlh;
589         } req = {
590                 .nlh = {
591                         .nlmsg_len = sizeof(req),
592                         .nlmsg_type = GENL_ID_CTRL,
593                         .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
594                 },
595                 .gnlh = {
596                         .cmd = CTRL_CMD_GETFAMILY,
597                 }
598         };
599         return send_query(tcp, fd, &req, sizeof(req));
600 }
601
602 static int
603 genl_parse_families_response(const void *const data,
604                              const int data_len, const unsigned long inode,
605                              void *opaque_data)
606 {
607         struct dyxlat *const dyxlat = opaque_data;
608         const struct genlmsghdr *const gnlh = data;
609         struct rtattr *attr;
610         int rta_len = data_len - NLMSG_LENGTH(sizeof(*gnlh));
611
612         char *name = NULL;
613         unsigned int name_len = 0;
614         uint16_t *id = NULL;
615
616         if (rta_len < 0)
617                 return -1;
618         if (gnlh->cmd != CTRL_CMD_NEWFAMILY)
619                 return -1;
620         if (gnlh->version != 2)
621                 return -1;
622
623         for (attr = (struct rtattr *) (gnlh + 1);
624              RTA_OK(attr, rta_len);
625              attr = RTA_NEXT(attr, rta_len)) {
626                 switch (attr->rta_type) {
627                 case CTRL_ATTR_FAMILY_NAME:
628                         if (!name) {
629                                 name = RTA_DATA(attr);
630                                 name_len = RTA_PAYLOAD(attr);
631                         }
632                         break;
633                 case CTRL_ATTR_FAMILY_ID:
634                         if (!id && RTA_PAYLOAD(attr) == sizeof(*id))
635                                 id = RTA_DATA(attr);
636                         break;
637                 }
638
639                 if (name && id) {
640                         dyxlat_add_pair(dyxlat, *id, name, name_len);
641                         name = NULL;
642                         id = NULL;
643                 }
644         }
645
646         return 0;
647 }
648
649 const struct xlat *
650 genl_families_xlat(struct tcb *tcp)
651 {
652         static struct dyxlat *dyxlat;
653
654         if (!dyxlat) {
655                 dyxlat = dyxlat_alloc(32);
656
657                 int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
658                 if (fd < 0)
659                         goto out;
660
661                 if (genl_send_dump_families(tcp, fd))
662                         receive_responses(tcp, fd, 0, GENL_ID_CTRL,
663                                           genl_parse_families_response, dyxlat);
664                 close(fd);
665         }
666
667 out:
668         return dyxlat_get(dyxlat);
669 }