diff options
Diffstat (limited to 'src/migration-scripts/interfaces')
34 files changed, 330 insertions, 181 deletions
diff --git a/src/migration-scripts/interfaces/0-to-1 b/src/migration-scripts/interfaces/0-to-1 index 7c135e76e..c4417c4ca 100644 --- a/src/migration-scripts/interfaces/0-to-1 +++ b/src/migration-scripts/interfaces/0-to-1 @@ -1,4 +1,4 @@ -# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 @@ -20,6 +20,8 @@ from vyos.configtree import ConfigTree +base = ['interfaces', 'bridge'] + def migrate_bridge(config, tree, intf): # check if bridge-group exists tree_bridge = tree + ['bridge-group'] @@ -49,8 +51,6 @@ def migrate_bridge(config, tree, intf): def migrate(config: ConfigTree) -> None: - base = ['interfaces', 'bridge'] - if not config.exists(base): # Nothing to do return diff --git a/src/migration-scripts/interfaces/1-to-2 b/src/migration-scripts/interfaces/1-to-2 index ebf02b028..d0abb4466 100644 --- a/src/migration-scripts/interfaces/1-to-2 +++ b/src/migration-scripts/interfaces/1-to-2 @@ -1,4 +1,4 @@ -# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 @@ -34,7 +34,7 @@ def migrate(config: ConfigTree) -> None: if config.exists(['interfaces', 'ethernet', intf, 'bond-group']): # get configured bond interface bond = config.return_value(['interfaces', 'ethernet', intf, 'bond-group']) - # delete old interface asigned (nested) bond group + # delete old interface assigned (nested) bond group config.delete(['interfaces', 'ethernet', intf, 'bond-group']) # create new bond member interface config.set(base + [bond, 'member', 'interface'], value=intf, replace=False) @@ -42,7 +42,7 @@ def migrate(config: ConfigTree) -> None: # # some combinations were allowed in the past from a CLI perspective # but the kernel overwrote them - remove from CLI to not confuse the users. - # In addition new consitency checks are in place so users can't repeat the + # In addition new consistency checks are in place so users can't repeat the # mistake. One of those nice issues is https://vyos.dev/T532 for bond in config.list_nodes(base): if config.exists(base + [bond, 'arp-monitor', 'interval']) and config.exists(base + [bond, 'mode']): diff --git a/src/migration-scripts/interfaces/10-to-11 b/src/migration-scripts/interfaces/10-to-11 index 8a562f2d0..2e8d2d099 100644 --- a/src/migration-scripts/interfaces/10-to-11 +++ b/src/migration-scripts/interfaces/10-to-11 @@ -1,4 +1,4 @@ -# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/11-to-12 b/src/migration-scripts/interfaces/11-to-12 index 132cecbb7..e1bd496c9 100644 --- a/src/migration-scripts/interfaces/11-to-12 +++ b/src/migration-scripts/interfaces/11-to-12 @@ -1,4 +1,4 @@ -# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/12-to-13 b/src/migration-scripts/interfaces/12-to-13 index 585deb898..abd01ceb8 100644 --- a/src/migration-scripts/interfaces/12-to-13 +++ b/src/migration-scripts/interfaces/12-to-13 @@ -1,4 +1,4 @@ -# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/13-to-14 b/src/migration-scripts/interfaces/13-to-14 index 45d8e3b5f..c8b686ee9 100644 --- a/src/migration-scripts/interfaces/13-to-14 +++ b/src/migration-scripts/interfaces/13-to-14 @@ -1,4 +1,4 @@ -# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/14-to-15 b/src/migration-scripts/interfaces/14-to-15 index d45d59bba..e48371539 100644 --- a/src/migration-scripts/interfaces/14-to-15 +++ b/src/migration-scripts/interfaces/14-to-15 @@ -1,4 +1,4 @@ -# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/15-to-16 b/src/migration-scripts/interfaces/15-to-16 index c9abdb5f8..44768356c 100644 --- a/src/migration-scripts/interfaces/15-to-16 +++ b/src/migration-scripts/interfaces/15-to-16 @@ -1,4 +1,4 @@ -# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/16-to-17 b/src/migration-scripts/interfaces/16-to-17 index 7d241ac68..e3161f178 100644 --- a/src/migration-scripts/interfaces/16-to-17 +++ b/src/migration-scripts/interfaces/16-to-17 @@ -1,4 +1,4 @@ -# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/17-to-18 b/src/migration-scripts/interfaces/17-to-18 index f45695a88..a9bf8174c 100644 --- a/src/migration-scripts/interfaces/17-to-18 +++ b/src/migration-scripts/interfaces/17-to-18 @@ -1,4 +1,4 @@ -# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/18-to-19 b/src/migration-scripts/interfaces/18-to-19 index ae1a07adb..2b54d5cdc 100644 --- a/src/migration-scripts/interfaces/18-to-19 +++ b/src/migration-scripts/interfaces/18-to-19 @@ -1,4 +1,4 @@ -# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/19-to-20 b/src/migration-scripts/interfaces/19-to-20 index 7ee6302e2..7262bdad8 100644 --- a/src/migration-scripts/interfaces/19-to-20 +++ b/src/migration-scripts/interfaces/19-to-20 @@ -1,4 +1,4 @@ -# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/2-to-3 b/src/migration-scripts/interfaces/2-to-3 index 695dcbf7a..bb59eb3ce 100644 --- a/src/migration-scripts/interfaces/2-to-3 +++ b/src/migration-scripts/interfaces/2-to-3 @@ -1,4 +1,4 @@ -# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/20-to-21 b/src/migration-scripts/interfaces/20-to-21 index 0b6895177..73c98957c 100644 --- a/src/migration-scripts/interfaces/20-to-21 +++ b/src/migration-scripts/interfaces/20-to-21 @@ -1,4 +1,4 @@ -# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/21-to-22 b/src/migration-scripts/interfaces/21-to-22 index 046eb10c6..a5feffce3 100644 --- a/src/migration-scripts/interfaces/21-to-22 +++ b/src/migration-scripts/interfaces/21-to-22 @@ -1,4 +1,4 @@ -# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/22-to-23 b/src/migration-scripts/interfaces/22-to-23 index 31f7fa2ff..401d5db0e 100644 --- a/src/migration-scripts/interfaces/22-to-23 +++ b/src/migration-scripts/interfaces/22-to-23 @@ -1,4 +1,4 @@ -# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/23-to-24 b/src/migration-scripts/interfaces/23-to-24 index b72ceee49..c534628ce 100644 --- a/src/migration-scripts/interfaces/23-to-24 +++ b/src/migration-scripts/interfaces/23-to-24 @@ -1,4 +1,4 @@ -# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/24-to-25 b/src/migration-scripts/interfaces/24-to-25 index 9f8cc80ec..7386507f9 100644 --- a/src/migration-scripts/interfaces/24-to-25 +++ b/src/migration-scripts/interfaces/24-to-25 @@ -1,4 +1,4 @@ -# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/25-to-26 b/src/migration-scripts/interfaces/25-to-26 index 7a4032d10..1f10e3dca 100644 --- a/src/migration-scripts/interfaces/25-to-26 +++ b/src/migration-scripts/interfaces/25-to-26 @@ -1,4 +1,4 @@ -# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 @@ -29,6 +29,7 @@ from vyos.pki import encode_dh_parameters from vyos.pki import encode_private_key from vyos.pki import verify_crl from vyos.utils.process import run +from vyos.utils.file import read_file def wrapped_pem_to_config_value(pem): out = [] @@ -38,20 +39,28 @@ def wrapped_pem_to_config_value(pem): out.append(line) return "".join(out) -def read_file_for_pki(config_auth_path): - full_path = os.path.join(AUTH_DIR, config_auth_path) - output = None +def read_auth_file(config_auth_path): + full_path = os.path.normpath(os.path.join(AUTH_DIR, config_auth_path)) + + # If the file is not found under `/config/auth`, it may be because the `/config` + # partition has not been bind-mounted yet during early boot migration execution. + # Fall back to the equivalent path under `/opt/vyatta/etc/config/auth` which + # is accessible at all boot stages. + if not os.path.isfile(full_path) and full_path.startswith(f'{AUTH_DIR}/'): + full_path = AUTH_DIR_FALLBACK + full_path[len(AUTH_DIR): ] if os.path.isfile(full_path): if not os.access(full_path, os.R_OK): - run(f'sudo chmod 644 {full_path}') + run(['sudo', 'chmod', '644', full_path]) + + return read_file(full_path) - with open(full_path, 'r') as f: - output = f.read() + return None - return output AUTH_DIR = '/config/auth' +AUTH_DIR_FALLBACK = '/opt/vyatta/etc/config/auth' + pki_base = ['pki'] def migrate(config: ConfigTree) -> None: @@ -69,13 +78,30 @@ def migrate(config: ConfigTree) -> None: config.set_tag(pki_base + ['openvpn', 'shared-secret']) key_file = config.return_value(base + [interface, 'shared-secret-key-file']) - key = read_file_for_pki(key_file) + key = read_auth_file(key_file) key_pki_name = f'{pki_name}_shared' if key: - config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key)) - config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1') - config.set(base + [interface, 'shared-secret-key'], value=key_pki_name) + # Check if OpenVPN shared-secret already exists - no need to check node + # existence as it is always created above when entering this context + secret_exists = None + for secret_name in config.list_nodes(pki_base + ['openvpn', 'shared-secret']): + secret_path = pki_base + ['openvpn', 'shared-secret', secret_name, 'key'] + if not config.exists(secret_path): + continue + + secret = config.return_value(secret_path) + # Check for duplicate cert/key - and re-use if possible + if secret == wrapped_pem_to_config_value(key): + secret_exists = secret_name + break + + if secret_exists: + config.set(base + [interface, 'shared-secret-key'], value=secret_exists) + else: + config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key)) + config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1') + config.set(base + [interface, 'shared-secret-key'], value=key_pki_name) else: print(f'Failed to migrate shared-secret-key on openvpn interface {interface}') @@ -90,13 +116,30 @@ def migrate(config: ConfigTree) -> None: config.set_tag(pki_base + ['openvpn', 'shared-secret']) key_file = config.return_value(base + [interface, 'tls', 'auth-file']) - key = read_file_for_pki(key_file) + key = read_auth_file(key_file) key_pki_name = f'{pki_name}_auth' if key: - config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key)) - config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1') - config.set(base + [interface, 'tls', 'auth-key'], value=key_pki_name) + # Check if OpenVPN auth key already exists - no need to check node + # existence as it is always created above when entering this context + secret_exists = None + for secret_name in config.list_nodes(pki_base + ['openvpn', 'shared-secret']): + secret_path = pki_base + ['openvpn', 'shared-secret', secret_name, 'key'] + if not config.exists(secret_path): + continue + + secret = config.return_value(secret_path) + # Check for duplicate cert/key - and re-use if possible + if secret == wrapped_pem_to_config_value(key): + secret_exists = secret_name + break + + if secret_exists: + config.set(base + [interface, 'tls', 'auth-key'], value=secret_exists) + else: + config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key)) + config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1') + config.set(base + [interface, 'tls', 'auth-key'], value=key_pki_name) else: print(f'Failed to migrate auth-key on openvpn interface {interface}') @@ -108,13 +151,30 @@ def migrate(config: ConfigTree) -> None: config.set_tag(pki_base + ['openvpn', 'shared-secret']) key_file = config.return_value(base + [interface, 'tls', 'crypt-file']) - key = read_file_for_pki(key_file) + key = read_auth_file(key_file) key_pki_name = f'{pki_name}_crypt' if key: - config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key)) - config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1') - config.set(base + [interface, 'tls', 'crypt-key'], value=key_pki_name) + # Check if OpenVPN auth key already exists - no need to check node + # existence as it is always created above when entering this context + secret_exists = None + for secret_name in config.list_nodes(pki_base + ['openvpn', 'shared-secret']): + secret_path = pki_base + ['openvpn', 'shared-secret', secret_name, 'key'] + if not config.exists(secret_path): + continue + + secret = config.return_value(secret_path) + # Check for duplicate cert/key - and re-use if possible + if secret == wrapped_pem_to_config_value(key): + secret_exists = secret_name + break + + if secret_exists: + config.set(base + [interface, 'tls', 'crypt-key'], value=secret_exists) + else: + config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'key'], value=wrapped_pem_to_config_value(key)) + config.set(pki_base + ['openvpn', 'shared-secret', key_pki_name, 'version'], value='1') + config.set(base + [interface, 'tls', 'crypt-key'], value=key_pki_name) else: print(f'Failed to migrate crypt-key on openvpn interface {interface}') @@ -128,28 +188,41 @@ def migrate(config: ConfigTree) -> None: config.set_tag(pki_base + ['ca']) cert_file = config.return_value(x509_base + ['ca-cert-file']) - cert_path = os.path.join(AUTH_DIR, cert_file) - - if os.path.isfile(cert_path): - if not os.access(cert_path, os.R_OK): - run(f'sudo chmod 644 {cert_path}') - - with open(cert_path, 'r') as f: - certs_str = f.read() - certs_data = certs_str.split(CERT_BEGIN) - index = 1 - for cert_data in certs_data[1:]: - cert = load_certificate(CERT_BEGIN + cert_data, wrap_tags=False) - - if cert: - ca_certs[f'{pki_name}_{index}'] = cert - cert_pem = encode_certificate(cert) + certs_str = read_auth_file(cert_file) + + if certs_str: + certs_data = certs_str.split(CERT_BEGIN) + index = 1 + for cert_data in certs_data[1:]: + cert = load_certificate(CERT_BEGIN + cert_data, wrap_tags=False) + + if cert: + ca_certs[f'{pki_name}_{index}'] = cert + cert_pem = encode_certificate(cert) + + # Check if CA already exists - no need to check node existence as + # it is always created above when entering this context + ca_exists = None + for ca_name in config.list_nodes(pki_base + ['ca']): + ca_cert_path = pki_base + ['ca', ca_name, 'certificate'] + if not config.exists(ca_cert_path): + continue + + ca_base64 = config.return_value(ca_cert_path) + # Check for duplicate cert/key - and re-use if possible + if ca_base64 == wrapped_pem_to_config_value(cert_pem): + ca_exists = ca_name + break + + if ca_exists: + config.set(x509_base + ['ca-certificate'], value=ca_exists, replace=False) + else: config.set(pki_base + ['ca', f'{pki_name}_{index}', 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) config.set(x509_base + ['ca-certificate'], value=f'{pki_name}_{index}', replace=False) - else: - print(f'Failed to migrate CA certificate on openvpn interface {interface}') + else: + print(f'Failed to migrate CA certificate on openvpn interface {interface}') - index += 1 + index += 1 else: print(f'Failed to migrate CA certificate on openvpn interface {interface}') @@ -161,26 +234,36 @@ def migrate(config: ConfigTree) -> None: config.set_tag(pki_base + ['ca']) crl_file = config.return_value(x509_base + ['crl-file']) - crl_path = os.path.join(AUTH_DIR, crl_file) - crl = None - crl_ca_name = None - - if os.path.isfile(crl_path): - if not os.access(crl_path, os.R_OK): - run(f'sudo chmod 644 {crl_path}') + crl_data = read_auth_file(crl_file) - with open(crl_path, 'r') as f: - crl_data = f.read() - crl = load_crl(crl_data, wrap_tags=False) + crl = load_crl(crl_data, wrap_tags=False) if crl_data else None + crl_ca_name = None - for ca_name, ca_cert in ca_certs.items(): - if verify_crl(crl, ca_cert): - crl_ca_name = ca_name - break + if crl: + for ca_name, ca_cert in ca_certs.items(): + if verify_crl(crl, ca_cert): + crl_ca_name = ca_name + break - if crl and crl_ca_name: + if crl_ca_name: crl_pem = encode_certificate(crl) - config.set(pki_base + ['ca', crl_ca_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem)) + + # Check if CRL already exists - no need to check node + # existence as it is always created above when entering this context + crl_exists = None + for ca_name in config.list_nodes(pki_base + ['ca']): + crl_path = pki_base + ['ca', ca_name, 'crl'] + if not config.exists(crl_path): + continue + + crl_base64 = config.return_value(crl_path) + # Check if CRL is a duplicate and we have already imported it + if crl_base64 == wrapped_pem_to_config_value(crl_pem): + crl_exists = ca_name + break + + if not crl_exists: + config.set(pki_base + ['ca', crl_ca_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem)) else: print(f'Failed to migrate CRL on openvpn interface {interface}') @@ -192,21 +275,31 @@ def migrate(config: ConfigTree) -> None: config.set_tag(pki_base + ['certificate']) cert_file = config.return_value(x509_base + ['cert-file']) - cert_path = os.path.join(AUTH_DIR, cert_file) - cert = None - - if os.path.isfile(cert_path): - if not os.access(cert_path, os.R_OK): - run(f'sudo chmod 644 {cert_path}') + cert_data = read_auth_file(cert_file) - with open(cert_path, 'r') as f: - cert_data = f.read() - cert = load_certificate(cert_data, wrap_tags=False) + cert = load_certificate(cert_data, wrap_tags=False) if cert_data else None if cert: cert_pem = encode_certificate(cert) - config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) - config.set(x509_base + ['certificate'], value=pki_name) + # Check if certificate public key already exists - no need to check node + # existence as it is always created above when entering this context + cert_exists = None + for cert_name in config.list_nodes(pki_base + ['certificate']): + cert_path = pki_base + ['certificate', cert_name, 'certificate'] + if not config.exists(cert_path): + continue + + cert_base64 = config.return_value(cert_path) + # Check for duplicate cert/key - and re-use if possible + if cert_base64 == wrapped_pem_to_config_value(cert_pem): + cert_exists = cert_name + break + + if cert_exists: + config.set(x509_base + ['certificate'], value=cert_exists) + else: + config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) + config.set(x509_base + ['certificate'], value=pki_name) else: print(f'Failed to migrate certificate on openvpn interface {interface}') @@ -214,20 +307,28 @@ def migrate(config: ConfigTree) -> None: if config.exists(x509_base + ['key-file']): key_file = config.return_value(x509_base + ['key-file']) - key_path = os.path.join(AUTH_DIR, key_file) - key = None - - if os.path.isfile(key_path): - if not os.access(key_path, os.R_OK): - run(f'sudo chmod 644 {key_path}') + key_data = read_auth_file(key_file) - with open(key_path, 'r') as f: - key_data = f.read() - key = load_private_key(key_data, passphrase=None, wrap_tags=False) + key = load_private_key(key_data, passphrase=None, wrap_tags=False) if key_data else None if key: key_pem = encode_private_key(key, passphrase=None) - config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem)) + # Check if certificate public key already exists - no need to check node + # existence as it is always created above when entering this context + key_exists = None + for key_name in config.list_nodes(pki_base + ['certificate']): + key_path = pki_base + ['certificate', key_name, 'private', 'key'] + if not config.exists(key_path): + continue + + key_base64 = config.return_value(key_path) + # Check for duplicate cert/key - and re-use if possible + if key_base64 == wrapped_pem_to_config_value(key_pem): + key_exists = key_name + break + + if not key_exists: + config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem)) else: print(f'Failed to migrate private key on openvpn interface {interface}') @@ -239,21 +340,32 @@ def migrate(config: ConfigTree) -> None: config.set_tag(pki_base + ['dh']) dh_file = config.return_value(x509_base + ['dh-file']) - dh_path = os.path.join(AUTH_DIR, dh_file) - dh = None - - if os.path.isfile(dh_path): - if not os.access(dh_path, os.R_OK): - run(f'sudo chmod 644 {dh_path}') + dh_data = read_auth_file(dh_file) - with open(dh_path, 'r') as f: - dh_data = f.read() - dh = load_dh_parameters(dh_data, wrap_tags=False) + dh = load_dh_parameters(dh_data, wrap_tags=False) if dh_data else None if dh: dh_pem = encode_dh_parameters(dh) - config.set(pki_base + ['dh', pki_name, 'parameters'], value=wrapped_pem_to_config_value(dh_pem)) - config.set(x509_base + ['dh-params'], value=pki_name) + + # Check if DH parameters already exists - no need to check node existence + # as it is always created above when entering this context + dh_exists = None + for dh_name in config.list_nodes(pki_base + ['dh']): + dh_param_path = pki_base + ['dh', dh_name, 'parameters'] + if not config.exists(dh_param_path): + continue + + dh_base64 = config.return_value(dh_param_path) + # Check for duplicate cert/key - and re-use if possible + if dh_base64 == wrapped_pem_to_config_value(dh_pem): + dh_exists = dh_name + break + + if dh_exists: + config.set(x509_base + ['dh-params'], value=dh_exists) + else: + config.set(pki_base + ['dh', pki_name, 'parameters'], value=wrapped_pem_to_config_value(dh_pem)) + config.set(x509_base + ['dh-params'], value=pki_name) else: print(f'Failed to migrate DH parameters on openvpn interface {interface}') @@ -270,15 +382,15 @@ def migrate(config: ConfigTree) -> None: if config.exists(private_key_path): key_file = config.return_value(private_key_path) - full_key_path = f'/config/auth/wireguard/{key_file}/private.key' + full_key_path = f'{AUTH_DIR}/wireguard/{key_file}/private.key' + key_data = read_auth_file(full_key_path) - if not os.path.exists(full_key_path): + if not key_data: print(f'Could not find wireguard private key for migration on interface "{interface}"') continue - with open(full_key_path, 'r') as f: - key_data = f.read().strip() - config.set(private_key_path, value=key_data) + key_data = key_data.strip() + config.set(private_key_path, value=key_data) for peer in config.list_nodes(base + [interface, 'peer']): config.rename(base + [interface, 'peer', peer, 'pubkey'], 'public-key') @@ -300,16 +412,9 @@ def migrate(config: ConfigTree) -> None: config.set_tag(pki_base + ['ca']) cert_file = config.return_value(x509_base + ['ca-cert-file']) - cert_path = os.path.join(AUTH_DIR, cert_file) - cert = None - - if os.path.isfile(cert_path): - if not os.access(cert_path, os.R_OK): - run(f'sudo chmod 644 {cert_path}') + cert_data = read_auth_file(cert_file) - with open(cert_path, 'r') as f: - cert_data = f.read() - cert = load_certificate(cert_data, wrap_tags=False) + cert = load_certificate(cert_data, wrap_tags=False) if cert_data else None if cert: cert_pem = encode_certificate(cert) @@ -326,16 +431,9 @@ def migrate(config: ConfigTree) -> None: config.set_tag(pki_base + ['certificate']) cert_file = config.return_value(x509_base + ['cert-file']) - cert_path = os.path.join(AUTH_DIR, cert_file) - cert = None + cert_data = read_auth_file(cert_file) - if os.path.isfile(cert_path): - if not os.access(cert_path, os.R_OK): - run(f'sudo chmod 644 {cert_path}') - - with open(cert_path, 'r') as f: - cert_data = f.read() - cert = load_certificate(cert_data, wrap_tags=False) + cert = load_certificate(cert_data, wrap_tags=False) if cert_data else None if cert: cert_pem = encode_certificate(cert) @@ -348,16 +446,9 @@ def migrate(config: ConfigTree) -> None: if config.exists(x509_base + ['key-file']): key_file = config.return_value(x509_base + ['key-file']) - key_path = os.path.join(AUTH_DIR, key_file) - key = None - - if os.path.isfile(key_path): - if not os.access(key_path, os.R_OK): - run(f'sudo chmod 644 {key_path}') + key_data = read_auth_file(key_file) - with open(key_path, 'r') as f: - key_data = f.read() - key = load_private_key(key_data, passphrase=None, wrap_tags=False) + key = load_private_key(key_data, passphrase=None, wrap_tags=False) if key_data else None if key: key_pem = encode_private_key(key, passphrase=None) diff --git a/src/migration-scripts/interfaces/26-to-27 b/src/migration-scripts/interfaces/26-to-27 index 3f58de02c..c04655da0 100644 --- a/src/migration-scripts/interfaces/26-to-27 +++ b/src/migration-scripts/interfaces/26-to-27 @@ -1,4 +1,4 @@ -# Copyright 2022-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/27-to-28 b/src/migration-scripts/interfaces/27-to-28 index eb9363e39..fb156a899 100644 --- a/src/migration-scripts/interfaces/27-to-28 +++ b/src/migration-scripts/interfaces/27-to-28 @@ -1,4 +1,4 @@ -# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/28-to-29 b/src/migration-scripts/interfaces/28-to-29 index 886d49e2c..9a2ba5757 100644 --- a/src/migration-scripts/interfaces/28-to-29 +++ b/src/migration-scripts/interfaces/28-to-29 @@ -1,4 +1,4 @@ -# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/29-to-30 b/src/migration-scripts/interfaces/29-to-30 index 7b32d871e..c9664e83a 100644 --- a/src/migration-scripts/interfaces/29-to-30 +++ b/src/migration-scripts/interfaces/29-to-30 @@ -1,4 +1,4 @@ -# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/3-to-4 b/src/migration-scripts/interfaces/3-to-4 index 4e56200e1..ed27a917b 100644 --- a/src/migration-scripts/interfaces/3-to-4 +++ b/src/migration-scripts/interfaces/3-to-4 @@ -1,4 +1,4 @@ -# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/30-to-31 b/src/migration-scripts/interfaces/30-to-31 index 7e509dd86..48ca063e2 100644 --- a/src/migration-scripts/interfaces/30-to-31 +++ b/src/migration-scripts/interfaces/30-to-31 @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/31-to-32 b/src/migration-scripts/interfaces/31-to-32 index 24077ed24..1c5147e6a 100644 --- a/src/migration-scripts/interfaces/31-to-32 +++ b/src/migration-scripts/interfaces/31-to-32 @@ -1,4 +1,4 @@ -# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/32-to-33 b/src/migration-scripts/interfaces/32-to-33 index c7b1c5b36..11b7aa58b 100644 --- a/src/migration-scripts/interfaces/32-to-33 +++ b/src/migration-scripts/interfaces/32-to-33 @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2024 VyOS maintainers and contributors +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> # # 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 @@ -13,28 +13,46 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -# -# T6318: WiFi country-code should be set system-wide instead of per-device -from vyos.configtree import ConfigTree +# T7646: restore behavior of IPv6 default route if only dhcpv6 was defined but +# not "ipv6 address autoconf" -base = ['interfaces', 'wireless'] +from vyos.configtree import ConfigTree def migrate(config: ConfigTree) -> None: - if not config.exists(base): - # Nothing to do - return + for type in config.list_nodes(['interfaces']): + for interface in config.list_nodes(['interfaces', type]): + iface_base_path = ['interfaces', type, interface] + dhcpv6_addr_path = iface_base_path + ['address'] + + if config.exists(dhcpv6_addr_path) and 'dhcpv6' in config.return_values(dhcpv6_addr_path): + autoconf_path = iface_base_path + ['ipv6', 'address', 'autoconf'] + if not config.exists(autoconf_path): + config.set(autoconf_path) + + vif_path = iface_base_path + ['vif'] + if config.exists(vif_path): + for vif in config.list_nodes(vif_path): + vif_dhcpv6_addr_path = vif_path + [vif, 'address'] + if config.exists(vif_dhcpv6_addr_path) and 'dhcpv6' in config.return_values(vif_dhcpv6_addr_path): + vif_autoconf_path = vif_path + [vif, 'ipv6', 'address', 'autoconf'] + if not config.exists(vif_autoconf_path): + config.set(vif_autoconf_path) - installed = False - for interface in config.list_nodes(base): - cc_path = base + [interface, 'country-code'] - if config.exists(cc_path): - tmp = config.return_value(cc_path) - config.delete(cc_path) + vif_s_path = iface_base_path + ['vif-s'] + if config.exists(vif_s_path): + for vif_s in config.list_nodes(vif_s_path): + vif_s_dhcpv6_addr_path = vif_s_path + [vif_s, 'address'] + if config.exists(vif_s_dhcpv6_addr_path) and 'dhcpv6' in config.return_values(vif_s_dhcpv6_addr_path): + vif_s_autoconf_path = vif_s_path + [vif_s, 'ipv6', 'address', 'autoconf'] + if not config.exists(vif_s_autoconf_path): + config.set(vif_s_autoconf_path) - # There can be only ONE wireless country-code per device, everything - # else makes no sense as a WIFI router can not operate in two - # different countries - if not installed: - config.set(['system', 'wireless', 'country-code'], value=tmp) - installed = True + vif_c_path = iface_base_path + ['vif-s', vif_s, 'vif-c'] + if config.exists(vif_c_path): + for vif_c in config.list_nodes(vif_c_path): + vif_c_dhcpv6_addr_path = vif_c_path + [vif_c, 'address'] + if config.exists(vif_c_dhcpv6_addr_path) and 'dhcpv6' in config.return_values(vif_c_dhcpv6_addr_path): + vif_c_autoconf_path = vif_c_path + [vif_c, 'ipv6', 'address', 'autoconf'] + if not config.exists(vif_c_autoconf_path): + config.set(vif_c_autoconf_path) diff --git a/src/migration-scripts/interfaces/33-to-34 b/src/migration-scripts/interfaces/33-to-34 new file mode 100644 index 000000000..ccda04d0c --- /dev/null +++ b/src/migration-scripts/interfaces/33-to-34 @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# +# Copyright VyOS maintainers and contributors <maintainers@vyos.io> +# +# 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/>. +# +# T6318: WiFi country-code should be set system-wide instead of per-device + +from vyos.configtree import ConfigTree + +base = ['interfaces', 'wireless'] + +def migrate(config: ConfigTree) -> None: + if not config.exists(base): + # Nothing to do + return + + installed = False + for interface in config.list_nodes(base): + cc_path = base + [interface, 'country-code'] + if config.exists(cc_path): + tmp = config.return_value(cc_path) + config.delete(cc_path) + + # There can be only ONE wireless country-code per device, everything + # else makes no sense as a WIFI router can not operate in two + # different countries + if not installed: + config.set(['system', 'wireless', 'country-code'], value=tmp) + installed = True diff --git a/src/migration-scripts/interfaces/4-to-5 b/src/migration-scripts/interfaces/4-to-5 index 93fa7c393..839e23d77 100644 --- a/src/migration-scripts/interfaces/4-to-5 +++ b/src/migration-scripts/interfaces/4-to-5 @@ -1,4 +1,4 @@ -# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/5-to-6 b/src/migration-scripts/interfaces/5-to-6 index 44c32ba63..e172d9c80 100644 --- a/src/migration-scripts/interfaces/5-to-6 +++ b/src/migration-scripts/interfaces/5-to-6 @@ -1,4 +1,4 @@ -# Copyright 202-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 @@ -13,7 +13,7 @@ # 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/>. -# Migrate IPv6 router advertisments from a nested interface configuration to +# Migrate IPv6 router advertisements from a nested interface configuration to # a denested "service router-advert" from vyos.configtree import ConfigTree @@ -56,7 +56,7 @@ def copy_rtradv(c, old_base, interface): # cleanup boolean nodes in individual route route_base = new_base + ['route'] if c.exists(route_base): - for route in config.list_nodes(route_base): + for route in c.list_nodes(route_base): if c.exists(route_base + [route, 'remove-route']): tmp = c.return_value(route_base + [route, 'remove-route']) c.delete(route_base + [route, 'remove-route']) @@ -66,7 +66,7 @@ def copy_rtradv(c, old_base, interface): # cleanup boolean nodes in individual prefix prefix_base = new_base + ['prefix'] if c.exists(prefix_base): - for prefix in config.list_nodes(prefix_base): + for prefix in c.list_nodes(prefix_base): if c.exists(prefix_base + [prefix, 'autonomous-flag']): tmp = c.return_value(prefix_base + [prefix, 'autonomous-flag']) c.delete(prefix_base + [prefix, 'autonomous-flag']) diff --git a/src/migration-scripts/interfaces/6-to-7 b/src/migration-scripts/interfaces/6-to-7 index e60121eec..0131b419c 100644 --- a/src/migration-scripts/interfaces/6-to-7 +++ b/src/migration-scripts/interfaces/6-to-7 @@ -1,4 +1,4 @@ -# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 diff --git a/src/migration-scripts/interfaces/7-to-8 b/src/migration-scripts/interfaces/7-to-8 index 43ae320ab..e670deb37 100644 --- a/src/migration-scripts/interfaces/7-to-8 +++ b/src/migration-scripts/interfaces/7-to-8 @@ -1,4 +1,4 @@ -# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 @@ -43,7 +43,7 @@ def migrate(config: ConfigTree) -> None: # Nothing to do return - # list all individual wireguard interface isntance + # list all individual wireguard interface instance for i in config.list_nodes(base): iface = base + [i] for peer in config.list_nodes(iface + ['peer']): diff --git a/src/migration-scripts/interfaces/8-to-9 b/src/migration-scripts/interfaces/8-to-9 index bae1b34fa..baabce8bc 100644 --- a/src/migration-scripts/interfaces/8-to-9 +++ b/src/migration-scripts/interfaces/8-to-9 @@ -1,4 +1,4 @@ -# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 @@ -26,7 +26,7 @@ def migrate(config: ConfigTree) -> None: # Nothing to do continue - # list all individual interface isntance + # list all individual interface instance for i in config.list_nodes(base): iface = base + [i] if config.exists(iface + ['link']): diff --git a/src/migration-scripts/interfaces/9-to-10 b/src/migration-scripts/interfaces/9-to-10 index cdfd7d432..354416975 100644 --- a/src/migration-scripts/interfaces/9-to-10 +++ b/src/migration-scripts/interfaces/9-to-10 @@ -1,4 +1,4 @@ -# Copyright 2020-2024 VyOS maintainers and contributors <maintainers@vyos.io> +# 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 @@ -13,7 +13,7 @@ # 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/>. -# - rename CLI node 'dhcpv6-options delgate' to 'dhcpv6-options prefix-delegation +# - rename CLI node 'dhcpv6-options delegate' to 'dhcpv6-options prefix-delegation # interface' # - rename CLI node 'interface-id' for prefix-delegation to 'address' as it # represents the local interface IPv6 address assigned by DHCPv6-PD @@ -41,5 +41,5 @@ def migrate(config: ConfigTree) -> None: for interface in config.list_nodes(new_path + ['interface']): config.rename(new_path + ['interface', interface, 'interface-id'], 'address') - # delete old noe + # delete old node config.delete(base_path) |
