Blame SOURCES/0018-ipXtables-Avoid-inserting-rules-with-index.patch

24f428
From 256b70dfaaa027a961205b08cd671f1fccf9b663 Mon Sep 17 00:00:00 2001
24f428
From: Eric Garver <eric@garver.life>
24f428
Date: Thu, 10 Jan 2019 13:02:34 -0500
24f428
Subject: [PATCH 18/23] ipXtables: Avoid inserting rules with index
24f428
24f428
iptables-restore (nftables) has a bug in which inserting by index
24f428
doesn't always work as expected. Rules may be inserted at the wrong
24f428
index. We can mostly avoid this by appending rules. This actually
24f428
simplifies things because we don't have to count indexes. Ref rhbz
24f428
1647925.
24f428
24f428
(cherry picked from commit 9f0eb929c240211d3da978732a9f6930da71486c)
24f428
---
24f428
 src/firewall/core/fw_direct.py |   5 +-
24f428
 src/firewall/core/ipXtables.py | 256 ++++++++++++++++-----------------
24f428
 2 files changed, 132 insertions(+), 129 deletions(-)
24f428
24f428
diff --git a/src/firewall/core/fw_direct.py b/src/firewall/core/fw_direct.py
24f428
index 94196e8a41fa..e53a72e3326a 100644
24f428
--- a/src/firewall/core/fw_direct.py
24f428
+++ b/src/firewall/core/fw_direct.py
24f428
@@ -181,7 +181,10 @@ class FirewallDirect(object):
24f428
     def _check_builtin_chain(self, ipv, table, chain):
24f428
         if ipv in ['ipv4', 'ipv6']:
24f428
             built_in_chains = ipXtables.BUILT_IN_CHAINS[table]
24f428
-            our_chains = ipXtables.OUR_CHAINS[table]
24f428
+            if self._fw.nftables_enabled:
24f428
+                our_chains = {}
24f428
+            else:
24f428
+                our_chains = self._fw.get_direct_backend_by_ipv(ipv).our_chains[table]
24f428
         else:
24f428
             built_in_chains = ebtables.BUILT_IN_CHAINS[table]
24f428
             our_chains = ebtables.OUR_CHAINS[table]
24f428
diff --git a/src/firewall/core/ipXtables.py b/src/firewall/core/ipXtables.py
24f428
index 2bd8cc20dc7b..4f04ac41f6a0 100644
24f428
--- a/src/firewall/core/ipXtables.py
24f428
+++ b/src/firewall/core/ipXtables.py
24f428
@@ -49,106 +49,6 @@ ICMP = {
24f428
     "ipv6": "ipv6-icmp",
24f428
 }
24f428
 
