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

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