]> granicus.if.org Git - strace/blob - netlink_sock_diag.c
netlink: introduce a basic netlink attributes parser
[strace] / netlink_sock_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 "nlattr.h"
33
34 #include <arpa/inet.h>
35 #include <linux/inet_diag.h>
36 #include <linux/netlink_diag.h>
37 #include <linux/packet_diag.h>
38 #ifdef AF_SMC
39 # include <linux/smc_diag.h>
40 #endif
41 #include <linux/unix_diag.h>
42
43 #include "xlat/inet_diag_extended_flags.h"
44
45 #include "xlat/tcp_states.h"
46 #include "xlat/tcp_state_flags.h"
47
48 #include "xlat/netlink_diag_show.h"
49 #include "xlat/netlink_states.h"
50
51 #include "xlat/packet_diag_show.h"
52
53 #ifdef AF_SMC
54 # include "xlat/smc_diag_extended_flags.h"
55 # include "xlat/smc_states.h"
56 #endif
57
58 #include "xlat/unix_diag_attrs.h"
59 #include "xlat/unix_diag_show.h"
60
61 static void
62 decode_family(struct tcb *const tcp, const uint8_t family,
63               const kernel_ulong_t addr, const kernel_ulong_t len)
64 {
65         tprints("{family=");
66         printxval(addrfams, family, "AF_???");
67         if (len > sizeof(family)) {
68                 tprints(", ");
69                 printstrn(tcp, addr + sizeof(family),
70                           len - sizeof(family));
71         }
72         tprints("}");
73 }
74
75 static void
76 decode_unix_diag_req(struct tcb *const tcp,
77                      const struct nlmsghdr *const nlmsghdr,
78                      const uint8_t family,
79                      const kernel_ulong_t addr,
80                      const kernel_ulong_t len)
81 {
82         struct unix_diag_req req = { .sdiag_family = family };
83         const size_t offset = sizeof(req.sdiag_family);
84
85         tprints("{sdiag_family=");
86         printxval(addrfams, req.sdiag_family, "AF_???");
87
88         tprints(", ");
89         if (len >= sizeof(req)) {
90                 if (!umoven_or_printaddr(tcp, addr + offset,
91                                          sizeof(req) - offset,
92                                          (void *) &req + offset)) {
93                         tprintf("sdiag_protocol=%" PRIu8 ", udiag_states=",
94                                 req.sdiag_protocol);
95                         printflags(tcp_state_flags, req.udiag_states,
96                                    "1<<TCP_???");
97                         tprintf(", udiag_ino=%" PRIu32 ", udiag_show=",
98                                 req.udiag_ino);
99                         printflags(unix_diag_show, req.udiag_show,
100                                    "UDIAG_SHOW_???");
101                         tprintf(", udiag_cookie=[%" PRIu32 ", %" PRIu32 "]",
102                                 req.udiag_cookie[0], req.udiag_cookie[1]);
103                 }
104         } else
105                 tprints("...");
106         tprints("}");
107 }
108
109 static void
110 decode_unix_diag_msg(struct tcb *const tcp,
111                      const struct nlmsghdr *const nlmsghdr,
112                      const uint8_t family,
113                      const kernel_ulong_t addr,
114                      const kernel_ulong_t len)
115 {
116         struct unix_diag_msg msg = { .udiag_family = family };
117         size_t offset = sizeof(msg.udiag_family);
118         bool decode_nla = false;
119
120         tprints("{udiag_family=");
121         printxval(addrfams, msg.udiag_family, "AF_???");
122
123         tprints(", ");
124         if (len >= sizeof(msg)) {
125                 if (!umoven_or_printaddr(tcp, addr + offset,
126                                          sizeof(msg) - offset,
127                                          (void *) &msg + offset)) {
128                         tprints("udiag_type=");
129                         printxval(socktypes, msg.udiag_type, "SOCK_???");
130                         tprintf(", udiag_state=");
131                         printxval(tcp_states, msg.udiag_state, "TCP_???");
132                         tprintf(", udiag_ino=%" PRIu32
133                                 ", udiag_cookie=[%" PRIu32 ", %" PRIu32 "]",
134                                 msg.udiag_ino,
135                                 msg.udiag_cookie[0], msg.udiag_cookie[1]);
136                         decode_nla = true;
137                 }
138         } else
139                 tprints("...");
140         tprints("}");
141
142         offset = NLMSG_ALIGN(sizeof(msg));
143         if (decode_nla && len > offset) {
144                 tprints(", ");
145                 decode_nlattr(tcp, addr + offset, len - offset,
146                               unix_diag_attrs, "UNIX_DIAG_???");
147         }
148 }
149
150 static void
151 decode_netlink_diag_req(struct tcb *const tcp,
152                         const struct nlmsghdr *const nlmsghdr,
153                         const uint8_t family,
154                         const kernel_ulong_t addr,
155                         const kernel_ulong_t len)
156 {
157         struct netlink_diag_req req = { .sdiag_family = family };
158         const size_t offset = sizeof(req.sdiag_family);
159
160         tprints("{sdiag_family=");
161         printxval(addrfams, req.sdiag_family, "AF_???");
162
163         tprints(", ");
164         if (len >= sizeof(req)) {
165                 if (!umoven_or_printaddr(tcp, addr + offset,
166                                          sizeof(req) - offset,
167                                          (void *) &req + offset)) {
168                         tprints("sdiag_protocol=");
169                         if (NDIAG_PROTO_ALL == req.sdiag_protocol)
170                                 tprints("NDIAG_PROTO_ALL");
171                         else
172                                 printxval(netlink_protocols,
173                                           req.sdiag_protocol, "NETLINK_???");
174                         tprintf(", ndiag_ino=%" PRIu32 ", ndiag_show=",
175                                 req.ndiag_ino);
176                         printflags(netlink_diag_show, req.ndiag_show,
177                                    "NDIAG_SHOW_???");
178                         tprintf(", ndiag_cookie=[%" PRIu32 ", %" PRIu32 "]",
179                                 req.ndiag_cookie[0], req.ndiag_cookie[1]);
180                 }
181         } else
182                 tprints("...");
183         tprints("}");
184 }
185
186 static void
187 decode_netlink_diag_msg(struct tcb *const tcp,
188                         const struct nlmsghdr *const nlmsghdr,
189                         const uint8_t family,
190                         const kernel_ulong_t addr,
191                         const kernel_ulong_t len)
192 {
193         struct netlink_diag_msg msg = { .ndiag_family = family };
194         const size_t offset = sizeof(msg.ndiag_family);
195
196         tprints("{ndiag_family=");
197         printxval(addrfams, msg.ndiag_family, "AF_???");
198
199         tprints(", ");
200         if (len >= sizeof(msg)) {
201                 if (!umoven_or_printaddr(tcp, addr + offset,
202                                          sizeof(msg) - offset,
203                                          (void *) &msg + offset)) {
204                         tprints("ndiag_type=");
205                         printxval(socktypes, msg.ndiag_type, "SOCK_???");
206                         tprints(", ndiag_protocol=");
207                         printxval(netlink_protocols, msg.ndiag_protocol,
208                                   "NETLINK_???");
209                         tprints(", ndiag_state=");
210                         printxval(netlink_states, msg.ndiag_state,
211                                   "NETLINK_???");
212                         tprintf(", ndiag_portid=%" PRIu32
213                                 ", ndiag_dst_portid=%" PRIu32
214                                 ", ndiag_dst_group=%" PRIu32
215                                 ", ndiag_ino=%" PRIu32
216                                 ", ndiag_cookie=[%" PRIu32
217                                 ", %" PRIu32 "]",
218                                 msg.ndiag_portid,
219                                 msg.ndiag_dst_portid,
220                                 msg.ndiag_dst_group,
221                                 msg.ndiag_ino,
222                                 msg.ndiag_cookie[0],
223                                 msg.ndiag_cookie[1]);
224                 }
225         } else
226                 tprints("...");
227         tprints("}");
228 }
229
230 static void
231 decode_packet_diag_req(struct tcb *const tcp,
232                        const struct nlmsghdr *const nlmsghdr,
233                        const uint8_t family,
234                        const kernel_ulong_t addr,
235                        const kernel_ulong_t len)
236 {
237         struct packet_diag_req req = { .sdiag_family = family };
238         const size_t offset = sizeof(req.sdiag_family);
239
240         tprints("{sdiag_family=");
241         printxval(addrfams, req.sdiag_family, "AF_???");
242         tprints(", ");
243         if (len >= sizeof(req)) {
244                 if (!umoven_or_printaddr(tcp, addr + offset,
245                                          sizeof(req) - offset,
246                                          (void *) &req + offset)) {
247                         tprints("sdiag_protocol=");
248                         printxval(ethernet_protocols, req.sdiag_protocol,
249                                   "ETH_P_???");
250                         tprintf(", pdiag_ino=%" PRIu32 ", pdiag_show=",
251                                 req.pdiag_ino);
252                         printflags(packet_diag_show, req.pdiag_show,
253                                    "PACKET_SHOW_???");
254                         tprintf(", pdiag_cookie=[%" PRIu32 ", %" PRIu32 "]",
255                                 req.pdiag_cookie[0], req.pdiag_cookie[1]);
256                 }
257         } else
258                 tprints("...");
259         tprints("}");
260 }
261
262 static void
263 decode_packet_diag_msg(struct tcb *const tcp,
264                        const struct nlmsghdr *const nlmsghdr,
265                        const uint8_t family,
266                        const kernel_ulong_t addr,
267                        const kernel_ulong_t len)
268 {
269         struct packet_diag_msg msg = { .pdiag_family = family };
270         const size_t offset = sizeof(msg.pdiag_family);
271
272         tprints("{pdiag_family=");
273         printxval(addrfams, msg.pdiag_family, "AF_???");
274
275         tprints(", ");
276         if (len >= sizeof(msg)) {
277                 if (!umoven_or_printaddr(tcp, addr + offset,
278                                          sizeof(msg) - offset,
279                                          (void *) &msg + offset)) {
280                         tprints("pdiag_type=");
281                         printxval(socktypes, msg.pdiag_type, "SOCK_???");
282                         tprintf(", pdiag_num=%" PRIu16 ", pdiag_ino=%" PRIu32
283                                 ", pdiag_cookie=[%" PRIu32 ", %" PRIu32 "]",
284                                 msg.pdiag_num, msg.pdiag_ino, msg.pdiag_cookie[0],
285                                 msg.pdiag_cookie[1]);
286                 }
287         } else
288                 tprints("...");
289         tprints("}");
290 }
291
292 static void
293 print_inet_diag_sockid(const struct inet_diag_sockid *id, const uint8_t family)
294 {
295         tprintf("{idiag_sport=htons(%u), idiag_dport=htons(%u)",
296                 ntohs(id->idiag_sport), ntohs(id->idiag_dport));
297
298         tprints(", ");
299         print_inet_addr(family, id->idiag_src,
300                         sizeof(id->idiag_src), "idiag_src");
301         tprints(", ");
302         print_inet_addr(family, id->idiag_dst,
303                         sizeof(id->idiag_dst), "idiag_dst");
304
305         tprintf(", idiag_if=%" PRIu32
306                 ", idiag_cookie=[%" PRIu32 ", %" PRIu32 "]}",
307                 id->idiag_if, id->idiag_cookie[0], id->idiag_cookie[1]);
308 }
309
310 static void
311 decode_inet_diag_req_compat(struct tcb *const tcp,
312                             const struct nlmsghdr *const nlmsghdr,
313                             const uint8_t family,
314                             const kernel_ulong_t addr,
315                             const kernel_ulong_t len)
316 {
317         struct inet_diag_req req = { .idiag_family = family };
318         const size_t offset = sizeof(req.idiag_family);
319
320         tprints("{idiag_family=");
321         printxval(addrfams, req.idiag_family, "AF_???");
322
323         tprints(", ");
324         if (len >= sizeof(req)) {
325                 if (!umoven_or_printaddr(tcp, addr + offset,
326                                          sizeof(req) - offset,
327                                          (void *) &req + offset)) {
328                         tprintf("idiag_src_len=%" PRIu8
329                                 ", idiag_dst_len=%" PRIu8,
330                                 req.idiag_src_len,
331                                 req.idiag_dst_len);
332                         tprints(", idiag_ext=");
333                         printflags(inet_diag_extended_flags, req.idiag_ext,
334                                    "1<<INET_DIAG_\?\?\?-1");
335                         tprints(", id=");
336                         print_inet_diag_sockid(&req.id, req.idiag_family);
337                         tprints(", idiag_states=");
338                         printflags(tcp_state_flags, req.idiag_states,
339                                    "1<<TCP_???");
340                         tprintf(", idiag_dbs=%" PRIu32, req.idiag_dbs);
341                 }
342         } else
343                 tprints("...");
344         tprints("}");
345 }
346
347 static void
348 decode_inet_diag_req_v2(struct tcb *const tcp,
349                         const struct nlmsghdr *const nlmsghdr,
350                         const uint8_t family,
351                         const kernel_ulong_t addr,
352                         const kernel_ulong_t len)
353 {
354         struct inet_diag_req_v2 req = { .sdiag_family = family };
355         const size_t offset = sizeof(req.sdiag_family);
356
357         tprints("{sdiag_family=");
358         printxval(addrfams, req.sdiag_family, "AF_???");
359
360         tprints(", ");
361         if (len >= sizeof(req)) {
362                 if (!umoven_or_printaddr(tcp, addr + offset,
363                                          sizeof(req) - offset,
364                                          (void *) &req + offset)) {
365                         tprints("sdiag_protocol=");
366                         printxval(inet_protocols, req.sdiag_protocol,
367                                   "IPPROTO_???");
368                         tprints(", idiag_ext=");
369                         printflags(inet_diag_extended_flags, req.idiag_ext,
370                                    "1<<INET_DIAG_\?\?\?-1");
371                         tprints(", idiag_states=");
372                         printflags(tcp_state_flags, req.idiag_states,
373                                    "1<<TCP_???");
374                         tprints(", id=");
375                         print_inet_diag_sockid(&req.id, req.sdiag_family);
376                 }
377         } else
378                 tprints("...");
379         tprints("}");
380 }
381
382 static void
383 decode_inet_diag_req(struct tcb *const tcp,
384                      const struct nlmsghdr *const nlmsghdr,
385                      const uint8_t family,
386                      const kernel_ulong_t addr,
387                      const kernel_ulong_t len)
388 {
389         if (nlmsghdr->nlmsg_type == TCPDIAG_GETSOCK
390             || nlmsghdr->nlmsg_type == DCCPDIAG_GETSOCK)
391                 return decode_inet_diag_req_compat(tcp, nlmsghdr,
392                                                    family, addr, len);
393         else
394                 return decode_inet_diag_req_v2(tcp, nlmsghdr,
395                                                family, addr, len);
396 }
397
398 static void
399 decode_inet_diag_msg(struct tcb *const tcp,
400                      const struct nlmsghdr *const nlmsghdr,
401                      const uint8_t family,
402                      const kernel_ulong_t addr,
403                      const kernel_ulong_t len)
404 {
405         struct inet_diag_msg msg = { .idiag_family = family };
406         const size_t offset = sizeof(msg.idiag_family);
407
408         tprints("{idiag_family=");
409         printxval(addrfams, msg.idiag_family, "AF_???");
410
411         tprints(", ");
412         if (len >= sizeof(msg)) {
413                 if (!umoven_or_printaddr(tcp, addr + offset,
414                                          sizeof(msg) - offset,
415                                          (void *) &msg + offset)) {
416                         tprints("idiag_state=");
417                         printxval(tcp_states, msg.idiag_state, "TCP_???");
418                         tprintf(", idiag_timer=%" PRIu8
419                                 ", idiag_retrans=%" PRIu8,
420                                 msg.idiag_timer, msg.idiag_retrans);
421                         tprints(", id=");
422                         print_inet_diag_sockid(&msg.id, msg.idiag_family);
423                         tprintf(", idiag_expires=%" PRIu32
424                                 ", idiag_rqueue=%" PRIu32
425                                 ", idiag_wqueue=%" PRIu32
426                                 ", idiag_uid=%" PRIu32
427                                 ", idiag_inode=%" PRIu32,
428                                 msg.idiag_expires,
429                                 msg.idiag_rqueue,
430                                 msg.idiag_wqueue,
431                                 msg.idiag_uid,
432                                 msg.idiag_inode);
433                 }
434         } else
435                 tprints("...");
436         tprints("}");
437 }
438
439 #ifdef AF_SMC
440 static void
441 decode_smc_diag_req(struct tcb *const tcp,
442                     const struct nlmsghdr *const nlmsghdr,
443                     const uint8_t family,
444                     const kernel_ulong_t addr,
445                     const kernel_ulong_t len)
446 {
447         struct smc_diag_req req = { .diag_family = family };
448         const size_t offset = sizeof(req.diag_family);
449
450         tprints("{diag_family=");
451         printxval(addrfams, req.diag_family, "AF_???");
452
453         tprints(", ");
454         if (len >= sizeof(req)) {
455                 if (!umoven_or_printaddr(tcp, addr + offset,
456                                          sizeof(req) - offset,
457                                          (void *) &req + offset)) {
458                         tprints("diag_ext=");
459                         printflags(smc_diag_extended_flags, req.diag_ext,
460                                    "1<<SMC_DIAG_\?\?\?-1");
461                         tprints(", id=");
462                         /*
463                          * AF_SMC protocol family socket handler
464                          * keeping the AF_INET sock address.
465                          */
466                         print_inet_diag_sockid(&req.id, AF_INET);
467                 }
468         } else
469                 tprints("...");
470         tprints("}");
471 }
472
473 static void
474 decode_smc_diag_msg(struct tcb *const tcp,
475                     const struct nlmsghdr *const nlmsghdr,
476                     const uint8_t family,
477                     const kernel_ulong_t addr,
478                     const kernel_ulong_t len)
479 {
480         struct smc_diag_msg msg = { .diag_family = family };
481         const size_t offset = sizeof(msg.diag_family);
482
483         tprints("{diag_family=");
484         printxval(addrfams, msg.diag_family, "AF_???");
485
486         tprints(", ");
487         if (len >= sizeof(msg)) {
488                 if (!umoven_or_printaddr(tcp, addr + offset,
489                                          sizeof(msg) - offset,
490                                          (void *) &msg + offset)) {
491                         tprints("diag_state=");
492                         printxval(smc_states, msg.diag_state, "SMC_???");
493                         tprintf(", diag_fallback=%" PRIu8
494                                 ", diag_shutdown=%" PRIu8,
495                                 msg.diag_fallback, msg.diag_shutdown);
496                         tprints(", id=");
497                         /*
498                          * AF_SMC protocol family socket handler
499                          * keeping the AF_INET sock address.
500                          */
501                         print_inet_diag_sockid(&msg.id, AF_INET);
502                         tprintf(", diag_uid=%" PRIu32 ", diag_inode=%" PRIu64,
503                                 msg.diag_uid, msg.diag_inode);
504                 }
505         } else
506                 tprints("...");
507         tprints("}");
508
509 }
510 #endif
511
512 typedef void (*netlink_diag_decoder_t)(struct tcb *,
513                                        const struct nlmsghdr *,
514                                        uint8_t family,
515                                        kernel_ulong_t addr,
516                                        kernel_ulong_t len);
517
518 static const struct {
519         const netlink_diag_decoder_t request, response;
520 } diag_decoders[] = {
521         [AF_INET] = { decode_inet_diag_req, decode_inet_diag_msg },
522         [AF_INET6] = { decode_inet_diag_req, decode_inet_diag_msg },
523         [AF_NETLINK] = { decode_netlink_diag_req, decode_netlink_diag_msg },
524         [AF_PACKET] = { decode_packet_diag_req, decode_packet_diag_msg },
525 #ifdef AF_SMC
526         [AF_SMC] = { decode_smc_diag_req, decode_smc_diag_msg },
527 #endif
528         [AF_UNIX] = { decode_unix_diag_req, decode_unix_diag_msg }
529 };
530
531 bool
532 decode_netlink_sock_diag(struct tcb *const tcp,
533                          const struct nlmsghdr *const nlmsghdr,
534                          const kernel_ulong_t addr,
535                          const kernel_ulong_t len)
536 {
537         uint8_t family;
538
539         if (!umove_or_printaddr(tcp, addr, &family)) {
540                 if (family < ARRAY_SIZE(diag_decoders)
541                     && len > sizeof(family)) {
542                         const netlink_diag_decoder_t decoder =
543                                 (nlmsghdr->nlmsg_flags & NLM_F_REQUEST)
544                                 ? diag_decoders[family].request
545                                 : diag_decoders[family].response;
546
547                         if (decoder) {
548                                 decoder(tcp, nlmsghdr, family, addr, len);
549                                 return true;
550                         }
551                 }
552
553                 decode_family(tcp, family, addr, len);
554         }
555
556         return true;
557 }