From 11641f9979d45ae3b519f3220fab68bfd8700be0 Mon Sep 17 00:00:00 2001
From: sarthurdev <965089+sarthurdev@users.noreply.github.com>
Date: Sun, 24 Sep 2023 14:38:12 +0200
Subject: firewall: T5614: Add support for matching on conntrack helper

(cherry picked from commit 81dee963a9ca3224ddbd54767a36efae5851a001)
---
 .../include/firewall/common-rule-inet.xml.i        |  1 +
 .../include/firewall/conntrack-helper.xml.i        | 42 ++++++++++++++++++++++
 python/vyos/firewall.py                            | 14 ++++++++
 smoketest/scripts/cli/test_firewall.py             |  6 +++-
 4 files changed, 62 insertions(+), 1 deletion(-)
 create mode 100644 interface-definitions/include/firewall/conntrack-helper.xml.i

diff --git a/interface-definitions/include/firewall/common-rule-inet.xml.i b/interface-definitions/include/firewall/common-rule-inet.xml.i
index 7a2eb86d4..88c055f52 100644
--- a/interface-definitions/include/firewall/common-rule-inet.xml.i
+++ b/interface-definitions/include/firewall/common-rule-inet.xml.i
@@ -4,6 +4,7 @@
 #include <include/firewall/dscp.xml.i>
 #include <include/firewall/packet-options.xml.i>
 #include <include/firewall/connection-mark.xml.i>
+#include <include/firewall/conntrack-helper.xml.i>
 #include <include/firewall/nft-queue.xml.i>
 <leafNode name="disable">
   <properties>
diff --git a/interface-definitions/include/firewall/conntrack-helper.xml.i b/interface-definitions/include/firewall/conntrack-helper.xml.i
new file mode 100644
index 000000000..ee17f2c61
--- /dev/null
+++ b/interface-definitions/include/firewall/conntrack-helper.xml.i
@@ -0,0 +1,42 @@
+<!-- include start from firewall/conntrack-helper.xml.i -->
+<leafNode name="conntrack-helper">
+  <properties>
+    <help>Match related traffic from conntrack helpers</help>
+    <completionHelp>
+      <list>ftp h323 pptp nfs sip tftp sqlnet</list>
+    </completionHelp>
+    <valueHelp>
+      <format>ftp</format>
+      <description>Related traffic from FTP helper</description>
+    </valueHelp>
+    <valueHelp>
+      <format>h323</format>
+      <description>Related traffic from H.323 helper</description>
+    </valueHelp>
+    <valueHelp>
+      <format>pptp</format>
+      <description>Related traffic from PPTP helper</description>
+    </valueHelp>
+    <valueHelp>
+      <format>nfs</format>
+      <description>Related traffic from NFS helper</description>
+    </valueHelp>
+    <valueHelp>
+      <format>sip</format>
+      <description>Related traffic from SIP helper</description>
+    </valueHelp>
+    <valueHelp>
+      <format>tftp</format>
+      <description>Related traffic from TFTP helper</description>
+    </valueHelp>
+    <valueHelp>
+      <format>sqlnet</format>
+      <description>Related traffic from SQLNet helper</description>
+    </valueHelp>
+    <constraint>
+      <regex>(ftp|h323|pptp|nfs|sip|tftp|sqlnet)</regex>
+    </constraint>
+    <multi/>
+  </properties>
+</leafNode>
+<!-- include end -->
diff --git a/python/vyos/firewall.py b/python/vyos/firewall.py
index 53ff8259e..7de268a00 100644
--- a/python/vyos/firewall.py
+++ b/python/vyos/firewall.py
@@ -95,6 +95,20 @@ def parse_rule(rule_conf, hook, fw_name, rule_id, ip_name):
         if states:
             output.append(f'ct state {{{states}}}')
 
+    if 'conntrack_helper' in rule_conf:
+        helper_map = {'h323': ['RAS', 'Q.931'], 'nfs': ['rpc'], 'sqlnet': ['tns']}
+        helper_out = []
+
+        for helper in rule_conf['conntrack_helper']:
+            if helper in helper_map:
+                helper_out.extend(helper_map[helper])
+            else:
+                helper_out.append(helper)
+
+        if helper_out:
+            helper_str = ','.join(f'"{s}"' for s in helper_out)
+            output.append(f'ct helper {{{helper_str}}}')
+
     if 'connection_status' in rule_conf and rule_conf['connection_status']:
         status = rule_conf['connection_status']
         if status['nat'] == 'destination':
diff --git a/smoketest/scripts/cli/test_firewall.py b/smoketest/scripts/cli/test_firewall.py
index ee6ccb710..925cdd2bb 100755
--- a/smoketest/scripts/cli/test_firewall.py
+++ b/smoketest/scripts/cli/test_firewall.py
@@ -503,12 +503,15 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
         self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '2', 'state', 'invalid', 'enable'])
         self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '3', 'action', 'accept'])
         self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '3', 'state', 'new', 'enable'])
-
         self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '3', 'connection-status', 'nat', 'destination'])
         self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '4', 'action', 'accept'])
         self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '4', 'state', 'new', 'enable'])
         self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '4', 'state', 'established', 'enable'])
         self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '4', 'connection-status', 'nat', 'source'])
+        self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '5', 'action', 'accept'])
+        self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '5', 'state', 'related', 'enable'])
+        self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '5', 'conntrack-helper', 'ftp'])
+        self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '5', 'conntrack-helper', 'pptp'])
 
         self.cli_commit()
 
@@ -517,6 +520,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
             ['ct state invalid', 'reject'],
             ['ct state new', 'ct status dnat', 'accept'],
             ['ct state { established, new }', 'ct status snat', 'accept'],
+            ['ct state related', 'ct helper { "ftp", "pptp" }', 'accept'],
             ['drop', f'comment "{name} default-action drop"']
         ]
 
-- 
cgit v1.2.3