24f428
-DEFAULT_RULES = { }
24f428
-LOG_RULES = { }
24f428
-OUR_CHAINS = {} # chains created by firewalld
24f428
-
24f428
-DEFAULT_RULES["security"] = [ ]
24f428
-OUR_CHAINS["security"] = set()
24f428
-for chain in BUILT_IN_CHAINS["security"]:
24f428
-    DEFAULT_RULES["security"].append("-N %s_direct" % chain)
24f428
-    DEFAULT_RULES["security"].append("-I %s 1 -j %s_direct" % (chain, chain))
24f428
-    OUR_CHAINS["security"].add("%s_direct" % chain)
24f428
-
24f428
-DEFAULT_RULES["raw"] = [ ]
24f428
-OUR_CHAINS["raw"] = set()
24f428
-for chain in BUILT_IN_CHAINS["raw"]:
24f428
-    DEFAULT_RULES["raw"].append("-N %s_direct" % chain)
24f428
-    DEFAULT_RULES["raw"].append("-I %s 1 -j %s_direct" % (chain, chain))
24f428
-    OUR_CHAINS["raw"].add("%s_direct" % chain)
24f428
-
24f428
-    if chain == "PREROUTING":
24f428
-        DEFAULT_RULES["raw"].append("-N %s_ZONES_SOURCE" % chain)
24f428
-        DEFAULT_RULES["raw"].append("-N %s_ZONES" % chain)
24f428
-        DEFAULT_RULES["raw"].append("-I %s 2 -j %s_ZONES_SOURCE" % (chain, chain))
24f428
-        DEFAULT_RULES["raw"].append("-I %s 3 -j %s_ZONES" % (chain, chain))
24f428
-        OUR_CHAINS["raw"].update(set(["%s_ZONES_SOURCE" % chain, "%s_ZONES" % chain]))
24f428
-
24f428
-DEFAULT_RULES["mangle"] = [ ]
24f428
-OUR_CHAINS["mangle"] = set()
24f428
-for chain in BUILT_IN_CHAINS["mangle"]:
24f428
-    DEFAULT_RULES["mangle"].append("-N %s_direct" % chain)
24f428
-    DEFAULT_RULES["mangle"].append("-I %s 1 -j %s_direct" % (chain, chain))
24f428
-    OUR_CHAINS["mangle"].add("%s_direct" % chain)
24f428
-
24f428
-    if chain == "PREROUTING":
24f428
-        DEFAULT_RULES["mangle"].append("-N %s_ZONES_SOURCE" % chain)
24f428
-        DEFAULT_RULES["mangle"].append("-N %s_ZONES" % chain)
24f428
-        DEFAULT_RULES["mangle"].append("-I %s 2 -j %s_ZONES_SOURCE" % (chain, chain))
24f428
-        DEFAULT_RULES["mangle"].append("-I %s 3 -j %s_ZONES" % (chain, chain))
24f428
-        OUR_CHAINS["mangle"].update(set(["%s_ZONES_SOURCE" % chain, "%s_ZONES" % chain]))
24f428
-
24f428
-DEFAULT_RULES["nat"] = [ ]
24f428
-OUR_CHAINS["nat"] = set()
24f428
-for chain in BUILT_IN_CHAINS["nat"]:
24f428
-    DEFAULT_RULES["nat"].append("-N %s_direct" % chain)
24f428
-    DEFAULT_RULES["nat"].append("-I %s 1 -j %s_direct" % (chain, chain))
24f428
-    OUR_CHAINS["nat"].add("%s_direct" % chain)
24f428
-
24f428
-    if chain in [ "PREROUTING", "POSTROUTING" ]:
24f428
-        DEFAULT_RULES["nat"].append("-N %s_ZONES_SOURCE" % chain)
24f428
-        DEFAULT_RULES["nat"].append("-N %s_ZONES" % chain)
24f428
-        DEFAULT_RULES["nat"].append("-I %s 2 -j %s_ZONES_SOURCE" % (chain, chain))
24f428
-        DEFAULT_RULES["nat"].append("-I %s 3 -j %s_ZONES" % (chain, chain))
24f428
-        OUR_CHAINS["nat"].update(set(["%s_ZONES_SOURCE" % chain, "%s_ZONES" % chain]))
24f428
-
24f428
-DEFAULT_RULES["filter"] = [
24f428
-    "-N INPUT_direct",
24f428
-    "-N INPUT_ZONES_SOURCE",
24f428
-    "-N INPUT_ZONES",
24f428
-
24f428
-    "-I INPUT 1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT",
24f428
-    "-I INPUT 2 -i lo -j ACCEPT",
24f428
-    "-I INPUT 3 -j INPUT_direct",
24f428
-    "-I INPUT 4 -j INPUT_ZONES_SOURCE",
24f428
-    "-I INPUT 5 -j INPUT_ZONES",
24f428
-    "-I INPUT 6 -m conntrack --ctstate INVALID -j DROP",
24f428
-    "-I INPUT 7 -j %%REJECT%%",
24f428
-
24f428
-    "-N FORWARD_direct",
24f428
-    "-N FORWARD_IN_ZONES_SOURCE",
24f428
-    "-N FORWARD_IN_ZONES",
24f428
-    "-N FORWARD_OUT_ZONES_SOURCE",
24f428
-    "-N FORWARD_OUT_ZONES",
24f428
-
24f428
-    "-I FORWARD 1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT",
24f428
-    "-I FORWARD 2 -i lo -j ACCEPT",
24f428
-    "-I FORWARD 3 -j FORWARD_direct",
24f428
-    "-I FORWARD 4 -j FORWARD_IN_ZONES_SOURCE",
24f428
-    "-I FORWARD 5 -j FORWARD_IN_ZONES",
24f428
-    "-I FORWARD 6 -j FORWARD_OUT_ZONES_SOURCE",
24f428
-    "-I FORWARD 7 -j FORWARD_OUT_ZONES",
24f428
-    "-I FORWARD 8 -m conntrack --ctstate INVALID -j DROP",
24f428
-    "-I FORWARD 9 -j %%REJECT%%",
24f428
-
24f428
-    "-N OUTPUT_direct",
24f428
-
24f428
-    "-I OUTPUT 1 -j OUTPUT_direct",
24f428
-]
24f428
-
24f428
-LOG_RULES["filter"] = [
24f428
-    "-I INPUT 6 -m conntrack --ctstate INVALID %%LOGTYPE%% -j LOG --log-prefix 'STATE_INVALID_DROP: '",
24f428
-    "-I INPUT 8 %%LOGTYPE%% -j LOG --log-prefix 'FINAL_REJECT: '",
24f428
-
24f428
-    "-I FORWARD 8 -m conntrack --ctstate INVALID %%LOGTYPE%% -j LOG --log-prefix 'STATE_INVALID_DROP: '",
24f428
-    "-I FORWARD 10 %%LOGTYPE%% -j LOG --log-prefix 'FINAL_REJECT: '",
24f428
-]
24f428
-
24f428
-OUR_CHAINS["filter"] = set(["INPUT_direct", "INPUT_ZONES_SOURCE", "INPUT_ZONES",
24f428
-                            "FORWARD_direct", "FORWARD_IN_ZONES_SOURCE",
24f428
-                            "FORWARD_IN_ZONES", "FORWARD_OUT_ZONES_SOURCE",
24f428
-                            "FORWARD_OUT_ZONES", "OUTPUT_direct"])
24f428
-
24f428
 # ipv ebtables also uses this
