From fb83f0f12e3ce0a972943b2e087375986983e959 Mon Sep 17 00:00:00 2001
From: Eric Garver <e@erig.me>
Date: Thu, 18 Oct 2018 16:26:54 -0400
Subject: [PATCH 19/34] rich: add support for rule priorities
(cherry picked from commit aeac75088ef2263a7a91c52956c914e69bee8a4b)
---
src/firewall/core/io/zone.py | 9 +++++++--
src/firewall/core/rich.py | 19 +++++++++++++++++--
src/firewall/errors.py | 1 +
3 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/src/firewall/core/io/zone.py b/src/firewall/core/io/zone.py
index 05368e9c73eb..68b2a7c9567c 100644
--- a/src/firewall/core/io/zone.py
+++ b/src/firewall/core/io/zone.py
@@ -88,7 +88,7 @@ class Zone(IO_Object):
"zone": [ "name", "immutable", "target", "version" ],
"masquerade": [ "enabled" ],
"forward-port": [ "to-port", "to-addr" ],
- "rule": [ "family" ],
+ "rule": [ "family", "priority" ],
"source": [ "address", "mac", "invert", "family", "ipset" ],
"destination": [ "invert" ],
"log": [ "prefix", "level" ],
@@ -627,6 +627,7 @@ class zone_ContentHandler(IO_Object_ContentHandler):
elif name == "rule":
family = None
+ priority = 0
if "family" in attrs:
family = attrs["family"]
if family not in [ "ipv4", "ipv6" ]:
@@ -634,7 +635,9 @@ class zone_ContentHandler(IO_Object_ContentHandler):
attrs["family"])
self._rule_error = True
return
- self._rule = rich.Rich_Rule(family)
+ if "priority" in attrs:
+ priority = int(attrs["priority"])
+ self._rule = rich.Rich_Rule(family=family, priority=priority)
elif name == "limit":
if not self._limit_ok:
@@ -834,6 +837,8 @@ def zone_writer(zone, path=None):
attrs = { }
if rule.family:
attrs["family"] = rule.family
+ if rule.priority != 0:
+ attrs["priority"] = str(rule.priority)
handler.ignorableWhitespace(" ")
handler.startElement("rule", attrs)
handler.ignorableWhitespace("\n")
diff --git a/src/firewall/core/rich.py b/src/firewall/core/rich.py
index 04791da612a2..c415bf39212f 100644
--- a/src/firewall/core/rich.py
+++ b/src/firewall/core/rich.py
@@ -266,12 +266,16 @@ class Rich_Limit(object):
return ''
class Rich_Rule(object):
- def __init__(self, family=None, rule_str=None):
+ priority_min = -32768
+ priority_max = 32767
+
+ def __init__(self, family=None, rule_str=None, priority=0):
if family is not None:
self.family = str(family)
else:
self.family = None
+ self.priority = priority
self.source = None
self.destination = None
self.element = None
@@ -303,6 +307,7 @@ class Rich_Rule(object):
if not rule_str:
raise FirewallError(errors.INVALID_RULE, 'empty rule')
+ self.priority = 0
self.family = None
self.source = None
self.destination = None
@@ -325,7 +330,7 @@ class Rich_Rule(object):
#print ("in_elements: ", in_elements)
#print ("index: %s, element: %s, attribute: %s=%s" % (index, element, attr_name, attr_value))
if attr_name: # attribute
- if attr_name not in ['family', 'address', 'mac', 'ipset',
+ if attr_name not in ['priority', 'family', 'address', 'mac', 'ipset',
'invert', 'value',
'port', 'protocol', 'to-port', 'to-addr',
'name', 'prefix', 'level', 'type',
@@ -360,6 +365,8 @@ class Rich_Rule(object):
if not element and attr_name:
if attr_name == 'family':
raise FirewallError(errors.INVALID_RULE, "'family' outside of rule. Use 'rule family=...'.")
+ elif attr_name == 'priority':
+ raise FirewallError(errors.INVALID_RULE, "'priority' outside of rule. Use 'rule priority=...'.")
else:
raise FirewallError(errors.INVALID_RULE, "'%s' outside of any element. Use 'rule <element> %s= ...'." % (attr_name, attr_name))
elif 'rule' not in element:
@@ -371,6 +378,8 @@ class Rich_Rule(object):
if attr_value not in ['ipv4', 'ipv6']:
raise FirewallError(errors.INVALID_RULE, "'family' attribute cannot have '%s' value. Use 'ipv4' or 'ipv6' instead." % attr_value)
self.family = attr_value
+ elif attr_name == 'priority':
+ self.priority = int(attr_value)
elif attr_name:
if attr_name == 'protocol':
err_msg = "wrong 'protocol' usage. Use either 'rule protocol value=...' or 'rule [forward-]port protocol=...'."
@@ -528,6 +537,10 @@ class Rich_Rule(object):
if type(self.element) == Rich_ForwardPort:
raise FirewallError(errors.MISSING_FAMILY)
+ if self.priority < self.priority_min or self.priority > self.priority_max:
+ raise FirewallError(errors.INVALID_PRIORITY, "'priority' attribute must be between %d and %d." \
+ % (self.priority_min, self.priority_max))
+
if self.element is None:
if self.action is None:
raise FirewallError(errors.INVALID_RULE, "no element, no action")
@@ -679,6 +692,8 @@ class Rich_Rule(object):
def __str__(self):
ret = 'rule'
+ if self.priority:
+ ret += ' priority="%d"' % self.priority
if self.family:
ret += ' family="%s"' % self.family
if self.source:
diff --git a/src/firewall/errors.py b/src/firewall/errors.py
index a48038028f25..4589f60848b9 100644
--- a/src/firewall/errors.py
+++ b/src/firewall/errors.py
@@ -87,6 +87,7 @@ INVALID_IPSET = 135
INVALID_ENTRY = 136
INVALID_OPTION = 137
INVALID_HELPER = 138
+INVALID_PRIORITY = 139
MISSING_TABLE = 200
MISSING_CHAIN = 201
--
2.18.0