Linux netfilter at some point (Linux 2.6.39) inverted the meaning of the
'--ctdir reply' and newer netfilter implementations now expect
'--ctdir original' instead and vice-versa.
We check for the kernel version and assume that all Linux kernels with version
2.6.39 have the newer inverted logic.
Any distro backporting the Linux kernel patch that inverts the --ctdir logic
(Linux commit 96120d86f) must also backport this patch for Linux and
adapt the kernel version being tested for.
Signed-off-by: Stefan Berger <stefanb(a)linux.vnet.ibm.com>
---
v2->v3:
- using uname now to check for Linux kernel version number
v1->v2:
- using virSocketAddrParseIPv4
---
src/nwfilter/nwfilter_ebiptables_driver.c | 52 ++++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
Index: libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c
===================================================================
--- libvirt-acl.orig/src/nwfilter/nwfilter_ebiptables_driver.c
+++ libvirt-acl/src/nwfilter/nwfilter_ebiptables_driver.c
@@ -27,6 +27,7 @@
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <sys/utsname.h>
#include "internal.h"
@@ -85,6 +86,17 @@ static char *iptables_cmd_path;
static char *ip6tables_cmd_path;
static char *grep_cmd_path;
+/*
+ * --ctdir original vs. --ctdir reply's meaning was inverted in netfilter
+ * at some point (Linux 2.6.39)
+ */
+enum ctdirStatus {
+ CTDIR_STATUS_UNKNOWN = 0,
+ CTDIR_STATUS_CORRECTED = 1,
+ CTDIR_STATUS_OLD = 2,
+};
+static enum ctdirStatus iptables_ctdir_corrected;
+
#define PRINT_ROOT_CHAIN(buf, prefix, ifname) \
snprintf(buf, sizeof(buf), "libvirt-%c-%s", prefix, ifname)
#define PRINT_CHAIN(buf, prefix, ifname, suffix) \
@@ -1262,6 +1274,17 @@ iptablesEnforceDirection(int directionIn
virNWFilterRuleDefPtr rule,
virBufferPtr buf)
{
+ switch (iptables_ctdir_corrected) {
+ case CTDIR_STATUS_UNKNOWN:
+ /* could not be determined or s.th. is seriously wrong */
+ return;
+ case CTDIR_STATUS_CORRECTED:
+ directionIn = !directionIn;
+ break;
+ case CTDIR_STATUS_OLD:
+ break;
+ }
+
if (rule->tt != VIR_NWFILTER_RULE_DIRECTION_INOUT)
virBufferAsprintf(buf, " -m conntrack --ctdir %s",
(directionIn) ? "Original"
@@ -4304,6 +4327,32 @@ ebiptablesDriverTestCLITools(void)
return ret;
}
+static void
+ebiptablesDriverProbeCtdir(void)
+{
+ struct utsname utsname;
+ unsigned long thisversion;
+
+ iptables_ctdir_corrected = CTDIR_STATUS_UNKNOWN;
+
+ if (uname(&utsname) < 0) {
+ VIR_ERROR(_("Call to utsname failed: %d"), errno);
+ return;
+ }
+
+ /* following Linux lxr, the logic was inverted in 2.6.39 */
+ if (virParseVersionString(utsname.release, &thisversion, true) < 0) {
+ VIR_ERROR(_("Could not determine kernel version from string %s"),
+ utsname.release);
+ return;
+ }
+
+ if (thisversion >= 2 * 1000000 + 6 * 1000 + 39)
+ iptables_ctdir_corrected = CTDIR_STATUS_CORRECTED;
+ else
+ iptables_ctdir_corrected = CTDIR_STATUS_OLD;
+}
+
static int
ebiptablesDriverInit(bool privileged)
{
@@ -4341,6 +4390,9 @@ ebiptablesDriverInit(bool privileged)
return -ENOTSUP;
}
+ if (iptables_cmd_path)
+ ebiptablesDriverProbeCtdir();
+
ebiptables_driver.flags = TECHDRV_FLAG_INITIALIZED;
return 0;