Blame SOURCES/0050-xtables-translate-Fix-translation-of-odd-netmasks.patch

ec5e2e
From d8b7a38b12888dcd39c7678b00625369389de9ea Mon Sep 17 00:00:00 2001
ec5e2e
From: Phil Sutter <phil@nwl.cc>
ec5e2e
Date: Tue, 2 Mar 2021 14:50:07 +0100
ec5e2e
Subject: [PATCH] xtables-translate: Fix translation of odd netmasks
ec5e2e
ec5e2e
Iptables supports netmasks which are not prefixes to match on (or
ec5e2e
ignore) arbitrary bits in an address. Yet nftables' prefix notation is
ec5e2e
available for real prefixes only, so translation is not as trivial -
ec5e2e
print bitmask syntax for those cases.
ec5e2e
ec5e2e
Signed-off-by: Phil Sutter <phil@nwl.cc>
ec5e2e
(cherry picked from commit 46f9d3a9a61ee80fa94b7fa7b3b36045c92606ae)
ec5e2e
Signed-off-by: Phil Sutter <psutter@redhat.com>
ec5e2e
---
ec5e2e
 extensions/generic.txlate   | 48 +++++++++++++++++++++++++++++++++++++
ec5e2e
 extensions/libxt_standard.t | 12 ++++++++++
ec5e2e
 iptables/nft-ipv4.c         | 42 ++++++++++++++++++++++----------
ec5e2e
 iptables/nft-ipv6.c         | 19 ++++++++++++---
ec5e2e
 4 files changed, 106 insertions(+), 15 deletions(-)
ec5e2e
ec5e2e
diff --git a/extensions/generic.txlate b/extensions/generic.txlate
ec5e2e
index 0e256c3727559..9ae9a5b54c1b9 100644
ec5e2e
--- a/extensions/generic.txlate
ec5e2e
+++ b/extensions/generic.txlate
ec5e2e
@@ -10,6 +10,54 @@ nft insert rule ip filter INPUT iifname "iifname" ip saddr 10.0.0.0/8 counter
ec5e2e
 iptables-translate -A INPUT -i iif+ ! -d 10.0.0.0/8
ec5e2e
 nft add rule ip filter INPUT iifname "iif*" ip daddr != 10.0.0.0/8 counter
ec5e2e
 
ec5e2e
+iptables-translate -I INPUT -s 10.11.12.13/255.255.0.0
ec5e2e
+nft insert rule ip filter INPUT ip saddr 10.11.0.0/16 counter
ec5e2e
+
ec5e2e
+iptables-translate -I INPUT -s 10.11.12.13/255.0.255.0
ec5e2e
+nft insert rule ip filter INPUT ip saddr & 255.0.255.0 == 10.0.12.0 counter
ec5e2e
+
ec5e2e
+iptables-translate -I INPUT -s 10.11.12.13/0.255.0.255
ec5e2e
+nft insert rule ip filter INPUT ip saddr & 0.255.0.255 == 0.11.0.13 counter
ec5e2e
+
ec5e2e
+iptables-translate -I INPUT ! -s 10.11.12.13/0.255.0.255
ec5e2e
+nft insert rule ip filter INPUT ip saddr & 0.255.0.255 != 0.11.0.13 counter
ec5e2e
+
ec5e2e
+iptables-translate -I INPUT -s 0.0.0.0/16
ec5e2e
+nft insert rule ip filter INPUT ip saddr 0.0.0.0/16 counter
ec5e2e
+
ec5e2e
+iptables-translate -I INPUT -s 0.0.0.0/0
ec5e2e
+nft insert rule ip filter INPUT counter
ec5e2e
+
ec5e2e
+iptables-translate -I INPUT ! -s 0.0.0.0/0
ec5e2e
+nft insert rule ip filter INPUT ip saddr != 0.0.0.0/0 counter
ec5e2e
+
ec5e2e
+ip6tables-translate -I INPUT -i iifname -s feed::/16
ec5e2e
+nft insert rule ip6 filter INPUT iifname "iifname" ip6 saddr feed::/16 counter
ec5e2e
+
ec5e2e
+ip6tables-translate -A INPUT -i iif+ ! -d feed::/16
ec5e2e
+nft add rule ip6 filter INPUT iifname "iif*" ip6 daddr != feed::/16 counter
ec5e2e
+
ec5e2e
+ip6tables-translate -I INPUT -s feed:babe::1/ffff:ff00::
ec5e2e
+nft insert rule ip6 filter INPUT ip6 saddr feed:ba00::/24 counter
ec5e2e
+
ec5e2e
+ip6tables-translate -I INPUT -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/ffff:0:ffff:0:ffff:0:ffff:0
ec5e2e
+nft insert rule ip6 filter INPUT ip6 saddr & ffff:0:ffff:0:ffff:0:ffff:0 == feed:0:c0ff:0:c0be:0:5678:0 counter
ec5e2e
+
ec5e2e
+ip6tables-translate -I INPUT -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/0:ffff:0:ffff:0:ffff:0:ffff
ec5e2e
+nft insert rule ip6 filter INPUT ip6 saddr & 0:ffff:0:ffff:0:ffff:0:ffff == 0:babe:0:ee00:0:1234:0:90ab counter
ec5e2e
+
ec5e2e
+ip6tables-translate -I INPUT ! -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/0:ffff:0:ffff:0:ffff:0:ffff
ec5e2e
+nft insert rule ip6 filter INPUT ip6 saddr & 0:ffff:0:ffff:0:ffff:0:ffff != 0:babe:0:ee00:0:1234:0:90ab counter
ec5e2e
+
ec5e2e
+ip6tables-translate -I INPUT -s ::/16
ec5e2e
+nft insert rule ip6 filter INPUT ip6 saddr ::/16 counter
ec5e2e
+
ec5e2e
+ip6tables-translate -I INPUT -s ::/0
ec5e2e
+nft insert rule ip6 filter INPUT counter
ec5e2e
+
ec5e2e
+ip6tables-translate -I INPUT ! -s ::/0
ec5e2e
+nft insert rule ip6 filter INPUT ip6 saddr != ::/0 counter
ec5e2e
+
ec5e2e
 ebtables-translate -I INPUT -i iname --logical-in ilogname -s 0:0:0:0:0:0
