Adapted versions of
commit d72384cfc3eba7db5739f83a28f3476b9553c856
Author: Jiri Popelka <jpopelka@redhat.com>
Date: Fri Jul 25 14:12:19 2014 +0200
Check built-in chains in direct chain handling functions. (RHBZ#1120619)
also rename ipXtables/ebtables.CHAINS to BUILT_IN_CHAINS
commit d4c839f838d0772b19d521ff826065e14f9a569d
Author: Jiri Popelka <jpopelka@redhat.com>
Date: Mon Aug 4 15:59:54 2014 +0200
Direct & LockdownWhitelist: clear() -> cleanup()
these were renamed in fb656f53bc
commit fb656f53bc0eac095694ba61af6933632abf0f20
Author: Thomas Woerner <twoerner@redhat.com>
Date: Tue Oct 22 17:21:55 2013 +0200
Fix cleanup and initializations to get leaked memory to 0 at all times
commit 07550d550e618a3040153341eb8218551c3aa776
Author: Jiri Popelka <jpopelka@redhat.com>
Date: Tue Sep 30 16:39:41 2014 +0200
permanent direct: more tests for ipv & table
see also 9139b468e5
commit 9139b468e5ffbe515dfd9892401eadb13a293a0b
Author: Jiri Popelka <jpopelka@redhat.com>
Date: Tue Jul 15 18:21:47 2014 +0200
FirewallDirect: check ipv & table sooner to provide consistent errors
thanks to Jakub Jelen
commit 1a5670befb208018196b4f897fb84033e544f886
Author: Jiri Popelka <jpopelka@redhat.com>
Date: Tue Oct 14 09:46:46 2014 +0200
Rich_Rule.check(): action can't be used with icmp-block/forward-port/masquerade
commit 76751826d97577fe2b41abf8c5448c653df49651
Author: Thomas Woerner <twoerner@redhat.com>
Date: Tue Feb 11 23:34:09 2014 +0100
firewalld: No load failed error for absent direct.xml file
commit 524438c41fae5a0b239d2273871ffe54c61e65de
Author: Thomas Woerner <twoerner@redhat.com>
Date: Tue Jul 7 13:01:12 2015 +0200
fw.py._start: Fix reload with runtime rules, but no direct.xml (RHBZ#1183008)
diff -up firewalld-0.3.9/src/firewall/core/ebtables.py.RHBZ#1183008 firewalld-0.3.9/src/firewall/core/ebtables.py
--- firewalld-0.3.9/src/firewall/core/ebtables.py.RHBZ#1183008 2015-07-07 13:10:10.938698154 +0200
+++ firewalld-0.3.9/src/firewall/core/ebtables.py 2015-07-07 13:10:11.074695768 +0200
@@ -25,7 +25,7 @@ from firewall.core.logger import log
PROC_IPxTABLE_NAMES = {
}
-CHAINS = {
+BUILT_IN_CHAINS = {
"broute": [ "BROUTING" ],
"nat": [ "PREROUTING", "POSTROUTING", "OUTPUT" ],
"filter": [ "INPUT", "OUTPUT", "FORWARD" ],
@@ -60,7 +60,7 @@ class ebtables:
def available_tables(self, table=None):
ret = []
- tables = [ table ] if table else CHAINS.keys()
+ tables = [ table ] if table else BUILT_IN_CHAINS.keys()
for table in tables:
try:
self.__run(["-t", table, "-L"])
@@ -71,7 +71,7 @@ class ebtables:
return ret
def used_tables(self):
- return list(CHAINS.keys())
+ return list(BUILT_IN_CHAINS.keys())
def flush(self):
tables = self.used_tables()
@@ -86,13 +86,13 @@ class ebtables:
if which == "used":
tables = self.used_tables()
else:
- tables = list(CHAINS.keys())
+ tables = list(BUILT_IN_CHAINS.keys())
if "nat" in tables:
tables.remove("nat") # nat can not set policies in nat table
for table in tables:
- for chain in CHAINS[table]:
+ for chain in BUILT_IN_CHAINS[table]:
self.__run([ "-t", table, "-P", chain, policy ])
ebtables_available_tables = ebtables().available_tables()
diff -up firewalld-0.3.9/src/firewall/core/fw_config.py.RHBZ#1183008 firewalld-0.3.9/src/firewall/core/fw_config.py
--- firewalld-0.3.9/src/firewall/core/fw_config.py.RHBZ#1183008 2013-12-03 14:59:48.000000000 +0100
+++ firewalld-0.3.9/src/firewall/core/fw_config.py 2015-07-07 13:13:50.709829789 +0200
@@ -131,7 +131,7 @@ class FirewallConfig:
def update_direct(self):
if not os.path.exists(FIREWALLD_DIRECT):
- self._direct.clear()
+ self._direct.cleanup()
else:
self._direct.read()
diff -up firewalld-0.3.9/src/firewall/core/fw_direct.py.RHBZ#1183008 firewalld-0.3.9/src/firewall/core/fw_direct.py
--- firewalld-0.3.9/src/firewall/core/fw_direct.py.RHBZ#1183008 2015-07-07 13:10:11.072695804 +0200
+++ firewalld-0.3.9/src/firewall/core/fw_direct.py 2015-07-07 13:10:11.075695751 +0200
@@ -132,9 +132,41 @@ class FirewallDirect:
except FirewallError as error:
log.warning(str(error))
+ def _check_ipv(self, ipv):
+ ipvs = ['ipv4', 'ipv6', 'eb']
+ if ipv not in ipvs:
+ raise FirewallError(INVALID_IPV,
+ "'%s' not in '%s'" % (ipv, ipvs))
+
+ def _check_ipv_table(self, ipv, table):
+ self._check_ipv(ipv)
+
+ tables = ipXtables.BUILT_IN_CHAINS.keys() if ipv in [ 'ipv4', 'ipv6' ] \
+ else ebtables.BUILT_IN_CHAINS.keys()
+ if table not in tables:
+ raise FirewallError(INVALID_TABLE,
+ "'%s' not in '%s'" % (table, tables))
+
+ def _check_builtin_chain(self, ipv, table, chain):
+ if ipv in ['ipv4', 'ipv6']:
+ built_in_chains = ipXtables.BUILT_IN_CHAINS[table]
+ our_chains = ipXtables.OUR_CHAINS[table]
+ else:
+ built_in_chains = ebtables.BUILT_IN_CHAINS[table]
+ our_chains = ebtables.OUR_CHAINS[table]
+ if chain in built_in_chains:
+ raise FirewallError(BUILTIN_CHAIN,
+ "chain '%s' is built-in chain" % chain)
+ if chain in our_chains:
+ raise FirewallError(BUILTIN_CHAIN,
+ "chain '%s' is reserved" % chain)
+
+
# DIRECT CHAIN
def __chain(self, add, ipv, table, chain):
+ self._check_ipv_table(ipv, table)
+ self._check_builtin_chain(ipv, table, chain)
table_id = (ipv, table)
if add:
@@ -174,11 +206,14 @@ class FirewallDirect:
self.__chain(False, ipv, table, chain)
def query_chain(self, ipv, table, chain):
+ self._check_ipv_table(ipv, table)
+ self._check_builtin_chain(ipv, table, chain)
table_id = (ipv, table)
- return (table_id in self._chains and \
- chain in self._chains[table_id])
+ return (table_id in self._chains and
+ chain in self._chains[table_id])
def get_chains(self, ipv, table):
+ self._check_ipv_table(ipv, table)
table_id = (ipv, table)
if table_id in self._chains:
return self._chains[table_id]
@@ -195,13 +230,14 @@ class FirewallDirect:
# DIRECT RULE
def __rule(self, enable, ipv, table, chain, priority, args):
+ self._check_ipv_table(ipv, table)
_chain = chain
# use "%s_chain" for built-in chains
if ipv in [ "ipv4", "ipv6" ]:
- _CHAINS = ipXtables.CHAINS
+ _CHAINS = ipXtables.BUILT_IN_CHAINS
else:
- _CHAINS = ebtables.CHAINS
+ _CHAINS = ebtables.BUILT_IN_CHAINS
if table in _CHAINS and chain in _CHAINS[table]:
_chain = "%s_direct" % (chain)
@@ -303,11 +339,13 @@ class FirewallDirect:
self.__rule(False, ipv, table, chain, priority, args)
def query_rule(self, ipv, table, chain, priority, args):
+ self._check_ipv_table(ipv, table)
chain_id = (ipv, table, chain)
return (chain_id in self._rules and \
(priority, args) in self._rules[chain_id])
def get_rules(self, ipv, table, chain):
+ self._check_ipv_table(ipv, table)
chain_id = (ipv, table, chain)
if chain_id in self._rules:
return list(self._rules[chain_id].keys())
@@ -332,12 +370,6 @@ class FirewallDirect:
# DIRECT PASSTHROUGH (tracked)
- def _check_ipv(self, ipv):
- ipvs = [ 'ipv4', 'ipv6', 'eb' ]
- if ipv not in ipvs:
- raise FirewallError(INVALID_IPV,
- "'%s' not in '%s'" % (ipv, ipvs))
-
def __passthrough(self, enable, ipv, args):
self._check_ipv(ipv)
diff -up firewalld-0.3.9/src/firewall/core/fw.py.RHBZ#1183008 firewalld-0.3.9/src/firewall/core/fw.py
--- firewalld-0.3.9/src/firewall/core/fw.py.RHBZ#1183008 2015-07-07 13:10:11.072695804 +0200
+++ firewalld-0.3.9/src/firewall/core/fw.py 2015-07-07 13:10:11.075695751 +0200
@@ -203,15 +203,16 @@ class Firewall:
self.zone.apply_zones()
# load direct rules
- log.debug1("Loading direct rules file '%s'" % FIREWALLD_DIRECT)
obj = Direct(FIREWALLD_DIRECT)
- try:
- obj.read()
- except Exception as msg:
- log.debug1("Failed to load direct rules file '%s': %s",
- FIREWALLD_DIRECT, msg)
- else:
- self.direct.set_permanent_config(obj)
+ if os.path.exists(FIREWALLD_DIRECT):
+ log.debug1("Loading direct rules file '%s'" % FIREWALLD_DIRECT)
+ try:
+ obj.read()
+ except Exception as msg:
+ log.debug1("Failed to load direct rules file '%s': %s",
+ FIREWALLD_DIRECT, msg)
+
+ self.direct.set_permanent_config(obj)
self.config.set_direct(copy.deepcopy(obj))
# check if default_zone is a valid zone
@@ -394,7 +395,7 @@ class Firewall:
rule.pop(1)
table = None
- for t in ipXtables.CHAINS.keys():
+ for t in ipXtables.BUILT_IN_CHAINS.keys():
if t in rule:
table = t
if table and not self.is_table_available(ipv, table):
diff -up firewalld-0.3.9/src/firewall/core/fw_zone.py.RHBZ#1183008 firewalld-0.3.9/src/firewall/core/fw_zone.py
--- firewalld-0.3.9/src/firewall/core/fw_zone.py.RHBZ#1183008 2015-07-07 13:10:11.068695874 +0200
+++ firewalld-0.3.9/src/firewall/core/fw_zone.py 2015-07-07 13:10:11.076695733 +0200
@@ -26,7 +26,8 @@ from firewall.functions import portStr,
checkProtocol, enable_ip_forwarding, check_single_address
from firewall.core.rich import *
from firewall.errors import *
-from firewall.core.ipXtables import ip4tables_available_tables, ip6tables_available_tables
+from firewall.core.ipXtables import ip4tables_available_tables,\
+ ip6tables_available_tables, OUR_CHAINS
mangle = []
if "mangle" in ip4tables_available_tables:
@@ -187,6 +188,10 @@ class FirewallZone:
ipvs.append("ipv6")
for ipv in ipvs:
+ OUR_CHAINS[table].update(set([_zone,
+ "%s_log" % _zone,
+ "%s_deny" % _zone,
+ "%s_allow" % _zone]))
chains.append((ipv, [ _zone, "-t", table ]))
chains.append((ipv, [ "%s_log" % (_zone), "-t", table ]))
chains.append((ipv, [ "%s_deny" % (_zone), "-t", table ]))
diff -up firewalld-0.3.9/src/firewall/core/io/direct.py.RHBZ#1183008 firewalld-0.3.9/src/firewall/core/io/direct.py
--- firewalld-0.3.9/src/firewall/core/io/direct.py.RHBZ#1183008 2015-07-07 13:10:11.030696540 +0200
+++ firewalld-0.3.9/src/firewall/core/io/direct.py 2015-07-07 13:10:11.076695733 +0200
@@ -29,6 +29,9 @@ from firewall.functions import splitArgs
from firewall.errors import *
from firewall.core.io.io_object import *
from firewall.core.logger import log
+from firewall.core import ipXtables
+from firewall.core import ebtables
+
class direct_ContentHandler(IO_Object_ContentHandler):
def __init__(self, item):
@@ -188,9 +191,25 @@ class Direct(IO_Object):
for args in self.passthroughs[key]:
print (" ('%s')" % ("','".join(args)))
+ def _check_ipv(self, ipv):
+ ipvs = ['ipv4', 'ipv6', 'eb']
+ if ipv not in ipvs:
+ raise FirewallError(INVALID_IPV,
+ "'%s' not in '%s'" % (ipv, ipvs))
+
+ def _check_ipv_table(self, ipv, table):
+ self._check_ipv(ipv)
+
+ tables = ipXtables.BUILT_IN_CHAINS.keys() if ipv in ['ipv4', 'ipv6'] \
+ else ebtables.BUILT_IN_CHAINS.keys()
+ if table not in tables:
+ raise FirewallError(INVALID_TABLE,
+ "'%s' not in '%s'" % (table, tables))
+
# chains
def add_chain(self, ipv, table, chain):
+ self._check_ipv_table(ipv, table)
key = (ipv, table)
if key not in self.chains:
self.chains[key] = [ ]
@@ -202,6 +221,7 @@ class Direct(IO_Object):
+ "already in list, ignoring")
def remove_chain(self, ipv, table, chain):
+ self._check_ipv_table(ipv, table)
key = (ipv, table)
if key in self.chains and chain in self.chains[key]:
self.chains[key].remove(chain)
@@ -213,10 +233,12 @@ class Direct(IO_Object):
(chain, table, ipv))
def query_chain(self, ipv, table, chain):
+ self._check_ipv_table(ipv, table)
key = (ipv, table)
return (key in self.chains and chain in self.chains[key])
def get_chains(self, ipv, table):
+ self._check_ipv_table(ipv, table)
key = (ipv, table)
if key in self.chains:
return self.chains[key]
@@ -230,6 +252,7 @@ class Direct(IO_Object):
# rules
def add_rule(self, ipv, table, chain, priority, args):
+ self._check_ipv_table(ipv, table)
key = (ipv, table, chain)
if key not in self.rules:
self.rules[key] = LastUpdatedOrderedDict()
@@ -243,6 +266,7 @@ class Direct(IO_Object):
+ "already in list, ignoring")
def remove_rule(self, ipv, table, chain, priority, args):
+ self._check_ipv_table(ipv, table)
key = (ipv, table, chain)
value = (priority, tuple(args))
if key in self.rules and value in self.rules[key]:
@@ -255,6 +279,7 @@ class Direct(IO_Object):
"with ipv '%s' and priority %d not in list" % (ipv, priority))
def remove_rules(self, ipv, table, chain):
+ self._check_ipv_table(ipv, table)
key = (ipv, table, chain)
if key in self.rules:
for value in self.rules[key].keys():
@@ -263,11 +288,13 @@ class Direct(IO_Object):
del self.rules[key]
def query_rule(self, ipv, table, chain, priority, args):
+ self._check_ipv_table(ipv, table)
key = (ipv, table, chain)
value = (priority, tuple(args))
return (key in self.rules and value in self.rules[key])
def get_rules(self, ipv, table, chain):
+ self._check_ipv_table(ipv, table)
key = (ipv, table, chain)
if key in self.rules:
return self.rules[key]
@@ -281,6 +308,7 @@ class Direct(IO_Object):
# # passthrough
#
def add_passthrough(self, ipv, args):
+ self._check_ipv(ipv)
if ipv not in self.passthroughs:
self.passthroughs[ipv] = [ ]
if args not in self.passthroughs[ipv]:
@@ -291,6 +319,7 @@ class Direct(IO_Object):
+ "already in list, ignoring")
def remove_passthrough(self, ipv, args):
+ self._check_ipv(ipv)
if ipv in self.passthroughs and args in self.passthroughs[ipv]:
self.passthroughs[ipv].remove(args)
if len(self.passthroughs[ipv]) == 0:
@@ -300,9 +329,11 @@ class Direct(IO_Object):
("',".join(args), ipv) + "not in list"
def query_passthrough(self, ipv, args):
+ self._check_ipv(ipv)
return (ipv in self.passthroughs and args in self.passthroughs[ipv])
def get_passthroughs(self, ipv):
+ self._check_ipv(ipv)
if ipv in self.passthroughs:
return self.passthroughs[ipv]
else:
diff -up firewalld-0.3.9/src/firewall/core/ipXtables.py.RHBZ#1183008 firewalld-0.3.9/src/firewall/core/ipXtables.py
--- firewalld-0.3.9/src/firewall/core/ipXtables.py.RHBZ#1183008 2015-07-07 13:10:11.066695909 +0200
+++ firewalld-0.3.9/src/firewall/core/ipXtables.py 2015-07-07 13:10:11.076695733 +0200
@@ -34,7 +34,7 @@ PROC_IPxTABLE_NAMES = {
"ipv6": "/proc/net/ip6_tables_names",
}
-CHAINS = {
+BUILT_IN_CHAINS = {
"security": [ "INPUT", "OUTPUT", "FORWARD" ],
"raw": [ "PREROUTING", "OUTPUT" ],
"mangle": [ "PREROUTING", "POSTROUTING", "INPUT", "OUTPUT", "FORWARD" ],
@@ -53,38 +53,49 @@ ICMP = {
}
DEFAULT_RULES = { }
+OUR_CHAINS = {} # chains created by firewalld
DEFAULT_RULES["security"] = [ ]
-for chain in CHAINS["security"]:
+OUR_CHAINS["security"] = set()
+for chain in BUILT_IN_CHAINS["security"]:
DEFAULT_RULES["security"].append("-N %s_direct" % chain)
DEFAULT_RULES["security"].append("-I %s 1 -j %s_direct" % (chain, chain))
+ OUR_CHAINS["security"].add("%s_direct" % chain)
DEFAULT_RULES["raw"] = [ ]
-for chain in CHAINS["raw"]:
+OUR_CHAINS["raw"] = set()
+for chain in BUILT_IN_CHAINS["raw"]:
DEFAULT_RULES["raw"].append("-N %s_direct" % chain)
DEFAULT_RULES["raw"].append("-I %s 1 -j %s_direct" % (chain, chain))
+ OUR_CHAINS["raw"].add("%s_direct" % chain)
DEFAULT_RULES["mangle"] = [ ]
-for chain in CHAINS["mangle"]:
+OUR_CHAINS["mangle"] = set()
+for chain in BUILT_IN_CHAINS["mangle"]:
DEFAULT_RULES["mangle"].append("-N %s_direct" % chain)
DEFAULT_RULES["mangle"].append("-I %s 1 -j %s_direct" % (chain, chain))
+ OUR_CHAINS["mangle"].add("%s_direct" % chain)
if chain == "PREROUTING":
DEFAULT_RULES["mangle"].append("-N %s_ZONES_SOURCE" % chain)
DEFAULT_RULES["mangle"].append("-N %s_ZONES" % chain)
DEFAULT_RULES["mangle"].append("-I %s 2 -j %s_ZONES_SOURCE" % (chain, chain))
DEFAULT_RULES["mangle"].append("-I %s 3 -j %s_ZONES" % (chain, chain))
+ OUR_CHAINS["mangle"].update(set(["%s_ZONES_SOURCE" % chain, "%s_ZONES" % chain]))
DEFAULT_RULES["nat"] = [ ]
-for chain in CHAINS["nat"]:
+OUR_CHAINS["nat"] = set()
+for chain in BUILT_IN_CHAINS["nat"]:
DEFAULT_RULES["nat"].append("-N %s_direct" % chain)
DEFAULT_RULES["nat"].append("-I %s 1 -j %s_direct" % (chain, chain))
+ OUR_CHAINS["nat"].add("%s_direct" % chain)
if chain in [ "PREROUTING", "POSTROUTING" ]:
DEFAULT_RULES["nat"].append("-N %s_ZONES_SOURCE" % chain)
DEFAULT_RULES["nat"].append("-N %s_ZONES" % chain)
DEFAULT_RULES["nat"].append("-I %s 2 -j %s_ZONES_SOURCE" % (chain, chain))
DEFAULT_RULES["nat"].append("-I %s 3 -j %s_ZONES" % (chain, chain))
+ OUR_CHAINS["nat"].update(set(["%s_ZONES_SOURCE" % chain, "%s_ZONES" % chain]))
DEFAULT_RULES["filter"] = [
"-N INPUT_direct",
@@ -119,6 +130,11 @@ DEFAULT_RULES["filter"] = [
"-I OUTPUT 1 -j OUTPUT_direct",
]
+OUR_CHAINS["filter"] = set(["INPUT_direct", "INPUT_ZONES_SOURCE", "INPUT_ZONES",
+ "FORWARD_direct", "FORWARD_IN_ZONES_SOURCE",
+ "FORWARD_IN_ZONES", "FORWARD_OUT_ZONES_SOURCE",
+ "FORWARD_OUT_ZONES", "OUTPUT_direct"])
+
class ip4tables:
ipv = "ipv4"
@@ -151,7 +167,7 @@ class ip4tables:
def available_tables(self, table=None):
ret = []
- tables = [ table ] if table else CHAINS.keys()
+ tables = [ table ] if table else BUILT_IN_CHAINS.keys()
for table in tables:
try:
self.__run(["-t", table, "-L"])
@@ -199,13 +215,13 @@ class ip4tables:
if which == "used":
tables = self.used_tables()
else:
- tables = list(CHAINS.keys())
+ tables = list(BUILT_IN_CHAINS.keys())
if "nat" in tables:
tables.remove("nat") # nat can not set policies in nat table
for table in tables:
- for chain in CHAINS[table]:
+ for chain in BUILT_IN_CHAINS[table]:
self.__run([ "-t", table, "-P", chain, policy ])
class ip6tables(ip4tables):
diff -up firewalld-0.3.9/src/firewall/core/rich.py.RHBZ#1183008 firewalld-0.3.9/src/firewall/core/rich.py
--- firewalld-0.3.9/src/firewall/core/rich.py.RHBZ#1183008 2015-07-07 13:10:11.070695839 +0200
+++ firewalld-0.3.9/src/firewall/core/rich.py 2015-07-07 13:10:11.076695733 +0200
@@ -481,6 +481,8 @@ class Rich_Rule(object):
elif type(self.element) == Rich_Masquerade:
if self.destination != None:
raise FirewallError(INVALID_RULE, "masquerade and destination")
+ if self.action:
+ raise FirewallError(INVALID_RULE, "masquerade and action")
# icmp-block
elif type(self.element) == Rich_IcmpBlock:
@@ -488,8 +490,8 @@ class Rich_Rule(object):
# knowledge about this, therefore only simple check
if self.element.name == None or len(self.element.name) < 1:
raise FirewallError(INVALID_ICMPTYPE, str(self.element.name))
- if self.action and type(self.action) == Rich_Accept:
- raise FirewallError(INVALID_RULE, "icmpblock and accept")
+ if self.action:
+ raise FirewallError(INVALID_RULE, "icmp-block and action")
# forward-port
elif type(self.element) == Rich_ForwardPort:
@@ -508,6 +510,8 @@ class Rich_Rule(object):
raise FirewallError(INVALID_ADDR, self.element.to_address)
if self.family == None:
raise FirewallError(INVALID_FAMILY)
+ if self.action:
+ raise FirewallError(INVALID_RULE, "forward-port and action")
# other element and not empty?
elif self.element != None: