summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Fort <nicolasfort1988@gmail.com>2023-12-05 10:36:14 +0000
committerNicolas Fort <nicolasfort1988@gmail.com>2023-12-05 10:44:19 +0000
commit24a1a70596fafdd35d88506159e6cb9cd94e7a66 (patch)
tree7ff0ee8d2bf779ce758ce2b3834d968c987207a8
parent7ec55fca91f2fd606e16325166b96a18dcb3d2c5 (diff)
downloadvyos-1x-24a1a70596fafdd35d88506159e6cb9cd94e7a66.tar.gz
vyos-1x-24a1a70596fafdd35d88506159e6cb9cd94e7a66.zip
T5779: conntrack: Apply fixes to <set system conntrack timeout custom>. Remove what was not working on 1.3, migrate what was working to new syntax and extend feature for ipv6.
-rw-r--r--data/templates/conntrack/nftables-ct.j240
-rw-r--r--interface-definitions/include/conntrack/timeout-custom-protocols.xml.i136
-rw-r--r--interface-definitions/system-conntrack.xml.in144
-rw-r--r--python/vyos/template.py29
-rwxr-xr-xsmoketest/scripts/cli/test_system_conntrack.py44
-rwxr-xr-xsrc/conf_mode/conntrack.py7
-rwxr-xr-xsrc/migration-scripts/conntrack/4-to-559
7 files changed, 406 insertions, 53 deletions
diff --git a/data/templates/conntrack/nftables-ct.j2 b/data/templates/conntrack/nftables-ct.j2
index 1e0fc8065..762a6f693 100644
--- a/data/templates/conntrack/nftables-ct.j2
+++ b/data/templates/conntrack/nftables-ct.j2
@@ -11,20 +11,33 @@ table ip vyos_conntrack {
{% if ignore.ipv4.rule is vyos_defined %}
{% for rule, rule_config in ignore.ipv4.rule.items() %}
# rule-{{ rule }} {{ '- ' ~ rule_config.description if rule_config.description is vyos_defined }}
- {{ rule_config | conntrack_ignore_rule(rule, ipv6=False) }}
+ {{ rule_config | conntrack_rule(rule, 'ignore', ipv6=False) }}
{% endfor %}
{% endif %}
- return
+ return
}
chain VYOS_CT_TIMEOUT {
-{% if timeout.custom.rule is vyos_defined %}
-{% for rule, rule_config in timeout.custom.rule.items() %}
+{% if timeout.custom.ipv4.rule is vyos_defined %}
+{% for rule, rule_config in timeout.custom.ipv4.rule.items() %}
# rule-{{ rule }} {{ '- ' ~ rule_config.description if rule_config.description is vyos_defined }}
+ {{ rule_config | conntrack_rule(rule, 'timeout', ipv6=False) }}
{% endfor %}
{% endif %}
return
}
+{% if timeout.custom.ipv4.rule is vyos_defined %}
+{% for rule, rule_config in timeout.custom.ipv4.rule.items() %}
+ ct timeout ct-timeout-{{ rule }} {
+ l3proto ip;
+{% for protocol, protocol_config in rule_config.protocol.items() %}
+ protocol {{ protocol }};
+ policy = { {{ protocol_config | conntrack_ct_policy() }} }
+{% endfor %}
+ }
+{% endfor %}
+{% endif %}
+
chain PREROUTING {
type filter hook prerouting priority -300; policy accept;
{% if ipv4_firewall_action == 'accept' or ipv4_nat_action == 'accept' %}
@@ -80,20 +93,33 @@ table ip6 vyos_conntrack {
{% if ignore.ipv6.rule is vyos_defined %}
{% for rule, rule_config in ignore.ipv6.rule.items() %}
# rule-{{ rule }} {{ '- ' ~ rule_config.description if rule_config.description is vyos_defined }}
- {{ rule_config | conntrack_ignore_rule(rule, ipv6=True) }}
+ {{ rule_config | conntrack_rule(rule, 'ignore', ipv6=True) }}
{% endfor %}
{% endif %}
return
}
chain VYOS_CT_TIMEOUT {
-{% if timeout.custom.rule is vyos_defined %}
-{% for rule, rule_config in timeout.custom.rule.items() %}
+{% if timeout.custom.ipv6.rule is vyos_defined %}
+{% for rule, rule_config in timeout.custom.ipv6.rule.items() %}
# rule-{{ rule }} {{ '- ' ~ rule_config.description if rule_config.description is vyos_defined }}
+ {{ rule_config | conntrack_rule(rule, 'timeout', ipv6=True) }}
{% endfor %}
{% endif %}
return
}
+{% if timeout.custom.ipv6.rule is vyos_defined %}
+{% for rule, rule_config in timeout.custom.ipv6.rule.items() %}
+ ct timeout ct-timeout-{{ rule }} {
+ l3proto ip;
+{% for protocol, protocol_config in rule_config.protocol.items() %}
+ protocol {{ protocol }};
+ policy = { {{ protocol_config | conntrack_ct_policy() }} }
+{% endfor %}
+ }
+{% endfor %}
+{% endif %}
+
chain PREROUTING {
type filter hook prerouting priority -300; policy accept;
{% if ipv6_firewall_action == 'accept' or ipv6_nat_action == 'accept' %}
diff --git a/interface-definitions/include/conntrack/timeout-custom-protocols.xml.i b/interface-definitions/include/conntrack/timeout-custom-protocols.xml.i
new file mode 100644
index 000000000..e6bff7e4d
--- /dev/null
+++ b/interface-definitions/include/conntrack/timeout-custom-protocols.xml.i
@@ -0,0 +1,136 @@
+<!-- include start from conntrack/timeout-custom-protocols.xml.i -->
+<node name="tcp">
+ <properties>
+ <help>TCP connection timeout options</help>
+ </properties>
+ <children>
+ <leafNode name="close-wait">
+ <properties>
+ <help>TCP CLOSE-WAIT timeout in seconds</help>
+ <valueHelp>
+ <format>u32:1-21474836</format>
+ <description>TCP CLOSE-WAIT timeout in seconds</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-21474836"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="close">
+ <properties>
+ <help>TCP CLOSE timeout in seconds</help>
+ <valueHelp>
+ <format>u32:1-21474836</format>
+ <description>TCP CLOSE timeout in seconds</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-21474836"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="established">
+ <properties>
+ <help>TCP ESTABLISHED timeout in seconds</help>
+ <valueHelp>
+ <format>u32:1-21474836</format>
+ <description>TCP ESTABLISHED timeout in seconds</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-21474836"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="fin-wait">
+ <properties>
+ <help>TCP FIN-WAIT timeout in seconds</help>
+ <valueHelp>
+ <format>u32:1-21474836</format>
+ <description>TCP FIN-WAIT timeout in seconds</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-21474836"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="last-ack">
+ <properties>
+ <help>TCP LAST-ACK timeout in seconds</help>
+ <valueHelp>
+ <format>u32:1-21474836</format>
+ <description>TCP LAST-ACK timeout in seconds</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-21474836"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="syn-recv">
+ <properties>
+ <help>TCP SYN-RECEIVED timeout in seconds</help>
+ <valueHelp>
+ <format>u32:1-21474836</format>
+ <description>TCP SYN-RECEIVED timeout in seconds</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-21474836"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="syn-sent">
+ <properties>
+ <help>TCP SYN-SENT timeout in seconds</help>
+ <valueHelp>
+ <format>u32:1-21474836</format>
+ <description>TCP SYN-SENT timeout in seconds</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-21474836"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="time-wait">
+ <properties>
+ <help>TCP TIME-WAIT timeout in seconds</help>
+ <valueHelp>
+ <format>u32:1-21474836</format>
+ <description>TCP TIME-WAIT timeout in seconds</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-21474836"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+</node>
+<node name="udp">
+ <properties>
+ <help>UDP timeout options</help>
+ </properties>
+ <children>
+ <leafNode name="replied">
+ <properties>
+ <help>Timeout for UDP connection seen in both directions</help>
+ <valueHelp>
+ <format>u32:1-21474836</format>
+ <description>Timeout for UDP connection seen in both directions</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-21474836"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="unreplied">
+ <properties>
+ <help>Timeout for unreplied UDP</help>
+ <valueHelp>
+ <format>u32:1-21474836</format>
+ <description>Timeout for unreplied UDP</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-21474836"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+</node>
+<!-- include end -->
diff --git a/interface-definitions/system-conntrack.xml.in b/interface-definitions/system-conntrack.xml.in
index 4452f1a74..d9504544d 100644
--- a/interface-definitions/system-conntrack.xml.in
+++ b/interface-definitions/system-conntrack.xml.in
@@ -385,58 +385,122 @@
<help>Define custom timeouts per connection</help>
</properties>
<children>
- <tagNode name="rule">
+ <node name="ipv4">
<properties>
- <help>Rule number</help>
- <valueHelp>
- <format>u32:1-999999</format>
- <description>Number of conntrack rule</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 1-999999"/>
- </constraint>
- <constraintErrorMessage>Ignore rule number must be between 1 and 999999</constraintErrorMessage>
+ <help>IPv4 rules</help>
</properties>
<children>
- #include <include/generic-description.xml.i>
- <node name="destination">
- <properties>
- <help>Destination parameters</help>
- </properties>
- <children>
- #include <include/nat-address.xml.i>
- #include <include/nat-port.xml.i>
- </children>
- </node>
- <leafNode name="inbound-interface">
- <properties>
- <help>Interface to ignore connections tracking on</help>
- <completionHelp>
- <list>any</list>
- <script>${vyos_completion_dir}/list_interfaces</script>
- </completionHelp>
- </properties>
- </leafNode>
- #include <include/ip-protocol.xml.i>
- <node name="protocol">
+ <tagNode name="rule">
<properties>
- <help>Customize protocol specific timers, one protocol configuration per rule</help>
+ <help>Rule number</help>
+ <valueHelp>
+ <format>u32:1-999999</format>
+ <description>Number of conntrack rule</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-999999"/>
+ </constraint>
+ <constraintErrorMessage>Ignore rule number must be between 1 and 999999</constraintErrorMessage>
</properties>
<children>
- #include <include/conntrack/timeout-common-protocols.xml.i>
+ #include <include/generic-description.xml.i>
+ <node name="destination">
+ <properties>
+ <help>Destination parameters</help>
+ </properties>
+ <children>
+ #include <include/nat-address.xml.i>
+ #include <include/nat-port.xml.i>
+ </children>
+ </node>
+ <leafNode name="inbound-interface">
+ <properties>
+ <help>Interface to ignore connections tracking on</help>
+ <completionHelp>
+ <list>any</list>
+ <script>${vyos_completion_dir}/list_interfaces</script>
+ </completionHelp>
+ </properties>
+ </leafNode>
+ <node name="protocol">
+ <properties>
+ <help>Customize protocol specific timers, one protocol configuration per rule</help>
+ </properties>
+ <children>
+ #include <include/conntrack/timeout-custom-protocols.xml.i>
+ </children>
+ </node>
+ <node name="source">
+ <properties>
+ <help>Source parameters</help>
+ </properties>
+ <children>
+ #include <include/nat-address.xml.i>
+ #include <include/nat-port.xml.i>
+ </children>
+ </node>
</children>
- </node>
- <node name="source">
+ </tagNode>
+ </children>
+ </node>
+ <node name="ipv6">
+ <properties>
+ <help>IPv6 rules</help>
+ </properties>
+ <children>
+ <tagNode name="rule">
<properties>
- <help>Source parameters</help>
+ <help>Rule number</help>
+ <valueHelp>
+ <format>u32:1-999999</format>
+ <description>Number of conntrack rule</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-999999"/>
+ </constraint>
+ <constraintErrorMessage>Ignore rule number must be between 1 and 999999</constraintErrorMessage>
</properties>
<children>
- #include <include/nat-address.xml.i>
- #include <include/nat-port.xml.i>
+ #include <include/generic-description.xml.i>
+ <node name="destination">
+ <properties>
+ <help>Destination parameters</help>
+ </properties>
+ <children>
+ #include <include/firewall/address-ipv6.xml.i>
+ #include <include/nat-port.xml.i>
+ </children>
+ </node>
+ <leafNode name="inbound-interface">
+ <properties>
+ <help>Interface to ignore connections tracking on</help>
+ <completionHelp>
+ <list>any</list>
+ <script>${vyos_completion_dir}/list_interfaces</script>
+ </completionHelp>
+ </properties>
+ </leafNode>
+ <node name="protocol">
+ <properties>
+ <help>Customize protocol specific timers, one protocol configuration per rule</help>
+ </properties>
+ <children>
+ #include <include/conntrack/timeout-custom-protocols.xml.i>
+ </children>
+ </node>
+ <node name="source">
+ <properties>
+ <help>Source parameters</help>
+ </properties>
+ <children>
+ #include <include/firewall/address-ipv6.xml.i>
+ #include <include/nat-port.xml.i>
+ </children>
+ </node>
</children>
- </node>
+ </tagNode>
</children>
- </tagNode>
+ </node>
</children>
</node>
#include <include/conntrack/timeout-common-protocols.xml.i>
diff --git a/python/vyos/template.py b/python/vyos/template.py
index 1e683b605..0e2663258 100644
--- a/python/vyos/template.py
+++ b/python/vyos/template.py
@@ -664,8 +664,8 @@ def nat_static_rule(rule_conf, rule_id, nat_type):
from vyos.nat import parse_nat_static_rule
return parse_nat_static_rule(rule_conf, rule_id, nat_type)
-@register_filter('conntrack_ignore_rule')
-def conntrack_ignore_rule(rule_conf, rule_id, ipv6=False):
+@register_filter('conntrack_rule')
+def conntrack_rule(rule_conf, rule_id, action, ipv6=False):
ip_prefix = 'ip6' if ipv6 else 'ip'
def_suffix = '6' if ipv6 else ''
output = []
@@ -676,11 +676,15 @@ def conntrack_ignore_rule(rule_conf, rule_id, ipv6=False):
output.append(f'iifname {ifname}')
if 'protocol' in rule_conf:
- proto = rule_conf['protocol']
+ if action != 'timeout':
+ proto = rule_conf['protocol']
+ else:
+ for protocol, protocol_config in rule_conf['protocol'].items():
+ proto = protocol
output.append(f'meta l4proto {proto}')
tcp_flags = dict_search_args(rule_conf, 'tcp', 'flags')
- if tcp_flags:
+ if tcp_flags and action != 'timeout':
from vyos.firewall import parse_tcp_flags
output.append(parse_tcp_flags(tcp_flags))
@@ -743,11 +747,24 @@ def conntrack_ignore_rule(rule_conf, rule_id, ipv6=False):
output.append(f'{proto} {prefix}port {operator} @P_{group_name}')
- output.append('counter notrack')
- output.append(f'comment "ignore-{rule_id}"')
+ if action == 'ignore':
+ output.append('counter notrack')
+ output.append(f'comment "ignore-{rule_id}"')
+ else:
+ output.append(f'counter ct timeout set ct-timeout-{rule_id}')
+ output.append(f'comment "timeout-{rule_id}"')
return " ".join(output)
+@register_filter('conntrack_ct_policy')
+def conntrack_ct_policy(protocol_conf):
+ output = []
+ for item in protocol_conf:
+ item_value = protocol_conf[item]
+ output.append(f'{item}: {item_value}')
+
+ return ", ".join(output)
+
@register_filter('range_to_regex')
def range_to_regex(num_range):
"""Convert range of numbers or list of ranges
diff --git a/smoketest/scripts/cli/test_system_conntrack.py b/smoketest/scripts/cli/test_system_conntrack.py
index 7657ab724..0dbc97d49 100755
--- a/smoketest/scripts/cli/test_system_conntrack.py
+++ b/smoketest/scripts/cli/test_system_conntrack.py
@@ -297,5 +297,49 @@ class TestSystemConntrack(VyOSUnitTestSHIM.TestCase):
self.cli_delete(['firewall'])
+ def test_conntrack_timeout_custom(self):
+
+ self.cli_set(base_path + ['timeout', 'custom', 'ipv4', 'rule', '1', 'source', 'address', '192.0.2.1'])
+ self.cli_set(base_path + ['timeout', 'custom', 'ipv4', 'rule', '1', 'destination', 'address', '192.0.2.2'])
+ self.cli_set(base_path + ['timeout', 'custom', 'ipv4', 'rule', '1', 'destination', 'port', '22'])
+ self.cli_set(base_path + ['timeout', 'custom', 'ipv4', 'rule', '1', 'protocol', 'tcp', 'syn-sent', '77'])
+ self.cli_set(base_path + ['timeout', 'custom', 'ipv4', 'rule', '1', 'protocol', 'tcp', 'close', '88'])
+ self.cli_set(base_path + ['timeout', 'custom', 'ipv4', 'rule', '1', 'protocol', 'tcp', 'established', '99'])
+
+ self.cli_set(base_path + ['timeout', 'custom', 'ipv4', 'rule', '2', 'inbound-interface', 'eth1'])
+ self.cli_set(base_path + ['timeout', 'custom', 'ipv4', 'rule', '2', 'source', 'address', '198.51.100.1'])
+ self.cli_set(base_path + ['timeout', 'custom', 'ipv4', 'rule', '2', 'protocol', 'udp', 'unreplied', '55'])
+
+ self.cli_set(base_path + ['timeout', 'custom', 'ipv6', 'rule', '1', 'source', 'address', '2001:db8::1'])
+ self.cli_set(base_path + ['timeout', 'custom', 'ipv6', 'rule', '1', 'inbound-interface', 'eth2'])
+ self.cli_set(base_path + ['timeout', 'custom', 'ipv6', 'rule', '1', 'protocol', 'tcp', 'time-wait', '22'])
+ self.cli_set(base_path + ['timeout', 'custom', 'ipv6', 'rule', '1', 'protocol', 'tcp', 'last-ack', '33'])
+
+ self.cli_commit()
+
+ nftables_search = [
+ ['ct timeout ct-timeout-1 {'],
+ ['protocol tcp'],
+ ['policy = { syn_sent : 77, established : 99, close : 88 }'],
+ ['ct timeout ct-timeout-2 {'],
+ ['protocol udp'],
+ ['policy = { unreplied : 55 }'],
+ ['chain VYOS_CT_TIMEOUT {'],
+ ['ip saddr 192.0.2.1', 'ip daddr 192.0.2.2', 'tcp dport 22', 'ct timeout set "ct-timeout-1"'],
+ ['iifname "eth1"', 'meta l4proto udp', 'ip saddr 198.51.100.1', 'ct timeout set "ct-timeout-2"']
+ ]
+
+ nftables6_search = [
+ ['ct timeout ct-timeout-1 {'],
+ ['protocol tcp'],
+ ['policy = { last_ack : 33, time_wait : 22 }'],
+ ['chain VYOS_CT_TIMEOUT {'],
+ ['iifname "eth2"', 'meta l4proto tcp', 'ip6 saddr 2001:db8::1', 'ct timeout set "ct-timeout-1"']
+ ]
+
+ self.verify_nftables(nftables_search, 'ip vyos_conntrack')
+ self.verify_nftables(nftables6_search, 'ip6 vyos_conntrack')
+
+ self.cli_delete(['firewall'])
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/conf_mode/conntrack.py b/src/conf_mode/conntrack.py
index 4cece6921..7f6c71440 100755
--- a/src/conf_mode/conntrack.py
+++ b/src/conf_mode/conntrack.py
@@ -159,6 +159,13 @@ def verify(conntrack):
if not group_obj:
Warning(f'{error_group} "{group_name}" has no members!')
+ if dict_search_args(conntrack, 'timeout', 'custom', inet, 'rule') != None:
+ for rule, rule_config in conntrack['timeout']['custom'][inet]['rule'].items():
+ if 'protocol' not in rule_config:
+ raise ConfigError(f'Conntrack custom timeout rule {rule} requires protocol tcp or udp')
+ else:
+ if 'tcp' in rule_config['protocol'] and 'udp' in rule_config['protocol']:
+ raise ConfigError(f'conntrack custom timeout rule {rule} - Cant use both tcp and udp protocol')
return None
def generate(conntrack):
diff --git a/src/migration-scripts/conntrack/4-to-5 b/src/migration-scripts/conntrack/4-to-5
new file mode 100755
index 000000000..d2e5fc5fa
--- /dev/null
+++ b/src/migration-scripts/conntrack/4-to-5
@@ -0,0 +1,59 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# T5779: system conntrack timeout custom
+# Before:
+# Protocols tcp, udp and icmp allowed. When using udp it did not work
+# Only ipv4 custom timeout rules
+# Now:
+# Valid protocols are only tcp or udp.
+# Extend functionality to ipv6 and move ipv4 custom rules to new node:
+# set system conntrack timeout custom [ipv4 | ipv6] rule <rule> ...
+
+from sys import argv
+from sys import exit
+
+from vyos.configtree import ConfigTree
+
+if len(argv) < 2:
+ print("Must specify file name!")
+ exit(1)
+
+file_name = argv[1]
+
+with open(file_name, 'r') as f:
+ config_file = f.read()
+
+base = ['system', 'conntrack']
+config = ConfigTree(config_file)
+
+if not config.exists(base):
+ # Nothing to do
+ exit(0)
+
+if config.exists(base + ['timeout', 'custom', 'rule']):
+ for rule in config.list_nodes(base + ['timeout', 'custom', 'rule']):
+ if config.exists(base + ['timeout', 'custom', 'rule', rule, 'protocol', 'tcp']):
+ config.set(base + ['timeout', 'custom', 'ipv4', 'rule'])
+ config.copy(base + ['timeout', 'custom', 'rule', rule], base + ['timeout', 'custom', 'ipv4', 'rule', rule])
+ config.delete(base + ['timeout', 'custom', 'rule'])
+
+try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+except OSError as e:
+ print("Failed to save the modified config: {}".format(e))
+ exit(1)