From 17c660a88d8f340d9acbcaf2a9bede937adb196f Mon Sep 17 00:00:00 2001
From: Nicolas Fort <nicolasfort1988@gmail.com>
Date: Mon, 5 Sep 2022 19:23:52 +0000
Subject: T4670: policy route: extend matching criteria for policy route and
 route6. Matching criteria added: ttl/hoplimit and packet-length

---
 interface-definitions/firewall.xml.in              | 22 +------
 .../include/firewall/hop-limit.xml.i               | 12 ++++
 interface-definitions/include/firewall/ttl.xml.i   | 12 ++++
 interface-definitions/policy-route.xml.in          |  4 ++
 smoketest/scripts/cli/test_policy_route.py         | 68 ++++++++++++++++++++++
 5 files changed, 98 insertions(+), 20 deletions(-)
 create mode 100644 interface-definitions/include/firewall/hop-limit.xml.i
 create mode 100644 interface-definitions/include/firewall/ttl.xml.i

diff --git a/interface-definitions/firewall.xml.in b/interface-definitions/firewall.xml.in
index c2d652278..0ab9d6a66 100644
--- a/interface-definitions/firewall.xml.in
+++ b/interface-definitions/firewall.xml.in
@@ -384,16 +384,7 @@
               </node>
               #include <include/firewall/common-rule.xml.i>
               #include <include/firewall/packet-length.xml.i>
-              <node name="hop-limit">
-                <properties>
-                  <help>Hop Limit</help>
-                </properties>
-                <children>
-                  #include <include/firewall/eq.xml.i>
-                  #include <include/firewall/gt.xml.i>
-                  #include <include/firewall/lt.xml.i>
-                </children>
-              </node>
+              #include <include/firewall/hop-limit.xml.i>
               <node name="icmpv6">
                 <properties>
                   <help>ICMPv6 type and code information</help>
@@ -572,16 +563,7 @@
                   #include <include/firewall/icmp-type-name.xml.i>
                 </children>
               </node>
-              <node name="ttl">
-                <properties>
-                  <help>Time to live limit</help>
-                </properties>
-                <children>
-                  #include <include/firewall/eq.xml.i>
-                  #include <include/firewall/gt.xml.i>
-                  #include <include/firewall/lt.xml.i>
-                </children>
-              </node>
+              #include <include/firewall/ttl.xml.i>
             </children>
           </tagNode>
         </children>
diff --git a/interface-definitions/include/firewall/hop-limit.xml.i b/interface-definitions/include/firewall/hop-limit.xml.i
new file mode 100644
index 000000000..d375dc985
--- /dev/null
+++ b/interface-definitions/include/firewall/hop-limit.xml.i
@@ -0,0 +1,12 @@
+<!-- include start from firewall/hop-limit.xml.i -->
+<node name="hop-limit">
+  <properties>
+    <help>Hop limit</help>
+  </properties>
+  <children>
+    #include <include/firewall/eq.xml.i>
+    #include <include/firewall/gt.xml.i>
+    #include <include/firewall/lt.xml.i>
+  </children>
+</node>
+<!-- include end -->
\ No newline at end of file
diff --git a/interface-definitions/include/firewall/ttl.xml.i b/interface-definitions/include/firewall/ttl.xml.i
new file mode 100644
index 000000000..9c782a9a5
--- /dev/null
+++ b/interface-definitions/include/firewall/ttl.xml.i
@@ -0,0 +1,12 @@
+<!-- include start from firewall/ttl.xml.i -->
+<node name="ttl">
+  <properties>
+    <help>Time to live limit</help>
+  </properties>
+  <children>
+    #include <include/firewall/eq.xml.i>
+    #include <include/firewall/gt.xml.i>
+    #include <include/firewall/lt.xml.i>
+  </children>
+</node>
+<!-- include end -->
\ No newline at end of file
diff --git a/interface-definitions/policy-route.xml.in b/interface-definitions/policy-route.xml.in
index c2a9a8d94..ba1371fab 100644
--- a/interface-definitions/policy-route.xml.in
+++ b/interface-definitions/policy-route.xml.in
@@ -47,6 +47,8 @@
                 </children>
               </node>
               #include <include/policy/route-common-rule-ipv6.xml.i>
+              #include <include/firewall/packet-length.xml.i>
+              #include <include/firewall/hop-limit.xml.i>
             </children>
           </tagNode>
         </children>
@@ -96,6 +98,8 @@
                 </children>
               </node>
               #include <include/policy/route-common-rule.xml.i>
+              #include <include/firewall/packet-length.xml.i>
+              #include <include/firewall/ttl.xml.i>
             </children>
           </tagNode>
         </children>
diff --git a/smoketest/scripts/cli/test_policy_route.py b/smoketest/scripts/cli/test_policy_route.py
index 534cfb082..f8406bbe0 100755
--- a/smoketest/scripts/cli/test_policy_route.py
+++ b/smoketest/scripts/cli/test_policy_route.py
@@ -158,5 +158,73 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
             self.assertTrue(matched)
 
 
