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