]> granicus.if.org Git - strace/commitdiff
netlink: decode AF_INET inet_diag_req_* attributes
authorJingPiao Chen <chenjingpiao@gmail.com>
Wed, 24 May 2017 06:55:59 +0000 (14:55 +0800)
committerDmitry V. Levin <ldv@altlinux.org>
Tue, 11 Jul 2017 22:24:03 +0000 (22:24 +0000)
* linux/inet_diag.h (inet_diag_bc_op, inet_diag_hostcond,
inet_diag_markcond): New structures.
(INET_DIAG_BC_*): New enum.
* netlink_sock_diag.c: Include "xlat/inet_diag_bytecodes.h".
(decode_inet_addr, decode_inet_diag_hostcond,
print_inet_diag_bc_op, decode_inet_diag_markcond,
decode_bytecode_data, decode_inet_diag_bc_op): New functions.
(inet_diag_req_nla_decoders): New array.
(decode_inet_diag_req_compat, decode_inet_diag_req_v2): Use it.
* xlat/inet_diag_bytecodes.in: New file.

linux/inet_diag.h
netlink_sock_diag.c
xlat/inet_diag_bytecodes.in [new file with mode: 0644]

index 24302db6eeb8c1415b26d00eefdbae8531f664b5..ec6356c2d69d342556e14e5cff33314b7a7f5095 100644 (file)
@@ -39,6 +39,38 @@ enum {
        INET_DIAG_REQ_BYTECODE,
 };
 
+struct inet_diag_bc_op {
+       unsigned char code;
+       unsigned char yes;
+       unsigned short no;
+};
+
+enum {
+       INET_DIAG_BC_NOP,
+       INET_DIAG_BC_JMP,
+       INET_DIAG_BC_S_GE,
+       INET_DIAG_BC_S_LE,
+       INET_DIAG_BC_D_GE,
+       INET_DIAG_BC_D_LE,
+       INET_DIAG_BC_AUTO,
+       INET_DIAG_BC_S_COND,
+       INET_DIAG_BC_D_COND,
+       INET_DIAG_BC_DEV_COND,   /* u32 ifindex */
+       INET_DIAG_BC_MARK_COND,
+};
+
+struct inet_diag_hostcond {
+       uint8_t family;
+       uint8_t prefix_len;
+       int port;
+       uint32_t addr[0];
+};
+
+struct inet_diag_markcond {
+       uint32_t mark;
+       uint32_t mask;
+};
+
 /* Info structure */
 struct inet_diag_msg {
        uint8_t idiag_family;
index cc80ed0d9da5e97bff15f51d0a1931854ff4f9cc..f0cb500be3584639542d057e3acc91f2cfeee334 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/unix_diag.h>
 
 #include "xlat/inet_diag_attrs.h"
+#include "xlat/inet_diag_bytecodes.h"
 #include "xlat/inet_diag_extended_flags.h"
 #include "xlat/inet_diag_req_attrs.h"
 
@@ -618,6 +619,170 @@ print_inet_diag_sockid(const struct inet_diag_sockid *id, const uint8_t family)
                print_inet_diag_sockid(&(where_).field_, (af_));        \
        } while (0)
 
