Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016 Fabien Siron <fabien.siron@epita.fr>
3 : : * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
4 : : * Copyright (c) 2017 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 : 102 : print_inet_diag_sockid(const struct inet_diag_sockid *id, const uint8_t family)
51 : : {
52 [ - + ]: 102 : PRINT_FIELD_NET_PORT("{", *id, idiag_sport);
53 [ - + ]: 102 : PRINT_FIELD_NET_PORT(", ", *id, idiag_dport);
54 : 102 : PRINT_FIELD_INET_ADDR(", ", *id, idiag_src, family);
55 : 102 : PRINT_FIELD_INET_ADDR(", ", *id, idiag_dst, family);
56 : 102 : PRINT_FIELD_IFINDEX(", ", *id, idiag_if);
57 : 102 : PRINT_FIELD_COOKIE(", ", *id, idiag_cookie);
58 : 102 : tprints("}");
59 : 102 : }
60 : :
61 : : static void
62 : 12 : decode_inet_addr(struct tcb *const tcp,
63 : : const kernel_ulong_t addr,
64 : : const unsigned int len,
65 : : const int family)
66 : : {
67 : : union {
68 : : struct in_addr a4;
69 : : struct in6_addr a6;
70 : : } addrbuf;
71 : 12 : size_t size = 0;
72 : :
73 [ + + - ]: 12 : switch (family) {
74 : : case AF_INET:
75 : 6 : size = sizeof(addrbuf.a4);
76 : 6 : break;
77 : : case AF_INET6:
78 : 6 : size = sizeof(addrbuf.a6);
79 : 6 : break;
80 : : }
81 : :
82 [ + - ][ + + ]: 12 : if (!size || len < size) {
83 : 4 : tprints("addr=");
84 : 4 : printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
85 : 8 : return;
86 : : }
87 : :
88 [ + + ]: 8 : if (umoven(tcp, addr, size, &addrbuf) < 0) {
89 : 4 : tprints("addr=");
90 : 4 : printaddr(addr);
91 : 4 : return;
92 : : }
93 : :
94 : 4 : print_inet_addr(family, &addrbuf, size, "addr");
95 : : }
96 : :
97 : : static void
98 : 18 : decode_inet_diag_hostcond(struct tcb *const tcp,
99 : : const kernel_ulong_t addr,
100 : : const unsigned int len)
101 : : {
102 : : struct inet_diag_hostcond cond;
103 : :
104 [ + + ]: 18 : if (len < sizeof(cond)) {
105 : 2 : printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
106 : 4 : return;
107 : : }
108 [ + + ]: 16 : if (umove_or_printaddr(tcp, addr, &cond))
109 : : return;
110 : :
111 : 14 : PRINT_FIELD_XVAL("{", cond, family, addrfams, "AF_???");
112 : 14 : PRINT_FIELD_U(", ", cond, prefix_len);
113 : 14 : PRINT_FIELD_U(", ", cond, port);
114 : :
115 [ + + ]: 14 : if (len > sizeof(cond)) {
116 : 12 : tprints(", ");
117 : 12 : decode_inet_addr(tcp, addr + sizeof(cond),
118 : 12 : len - sizeof(cond), cond.family);
119 : : }
120 : 14 : tprints("}");
121 : : }
122 : :
123 : : static void
124 : 42 : print_inet_diag_bc_op(const struct inet_diag_bc_op *const op)
125 : : {
126 : 42 : PRINT_FIELD_XVAL("{", *op, code, inet_diag_bytecodes,
127 : : "INET_DIAG_BC_???");
128 : 42 : PRINT_FIELD_U(", ", *op, yes);
129 : 42 : PRINT_FIELD_U(", ", *op, no);
130 : 42 : tprints("}");
131 : 42 : }
132 : :
133 : : static void
134 : 6 : decode_inet_diag_markcond(struct tcb *const tcp,
135 : : const kernel_ulong_t addr,
136 : : const unsigned int len)
137 : : {
138 : : struct inet_diag_markcond markcond;
139 : :
140 [ + + ]: 6 : if (len < sizeof(markcond))
141 : 2 : printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
142 [ + + ]: 4 : else if (!umove_or_printaddr(tcp, addr, &markcond)) {
143 : 2 : PRINT_FIELD_U("{", markcond, mark);
144 : 2 : PRINT_FIELD_U(", ", markcond, mask);
145 : 2 : tprints("}");
146 : : }
147 : 6 : }
148 : :
149 : : static void
150 : 38 : decode_bytecode_data(struct tcb *const tcp,
151 : : const kernel_ulong_t addr,
152 : : const unsigned int len,
153 : : const unsigned char code)
154 : : {
155 [ + + + + : 38 : switch (code) {
+ ]
156 : : case INET_DIAG_BC_S_COND:
157 : : case INET_DIAG_BC_D_COND:
158 : 18 : decode_inet_diag_hostcond(tcp, addr, len);
159 : 18 : break;
160 : : case INET_DIAG_BC_DEV_COND: {
161 : : uint32_t ifindex;
162 : :
163 [ + + ]: 6 : if (len < sizeof(ifindex))
164 : 2 : printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
165 [ + + ]: 4 : else if (!umove_or_printaddr(tcp, addr, &ifindex))
166 : 6 : print_ifindex(ifindex);
167 : : break;
168 : : }
169 : : case INET_DIAG_BC_S_GE:
170 : : case INET_DIAG_BC_S_LE:
171 : : case INET_DIAG_BC_D_GE:
172 : : case INET_DIAG_BC_D_LE: {
173 : : struct inet_diag_bc_op op;
174 : :
175 [ + + ]: 6 : if (len < sizeof(op))
176 : 2 : printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
177 [ + + ]: 4 : else if (!umove_or_printaddr(tcp, addr, &op))
178 : 6 : print_inet_diag_bc_op(&op);
179 : : break;
180 : : }
181 : : case INET_DIAG_BC_MARK_COND:
182 : 6 : decode_inet_diag_markcond(tcp, addr, len);
183 : 6 : break;
184 : : case INET_DIAG_BC_AUTO:
185 : : case INET_DIAG_BC_JMP:
186 : : case INET_DIAG_BC_NOP:
187 : : default:
188 : 2 : printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
189 : 2 : break;
190 : : }
191 : 38 : }
192 : :
193 : : static bool
194 : 44 : decode_inet_diag_bc_op(struct tcb *const tcp,
195 : : const kernel_ulong_t addr,
196 : : const unsigned int len,
197 : : const void *const opaque_data)
198 : : {
199 : : struct inet_diag_bc_op op;
200 : :
201 [ + + ]: 44 : if (len < sizeof(op))
202 : : return false;
203 [ + + ]: 42 : if (umove_or_printaddr(tcp, addr, &op))
204 : : return true;
205 : :
206 [ + + ]: 40 : if (len > sizeof(op))
207 : 38 : tprints("{");
208 : :
209 : 40 : print_inet_diag_bc_op(&op);
210 : :
211 [ + + ]: 40 : if (len > sizeof(op)) {
212 : 38 : tprints(", ");
213 : 38 : decode_bytecode_data(tcp, addr + sizeof(op),
214 : 38 : len - sizeof(op), op.code);
215 : 38 : tprints("}");
216 : : }
217 : :
218 : : return true;
219 : : }
220 : :
221 : : static const nla_decoder_t inet_diag_req_nla_decoders[] = {
222 : : [INET_DIAG_REQ_BYTECODE] = decode_inet_diag_bc_op
223 : : };
224 : :
225 : : static void
226 : 8 : decode_inet_diag_req_compat(struct tcb *const tcp,
227 : : const struct nlmsghdr *const nlmsghdr,
228 : : const uint8_t family,
229 : : const kernel_ulong_t addr,
230 : : const unsigned int len)
231 : : {
232 : 8 : struct inet_diag_req req = { .idiag_family = family };
233 : 8 : size_t offset = sizeof(req.idiag_family);
234 : 8 : bool decode_nla = false;
235 : :
236 : 8 : PRINT_FIELD_XVAL("{", req, idiag_family, addrfams, "AF_???");
237 : 8 : tprints(", ");
238 [ + + ]: 8 : if (len >= sizeof(req)) {
239 [ + + ]: 6 : if (!umoven_or_printaddr(tcp, addr + offset,
240 : : sizeof(req) - offset,
241 : : (void *) &req + offset)) {
242 : 4 : PRINT_FIELD_U("", req, idiag_src_len);
243 : 4 : PRINT_FIELD_U(", ", req, idiag_dst_len);
244 : 4 : PRINT_FIELD_FLAGS(", ", req, idiag_ext,
245 : : inet_diag_extended_flags,
246 : : "1<<INET_DIAG_\?\?\?-1");
247 : 4 : PRINT_FIELD_INET_DIAG_SOCKID(", ", req, id,
248 : : req.idiag_family);
249 : 4 : PRINT_FIELD_FLAGS(", ", req, idiag_states,
250 : : tcp_state_flags, "1<<TCP_???");
251 : 4 : PRINT_FIELD_U(", ", req, idiag_dbs);
252 : 4 : decode_nla = true;
253 : : }
254 : : } else
255 : 2 : tprints("...");
256 : 8 : tprints("}");
257 : :
258 : 8 : offset = NLMSG_ALIGN(sizeof(req));
259 [ + + ][ + + ]: 8 : if (decode_nla && len > offset) {
260 : 2 : tprints(", ");
261 : 2 : decode_nlattr(tcp, addr + offset, len - offset,
262 : : inet_diag_req_attrs, "INET_DIAG_REQ_???",
263 : : inet_diag_req_nla_decoders,
264 : : ARRAY_SIZE(inet_diag_req_nla_decoders), NULL);
265 : : }
266 : 8 : }
267 : :
268 : : static void
269 : 54 : decode_inet_diag_req_v2(struct tcb *const tcp,
270 : : const struct nlmsghdr *const nlmsghdr,
271 : : const uint8_t family,
272 : : const kernel_ulong_t addr,
273 : : const unsigned int len)
274 : : {
275 : 54 : struct inet_diag_req_v2 req = { .sdiag_family = family };
276 : 54 : size_t offset = sizeof(req.sdiag_family);
277 : 54 : bool decode_nla = false;
278 : :
279 : 54 : PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???");
280 : 54 : tprints(", ");
281 [ + + ]: 54 : if (len >= sizeof(req)) {
282 [ + + ]: 52 : if (!umoven_or_printaddr(tcp, addr + offset,
283 : : sizeof(req) - offset,
284 : : (void *) &req + offset)) {
285 : 50 : PRINT_FIELD_XVAL("", req, sdiag_protocol,
286 : : inet_protocols, "IPPROTO_???");
287 : 50 : PRINT_FIELD_FLAGS(", ", req, idiag_ext,
288 : : inet_diag_extended_flags,
289 : : "1<<INET_DIAG_\?\?\?-1");
290 : 50 : PRINT_FIELD_FLAGS(", ", req, idiag_states,
291 : : tcp_state_flags, "1<<TCP_???");
292 : 50 : PRINT_FIELD_INET_DIAG_SOCKID(", ", req, id,
293 : : req.sdiag_family);
294 : 50 : decode_nla = true;
295 : : }
296 : : } else
297 : 2 : tprints("...");
298 : 54 : tprints("}");
299 : :
300 : 54 : offset = NLMSG_ALIGN(sizeof(req));
301 [ + + ][ + + ]: 54 : if (decode_nla && len > offset) {
302 : 44 : tprints(", ");
303 : 44 : decode_nlattr(tcp, addr + offset, len - offset,
304 : : inet_diag_req_attrs, "INET_DIAG_REQ_???",
305 : : inet_diag_req_nla_decoders,
306 : : ARRAY_SIZE(inet_diag_req_nla_decoders), NULL);
307 : : }
308 : 54 : }
309 : :
310 : 62 : DECL_NETLINK_DIAG_DECODER(decode_inet_diag_req)
311 : : {
312 [ + + ]: 62 : if (nlmsghdr->nlmsg_type == TCPDIAG_GETSOCK
313 : 62 : || nlmsghdr->nlmsg_type == DCCPDIAG_GETSOCK)
314 : 8 : return decode_inet_diag_req_compat(tcp, nlmsghdr,
315 : : family, addr, len);
316 : : else
317 : 54 : return decode_inet_diag_req_v2(tcp, nlmsghdr,
318 : : family, addr, len);
319 : : }
320 : :
321 : : static bool
322 : 6 : decode_inet_diag_meminfo(struct tcb *const tcp,
323 : : const kernel_ulong_t addr,
324 : : const unsigned int len,
325 : : const void *const opaque_data)
326 : : {
327 : : struct inet_diag_meminfo minfo;
328 : :
329 [ + + ]: 6 : if (len < sizeof(minfo))
330 : : return false;
331 [ + + ]: 4 : if (umove_or_printaddr(tcp, addr, &minfo))
332 : : return true;
333 : :
334 : 2 : PRINT_FIELD_U("{", minfo, idiag_rmem);
335 : 2 : PRINT_FIELD_U(", ", minfo, idiag_wmem);
336 : 2 : PRINT_FIELD_U(", ", minfo, idiag_fmem);
337 : 2 : PRINT_FIELD_U(", ", minfo, idiag_tmem);
338 : 2 : tprints("}");
339 : :
340 : 2 : return true;
341 : : }
342 : :
343 : : static bool
344 : 6 : decode_tcpvegas_info(struct tcb *const tcp,
345 : : const kernel_ulong_t addr,
346 : : const unsigned int len,
347 : : const void *const opaque_data)
348 : : {
349 : : struct tcpvegas_info vegas;
350 : :
351 [ + + ]: 6 : if (len < sizeof(vegas))
352 : : return false;
353 [ + + ]: 4 : if (umove_or_printaddr(tcp, addr, &vegas))
354 : : return true;
355 : :
356 : 2 : PRINT_FIELD_U("{", vegas, tcpv_enabled);
357 : 2 : PRINT_FIELD_U(", ", vegas, tcpv_rttcnt);
358 : 2 : PRINT_FIELD_U(", ", vegas, tcpv_rtt);
359 : 2 : PRINT_FIELD_U(", ", vegas, tcpv_minrtt);
360 : 2 : tprints("}");
361 : :
362 : 2 : return true;
363 : : }
364 : :
365 : : static bool
366 : 6 : decode_tcp_dctcp_info(struct tcb *const tcp,
367 : : const kernel_ulong_t addr,
368 : : const unsigned int len,
369 : : const void *const opaque_data)
370 : : {
371 : : struct tcp_dctcp_info dctcp;
372 : :
373 [ + + ]: 6 : if (len < sizeof(dctcp))
374 : : return false;
375 [ + + ]: 4 : if (umove_or_printaddr(tcp, addr, &dctcp))
376 : : return true;
377 : :
378 : 2 : PRINT_FIELD_U("{", dctcp, dctcp_enabled);
379 : 2 : PRINT_FIELD_U(", ", dctcp, dctcp_ce_state);
380 : 2 : PRINT_FIELD_U(", ", dctcp, dctcp_alpha);
381 : 2 : PRINT_FIELD_U(", ", dctcp, dctcp_ab_ecn);
382 : 2 : PRINT_FIELD_U(", ", dctcp, dctcp_ab_tot);
383 : 2 : tprints("}");
384 : :
385 : 2 : return true;
386 : : }
387 : :
388 : : static bool
389 : 6 : decode_tcp_bbr_info(struct tcb *const tcp,
390 : : const kernel_ulong_t addr,
391 : : const unsigned int len,
392 : : const void *const opaque_data)
393 : : {
394 : : struct tcp_bbr_info bbr;
395 : :
396 [ + + ]: 6 : if (len < sizeof(bbr))
397 : : return false;
398 [ + + ]: 4 : if (umove_or_printaddr(tcp, addr, &bbr))
399 : : return true;
400 : :
401 : 2 : PRINT_FIELD_X("{", bbr, bbr_bw_lo);
402 : 2 : PRINT_FIELD_X(", ", bbr, bbr_bw_hi);
403 : 2 : PRINT_FIELD_U(", ", bbr, bbr_min_rtt);
404 : 2 : PRINT_FIELD_U(", ", bbr, bbr_pacing_gain);
405 : 2 : PRINT_FIELD_U(", ", bbr, bbr_cwnd_gain);
406 : 2 : tprints("}");
407 : :
408 : 2 : return true;
409 : : }
410 : :
411 : : static const nla_decoder_t inet_diag_msg_nla_decoders[] = {
412 : : [INET_DIAG_MEMINFO] = decode_inet_diag_meminfo,
413 : : [INET_DIAG_INFO] = NULL, /* unimplemented */
414 : : [INET_DIAG_VEGASINFO] = decode_tcpvegas_info,
415 : : [INET_DIAG_CONG] = decode_nla_str,
416 : : [INET_DIAG_TOS] = decode_nla_u8,
417 : : [INET_DIAG_TCLASS] = decode_nla_u8,
418 : : [INET_DIAG_SKMEMINFO] = decode_nla_meminfo,
419 : : [INET_DIAG_SHUTDOWN] = decode_nla_u8,
420 : : [INET_DIAG_DCTCPINFO] = decode_tcp_dctcp_info,
421 : : [INET_DIAG_PROTOCOL] = decode_nla_u8,
422 : : [INET_DIAG_SKV6ONLY] = decode_nla_u8,
423 : : [INET_DIAG_LOCALS] = NULL, /* unimplemented */
424 : : [INET_DIAG_PEERS] = NULL, /* unimplemented */
425 : : [INET_DIAG_PAD] = NULL,
426 : : [INET_DIAG_MARK] = decode_nla_u32,
427 : : [INET_DIAG_BBRINFO] = decode_tcp_bbr_info
428 : : };
429 : :
430 : 52 : DECL_NETLINK_DIAG_DECODER(decode_inet_diag_msg)
431 : : {
432 : 52 : struct inet_diag_msg msg = { .idiag_family = family };
433 : 52 : size_t offset = sizeof(msg.idiag_family);
434 : 52 : bool decode_nla = false;
435 : :
436 : 52 : PRINT_FIELD_XVAL("{", msg, idiag_family, addrfams, "AF_???");
437 : 52 : tprints(", ");
438 [ + + ]: 52 : if (len >= sizeof(msg)) {
439 [ + + ]: 50 : if (!umoven_or_printaddr(tcp, addr + offset,
440 : : sizeof(msg) - offset,
441 : : (void *) &msg + offset)) {
442 : 48 : PRINT_FIELD_XVAL("", msg, idiag_state,
443 : : tcp_states, "TCP_???");
444 : 48 : PRINT_FIELD_U(", ", msg, idiag_timer);
445 : 48 : PRINT_FIELD_U(", ", msg, idiag_retrans);
446 : 48 : PRINT_FIELD_INET_DIAG_SOCKID(", ", msg, id,
447 : : msg.idiag_family);
448 : 48 : PRINT_FIELD_U(", ", msg, idiag_expires);
449 : 48 : PRINT_FIELD_U(", ", msg, idiag_rqueue);
450 : 48 : PRINT_FIELD_U(", ", msg, idiag_wqueue);
451 : 48 : PRINT_FIELD_U(", ", msg, idiag_uid);
452 : 48 : PRINT_FIELD_U(", ", msg, idiag_inode);
453 : 48 : decode_nla = true;
454 : : }
455 : : } else
456 : 2 : tprints("...");
457 : 52 : tprints("}");
458 : :
459 : 52 : offset = NLMSG_ALIGN(sizeof(msg));
460 [ + + ][ + + ]: 52 : if (decode_nla && len > offset) {
461 : 46 : tprints(", ");
462 : 46 : decode_nlattr(tcp, addr + offset, len - offset,
463 : : inet_diag_attrs, "INET_DIAG_???",
464 : : inet_diag_msg_nla_decoders,
465 : : ARRAY_SIZE(inet_diag_msg_nla_decoders), NULL);
466 : : }
467 : 52 : }
|