[PATCH/RFC] decode extend getsockopt/setsockopt options

Mike Frysinger vapier at gentoo.org
Tue Aug 18 21:03:20 UTC 2015


Currently the code assumes the set of valid options between getsockopt
and setsockopt are exactly the same and thus maintain 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:
getsockopt(4, SOL_IP, 0x40 /* IP_??? */, ...) = 0
getsockopt(4, SOL_IP, 0x41 /* IP_??? */, ...) = 0
getsockopt(4, SOL_IP, IPT_SO_GET_INFO, ...) = 0
getsockopt(4, SOL_IP, IPT_SO_GET_ENTRIES, ...) = 0

If these were setsockopt, 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.
---
RFC: i'm not terribly happy with the printxvals logic.  open to suggestions.

 configure.ac               |  8 ++++++++
 defs.h                     |  3 ++-
 net.c                      | 28 +++++++++++++++++++++++-----
 util.c                     | 25 +++++++++++++++++++------
 xlat/getsockipoptions.in   | 26 ++++++++++++++++++++++++++
 xlat/getsockipv6options.in |  7 +++++++
 xlat/setsockipoptions.in   | 28 ++++++++++++++++++++++++++++
 xlat/setsockipv6options.in |  5 +++++
 8 files changed, 118 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..8a0c8f2 100644
--- a/net.c
+++ b/net.c
@@ -55,6 +55,18 @@
 #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 +1001,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 +1013,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 +1025,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 +1190,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 +1453,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..66c4bac
--- /dev/null
+++ b/xlat/setsockipv6options.in
@@ -0,0 +1,5 @@
+// Options specific to getsockopt(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





More information about the Strace-devel mailing list