+static void
+decode_inet_addr(struct tcb *const tcp,
+                const kernel_ulong_t addr,
+                const kernel_ulong_t len,
+                const int family)
+{
+       union {
+               struct in_addr  a4;
+               struct in6_addr a6;
+       } addrbuf;
+       size_t size = 0;
+
+       switch (family) {
+       case AF_INET:
+               size = sizeof(addrbuf.a4);
+               break;
+       case AF_INET6:
+               size = sizeof(addrbuf.a6);
+               break;
+       }
+
+       if (!size || len < size) {
+               tprints("addr=");
+               printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
+               return;
+       }
+
+       if (umoven(tcp, addr, size, &addrbuf) < 0) {
+               tprints("addr=");
+               printaddr(addr);
+               return;
+       }
+
+       print_inet_addr(family, &addrbuf, size, "addr");
+}
+
+static void
+decode_inet_diag_hostcond(struct tcb *const tcp,
+                         const kernel_ulong_t addr,
+                         const kernel_ulong_t len)
+{
+       struct inet_diag_hostcond cond;
+
+       if (len < sizeof(cond)) {
+               printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
+               return;
+       }
+       if (umove_or_printaddr(tcp, addr, &cond))
+               return;
+
+       PRINT_FIELD_XVAL("{", cond, family, addrfams, "AF_???");
+       PRINT_FIELD_U(", ", cond, prefix_len);
+       PRINT_FIELD_U(", ", cond, port);
+
+       if (len > sizeof(cond)) {
+               tprints(", ");
+               decode_inet_addr(tcp, addr + sizeof(cond),
+                                len - sizeof(cond), cond.family);
+       }
+       tprints("}");
+}
+
+static void
+print_inet_diag_bc_op(const struct inet_diag_bc_op *const op)
+{
+       PRINT_FIELD_XVAL("{", *op, code, inet_diag_bytecodes,
+                        "INET_DIAG_BC_???");
+       PRINT_FIELD_U(", ", *op, yes);
+       PRINT_FIELD_U(", ", *op, no);
+       tprints("}");
+}
+
+static void
+decode_inet_diag_markcond(struct tcb *const tcp,
+                         const kernel_ulong_t addr,
+                         const kernel_ulong_t len)
+{
+       struct inet_diag_markcond markcond;
+
+       if (len < sizeof(markcond))
+               printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
+       else if (!umove_or_printaddr(tcp, addr, &markcond)) {
+               PRINT_FIELD_U("{", markcond, mark);
+               PRINT_FIELD_U(", ", markcond, mask);
+               tprints("}");
+       }
+}
+
+static void
+decode_bytecode_data(struct tcb *const tcp,
+                    const kernel_ulong_t addr,
+                    const kernel_ulong_t len,
+                    const unsigned char code)
+{
+       switch (code) {
+       case INET_DIAG_BC_S_COND:
+       case INET_DIAG_BC_D_COND:
+               decode_inet_diag_hostcond(tcp, addr, len);
+               break;
+       case INET_DIAG_BC_DEV_COND: {
+               uint32_t ifindex;
+
+               if (len < sizeof(ifindex))
+                       printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
+               else if (!umove_or_printaddr(tcp, addr, &ifindex))
+                       print_ifindex(ifindex);
+               break;
+       }
+       case INET_DIAG_BC_S_GE:
+       case INET_DIAG_BC_S_LE:
+       case INET_DIAG_BC_D_GE:
+       case INET_DIAG_BC_D_LE: {
+               struct inet_diag_bc_op op;
+
+               if (len < sizeof(op))
+                       printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
+               else if (!umove_or_printaddr(tcp, addr, &op))
+                       print_inet_diag_bc_op(&op);
+               break;
+       }
+       case INET_DIAG_BC_MARK_COND:
+               decode_inet_diag_markcond(tcp, addr, len);
+               break;
+       case INET_DIAG_BC_AUTO:
+       case INET_DIAG_BC_JMP:
+       case INET_DIAG_BC_NOP:
+       default:
+               printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
+               break;
+       }
+}
+
+static bool
+decode_inet_diag_bc_op(struct tcb *const tcp,
+                      const kernel_ulong_t addr,
+                      const kernel_ulong_t len,
+                      const void *const opaque_data)
+{
+       struct inet_diag_bc_op op;
+
+       if (len < sizeof(op))
+               return false;
+       if (umove_or_printaddr(tcp, addr, &op))
+               return true;
+
+       if (len > sizeof(op))
+               tprints("{");
+
+       print_inet_diag_bc_op(&op);
+
+       if (len > sizeof(op)) {
+               tprints(", ");
+               decode_bytecode_data(tcp, addr + sizeof(op),
+                                    len - sizeof(op), op.code);
+               tprints("}");
+       }
+
+       return true;
+}
+
+static const nla_decoder_t inet_diag_req_nla_decoders[] = {
+       [INET_DIAG_REQ_BYTECODE] = decode_inet_diag_bc_op
+};
+
 static void
 decode_inet_diag_req_compat(struct tcb *const tcp,
                            const struct nlmsghdr *const nlmsghdr,
@@ -656,7 +821,8 @@ decode_inet_diag_req_compat(struct tcb *const tcp,
                tprints(", ");
                decode_nlattr(tcp, addr + offset, len - offset,
                              inet_diag_req_attrs, "INET_DIAG_REQ_???",
-                             NULL, 0, NULL);
+                             inet_diag_req_nla_decoders,
+                             ARRAY_SIZE(inet_diag_req_nla_decoders), NULL);
        }
 }
 
@@ -697,7 +863,8 @@ decode_inet_diag_req_v2(struct tcb *const tcp,
                tprints(", ");
                decode_nlattr(tcp, addr + offset, len - offset,
                              inet_diag_req_attrs, "INET_DIAG_REQ_???",
-                             NULL, 0, NULL);
+                             inet_diag_req_nla_decoders,
+                             ARRAY_SIZE(inet_diag_req_nla_decoders), NULL);
        }
 }
 
diff --git a/xlat/inet_diag_bytecodes.in b/xlat/inet_diag_bytecodes.in
new file mode 100644 (file)
index 0000000..ccaf0da
--- /dev/null
@@ -0,0 +1,12 @@
+#unconditional
+INET_DIAG_BC_NOP
+INET_DIAG_BC_JMP
+INET_DIAG_BC_S_GE
+INET_DIAG_BC_S_LE
+INET_DIAG_BC_D_GE
+INET_DIAG_BC_D_LE
+INET_DIAG_BC_AUTO
+INET_DIAG_BC_S_COND
+INET_DIAG_BC_D_COND
+INET_DIAG_BC_DEV_COND
+INET_DIAG_BC_MARK_COND