Currently the code assumes the set of valid options between getsockopt and setsockopt are exactly the same and thus maintains one list. The kernel unfortunately does not do this -- it allows for different opts between the get and set functions. See the {g,s}et_opt{min,max} fields in the various netfilter subcores.
To support this, extend the printxval function to take multiple sets of xlats as varargs. Then we add the new get/set lists, and pass them down in the net code when decoding things. A simple example is iptables; before: getsockopt(4, SOL_IP, 0x40 /* IP_??? */, ...) = 0 getsockopt(4, SOL_IP, 0x41 /* IP_??? */, ...) = 0 after: getsockopt(4, SOL_IP, IPT_SO_GET_INFO, ...) = 0 getsockopt(4, SOL_IP, IPT_SO_GET_ENTRIES, ...) = 0 If these were setsockopt calls, then 0x40 & 0x41 would be IPT_SO_SET_REPLACE & IPT_SO_SET_ADD_COUNTERS. * configure.ac: Check for netfilter headers. * defs.h (printxvals): New prototype. (printxval): Change to a define. * net.c: Include netfilter headers and new sockopts headers. (print_sockopt_fd_level_name): Add a is_getsockopt argument. Change SOL_IP and SOL_IPV6 decoding to use printxvals, and use is_getsockopt to pass more xlats down. (getsockopt): Call print_sockopt_fd_level_name with is_getsockopt as true. (setsockopt): Call print_sockopt_fd_level_name with is_getsockopt as false. * util.c (printxval): Rename to ... (printxvals): ... this. Rewrite to be varargs based. * xlat/getsockipoptions.in: New xlat list. * xlat/getsockipv6options.in, xlat/setsockipoptions.in, xlat/setsockipv6options.in: Likewise. --- v2 - fix a few typos configure.ac | 8 ++++++++ defs.h | 3 ++- net.c | 31 ++++++++++++++++++++++++++----- util.c | 25 +++++++++++++++++++------ xlat/getsockipoptions.in | 26 ++++++++++++++++++++++++++ xlat/getsockipv6options.in | 7 +++++++ xlat/setsockipoptions.in | 28 ++++++++++++++++++++++++++++ xlat/setsockipv6options.in | 5 +++++ 8 files changed, 121 insertions(+), 12 deletions(-) create mode 100644 xlat/getsockipoptions.in create mode 100644 xlat/getsockipv6options.in create mode 100644 xlat/setsockipoptions.in create mode 100644 xlat/setsockipv6options.in diff --git a/configure.ac b/configure.ac index fbd20d2..4fedbf5 100644 --- a/configure.ac +++ b/configure.ac @@ -261,6 +261,7 @@ AC_CHECK_HEADERS(m4_normalize([ linux/falloc.h linux/filter.h linux/hiddev.h + linux/ip_vs.h linux/mmtimer.h linux/perf_event.h linux/seccomp.h @@ -287,6 +288,13 @@ AC_CHECK_HEADERS([linux/icmp.h linux/in6.h linux/netlink.h linux/if_packet.h], AC_CHECK_HEADERS([asm/sigcontext.h], [], [], [#include <signal.h>]) AC_CHECK_TYPES([struct sigcontext],,, [#include <signal.h>]) AC_CHECK_HEADERS([netinet/tcp.h netinet/udp.h],,, [#include <netinet/in.h>]) +AC_CHECK_HEADERS(m4_normalize([ + linux/netfilter_arp/arp_tables.h + linux/netfilter_bridge/ebtables.h + linux/netfilter_ipv4/ip_tables.h + linux/netfilter_ipv6/ip6_tables.h +]), [], [], [#include <netinet/in.h> +#include <net/if.h>]) AC_CHECK_TYPES([struct mmsghdr],,, [#include <sys/socket.h>]) AC_CHECK_MEMBERS([struct msghdr.msg_control],,, [#include <sys/socket.h>]) diff --git a/defs.h b/defs.h index 857175d..9933983 100644 --- a/defs.h +++ b/defs.h @@ -516,7 +516,8 @@ extern int printllval(struct tcb *, const char *, int) ATTRIBUTE_FORMAT((printf, 2, 0)); extern void printaddr(long); -extern void printxval(const struct xlat *, const unsigned int, const char *); +extern void printxvals(const unsigned int, const char *, const struct xlat *, ...); +#define printxval(xlat, val, dflt) printxvals(val, dflt, xlat, NULL) extern int printargs(struct tcb *); extern int printargs_lu(struct tcb *); extern int printargs_ld(struct tcb *); diff --git a/net.c b/net.c index 7e73528..40b5a5c 100644 --- a/net.c +++ b/net.c @@ -52,9 +52,24 @@ # include <linux/ipx.h> #endif +#if defined(HAVE_LINUX_IP_VS_H) +# include <linux/ip_vs.h> +#endif #if defined(HAVE_LINUX_NETLINK_H) # include <linux/netlink.h> #endif +#if defined(HAVE_LINUX_NETFILTER_ARP_ARP_TABLES_H) +# include <linux/netfilter_arp/arp_tables.h> +#endif +#if defined(HAVE_LINUX_NETFILTER_BRIDGE_EBTABLES_H) +# include <linux/netfilter_bridge/ebtables.h> +#endif +#if defined(HAVE_LINUX_NETFILTER_IPV4_IP_TABLES_H) +# include <linux/netfilter_ipv4/ip_tables.h> +#endif +#if defined(HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H) +# include <linux/netfilter_ipv6/ip6_tables.h> +#endif #if defined(HAVE_LINUX_IF_PACKET_H) # include <linux/if_packet.h> #endif @@ -989,7 +1004,11 @@ SYS_FUNC(socketpair) #include "xlat/sockoptions.h" #include "xlat/sockipoptions.h" +#include "xlat/getsockipoptions.h" +#include "xlat/setsockipoptions.h" #include "xlat/sockipv6options.h" +#include "xlat/getsockipv6options.h" +#include "xlat/setsockipv6options.h" #include "xlat/sockipxoptions.h" #include "xlat/sockrawoptions.h" #include "xlat/sockpacketoptions.h" @@ -997,7 +1016,7 @@ SYS_FUNC(socketpair) #include "xlat/socktcpoptions.h" static void -print_sockopt_fd_level_name(struct tcb *tcp, int fd, int level, int name) +print_sockopt_fd_level_name(struct tcb *tcp, int fd, int level, int name, bool is_getsockopt) { printfd(tcp, fd); tprints(", "); @@ -1009,10 +1028,12 @@ print_sockopt_fd_level_name(struct tcb *tcp, int fd, int level, int name) printxval(sockoptions, name, "SO_???"); break; case SOL_IP: - printxval(sockipoptions, name, "IP_???"); + printxvals(name, "IP_???", sockipoptions, + is_getsockopt ? getsockipoptions : setsockipoptions, NULL); break; case SOL_IPV6: - printxval(sockipv6options, name, "IPV6_???"); + printxvals(name, "IPV6_???", sockipv6options, + is_getsockopt ? getsockipv6options : setsockipv6options, NULL); break; case SOL_IPX: printxval(sockipxoptions, name, "IPX_???"); @@ -1172,7 +1193,7 @@ SYS_FUNC(getsockopt) { if (entering(tcp)) { print_sockopt_fd_level_name(tcp, tcp->u_arg[0], - tcp->u_arg[1], tcp->u_arg[2]); + tcp->u_arg[1], tcp->u_arg[2], true); } else { int len; @@ -1435,7 +1456,7 @@ done: SYS_FUNC(setsockopt) { print_sockopt_fd_level_name(tcp, tcp->u_arg[0], - tcp->u_arg[1], tcp->u_arg[2]); + tcp->u_arg[1], tcp->u_arg[2], false); print_setsockopt(tcp, tcp->u_arg[1], tcp->u_arg[2], tcp->u_arg[3], tcp->u_arg[4]); diff --git a/util.c b/util.c index 2a22cac..7682235 100644 --- a/util.c +++ b/util.c @@ -34,6 +34,7 @@ #include "defs.h" #include <sys/param.h> #include <fcntl.h> +#include <stdarg.h> #ifdef HAVE_SYS_XATTR_H # include <sys/xattr.h> #endif @@ -207,14 +208,26 @@ next_set_bit(const void *bit_array, unsigned cur_bit, unsigned size_bits) * Print entry in struct xlat table, if there. */ void -printxval(const struct xlat *xlat, const unsigned int val, const char *dflt) +printxvals(const unsigned int val, const char *dflt, const struct xlat *xlat, ...) { - const char *str = xlookup(xlat, val); + va_list args; + const char *str; + + va_start(args, xlat); + while (xlat) { + str = xlookup(xlat, val); + if (str) { + tprints(str); + return; + } - if (str) - tprints(str); - else - tprintf("%#x /* %s */", val, dflt); + xlat = va_arg(args, const struct xlat *); + if (!xlat) { + tprintf("%#x /* %s */", val, dflt); + break; + } + } + va_end(args); } /* diff --git a/xlat/getsockipoptions.in b/xlat/getsockipoptions.in new file mode 100644 index 0000000..afa964b --- /dev/null +++ b/xlat/getsockipoptions.in @@ -0,0 +1,26 @@ +// Options specific to getsockopt(SOL_IP); common {g,s}etsockopt(SOL_IP) +// options should be in sockipoptions.in instead. + +ARPT_SO_GET_INFO +ARPT_SO_GET_ENTRIES +ARPT_SO_GET_REVISION_MATCH +ARPT_SO_GET_REVISION_TARGET + +EBT_SO_GET_INFO +EBT_SO_GET_ENTRIES +EBT_SO_GET_INIT_INFO +EBT_SO_GET_INIT_ENTRIES + +IP_VS_SO_GET_VERSION +IP_VS_SO_GET_INFO +IP_VS_SO_GET_SERVICES +IP_VS_SO_GET_SERVICE +IP_VS_SO_GET_DESTS +IP_VS_SO_GET_DEST +IP_VS_SO_GET_TIMEOUT +IP_VS_SO_GET_DAEMON + +IPT_SO_GET_INFO +IPT_SO_GET_ENTRIES +IPT_SO_GET_REVISION_MATCH +IPT_SO_GET_REVISION_TARGET diff --git a/xlat/getsockipv6options.in b/xlat/getsockipv6options.in new file mode 100644 index 0000000..d9c89ec --- /dev/null +++ b/xlat/getsockipv6options.in @@ -0,0 +1,7 @@ +// Options specific to getsockopt(SOL_IPV6); common {g,s}etsockopt(SOL_IPV6) +// options should be in sockipv6options.in instead. + +IP6T_SO_GET_INFO +IP6T_SO_GET_ENTRIES +IP6T_SO_GET_REVISION_MATCH +IP6T_SO_GET_REVISION_TARGET diff --git a/xlat/setsockipoptions.in b/xlat/setsockipoptions.in new file mode 100644 index 0000000..3996393 --- /dev/null +++ b/xlat/setsockipoptions.in @@ -0,0 +1,28 @@ +// Options specific to setsockopt(SOL_IP); common {g,s}etsockopt(SOL_IP) +// options should be in sockipoptions.in instead. + +ARPT_SO_SET_REPLACE +ARPT_SO_SET_ADD_COUNTERS + +EBT_SO_SET_ENTRIES +EBT_SO_SET_COUNTERS + +IP_VS_SO_SET_NONE +IP_VS_SO_SET_INSERT +IP_VS_SO_SET_ADD +IP_VS_SO_SET_EDIT +IP_VS_SO_SET_DEL +IP_VS_SO_SET_FLUSH +IP_VS_SO_SET_LIST +IP_VS_SO_SET_ADDDEST +IP_VS_SO_SET_DELDEST +IP_VS_SO_SET_EDITDEST +IP_VS_SO_SET_TIMEOUT +IP_VS_SO_SET_STARTDAEMON +IP_VS_SO_SET_STOPDAEMON +IP_VS_SO_SET_RESTORE +IP_VS_SO_SET_SAVE +IP_VS_SO_SET_ZERO + +IPT_SO_SET_REPLACE +IPT_SO_SET_ADD_COUNTERS diff --git a/xlat/setsockipv6options.in b/xlat/setsockipv6options.in new file mode 100644 index 0000000..8be0c97 --- /dev/null +++ b/xlat/setsockipv6options.in @@ -0,0 +1,5 @@ +// Options specific to setsockopt(SOL_IPV6); common {g,s}etsockopt(SOL_IPV6) +// options should be in sockipv6options.in instead. + +IP6T_SO_SET_REPLACE +IP6T_SO_SET_ADD_COUNTERS -- 2.4.4 ------------------------------------------------------------------------------ _______________________________________________ Strace-devel mailing list Strace-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/strace-devel