]> granicus.if.org Git - strace/blob - netlink_inet_diag.c
Remove linux/ptp_clock.h
[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 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                                          (void *) &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                                          (void *) &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                 return decode_inet_diag_req_compat(tcp, nlmsghdr,
279                                                    family, addr, len);
280         else
281                 return decode_inet_diag_req_v2(tcp, nlmsghdr,
282                                                family, addr, len);
283 }
284
285 static bool
286 decode_inet_diag_meminfo(struct tcb *const tcp,
287                          const kernel_ulong_t addr,
288                          const unsigned int len,
289                          const void *const opaque_data)
290 {
291         struct inet_diag_meminfo minfo;
292
293         if (len < sizeof(minfo))
294                 return false;
295         if (umove_or_printaddr(tcp, addr, &minfo))
296                 return true;
297
298         PRINT_FIELD_U("{", minfo, idiag_rmem);
299         PRINT_FIELD_U(", ", minfo, idiag_wmem);
300         PRINT_FIELD_U(", ", minfo, idiag_fmem);
301         PRINT_FIELD_U(", ", minfo, idiag_tmem);
302         tprints("}");
303
304         return true;
305 }
306
307 static bool
308 decode_tcpvegas_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 tcpvegas_info vegas;
314
315         if (len < sizeof(vegas))
316                 return false;
317         if (umove_or_printaddr(tcp, addr, &vegas))
318                 return true;
319
320         PRINT_FIELD_U("{", vegas, tcpv_enabled);
321         PRINT_FIELD_U(", ", vegas, tcpv_rttcnt);
322         PRINT_FIELD_U(", ", vegas, tcpv_rtt);
323         PRINT_FIELD_U(", ", vegas, tcpv_minrtt);
324         tprints("}");
325
326         return true;
327 }
328
329 static bool
330 decode_tcp_dctcp_info(struct tcb *const tcp,
331                       const kernel_ulong_t addr,
332                       const unsigned int len,
333                       const void *const opaque_data)
334 {
335         struct tcp_dctcp_info dctcp;
336
337         if (len < sizeof(dctcp))
338                 return false;
339         if (umove_or_printaddr(tcp, addr, &dctcp))
340                 return true;
341
342         PRINT_FIELD_U("{", dctcp, dctcp_enabled);
343         PRINT_FIELD_U(", ", dctcp, dctcp_ce_state);
344         PRINT_FIELD_U(", ", dctcp, dctcp_alpha);
345         PRINT_FIELD_U(", ", dctcp, dctcp_ab_ecn);
346         PRINT_FIELD_U(", ", dctcp, dctcp_ab_tot);
347         tprints("}");
348
349         return true;
350 }
351
352 static bool
353 decode_tcp_bbr_info(struct tcb *const tcp,
354                     const kernel_ulong_t addr,
355                     const unsigned int len,
356                     const void *const opaque_data)
357 {
358         struct tcp_bbr_info bbr;
359
360         if (len < sizeof(bbr))
361                 return false;
362         if (umove_or_printaddr(tcp, addr, &bbr))
363                 return true;
364
365         PRINT_FIELD_X("{", bbr, bbr_bw_lo);
366         PRINT_FIELD_X(", ", bbr, bbr_bw_hi);
367         PRINT_FIELD_U(", ", bbr, bbr_min_rtt);
368         PRINT_FIELD_U(", ", bbr, bbr_pacing_gain);
369         PRINT_FIELD_U(", ", bbr, bbr_cwnd_gain);
370         tprints("}");
371
372         return true;
373 }
374
375 static const nla_decoder_t inet_diag_msg_nla_decoders[] = {
376         [INET_DIAG_MEMINFO]     = decode_inet_diag_meminfo,
377         [INET_DIAG_INFO]        = NULL,                 /* unimplemented */
378         [INET_DIAG_VEGASINFO]   = decode_tcpvegas_info,
379         [INET_DIAG_CONG]        = decode_nla_str,
380         [INET_DIAG_TOS]         = decode_nla_u8,
381         [INET_DIAG_TCLASS]      = decode_nla_u8,
382         [INET_DIAG_SKMEMINFO]   = decode_nla_meminfo,
383         [INET_DIAG_SHUTDOWN]    = decode_nla_u8,
384         [INET_DIAG_DCTCPINFO]   = decode_tcp_dctcp_info,
385         [INET_DIAG_PROTOCOL]    = decode_nla_u8,
386         [INET_DIAG_SKV6ONLY]    = decode_nla_u8,
387         [INET_DIAG_LOCALS]      = NULL,                 /* unimplemented */
388         [INET_DIAG_PEERS]       = NULL,                 /* unimplemented */
389         [INET_DIAG_PAD]         = NULL,
390         [INET_DIAG_MARK]        = decode_nla_u32,
391         [INET_DIAG_BBRINFO]     = decode_tcp_bbr_info,
392         [INET_DIAG_CLASS_ID]    = decode_nla_u32
393 };
394
395 DECL_NETLINK_DIAG_DECODER(decode_inet_diag_msg)
396 {
397         struct inet_diag_msg msg = { .idiag_family = family };
398         size_t offset = sizeof(msg.idiag_family);
399         bool decode_nla = false;
400
401         PRINT_FIELD_XVAL("{", msg, idiag_family, addrfams, "AF_???");
402         tprints(", ");
403         if (len >= sizeof(msg)) {
404                 if (!umoven_or_printaddr(tcp, addr + offset,
405                                          sizeof(msg) - offset,
406                                          (void *) &msg + offset)) {
407                         PRINT_FIELD_XVAL("", msg, idiag_state,
408                                          tcp_states, "TCP_???");
409                         PRINT_FIELD_U(", ", msg, idiag_timer);
410                         PRINT_FIELD_U(", ", msg, idiag_retrans);
411                         PRINT_FIELD_INET_DIAG_SOCKID(", ", msg, id,
412                                                      msg.idiag_family);
413                         PRINT_FIELD_U(", ", msg, idiag_expires);
414                         PRINT_FIELD_U(", ", msg, idiag_rqueue);
415                         PRINT_FIELD_U(", ", msg, idiag_wqueue);
416                         PRINT_FIELD_U(", ", msg, idiag_uid);
417                         PRINT_FIELD_U(", ", msg, idiag_inode);
418                         decode_nla = true;
419                 }
420         } else
421                 tprints("...");
422         tprints("}");
423
424         offset = NLMSG_ALIGN(sizeof(msg));
425         if (decode_nla && len > offset) {
426                 tprints(", ");
427                 decode_nlattr(tcp, addr + offset, len - offset,
428                               inet_diag_attrs, "INET_DIAG_???",
429                               inet_diag_msg_nla_decoders,
430                               ARRAY_SIZE(inet_diag_msg_nla_decoders), NULL);
431         }
432 }