diff options
Diffstat (limited to 'src/conf_mode/interfaces-openvpn.py')
-rwxr-xr-x | src/conf_mode/interfaces-openvpn.py | 82 |
1 files changed, 51 insertions, 31 deletions
diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py index 708ac8f91..ea8e1a7c4 100755 --- a/src/conf_mode/interfaces-openvpn.py +++ b/src/conf_mode/interfaces-openvpn.py @@ -25,10 +25,11 @@ from time import sleep from shutil import rmtree from vyos.config import Config +from vyos.configdict import list_diff from vyos.ifconfig import VTunIf from vyos.template import render from vyos.util import call, chown, chmod_600, chmod_755 -from vyos.validate import is_addr_assigned, is_bridge_member, is_ipv4 +from vyos.validate import is_addr_assigned, is_member, is_ipv4 from vyos import ConfigError user = 'openvpn' @@ -40,7 +41,6 @@ default_config_data = { 'auth_pass': '', 'auth_user_pass_file': '', 'auth': False, - 'bridge_member': [], 'compress_lzo': False, 'deleted': False, 'description': '', @@ -49,8 +49,10 @@ default_config_data = { 'encryption': '', 'hash': '', 'intf': '', + 'ipv6_accept_ra': 1, 'ipv6_autoconf': 0, - 'ipv6_eui64_prefix': '', + 'ipv6_eui64_prefix': [], + 'ipv6_eui64_prefix_remove': [], 'ipv6_forwarding': 1, 'ipv6_dup_addr_detect': 1, 'ipv6_local_address': [], @@ -197,21 +199,16 @@ def get_config(): openvpn['intf'] = os.environ['VYOS_TAGNODE_VALUE'] openvpn['auth_user_pass_file'] = f"/run/openvpn/{openvpn['intf']}.pw" + # check if interface is member of a bridge + openvpn['is_bridge_member'] = is_member(conf, openvpn['intf'], 'bridge') + # Check if interface instance has been removed if not conf.exists('interfaces openvpn ' + openvpn['intf']): openvpn['deleted'] = True - # check if interface is member if a bridge - openvpn['is_bridge_member'] = is_bridge_member(conf, openvpn['intf']) return openvpn - # Check if we belong to any bridge interface - for bridge in conf.list_nodes('interfaces bridge'): - for intf in conf.list_nodes('interfaces bridge {} member interface'.format(bridge)): - if intf == openvpn['intf']: - openvpn['bridge_member'].append(intf) - # bridged server should not have a pool by default (but can be specified manually) - if openvpn['bridge_member']: + if openvpn['is_bridge_member']: openvpn['server_pool'] = False openvpn['server_ipv6_pool'] = False @@ -314,9 +311,21 @@ def get_config(): if conf.exists('ipv6 address autoconf'): openvpn['ipv6_autoconf'] = 1 - # Get prefix for IPv6 addressing based on MAC address (EUI-64) + # Get prefixes for IPv6 addressing based on MAC address (EUI-64) if conf.exists('ipv6 address eui64'): - openvpn['ipv6_eui64_prefix'] = conf.return_value('ipv6 address eui64') + openvpn['ipv6_eui64_prefix'] = conf.return_values('ipv6 address eui64') + + # Determine currently effective EUI64 addresses - to determine which + # address is no longer valid and needs to be removed + eff_addr = conf.return_effective_values('ipv6 address eui64') + openvpn['ipv6_eui64_prefix_remove'] = list_diff(eff_addr, openvpn['ipv6_eui64_prefix']) + + # Remove the default link-local address if set. + if conf.exists('ipv6 address no-default-link-local'): + openvpn['ipv6_eui64_prefix_remove'].append('fe80::/64') + else: + # add the link-local by default to make IPv6 work + openvpn['ipv6_eui64_prefix'].append('fe80::/64') # Disable IPv6 forwarding on this interface if conf.exists('ipv6 disable-forwarding'): @@ -326,6 +335,11 @@ def get_config(): if conf.exists('ipv6 dup-addr-detect-transmits'): openvpn['ipv6_dup_addr_detect'] = int(conf.return_value('ipv6 dup-addr-detect-transmits')) + # to make IPv6 SLAAC and DHCPv6 work with forwarding=1, + # accept_ra must be 2 + if openvpn['ipv6_autoconf'] or 'dhcpv6' in openvpn['address']: + openvpn['ipv6_accept_ra'] = 2 + # OpenVPN operation mode if conf.exists('mode'): openvpn['mode'] = conf.return_value('mode') @@ -583,7 +597,7 @@ def get_config(): default_server = getDefaultServer(server_network_v4, openvpn['server_topology'], openvpn['type']) if default_server: # server-bridge doesn't require a pool so don't set defaults for it - if openvpn['server_pool'] and not openvpn['bridge_member']: + if openvpn['server_pool'] and not openvpn['is_bridge_member']: if not openvpn['server_pool_start']: openvpn['server_pool_start'] = default_server['pool_start'] @@ -621,22 +635,15 @@ def get_config(): def verify(openvpn): if openvpn['deleted']: if openvpn['is_bridge_member']: - interface = openvpn['intf'] - bridge = openvpn['is_bridge_member'] - raise ConfigError(f'Interface "{interface}" can not be deleted as it belongs to bridge "{bridge}"!') - + raise ConfigError(( + f'Cannot delete interface "{openvpn["intf"]}" as it is a ' + f'member of bridge "{openvpn["is_bridge_menber"]}"!')) return None if not openvpn['mode']: raise ConfigError('Must specify OpenVPN operation mode') - # Checks which need to be performed on interface rmeoval - if openvpn['deleted']: - # OpenVPN interface can not be deleted if it's still member of a bridge - if openvpn['bridge_member']: - raise ConfigError('Can not delete {} as it is a member interface of bridge {}!'.format(openvpn['intf'], bridge)) - # Check if we have disabled ncp and at the same time specified ncp-ciphers if openvpn['disable_ncp'] and openvpn['ncp_ciphers']: raise ConfigError('Cannot specify both "encryption disable-ncp" and "encryption ncp-ciphers"') @@ -666,9 +673,9 @@ def verify(openvpn): if openvpn['ncp_ciphers']: raise ConfigError('encryption ncp-ciphers cannot be specified in site-to-site mode, only server or client') - if openvpn['mode'] == 'site-to-site' and not openvpn['bridge_member']: + if openvpn['mode'] == 'site-to-site' and not openvpn['is_bridge_member']: if not (openvpn['local_address'] or openvpn['ipv6_local_address']): - raise ConfigError('Must specify "local-address" or "bridge member interface"') + raise ConfigError('Must specify "local-address" or add interface to bridge') if len(openvpn['local_address']) > 1 or len(openvpn['ipv6_local_address']) > 1: raise ConfigError('Cannot specify more than 1 IPv4 and 1 IPv6 "local-address"') @@ -747,8 +754,8 @@ def verify(openvpn): raise ConfigError(f'Client "{client["name"]}" IP {client["ip"][0]} not in server subnet {subnet}') else: - if not openvpn['bridge_member']: - raise ConfigError('Must specify "server subnet" or "bridge member interface" in server mode') + if not openvpn['is_bridge_member']: + raise ConfigError('Must specify "server subnet" or add interface to bridge in server mode') if openvpn['server_pool']: if not (openvpn['server_pool_start'] and openvpn['server_pool_stop']): @@ -1041,15 +1048,28 @@ def apply(openvpn): o = VTunIf(interface) # update interface description used e.g. within SNMP o.set_alias(openvpn['description']) + # IPv6 accept RA + o.set_ipv6_accept_ra(openvpn['ipv6_accept_ra']) # IPv6 address autoconfiguration o.set_ipv6_autoconf(openvpn['ipv6_autoconf']) - # IPv6 EUI-based address - o.set_ipv6_eui64_address(openvpn['ipv6_eui64_prefix']) # IPv6 forwarding o.set_ipv6_forwarding(openvpn['ipv6_forwarding']) # IPv6 Duplicate Address Detection (DAD) tries o.set_ipv6_dad_messages(openvpn['ipv6_dup_addr_detect']) + # IPv6 EUI-based addresses - only in TAP mode (TUN's have no MAC) + # If MAC has changed, old EUI64 addresses won't get deleted, + # but this isn't easy to solve, so leave them. + # This is even more difficult as openvpn uses a random MAC for the + # initial interface creation, unless set by 'lladdr'. + # NOTE: right now the interface is always deleted. For future + # compatibility when tap's are not deleted, leave the del_ in + if openvpn['mode'] == 'tap': + for addr in openvpn['ipv6_eui64_prefix_remove']: + o.del_ipv6_eui64_address(addr) + for addr in openvpn['ipv6_eui64_prefix']: + o.add_ipv6_eui64_address(addr) + except: pass |