From b6abe23ba2d2a5d5055afd203bc3e60ee20bf757 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Thu, 24 Sep 2026 16:32:15 +0200 Subject: openvpn: T9363: multiply the site-to-site keepalive timeout "failure-count" counts missed intervals, so the timeout it describes is interval * failure-count. Server mode renders and verifies it that way; site-to-site passed the bare count to "ping-restart", where it lands as seconds - 60s instead of 600s with the defaults. Render the product. That puts a timeout past the 86400 "ping-restart" accepts within reach, so verify() rejects it and the 5-to-6 migration clamps configurations already beyond it. This changes behaviour on upgrade: site-to-site tunnels now tolerate a longer silence, 600 seconds instead of 60 with the defaults. --- src/tests/test_openvpn_migration.py | 52 +++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'src/tests') diff --git a/src/tests/test_openvpn_migration.py b/src/tests/test_openvpn_migration.py index 53640a0a6..2784c4f50 100644 --- a/src/tests/test_openvpn_migration.py +++ b/src/tests/test_openvpn_migration.py @@ -437,6 +437,58 @@ class TestOpenVPNMigration(TestCase): tmp = ['interfaces', 'openvpn', 'vtun10', 'keep-alive', 'failure-count'] self.assertEqual(config.return_value(tmp), '1000') + def test_site_to_site_keepalive_left_alone_when_valid(self): + config = config_tree( + ' mode site-to-site\n' + ' keep-alive {\n' + ' interval 10\n' + ' failure-count 60\n' + ' }\n' + ) + self.migrate(config) + tmp = ['interfaces', 'openvpn', 'vtun10', 'keep-alive', 'failure-count'] + self.assertEqual(config.return_value(tmp), '60') + + def test_site_to_site_keepalive_over_a_day_is_clamped(self): + config = config_tree( + ' mode site-to-site\n' + ' keep-alive {\n' + ' interval 600\n' + ' failure-count 1000\n' + ' }\n' + ) + self.migrate(config) + tmp = ['interfaces', 'openvpn', 'vtun10', 'keep-alive', 'failure-count'] + # 600 * 144 is exactly 24 hours, and nothing doubles it here + self.assertEqual(config.return_value(tmp), '144') + + def test_site_to_site_disabled_keepalive_survives(self): + config = config_tree( + ' mode site-to-site\n' + ' keep-alive {\n' + ' interval 0\n' + ' failure-count 1000\n' + ' }\n' + ) + self.migrate(config) + tmp = ['interfaces', 'openvpn', 'vtun10', 'keep-alive'] + self.assertEqual(config.return_value(tmp + ['interval']), '0') + self.assertEqual(config.return_value(tmp + ['failure-count']), '1000') + + def test_site_to_site_keeps_a_failure_count_below_two(self): + # only "keepalive" wants the timeout to be twice the interval, and + # site-to-site renders no "keepalive" + config = config_tree( + ' mode site-to-site\n' + ' keep-alive {\n' + ' interval 10\n' + ' failure-count 1\n' + ' }\n' + ) + self.migrate(config) + tmp = ['interfaces', 'openvpn', 'vtun10', 'keep-alive', 'failure-count'] + self.assertEqual(config.return_value(tmp), '1') + def test_raw_cipher_drops_dco_in_site_to_site(self): # site-to-site renders neither "client" nor "server", so OpenVPN takes # a raw "--cipher" as the fallback cipher and gives up the offload -- cgit v1.2.3