From: Dmitry V. Levin Date: Wed, 19 Jul 2017 10:07:34 +0000 (+0000) Subject: Move family-specific NETLINK_SOCK_DIAG parsers to separate files X-Git-Tag: v4.19~240 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bf24770d91c6141796d959f76fd531728c2095a6;p=strace Move family-specific NETLINK_SOCK_DIAG parsers to separate files Split netlink_sock_diag.c that grew too big. * defs.h (tcp_states, tcp_state_flags): New xlat prototypes. * netlink_sock_diag.h: New file. * netlink_inet_diag.c: Likewise. * netlink_netlink_diag.c: Likewise. * netlink_packet_diag.c: Likewise. * netlink_smc_diag.c: Likewise. * netlink_unix_diag.c: Likewise. * Makefile.am (strace_SOURCES): Add them. * netlink_sock_diag.c: Move family-specific parsers and associated header includes to separate files. * nlattr.h (DECL_NLA(meminfo)): New prototype. * nlattr.c: Include . (print_meminfo, decode_nla_meminfo): New functions from netlink_sock_diag.c. --- diff --git a/Makefile.am b/Makefile.am index 03f26245..7d9353c7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -183,8 +183,14 @@ strace_SOURCES = \ net.c \ netlink.c \ netlink.h \ + netlink_sock_diag.h \ + netlink_inet_diag.c \ + netlink_netlink_diag.c \ + netlink_packet_diag.c \ netlink_selinux.c \ + netlink_smc_diag.c \ netlink_sock_diag.c \ + netlink_unix_diag.c \ nlattr.c \ nlattr.h \ nsfs.c \ diff --git a/defs.h b/defs.h index 4a77008d..40489155 100644 --- a/defs.h +++ b/defs.h @@ -302,6 +302,8 @@ extern const struct xlat setns_types[]; extern const struct xlat sg_io_info[]; extern const struct xlat socketlayers[]; extern const struct xlat socktypes[]; +extern const struct xlat tcp_state_flags[]; +extern const struct xlat tcp_states[]; extern const struct xlat whence_codes[]; /* Format of syscall return values */ diff --git a/netlink_inet_diag.c b/netlink_inet_diag.c new file mode 100644 index 00000000..eb216f58 --- /dev/null +++ b/netlink_inet_diag.c @@ -0,0 +1,467 @@ +/* + * Copyright (c) 2016 Fabien Siron + * Copyright (c) 2017 JingPiao Chen + * Copyright (c) 2017 The strace developers. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "defs.h" +#include "netlink.h" +#include "netlink_sock_diag.h" +#include "nlattr.h" +#include "print_fields.h" + +#include + +#include +#include + +#include "xlat/inet_diag_attrs.h" +#include "xlat/inet_diag_bytecodes.h" +#include "xlat/inet_diag_extended_flags.h" +#include "xlat/inet_diag_req_attrs.h" + +#include "xlat/tcp_states.h" +#include "xlat/tcp_state_flags.h" + +void +print_inet_diag_sockid(const struct inet_diag_sockid *id, const uint8_t family) +{ + PRINT_FIELD_NET_PORT("{", *id, idiag_sport); + PRINT_FIELD_NET_PORT(", ", *id, idiag_dport); + PRINT_FIELD_INET_ADDR(", ", *id, idiag_src, family); + PRINT_FIELD_INET_ADDR(", ", *id, idiag_dst, family); + PRINT_FIELD_IFINDEX(", ", *id, idiag_if); + PRINT_FIELD_COOKIE(", ", *id, idiag_cookie); + tprints("}"); +} + +static void +decode_inet_addr(struct tcb *const tcp, + const kernel_ulong_t addr, + const unsigned int len, + const int family) +{ + union { + struct in_addr a4; + struct in6_addr a6; + } addrbuf; + size_t size = 0; + + switch (family) { + case AF_INET: + size = sizeof(addrbuf.a4); + break; + case AF_INET6: + size = sizeof(addrbuf.a6); + break; + } + + if (!size || len < size) { + tprints("addr="); + printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX); + return; + } + + if (umoven(tcp, addr, size, &addrbuf) < 0) { + tprints("addr="); + printaddr(addr); + return; + } + + print_inet_addr(family, &addrbuf, size, "addr"); +} + +static void +decode_inet_diag_hostcond(struct tcb *const tcp, + const kernel_ulong_t addr, + const unsigned int len) +{ + struct inet_diag_hostcond cond; + + if (len < sizeof(cond)) { + printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX); + return; + } + if (umove_or_printaddr(tcp, addr, &cond)) + return; + + PRINT_FIELD_XVAL("{", cond, family, addrfams, "AF_???"); + PRINT_FIELD_U(", ", cond, prefix_len); + PRINT_FIELD_U(", ", cond, port); + + if (len > sizeof(cond)) { + tprints(", "); + decode_inet_addr(tcp, addr + sizeof(cond), + len - sizeof(cond), cond.family); + } + tprints("}"); +} + +static void +print_inet_diag_bc_op(const struct inet_diag_bc_op *const op) +{ + PRINT_FIELD_XVAL("{", *op, code, inet_diag_bytecodes, + "INET_DIAG_BC_???"); + PRINT_FIELD_U(", ", *op, yes); + PRINT_FIELD_U(", ", *op, no); + tprints("}"); +} + +static void +decode_inet_diag_markcond(struct tcb *const tcp, + const kernel_ulong_t addr, + const unsigned int len) +{ + struct inet_diag_markcond markcond; + + if (len < sizeof(markcond)) + printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX); + else if (!umove_or_printaddr(tcp, addr, &markcond)) { + PRINT_FIELD_U("{", markcond, mark); + PRINT_FIELD_U(", ", markcond, mask); + tprints("}"); + } +} + +static void +decode_bytecode_data(struct tcb *const tcp, + const kernel_ulong_t addr, + const unsigned int len, + const unsigned char code) +{ + switch (code) { + case INET_DIAG_BC_S_COND: + case INET_DIAG_BC_D_COND: + decode_inet_diag_hostcond(tcp, addr, len); + break; + case INET_DIAG_BC_DEV_COND: { + uint32_t ifindex; + + if (len < sizeof(ifindex)) + printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX); + else if (!umove_or_printaddr(tcp, addr, &ifindex)) + print_ifindex(ifindex); + break; + } + case INET_DIAG_BC_S_GE: + case INET_DIAG_BC_S_LE: + case INET_DIAG_BC_D_GE: + case INET_DIAG_BC_D_LE: { + struct inet_diag_bc_op op; + + if (len < sizeof(op)) + printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX); + else if (!umove_or_printaddr(tcp, addr, &op)) + print_inet_diag_bc_op(&op); + break; + } + case INET_DIAG_BC_MARK_COND: + decode_inet_diag_markcond(tcp, addr, len); + break; + case INET_DIAG_BC_AUTO: + case INET_DIAG_BC_JMP: + case INET_DIAG_BC_NOP: + default: + printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX); + break; + } +} + +static bool +decode_inet_diag_bc_op(struct tcb *const tcp, + const kernel_ulong_t addr, + const unsigned int len, + const void *const opaque_data) +{ + struct inet_diag_bc_op op; + + if (len < sizeof(op)) + return false; + if (umove_or_printaddr(tcp, addr, &op)) + return true; + + if (len > sizeof(op)) + tprints("{"); + + print_inet_diag_bc_op(&op); + + if (len > sizeof(op)) { + tprints(", "); + decode_bytecode_data(tcp, addr + sizeof(op), + len - sizeof(op), op.code); + tprints("}"); + } + + return true; +} + +static const nla_decoder_t inet_diag_req_nla_decoders[] = { + [INET_DIAG_REQ_BYTECODE] = decode_inet_diag_bc_op +}; + +static void +decode_inet_diag_req_compat(struct tcb *const tcp, + const struct nlmsghdr *const nlmsghdr, + const uint8_t family, + const kernel_ulong_t addr, + const unsigned int len) +{ + struct inet_diag_req req = { .idiag_family = family }; + size_t offset = sizeof(req.idiag_family); + bool decode_nla = false; + + PRINT_FIELD_XVAL("{", req, idiag_family, addrfams, "AF_???"); + tprints(", "); + if (len >= sizeof(req)) { + if (!umoven_or_printaddr(tcp, addr + offset, + sizeof(req) - offset, + (void *) &req + offset)) { + PRINT_FIELD_U("", req, idiag_src_len); + PRINT_FIELD_U(", ", req, idiag_dst_len); + PRINT_FIELD_FLAGS(", ", req, idiag_ext, + inet_diag_extended_flags, + "1< offset) { + tprints(", "); + decode_nlattr(tcp, addr + offset, len - offset, + inet_diag_req_attrs, "INET_DIAG_REQ_???", + inet_diag_req_nla_decoders, + ARRAY_SIZE(inet_diag_req_nla_decoders), NULL); + } +} + +static void +decode_inet_diag_req_v2(struct tcb *const tcp, + const struct nlmsghdr *const nlmsghdr, + const uint8_t family, + const kernel_ulong_t addr, + const unsigned int len) +{ + struct inet_diag_req_v2 req = { .sdiag_family = family }; + size_t offset = sizeof(req.sdiag_family); + bool decode_nla = false; + + PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???"); + tprints(", "); + if (len >= sizeof(req)) { + if (!umoven_or_printaddr(tcp, addr + offset, + sizeof(req) - offset, + (void *) &req + offset)) { + PRINT_FIELD_XVAL("", req, sdiag_protocol, + inet_protocols, "IPPROTO_???"); + PRINT_FIELD_FLAGS(", ", req, idiag_ext, + inet_diag_extended_flags, + "1< offset) { + tprints(", "); + decode_nlattr(tcp, addr + offset, len - offset, + inet_diag_req_attrs, "INET_DIAG_REQ_???", + inet_diag_req_nla_decoders, + ARRAY_SIZE(inet_diag_req_nla_decoders), NULL); + } +} + +DECL_NETLINK_DIAG_DECODER(decode_inet_diag_req) +{ + if (nlmsghdr->nlmsg_type == TCPDIAG_GETSOCK + || nlmsghdr->nlmsg_type == DCCPDIAG_GETSOCK) + return decode_inet_diag_req_compat(tcp, nlmsghdr, + family, addr, len); + else + return decode_inet_diag_req_v2(tcp, nlmsghdr, + family, addr, len); +} + +static bool +decode_inet_diag_meminfo(struct tcb *const tcp, + const kernel_ulong_t addr, + const unsigned int len, + const void *const opaque_data) +{ + struct inet_diag_meminfo minfo; + + if (len < sizeof(minfo)) + return false; + if (umove_or_printaddr(tcp, addr, &minfo)) + return true; + + PRINT_FIELD_U("{", minfo, idiag_rmem); + PRINT_FIELD_U(", ", minfo, idiag_wmem); + PRINT_FIELD_U(", ", minfo, idiag_fmem); + PRINT_FIELD_U(", ", minfo, idiag_tmem); + tprints("}"); + + return true; +} + +static bool +decode_tcpvegas_info(struct tcb *const tcp, + const kernel_ulong_t addr, + const unsigned int len, + const void *const opaque_data) +{ + struct tcpvegas_info vegas; + + if (len < sizeof(vegas)) + return false; + if (umove_or_printaddr(tcp, addr, &vegas)) + return true; + + PRINT_FIELD_U("{", vegas, tcpv_enabled); + PRINT_FIELD_U(", ", vegas, tcpv_rttcnt); + PRINT_FIELD_U(", ", vegas, tcpv_rtt); + PRINT_FIELD_U(", ", vegas, tcpv_minrtt); + tprints("}"); + + return true; +} + +static bool +decode_tcp_dctcp_info(struct tcb *const tcp, + const kernel_ulong_t addr, + const unsigned int len, + const void *const opaque_data) +{ + struct tcp_dctcp_info dctcp; + + if (len < sizeof(dctcp)) + return false; + if (umove_or_printaddr(tcp, addr, &dctcp)) + return true; + + PRINT_FIELD_U("{", dctcp, dctcp_enabled); + PRINT_FIELD_U(", ", dctcp, dctcp_ce_state); + PRINT_FIELD_U(", ", dctcp, dctcp_alpha); + PRINT_FIELD_U(", ", dctcp, dctcp_ab_ecn); + PRINT_FIELD_U(", ", dctcp, dctcp_ab_tot); + tprints("}"); + + return true; +} + +static bool +decode_tcp_bbr_info(struct tcb *const tcp, + const kernel_ulong_t addr, + const unsigned int len, + const void *const opaque_data) +{ + struct tcp_bbr_info bbr; + + if (len < sizeof(bbr)) + return false; + if (umove_or_printaddr(tcp, addr, &bbr)) + return true; + + PRINT_FIELD_X("{", bbr, bbr_bw_lo); + PRINT_FIELD_X(", ", bbr, bbr_bw_hi); + PRINT_FIELD_U(", ", bbr, bbr_min_rtt); + PRINT_FIELD_U(", ", bbr, bbr_pacing_gain); + PRINT_FIELD_U(", ", bbr, bbr_cwnd_gain); + tprints("}"); + + return true; +} + +static const nla_decoder_t inet_diag_msg_nla_decoders[] = { + [INET_DIAG_MEMINFO] = decode_inet_diag_meminfo, + [INET_DIAG_INFO] = NULL, /* unimplemented */ + [INET_DIAG_VEGASINFO] = decode_tcpvegas_info, + [INET_DIAG_CONG] = decode_nla_str, + [INET_DIAG_TOS] = decode_nla_u8, + [INET_DIAG_TCLASS] = decode_nla_u8, + [INET_DIAG_SKMEMINFO] = decode_nla_meminfo, + [INET_DIAG_SHUTDOWN] = decode_nla_u8, + [INET_DIAG_DCTCPINFO] = decode_tcp_dctcp_info, + [INET_DIAG_PROTOCOL] = decode_nla_u8, + [INET_DIAG_SKV6ONLY] = decode_nla_u8, + [INET_DIAG_LOCALS] = NULL, /* unimplemented */ + [INET_DIAG_PEERS] = NULL, /* unimplemented */ + [INET_DIAG_PAD] = NULL, + [INET_DIAG_MARK] = decode_nla_u32, + [INET_DIAG_BBRINFO] = decode_tcp_bbr_info +}; + +DECL_NETLINK_DIAG_DECODER(decode_inet_diag_msg) +{ + struct inet_diag_msg msg = { .idiag_family = family }; + size_t offset = sizeof(msg.idiag_family); + bool decode_nla = false; + + PRINT_FIELD_XVAL("{", msg, idiag_family, addrfams, "AF_???"); + tprints(", "); + if (len >= sizeof(msg)) { + if (!umoven_or_printaddr(tcp, addr + offset, + sizeof(msg) - offset, + (void *) &msg + offset)) { + PRINT_FIELD_XVAL("", msg, idiag_state, + tcp_states, "TCP_???"); + PRINT_FIELD_U(", ", msg, idiag_timer); + PRINT_FIELD_U(", ", msg, idiag_retrans); + PRINT_FIELD_INET_DIAG_SOCKID(", ", msg, id, + msg.idiag_family); + PRINT_FIELD_U(", ", msg, idiag_expires); + PRINT_FIELD_U(", ", msg, idiag_rqueue); + PRINT_FIELD_U(", ", msg, idiag_wqueue); + PRINT_FIELD_U(", ", msg, idiag_uid); + PRINT_FIELD_U(", ", msg, idiag_inode); + decode_nla = true; + } + } else + tprints("..."); + tprints("}"); + + offset = NLA_ALIGN(sizeof(msg)); + if (decode_nla && len > offset) { + tprints(", "); + decode_nlattr(tcp, addr + offset, len - offset, + inet_diag_attrs, "INET_DIAG_???", + inet_diag_msg_nla_decoders, + ARRAY_SIZE(inet_diag_msg_nla_decoders), NULL); + } +} diff --git a/netlink_netlink_diag.c b/netlink_netlink_diag.c new file mode 100644 index 00000000..b17d44fc --- /dev/null +++ b/netlink_netlink_diag.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2016 Fabien Siron + * Copyright (c) 2017 JingPiao Chen + * Copyright (c) 2017 The strace developers. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "defs.h" +#include "netlink.h" +#include "netlink_sock_diag.h" +#include "nlattr.h" +#include "print_fields.h" + +#include +#include + +#include "xlat/netlink_diag_attrs.h" +#include "xlat/netlink_diag_show.h" +#include "xlat/netlink_socket_flags.h" +#include "xlat/netlink_states.h" + +DECL_NETLINK_DIAG_DECODER(decode_netlink_diag_req) +{ + struct netlink_diag_req req = { .sdiag_family = family }; + const size_t offset = sizeof(req.sdiag_family); + + PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???"); + tprints(", "); + if (len >= sizeof(req)) { + if (!umoven_or_printaddr(tcp, addr + offset, + sizeof(req) - offset, + (void *) &req + offset)) { + if (NDIAG_PROTO_ALL == req.sdiag_protocol) + tprintf("%s=%s", + "sdiag_protocol", "NDIAG_PROTO_ALL"); + else + PRINT_FIELD_XVAL("", req, sdiag_protocol, + netlink_protocols, + "NETLINK_???"); + PRINT_FIELD_U(", ", req, ndiag_ino); + PRINT_FIELD_FLAGS(", ", req, ndiag_show, + netlink_diag_show, "NDIAG_SHOW_???"); + PRINT_FIELD_COOKIE(", ", req, ndiag_cookie); + } + } else + tprints("..."); + tprints("}"); +} + +static bool +print_group(struct tcb *const tcp, + void *const elem_buf, + const size_t elem_size, + void *const opaque_data) +{ + if (elem_size < sizeof(kernel_ulong_t)) + tprintf("%#0*x", (int) elem_size * 2 + 2, + *(unsigned int *) elem_buf); + else + tprintf("%#0*" PRI_klx, (int) elem_size * 2 + 2, + *(kernel_ulong_t *) elem_buf); + + return true; +} + +static bool +decode_netlink_diag_groups(struct tcb *const tcp, + const kernel_ulong_t addr, + const unsigned int len, + const void *const opaque_data) +{ + kernel_ulong_t buf; + const size_t nmemb = len / current_wordsize; + + if (!nmemb) + return false; + + print_array(tcp, addr, nmemb, &buf, current_wordsize, + umoven_or_printaddr, print_group, 0); + + return true; +} + +static bool +decode_netlink_diag_ring(struct tcb *const tcp, + const kernel_ulong_t addr, + const unsigned int len, + const void *const opaque_data) +{ + struct netlink_diag_ring ndr; + + if (len < sizeof(ndr)) + return false; + if (umove_or_printaddr(tcp, addr, &ndr)) + return true; + + PRINT_FIELD_U("{", ndr, ndr_block_size); + PRINT_FIELD_U(", ", ndr, ndr_block_nr); + PRINT_FIELD_U(", ", ndr, ndr_frame_size); + PRINT_FIELD_U(", ", ndr, ndr_frame_nr); + tprints("}"); + + return true; +} + +static bool +decode_netlink_diag_flags(struct tcb *const tcp, + const kernel_ulong_t addr, + const unsigned int len, + const void *const opaque_data) +{ + uint32_t flags; + + if (len < sizeof(flags)) + return false; + if (umove_or_printaddr(tcp, addr, &flags)) + return true; + + printflags(netlink_socket_flags, flags, "NDIAG_FLAG_???"); + + return true; +} + +static const nla_decoder_t netlink_diag_msg_nla_decoders[] = { + [NETLINK_DIAG_MEMINFO] = decode_nla_meminfo, + [NETLINK_DIAG_GROUPS] = decode_netlink_diag_groups, + [NETLINK_DIAG_RX_RING] = decode_netlink_diag_ring, + [NETLINK_DIAG_TX_RING] = decode_netlink_diag_ring, + [NETLINK_DIAG_FLAGS] = decode_netlink_diag_flags +}; + +DECL_NETLINK_DIAG_DECODER(decode_netlink_diag_msg) +{ + struct netlink_diag_msg msg = { .ndiag_family = family }; + size_t offset = sizeof(msg.ndiag_family); + bool decode_nla = false; + + PRINT_FIELD_XVAL("{", msg, ndiag_family, addrfams, "AF_???"); + tprints(", "); + if (len >= sizeof(msg)) { + if (!umoven_or_printaddr(tcp, addr + offset, + sizeof(msg) - offset, + (void *) &msg + offset)) { + PRINT_FIELD_XVAL("", msg, ndiag_type, + socktypes, "SOCK_???"); + PRINT_FIELD_XVAL(", ", msg, ndiag_protocol, + netlink_protocols, "NETLINK_???"); + PRINT_FIELD_XVAL(", ", msg, ndiag_state, + netlink_states, "NETLINK_???"); + PRINT_FIELD_U(", ", msg, ndiag_portid); + PRINT_FIELD_U(", ", msg, ndiag_dst_portid); + PRINT_FIELD_U(", ", msg, ndiag_dst_group); + PRINT_FIELD_U(", ", msg, ndiag_ino); + PRINT_FIELD_COOKIE(", ", msg, ndiag_cookie); + decode_nla = true; + } + } else + tprints("..."); + tprints("}"); + + offset = NLA_ALIGN(sizeof(msg)); + if (decode_nla && len > offset) { + tprints(", "); + decode_nlattr(tcp, addr + offset, len - offset, + netlink_diag_attrs, "NETLINK_DIAG_???", + netlink_diag_msg_nla_decoders, + ARRAY_SIZE(netlink_diag_msg_nla_decoders), NULL); + } +} diff --git a/netlink_packet_diag.c b/netlink_packet_diag.c new file mode 100644 index 00000000..94eff1df --- /dev/null +++ b/netlink_packet_diag.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2016 Fabien Siron + * Copyright (c) 2017 JingPiao Chen + * Copyright (c) 2017 The strace developers. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "defs.h" +#include "netlink.h" +#include "netlink_sock_diag.h" +#include "nlattr.h" +#include "print_fields.h" + +#include +#include +#include + +#include "xlat/packet_diag_attrs.h" +#include "xlat/packet_diag_info_flags.h" +#include "xlat/packet_diag_show.h" + +DECL_NETLINK_DIAG_DECODER(decode_packet_diag_req) +{ + struct packet_diag_req req = { .sdiag_family = family }; + const size_t offset = sizeof(req.sdiag_family); + + PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???"); + tprints(", "); + if (len >= sizeof(req)) { + if (!umoven_or_printaddr(tcp, addr + offset, + sizeof(req) - offset, + (void *) &req + offset)) { + PRINT_FIELD_XVAL("", req, sdiag_protocol, + ethernet_protocols, "ETH_P_???"); + PRINT_FIELD_U(", ", req, pdiag_ino); + PRINT_FIELD_FLAGS(", ", req, pdiag_show, + packet_diag_show, "PACKET_SHOW_???"); + PRINT_FIELD_COOKIE(", ", req, pdiag_cookie); + } + } else + tprints("..."); + tprints("}"); +} + +static bool +decode_packet_diag_info(struct tcb *const tcp, + const kernel_ulong_t addr, + const unsigned int len, + const void *const opaque_data) +{ + struct packet_diag_info pinfo; + + if (len < sizeof(pinfo)) + return false; + if (umove_or_printaddr(tcp, addr, &pinfo)) + return true; + + PRINT_FIELD_U("{", pinfo, pdi_index); + PRINT_FIELD_U(", ", pinfo, pdi_version); + PRINT_FIELD_U(", ", pinfo, pdi_reserve); + PRINT_FIELD_U(", ", pinfo, pdi_copy_thresh); + PRINT_FIELD_U(", ", pinfo, pdi_tstamp); + PRINT_FIELD_FLAGS(", ", pinfo, pdi_flags, + packet_diag_info_flags, "PDI_???"); + tprints("}"); + + return true; +} + +static bool +print_packet_diag_mclist(struct tcb *const tcp, void *const elem_buf, + const size_t elem_size, void *const opaque_data) +{ + struct packet_diag_mclist *dml = elem_buf; + uint16_t alen = dml->pdmc_alen > sizeof(dml->pdmc_addr) ? + sizeof(dml->pdmc_addr) : dml->pdmc_alen; + + PRINT_FIELD_IFINDEX("{", *dml, pdmc_index); + PRINT_FIELD_U(", ", *dml, pdmc_count); + PRINT_FIELD_U(", ", *dml, pdmc_type); + PRINT_FIELD_U(", ", *dml, pdmc_alen); + PRINT_FIELD_STRING(", ", *dml, pdmc_addr, alen, QUOTE_FORCE_HEX); + tprints("}"); + + return true; +} + +static bool +decode_packet_diag_mclist(struct tcb *const tcp, + const kernel_ulong_t addr, + const unsigned int len, + const void *const opaque_data) +{ + struct packet_diag_mclist dml; + const size_t nmemb = len / sizeof(dml); + + if (!nmemb) + return false; + + print_array(tcp, addr, nmemb, &dml, sizeof(dml), + umoven_or_printaddr, print_packet_diag_mclist, 0); + + return true; +} + +static bool +decode_packet_diag_ring(struct tcb *const tcp, + const kernel_ulong_t addr, + const unsigned int len, + const void *const opaque_data) +{ + struct packet_diag_ring pdr; + + if (len < sizeof(pdr)) + return false; + if (umove_or_printaddr(tcp, addr, &pdr)) + return true; + + PRINT_FIELD_U("{", pdr, pdr_block_size); + PRINT_FIELD_U(", ", pdr, pdr_block_nr); + PRINT_FIELD_U(", ", pdr, pdr_frame_size); + PRINT_FIELD_U(", ", pdr, pdr_frame_nr); + PRINT_FIELD_U(", ", pdr, pdr_retire_tmo); + PRINT_FIELD_U(", ", pdr, pdr_sizeof_priv); + PRINT_FIELD_U(", ", pdr, pdr_features); + tprints("}"); + + return true; +} + +static bool +decode_packet_diag_filter(struct tcb *const tcp, + const kernel_ulong_t addr, + const unsigned int len, + const void *const opaque_data) +{ + const unsigned int nmemb = len / sizeof(struct sock_filter); + if (!nmemb || (unsigned short) nmemb != nmemb) + return false; + + print_sock_fprog(tcp, addr, nmemb); + + return true; +} + +static const nla_decoder_t packet_diag_msg_nla_decoders[] = { + [PACKET_DIAG_INFO] = decode_packet_diag_info, + [PACKET_DIAG_MCLIST] = decode_packet_diag_mclist, + [PACKET_DIAG_RX_RING] = decode_packet_diag_ring, + [PACKET_DIAG_TX_RING] = decode_packet_diag_ring, + [PACKET_DIAG_FANOUT] = decode_nla_u32, + [PACKET_DIAG_UID] = decode_nla_u32, + [PACKET_DIAG_MEMINFO] = decode_nla_meminfo, + [PACKET_DIAG_FILTER] = decode_packet_diag_filter +}; + +DECL_NETLINK_DIAG_DECODER(decode_packet_diag_msg) +{ + struct packet_diag_msg msg = { .pdiag_family = family }; + size_t offset = sizeof(msg.pdiag_family); + bool decode_nla = false; + + PRINT_FIELD_XVAL("{", msg, pdiag_family, addrfams, "AF_???"); + tprints(", "); + if (len >= sizeof(msg)) { + if (!umoven_or_printaddr(tcp, addr + offset, + sizeof(msg) - offset, + (void *) &msg + offset)) { + PRINT_FIELD_XVAL("", msg, pdiag_type, + socktypes, "SOCK_???"); + PRINT_FIELD_U(", ", msg, pdiag_num); + PRINT_FIELD_U(", ", msg, pdiag_ino); + PRINT_FIELD_COOKIE(", ", msg, pdiag_cookie); + decode_nla = true; + } + } else + tprints("..."); + tprints("}"); + + offset = NLA_ALIGN(sizeof(msg)); + if (decode_nla && len > offset) { + tprints(", "); + decode_nlattr(tcp, addr + offset, len - offset, + packet_diag_attrs, "PACKET_DIAG_???", + packet_diag_msg_nla_decoders, + ARRAY_SIZE(packet_diag_msg_nla_decoders), NULL); + } +} diff --git a/netlink_smc_diag.c b/netlink_smc_diag.c new file mode 100644 index 00000000..2cd07ee0 --- /dev/null +++ b/netlink_smc_diag.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2017 JingPiao Chen + * Copyright (c) 2017 The strace developers. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "defs.h" +#include + +#ifdef AF_SMC + +# include "netlink.h" +# include "netlink_sock_diag.h" +# include "nlattr.h" +# include "print_fields.h" + +# include +# include + +# include "xlat/smc_diag_attrs.h" +# include "xlat/smc_diag_extended_flags.h" +# include "xlat/smc_link_group_roles.h" +# include "xlat/smc_states.h" + +DECL_NETLINK_DIAG_DECODER(decode_smc_diag_req) +{ + struct smc_diag_req req = { .diag_family = family }; + const size_t offset = sizeof(req.diag_family); + + PRINT_FIELD_XVAL("{", req, diag_family, addrfams, "AF_???"); + tprints(", "); + if (len >= sizeof(req)) { + if (!umoven_or_printaddr(tcp, addr + offset, + sizeof(req) - offset, + (void *) &req + offset)) { + PRINT_FIELD_FLAGS("", req, diag_ext, + smc_diag_extended_flags, + "1<= sizeof(msg)) { + if (!umoven_or_printaddr(tcp, addr + offset, + sizeof(msg) - offset, + (void *) &msg + offset)) { + PRINT_FIELD_XVAL("", msg, diag_state, + smc_states, "SMC_???"); + PRINT_FIELD_U(", ", msg, diag_fallback); + PRINT_FIELD_U(", ", msg, diag_shutdown); + /* + * AF_SMC protocol family socket handler + * keeping the AF_INET sock address. + */ + PRINT_FIELD_INET_DIAG_SOCKID(", ", msg, id, AF_INET); + PRINT_FIELD_U(", ", msg, diag_uid); + PRINT_FIELD_U(", ", msg, diag_inode); + decode_nla = true; + } + } else + tprints("..."); + tprints("}"); + + offset = NLA_ALIGN(sizeof(msg)); + if (decode_nla && len > offset) { + tprints(", "); + decode_nlattr(tcp, addr + offset, len - offset, + smc_diag_attrs, "SMC_DIAG_???", + smc_diag_msg_nla_decoders, + ARRAY_SIZE(smc_diag_msg_nla_decoders), NULL); + } +} + +#endif /* AF_SMC */ diff --git a/netlink_sock_diag.c b/netlink_sock_diag.c index cd4e54e7..dd1e03d3 100644 --- a/netlink_sock_diag.c +++ b/netlink_sock_diag.c @@ -29,47 +29,7 @@ #include "defs.h" #include "netlink.h" -#include "nlattr.h" -#include "print_fields.h" - -#include -#include - -#include -#include -#include -#ifdef AF_SMC -# include -#endif -#include -#include - -#include "xlat/inet_diag_attrs.h" -#include "xlat/inet_diag_bytecodes.h" -#include "xlat/inet_diag_extended_flags.h" -#include "xlat/inet_diag_req_attrs.h" - -#include "xlat/tcp_states.h" -#include "xlat/tcp_state_flags.h" - -#include "xlat/netlink_diag_attrs.h" -#include "xlat/netlink_diag_show.h" -#include "xlat/netlink_socket_flags.h" -#include "xlat/netlink_states.h" - -#include "xlat/packet_diag_attrs.h" -#include "xlat/packet_diag_info_flags.h" -#include "xlat/packet_diag_show.h" - -#ifdef AF_SMC -# include "xlat/smc_diag_attrs.h" -# include "xlat/smc_diag_extended_flags.h" -# include "xlat/smc_link_group_roles.h" -# include "xlat/smc_states.h" -#endif - -#include "xlat/unix_diag_attrs.h" -#include "xlat/unix_diag_show.h" +#include "netlink_sock_diag.h" static void decode_family(struct tcb *const tcp, const uint8_t family, @@ -85,1123 +45,7 @@ decode_family(struct tcb *const tcp, const uint8_t family, tprints("}"); } -static void -decode_unix_diag_req(struct tcb *const tcp, - const struct nlmsghdr *const nlmsghdr, - const uint8_t family, - const kernel_ulong_t addr, - const unsigned int len) -{ - struct unix_diag_req req = { .sdiag_family = family }; - const size_t offset = sizeof(req.sdiag_family); - - PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???"); - tprints(", "); - if (len >= sizeof(req)) { - if (!umoven_or_printaddr(tcp, addr + offset, - sizeof(req) - offset, - (void *) &req + offset)) { - PRINT_FIELD_U("", req, sdiag_protocol); - PRINT_FIELD_FLAGS(", ", req, udiag_states, - tcp_state_flags, "1<= SK_MEMINFO_VARS) { - tprints("..."); - return false; - } - - tprintf("%" PRIu32, *(uint32_t *) elem_buf); - - return true; -} - -static bool -decode_meminfo(struct tcb *const tcp, - const kernel_ulong_t addr, - const unsigned int len, - const void *const opaque_data) -{ - uint32_t mem; - const size_t nmemb = len / sizeof(mem); - - if (!nmemb) - return false; - - unsigned int count = 0; - print_array(tcp, addr, nmemb, &mem, sizeof(mem), - umoven_or_printaddr, print_meminfo, &count); - - return true; -} - -static bool -decode_unix_diag_vfs(struct tcb *const tcp, - const kernel_ulong_t addr, - const unsigned int len, - const void *const opaque_data) -{ - struct unix_diag_vfs uv; - - if (len < sizeof(uv)) - return false; - if (umove_or_printaddr(tcp, addr, &uv)) - return true; - - PRINT_FIELD_DEV("{", uv, udiag_vfs_dev); - PRINT_FIELD_U(", ", uv, udiag_vfs_ino); - tprints("}"); - - return true; -} - -static bool -print_inode(struct tcb *const tcp, - void *const elem_buf, - const size_t elem_size, - void *const opaque_data) -{ - tprintf("%" PRIu32, *(uint32_t *) elem_buf); - - return true; -} - -static bool -decode_unix_diag_inode(struct tcb *const tcp, - const kernel_ulong_t addr, - const unsigned int len, - const void *const opaque_data) -{ - uint32_t inode; - const size_t nmemb = len / sizeof(inode); - - if (!nmemb) - return false; - - print_array(tcp, addr, nmemb, &inode, sizeof(inode), - umoven_or_printaddr, print_inode, 0); - - return true; -} - -static bool -decode_unix_diag_rqlen(struct tcb *const tcp, - const kernel_ulong_t addr, - const unsigned int len, - const void *const opaque_data) -{ - struct unix_diag_rqlen rql; - - if (len < sizeof(rql)) - return false; - if (umove_or_printaddr(tcp, addr, &rql)) - return true; - - PRINT_FIELD_U("{", rql, udiag_rqueue); - PRINT_FIELD_U(", ", rql, udiag_wqueue); - tprints("}"); - - return true; -} - -static const nla_decoder_t unix_diag_msg_nla_decoders[] = { - [UNIX_DIAG_NAME] = decode_nla_str, - [UNIX_DIAG_VFS] = decode_unix_diag_vfs, - [UNIX_DIAG_PEER] = decode_nla_u32, - [UNIX_DIAG_ICONS] = decode_unix_diag_inode, - [UNIX_DIAG_RQLEN] = decode_unix_diag_rqlen, - [UNIX_DIAG_MEMINFO] = decode_meminfo, - [UNIX_DIAG_SHUTDOWN] = decode_nla_u8 -}; - -static void -decode_unix_diag_msg(struct tcb *const tcp, - const struct nlmsghdr *const nlmsghdr, - const uint8_t family, - const kernel_ulong_t addr, - const unsigned int len) -{ - struct unix_diag_msg msg = { .udiag_family = family }; - size_t offset = sizeof(msg.udiag_family); - bool decode_nla = false; - - PRINT_FIELD_XVAL("{", msg, udiag_family, addrfams, "AF_???"); - tprints(", "); - if (len >= sizeof(msg)) { - if (!umoven_or_printaddr(tcp, addr + offset, - sizeof(msg) - offset, - (void *) &msg + offset)) { - PRINT_FIELD_XVAL("", msg, udiag_type, - socktypes, "SOCK_???"); - PRINT_FIELD_XVAL(", ", msg, udiag_state, - tcp_states, "TCP_???"); - PRINT_FIELD_U(", ", msg, udiag_ino); - PRINT_FIELD_COOKIE(", ", msg, udiag_cookie); - decode_nla = true; - } - } else - tprints("..."); - tprints("}"); - - offset = NLMSG_ALIGN(sizeof(msg)); - if (decode_nla && len > offset) { - tprints(", "); - decode_nlattr(tcp, addr + offset, len - offset, - unix_diag_attrs, "UNIX_DIAG_???", - unix_diag_msg_nla_decoders, - ARRAY_SIZE(unix_diag_msg_nla_decoders), NULL); - } -} - -static void -decode_netlink_diag_req(struct tcb *const tcp, - const struct nlmsghdr *const nlmsghdr, - const uint8_t family, - const kernel_ulong_t addr, - const unsigned int len) -{ - struct netlink_diag_req req = { .sdiag_family = family }; - const size_t offset = sizeof(req.sdiag_family); - - PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???"); - tprints(", "); - if (len >= sizeof(req)) { - if (!umoven_or_printaddr(tcp, addr + offset, - sizeof(req) - offset, - (void *) &req + offset)) { - if (NDIAG_PROTO_ALL == req.sdiag_protocol) - tprintf("%s=%s", - "sdiag_protocol", "NDIAG_PROTO_ALL"); - else - PRINT_FIELD_XVAL("", req, sdiag_protocol, - netlink_protocols, - "NETLINK_???"); - PRINT_FIELD_U(", ", req, ndiag_ino); - PRINT_FIELD_FLAGS(", ", req, ndiag_show, - netlink_diag_show, "NDIAG_SHOW_???"); - PRINT_FIELD_COOKIE(", ", req, ndiag_cookie); - } - } else - tprints("..."); - tprints("}"); -} - -static bool -print_group(struct tcb *const tcp, - void *const elem_buf, - const size_t elem_size, - void *const opaque_data) -{ - if (elem_size < sizeof(kernel_ulong_t)) - tprintf("%#0*x", (int) elem_size * 2 + 2, - *(unsigned int *) elem_buf); - else - tprintf("%#0*" PRI_klx, (int) elem_size * 2 + 2, - *(kernel_ulong_t *) elem_buf); - - return true; -} - -static bool -decode_netlink_diag_groups(struct tcb *const tcp, - const kernel_ulong_t addr, - const unsigned int len, - const void *const opaque_data) -{ - kernel_ulong_t buf; - const size_t nmemb = len / current_wordsize; - - if (!nmemb) - return false; - - print_array(tcp, addr, nmemb, &buf, current_wordsize, - umoven_or_printaddr, print_group, 0); - - return true; -} - -static bool -decode_netlink_diag_ring(struct tcb *const tcp, - const kernel_ulong_t addr, - const unsigned int len, - const void *const opaque_data) -{ - struct netlink_diag_ring ndr; - - if (len < sizeof(ndr)) - return false; - if (umove_or_printaddr(tcp, addr, &ndr)) - return true; - - PRINT_FIELD_U("{", ndr, ndr_block_size); - PRINT_FIELD_U(", ", ndr, ndr_block_nr); - PRINT_FIELD_U(", ", ndr, ndr_frame_size); - PRINT_FIELD_U(", ", ndr, ndr_frame_nr); - tprints("}"); - - return true; -} - -static bool -decode_netlink_diag_flags(struct tcb *const tcp, - const kernel_ulong_t addr, - const unsigned int len, - const void *const opaque_data) -{ - uint32_t flags; - - if (len < sizeof(flags)) - return false; - if (umove_or_printaddr(tcp, addr, &flags)) - return true; - - printflags(netlink_socket_flags, flags, "NDIAG_FLAG_???"); - - return true; -} - -static const nla_decoder_t netlink_diag_msg_nla_decoders[] = { - [NETLINK_DIAG_MEMINFO] = decode_meminfo, - [NETLINK_DIAG_GROUPS] = decode_netlink_diag_groups, - [NETLINK_DIAG_RX_RING] = decode_netlink_diag_ring, - [NETLINK_DIAG_TX_RING] = decode_netlink_diag_ring, - [NETLINK_DIAG_FLAGS] = decode_netlink_diag_flags -}; - -static void -decode_netlink_diag_msg(struct tcb *const tcp, - const struct nlmsghdr *const nlmsghdr, - const uint8_t family, - const kernel_ulong_t addr, - const unsigned int len) -{ - struct netlink_diag_msg msg = { .ndiag_family = family }; - size_t offset = sizeof(msg.ndiag_family); - bool decode_nla = false; - - PRINT_FIELD_XVAL("{", msg, ndiag_family, addrfams, "AF_???"); - tprints(", "); - if (len >= sizeof(msg)) { - if (!umoven_or_printaddr(tcp, addr + offset, - sizeof(msg) - offset, - (void *) &msg + offset)) { - PRINT_FIELD_XVAL("", msg, ndiag_type, - socktypes, "SOCK_???"); - PRINT_FIELD_XVAL(", ", msg, ndiag_protocol, - netlink_protocols, "NETLINK_???"); - PRINT_FIELD_XVAL(", ", msg, ndiag_state, - netlink_states, "NETLINK_???"); - PRINT_FIELD_U(", ", msg, ndiag_portid); - PRINT_FIELD_U(", ", msg, ndiag_dst_portid); - PRINT_FIELD_U(", ", msg, ndiag_dst_group); - PRINT_FIELD_U(", ", msg, ndiag_ino); - PRINT_FIELD_COOKIE(", ", msg, ndiag_cookie); - decode_nla = true; - } - } else - tprints("..."); - tprints("}"); - - offset = NLA_ALIGN(sizeof(msg)); - if (decode_nla && len > offset) { - tprints(", "); - decode_nlattr(tcp, addr + offset, len - offset, - netlink_diag_attrs, "NETLINK_DIAG_???", - netlink_diag_msg_nla_decoders, - ARRAY_SIZE(netlink_diag_msg_nla_decoders), NULL); - } -} - -static void -decode_packet_diag_req(struct tcb *const tcp, - const struct nlmsghdr *const nlmsghdr, - const uint8_t family, - const kernel_ulong_t addr, - const unsigned int len) -{ - struct packet_diag_req req = { .sdiag_family = family }; - const size_t offset = sizeof(req.sdiag_family); - - PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???"); - tprints(", "); - if (len >= sizeof(req)) { - if (!umoven_or_printaddr(tcp, addr + offset, - sizeof(req) - offset, - (void *) &req + offset)) { - PRINT_FIELD_XVAL("", req, sdiag_protocol, - ethernet_protocols, "ETH_P_???"); - PRINT_FIELD_U(", ", req, pdiag_ino); - PRINT_FIELD_FLAGS(", ", req, pdiag_show, - packet_diag_show, "PACKET_SHOW_???"); - PRINT_FIELD_COOKIE(", ", req, pdiag_cookie); - } - } else - tprints("..."); - tprints("}"); -} - -static bool -decode_packet_diag_info(struct tcb *const tcp, - const kernel_ulong_t addr, - const unsigned int len, - const void *const opaque_data) -{ - struct packet_diag_info pinfo; - - if (len < sizeof(pinfo)) - return false; - if (umove_or_printaddr(tcp, addr, &pinfo)) - return true; - - PRINT_FIELD_U("{", pinfo, pdi_index); - PRINT_FIELD_U(", ", pinfo, pdi_version); - PRINT_FIELD_U(", ", pinfo, pdi_reserve); - PRINT_FIELD_U(", ", pinfo, pdi_copy_thresh); - PRINT_FIELD_U(", ", pinfo, pdi_tstamp); - PRINT_FIELD_FLAGS(", ", pinfo, pdi_flags, - packet_diag_info_flags, "PDI_???"); - tprints("}"); - - return true; -} - -static bool -print_packet_diag_mclist(struct tcb *const tcp, void *const elem_buf, - const size_t elem_size, void *const opaque_data) -{ - struct packet_diag_mclist *dml = elem_buf; - uint16_t alen = dml->pdmc_alen > sizeof(dml->pdmc_addr) ? - sizeof(dml->pdmc_addr) : dml->pdmc_alen; - - PRINT_FIELD_IFINDEX("{", *dml, pdmc_index); - PRINT_FIELD_U(", ", *dml, pdmc_count); - PRINT_FIELD_U(", ", *dml, pdmc_type); - PRINT_FIELD_U(", ", *dml, pdmc_alen); - PRINT_FIELD_STRING(", ", *dml, pdmc_addr, alen, QUOTE_FORCE_HEX); - tprints("}"); - - return true; -} - -static bool -decode_packet_diag_mclist(struct tcb *const tcp, - const kernel_ulong_t addr, - const unsigned int len, - const void *const opaque_data) -{ - struct packet_diag_mclist dml; - const size_t nmemb = len / sizeof(dml); - - if (!nmemb) - return false; - - print_array(tcp, addr, nmemb, &dml, sizeof(dml), - umoven_or_printaddr, print_packet_diag_mclist, 0); - - return true; -} - -static bool -decode_packet_diag_ring(struct tcb *const tcp, - const kernel_ulong_t addr, - const unsigned int len, - const void *const opaque_data) -{ - struct packet_diag_ring pdr; - - if (len < sizeof(pdr)) - return false; - if (umove_or_printaddr(tcp, addr, &pdr)) - return true; - - PRINT_FIELD_U("{", pdr, pdr_block_size); - PRINT_FIELD_U(", ", pdr, pdr_block_nr); - PRINT_FIELD_U(", ", pdr, pdr_frame_size); - PRINT_FIELD_U(", ", pdr, pdr_frame_nr); - PRINT_FIELD_U(", ", pdr, pdr_retire_tmo); - PRINT_FIELD_U(", ", pdr, pdr_sizeof_priv); - PRINT_FIELD_U(", ", pdr, pdr_features); - tprints("}"); - - return true; -} - -static bool -decode_packet_diag_filter(struct tcb *const tcp, - const kernel_ulong_t addr, - const unsigned int len, - const void *const opaque_data) -{ - const unsigned int nmemb = len / sizeof(struct sock_filter); - if (!nmemb || (unsigned short) nmemb != nmemb) - return false; - - print_sock_fprog(tcp, addr, nmemb); - - return true; -} - -static const nla_decoder_t packet_diag_msg_nla_decoders[] = { - [PACKET_DIAG_INFO] = decode_packet_diag_info, - [PACKET_DIAG_MCLIST] = decode_packet_diag_mclist, - [PACKET_DIAG_RX_RING] = decode_packet_diag_ring, - [PACKET_DIAG_TX_RING] = decode_packet_diag_ring, - [PACKET_DIAG_FANOUT] = decode_nla_u32, - [PACKET_DIAG_UID] = decode_nla_u32, - [PACKET_DIAG_MEMINFO] = decode_meminfo, - [PACKET_DIAG_FILTER] = decode_packet_diag_filter -}; - -static void -decode_packet_diag_msg(struct tcb *const tcp, - const struct nlmsghdr *const nlmsghdr, - const uint8_t family, - const kernel_ulong_t addr, - const unsigned int len) -{ - struct packet_diag_msg msg = { .pdiag_family = family }; - size_t offset = sizeof(msg.pdiag_family); - bool decode_nla = false; - - PRINT_FIELD_XVAL("{", msg, pdiag_family, addrfams, "AF_???"); - tprints(", "); - if (len >= sizeof(msg)) { - if (!umoven_or_printaddr(tcp, addr + offset, - sizeof(msg) - offset, - (void *) &msg + offset)) { - PRINT_FIELD_XVAL("", msg, pdiag_type, - socktypes, "SOCK_???"); - PRINT_FIELD_U(", ", msg, pdiag_num); - PRINT_FIELD_U(", ", msg, pdiag_ino); - PRINT_FIELD_COOKIE(", ", msg, pdiag_cookie); - decode_nla = true; - } - } else - tprints("..."); - tprints("}"); - - offset = NLA_ALIGN(sizeof(msg)); - if (decode_nla && len > offset) { - tprints(", "); - decode_nlattr(tcp, addr + offset, len - offset, - packet_diag_attrs, "PACKET_DIAG_???", - packet_diag_msg_nla_decoders, - ARRAY_SIZE(packet_diag_msg_nla_decoders), NULL); - } -} - -static void -print_inet_diag_sockid(const struct inet_diag_sockid *id, const uint8_t family) -{ - PRINT_FIELD_NET_PORT("{", *id, idiag_sport); - PRINT_FIELD_NET_PORT(", ", *id, idiag_dport); - PRINT_FIELD_INET_ADDR(", ", *id, idiag_src, family); - PRINT_FIELD_INET_ADDR(", ", *id, idiag_dst, family); - PRINT_FIELD_IFINDEX(", ", *id, idiag_if); - PRINT_FIELD_COOKIE(", ", *id, idiag_cookie); - tprints("}"); -} - -#define PRINT_FIELD_INET_DIAG_SOCKID(prefix_, where_, field_, af_) \ - do { \ - STRACE_PRINTF("%s%s=", (prefix_), #field_); \ - print_inet_diag_sockid(&(where_).field_, (af_)); \ - } while (0) - -static void -decode_inet_addr(struct tcb *const tcp, - const kernel_ulong_t addr, - const unsigned int len, - const int family) -{ - union { - struct in_addr a4; - struct in6_addr a6; - } addrbuf; - size_t size = 0; - - switch (family) { - case AF_INET: - size = sizeof(addrbuf.a4); - break; - case AF_INET6: - size = sizeof(addrbuf.a6); - break; - } - - if (!size || len < size) { - tprints("addr="); - printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX); - return; - } - - if (umoven(tcp, addr, size, &addrbuf) < 0) { - tprints("addr="); - printaddr(addr); - return; - } - - print_inet_addr(family, &addrbuf, size, "addr"); -} - -static void -decode_inet_diag_hostcond(struct tcb *const tcp, - const kernel_ulong_t addr, - const unsigned int len) -{ - struct inet_diag_hostcond cond; - - if (len < sizeof(cond)) { - printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX); - return; - } - if (umove_or_printaddr(tcp, addr, &cond)) - return; - - PRINT_FIELD_XVAL("{", cond, family, addrfams, "AF_???"); - PRINT_FIELD_U(", ", cond, prefix_len); - PRINT_FIELD_U(", ", cond, port); - - if (len > sizeof(cond)) { - tprints(", "); - decode_inet_addr(tcp, addr + sizeof(cond), - len - sizeof(cond), cond.family); - } - tprints("}"); -} - -static void -print_inet_diag_bc_op(const struct inet_diag_bc_op *const op) -{ - PRINT_FIELD_XVAL("{", *op, code, inet_diag_bytecodes, - "INET_DIAG_BC_???"); - PRINT_FIELD_U(", ", *op, yes); - PRINT_FIELD_U(", ", *op, no); - tprints("}"); -} - -static void -decode_inet_diag_markcond(struct tcb *const tcp, - const kernel_ulong_t addr, - const unsigned int len) -{ - struct inet_diag_markcond markcond; - - if (len < sizeof(markcond)) - printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX); - else if (!umove_or_printaddr(tcp, addr, &markcond)) { - PRINT_FIELD_U("{", markcond, mark); - PRINT_FIELD_U(", ", markcond, mask); - tprints("}"); - } -} - -static void -decode_bytecode_data(struct tcb *const tcp, - const kernel_ulong_t addr, - const unsigned int len, - const unsigned char code) -{ - switch (code) { - case INET_DIAG_BC_S_COND: - case INET_DIAG_BC_D_COND: - decode_inet_diag_hostcond(tcp, addr, len); - break; - case INET_DIAG_BC_DEV_COND: { - uint32_t ifindex; - - if (len < sizeof(ifindex)) - printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX); - else if (!umove_or_printaddr(tcp, addr, &ifindex)) - print_ifindex(ifindex); - break; - } - case INET_DIAG_BC_S_GE: - case INET_DIAG_BC_S_LE: - case INET_DIAG_BC_D_GE: - case INET_DIAG_BC_D_LE: { - struct inet_diag_bc_op op; - - if (len < sizeof(op)) - printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX); - else if (!umove_or_printaddr(tcp, addr, &op)) - print_inet_diag_bc_op(&op); - break; - } - case INET_DIAG_BC_MARK_COND: - decode_inet_diag_markcond(tcp, addr, len); - break; - case INET_DIAG_BC_AUTO: - case INET_DIAG_BC_JMP: - case INET_DIAG_BC_NOP: - default: - printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX); - break; - } -} - -static bool -decode_inet_diag_bc_op(struct tcb *const tcp, - const kernel_ulong_t addr, - const unsigned int len, - const void *const opaque_data) -{ - struct inet_diag_bc_op op; - - if (len < sizeof(op)) - return false; - if (umove_or_printaddr(tcp, addr, &op)) - return true; - - if (len > sizeof(op)) - tprints("{"); - - print_inet_diag_bc_op(&op); - - if (len > sizeof(op)) { - tprints(", "); - decode_bytecode_data(tcp, addr + sizeof(op), - len - sizeof(op), op.code); - tprints("}"); - } - - return true; -} - -static const nla_decoder_t inet_diag_req_nla_decoders[] = { - [INET_DIAG_REQ_BYTECODE] = decode_inet_diag_bc_op -}; - -static void -decode_inet_diag_req_compat(struct tcb *const tcp, - const struct nlmsghdr *const nlmsghdr, - const uint8_t family, - const kernel_ulong_t addr, - const unsigned int len) -{ - struct inet_diag_req req = { .idiag_family = family }; - size_t offset = sizeof(req.idiag_family); - bool decode_nla = false; - - PRINT_FIELD_XVAL("{", req, idiag_family, addrfams, "AF_???"); - tprints(", "); - if (len >= sizeof(req)) { - if (!umoven_or_printaddr(tcp, addr + offset, - sizeof(req) - offset, - (void *) &req + offset)) { - PRINT_FIELD_U("", req, idiag_src_len); - PRINT_FIELD_U(", ", req, idiag_dst_len); - PRINT_FIELD_FLAGS(", ", req, idiag_ext, - inet_diag_extended_flags, - "1< offset) { - tprints(", "); - decode_nlattr(tcp, addr + offset, len - offset, - inet_diag_req_attrs, "INET_DIAG_REQ_???", - inet_diag_req_nla_decoders, - ARRAY_SIZE(inet_diag_req_nla_decoders), NULL); - } -} - -static void -decode_inet_diag_req_v2(struct tcb *const tcp, - const struct nlmsghdr *const nlmsghdr, - const uint8_t family, - const kernel_ulong_t addr, - const unsigned int len) -{ - struct inet_diag_req_v2 req = { .sdiag_family = family }; - size_t offset = sizeof(req.sdiag_family); - bool decode_nla = false; - - PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???"); - tprints(", "); - if (len >= sizeof(req)) { - if (!umoven_or_printaddr(tcp, addr + offset, - sizeof(req) - offset, - (void *) &req + offset)) { - PRINT_FIELD_XVAL("", req, sdiag_protocol, - inet_protocols, "IPPROTO_???"); - PRINT_FIELD_FLAGS(", ", req, idiag_ext, - inet_diag_extended_flags, - "1< offset) { - tprints(", "); - decode_nlattr(tcp, addr + offset, len - offset, - inet_diag_req_attrs, "INET_DIAG_REQ_???", - inet_diag_req_nla_decoders, - ARRAY_SIZE(inet_diag_req_nla_decoders), NULL); - } -} - -static void -decode_inet_diag_req(struct tcb *const tcp, - const struct nlmsghdr *const nlmsghdr, - const uint8_t family, - const kernel_ulong_t addr, - const unsigned int len) -{ - if (nlmsghdr->nlmsg_type == TCPDIAG_GETSOCK - || nlmsghdr->nlmsg_type == DCCPDIAG_GETSOCK) - return decode_inet_diag_req_compat(tcp, nlmsghdr, - family, addr, len); - else - return decode_inet_diag_req_v2(tcp, nlmsghdr, - family, addr, len); -} - -static bool -decode_inet_diag_meminfo(struct tcb *const tcp, - const kernel_ulong_t addr, - const unsigned int len, - const void *const opaque_data) -{ - struct inet_diag_meminfo minfo; - - if (len < sizeof(minfo)) - return false; - if (umove_or_printaddr(tcp, addr, &minfo)) - return true; - - PRINT_FIELD_U("{", minfo, idiag_rmem); - PRINT_FIELD_U(", ", minfo, idiag_wmem); - PRINT_FIELD_U(", ", minfo, idiag_fmem); - PRINT_FIELD_U(", ", minfo, idiag_tmem); - tprints("}"); - - return true; -} - -static bool -decode_tcpvegas_info(struct tcb *const tcp, - const kernel_ulong_t addr, - const unsigned int len, - const void *const opaque_data) -{ - struct tcpvegas_info vegas; - - if (len < sizeof(vegas)) - return false; - if (umove_or_printaddr(tcp, addr, &vegas)) - return true; - - PRINT_FIELD_U("{", vegas, tcpv_enabled); - PRINT_FIELD_U(", ", vegas, tcpv_rttcnt); - PRINT_FIELD_U(", ", vegas, tcpv_rtt); - PRINT_FIELD_U(", ", vegas, tcpv_minrtt); - tprints("}"); - - return true; -} - -static bool -decode_tcp_dctcp_info(struct tcb *const tcp, - const kernel_ulong_t addr, - const unsigned int len, - const void *const opaque_data) -{ - struct tcp_dctcp_info dctcp; - - if (len < sizeof(dctcp)) - return false; - if (umove_or_printaddr(tcp, addr, &dctcp)) - return true; - - PRINT_FIELD_U("{", dctcp, dctcp_enabled); - PRINT_FIELD_U(", ", dctcp, dctcp_ce_state); - PRINT_FIELD_U(", ", dctcp, dctcp_alpha); - PRINT_FIELD_U(", ", dctcp, dctcp_ab_ecn); - PRINT_FIELD_U(", ", dctcp, dctcp_ab_tot); - tprints("}"); - - return true; -} - -static bool -decode_tcp_bbr_info(struct tcb *const tcp, - const kernel_ulong_t addr, - const unsigned int len, - const void *const opaque_data) -{ - struct tcp_bbr_info bbr; - - if (len < sizeof(bbr)) - return false; - if (umove_or_printaddr(tcp, addr, &bbr)) - return true; - - PRINT_FIELD_X("{", bbr, bbr_bw_lo); - PRINT_FIELD_X(", ", bbr, bbr_bw_hi); - PRINT_FIELD_U(", ", bbr, bbr_min_rtt); - PRINT_FIELD_U(", ", bbr, bbr_pacing_gain); - PRINT_FIELD_U(", ", bbr, bbr_cwnd_gain); - tprints("}"); - - return true; -} - -static const nla_decoder_t inet_diag_msg_nla_decoders[] = { - [INET_DIAG_MEMINFO] = decode_inet_diag_meminfo, - [INET_DIAG_INFO] = NULL, /* unimplemented */ - [INET_DIAG_VEGASINFO] = decode_tcpvegas_info, - [INET_DIAG_CONG] = decode_nla_str, - [INET_DIAG_TOS] = decode_nla_u8, - [INET_DIAG_TCLASS] = decode_nla_u8, - [INET_DIAG_SKMEMINFO] = decode_meminfo, - [INET_DIAG_SHUTDOWN] = decode_nla_u8, - [INET_DIAG_DCTCPINFO] = decode_tcp_dctcp_info, - [INET_DIAG_PROTOCOL] = decode_nla_u8, - [INET_DIAG_SKV6ONLY] = decode_nla_u8, - [INET_DIAG_LOCALS] = NULL, /* unimplemented */ - [INET_DIAG_PEERS] = NULL, /* unimplemented */ - [INET_DIAG_PAD] = NULL, - [INET_DIAG_MARK] = decode_nla_u32, - [INET_DIAG_BBRINFO] = decode_tcp_bbr_info -}; - -static void -decode_inet_diag_msg(struct tcb *const tcp, - const struct nlmsghdr *const nlmsghdr, - const uint8_t family, - const kernel_ulong_t addr, - const unsigned int len) -{ - struct inet_diag_msg msg = { .idiag_family = family }; - size_t offset = sizeof(msg.idiag_family); - bool decode_nla = false; - - PRINT_FIELD_XVAL("{", msg, idiag_family, addrfams, "AF_???"); - tprints(", "); - if (len >= sizeof(msg)) { - if (!umoven_or_printaddr(tcp, addr + offset, - sizeof(msg) - offset, - (void *) &msg + offset)) { - PRINT_FIELD_XVAL("", msg, idiag_state, - tcp_states, "TCP_???"); - PRINT_FIELD_U(", ", msg, idiag_timer); - PRINT_FIELD_U(", ", msg, idiag_retrans); - PRINT_FIELD_INET_DIAG_SOCKID(", ", msg, id, - msg.idiag_family); - PRINT_FIELD_U(", ", msg, idiag_expires); - PRINT_FIELD_U(", ", msg, idiag_rqueue); - PRINT_FIELD_U(", ", msg, idiag_wqueue); - PRINT_FIELD_U(", ", msg, idiag_uid); - PRINT_FIELD_U(", ", msg, idiag_inode); - decode_nla = true; - } - } else - tprints("..."); - tprints("}"); - - offset = NLA_ALIGN(sizeof(msg)); - if (decode_nla && len > offset) { - tprints(", "); - decode_nlattr(tcp, addr + offset, len - offset, - inet_diag_attrs, "INET_DIAG_???", - inet_diag_msg_nla_decoders, - ARRAY_SIZE(inet_diag_msg_nla_decoders), NULL); - } -} - -#ifdef AF_SMC -static void -decode_smc_diag_req(struct tcb *const tcp, - const struct nlmsghdr *const nlmsghdr, - const uint8_t family, - const kernel_ulong_t addr, - const unsigned int len) -{ - struct smc_diag_req req = { .diag_family = family }; - const size_t offset = sizeof(req.diag_family); - - PRINT_FIELD_XVAL("{", req, diag_family, addrfams, "AF_???"); - tprints(", "); - if (len >= sizeof(req)) { - if (!umoven_or_printaddr(tcp, addr + offset, - sizeof(req) - offset, - (void *) &req + offset)) { - PRINT_FIELD_FLAGS("", req, diag_ext, - smc_diag_extended_flags, - "1<= sizeof(msg)) { - if (!umoven_or_printaddr(tcp, addr + offset, - sizeof(msg) - offset, - (void *) &msg + offset)) { - PRINT_FIELD_XVAL("", msg, diag_state, - smc_states, "SMC_???"); - PRINT_FIELD_U(", ", msg, diag_fallback); - PRINT_FIELD_U(", ", msg, diag_shutdown); - /* - * AF_SMC protocol family socket handler - * keeping the AF_INET sock address. - */ - PRINT_FIELD_INET_DIAG_SOCKID(", ", msg, id, AF_INET); - PRINT_FIELD_U(", ", msg, diag_uid); - PRINT_FIELD_U(", ", msg, diag_inode); - decode_nla = true; - } - } else - tprints("..."); - tprints("}"); - - offset = NLA_ALIGN(sizeof(msg)); - if (decode_nla && len > offset) { - tprints(", "); - decode_nlattr(tcp, addr + offset, len - offset, - smc_diag_attrs, "SMC_DIAG_???", - smc_diag_msg_nla_decoders, - ARRAY_SIZE(smc_diag_msg_nla_decoders), NULL); - } -} -#endif - -typedef void (*netlink_diag_decoder_t)(struct tcb *, - const struct nlmsghdr *, - uint8_t family, - kernel_ulong_t addr, - unsigned int len); +typedef DECL_NETLINK_DIAG_DECODER((*netlink_diag_decoder_t)); static const struct { const netlink_diag_decoder_t request, response; diff --git a/netlink_sock_diag.h b/netlink_sock_diag.h new file mode 100644 index 00000000..af99bc83 --- /dev/null +++ b/netlink_sock_diag.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2017 JingPiao Chen + * Copyright (c) 2016-2017 The strace developers. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef STRACE_NETLINK_SOCK_DIAG_H +#define STRACE_NETLINK_SOCK_DIAG_H + +#define DECL_NETLINK_DIAG_DECODER(diag_decode_name) \ +void \ +diag_decode_name(struct tcb *tcp, \ + const struct nlmsghdr *nlmsghdr, \ + uint8_t family, \ + kernel_ulong_t addr, \ + unsigned int len) + +extern DECL_NETLINK_DIAG_DECODER(decode_inet_diag_msg); +extern DECL_NETLINK_DIAG_DECODER(decode_inet_diag_req); +extern DECL_NETLINK_DIAG_DECODER(decode_netlink_diag_msg); +extern DECL_NETLINK_DIAG_DECODER(decode_netlink_diag_req); +extern DECL_NETLINK_DIAG_DECODER(decode_packet_diag_msg); +extern DECL_NETLINK_DIAG_DECODER(decode_packet_diag_req); +extern DECL_NETLINK_DIAG_DECODER(decode_smc_diag_msg); +extern DECL_NETLINK_DIAG_DECODER(decode_smc_diag_req); +extern DECL_NETLINK_DIAG_DECODER(decode_unix_diag_msg); +extern DECL_NETLINK_DIAG_DECODER(decode_unix_diag_req); + +struct inet_diag_sockid; + +extern void +print_inet_diag_sockid(const struct inet_diag_sockid *, const uint8_t family); + +#define PRINT_FIELD_INET_DIAG_SOCKID(prefix_, where_, field_, af_) \ + do { \ + STRACE_PRINTF("%s%s=", (prefix_), #field_); \ + print_inet_diag_sockid(&(where_).field_, (af_)); \ + } while (0) + + +#endif /* !STRACE_NETLINK_SOCK_DIAG_H */ diff --git a/netlink_unix_diag.c b/netlink_unix_diag.c new file mode 100644 index 00000000..254a659f --- /dev/null +++ b/netlink_unix_diag.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2016 Fabien Siron + * Copyright (c) 2017 JingPiao Chen + * Copyright (c) 2017 The strace developers. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "defs.h" +#include "netlink.h" +#include "netlink_sock_diag.h" +#include "nlattr.h" +#include "print_fields.h" + +#include +#include + +#include "xlat/unix_diag_attrs.h" +#include "xlat/unix_diag_show.h" + +DECL_NETLINK_DIAG_DECODER(decode_unix_diag_req) +{ + struct unix_diag_req req = { .sdiag_family = family }; + const size_t offset = sizeof(req.sdiag_family); + + PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???"); + tprints(", "); + if (len >= sizeof(req)) { + if (!umoven_or_printaddr(tcp, addr + offset, + sizeof(req) - offset, + (void *) &req + offset)) { + PRINT_FIELD_U("", req, sdiag_protocol); + PRINT_FIELD_FLAGS(", ", req, udiag_states, + tcp_state_flags, "1<= sizeof(msg)) { + if (!umoven_or_printaddr(tcp, addr + offset, + sizeof(msg) - offset, + (void *) &msg + offset)) { + PRINT_FIELD_XVAL("", msg, udiag_type, + socktypes, "SOCK_???"); + PRINT_FIELD_XVAL(", ", msg, udiag_state, + tcp_states, "TCP_???"); + PRINT_FIELD_U(", ", msg, udiag_ino); + PRINT_FIELD_COOKIE(", ", msg, udiag_cookie); + decode_nla = true; + } + } else + tprints("..."); + tprints("}"); + + offset = NLMSG_ALIGN(sizeof(msg)); + if (decode_nla && len > offset) { + tprints(", "); + decode_nlattr(tcp, addr + offset, len - offset, + unix_diag_attrs, "UNIX_DIAG_???", + unix_diag_msg_nla_decoders, + ARRAY_SIZE(unix_diag_msg_nla_decoders), NULL); + } +} diff --git a/nlattr.c b/nlattr.c index 6293f93a..a17b3473 100644 --- a/nlattr.c +++ b/nlattr.c @@ -30,6 +30,7 @@ #include "defs.h" #include "netlink.h" #include "nlattr.h" +#include static bool fetch_nlattr(struct tcb *const tcp, struct nlattr *const nlattr, @@ -166,6 +167,43 @@ decode_nla_strn(struct tcb *const tcp, return true; } +static bool +print_meminfo(struct tcb *const tcp, + void *const elem_buf, + const size_t elem_size, + void *const opaque_data) +{ + unsigned int *const count = opaque_data; + + if ((*count)++ >= SK_MEMINFO_VARS) { + tprints("..."); + return false; + } + + tprintf("%" PRIu32, *(uint32_t *) elem_buf); + + return true; +} + +bool +decode_nla_meminfo(struct tcb *const tcp, + const kernel_ulong_t addr, + const unsigned int len, + const void *const opaque_data) +{ + uint32_t mem; + const size_t nmemb = len / sizeof(mem); + + if (!nmemb) + return false; + + unsigned int count = 0; + print_array(tcp, addr, nmemb, &mem, sizeof(mem), + umoven_or_printaddr, print_meminfo, &count); + + return true; +} + #define DECODE_NLA_INTEGER(name, type, fmt) \ bool \ decode_nla_ ## name(struct tcb *const tcp, \ diff --git a/nlattr.h b/nlattr.h index 1a8ca88f..8e580868 100644 --- a/nlattr.h +++ b/nlattr.h @@ -56,5 +56,6 @@ DECL_NLA(s32); DECL_NLA(s64); DECL_NLA(str); DECL_NLA(strn); +DECL_NLA(meminfo); #endif /* !STRACE_NLATTR_H */