summaryrefslogtreecommitdiff
path: root/src/migration-scripts
diff options
context:
space:
mode:
authorAntonio Quartulli <antonio@mandelbit.com>2026-08-30 19:43:51 +0200
committerAntonio Quartulli <antonio@mandelbit.com>2026-09-13 21:06:12 +0200
commit585c491b3ee5c02a0367bf2bd752fe4510200c6a (patch)
tree04d82e00c077418c4ab9f14cac17cdf4d682c9b1 /src/migration-scripts
parentb7e0a79b7c028cf604fb3becef3f74ae0f1f06cc (diff)
downloadvyos-1x-585c491b3ee5c02a0367bf2bd752fe4510200c6a.tar.gz
vyos-1x-585c491b3ee5c02a0367bf2bd752fe4510200c6a.zip
openvpn: T8264: migrate away DCO the Kernel module cannot serve
"offload dco" was accepted next to tap, static keys, compression, CBC ciphers and raw options OpenVPN refuses to offload, because 2.6 ignored the module altogether. Those combinations now fail verify(), which would break config load on upgrade, so drop the request instead. The migration has to mirror verify_dco() exactly: anything it keeps that verify() turns away leaves a router unable to commit its own configuration.
Diffstat (limited to 'src/migration-scripts')
-rw-r--r--src/migration-scripts/openvpn/5-to-695
1 files changed, 95 insertions, 0 deletions
diff --git a/src/migration-scripts/openvpn/5-to-6 b/src/migration-scripts/openvpn/5-to-6
new file mode 100644
index 000000000..46c9aaeb7
--- /dev/null
+++ b/src/migration-scripts/openvpn/5-to-6
@@ -0,0 +1,95 @@
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+# T8264: "offload dco" used to be accepted next to settings the Kernel module
+# can not serve, because OpenVPN 2.6 silently ignored the module. Now that the
+# offload is real those combinations are rejected, so drop the request from
+# configurations that would otherwise fail to load.
+
+from vyos.configtree import ConfigTree
+
+base = ['interfaces', 'openvpn']
+dco_ciphers = ['aes128gcm', 'aes192gcm', 'aes256gcm']
+dco_incompatible_options = [
+ 'comp-lzo',
+ 'disable-dco',
+ 'fragment',
+ 'http-proxy',
+ 'management-query-proxy',
+ 'socks-proxy',
+]
+dco_conditional_options = {
+ 'allow-compression': 'no',
+ 'compress': 'migrate',
+}
+
+
+def _offloadable(options: list) -> bool:
+ """Whether every raw option leaves the data path offloadable."""
+ for option in options:
+ tmp = option.split()
+ if not tmp:
+ continue
+ keyword = tmp[0].lstrip('-')
+ if keyword in dco_incompatible_options:
+ return False
+ keep = dco_conditional_options.get(keyword)
+ if keep is not None and tmp[1:] != [keep]:
+ return False
+ return True
+
+
+def _value(config: ConfigTree, path: list):
+ # return_value() raises on a missing path, and nodes carrying a CLI
+ # default are usually absent from a saved configuration
+ return config.return_value(path) if config.exists(path) else None
+
+
+def migrate(config: ConfigTree) -> None:
+ if not config.exists(base):
+ return
+
+ for interface in config.list_nodes(base):
+ path = base + [interface]
+ if not config.exists(path + ['offload', 'dco']):
+ continue
+
+ ciphers = []
+ if config.exists(path + ['encryption', 'data-ciphers']):
+ ciphers += config.return_values(path + ['encryption', 'data-ciphers'])
+ fallback = _value(config, path + ['encryption', 'data-ciphers-fallback'])
+ if fallback:
+ ciphers.append(fallback)
+
+ options = []
+ if config.exists(path + ['openvpn-option']):
+ options = config.return_values(path + ['openvpn-option'])
+
+ topology = None
+ if _value(config, path + ['mode']) == 'server':
+ topology = _value(config, path + ['server', 'topology'])
+
+ if (
+ _value(config, path + ['device-type']) == 'tap'
+ or config.exists(path + ['shared-secret-key'])
+ or config.exists(path + ['use-lzo-compression'])
+ or (topology is not None and topology != 'subnet')
+ or any(cipher not in dco_ciphers for cipher in ciphers)
+ or not _offloadable(options)
+ ):
+ offload = path + ['offload']
+ config.delete(offload + ['dco'])
+ if config.exists(offload) and not config.list_nodes(offload):
+ config.delete(offload)