ec5e2e
 nft insert rule bridge filter INPUT iifname "iname" meta ibrname "ilogname" ether saddr 00:00:00:00:00:00 counter
ec5e2e
 
ec5e2e
diff --git a/extensions/libxt_standard.t b/extensions/libxt_standard.t
ec5e2e
index 4313f7b7bac9d..56d6da2e5884e 100644
ec5e2e
--- a/extensions/libxt_standard.t
ec5e2e
+++ b/extensions/libxt_standard.t
ec5e2e
@@ -9,3 +9,15 @@
ec5e2e
 -j ACCEPT;=;OK
ec5e2e
 -j RETURN;=;OK
ec5e2e
 ! -p 0 -j ACCEPT;=;FAIL
ec5e2e
+-s 10.11.12.13/8;-s 10.0.0.0/8;OK
ec5e2e
+-s 10.11.12.13/9;-s 10.0.0.0/9;OK
ec5e2e
+-s 10.11.12.13/10;-s 10.0.0.0/10;OK
ec5e2e
+-s 10.11.12.13/11;-s 10.0.0.0/11;OK
ec5e2e
+-s 10.11.12.13/12;-s 10.0.0.0/12;OK
ec5e2e
+-s 10.11.12.13/30;-s 10.11.12.12/30;OK
ec5e2e
+-s 10.11.12.13/31;-s 10.11.12.12/31;OK
ec5e2e
+-s 10.11.12.13/32;-s 10.11.12.13/32;OK
ec5e2e
+-s 10.11.12.13/255.0.0.0;-s 10.0.0.0/8;OK
ec5e2e
+-s 10.11.12.13/255.128.0.0;-s 10.0.0.0/9;OK
ec5e2e
+-s 10.11.12.13/255.0.255.0;-s 10.0.12.0/255.0.255.0;OK
ec5e2e
+-s 10.11.12.13/255.0.12.0;-s 10.0.12.0/255.0.12.0;OK
ec5e2e
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
ec5e2e
index 5bd0710781533..af5db31532540 100644
ec5e2e
--- a/iptables/nft-ipv4.c
ec5e2e
+++ b/iptables/nft-ipv4.c
ec5e2e
@@ -383,6 +383,32 @@ static void nft_ipv4_post_parse(int command,
ec5e2e
 			      " source or destination IP addresses");
ec5e2e
 }
ec5e2e
 
ec5e2e
+static void xlate_ipv4_addr(const char *selector, const struct in_addr *addr,
ec5e2e
+			    const struct in_addr *mask,
ec5e2e
+			    bool inv, struct xt_xlate *xl)
ec5e2e
+{
ec5e2e
+	const char *op = inv ? "!= " : "";
ec5e2e
+	int cidr;
ec5e2e
+
ec5e2e
+	if (!inv && !addr->s_addr && !mask->s_addr)
ec5e2e
+		return;
ec5e2e
+
ec5e2e
+	cidr = xtables_ipmask_to_cidr(mask);
ec5e2e
+	switch (cidr) {
ec5e2e
+	case -1:
ec5e2e
+		/* inet_ntoa() is not reentrant */
ec5e2e
+		xt_xlate_add(xl, "%s & %s ", selector, inet_ntoa(*mask));
ec5e2e
+		xt_xlate_add(xl, "%s %s ", inv ? "!=" : "==", inet_ntoa(*addr));
ec5e2e
+		break;
ec5e2e
+	case 32:
ec5e2e
+		xt_xlate_add(xl, "%s %s%s ", selector, op, inet_ntoa(*addr));
ec5e2e
+		break;
ec5e2e
+	default:
ec5e2e
+		xt_xlate_add(xl, "%s %s%s/%d ", selector, op, inet_ntoa(*addr),
ec5e2e
+			     cidr);
ec5e2e
+	}
ec5e2e
+}
ec5e2e
+
ec5e2e
 static int nft_ipv4_xlate(const void *data, struct xt_xlate *xl)
