Blob Blame History Raw
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