diff options
Diffstat (limited to 'src/migration-scripts/interfaces')
-rwxr-xr-x | src/migration-scripts/interfaces/22-to-23 | 144 | ||||
-rwxr-xr-x | src/migration-scripts/interfaces/23-to-24 | 143 | ||||
-rwxr-xr-x | src/migration-scripts/interfaces/24-to-25 | 399 | ||||
-rwxr-xr-x | src/migration-scripts/interfaces/25-to-26 | 377 | ||||
-rwxr-xr-x | src/migration-scripts/interfaces/26-to-27 | 27 | ||||
-rwxr-xr-x | src/migration-scripts/interfaces/27-to-28 | 25 | ||||
-rwxr-xr-x | src/migration-scripts/interfaces/28-to-29 | 25 | ||||
-rwxr-xr-x | src/migration-scripts/interfaces/29-to-30 | 61 |
8 files changed, 602 insertions, 599 deletions
diff --git a/src/migration-scripts/interfaces/22-to-23 b/src/migration-scripts/interfaces/22-to-23 index 8b21fce51..04e023e77 100755 --- a/src/migration-scripts/interfaces/22-to-23 +++ b/src/migration-scripts/interfaces/22-to-23 @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021 VyOS maintainers and contributors +# Copyright (C) 2021-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 @@ -13,133 +13,45 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. - -from sys import argv -from sys import exit +# +# Deletes Wireguard peers if they have the same public key as the router has. +import sys from vyos.configtree import ConfigTree - -def migrate_ospf(config, path, interface): - path = path + ['ospf'] - if config.exists(path): - new_base = ['protocols', 'ospf', 'interface'] - config.set(new_base) - config.set_tag(new_base) - config.copy(path, new_base + [interface]) - config.delete(path) - - # if "ip ospf" was the only setting, we can clean out the empty - # ip node afterwards - if len(config.list_nodes(path[:-1])) == 0: - config.delete(path[:-1]) - -def migrate_ospfv3(config, path, interface): - path = path + ['ospfv3'] - if config.exists(path): - new_base = ['protocols', 'ospfv3', 'interface'] - config.set(new_base) - config.set_tag(new_base) - config.copy(path, new_base + [interface]) - config.delete(path) - - # if "ipv6 ospfv3" was the only setting, we can clean out the empty - # ip node afterwards - if len(config.list_nodes(path[:-1])) == 0: - config.delete(path[:-1]) - -def migrate_rip(config, path, interface): - path = path + ['rip'] - if config.exists(path): - new_base = ['protocols', 'rip', 'interface'] - config.set(new_base) - config.set_tag(new_base) - config.copy(path, new_base + [interface]) - config.delete(path) - - # if "ip rip" was the only setting, we can clean out the empty - # ip node afterwards - if len(config.list_nodes(path[:-1])) == 0: - config.delete(path[:-1]) - -def migrate_ripng(config, path, interface): - path = path + ['ripng'] - if config.exists(path): - new_base = ['protocols', 'ripng', 'interface'] - config.set(new_base) - config.set_tag(new_base) - config.copy(path, new_base + [interface]) - config.delete(path) - - # if "ipv6 ripng" was the only setting, we can clean out the empty - # ip node afterwards - if len(config.list_nodes(path[:-1])) == 0: - config.delete(path[:-1]) +from vyos.utils.network import is_wireguard_key_pair if __name__ == '__main__': - if len(argv) < 2: + if len(sys.argv) < 2: print("Must specify file name!") - exit(1) + sys.exit(1) + + file_name = sys.argv[1] - file_name = argv[1] with open(file_name, 'r') as f: config_file = f.read() config = ConfigTree(config_file) - - # - # Migrate "interface ethernet eth0 ip ospf" to "protocols ospf interface eth0" - # - for type in config.list_nodes(['interfaces']): - for interface in config.list_nodes(['interfaces', type]): - ip_base = ['interfaces', type, interface, 'ip'] - ipv6_base = ['interfaces', type, interface, 'ipv6'] - migrate_rip(config, ip_base, interface) - migrate_ripng(config, ipv6_base, interface) - migrate_ospf(config, ip_base, interface) - migrate_ospfv3(config, ipv6_base, interface) - - vif_path = ['interfaces', type, interface, 'vif'] - if config.exists(vif_path): - for vif in config.list_nodes(vif_path): - vif_ip_base = vif_path + [vif, 'ip'] - vif_ipv6_base = vif_path + [vif, 'ipv6'] - ifname = f'{interface}.{vif}' - - migrate_rip(config, vif_ip_base, ifname) - migrate_ripng(config, vif_ipv6_base, ifname) - migrate_ospf(config, vif_ip_base, ifname) - migrate_ospfv3(config, vif_ipv6_base, ifname) - - - vif_s_path = ['interfaces', type, interface, 'vif-s'] - if config.exists(vif_s_path): - for vif_s in config.list_nodes(vif_s_path): - vif_s_ip_base = vif_s_path + [vif_s, 'ip'] - vif_s_ipv6_base = vif_s_path + [vif_s, 'ipv6'] - - # vif-c interfaces MUST be migrated before their parent vif-s - # interface as the migrate_*() functions delete the path! - vif_c_path = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c'] - if config.exists(vif_c_path): - for vif_c in config.list_nodes(vif_c_path): - vif_c_ip_base = vif_c_path + [vif_c, 'ip'] - vif_c_ipv6_base = vif_c_path + [vif_c, 'ipv6'] - ifname = f'{interface}.{vif_s}.{vif_c}' - - migrate_rip(config, vif_c_ip_base, ifname) - migrate_ripng(config, vif_c_ipv6_base, ifname) - migrate_ospf(config, vif_c_ip_base, ifname) - migrate_ospfv3(config, vif_c_ipv6_base, ifname) - - - ifname = f'{interface}.{vif_s}' - migrate_rip(config, vif_s_ip_base, ifname) - migrate_ripng(config, vif_s_ipv6_base, ifname) - migrate_ospf(config, vif_s_ip_base, ifname) - migrate_ospfv3(config, vif_s_ipv6_base, ifname) + base = ['interfaces', 'wireguard'] + if not config.exists(base): + # Nothing to do + sys.exit(0) + for interface in config.list_nodes(base): + if not config.exists(base + [interface, 'private-key']): + continue + private_key = config.return_value(base + [interface, 'private-key']) + interface_base = base + [interface] + if config.exists(interface_base + ['peer']): + for peer in config.list_nodes(interface_base + ['peer']): + peer_base = interface_base + ['peer', peer] + if not config.exists(peer_base + ['public-key']): + continue + peer_public_key = config.return_value(peer_base + ['public-key']) + if not config.exists(peer_base + ['disable']) \ + and is_wireguard_key_pair(private_key, peer_public_key): + config.set(peer_base + ['disable']) 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) + sys.exit(1) diff --git a/src/migration-scripts/interfaces/23-to-24 b/src/migration-scripts/interfaces/23-to-24 index 8fd79ecc6..8b21fce51 100755 --- a/src/migration-scripts/interfaces/23-to-24 +++ b/src/migration-scripts/interfaces/23-to-24 @@ -14,47 +14,132 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -# A VTI interface also requires an IPSec configuration - VyOS 1.2 supported -# having a VTI interface in the CLI but no IPSec configuration - drop VTI -# configuration if this is the case for VyOS 1.4 - -import sys +from sys import argv +from sys import exit from vyos.configtree import ConfigTree +def migrate_ospf(config, path, interface): + path = path + ['ospf'] + if config.exists(path): + new_base = ['protocols', 'ospf', 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(path, new_base + [interface]) + config.delete(path) + + # if "ip ospf" was the only setting, we can clean out the empty + # ip node afterwards + if len(config.list_nodes(path[:-1])) == 0: + config.delete(path[:-1]) + +def migrate_ospfv3(config, path, interface): + path = path + ['ospfv3'] + if config.exists(path): + new_base = ['protocols', 'ospfv3', 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(path, new_base + [interface]) + config.delete(path) + + # if "ipv6 ospfv3" was the only setting, we can clean out the empty + # ip node afterwards + if len(config.list_nodes(path[:-1])) == 0: + config.delete(path[:-1]) + +def migrate_rip(config, path, interface): + path = path + ['rip'] + if config.exists(path): + new_base = ['protocols', 'rip', 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(path, new_base + [interface]) + config.delete(path) + + # if "ip rip" was the only setting, we can clean out the empty + # ip node afterwards + if len(config.list_nodes(path[:-1])) == 0: + config.delete(path[:-1]) + +def migrate_ripng(config, path, interface): + path = path + ['ripng'] + if config.exists(path): + new_base = ['protocols', 'ripng', 'interface'] + config.set(new_base) + config.set_tag(new_base) + config.copy(path, new_base + [interface]) + config.delete(path) + + # if "ipv6 ripng" was the only setting, we can clean out the empty + # ip node afterwards + if len(config.list_nodes(path[:-1])) == 0: + config.delete(path[:-1]) + if __name__ == '__main__': - if len(sys.argv) < 2: + if len(argv) < 2: print("Must specify file name!") - sys.exit(1) - - file_name = sys.argv[1] + exit(1) + file_name = argv[1] with open(file_name, 'r') as f: config_file = f.read() config = ConfigTree(config_file) - base = ['interfaces', 'vti'] - if not config.exists(base): - # Nothing to do - sys.exit(0) - - ipsec_base = ['vpn', 'ipsec', 'site-to-site', 'peer'] - for interface in config.list_nodes(base): - found = False - if config.exists(ipsec_base): - for peer in config.list_nodes(ipsec_base): - if config.exists(ipsec_base + [peer, 'vti', 'bind']): - tmp = config.return_value(ipsec_base + [peer, 'vti', 'bind']) - if tmp == interface: - # Interface was found and we no longer need to search - # for it in our IPSec peers - found = True - break - if not found: - config.delete(base + [interface]) + + # + # Migrate "interface ethernet eth0 ip ospf" to "protocols ospf interface eth0" + # + for type in config.list_nodes(['interfaces']): + for interface in config.list_nodes(['interfaces', type]): + ip_base = ['interfaces', type, interface, 'ip'] + ipv6_base = ['interfaces', type, interface, 'ipv6'] + migrate_rip(config, ip_base, interface) + migrate_ripng(config, ipv6_base, interface) + migrate_ospf(config, ip_base, interface) + migrate_ospfv3(config, ipv6_base, interface) + + vif_path = ['interfaces', type, interface, 'vif'] + if config.exists(vif_path): + for vif in config.list_nodes(vif_path): + vif_ip_base = vif_path + [vif, 'ip'] + vif_ipv6_base = vif_path + [vif, 'ipv6'] + ifname = f'{interface}.{vif}' + + migrate_rip(config, vif_ip_base, ifname) + migrate_ripng(config, vif_ipv6_base, ifname) + migrate_ospf(config, vif_ip_base, ifname) + migrate_ospfv3(config, vif_ipv6_base, ifname) + + + vif_s_path = ['interfaces', type, interface, 'vif-s'] + if config.exists(vif_s_path): + for vif_s in config.list_nodes(vif_s_path): + vif_s_ip_base = vif_s_path + [vif_s, 'ip'] + vif_s_ipv6_base = vif_s_path + [vif_s, 'ipv6'] + + # vif-c interfaces MUST be migrated before their parent vif-s + # interface as the migrate_*() functions delete the path! + vif_c_path = ['interfaces', type, interface, 'vif-s', vif_s, 'vif-c'] + if config.exists(vif_c_path): + for vif_c in config.list_nodes(vif_c_path): + vif_c_ip_base = vif_c_path + [vif_c, 'ip'] + vif_c_ipv6_base = vif_c_path + [vif_c, 'ipv6'] + ifname = f'{interface}.{vif_s}.{vif_c}' + + migrate_rip(config, vif_c_ip_base, ifname) + migrate_ripng(config, vif_c_ipv6_base, ifname) + migrate_ospf(config, vif_c_ip_base, ifname) + migrate_ospfv3(config, vif_c_ipv6_base, ifname) + + + ifname = f'{interface}.{vif_s}' + migrate_rip(config, vif_s_ip_base, ifname) + migrate_ripng(config, vif_s_ipv6_base, ifname) + migrate_ospf(config, vif_s_ip_base, ifname) + migrate_ospfv3(config, vif_s_ipv6_base, ifname) 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)) - sys.exit(1) + exit(1) diff --git a/src/migration-scripts/interfaces/24-to-25 b/src/migration-scripts/interfaces/24-to-25 index 9aa6ea5e3..8fd79ecc6 100755 --- a/src/migration-scripts/interfaces/24-to-25 +++ b/src/migration-scripts/interfaces/24-to-25 @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021-2023 VyOS maintainers and contributors +# Copyright (C) 2021 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 @@ -14,374 +14,47 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -# Migrate Wireguard to store keys in CLI -# Migrate EAPoL to PKI configuration +# A VTI interface also requires an IPSec configuration - VyOS 1.2 supported +# having a VTI interface in the CLI but no IPSec configuration - drop VTI +# configuration if this is the case for VyOS 1.4 -import os import sys - from vyos.configtree import ConfigTree -from vyos.pki import CERT_BEGIN -from vyos.pki import load_certificate -from vyos.pki import load_crl -from vyos.pki import load_dh_parameters -from vyos.pki import load_private_key -from vyos.pki import encode_certificate -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 - -def wrapped_pem_to_config_value(pem): - out = [] - for line in pem.strip().split("\n"): - if not line or line.startswith("-----") or line[0] == '#': - continue - 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 - - if os.path.isfile(full_path): - if not os.access(full_path, os.R_OK): - run(f'sudo chmod 644 {full_path}') - - with open(full_path, 'r') as f: - output = f.read() - - return output -if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) +if __name__ == '__main__': + if len(sys.argv) < 2: + print("Must specify file name!") + sys.exit(1) -file_name = sys.argv[1] + file_name = sys.argv[1] -with open(file_name, 'r') as f: - config_file = f.read() + with open(file_name, 'r') as f: + config_file = f.read() -config = ConfigTree(config_file) + config = ConfigTree(config_file) + base = ['interfaces', 'vti'] + if not config.exists(base): + # Nothing to do + sys.exit(0) -AUTH_DIR = '/config/auth' -pki_base = ['pki'] - -# OpenVPN -base = ['interfaces', 'openvpn'] - -if config.exists(base): + ipsec_base = ['vpn', 'ipsec', 'site-to-site', 'peer'] for interface in config.list_nodes(base): - x509_base = base + [interface, 'tls'] - pki_name = f'openvpn_{interface}' - - if config.exists(base + [interface, 'shared-secret-key-file']): - if not config.exists(pki_base + ['openvpn', 'shared-secret']): - config.set(pki_base + ['openvpn', 'shared-secret']) - 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_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) - else: - print(f'Failed to migrate shared-secret-key on openvpn interface {interface}') - - config.delete(base + [interface, 'shared-secret-key-file']) - - if not config.exists(base + [interface, 'tls']): - continue - - if config.exists(base + [interface, 'tls', 'auth-file']): - if not config.exists(pki_base + ['openvpn', 'shared-secret']): - config.set(pki_base + ['openvpn', 'shared-secret']) - 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_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) - else: - print(f'Failed to migrate auth-key on openvpn interface {interface}') - - config.delete(base + [interface, 'tls', 'auth-file']) - - if config.exists(base + [interface, 'tls', 'crypt-file']): - if not config.exists(pki_base + ['openvpn', 'shared-secret']): - config.set(pki_base + ['openvpn', 'shared-secret']) - 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_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) - else: - print(f'Failed to migrate crypt-key on openvpn interface {interface}') - - config.delete(base + [interface, 'tls', 'crypt-file']) - - ca_certs = {} - - if config.exists(x509_base + ['ca-cert-file']): - if not config.exists(pki_base + ['ca']): - config.set(pki_base + ['ca']) - 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) - 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}') - - index += 1 - else: - print(f'Failed to migrate CA certificate on openvpn interface {interface}') - - config.delete(x509_base + ['ca-cert-file']) - - if config.exists(x509_base + ['crl-file']): - if not config.exists(pki_base + ['ca']): - config.set(pki_base + ['ca']) - 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}') - - with open(crl_path, 'r') as f: - crl_data = f.read() - crl = load_crl(crl_data, wrap_tags=False) - - 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: - crl_pem = encode_certificate(crl) - 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}') - - config.delete(x509_base + ['crl-file']) - - if config.exists(x509_base + ['cert-file']): - if not config.exists(pki_base + ['certificate']): - config.set(pki_base + ['certificate']) - 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}') - - with open(cert_path, 'r') as f: - cert_data = f.read() - cert = load_certificate(cert_data, wrap_tags=False) - - 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) - else: - print(f'Failed to migrate certificate on openvpn interface {interface}') - - config.delete(x509_base + ['cert-file']) - - 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}') - - with open(key_path, 'r') as f: - key_data = f.read() - key = load_private_key(key_data, passphrase=None, wrap_tags=False) - - 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)) - else: - print(f'Failed to migrate private key on openvpn interface {interface}') - - config.delete(x509_base + ['key-file']) - - if config.exists(x509_base + ['dh-file']): - if not config.exists(pki_base + ['dh']): - config.set(pki_base + ['dh']) - 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}') - - with open(dh_path, 'r') as f: - dh_data = f.read() - dh = load_dh_parameters(dh_data, wrap_tags=False) - - 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) - else: - print(f'Failed to migrate DH parameters on openvpn interface {interface}') - - config.delete(x509_base + ['dh-file']) - -# Wireguard -base = ['interfaces', 'wireguard'] - -if config.exists(base): - for interface in config.list_nodes(base): - private_key_path = base + [interface, 'private-key'] - - key_file = 'default' - 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' - - if not os.path.exists(full_key_path): - 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) - - for peer in config.list_nodes(base + [interface, 'peer']): - config.rename(base + [interface, 'peer', peer, 'pubkey'], 'public-key') - -# Ethernet EAPoL -base = ['interfaces', 'ethernet'] - -if config.exists(base): - for interface in config.list_nodes(base): - if not config.exists(base + [interface, 'eapol']): - continue - - x509_base = base + [interface, 'eapol'] - pki_name = f'eapol_{interface}' - - if config.exists(x509_base + ['ca-cert-file']): - if not config.exists(pki_base + ['ca']): - config.set(pki_base + ['ca']) - 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}') - - with open(cert_path, 'r') as f: - cert_data = f.read() - cert = load_certificate(cert_data, wrap_tags=False) - - if cert: - cert_pem = encode_certificate(cert) - config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) - config.set(x509_base + ['ca-certificate'], value=pki_name) - else: - print(f'Failed to migrate CA certificate on eapol config for interface {interface}') - - config.delete(x509_base + ['ca-cert-file']) - - if config.exists(x509_base + ['cert-file']): - if not config.exists(pki_base + ['certificate']): - config.set(pki_base + ['certificate']) - 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}') - - with open(cert_path, 'r') as f: - cert_data = f.read() - cert = load_certificate(cert_data, wrap_tags=False) - - 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) - else: - print(f'Failed to migrate certificate on eapol config for interface {interface}') - - config.delete(x509_base + ['cert-file']) - - 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}') - - with open(key_path, 'r') as f: - key_data = f.read() - key = load_private_key(key_data, passphrase=None, wrap_tags=False) - - 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)) - else: - print(f'Failed to migrate private key on eapol config for interface {interface}') - - config.delete(x509_base + ['key-file']) - -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)) - sys.exit(1) + found = False + if config.exists(ipsec_base): + for peer in config.list_nodes(ipsec_base): + if config.exists(ipsec_base + [peer, 'vti', 'bind']): + tmp = config.return_value(ipsec_base + [peer, 'vti', 'bind']) + if tmp == interface: + # Interface was found and we no longer need to search + # for it in our IPSec peers + found = True + break + if not found: + config.delete(base + [interface]) + + 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)) + sys.exit(1) diff --git a/src/migration-scripts/interfaces/25-to-26 b/src/migration-scripts/interfaces/25-to-26 index 4967a29fa..9aa6ea5e3 100755 --- a/src/migration-scripts/interfaces/25-to-26 +++ b/src/migration-scripts/interfaces/25-to-26 @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2022 VyOS maintainers and contributors +# Copyright (C) 2021-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 @@ -14,41 +14,374 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -# T4384: pppoe: replace default-route CLI option with common CLI nodes already -# present for DHCP +# Migrate Wireguard to store keys in CLI +# Migrate EAPoL to PKI configuration -from sys import argv +import os +import sys -from vyos.ethtool import Ethtool from vyos.configtree import ConfigTree +from vyos.pki import CERT_BEGIN +from vyos.pki import load_certificate +from vyos.pki import load_crl +from vyos.pki import load_dh_parameters +from vyos.pki import load_private_key +from vyos.pki import encode_certificate +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 -if len(argv) < 2: +def wrapped_pem_to_config_value(pem): + out = [] + for line in pem.strip().split("\n"): + if not line or line.startswith("-----") or line[0] == '#': + continue + 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 + + if os.path.isfile(full_path): + if not os.access(full_path, os.R_OK): + run(f'sudo chmod 644 {full_path}') + + with open(full_path, 'r') as f: + output = f.read() + + return output + +if len(sys.argv) < 2: print("Must specify file name!") - exit(1) + sys.exit(1) + +file_name = sys.argv[1] -file_name = argv[1] with open(file_name, 'r') as f: config_file = f.read() -base = ['interfaces', 'pppoe'] config = ConfigTree(config_file) -if not config.exists(base): - exit(0) +AUTH_DIR = '/config/auth' +pki_base = ['pki'] + +# OpenVPN +base = ['interfaces', 'openvpn'] + +if config.exists(base): + for interface in config.list_nodes(base): + x509_base = base + [interface, 'tls'] + pki_name = f'openvpn_{interface}' + + if config.exists(base + [interface, 'shared-secret-key-file']): + if not config.exists(pki_base + ['openvpn', 'shared-secret']): + config.set(pki_base + ['openvpn', 'shared-secret']) + 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_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) + else: + print(f'Failed to migrate shared-secret-key on openvpn interface {interface}') + + config.delete(base + [interface, 'shared-secret-key-file']) + + if not config.exists(base + [interface, 'tls']): + continue + + if config.exists(base + [interface, 'tls', 'auth-file']): + if not config.exists(pki_base + ['openvpn', 'shared-secret']): + config.set(pki_base + ['openvpn', 'shared-secret']) + 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_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) + else: + print(f'Failed to migrate auth-key on openvpn interface {interface}') + + config.delete(base + [interface, 'tls', 'auth-file']) + + if config.exists(base + [interface, 'tls', 'crypt-file']): + if not config.exists(pki_base + ['openvpn', 'shared-secret']): + config.set(pki_base + ['openvpn', 'shared-secret']) + 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_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) + else: + print(f'Failed to migrate crypt-key on openvpn interface {interface}') + + config.delete(base + [interface, 'tls', 'crypt-file']) + + ca_certs = {} + + if config.exists(x509_base + ['ca-cert-file']): + if not config.exists(pki_base + ['ca']): + config.set(pki_base + ['ca']) + 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) + 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}') + + index += 1 + else: + print(f'Failed to migrate CA certificate on openvpn interface {interface}') + + config.delete(x509_base + ['ca-cert-file']) + + if config.exists(x509_base + ['crl-file']): + if not config.exists(pki_base + ['ca']): + config.set(pki_base + ['ca']) + 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}') + + with open(crl_path, 'r') as f: + crl_data = f.read() + crl = load_crl(crl_data, wrap_tags=False) + + 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: + crl_pem = encode_certificate(crl) + 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}') + + config.delete(x509_base + ['crl-file']) + + if config.exists(x509_base + ['cert-file']): + if not config.exists(pki_base + ['certificate']): + config.set(pki_base + ['certificate']) + 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}') + + with open(cert_path, 'r') as f: + cert_data = f.read() + cert = load_certificate(cert_data, wrap_tags=False) + + 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) + else: + print(f'Failed to migrate certificate on openvpn interface {interface}') + + config.delete(x509_base + ['cert-file']) + + 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}') + + with open(key_path, 'r') as f: + key_data = f.read() + key = load_private_key(key_data, passphrase=None, wrap_tags=False) + + 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)) + else: + print(f'Failed to migrate private key on openvpn interface {interface}') + + config.delete(x509_base + ['key-file']) + + if config.exists(x509_base + ['dh-file']): + if not config.exists(pki_base + ['dh']): + config.set(pki_base + ['dh']) + 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}') + + with open(dh_path, 'r') as f: + dh_data = f.read() + dh = load_dh_parameters(dh_data, wrap_tags=False) + + 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) + else: + print(f'Failed to migrate DH parameters on openvpn interface {interface}') + + config.delete(x509_base + ['dh-file']) + +# Wireguard +base = ['interfaces', 'wireguard'] + +if config.exists(base): + for interface in config.list_nodes(base): + private_key_path = base + [interface, 'private-key'] + + key_file = 'default' + 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' + + if not os.path.exists(full_key_path): + 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) + + for peer in config.list_nodes(base + [interface, 'peer']): + config.rename(base + [interface, 'peer', peer, 'pubkey'], 'public-key') + +# Ethernet EAPoL +base = ['interfaces', 'ethernet'] + +if config.exists(base): + for interface in config.list_nodes(base): + if not config.exists(base + [interface, 'eapol']): + continue + + x509_base = base + [interface, 'eapol'] + pki_name = f'eapol_{interface}' + + if config.exists(x509_base + ['ca-cert-file']): + if not config.exists(pki_base + ['ca']): + config.set(pki_base + ['ca']) + 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}') + + with open(cert_path, 'r') as f: + cert_data = f.read() + cert = load_certificate(cert_data, wrap_tags=False) + + if cert: + cert_pem = encode_certificate(cert) + config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem)) + config.set(x509_base + ['ca-certificate'], value=pki_name) + else: + print(f'Failed to migrate CA certificate on eapol config for interface {interface}') + + config.delete(x509_base + ['ca-cert-file']) + + if config.exists(x509_base + ['cert-file']): + if not config.exists(pki_base + ['certificate']): + config.set(pki_base + ['certificate']) + 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}') + + with open(cert_path, 'r') as f: + cert_data = f.read() + cert = load_certificate(cert_data, wrap_tags=False) + + 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) + else: + print(f'Failed to migrate certificate on eapol config for interface {interface}') + + config.delete(x509_base + ['cert-file']) + + 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}') + + with open(key_path, 'r') as f: + key_data = f.read() + key = load_private_key(key_data, passphrase=None, wrap_tags=False) + + 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)) + else: + print(f'Failed to migrate private key on eapol config for interface {interface}') -for ifname in config.list_nodes(base): - tmp_config = base + [ifname, 'default-route'] - if config.exists(tmp_config): - # Retrieve current config value - value = config.return_value(tmp_config) - # Delete old Config node - config.delete(tmp_config) - if value == 'none': - config.set(base + [ifname, 'no-default-route']) + config.delete(x509_base + ['key-file']) try: with open(file_name, 'w') as f: f.write(config.to_string()) except OSError as e: - print(f'Failed to save the modified config: {e}') - exit(1) + print("Failed to save the modified config: {}".format(e)) + sys.exit(1) diff --git a/src/migration-scripts/interfaces/26-to-27 b/src/migration-scripts/interfaces/26-to-27 index a0d043d11..4967a29fa 100755 --- a/src/migration-scripts/interfaces/26-to-27 +++ b/src/migration-scripts/interfaces/26-to-27 @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023 VyOS maintainers and contributors +# Copyright (C) 2022 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 @@ -14,8 +14,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -# T4995: pppoe, wwan, sstpc-client rename "authentication user" CLI node -# to "authentication username" +# T4384: pppoe: replace default-route CLI option with common CLI nodes already +# present for DHCP from sys import argv @@ -30,16 +30,21 @@ file_name = argv[1] with open(file_name, 'r') as f: config_file = f.read() +base = ['interfaces', 'pppoe'] config = ConfigTree(config_file) -for type in ['pppoe', 'sstpc-client', 'wwam']: - base = ['interfaces', type] - if not config.exists(base): - continue - for interface in config.list_nodes(base): - auth_base = base + [interface, 'authentication', 'user'] - if config.exists(auth_base): - config.rename(auth_base, 'username') +if not config.exists(base): + exit(0) + +for ifname in config.list_nodes(base): + tmp_config = base + [ifname, 'default-route'] + if config.exists(tmp_config): + # Retrieve current config value + value = config.return_value(tmp_config) + # Delete old Config node + config.delete(tmp_config) + if value == 'none': + config.set(base + [ifname, 'no-default-route']) try: with open(file_name, 'w') as f: diff --git a/src/migration-scripts/interfaces/27-to-28 b/src/migration-scripts/interfaces/27-to-28 index ad5bfa653..a0d043d11 100755 --- a/src/migration-scripts/interfaces/27-to-28 +++ b/src/migration-scripts/interfaces/27-to-28 @@ -14,8 +14,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -# T5034: tunnel: rename "multicast enable" CLI node to "enable-multicast" -# valueless node. +# T4995: pppoe, wwan, sstpc-client rename "authentication user" CLI node +# to "authentication username" from sys import argv @@ -30,21 +30,16 @@ file_name = argv[1] with open(file_name, 'r') as f: config_file = f.read() -base = ['interfaces', 'tunnel'] config = ConfigTree(config_file) -if not config.exists(base): - exit(0) - -for ifname in config.list_nodes(base): - multicast_base = base + [ifname, 'multicast'] - if config.exists(multicast_base): - tmp = config.return_value(multicast_base) - print(tmp) - # Delete old Config node - config.delete(multicast_base) - if tmp == 'enable': - config.set(base + [ifname, 'enable-multicast']) +for type in ['pppoe', 'sstpc-client', 'wwam']: + base = ['interfaces', type] + if not config.exists(base): + continue + for interface in config.list_nodes(base): + auth_base = base + [interface, 'authentication', 'user'] + if config.exists(auth_base): + config.rename(auth_base, 'username') try: with open(file_name, 'w') as f: diff --git a/src/migration-scripts/interfaces/28-to-29 b/src/migration-scripts/interfaces/28-to-29 index acb6ee1fb..ad5bfa653 100755 --- a/src/migration-scripts/interfaces/28-to-29 +++ b/src/migration-scripts/interfaces/28-to-29 @@ -14,7 +14,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -# T5286: remove XDP support in favour of VPP +# T5034: tunnel: rename "multicast enable" CLI node to "enable-multicast" +# valueless node. from sys import argv @@ -29,17 +30,21 @@ file_name = argv[1] with open(file_name, 'r') as f: config_file = f.read() -supports_xdp = ['bonding', 'ethernet'] +base = ['interfaces', 'tunnel'] config = ConfigTree(config_file) -for if_type in supports_xdp: - base = ['interfaces', if_type] - if not config.exists(base): - continue - for interface in config.list_nodes(base): - if_base = base + [interface] - if config.exists(if_base + ['xdp']): - config.delete(if_base + ['xdp']) +if not config.exists(base): + exit(0) + +for ifname in config.list_nodes(base): + multicast_base = base + [ifname, 'multicast'] + if config.exists(multicast_base): + tmp = config.return_value(multicast_base) + print(tmp) + # Delete old Config node + config.delete(multicast_base) + if tmp == 'enable': + config.set(base + [ifname, 'enable-multicast']) try: with open(file_name, 'w') as f: diff --git a/src/migration-scripts/interfaces/29-to-30 b/src/migration-scripts/interfaces/29-to-30 index 97e1b329c..acb6ee1fb 100755 --- a/src/migration-scripts/interfaces/29-to-30 +++ b/src/migration-scripts/interfaces/29-to-30 @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021-2023 VyOS maintainers and contributors +# 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 @@ -13,42 +13,37 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -# -# Deletes Wireguard peers if they have the same public key as the router has. -import sys + +# T5286: remove XDP support in favour of VPP + +from sys import argv + +from vyos.ethtool import Ethtool from vyos.configtree import ConfigTree -from vyos.utils.network import is_wireguard_key_pair -if __name__ == '__main__': - if len(sys.argv) < 2: - print("Must specify file name!") - sys.exit(1) +if len(argv) < 2: + print("Must specify file name!") + exit(1) - file_name = sys.argv[1] +file_name = argv[1] +with open(file_name, 'r') as f: + config_file = f.read() - with open(file_name, 'r') as f: - config_file = f.read() +supports_xdp = ['bonding', 'ethernet'] +config = ConfigTree(config_file) - config = ConfigTree(config_file) - base = ['interfaces', 'wireguard'] +for if_type in supports_xdp: + base = ['interfaces', if_type] if not config.exists(base): - # Nothing to do - sys.exit(0) + continue for interface in config.list_nodes(base): - private_key = config.return_value(base + [interface, 'private-key']) - interface_base = base + [interface] - if config.exists(interface_base + ['peer']): - for peer in config.list_nodes(interface_base + ['peer']): - peer_base = interface_base + ['peer', peer] - peer_public_key = config.return_value(peer_base + ['public-key']) - if config.exists(peer_base + ['public-key']): - if not config.exists(peer_base + ['disable']) \ - and is_wireguard_key_pair(private_key, peer_public_key): - config.set(peer_base + ['disable']) - - 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)) - sys.exit(1) + if_base = base + [interface] + if config.exists(if_base + ['xdp']): + config.delete(if_base + ['xdp']) + +try: + with open(file_name, 'w') as f: + f.write(config.to_string()) +except OSError as e: + print(f'Failed to save the modified config: {e}') + exit(1) |