Blame SOURCES/0044-xtables-Fix-for-inserting-rule-at-wrong-position.patch

1dc35b
From 3c0eab01c78ff0215cafc124fd76d67f39f2b4ca Mon Sep 17 00:00:00 2001
8cce6c
From: Phil Sutter <phil@nwl.cc>
8cce6c
Date: Tue, 15 Jan 2019 23:23:05 +0100
8cce6c
Subject: [PATCH] xtables: Fix for inserting rule at wrong position
8cce6c
8cce6c
iptables-restore allows to insert rules at a certain position which is
8cce6c
problematic for iptables-nft to realize since rule position is not
8cce6c
determined by number but handle of previous or following rule and in
8cce6c
case the rules surrounding the new one are new as well, they don't have
8cce6c
a handle to refer to yet.
8cce6c
8cce6c
Fix this by making use of NFTNL_RULE_POSITION_ID attribute: When
8cce6c
inserting before a rule which does not have a handle, refer to it using
8cce6c
its NFTNL_RULE_ID value. If the latter doesn't exist either, assign a
8cce6c
new one to it.
8cce6c
8cce6c
The last used rule ID value is tracked in a new field of struct
8cce6c
nft_handle which is incremented before each use.
8cce6c
8cce6c
Signed-off-by: Phil Sutter <phil@nwl.cc>
8cce6c
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
8cce6c
(cherry picked from commit 7ea0b7d809229973d950ed99845bdd0b2eb4cbb7)
8cce6c
Signed-off-by: Phil Sutter <psutter@redhat.com>
8cce6c
---
8cce6c
 iptables/nft.c                                |  30 +++--
8cce6c
 iptables/nft.h                                |   1 +
8cce6c
 .../ipt-restore/0003-restore-ordering_0       | 117 ++++++++++++++++++
8cce6c
 .../testcases/iptables/0005-rule-replace_0    |  38 ++++++
8cce6c
 4 files changed, 176 insertions(+), 10 deletions(-)
8cce6c
 create mode 100755 iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0
8cce6c
 create mode 100755 iptables/tests/shell/testcases/iptables/0005-rule-replace_0
8cce6c
8cce6c
diff --git a/iptables/nft.c b/iptables/nft.c
8cce6c
index 76764fde4e9fb..2fa973cf03975 100644
8cce6c
--- a/iptables/nft.c
8cce6c
+++ b/iptables/nft.c
8cce6c
@@ -2065,16 +2065,30 @@ int nft_rule_delete(struct nft_handle *h, const char *chain,
8cce6c
 static struct nftnl_rule *
8cce6c
 nft_rule_add(struct nft_handle *h, const char *chain,
8cce6c
 	     const char *table, struct iptables_command_state *cs,
8cce6c
-	     uint64_t handle, bool verbose)
8cce6c
+	     struct nftnl_rule *ref, bool verbose)
8cce6c
 {
8cce6c
 	struct nftnl_rule *r;
8cce6c
+	uint64_t ref_id;
8cce6c
 
8cce6c
 	r = nft_rule_new(h, chain, table, cs);
8cce6c
 	if (r == NULL)
8cce6c
 		return NULL;
8cce6c
 
8cce6c
-	if (handle > 0)
8cce6c
-		nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, handle);
8cce6c
+	if (ref) {
8cce6c
+		ref_id = nftnl_rule_get_u64(ref, NFTNL_RULE_HANDLE);
8cce6c
+		if (ref_id > 0) {
8cce6c
+			nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, ref_id);
8cce6c
+			DEBUGP("adding after rule handle %"PRIu64"\n", ref_id);
8cce6c
+		} else {
8cce6c
+			ref_id = nftnl_rule_get_u32(ref, NFTNL_RULE_ID);
8cce6c
+			if (!ref_id) {
8cce6c
+				ref_id = ++h->rule_id;
8cce6c
+				nftnl_rule_set_u32(ref, NFTNL_RULE_ID, ref_id);
8cce6c
+			}
8cce6c
+			nftnl_rule_set_u32(r, NFTNL_RULE_POSITION_ID, ref_id);
8cce6c
+			DEBUGP("adding after rule ID %"PRIu64"\n", ref_id);
8cce6c
+		}
8cce6c
+	}
8cce6c
 
