summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Syromyatnikov <evgsyr@gmail.com>2021-12-16 19:02:16 +0100
committerDmitry V. Levin <ldv@strace.io>2022-07-31 21:03:01 +0000
commitbe93c49062a5c6371d9f54fda33aad50fdd8d2f2 (patch)
tree475ba9fc87c2e4d55680e4180d5f4b984039e66e
parent73be9ad60dd7b079ab8229bece552efd4f780baa (diff)
downloadstrace-be93c49062a5c6371d9f54fda33aad50fdd8d2f2.tar.gz
inet_diag: implement INET_DIAG_SOCKOPT attribute decoding
* src/netlink_inet_diag.c (decode_diag_sockopt): New function. (OPT_PRINT_FIELD_U): New macro. (inet_diag_msg_nla_decoders) <[INET_DIAG_SOCKOPT]>: New entry with the value of decode_diag_sockopt. * tests/nlattr_inet_diag_msg.c: Add checks. * NEWS: Mention it.
-rw-r--r--NEWS3
-rw-r--r--src/netlink_inet_diag.c75
-rw-r--r--tests/nlattr_inet_diag_msg.c31
3 files changed, 108 insertions, 1 deletions
diff --git a/NEWS b/NEWS
index b546164c1..9829d98a3 100644
--- a/NEWS
+++ b/NEWS
@@ -10,7 +10,8 @@ Noteworthy changes in release ?.?? (????-??-??)
* Implemented printing of Unix socket sun_path field's SELinux context.
* Improved decoding of INET_DIAG_MD5SIG, INET_DIAG_PROTOCOL,
INET_DIAG_REQ_PROTOCOL, INET_DIAG_SHUTDOWN, INET_DIAG_SK_BPF_STORAGES,
- and INET_DIAG_ULP_INFO NETLINK_SOCK_DIAG netlink attributes.
+ INET_DIAG_SOCKOPT, and INET_DIAG_ULP_INFO NETLINK_SOCK_DIAG netlink
+ attributes.
* Updated the list of NET_IPV4_CONF_* constants.
* Updated lists of ioctl commands from Linux 5.19.
diff --git a/src/netlink_inet_diag.c b/src/netlink_inet_diag.c
index 93ae94ad5..2cc3f24e2 100644
--- a/src/netlink_inet_diag.c
+++ b/src/netlink_inet_diag.c
@@ -667,6 +667,80 @@ decode_diag_bpf_storages(struct tcb *const tcp,
return true;
}
+static bool
+decode_diag_sockopt(struct tcb *const tcp,
+ const kernel_ulong_t addr,
+ const unsigned int len,
+ const void *const opaque_data)
+{
+ /*
+ * The own version of struct inet_diag_sockopt here since
+ * there is no trivial way to detect new bit fields and, as a result,
+ * shrinkage of the "unused" field.
+ */
+ struct inet_diag_sockopt {
+ uint8_t recverr :1,
+ is_icsk :1,
+ freebind :1,
+ hdrincl :1,
+ mc_loop :1,
+ transparent :1,
+ mc_all :1,
+ nodefrag :1;
+ uint8_t bind_address_no_port :1,
+ recverr_rfc4884 :1,
+ defer_connect :1,
+ unused :5;
+ } sockopt;
+
+ if (len < sizeof(sockopt))
+ return false;
+ if (umove_or_printaddr(tcp, addr, &sockopt))
+ return true;
+
+ void (*delim_f)(void) = tprint_struct_begin;
+
+#define OPT_PRINT_FIELD_U(where_, field_) \
+ do { \
+ if (!abbrev(tcp) || ((where_).field_)) { \
+ delim_f(); \
+ delim_f = tprint_struct_next; \
+ PRINT_FIELD_U_CAST((where_), field_, uint8_t); \
+ } \
+ } while (0)
+
+ OPT_PRINT_FIELD_U(sockopt, recverr);
+ OPT_PRINT_FIELD_U(sockopt, is_icsk);
+ OPT_PRINT_FIELD_U(sockopt, freebind);
+ OPT_PRINT_FIELD_U(sockopt, hdrincl);
+ OPT_PRINT_FIELD_U(sockopt, mc_loop);
+ OPT_PRINT_FIELD_U(sockopt, transparent);
+ OPT_PRINT_FIELD_U(sockopt, mc_all);
+ OPT_PRINT_FIELD_U(sockopt, nodefrag);
+ OPT_PRINT_FIELD_U(sockopt, bind_address_no_port);
+ OPT_PRINT_FIELD_U(sockopt, recverr_rfc4884);
+ OPT_PRINT_FIELD_U(sockopt, defer_connect);
+
+ if (!abbrev(tcp) || sockopt.unused) {
+ delim_f();
+ delim_f = tprint_struct_next;
+ PRINT_FIELD_X_CAST(sockopt, unused, uint8_t);
+ tprints_comment("bits 3..8");
+ }
+
+ if (delim_f == tprint_struct_begin)
+ tprint_struct_begin();
+
+ tprint_struct_end();
+
+#undef OPT_PRINT_FIELD_U
+
+ print_nonzero_bytes(tcp, tprint_array_next, addr, sizeof(sockopt),
+ MIN(len, get_pagesize()), QUOTE_FORCE_HEX);
+
+ return true;
+}
+
static const nla_decoder_t inet_diag_msg_nla_decoders[] = {
[INET_DIAG_MEMINFO] = decode_inet_diag_meminfo,
[INET_DIAG_INFO] = NULL, /* unimplemented */
@@ -689,6 +763,7 @@ static const nla_decoder_t inet_diag_msg_nla_decoders[] = {
[INET_DIAG_ULP_INFO] = decode_diag_ulp_info,
[INET_DIAG_SK_BPF_STORAGES] = decode_diag_bpf_storages,
[INET_DIAG_CGROUP_ID] = decode_nla_u64,
+ [INET_DIAG_SOCKOPT] = decode_diag_sockopt,
};
DECL_NETLINK_DIAG_DECODER(decode_inet_diag_msg)
diff --git a/tests/nlattr_inet_diag_msg.c b/tests/nlattr_inet_diag_msg.c
index 792f60d28..e178e763b 100644
--- a/tests/nlattr_inet_diag_msg.c
+++ b/tests/nlattr_inet_diag_msg.c
@@ -782,6 +782,37 @@ main(void)
printf("%s", bpfst_vals[i].str));
}
+ /* INET_DIAG_SOCKOPT */
+ static const struct {
+ ssize_t sz;
+ const char *val;
+ const char *str;
+ } sockopts[] = {
+ { 1, "\xbe", "\"\\xbe\"" },
+ { 2, "\x00\x00", "{}" },
+ { 2, BE_LE("\xca\xa0", "\x53\x05"),
+ "{recverr=1, is_icsk=1, mc_loop=1, mc_all=1"
+ ", bind_address_no_port=1, defer_connect=1}" },
+ { 3, BE_LE("\x1e\xad", "\x78\xb5"),
+ "{hdrincl=1, mc_loop=1, transparent=1, mc_all=1"
+ ", bind_address_no_port=1, defer_connect=1"
+ ", unused=0x16 /* bits 3..8 */}" },
+ { 4, "\xff\xff\x00\xff",
+ "{recverr=1, is_icsk=1, freebind=1, hdrincl=1, mc_loop=1"
+ ", transparent=1, mc_all=1, nodefrag=1"
+ ", bind_address_no_port=1, recverr_rfc4884=1, defer_connect=1"
+ ", unused=0x1f /* bits 3..8 */}"
+ ", /* bytes 2..3 */ \"\\x00\\xff\"" },
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE(sockopts); i++) {
+ TEST_NLATTR(fd, nlh0, hdrlen,
+ init_inet_diag_msg, print_inet_diag_msg,
+ INET_DIAG_SOCKOPT,
+ sockopts[i].sz, sockopts[i].val, sockopts[i].sz,
+ printf("%s", sockopts[i].str));
+ }
+
puts("+++ exited with 0 +++");
return 0;
}