summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--interface-definitions/include/firewall/common-rule.xml.i45
-rw-r--r--python/vyos/firewall.py6
-rwxr-xr-xsmoketest/scripts/cli/test_firewall.py39
3 files changed, 90 insertions, 0 deletions
diff --git a/interface-definitions/include/firewall/common-rule.xml.i b/interface-definitions/include/firewall/common-rule.xml.i
index cd80b7e28..6e61de848 100644
--- a/interface-definitions/include/firewall/common-rule.xml.i
+++ b/interface-definitions/include/firewall/common-rule.xml.i
@@ -95,6 +95,51 @@
</constraint>
</properties>
</leafNode>
+<node name="ct-status">
+ <properties>
+ <help>Connection status in conntrack</help>
+ </properties>
+ <children>
+ <leafNode name="dnat">
+ <properties>
+ <help>Set when connection needs DNAT in original direction</help>
+ <completionHelp>
+ <list>enable disable</list>
+ </completionHelp>
+ <valueHelp>
+ <format>enable</format>
+ <description>Enable</description>
+ </valueHelp>
+ <valueHelp>
+ <format>disable</format>
+ <description>Disable</description>
+ </valueHelp>
+ <constraint>
+ <regex>^(enable|disable)$</regex>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="snat">
+ <properties>
+ <help>Set when connection needs SNAT in original direction</help>
+ <completionHelp>
+ <list>enable disable</list>
+ </completionHelp>
+ <valueHelp>
+ <format>enable</format>
+ <description>Enable</description>
+ </valueHelp>
+ <valueHelp>
+ <format>disable</format>
+ <description>Disable</description>
+ </valueHelp>
+ <constraint>
+ <regex>^(enable|disable)$</regex>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+</node>
<leafNode name="protocol">
<properties>
<help>Protocol to match (protocol name, number, or "all")</help>
diff --git a/python/vyos/firewall.py b/python/vyos/firewall.py
index ff8623592..5e11e4332 100644
--- a/python/vyos/firewall.py
+++ b/python/vyos/firewall.py
@@ -49,6 +49,12 @@ def parse_rule(rule_conf, fw_name, rule_id, ip_name):
if states:
output.append(f'ct state {{{states}}}')
+ if 'ct_status' in rule_conf and rule_conf['ct_status']:
+ status = ",".join([s for s, v in rule_conf['ct_status'].items() if v == 'enable'])
+
+ if status:
+ output.append(f'ct status {{{status}}}')
+
if 'protocol' in rule_conf and rule_conf['protocol'] != 'all':
proto = rule_conf['protocol']
operator = ''
diff --git a/smoketest/scripts/cli/test_firewall.py b/smoketest/scripts/cli/test_firewall.py
index 16b020e07..b914d930a 100755
--- a/smoketest/scripts/cli/test_firewall.py
+++ b/smoketest/scripts/cli/test_firewall.py
@@ -162,6 +162,45 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
nftables_output = cmd(f'sudo nft list chain {table} {chain}')
self.assertTrue('jump VYOS_STATE_POLICY' in nftables_output)
+ def test_state_and_status_rules(self):
+ self.cli_set(['firewall', 'name', 'smoketest', 'default-action', 'drop'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'action', 'accept'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'state', 'established', 'enable'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '1', 'state', 'related', 'enable'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '2', 'action', 'reject'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '2', 'state', 'invalid', 'enable'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '3', 'action', 'accept'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '3', 'state', 'new', 'enable'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '3', 'ct-status', 'dnat', 'enable'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '4', 'action', 'accept'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '4', 'state', 'new', 'enable'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '4', 'state', 'established', 'enable'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '4', 'ct-status', 'snat', 'enable'])
+ self.cli_set(['firewall', 'name', 'smoketest', 'rule', '4', 'ct-status', 'dnat', 'enable'])
+
+ self.cli_set(['interfaces', 'ethernet', 'eth0', 'firewall', 'in', 'name', 'smoketest'])
+
+ self.cli_commit()
+
+ nftables_search = [
+ ['iifname "eth0"', 'jump NAME_smoketest'],
+ ['ct state { established, related }', 'return'],
+ ['ct state { invalid }', 'reject'],
+ ['ct state { new }', 'ct status { dnat }', 'return'],
+ ['ct state { established, new }', 'ct status { snat, dnat }', 'return'],
+ ['smoketest default-action', 'drop']
+ ]
+
+ nftables_output = cmd('sudo nft list table ip filter')
+
+ for search in nftables_search:
+ matched = False
+ for line in nftables_output.split("\n"):
+ if all(item in line for item in search):
+ matched = True
+ break
+ self.assertTrue(matched, msg=search)
+
def test_sysfs(self):
for name, conf in sysfs_config.items():
paths = glob(conf['sysfs'])