diff options
| -rw-r--r-- | interface-definitions/include/version/interfaces-version.xml.i | 2 | ||||
| -rw-r--r-- | python/vyos/validate.py | 19 | ||||
| -rwxr-xr-x | smoketest/scripts/cli/test_interfaces_wireguard.py | 29 | ||||
| -rwxr-xr-x | src/conf_mode/interfaces-wireguard.py | 7 | ||||
| -rwxr-xr-x | src/migration-scripts/interfaces/29-to-30 | 54 | 
5 files changed, 108 insertions, 3 deletions
| diff --git a/interface-definitions/include/version/interfaces-version.xml.i b/interface-definitions/include/version/interfaces-version.xml.i index 4a2b3f9ab..3d11ce888 100644 --- a/interface-definitions/include/version/interfaces-version.xml.i +++ b/interface-definitions/include/version/interfaces-version.xml.i @@ -1,3 +1,3 @@  <!-- include start from include/version/interfaces-version.xml.i --> -<syntaxVersion component='interfaces' version='29'></syntaxVersion> +<syntaxVersion component='interfaces' version='30'></syntaxVersion>  <!-- include end --> diff --git a/python/vyos/validate.py b/python/vyos/validate.py index 567f4c972..b149b258f 100644 --- a/python/vyos/validate.py +++ b/python/vyos/validate.py @@ -1,4 +1,4 @@ -# Copyright 2018-2021 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 2018-2023 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 @@ -302,3 +302,20 @@ def has_vrf_configured(conf, intf):      conf.set_level(old_level)      return ret + +def is_wireguard_key_pair(private_key: str, public_key:str) -> bool: +    """ +     Checks if public/private keys are keypair +    :param private_key: Wireguard private key +    :type private_key: str +    :param public_key: Wireguard public key +    :type public_key: str +    :return: If public/private keys are keypair returns True else False +    :rtype: bool +    """ +    from vyos.utils.process import cmd +    gen_public_key = cmd('wg pubkey', input=private_key) +    if gen_public_key == public_key: +        return True +    else: +        return False diff --git a/smoketest/scripts/cli/test_interfaces_wireguard.py b/smoketest/scripts/cli/test_interfaces_wireguard.py index 14fc8d109..f84ce159d 100755 --- a/smoketest/scripts/cli/test_interfaces_wireguard.py +++ b/smoketest/scripts/cli/test_interfaces_wireguard.py @@ -100,5 +100,34 @@ class WireGuardInterfaceTest(VyOSUnitTestSHIM.TestCase):          self.cli_delete(base_path + [interface, 'peer', 'PEER01'])          self.cli_commit() +    def test_wireguard_same_public_key(self): +        # T2939: Create WireGuard interfaces with associated peers. +        # Remove one of the configured peers. +        # T4774: Test prevention of duplicate peer public keys +        interface = 'wg0' +        port = '12345' +        privkey = 'OOjcXGfgQlAuM6q8Z9aAYduCua7pxf7UKYvIqoUPoGQ=' +        pubkey_fail = 'eiVeYKq66mqKLbrZLzlckSP9voaw8jSFyVNiNTdZDjU=' +        pubkey_ok = 'ebFx/1G0ti8tvuZd94sEIosAZZIznX+dBAKG/8DFm0I=' + +        self.cli_set(base_path + [interface, 'address', '172.16.0.1/24']) +        self.cli_set(base_path + [interface, 'private-key', privkey]) + +        self.cli_set(base_path + [interface, 'peer', 'PEER01', 'public-key', pubkey_fail]) +        self.cli_set(base_path + [interface, 'peer', 'PEER01', 'port', port]) +        self.cli_set(base_path + [interface, 'peer', 'PEER01', 'allowed-ips', '10.205.212.10/32']) +        self.cli_set(base_path + [interface, 'peer', 'PEER01', 'address', '192.0.2.1']) + +        # The same pubkey as the interface wg0 +        with self.assertRaises(ConfigSessionError): +            self.cli_commit() + +        self.cli_set(base_path + [interface, 'peer', 'PEER01', 'public-key', pubkey_ok]) + +        # Commit peers +        self.cli_commit() + +        self.assertTrue(os.path.isdir(f'/sys/class/net/{interface}')) +  if __name__ == '__main__':      unittest.main(verbosity=2) diff --git a/src/conf_mode/interfaces-wireguard.py b/src/conf_mode/interfaces-wireguard.py index a02baba82..40404d091 100755 --- a/src/conf_mode/interfaces-wireguard.py +++ b/src/conf_mode/interfaces-wireguard.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2018-2022 VyOS maintainers and contributors +# Copyright (C) 2018-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 @@ -29,10 +29,12 @@ from vyos.configverify import verify_bond_bridge_member  from vyos.ifconfig import WireGuardIf  from vyos.utils.kernel import check_kmod  from vyos.utils.network import check_port_availability +from vyos.validate import is_wireguard_key_pair  from vyos import ConfigError  from vyos import airbag  airbag.enable() +  def get_config(config=None):      """      Retrive CLI config as dictionary. Dictionary can never be empty, as at least the @@ -105,6 +107,9 @@ def verify(wireguard):          if peer['public_key'] in public_keys:              raise ConfigError(f'Duplicate public-key defined on peer "{tmp}"') +        if 'disable' not in peer and is_wireguard_key_pair(wireguard['private_key'], peer['public_key']): +            raise ConfigError(f'Peer "{tmp}" has the same public key as the interface "{wireguard["ifname"]}"') +          public_keys.append(peer['public_key'])  def apply(wireguard): diff --git a/src/migration-scripts/interfaces/29-to-30 b/src/migration-scripts/interfaces/29-to-30 new file mode 100755 index 000000000..54def1be9 --- /dev/null +++ b/src/migration-scripts/interfaces/29-to-30 @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# +# 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 +# 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/>. +# +# Deletes Wireguard peers if they have the same public key as the router has. +import sys +from vyos.configtree import ConfigTree +from vyos.validate import is_wireguard_key_pair + +if __name__ == '__main__': +    if len(sys.argv) < 2: +        print("Must specify file name!") +        sys.exit(1) + +    file_name = sys.argv[1] + +    with open(file_name, 'r') as f: +        config_file = f.read() + +    config = ConfigTree(config_file) +    base = ['interfaces', 'wireguard'] +    if not config.exists(base): +        # Nothing to do +        sys.exit(0) +    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) | 
