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