24f428
 #
24f428
 def common_reverse_rule(args):
24f428
@@ -275,6 +175,7 @@ class ip4tables(object):
24f428
         self.restore_wait_option = self._detect_restore_wait_option()
24f428
         self.fill_exists()
24f428
         self.available_tables = []
24f428
+        self.our_chains = {} # chains created by firewalld
24f428
 
24f428
     def fill_exists(self):
24f428
         self.command_exists = os.path.exists(self._command)
24f428
@@ -602,20 +503,117 @@ class ip4tables(object):
24f428
         return []
24f428
 
24f428
     def build_default_rules(self, log_denied="off"):
24f428
-        default_rules = []
24f428
-        for table in DEFAULT_RULES:
24f428
+        default_rules = {}
24f428
+
24f428
+        default_rules["security"] = [ ]
24f428
+        self.our_chains["security"] = set()
24f428
+        for chain in BUILT_IN_CHAINS["security"]:
24f428
+            default_rules["security"].append("-N %s_direct" % chain)
24f428
+            default_rules["security"].append("-A %s -j %s_direct" % (chain, chain))
24f428
+            self.our_chains["security"].add("%s_direct" % chain)
24f428
+
24f428
+        default_rules["raw"] = [ ]
24f428
+        self.our_chains["raw"] = set()
24f428
+        for chain in BUILT_IN_CHAINS["raw"]:
24f428
+            default_rules["raw"].append("-N %s_direct" % chain)
24f428
+            default_rules["raw"].append("-A %s -j %s_direct" % (chain, chain))
24f428
+            self.our_chains["raw"].add("%s_direct" % chain)
24f428
+
24f428
+            if chain == "PREROUTING":
24f428
+                default_rules["raw"].append("-N %s_ZONES_SOURCE" % chain)
24f428
+                default_rules["raw"].append("-N %s_ZONES" % chain)
24f428
+                default_rules["raw"].append("-A %s -j %s_ZONES_SOURCE" % (chain, chain))
24f428
+                default_rules["raw"].append("-A %s -j %s_ZONES" % (chain, chain))
24f428
+                self.our_chains["raw"].update(set(["%s_ZONES_SOURCE" % chain, "%s_ZONES" % chain]))
24f428
+
24f428
+        default_rules["mangle"] = [ ]
24f428
+        self.our_chains["mangle"] = set()
24f428
+        for chain in BUILT_IN_CHAINS["mangle"]:
24f428
+            default_rules["mangle"].append("-N %s_direct" % chain)
24f428
+            default_rules["mangle"].append("-A %s -j %s_direct" % (chain, chain))
24f428
+            self.our_chains["mangle"].add("%s_direct" % chain)
24f428
+
24f428
+            if chain == "PREROUTING":
24f428
+                default_rules["mangle"].append("-N %s_ZONES_SOURCE" % chain)
24f428
+                default_rules["mangle"].append("-N %s_ZONES" % chain)
24f428
+                default_rules["mangle"].append("-A %s -j %s_ZONES_SOURCE" % (chain, chain))
24f428
+                default_rules["mangle"].append("-A %s -j %s_ZONES" % (chain, chain))
24f428
+                self.our_chains["mangle"].update(set(["%s_ZONES_SOURCE" % chain, "%s_ZONES" % chain]))
24f428
+
24f428
+        default_rules["nat"] = [ ]
24f428
+        self.our_chains["nat"] = set()
24f428
+        for chain in BUILT_IN_CHAINS["nat"]:
24f428
+            default_rules["nat"].append("-N %s_direct" % chain)
24f428
+            default_rules["nat"].append("-A %s -j %s_direct" % (chain, chain))
24f428
+            self.our_chains["nat"].add("%s_direct" % chain)
24f428
+
24f428
+            if chain in [ "PREROUTING", "POSTROUTING" ]:
24f428
+                default_rules["nat"].append("-N %s_ZONES_SOURCE" % chain)
24f428
+                default_rules["nat"].append("-N %s_ZONES" % chain)
24f428
+                default_rules["nat"].append("-A %s -j %s_ZONES_SOURCE" % (chain, chain))
24f428
+                default_rules["nat"].append("-A %s -j %s_ZONES" % (chain, chain))
24f428
+                self.our_chains["nat"].update(set(["%s_ZONES_SOURCE" % chain, "%s_ZONES" % chain]))
24f428
+
24f428
+        default_rules["filter"] = [
24f428
+            "-N INPUT_direct",
24f428
+            "-N INPUT_ZONES_SOURCE",
24f428
+            "-N INPUT_ZONES",
24f428
+
24f428
+            "-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT",
24f428
+            "-A INPUT -i lo -j ACCEPT",
24f428
+            "-A INPUT -j INPUT_direct",
24f428
+            "-A INPUT -j INPUT_ZONES_SOURCE",
24f428
+            "-A INPUT -j INPUT_ZONES",
24f428
+        ]
24f428
+        if log_denied != "off":
24f428
+            default_rules["filter"].append("-A INPUT -m conntrack --ctstate INVALID %%LOGTYPE%% -j LOG --log-prefix 'STATE_INVALID_DROP: '")
24f428
+        default_rules["filter"].append("-A INPUT -m conntrack --ctstate INVALID -j DROP")
24f428
+        if log_denied != "off":
24f428
+            default_rules["filter"].append("-A INPUT %%LOGTYPE%% -j LOG --log-prefix 'FINAL_REJECT: '")
24f428
+        default_rules["filter"].append("-A INPUT -j %%REJECT%%")
24f428
+
24f428
+        default_rules["filter"] += [
24f428
+            "-N FORWARD_direct",
24f428
+            "-N FORWARD_IN_ZONES_SOURCE",
24f428
+            "-N FORWARD_IN_ZONES",
24f428
+            "-N FORWARD_OUT_ZONES_SOURCE",
24f428
+            "-N FORWARD_OUT_ZONES",
24f428
+
24f428
+            "-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT",
24f428
+            "-A FORWARD -i lo -j ACCEPT",
24f428
+            "-A FORWARD -j FORWARD_direct",
24f428
+            "-A FORWARD -j FORWARD_IN_ZONES_SOURCE",
24f428
+            "-A FORWARD -j FORWARD_IN_ZONES",
24f428
+            "-A FORWARD -j FORWARD_OUT_ZONES_SOURCE",
24f428
+            "-A FORWARD -j FORWARD_OUT_ZONES",
24f428
+        ]
24f428
+        if log_denied != "off":
24f428
+            default_rules["filter"].append("-A FORWARD -m conntrack --ctstate INVALID %%LOGTYPE%% -j LOG --log-prefix 'STATE_INVALID_DROP: '")
24f428
+        default_rules["filter"].append("-A FORWARD -m conntrack --ctstate INVALID -j DROP")
24f428
+        if log_denied != "off":
24f428
+            default_rules["filter"].append("-A FORWARD %%LOGTYPE%% -j LOG --log-prefix 'FINAL_REJECT: '")
24f428
+        default_rules["filter"].append("-A FORWARD -j %%REJECT%%")
24f428
+
24f428
+        default_rules["filter"] += [
24f428
+            "-N OUTPUT_direct",
24f428
+
24f428
+            "-A OUTPUT -o lo -j ACCEPT",
24f428
+            "-A OUTPUT -j OUTPUT_direct",
24f428
+        ]
24f428
+
24f428
+        self.our_chains["filter"] = set(["INPUT_direct", "INPUT_ZONES_SOURCE", "INPUT_ZONES",
24f428
+                                    "FORWARD_direct", "FORWARD_IN_ZONES_SOURCE",
24f428
+                                    "FORWARD_IN_ZONES", "FORWARD_OUT_ZONES_SOURCE",
24f428
+                                    "FORWARD_OUT_ZONES", "OUTPUT_direct"])
24f428
+
24f428
+        final_default_rules = []
24f428
+        for table in default_rules:
24f428
             if table not in self.get_available_tables():
