summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/templates/conntrack/sysctl.conf.j220
-rw-r--r--data/templates/firewall/sysctl-firewall.conf.j228
-rw-r--r--interface-definitions/include/firewall/action-and-notrack.xml.i2
-rw-r--r--interface-definitions/include/firewall/global-options.xml.i8
-rw-r--r--interface-definitions/include/firewall/timeout-common-protocols.xml.i (renamed from interface-definitions/include/conntrack/timeout-common-protocols.xml.i)3
-rw-r--r--interface-definitions/include/version/firewall-version.xml.i2
-rw-r--r--interface-definitions/system_conntrack.xml.in1
-rwxr-xr-xsmoketest/scripts/cli/test_firewall.py96
-rwxr-xr-xsmoketest/scripts/cli/test_system_conntrack.py60
-rwxr-xr-xsrc/conf_mode/firewall.py39
-rwxr-xr-xsrc/conf_mode/system_conntrack.py2
-rwxr-xr-xsrc/migration-scripts/firewall/15-to-1655
12 files changed, 193 insertions, 123 deletions
diff --git a/data/templates/conntrack/sysctl.conf.j2 b/data/templates/conntrack/sysctl.conf.j2
index 986f75c61..554512f4d 100644
--- a/data/templates/conntrack/sysctl.conf.j2
+++ b/data/templates/conntrack/sysctl.conf.j2
@@ -3,25 +3,7 @@
net.netfilter.nf_conntrack_expect_max = {{ expect_table_size }}
net.netfilter.nf_conntrack_max = {{ table_size }}
-
net.ipv4.tcp_max_syn_backlog = {{ tcp.half_open_connections }}
-
net.netfilter.nf_conntrack_tcp_loose = {{ '1' if tcp.loose is vyos_defined('enable') else '0' }}
net.netfilter.nf_conntrack_tcp_max_retrans = {{ tcp.max_retrans }}
-
-net.netfilter.nf_conntrack_icmp_timeout = {{ timeout.icmp }}
-net.netfilter.nf_conntrack_generic_timeout = {{ timeout.other }}
-
-net.netfilter.nf_conntrack_tcp_timeout_close_wait = {{ timeout.tcp.close_wait }}
-net.netfilter.nf_conntrack_tcp_timeout_close = {{ timeout.tcp.close }}
-net.netfilter.nf_conntrack_tcp_timeout_established = {{ timeout.tcp.established }}
-net.netfilter.nf_conntrack_tcp_timeout_fin_wait = {{ timeout.tcp.fin_wait }}
-net.netfilter.nf_conntrack_tcp_timeout_last_ack = {{ timeout.tcp.last_ack }}
-net.netfilter.nf_conntrack_tcp_timeout_syn_recv = {{ timeout.tcp.syn_recv }}
-net.netfilter.nf_conntrack_tcp_timeout_syn_sent = {{ timeout.tcp.syn_sent }}
-net.netfilter.nf_conntrack_tcp_timeout_time_wait = {{ timeout.tcp.time_wait }}
-
-net.netfilter.nf_conntrack_udp_timeout = {{ timeout.udp.other }}
-net.netfilter.nf_conntrack_udp_timeout_stream = {{ timeout.udp.stream }}
-
-net.netfilter.nf_conntrack_acct = {{ '1' if flow_accounting is vyos_defined else '0' }}
+net.netfilter.nf_conntrack_acct = {{ '1' if flow_accounting is vyos_defined else '0' }} \ No newline at end of file
diff --git a/data/templates/firewall/sysctl-firewall.conf.j2 b/data/templates/firewall/sysctl-firewall.conf.j2
new file mode 100644
index 000000000..b9c3311e2
--- /dev/null
+++ b/data/templates/firewall/sysctl-firewall.conf.j2
@@ -0,0 +1,28 @@
+# Autogenerated by firewall.py
+
+# gloabl options
+net.ipv4.icmp_echo_ignore_all = {{ 0 if global_options.all_ping == 'enable' else 1 }}
+net.ipv4.icmp_echo_ignore_broadcasts = {{ 0 if global_options.broadcast_ping == 'enable' else 1 }}
+net.ipv4.conf.all.bc_forwarding = {{ 1 if global_options.directed_broadcast == 'enable' else 0 }}
+net.ipv4.conf.*.accept_source_route = {{ 1 if global_options.ip_src_route == 'enable' else 0 }}
+net.ipv6.conf.*.accept_redirects = {{ 1 if global_options.ipv6_receive_redirects == 'enable' else 0 }}
+net.ipv6.conf.*.accept_source_route = {{ 0 if global_options.ipv6_src_route == 'enable' else -1 }}
+net.ipv4.conf.all.log_martians = {{ 1 if global_options.log_martians == 'enable' else 0 }}
+net.ipv4.conf.*.accept_redirects = {{ 1 if global_options.receive_redirects == 'enable' else 0 }}
+net.ipv4.conf.*.send_redirects = {{ 1 if global_options.send_redirects == 'enable' else 0 }}
+net.ipv4.tcp_syncookies = {{ 1 if global_options.syn_cookies == 'enable' else 0 }}
+net.ipv4.tcp_rfc1337 = {{ 1 if global_options.twa_hazards_protection == 'enable' else 0 }}
+
+## Timeout values:
+net.netfilter.nf_conntrack_icmp_timeout = {{ global_options.timeout.icmp }}
+net.netfilter.nf_conntrack_generic_timeout = {{ global_options.timeout.other }}
+net.netfilter.nf_conntrack_tcp_timeout_close_wait = {{ global_options.timeout.tcp.close_wait }}
+net.netfilter.nf_conntrack_tcp_timeout_close = {{ global_options.timeout.tcp.close }}
+net.netfilter.nf_conntrack_tcp_timeout_established = {{ global_options.timeout.tcp.established }}
+net.netfilter.nf_conntrack_tcp_timeout_fin_wait = {{ global_options.timeout.tcp.fin_wait }}
+net.netfilter.nf_conntrack_tcp_timeout_last_ack = {{ global_options.timeout.tcp.last_ack }}
+net.netfilter.nf_conntrack_tcp_timeout_syn_recv = {{ global_options.timeout.tcp.syn_recv }}
+net.netfilter.nf_conntrack_tcp_timeout_syn_sent = {{ global_options.timeout.tcp.syn_sent }}
+net.netfilter.nf_conntrack_tcp_timeout_time_wait = {{ global_options.timeout.tcp.time_wait }}
+net.netfilter.nf_conntrack_udp_timeout = {{ global_options.timeout.udp.other }}
+net.netfilter.nf_conntrack_udp_timeout_stream = {{ global_options.timeout.udp.stream }}
diff --git a/interface-definitions/include/firewall/action-and-notrack.xml.i b/interface-definitions/include/firewall/action-and-notrack.xml.i
index e063c58d5..de11f7dd5 100644
--- a/interface-definitions/include/firewall/action-and-notrack.xml.i
+++ b/interface-definitions/include/firewall/action-and-notrack.xml.i
@@ -35,7 +35,7 @@
</valueHelp>
<valueHelp>
<format>notrack</format>
- <description>Igone connection tracking</description>
+ <description>Ignore connection tracking</description>
</valueHelp>
<constraint>
<regex>(accept|continue|jump|notrack|reject|return|drop|queue)</regex>
diff --git a/interface-definitions/include/firewall/global-options.xml.i b/interface-definitions/include/firewall/global-options.xml.i
index 9cd0b3239..9039b76fd 100644
--- a/interface-definitions/include/firewall/global-options.xml.i
+++ b/interface-definitions/include/firewall/global-options.xml.i
@@ -244,6 +244,14 @@
</properties>
<defaultValue>enable</defaultValue>
</leafNode>
+ <node name="timeout">
+ <properties>
+ <help>Connection timeout options</help>
+ </properties>
+ <children>
+ #include <include/firewall/timeout-common-protocols.xml.i>
+ </children>
+ </node>
<leafNode name="twa-hazards-protection">
<properties>
<help>RFC1337 TCP TIME-WAIT assasination hazards protection</help>
diff --git a/interface-definitions/include/conntrack/timeout-common-protocols.xml.i b/interface-definitions/include/firewall/timeout-common-protocols.xml.i
index 2676d846e..037d7d2b1 100644
--- a/interface-definitions/include/conntrack/timeout-common-protocols.xml.i
+++ b/interface-definitions/include/firewall/timeout-common-protocols.xml.i
@@ -1,4 +1,4 @@
-<!-- include start from conntrack/timeout-common-protocols.xml.i -->
+<!-- include start from firewall/timeout-common-protocols.xml.i -->
<leafNode name="icmp">
<properties>
<help>ICMP timeout in seconds</help>
@@ -169,4 +169,3 @@
</leafNode>
</children>
</node>
-<!-- include end -->
diff --git a/interface-definitions/include/version/firewall-version.xml.i b/interface-definitions/include/version/firewall-version.xml.i
index fa8e26f78..560ed9e5f 100644
--- a/interface-definitions/include/version/firewall-version.xml.i
+++ b/interface-definitions/include/version/firewall-version.xml.i
@@ -1,3 +1,3 @@
<!-- include start from include/version/firewall-version.xml.i -->
-<syntaxVersion component='firewall' version='15'></syntaxVersion>
+<syntaxVersion component='firewall' version='16'></syntaxVersion>
<!-- include end -->
diff --git a/interface-definitions/system_conntrack.xml.in b/interface-definitions/system_conntrack.xml.in
index 219c6e28e..33aa832a8 100644
--- a/interface-definitions/system_conntrack.xml.in
+++ b/interface-definitions/system_conntrack.xml.in
@@ -509,7 +509,6 @@
</node>
</children>
</node>
- #include <include/conntrack/timeout-common-protocols.xml.i>
</children>
</node>
</children>
diff --git a/smoketest/scripts/cli/test_firewall.py b/smoketest/scripts/cli/test_firewall.py
index 5cf2b2146..0943d8e24 100755
--- a/smoketest/scripts/cli/test_firewall.py
+++ b/smoketest/scripts/cli/test_firewall.py
@@ -23,6 +23,7 @@ from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.configsession import ConfigSessionError
from vyos.utils.process import run
+from vyos.utils.file import read_file
sysfs_config = {
'all_ping': {'sysfs': '/proc/sys/net/ipv4/icmp_echo_ignore_all', 'default': '0', 'test_value': 'disable'},
@@ -38,6 +39,10 @@ sysfs_config = {
'twa_hazards_protection': {'sysfs': '/proc/sys/net/ipv4/tcp_rfc1337', 'default': '0', 'test_value': 'enable'}
}
+def get_sysctl(parameter):
+ tmp = parameter.replace(r'.', r'/')
+ return read_file(f'/proc/sys/{tmp}')
+
class TestFirewall(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
@@ -240,7 +245,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
self.cli_set(['firewall', 'ipv4', 'output', 'raw', 'rule', '1', 'action', 'accept'])
self.cli_set(['firewall', 'ipv4', 'output', 'raw', 'rule', '1', 'protocol', 'udp'])
- self.cli_set(['firewall', 'ipv4', 'prerouting', 'raw', 'rule', '1', 'action', 'drop'])
+ self.cli_set(['firewall', 'ipv4', 'prerouting', 'raw', 'rule', '1', 'action', 'notrack'])
self.cli_set(['firewall', 'ipv4', 'prerouting', 'raw', 'rule', '1', 'protocol', 'tcp'])
self.cli_set(['firewall', 'ipv4', 'prerouting', 'raw', 'rule', '1', 'destination', 'port', '23'])
@@ -270,7 +275,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
['OUT-raw default-action drop', 'drop'],
['chain VYOS_PREROUTING_raw'],
['type filter hook prerouting priority raw; policy accept;'],
- ['tcp dport 23', 'drop'],
+ ['tcp dport 23', 'notrack'],
['PRE-raw default-action accept', 'accept'],
['chain NAME_smoketest'],
['saddr 172.16.20.10', 'daddr 172.16.10.10', 'log prefix "[ipv4-NAM-smoketest-1-A]" log level debug', 'ip ttl 15', 'accept'],
@@ -474,7 +479,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
self.cli_set(['firewall', 'ipv6', 'output', 'filter', 'rule', '3', 'outbound-interface', 'name', interface])
self.cli_set(['firewall', 'ipv6', 'output', 'raw', 'default-action', 'drop'])
- self.cli_set(['firewall', 'ipv6', 'output', 'raw', 'rule', '1', 'action', 'accept'])
+ self.cli_set(['firewall', 'ipv6', 'output', 'raw', 'rule', '1', 'action', 'notrack'])
self.cli_set(['firewall', 'ipv6', 'output', 'raw', 'rule', '1', 'protocol', 'udp'])
self.cli_set(['firewall', 'ipv6', 'prerouting', 'raw', 'rule', '1', 'action', 'drop'])
@@ -498,7 +503,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
['log prefix "[ipv6-OUT-filter-default-D]"','OUT-filter default-action drop', 'drop'],
['chain VYOS_IPV6_OUTPUT_raw'],
['type filter hook output priority raw; policy accept;'],
- ['udp', 'accept'],
+ ['udp', 'notrack'],
['OUT-raw default-action drop', 'drop'],
['chain VYOS_IPV6_PREROUTING_raw'],
['type filter hook prerouting priority raw; policy accept;'],
@@ -770,6 +775,89 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
with open(path, 'r') as f:
self.assertNotEqual(f.read().strip(), conf['default'], msg=path)
+ def test_timeout_sysctl(self):
+ timeout_config = {
+ 'net.netfilter.nf_conntrack_icmp_timeout' :{
+ 'cli' : ['global-options', 'timeout', 'icmp'],
+ 'test_value' : '180',
+ 'default_value' : '30',
+ },
+ 'net.netfilter.nf_conntrack_generic_timeout' :{
+ 'cli' : ['global-options', 'timeout', 'other'],
+ 'test_value' : '1200',
+ 'default_value' : '600',
+ },
+ 'net.netfilter.nf_conntrack_tcp_timeout_close_wait' :{
+ 'cli' : ['global-options', 'timeout', 'tcp', 'close-wait'],
+ 'test_value' : '30',
+ 'default_value' : '60',
+ },
+ 'net.netfilter.nf_conntrack_tcp_timeout_close' :{
+ 'cli' : ['global-options', 'timeout', 'tcp', 'close'],
+ 'test_value' : '20',
+ 'default_value' : '10',
+ },
+ 'net.netfilter.nf_conntrack_tcp_timeout_established' :{
+ 'cli' : ['global-options', 'timeout', 'tcp', 'established'],
+ 'test_value' : '1000',
+ 'default_value' : '432000',
+ },
+ 'net.netfilter.nf_conntrack_tcp_timeout_fin_wait' :{
+ 'cli' : ['global-options', 'timeout', 'tcp', 'fin-wait'],
+ 'test_value' : '240',
+ 'default_value' : '120',
+ },
+ 'net.netfilter.nf_conntrack_tcp_timeout_last_ack' :{
+ 'cli' : ['global-options', 'timeout', 'tcp', 'last-ack'],
+ 'test_value' : '300',
+ 'default_value' : '30',
+ },
+ 'net.netfilter.nf_conntrack_tcp_timeout_syn_recv' :{
+ 'cli' : ['global-options', 'timeout', 'tcp', 'syn-recv'],
+ 'test_value' : '100',
+ 'default_value' : '60',
+ },
+ 'net.netfilter.nf_conntrack_tcp_timeout_syn_sent' :{
+ 'cli' : ['global-options', 'timeout', 'tcp', 'syn-sent'],
+ 'test_value' : '300',
+ 'default_value' : '120',
+ },
+ 'net.netfilter.nf_conntrack_tcp_timeout_time_wait' :{
+ 'cli' : ['global-options', 'timeout', 'tcp', 'time-wait'],
+ 'test_value' : '303',
+ 'default_value' : '120',
+ },
+ 'net.netfilter.nf_conntrack_udp_timeout' :{
+ 'cli' : ['global-options', 'timeout', 'udp', 'other'],
+ 'test_value' : '90',
+ 'default_value' : '30',
+ },
+ 'net.netfilter.nf_conntrack_udp_timeout_stream' :{
+ 'cli' : ['global-options', 'timeout', 'udp', 'stream'],
+ 'test_value' : '200',
+ 'default_value' : '180',
+ },
+ }
+
+ for parameter, parameter_config in timeout_config.items():
+ self.cli_set(['firewall'] + parameter_config['cli'] + [parameter_config['test_value']])
+
+ # commit changes
+ self.cli_commit()
+
+ # validate configuration
+ for parameter, parameter_config in timeout_config.items():
+ tmp = parameter_config['test_value']
+ self.assertEqual(get_sysctl(f'{parameter}'), tmp)
+
+ # delete all configuration options and revert back to defaults
+ self.cli_delete(['firewall', 'global-options', 'timeout'])
+ self.cli_commit()
+
+ # validate configuration
+ for parameter, parameter_config in timeout_config.items():
+ self.assertEqual(get_sysctl(f'{parameter}'), parameter_config['default_value'])
+
### Zone
def test_zone_basic(self):
self.cli_set(['firewall', 'ipv4', 'name', 'smoketest', 'default-action', 'drop'])
diff --git a/smoketest/scripts/cli/test_system_conntrack.py b/smoketest/scripts/cli/test_system_conntrack.py
index c6d8a5436..3ae7b6217 100755
--- a/smoketest/scripts/cli/test_system_conntrack.py
+++ b/smoketest/scripts/cli/test_system_conntrack.py
@@ -68,66 +68,6 @@ class TestSystemConntrack(VyOSUnitTestSHIM.TestCase):
'test_value' : '128',
'default_value' : '3',
},
- 'net.netfilter.nf_conntrack_icmp_timeout' :{
- 'cli' : ['timeout', 'icmp'],
- 'test_value' : '180',
- 'default_value' : '30',
- },
- 'net.netfilter.nf_conntrack_generic_timeout' :{
- 'cli' : ['timeout', 'other'],
- 'test_value' : '1200',
- 'default_value' : '600',
- },
- 'net.netfilter.nf_conntrack_tcp_timeout_close_wait' :{
- 'cli' : ['timeout', 'tcp', 'close-wait'],
- 'test_value' : '30',
- 'default_value' : '60',
- },
- 'net.netfilter.nf_conntrack_tcp_timeout_close' :{
- 'cli' : ['timeout', 'tcp', 'close'],
- 'test_value' : '20',
- 'default_value' : '10',
- },
- 'net.netfilter.nf_conntrack_tcp_timeout_established' :{
- 'cli' : ['timeout', 'tcp', 'established'],
- 'test_value' : '1000',
- 'default_value' : '432000',
- },
- 'net.netfilter.nf_conntrack_tcp_timeout_fin_wait' :{
- 'cli' : ['timeout', 'tcp', 'fin-wait'],
- 'test_value' : '240',
- 'default_value' : '120',
- },
- 'net.netfilter.nf_conntrack_tcp_timeout_last_ack' :{
- 'cli' : ['timeout', 'tcp', 'last-ack'],
- 'test_value' : '300',
- 'default_value' : '30',
- },
- 'net.netfilter.nf_conntrack_tcp_timeout_syn_recv' :{
- 'cli' : ['timeout', 'tcp', 'syn-recv'],
- 'test_value' : '100',
- 'default_value' : '60',
- },
- 'net.netfilter.nf_conntrack_tcp_timeout_syn_sent' :{
- 'cli' : ['timeout', 'tcp', 'syn-sent'],
- 'test_value' : '300',
- 'default_value' : '120',
- },
- 'net.netfilter.nf_conntrack_tcp_timeout_time_wait' :{
- 'cli' : ['timeout', 'tcp', 'time-wait'],
- 'test_value' : '303',
- 'default_value' : '120',
- },
- 'net.netfilter.nf_conntrack_udp_timeout' :{
- 'cli' : ['timeout', 'udp', 'other'],
- 'test_value' : '90',
- 'default_value' : '30',
- },
- 'net.netfilter.nf_conntrack_udp_timeout_stream' :{
- 'cli' : ['timeout', 'udp', 'stream'],
- 'test_value' : '200',
- 'default_value' : '180',
- },
}
for parameter, parameter_config in conntrack_config.items():
diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py
index acf3805d2..4c289b921 100755
--- a/src/conf_mode/firewall.py
+++ b/src/conf_mode/firewall.py
@@ -33,6 +33,7 @@ from vyos.template import render
from vyos.utils.dict import dict_search_args
from vyos.utils.dict import dict_search_recursive
from vyos.utils.process import call
+from vyos.utils.process import cmd
from vyos.utils.process import rc_cmd
from vyos import ConfigError
from vyos import airbag
@@ -40,20 +41,7 @@ from vyos import airbag
airbag.enable()
nftables_conf = '/run/nftables.conf'
-
-sysfs_config = {
- 'all_ping': {'sysfs': '/proc/sys/net/ipv4/icmp_echo_ignore_all', 'enable': '0', 'disable': '1'},
- 'broadcast_ping': {'sysfs': '/proc/sys/net/ipv4/icmp_echo_ignore_broadcasts', 'enable': '0', 'disable': '1'},
- 'directed_broadcast' : {'sysfs': '/proc/sys/net/ipv4/conf/all/bc_forwarding', 'enable': '1', 'disable': '0'},
- 'ip_src_route': {'sysfs': '/proc/sys/net/ipv4/conf/*/accept_source_route'},
- 'ipv6_receive_redirects': {'sysfs': '/proc/sys/net/ipv6/conf/*/accept_redirects'},
- 'ipv6_src_route': {'sysfs': '/proc/sys/net/ipv6/conf/*/accept_source_route', 'enable': '0', 'disable': '-1'},
- 'log_martians': {'sysfs': '/proc/sys/net/ipv4/conf/all/log_martians'},
- 'receive_redirects': {'sysfs': '/proc/sys/net/ipv4/conf/*/accept_redirects'},
- 'send_redirects': {'sysfs': '/proc/sys/net/ipv4/conf/*/send_redirects'},
- 'syn_cookies': {'sysfs': '/proc/sys/net/ipv4/tcp_syncookies'},
- 'twa_hazards_protection': {'sysfs': '/proc/sys/net/ipv4/tcp_rfc1337'}
-}
+sysctl_file = r'/run/sysctl/10-vyos-firewall.conf'
valid_groups = [
'address_group',
@@ -467,33 +455,16 @@ def generate(firewall):
local_zone_conf['from_local'][zone] = zone_conf['from'][local_zone]
render(nftables_conf, 'firewall/nftables.j2', firewall)
+ render(sysctl_file, 'firewall/sysctl-firewall.conf.j2', firewall)
return None
-def apply_sysfs(firewall):
- for name, conf in sysfs_config.items():
- paths = glob(conf['sysfs'])
- value = None
-
- if name in firewall['global_options']:
- conf_value = firewall['global_options'][name]
- if conf_value in conf:
- value = conf[conf_value]
- elif conf_value == 'enable':
- value = '1'
- elif conf_value == 'disable':
- value = '0'
-
- if value:
- for path in paths:
- with open(path, 'w') as f:
- f.write(value)
-
def apply(firewall):
install_result, output = rc_cmd(f'nft --file {nftables_conf}')
if install_result == 1:
raise ConfigError(f'Failed to apply firewall: {output}')
- apply_sysfs(firewall)
+ # Apply firewall global-options sysctl settings
+ cmd(f'sysctl -f {sysctl_file}')
call_dependents()
diff --git a/src/conf_mode/system_conntrack.py b/src/conf_mode/system_conntrack.py
index d9c38fd95..aa290788c 100755
--- a/src/conf_mode/system_conntrack.py
+++ b/src/conf_mode/system_conntrack.py
@@ -166,7 +166,7 @@ def verify(conntrack):
if not group_obj:
Warning(f'{error_group} "{group_name}" has no members!')
- Warning(f'It is prefered to defined {inet} conntrack ignore rules in the <firewall {inet} prerouting raw> section')
+ Warning(f'It is prefered to define {inet} conntrack ignore rules in <firewall {inet} prerouting raw> section')
if dict_search_args(conntrack, 'timeout', 'custom', inet, 'rule') != None:
for rule, rule_config in conntrack['timeout']['custom'][inet]['rule'].items():
diff --git a/src/migration-scripts/firewall/15-to-16 b/src/migration-scripts/firewall/15-to-16
new file mode 100755
index 000000000..7c8d38fe6
--- /dev/null
+++ b/src/migration-scripts/firewall/15-to-16
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2022-2024 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/>.
+
+# T6394: Migrate conntrack timeout options to firewall global-options
+ # from: set system conntrack timeout ..
+ # to: set firewall global-options timeout ...
+
+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()
+
+firewall_base = ['firewall', 'global-options']
+conntrack_base = ['system', 'conntrack', 'timeout']
+config = ConfigTree(config_file)
+
+if not config.exists(conntrack_base):
+ # Nothing to do
+ exit(0)
+
+for protocol in ['icmp', 'tcp', 'udp', 'other']:
+ if config.exists(conntrack_base + [protocol]):
+ if not config.exists(firewall_base):
+ config.set(firewall_base + ['timeout'])
+ config.copy(conntrack_base + [protocol], firewall_base + ['timeout', protocol])
+ config.delete(conntrack_base + [protocol])
+
+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) \ No newline at end of file