+    def test_pbr_matching_criteria(self):
+        self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'protocol', 'udp'])
+        self.cli_set(['policy', 'route', 'smoketest', 'rule', '1', 'action', 'drop'])
+        self.cli_set(['policy', 'route', 'smoketest', 'rule', '2', 'protocol', 'tcp'])
+        self.cli_set(['policy', 'route', 'smoketest', 'rule', '2', 'tcp', 'flags', 'syn'])
+        self.cli_set(['policy', 'route', 'smoketest', 'rule', '2', 'tcp', 'flags', 'not', 'ack'])
+        self.cli_set(['policy', 'route', 'smoketest', 'rule', '2', 'set', 'table', table_id])
+        self.cli_set(['policy', 'route', 'smoketest', 'rule', '3', 'source', 'address', '198.51.100.0/24'])
+        self.cli_set(['policy', 'route', 'smoketest', 'rule', '3', 'protocol', 'tcp'])
+        self.cli_set(['policy', 'route', 'smoketest', 'rule', '3', 'destination', 'port', '22'])
+        self.cli_set(['policy', 'route', 'smoketest', 'rule', '3', 'state', 'new', 'enable'])
+        self.cli_set(['policy', 'route', 'smoketest', 'rule', '3', 'ttl', 'gt', '2'])
+        self.cli_set(['policy', 'route', 'smoketest', 'rule', '3', 'set', 'table', table_id])
+        self.cli_set(['policy', 'route', 'smoketest', 'rule', '4', 'protocol', 'icmp'])
+        self.cli_set(['policy', 'route', 'smoketest', 'rule', '4', 'icmp', 'type-name', 'echo-request'])
+        self.cli_set(['policy', 'route', 'smoketest', 'rule', '4', 'packet-length', '128'])
+        self.cli_set(['policy', 'route', 'smoketest', 'rule', '4', 'packet-length', '1024-2048'])
+        self.cli_set(['policy', 'route', 'smoketest', 'rule', '4', 'log', 'enable'])
+        self.cli_set(['policy', 'route', 'smoketest', 'rule', '4', 'set', 'table', table_id])
+
+        self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '1', 'protocol', 'udp'])
+        self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '1', 'action', 'drop'])
+        self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '2', 'protocol', 'tcp'])
+        self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '2', 'tcp', 'flags', 'syn'])
+        self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '2', 'tcp', 'flags', 'not', 'ack'])
+        self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '2', 'set', 'table', table_id])
+        self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '3', 'source', 'address', '2001:db8::0/64'])
+        self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '3', 'protocol', 'tcp'])
+        self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '3', 'destination', 'port', '22'])
+        self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '3', 'state', 'new', 'enable'])
+        self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '3', 'hop-limit', 'gt', '2'])
+        self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '3', 'set', 'table', table_id])
+        self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '4', 'protocol', 'icmpv6'])
+        self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '4', 'icmpv6', 'type', 'echo-request'])
+        self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '4', 'packet-length-exclude', '128'])
+        self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '4', 'packet-length-exclude', '1024-2048'])
+        self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '4', 'log', 'enable'])
+        self.cli_set(['policy', 'route6', 'smoketest6', 'rule', '4', 'set', 'table', table_id])
+
+        self.cli_set(['interfaces', 'ethernet', interface, 'policy', 'route', 'smoketest'])
+        self.cli_set(['interfaces', 'ethernet', interface, 'policy', 'route6', 'smoketest6'])
+
+        self.cli_commit()
+
+        mark_hex = "{0:#010x}".format(table_mark_offset - int(table_id))
+
+        # IPv4
+        nftables_search = [
+            [f'iifname "{interface}"', 'jump VYOS_PBR_smoketest'],
+            ['meta l4proto udp', 'drop'],
+            ['tcp flags & (syn | ack) == syn', 'meta mark set ' + mark_hex],
+            ['ct state { new }', 'tcp dport { 22 }', 'ip saddr 198.51.100.0/24', 'ip ttl > 2', 'meta mark set ' + mark_hex],
+            ['meta l4proto icmp', 'log prefix "[smoketest-4-A]"', 'icmp type echo-request', 'ip length { 128, 1024-2048 }', 'meta mark set ' + mark_hex]
+        ]
+
+        self.verify_nftables(nftables_search, 'ip mangle')
+
+        # IPv6
+        nftables6_search = [
+            [f'iifname "{interface}"', 'jump VYOS_PBR6_smoketest'],
+            ['meta l4proto udp', 'drop'],
+            ['tcp flags & (syn | ack) == syn', 'meta mark set ' + mark_hex],
+            ['ct state { new }', 'tcp dport { 22 }', 'ip6 saddr 2001:db8::/64', 'ip6 hoplimit > 2', 'meta mark set ' + mark_hex],
+            ['meta l4proto ipv6-icmp', 'log prefix "[smoketest6-4-A]"', 'icmpv6 type echo-request', 'ip6 length != { 128, 1024-2048 }', 'meta mark set ' + mark_hex]
+        ]
+
+        self.verify_nftables(nftables6_search, 'ip6 mangle')
+
 if __name__ == '__main__':
     unittest.main(verbosity=2)
-- 
cgit v1.2.3