Home | History | Annotate | Download | only in strace
      1 /*
      2  * Copyright (c) 2016 Fabien Siron <fabien.siron (at) epita.fr>
      3  * Copyright (c) 2017 JingPiao Chen <chenjingpiao (at) gmail.com>
      4  * Copyright (c) 2017-2018 The strace developers.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. The name of the author may not be used to endorse or promote products
     16  *    derived from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #include "defs.h"
     31 #include "netlink.h"
     32 #include "netlink_sock_diag.h"
     33 #include "nlattr.h"
     34 #include "print_fields.h"
     35 
     36 #include <arpa/inet.h>
     37 
     38 #include <linux/sock_diag.h>
     39 #include <linux/inet_diag.h>
     40 
     41 #include "xlat/inet_diag_attrs.h"
     42 #include "xlat/inet_diag_bytecodes.h"
     43 #include "xlat/inet_diag_extended_flags.h"
     44 #include "xlat/inet_diag_req_attrs.h"
     45 
     46 #include "xlat/tcp_states.h"
     47 #include "xlat/tcp_state_flags.h"
     48 
     49 void
     50 print_inet_diag_sockid(const struct inet_diag_sockid *id, const uint8_t family)
     51 {
     52 	PRINT_FIELD_NET_PORT("{", *id, idiag_sport);
     53 	PRINT_FIELD_NET_PORT(", ", *id, idiag_dport);
     54 	PRINT_FIELD_INET_ADDR(", ", *id, idiag_src, family);
     55 	PRINT_FIELD_INET_ADDR(", ", *id, idiag_dst, family);
     56 	PRINT_FIELD_IFINDEX(", ", *id, idiag_if);
     57 	PRINT_FIELD_COOKIE(", ", *id, idiag_cookie);
     58 	tprints("}");
     59 }
     60 
     61 static void
     62 decode_inet_diag_hostcond(struct tcb *const tcp,
     63 			  const kernel_ulong_t addr,
     64 			  const unsigned int len)
     65 {
     66 	struct inet_diag_hostcond cond;
     67 
     68 	if (len < sizeof(cond)) {
     69 		printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
     70 		return;
     71 	}
     72 	if (umove_or_printaddr(tcp, addr, &cond))
     73 		return;
     74 
     75 	PRINT_FIELD_XVAL("{", cond, family, addrfams, "AF_???");
     76 	PRINT_FIELD_U(", ", cond, prefix_len);
     77 	PRINT_FIELD_U(", ", cond, port);
     78 
     79 	if (len > sizeof(cond)) {
     80 		tprints(", ");
     81 		decode_inet_addr(tcp, addr + sizeof(cond),
     82 				 len - sizeof(cond), cond.family, "addr");
     83 	}
     84 	tprints("}");
     85 }
     86 
     87 static void
     88 print_inet_diag_bc_op(const struct inet_diag_bc_op *const op)
     89 {
     90 	PRINT_FIELD_XVAL("{", *op, code, inet_diag_bytecodes,
     91 			 "INET_DIAG_BC_???");
     92 	PRINT_FIELD_U(", ", *op, yes);
     93 	PRINT_FIELD_U(", ", *op, no);
     94 	tprints("}");
     95 }
     96 
     97 static void
     98 decode_inet_diag_markcond(struct tcb *const tcp,
     99 			  const kernel_ulong_t addr,
    100 			  const unsigned int len)
    101 {
    102 	struct inet_diag_markcond markcond;
    103 
    104 	if (len < sizeof(markcond))
    105 		printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
    106 	else if (!umove_or_printaddr(tcp, addr, &markcond)) {
    107 		PRINT_FIELD_U("{", markcond, mark);
    108 		PRINT_FIELD_U(", ", markcond, mask);
    109 		tprints("}");
    110 	}
    111 }
    112 
    113 static void
    114 decode_bytecode_data(struct tcb *const tcp,
    115 		     const kernel_ulong_t addr,
    116 		     const unsigned int len,
    117 		     const unsigned char code)
    118 {
    119 	switch (code) {
    120 	case INET_DIAG_BC_S_COND:
    121 	case INET_DIAG_BC_D_COND:
    122 		decode_inet_diag_hostcond(tcp, addr, len);
    123 		break;
    124 	case INET_DIAG_BC_DEV_COND: {
    125 		uint32_t ifindex;
    126 
    127 		if (len < sizeof(ifindex))
    128 			printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
    129 		else if (!umove_or_printaddr(tcp, addr, &ifindex))
    130 			print_ifindex(ifindex);
    131 		break;
    132 	}
    133 	case INET_DIAG_BC_S_GE:
    134 	case INET_DIAG_BC_S_LE:
    135 	case INET_DIAG_BC_D_GE:
    136 	case INET_DIAG_BC_D_LE: {
    137 		struct inet_diag_bc_op op;
    138 
    139 		if (len < sizeof(op))
    140 			printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
    141 		else if (!umove_or_printaddr(tcp, addr, &op))
    142 			print_inet_diag_bc_op(&op);
    143 		break;
    144 	}
    145 	case INET_DIAG_BC_MARK_COND:
    146 		decode_inet_diag_markcond(tcp, addr, len);
    147 		break;
    148 	case INET_DIAG_BC_AUTO:
    149 	case INET_DIAG_BC_JMP:
    150 	case INET_DIAG_BC_NOP:
    151 	default:
    152 		printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
    153 		break;
    154 	}
    155 }
    156 
    157 static bool
    158 decode_inet_diag_bc_op(struct tcb *const tcp,
    159 		       const kernel_ulong_t addr,
    160 		       const unsigned int len,
    161 		       const void *const opaque_data)
    162 {
    163 	struct inet_diag_bc_op op;
    164 
    165 	if (len < sizeof(op))
    166 		return false;
    167 	if (umove_or_printaddr(tcp, addr, &op))
    168 		return true;
    169 
    170 	if (len > sizeof(op))
    171 		tprints("{");
    172 
    173 	print_inet_diag_bc_op(&op);
    174 
    175 	if (len > sizeof(op)) {
    176 		tprints(", ");
    177 		decode_bytecode_data(tcp, addr + sizeof(op),
    178 				     len - sizeof(op), op.code);
    179 		tprints("}");
    180 	}
    181 
    182 	return true;
    183 }
    184 
    185 static const nla_decoder_t inet_diag_req_nla_decoders[] = {
    186 	[INET_DIAG_REQ_BYTECODE] = decode_inet_diag_bc_op
    187 };
    188 
    189 static void
    190 decode_inet_diag_req_compat(struct tcb *const tcp,
    191 			    const struct nlmsghdr *const nlmsghdr,
    192 			    const uint8_t family,
    193 			    const kernel_ulong_t addr,
    194 			    const unsigned int len)
    195 {
    196 	struct inet_diag_req req = { .idiag_family = family };
    197 	size_t offset = sizeof(req.idiag_family);
    198 	bool decode_nla = false;
    199 
    200 	PRINT_FIELD_XVAL("{", req, idiag_family, addrfams, "AF_???");
    201 	tprints(", ");
    202 	if (len >= sizeof(req)) {
    203 		if (!umoven_or_printaddr(tcp, addr + offset,
    204 					 sizeof(req) - offset,
    205 					 (char *) &req + offset)) {
    206 			PRINT_FIELD_U("", req, idiag_src_len);
    207 			PRINT_FIELD_U(", ", req, idiag_dst_len);
    208 			PRINT_FIELD_FLAGS(", ", req, idiag_ext,
    209 					  inet_diag_extended_flags,
    210 					  "1<<INET_DIAG_\?\?\?-1");
    211 			PRINT_FIELD_INET_DIAG_SOCKID(", ", req, id,
    212 						     req.idiag_family);
    213 			PRINT_FIELD_FLAGS(", ", req, idiag_states,
    214 					  tcp_state_flags, "1<<TCP_???");
    215 			PRINT_FIELD_U(", ", req, idiag_dbs);
    216 			decode_nla = true;
    217 		}
    218 	} else
    219 		tprints("...");
    220 	tprints("}");
    221 
    222 	offset = NLMSG_ALIGN(sizeof(req));
    223 	if (decode_nla && len > offset) {
    224 		tprints(", ");
    225 		decode_nlattr(tcp, addr + offset, len - offset,
    226 			      inet_diag_req_attrs, "INET_DIAG_REQ_???",
    227 			      inet_diag_req_nla_decoders,
    228 			      ARRAY_SIZE(inet_diag_req_nla_decoders), NULL);
    229 	}
    230 }
    231 
    232 static void
    233 decode_inet_diag_req_v2(struct tcb *const tcp,
    234 			const struct nlmsghdr *const nlmsghdr,
    235 			const uint8_t family,
    236 			const kernel_ulong_t addr,
    237 			const unsigned int len)
    238 {
    239 	struct inet_diag_req_v2 req = { .sdiag_family = family };
    240 	size_t offset = sizeof(req.sdiag_family);
    241 	bool decode_nla = false;
    242 
    243 	PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???");
    244 	tprints(", ");
    245 	if (len >= sizeof(req)) {
    246 		if (!umoven_or_printaddr(tcp, addr + offset,
    247 					 sizeof(req) - offset,
    248 					 (char *) &req + offset)) {
    249 			PRINT_FIELD_XVAL("", req, sdiag_protocol,
    250 					 inet_protocols, "IPPROTO_???");
    251 			PRINT_FIELD_FLAGS(", ", req, idiag_ext,
    252 					  inet_diag_extended_flags,
    253 					  "1<<INET_DIAG_\?\?\?-1");
    254 			PRINT_FIELD_FLAGS(", ", req, idiag_states,
    255 					  tcp_state_flags, "1<<TCP_???");
    256 			PRINT_FIELD_INET_DIAG_SOCKID(", ", req, id,
    257 						     req.sdiag_family);
    258 			decode_nla = true;
    259 		}
    260 	} else
    261 		tprints("...");
    262 	tprints("}");
    263 
    264 	offset = NLMSG_ALIGN(sizeof(req));
    265 	if (decode_nla && len > offset) {
    266 		tprints(", ");
    267 		decode_nlattr(tcp, addr + offset, len - offset,
    268 			      inet_diag_req_attrs, "INET_DIAG_REQ_???",
    269 			      inet_diag_req_nla_decoders,
    270 			      ARRAY_SIZE(inet_diag_req_nla_decoders), NULL);
    271 	}
    272 }
    273 
    274 DECL_NETLINK_DIAG_DECODER(decode_inet_diag_req)
    275 {
    276 	if (nlmsghdr->nlmsg_type == TCPDIAG_GETSOCK
    277 	    || nlmsghdr->nlmsg_type == DCCPDIAG_GETSOCK)
    278 		decode_inet_diag_req_compat(tcp, nlmsghdr, family, addr, len);
    279 	else
    280 		decode_inet_diag_req_v2(tcp, nlmsghdr, family, addr, len);
    281 }
    282 
    283 static bool
    284 decode_inet_diag_meminfo(struct tcb *const tcp,
    285 			 const kernel_ulong_t addr,
    286 			 const unsigned int len,
    287 			 const void *const opaque_data)
    288 {
    289 	struct inet_diag_meminfo minfo;
    290 
    291 	if (len < sizeof(minfo))
    292 		return false;
    293 	if (umove_or_printaddr(tcp, addr, &minfo))
    294 		return true;
    295 
    296 	PRINT_FIELD_U("{", minfo, idiag_rmem);
    297 	PRINT_FIELD_U(", ", minfo, idiag_wmem);
    298 	PRINT_FIELD_U(", ", minfo, idiag_fmem);
    299 	PRINT_FIELD_U(", ", minfo, idiag_tmem);
    300 	tprints("}");
    301 
    302 	return true;
    303 }
    304 
    305 static bool
    306 decode_tcpvegas_info(struct tcb *const tcp,
    307 		     const kernel_ulong_t addr,
    308 		     const unsigned int len,
    309 		     const void *const opaque_data)
    310 {
    311 	struct tcpvegas_info vegas;
    312 
    313 	if (len < sizeof(vegas))
    314 		return false;
    315 	if (umove_or_printaddr(tcp, addr, &vegas))
    316 		return true;
    317 
    318 	PRINT_FIELD_U("{", vegas, tcpv_enabled);
    319 	PRINT_FIELD_U(", ", vegas, tcpv_rttcnt);
    320 	PRINT_FIELD_U(", ", vegas, tcpv_rtt);
    321 	PRINT_FIELD_U(", ", vegas, tcpv_minrtt);
    322 	tprints("}");
    323 
    324 	return true;
    325 }
    326 
    327 static bool
    328 decode_tcp_dctcp_info(struct tcb *const tcp,
    329 		      const kernel_ulong_t addr,
    330 		      const unsigned int len,
    331 		      const void *const opaque_data)
    332 {
    333 	struct tcp_dctcp_info dctcp;
    334 
    335 	if (len < sizeof(dctcp))
    336 		return false;
    337 	if (umove_or_printaddr(tcp, addr, &dctcp))
    338 		return true;
    339 
    340 	PRINT_FIELD_U("{", dctcp, dctcp_enabled);
    341 	PRINT_FIELD_U(", ", dctcp, dctcp_ce_state);
    342 	PRINT_FIELD_U(", ", dctcp, dctcp_alpha);
    343 	PRINT_FIELD_U(", ", dctcp, dctcp_ab_ecn);
    344 	PRINT_FIELD_U(", ", dctcp, dctcp_ab_tot);
    345 	tprints("}");
    346 
    347 	return true;
    348 }
    349 
    350 static bool
    351 decode_tcp_bbr_info(struct tcb *const tcp,
    352 		    const kernel_ulong_t addr,
    353 		    const unsigned int len,
    354 		    const void *const opaque_data)
    355 {
    356 	struct tcp_bbr_info bbr;
    357 
    358 	if (len < sizeof(bbr))
    359 		return false;
    360 	if (umove_or_printaddr(tcp, addr, &bbr))
    361 		return true;
    362 
    363 	PRINT_FIELD_X("{", bbr, bbr_bw_lo);
    364 	PRINT_FIELD_X(", ", bbr, bbr_bw_hi);
    365 	PRINT_FIELD_U(", ", bbr, bbr_min_rtt);
    366 	PRINT_FIELD_U(", ", bbr, bbr_pacing_gain);
    367 	PRINT_FIELD_U(", ", bbr, bbr_cwnd_gain);
    368 	tprints("}");
    369 
    370 	return true;
    371 }
    372 
    373 static const nla_decoder_t inet_diag_msg_nla_decoders[] = {
    374 	[INET_DIAG_MEMINFO]	= decode_inet_diag_meminfo,
    375 	[INET_DIAG_INFO]	= NULL,			/* unimplemented */
    376 	[INET_DIAG_VEGASINFO]	= decode_tcpvegas_info,
    377 	[INET_DIAG_CONG]	= decode_nla_str,
    378 	[INET_DIAG_TOS]		= decode_nla_u8,
    379 	[INET_DIAG_TCLASS]	= decode_nla_u8,
    380 	[INET_DIAG_SKMEMINFO]	= decode_nla_meminfo,
    381 	[INET_DIAG_SHUTDOWN]	= decode_nla_u8,
    382 	[INET_DIAG_DCTCPINFO]	= decode_tcp_dctcp_info,
    383 	[INET_DIAG_PROTOCOL]	= decode_nla_u8,
    384 	[INET_DIAG_SKV6ONLY]	= decode_nla_u8,
    385 	[INET_DIAG_LOCALS]	= NULL,			/* unimplemented */
    386 	[INET_DIAG_PEERS]	= NULL,			/* unimplemented */
    387 	[INET_DIAG_PAD]		= NULL,
    388 	[INET_DIAG_MARK]	= decode_nla_u32,
    389 	[INET_DIAG_BBRINFO]	= decode_tcp_bbr_info,
    390 	[INET_DIAG_CLASS_ID]	= decode_nla_u32
    391 };
    392 
    393 DECL_NETLINK_DIAG_DECODER(decode_inet_diag_msg)
    394 {
    395 	struct inet_diag_msg msg = { .idiag_family = family };
    396 	size_t offset = sizeof(msg.idiag_family);
    397 	bool decode_nla = false;
    398 
    399 	PRINT_FIELD_XVAL("{", msg, idiag_family, addrfams, "AF_???");
    400 	tprints(", ");
    401 	if (len >= sizeof(msg)) {
    402 		if (!umoven_or_printaddr(tcp, addr + offset,
    403 					 sizeof(msg) - offset,
    404 					 (char *) &msg + offset)) {
    405 			PRINT_FIELD_XVAL("", msg, idiag_state,
    406 					 tcp_states, "TCP_???");
    407 			PRINT_FIELD_U(", ", msg, idiag_timer);
    408 			PRINT_FIELD_U(", ", msg, idiag_retrans);
    409 			PRINT_FIELD_INET_DIAG_SOCKID(", ", msg, id,
    410 						     msg.idiag_family);
    411 			PRINT_FIELD_U(", ", msg, idiag_expires);
    412 			PRINT_FIELD_U(", ", msg, idiag_rqueue);
    413 			PRINT_FIELD_U(", ", msg, idiag_wqueue);
    414 			PRINT_FIELD_U(", ", msg, idiag_uid);
    415 			PRINT_FIELD_U(", ", msg, idiag_inode);
    416 			decode_nla = true;
    417 		}
    418 	} else
    419 		tprints("...");
    420 	tprints("}");
    421 
    422 	offset = NLMSG_ALIGN(sizeof(msg));
    423 	if (decode_nla && len > offset) {
    424 		tprints(", ");
    425 		decode_nlattr(tcp, addr + offset, len - offset,
    426 			      inet_diag_attrs, "INET_DIAG_???",
    427 			      inet_diag_msg_nla_decoders,
    428 			      ARRAY_SIZE(inet_diag_msg_nla_decoders), NULL);
    429 	}
    430 }
    431