Skip to content

Commit

Permalink
improvement(core): use dict for IMPORT_EXPORT_STRUCTURE
Browse files Browse the repository at this point in the history
Since Python 3.7 (inofficially since 3.6), dictionaries are iterated in
the order of insertion.

That means, we don't need to use a tuple of 2-tuples to keep the type
mapping of the tuple structure. Instead, use a dictionary, which allows
for more convenient uses, at various places.
  • Loading branch information
thom311 authored and erig0 committed Jan 9, 2024
1 parent 37d453c commit 532da53
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 120 deletions.
16 changes: 8 additions & 8 deletions src/firewall/core/io/direct.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,14 @@ def endElement(self, name):
class Direct(IO_Object):
"""Direct class"""

IMPORT_EXPORT_STRUCTURE = (
IMPORT_EXPORT_STRUCTURE = {
# chain: [ ipv, table, [ chain ] ]
("chains", [("", "", "")]), # a(sss)
"chains": [("", "", "")], # a(sss)
# rule: [ ipv, table, chain, [ priority, [ arg ] ] ]
("rules", [("", "", "", 0, [""])]), # a(sssias)
"rules": [("", "", "", 0, [""])], # a(sssias)
# passthrough: [ ipv, [ [ arg ] ] ]
("passthroughs", [("", [""])]), # a(sas)
)
"passthroughs": [("", [""])], # a(sas)
}
DBUS_SIGNATURE = "(a(sss)a(sssias)a(sas))"
PARSER_REQUIRED_ELEMENT_ATTRS = {
"direct": None,
Expand Down Expand Up @@ -153,14 +153,14 @@ def export_config(self):
def import_config(self, conf, all_io_objects):
self.cleanup()
self.check_config(conf)
for i, (element, dummy) in enumerate(self.IMPORT_EXPORT_STRUCTURE):
for i, element in enumerate(self.IMPORT_EXPORT_STRUCTURE):
if element == "chains":
for x in conf[i]:
self.add_chain(*x)
if element == "rules":
elif element == "rules":
for x in conf[i]:
self.add_rule(*x)
if element == "passthroughs":
elif element == "passthroughs":
for x in conf[i]:
self.add_passthrough(*x)

Expand Down
16 changes: 8 additions & 8 deletions src/firewall/core/io/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@


class Helper(IO_Object):
IMPORT_EXPORT_STRUCTURE = (
("version", ""), # s
("short", ""), # s
("description", ""), # s
("family", ""), # s
("module", ""), # s
("ports", [("", "")]), # a(ss)
)
IMPORT_EXPORT_STRUCTURE = {
"version": "", # s
"short": "", # s
"description": "", # s
"family": "", # s
"module": "", # s
"ports": [("", "")], # a(ss)
}
DBUS_SIGNATURE = "(sssssa(ss))"
ADDITIONAL_ALNUM_CHARS = ["-", "."]
PARSER_REQUIRED_ELEMENT_ATTRS = {
Expand Down
12 changes: 6 additions & 6 deletions src/firewall/core/io/icmptype.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@


class IcmpType(IO_Object):
IMPORT_EXPORT_STRUCTURE = (
("version", ""), # s
("short", ""), # s
("description", ""), # s
("destination", [""]), # as
)
IMPORT_EXPORT_STRUCTURE = {
"version": "", # s
"short": "", # s
"description": "", # s
"destination": [""], # as
}
DBUS_SIGNATURE = "(sssas)"
ADDITIONAL_ALNUM_CHARS = ["_", "-"]
PARSER_REQUIRED_ELEMENT_ATTRS = {
Expand Down
62 changes: 29 additions & 33 deletions src/firewall/core/io/io_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

"""Generic io_object handler, io specific check methods."""

import itertools
import xml.sax as sax
import xml.sax.saxutils as saxutils
import copy
Expand All @@ -20,7 +21,7 @@
class IO_Object:
"""Abstract IO_Object as base for icmptype, service and zone"""

IMPORT_EXPORT_STRUCTURE = ()
IMPORT_EXPORT_STRUCTURE = {}
DBUS_SIGNATURE = "()"
ADDITIONAL_ALNUM_CHARS = [] # additional to alnum
PARSER_REQUIRED_ELEMENT_ATTRS = {}
Expand All @@ -34,54 +35,51 @@ def __init__(self):
self.builtin = False

def export_config(self):
ret = []
for x in self.IMPORT_EXPORT_STRUCTURE:
ret.append(copy.deepcopy(getattr(self, x[0])))
return tuple(ret)
return tuple(
copy.deepcopy(getattr(self, key)) for key in self.IMPORT_EXPORT_STRUCTURE
)

@staticmethod
def get_dict_from_tuple_static(IMPORT_EXPORT_STRUCTURE, conf):
conf_dict = {}
for i, value in enumerate(conf):
conf_dict[IMPORT_EXPORT_STRUCTURE[i][0]] = value
return conf_dict
if len(conf) > len(IMPORT_EXPORT_STRUCTURE):
raise errors.BugError(
f"conf tuple has unexpected too many elements ({conf} vs. {list(IMPORT_EXPORT_STRUCTURE)})"
)
return dict(zip(IMPORT_EXPORT_STRUCTURE, conf))

def get_dict_from_tuple(obj, conf):
return IO_Object.get_dict_from_tuple_static(obj.IMPORT_EXPORT_STRUCTURE, conf)

def export_config_dict(self):
conf = {}
type_formats = dict([(x[0], x[1]) for x in self.IMPORT_EXPORT_STRUCTURE])
for key in type_formats:
if (
getattr(self, key)
or isinstance(getattr(self, key), bool)
or isinstance(getattr(self, key), int)
):
conf[key] = copy.deepcopy(getattr(self, key))
for key in self.IMPORT_EXPORT_STRUCTURE:
v = getattr(self, key)
if v or isinstance(v, bool) or isinstance(v, int):
conf[key] = copy.deepcopy(v)
return conf

def export_config_tuple(self, conf_dict=None, length=None):
if conf_dict is None:
conf_dict = self.export_config_dict()

if length is None:
length = len(self.IMPORT_EXPORT_STRUCTURE)
keys = self.IMPORT_EXPORT_STRUCTURE

if length is not None:
keys = tuple(itertools.islice(keys, length))
assert length == len(keys)

conf_list = []
for i in range(length):
key = self.IMPORT_EXPORT_STRUCTURE[i][0]
def _get(self, conf_dict, key):
if key not in conf_dict:
# old API needs the empty elements as well. Grab it from the
# object otherwise we don't know the type.
conf_list.append(copy.deepcopy(getattr(self, key)))
else:
conf_list.append(conf_dict[key])
return tuple(conf_list)
return copy.deepcopy(getattr(self, key))
return conf_dict[key]

return tuple(_get(self, conf_dict, key) for key in keys)

def import_config(self, conf, all_io_objects):
self.check_config(conf, all_io_objects)
for i, (element, dummy) in enumerate(self.IMPORT_EXPORT_STRUCTURE):
for i, element in enumerate(self.IMPORT_EXPORT_STRUCTURE):
if isinstance(conf[i], list):
# remove duplicates without changing the order
_conf = []
Expand Down Expand Up @@ -131,19 +129,17 @@ def check_config(self, conf, all_io_objects={}):
"structure size mismatch %d != %d"
% (len(conf), len(self.IMPORT_EXPORT_STRUCTURE)),
)
conf_dict = {}
for i, (x, y) in enumerate(self.IMPORT_EXPORT_STRUCTURE):
conf_dict[x] = conf[i]
conf_dict = dict(zip(self.IMPORT_EXPORT_STRUCTURE, conf))
self.check_config_dict(conf_dict, all_io_objects)

def check_config_dict(self, conf, all_io_objects):
type_formats = dict([(x[0], x[1]) for x in self.IMPORT_EXPORT_STRUCTURE])
for key in conf:
if key not in [x for (x, y) in self.IMPORT_EXPORT_STRUCTURE]:
type_format = self.IMPORT_EXPORT_STRUCTURE.get(key)
if type_format is None:
raise FirewallError(
errors.INVALID_OPTION, "option '{}' is not valid".format(key)
)
self._check_config_structure(conf[key], type_formats[key])
self._check_config_structure(conf[key], type_format)
self._check_config(conf[key], key, conf, all_io_objects)

def _check_config(self, dummy1, dummy2, dummy3, dummy4):
Expand Down
16 changes: 8 additions & 8 deletions src/firewall/core/io/ipset.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@


class IPSet(IO_Object):
IMPORT_EXPORT_STRUCTURE = (
("version", ""), # s
("short", ""), # s
("description", ""), # s
("type", ""), # s
("options", {"": ""}), # a{ss}
("entries", [""]), # as
)
IMPORT_EXPORT_STRUCTURE = {
"version": "", # s
"short": "", # s
"description": "", # s
"type": "", # s
"options": {"": ""}, # a{ss}
"entries": [""], # as
}
DBUS_SIGNATURE = "(ssssa{ss}as)"
ADDITIONAL_ALNUM_CHARS = ["_", "-", ":", "."]
PARSER_REQUIRED_ELEMENT_ATTRS = {
Expand Down
12 changes: 6 additions & 6 deletions src/firewall/core/io/lockdown_whitelist.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,12 @@ def startElement(self, name, attrs):
class LockdownWhitelist(IO_Object):
"""LockdownWhitelist class"""

IMPORT_EXPORT_STRUCTURE = (
("commands", [""]), # as
("contexts", [""]), # as
("users", [""]), # as
("uids", [0]), # ai
)
IMPORT_EXPORT_STRUCTURE = {
"commands": [""], # as
"contexts": [""], # as
"users": [""], # as
"uids": [0], # ai
}
DBUS_SIGNATURE = "(asasasai)"
ADDITIONAL_ALNUM_CHARS = ["_"]
PARSER_REQUIRED_ELEMENT_ATTRS = {
Expand Down
34 changes: 17 additions & 17 deletions src/firewall/core/io/policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -828,23 +828,23 @@ class Policy(IO_Object):
priority_default = DEFAULT_POLICY_PRIORITY
priority_reserved = [0]

IMPORT_EXPORT_STRUCTURE = (
("version", ""), # s
("short", ""), # s
("description", ""), # s
("target", ""), # s
("services", [""]), # as
("ports", [("", "")]), # a(ss)
("icmp_blocks", [""]), # as
("masquerade", False), # b
("forward_ports", [("", "", "", "")]), # a(ssss)
("rich_rules", [""]), # as
("protocols", [""]), # as
("source_ports", [("", "")]), # a(ss)
("priority", 0), # i
("ingress_zones", [""]), # as
("egress_zones", [""]), # as
)
IMPORT_EXPORT_STRUCTURE = {
"version": "", # s
"short": "", # s
"description": "", # s
"target": "", # s
"services": [""], # as
"ports": [("", "")], # a(ss)
"icmp_blocks": [""], # as
"masquerade": False, # b
"forward_ports": [("", "", "", "")], # a(ssss)
"rich_rules": [""], # as
"protocols": [""], # as
"source_ports": [("", "")], # a(ss)
"priority": 0, # i
"ingress_zones": [""], # as
"egress_zones": [""], # as
}
ADDITIONAL_ALNUM_CHARS = ["_", "-", "/"]
PARSER_REQUIRED_ELEMENT_ATTRS = {
"short": None,
Expand Down
24 changes: 12 additions & 12 deletions src/firewall/core/io/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,18 @@


class Service(IO_Object):
IMPORT_EXPORT_STRUCTURE = (
("version", ""),
("short", ""),
("description", ""),
("ports", [("", "")]),
("modules", [""]),
("destination", {"": ""}),
("protocols", [""]),
("source_ports", [("", "")]),
("includes", [""]),
("helpers", [""]),
)
IMPORT_EXPORT_STRUCTURE = {
"version": "",
"short": "",
"description": "",
"ports": [("", "")],
"modules": [""],
"destination": {"": ""},
"protocols": [""],
"source_ports": [("", "")],
"includes": [""],
"helpers": [""],
}
ADDITIONAL_ALNUM_CHARS = ["_", "-"]
PARSER_REQUIRED_ELEMENT_ATTRS = {
"short": None,
Expand Down
44 changes: 22 additions & 22 deletions src/firewall/core/io/zone.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,27 +44,27 @@ class Zone(IO_Object):
priority_max = 32767
priority_default = DEFAULT_ZONE_PRIORITY

IMPORT_EXPORT_STRUCTURE = (
("version", ""), # s
("short", ""), # s
("description", ""), # s
("UNUSED", False), # b
("target", ""), # s
("services", [""]), # as
("ports", [("", "")]), # a(ss)
("icmp_blocks", [""]), # as
("masquerade", False), # b
("forward_ports", [("", "", "", "")]), # a(ssss)
("interfaces", [""]), # as
("sources", [""]), # as
("rules_str", [""]), # as
("protocols", [""]), # as
("source_ports", [("", "")]), # a(ss)
("icmp_block_inversion", False), # b
("forward", True), # b
("ingress_priority", 0), # i
("egress_priority", 0), # i
)
IMPORT_EXPORT_STRUCTURE = {
"version": "", # s
"short": "", # s
"description": "", # s
"UNUSED": False, # b
"target": "", # s
"services": [""], # as
"ports": [("", "")], # a(ss)
"icmp_blocks": [""], # as
"masquerade": False, # b
"forward_ports": [("", "", "", "")], # a(ssss)
"interfaces": [""], # as
"sources": [""], # as
"rules_str": [""], # as
"protocols": [""], # as
"source_ports": [("", "")], # a(ss)
"icmp_block_inversion": False, # b
"forward": True, # b
"ingress_priority": 0, # i
"egress_priority": 0, # i
}
ADDITIONAL_ALNUM_CHARS = ["_", "-", "/"]
PARSER_REQUIRED_ELEMENT_ATTRS = {
"short": None,
Expand Down Expand Up @@ -114,7 +114,7 @@ class Zone(IO_Object):

@staticmethod
def index_of(element):
for i, (el, dummy) in enumerate(Zone.IMPORT_EXPORT_STRUCTURE):
for i, el in enumerate(Zone.IMPORT_EXPORT_STRUCTURE):
if el == element:
return i
raise FirewallError(errors.UNKNOWN_ERROR, "index_of()")
Expand Down

0 comments on commit 532da53

Please sign in to comment.