8cce6c
 	if (batch_rule_add(h, NFT_COMPAT_RULE_INSERT, r) < 0) {
8cce6c
 		nftnl_rule_free(r);
8cce6c
@@ -2090,9 +2104,8 @@ nft_rule_add(struct nft_handle *h, const char *chain,
8cce6c
 int nft_rule_insert(struct nft_handle *h, const char *chain,
8cce6c
 		    const char *table, void *data, int rulenum, bool verbose)
8cce6c
 {
8cce6c
-	struct nftnl_rule *r, *new_rule;
8cce6c
+	struct nftnl_rule *r = NULL, *new_rule;
8cce6c
 	struct nftnl_chain *c;
8cce6c
-	uint64_t handle = 0;
8cce6c
 
8cce6c
 	/* If built-in chains don't exist for this table, create them */
8cce6c
 	if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
8cce6c
@@ -2120,16 +2133,13 @@ int nft_rule_insert(struct nft_handle *h, const char *chain,
8cce6c
 			errno = ENOENT;
8cce6c
 			goto err;
8cce6c
 		}
8cce6c
-
8cce6c
-		handle = nftnl_rule_get_u64(r, NFTNL_RULE_HANDLE);
8cce6c
-		DEBUGP("adding after rule handle %"PRIu64"\n", handle);
8cce6c
 	}
8cce6c
 
8cce6c
-	new_rule = nft_rule_add(h, chain, table, data, handle, verbose);
8cce6c
+	new_rule = nft_rule_add(h, chain, table, data, r, verbose);
8cce6c
 	if (!new_rule)
8cce6c
 		goto err;
8cce6c
 
8cce6c
-	if (handle)
8cce6c
+	if (r)
8cce6c
 		nftnl_chain_rule_insert_at(new_rule, r);
8cce6c
 	else
8cce6c
 		nftnl_chain_rule_add(new_rule, c);
8cce6c
diff --git a/iptables/nft.h b/iptables/nft.h
8cce6c
index 97d73c8b534be..0726923a63dd4 100644
8cce6c
--- a/iptables/nft.h
8cce6c
+++ b/iptables/nft.h
8cce6c
@@ -32,6 +32,7 @@ struct nft_handle {
8cce6c
 	struct mnl_socket	*nl;
8cce6c
 	uint32_t		portid;
8cce6c
 	uint32_t		seq;
8cce6c
+	uint32_t		rule_id;
8cce6c
 	struct list_head	obj_list;
8cce6c
 	int			obj_list_num;
8cce6c
 	struct nftnl_batch	*batch;
8cce6c
diff --git a/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0 b/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0
8cce6c
new file mode 100755
8cce6c
index 0000000000000..51f2422e15259
8cce6c
--- /dev/null
8cce6c
+++ b/iptables/tests/shell/testcases/ipt-restore/0003-restore-ordering_0
8cce6c
@@ -0,0 +1,117 @@
8cce6c
+#!/bin/bash
8cce6c
+
8cce6c
+# Make sure iptables-restore does the right thing
8cce6c
+# when encountering INSERT rules with index.
8cce6c
+
8cce6c
+set -e
8cce6c
+
8cce6c
+# show rules, drop uninteresting policy settings
8cce6c
+ipt_show() {
8cce6c
+	$XT_MULTI iptables -S | grep -v '^-P'
8cce6c
+}
8cce6c
+
8cce6c
+# basic issue reproducer
8cce6c
+
8cce6c
+$XT_MULTI iptables-restore <
8cce6c
+*filter
8cce6c
+-A FORWARD -m comment --comment "appended rule" -j ACCEPT
8cce6c
+-I FORWARD 1 -m comment --comment "rule 1" -j ACCEPT
8cce6c
+-I FORWARD 2 -m comment --comment "rule 2" -j ACCEPT
8cce6c
+-I FORWARD 3 -m comment --comment "rule 3" -j ACCEPT
8cce6c
+COMMIT
8cce6c
+EOF
8cce6c
+
8cce6c
+EXPECT='-A FORWARD -m comment --comment "rule 1" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "rule 2" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "rule 3" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "appended rule" -j ACCEPT'
8cce6c
+
8cce6c
+diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
8cce6c
+
8cce6c
+# insert rules into existing ruleset
8cce6c
+
8cce6c
+$XT_MULTI iptables-restore --noflush <
8cce6c
+*filter
8cce6c
+-I FORWARD 1 -m comment --comment "rule 0.5" -j ACCEPT
8cce6c
+-I FORWARD 3 -m comment --comment "rule 1.5" -j ACCEPT
8cce6c
+-I FORWARD 5 -m comment --comment "rule 2.5" -j ACCEPT
8cce6c
+-I FORWARD 7 -m comment --comment "rule 3.5" -j ACCEPT
8cce6c
+-I FORWARD 9 -m comment --comment "appended rule 2" -j ACCEPT
8cce6c
+COMMIT
8cce6c
+EOF
8cce6c
+
8cce6c
+EXPECT='-A FORWARD -m comment --comment "rule 0.5" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "rule 1" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "rule 1.5" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "rule 2" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "rule 2.5" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "rule 3" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "rule 3.5" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "appended rule" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "appended rule 2" -j ACCEPT'
8cce6c
+
8cce6c
+diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
8cce6c
+
8cce6c
+# insert rules in between added ones
8cce6c
+
8cce6c
+$XT_MULTI iptables-restore <
8cce6c
+*filter
8cce6c
+-A FORWARD -m comment --comment "appended rule 1" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "appended rule 2" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "appended rule 3" -j ACCEPT
8cce6c
+-I FORWARD 1 -m comment --comment "rule 1" -j ACCEPT
8cce6c
+-I FORWARD 3 -m comment --comment "rule 2" -j ACCEPT
8cce6c
+-I FORWARD 5 -m comment --comment "rule 3" -j ACCEPT
8cce6c
+COMMIT
8cce6c
+EOF
8cce6c
+
8cce6c
+EXPECT='-A FORWARD -m comment --comment "rule 1" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "appended rule 1" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "rule 2" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "appended rule 2" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "rule 3" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "appended rule 3" -j ACCEPT'
8cce6c
+
8cce6c
+diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
8cce6c
+
8cce6c
+# test rule deletion in dump files
8cce6c
+
8cce6c
+$XT_MULTI iptables-restore --noflush <
8cce6c
+*filter
8cce6c
+-D FORWARD -m comment --comment "appended rule 1" -j ACCEPT
8cce6c
+-D FORWARD 3
8cce6c
+-I FORWARD 3 -m comment --comment "manually replaced rule 2" -j ACCEPT
8cce6c
+COMMIT
8cce6c
+EOF
8cce6c
+
8cce6c
+EXPECT='-A FORWARD -m comment --comment "rule 1" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "rule 2" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "manually replaced rule 2" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "rule 3" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "appended rule 3" -j ACCEPT'
8cce6c
+
8cce6c
+diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
8cce6c
+
8cce6c
+# test rule replacement in dump files
8cce6c
+
8cce6c
+$XT_MULTI iptables-restore <
8cce6c
+*filter
8cce6c
+-A FORWARD -m comment --comment "rule 1" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "rule to be replaced" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "rule 3" -j ACCEPT
8cce6c
+COMMIT
8cce6c
+EOF
8cce6c
+
8cce6c
+$XT_MULTI iptables-restore --noflush <
8cce6c
+*filter
8cce6c
+-R FORWARD 2 -m comment --comment "replacement" -j ACCEPT
8cce6c
+-I FORWARD 2 -m comment --comment "insert referencing replaced rule" -j ACCEPT
8cce6c
+COMMIT
8cce6c
+EOF
8cce6c
+
8cce6c
+EXPECT='-A FORWARD -m comment --comment "rule 1" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "insert referencing replaced rule" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment replacement -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "rule 3" -j ACCEPT'
8cce6c
+
8cce6c
+diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
8cce6c
diff --git a/iptables/tests/shell/testcases/iptables/0005-rule-replace_0 b/iptables/tests/shell/testcases/iptables/0005-rule-replace_0
8cce6c
new file mode 100755
8cce6c
index 0000000000000..5a3e922e50672
8cce6c
--- /dev/null
8cce6c
+++ b/iptables/tests/shell/testcases/iptables/0005-rule-replace_0
8cce6c
@@ -0,0 +1,38 @@
8cce6c
+#!/bin/bash
8cce6c
+
8cce6c
+# test rule replacement
8cce6c
+
8cce6c
+set -e
8cce6c
+
8cce6c
+# show rules, drop uninteresting policy settings
8cce6c
+ipt_show() {
8cce6c
+	$XT_MULTI iptables -S | grep -v '^-P'
8cce6c
+}
8cce6c
+
8cce6c
+$XT_MULTI iptables -A FORWARD -m comment --comment "rule 1" -j ACCEPT
8cce6c
+$XT_MULTI iptables -A FORWARD -m comment --comment "rule 2" -j ACCEPT
8cce6c
+$XT_MULTI iptables -A FORWARD -m comment --comment "rule 3" -j ACCEPT
8cce6c
+
8cce6c
+$XT_MULTI iptables -R FORWARD 2 -m comment --comment "replaced 2" -j ACCEPT
8cce6c
+
8cce6c
+EXPECT='-A FORWARD -m comment --comment "rule 1" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "replaced 2" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "rule 3" -j ACCEPT'
8cce6c
+
8cce6c
+diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
8cce6c
+
8cce6c
+$XT_MULTI iptables -R FORWARD 1 -m comment --comment "replaced 1" -j ACCEPT
8cce6c
+
8cce6c
+EXPECT='-A FORWARD -m comment --comment "replaced 1" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "replaced 2" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "rule 3" -j ACCEPT'
8cce6c
+
8cce6c
+diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
8cce6c
+
8cce6c
+$XT_MULTI iptables -R FORWARD 3 -m comment --comment "replaced 3" -j ACCEPT
8cce6c
+
8cce6c
+EXPECT='-A FORWARD -m comment --comment "replaced 1" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "replaced 2" -j ACCEPT
8cce6c
+-A FORWARD -m comment --comment "replaced 3" -j ACCEPT'
8cce6c
+
8cce6c
+diff -u -Z <(echo -e "$EXPECT") <(ipt_show)
8cce6c
-- 
1dc35b
2.21.0
8cce6c