diff options
-rw-r--r-- | interface-definitions/include/firewall/common-rule.xml.i | 45 | ||||
-rw-r--r-- | python/vyos/firewall.py | 6 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_firewall.py | 39 |
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']) |