ec5e2e
 {
ec5e2e
 	const struct iptables_command_state *cs = data;
ec5e2e
@@ -417,18 +443,10 @@ static int nft_ipv4_xlate(const void *data, struct xt_xlate *xl)
ec5e2e
 		}
ec5e2e
 	}
ec5e2e
 
ec5e2e
-	if (cs->fw.ip.src.s_addr != 0) {
ec5e2e
-		xt_xlate_add(xl, "ip saddr %s%s%s ",
ec5e2e
-			   cs->fw.ip.invflags & IPT_INV_SRCIP ? "!= " : "",
ec5e2e
-			   inet_ntoa(cs->fw.ip.src),
ec5e2e
-			   xtables_ipmask_to_numeric(&cs->fw.ip.smsk));
ec5e2e
-	}
ec5e2e
-	if (cs->fw.ip.dst.s_addr != 0) {
ec5e2e
-		xt_xlate_add(xl, "ip daddr %s%s%s ",
ec5e2e
-			   cs->fw.ip.invflags & IPT_INV_DSTIP ? "!= " : "",
ec5e2e
-			   inet_ntoa(cs->fw.ip.dst),
ec5e2e
-			   xtables_ipmask_to_numeric(&cs->fw.ip.dmsk));
ec5e2e
-	}
ec5e2e
+	xlate_ipv4_addr("ip saddr", &cs->fw.ip.src, &cs->fw.ip.smsk,
ec5e2e
+			cs->fw.ip.invflags & IPT_INV_SRCIP, xl);
ec5e2e
+	xlate_ipv4_addr("ip daddr", &cs->fw.ip.dst, &cs->fw.ip.dmsk,
ec5e2e
+			cs->fw.ip.invflags & IPT_INV_DSTIP, xl);
ec5e2e
 
ec5e2e
 	ret = xlate_matches(cs, xl);
ec5e2e
 	if (!ret)
ec5e2e
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c
ec5e2e
index 6ece631d85f59..a5481b3f77ac5 100644
ec5e2e
--- a/iptables/nft-ipv6.c
ec5e2e
+++ b/iptables/nft-ipv6.c
ec5e2e
@@ -337,14 +337,27 @@ static void xlate_ipv6_addr(const char *selector, const struct in6_addr *addr,
ec5e2e
 			    const struct in6_addr *mask,
ec5e2e
 			    int invert, struct xt_xlate *xl)
ec5e2e
 {
ec5e2e
+	const char *op = invert ? "!= " : "";
ec5e2e
 	char addr_str[INET6_ADDRSTRLEN];
ec5e2e
+	int cidr;
ec5e2e
 
ec5e2e
-	if (!invert && IN6_IS_ADDR_UNSPECIFIED(addr))
ec5e2e
+	if (!invert && IN6_IS_ADDR_UNSPECIFIED(addr) && IN6_IS_ADDR_UNSPECIFIED(mask))
ec5e2e
 		return;
ec5e2e
 
ec5e2e
 	inet_ntop(AF_INET6, addr, addr_str, INET6_ADDRSTRLEN);
ec5e2e
-	xt_xlate_add(xl, "%s %s%s%s ", selector, invert ? "!= " : "", addr_str,
ec5e2e
-			xtables_ip6mask_to_numeric(mask));
ec5e2e
+	cidr = xtables_ip6mask_to_cidr(mask);
ec5e2e
+	switch (cidr) {
ec5e2e
+	case -1:
ec5e2e
+		xt_xlate_add(xl, "%s & %s %s %s ", selector,
ec5e2e
+			     xtables_ip6addr_to_numeric(mask),
ec5e2e
+			     invert ? "!=" : "==", addr_str);
ec5e2e
+		break;
ec5e2e
+	case 128:
ec5e2e
+		xt_xlate_add(xl, "%s %s%s ", selector, op, addr_str);
ec5e2e
+		break;
ec5e2e
+	default:
ec5e2e
+		xt_xlate_add(xl, "%s %s%s/%d ", selector, op, addr_str, cidr);
ec5e2e
+	}
ec5e2e
 }
ec5e2e
 
ec5e2e
 static int nft_ipv6_xlate(const void *data, struct xt_xlate *xl)
ec5e2e
-- 
ec5e2e
2.31.1
ec5e2e