24f428
                 continue
24f428
-            _default_rules = DEFAULT_RULES[table][:]
24f428
-            if log_denied != "off" and table in LOG_RULES:
24f428
-                _default_rules.extend(LOG_RULES[table])
24f428
-            prefix = [ "-t", table ]
24f428
-            for rule in _default_rules:
24f428
-                if type(rule) == list:
24f428
-                    default_rules.append(prefix + rule)
24f428
-                else:
24f428
-                    default_rules.append(prefix + splitArgs(rule))
24f428
-        return default_rules
24f428
+            for rule in default_rules[table]:
24f428
+                final_default_rules.append(["-t", table] + splitArgs(rule))
24f428
+
24f428
+        return final_default_rules
24f428
 
24f428
     def get_zone_table_chains(self, table):
24f428
         if table == "filter":
24f428
@@ -709,7 +707,7 @@ class ip4tables(object):
24f428
     def build_zone_chain_rules(self, zone, table, chain):
24f428
         _zone = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS[chain], zone=zone)
24f428
 
24f428
-        OUR_CHAINS[table].update(set([_zone,
24f428
+        self.our_chains[table].update(set([_zone,
24f428
                                       "%s_log" % _zone,
24f428
                                       "%s_deny" % _zone,
24f428
                                       "%s_allow" % _zone]))
24f428
@@ -719,33 +717,35 @@ class ip4tables(object):
24f428
         rules.append([ "-N", "%s_log" % _zone, "-t", table ])
24f428
         rules.append([ "-N", "%s_deny" % _zone, "-t", table ])
24f428
         rules.append([ "-N", "%s_allow" % _zone, "-t", table ])
24f428
-        rules.append([ "-I", _zone, "1", "-t", table, "-j", "%s_log" % _zone ])
24f428
-        rules.append([ "-I", _zone, "2", "-t", table, "-j", "%s_deny" % _zone ])
24f428
-        rules.append([ "-I", _zone, "3", "-t", table, "-j", "%s_allow" % _zone ])
24f428
+        rules.append([ "-A", _zone, "-t", table, "-j", "%s_log" % _zone ])
24f428
+        rules.append([ "-A", _zone, "-t", table, "-j", "%s_deny" % _zone ])
24f428
+        rules.append([ "-A", _zone, "-t", table, "-j", "%s_allow" % _zone ])
24f428
 
24f428
-        # Handle trust, block and drop zones:
24f428
-        # Add an additional rule with the zone target (accept, reject
24f428
-        # or drop) to the base zone only in the filter table.
24f428
-        # Otherwise it is not be possible to have a zone with drop
24f428
-        # target, that is allowing traffic that is locally initiated
24f428
-        # or that adds additional rules. (RHBZ#1055190)
24f428
         target = self._fw.zone._zones[zone].target
24f428
-        if table == "filter" and \
24f428
-           target in [ "ACCEPT", "REJECT", "%%REJECT%%", "DROP" ] and \
24f428
-           chain in [ "INPUT", "FORWARD_IN", "FORWARD_OUT", "OUTPUT" ]:
24f428
-            rules.append([ "-I", _zone, "4", "-t", table, "-j", target ])
24f428
 
24f428
         if self._fw.get_log_denied() != "off":
24f428
             if table == "filter" and \
24f428
                chain in [ "INPUT", "FORWARD_IN", "FORWARD_OUT", "OUTPUT" ]:
24f428
                 if target in [ "REJECT", "%%REJECT%%" ]:
24f428
-                    rules.append([ "-I", _zone, "4", "-t", table, "%%LOGTYPE%%",
24f428
+                    rules.append([ "-A", _zone, "-t", table, "%%LOGTYPE%%",
24f428
                                    "-j", "LOG", "--log-prefix",
24f428
                                    "\"%s_REJECT: \"" % _zone ])
24f428
                 if target == "DROP":
24f428
-                    rules.append([ "-I", _zone, "4", "-t", table, "%%LOGTYPE%%",
24f428
+                    rules.append([ "-A", _zone, "-t", table, "%%LOGTYPE%%",
24f428
                                    "-j", "LOG", "--log-prefix",
24f428
                                    "\"%s_DROP: \"" % _zone ])
24f428
+
24f428
+        # Handle trust, block and drop zones:
24f428
+        # Add an additional rule with the zone target (accept, reject
24f428
+        # or drop) to the base zone only in the filter table.
24f428
+        # Otherwise it is not be possible to have a zone with drop
24f428
+        # target, that is allowing traffic that is locally initiated
24f428
+        # or that adds additional rules. (RHBZ#1055190)
24f428
+        if table == "filter" and \
24f428
+           target in [ "ACCEPT", "REJECT", "%%REJECT%%", "DROP" ] and \
24f428
+           chain in [ "INPUT", "FORWARD_IN", "FORWARD_OUT", "OUTPUT" ]:
24f428
+            rules.append([ "-A", _zone, "-t", table, "-j", target ])
24f428
+
24f428
         return rules
24f428
 
24f428
     def _rule_limit(self, limit):
24f428
-- 
24f428
2.20.1
24f428