diff options
author | Eugene Syromyatnikov <evgsyr@gmail.com> | 2021-12-16 19:02:16 +0100 |
---|---|---|
committer | Dmitry V. Levin <ldv@strace.io> | 2022-07-31 21:03:01 +0000 |
commit | be93c49062a5c6371d9f54fda33aad50fdd8d2f2 (patch) | |
tree | 475ba9fc87c2e4d55680e4180d5f4b984039e66e | |
parent | 73be9ad60dd7b079ab8229bece552efd4f780baa (diff) | |
download | strace-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-- | NEWS | 3 | ||||
-rw-r--r-- | src/netlink_inet_diag.c | 75 | ||||
-rw-r--r-- | tests/nlattr_inet_diag_msg.c | 31 |
3 files changed, 108 insertions, 1 deletions
@@ -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; } |