def verify(bridge): if bridge['dhcpv6_prm_only'] and bridge['dhcpv6_temporary']: raise ConfigError( 'DHCPv6 temporary and parameters-only options are mutually exclusive!' ) vrf_name = bridge['vrf'] if vrf_name and vrf_name not in interfaces(): raise ConfigError(f'VRF "{vrf_name}" does not exist') conf = Config() for intf in bridge['member']: # the interface must exist prior adding it to a bridge if intf['name'] not in interfaces(): raise ConfigError( (f'Cannot add nonexistent interface "{intf["name"]}" ' f'to bridge "{bridge["intf"]}"')) if intf['name'] == 'lo': raise ConfigError( 'Loopback interface "lo" can not be added to a bridge') # bridge members aren't allowed to be members of another bridge for br in conf.list_nodes('interfaces bridge'): # it makes no sense to verify ourself in this case if br == bridge['intf']: continue tmp = conf.list_nodes(f'interfaces bridge {br} member interface') if intf['name'] in tmp: raise ConfigError(( f'Cannot add interface "{intf["name"]}" to bridge ' f'"{bridge["intf"]}", it is already a member of bridge "{br}"!' )) # bridge members are not allowed to be bond members tmp = is_member(conf, intf['name'], 'bonding') if tmp: raise ConfigError( (f'Cannot add interface "{intf["name"]}" to bridge ' f'"{bridge["intf"]}", it is already a member of bond "{tmp}"!' )) # bridge members must not have an assigned address if has_address_configured(conf, intf['name']): raise ConfigError( (f'Cannot add interface "{intf["name"]}" to bridge ' f'"{bridge["intf"]}", it has an address assigned!')) return None
def get_config(): dummy = deepcopy(default_config_data) conf = Config() # determine tagNode instance if 'VYOS_TAGNODE_VALUE' not in os.environ: raise ConfigError('Interface (VYOS_TAGNODE_VALUE) not specified') dummy['intf'] = os.environ['VYOS_TAGNODE_VALUE'] # check if we are a member of any bridge dummy['is_bridge_member'] = is_member(conf, dummy['intf'], 'bridge') # Check if interface has been removed if not conf.exists('interfaces dummy ' + dummy['intf']): dummy['deleted'] = True return dummy # set new configuration level conf.set_level('interfaces dummy ' + dummy['intf']) # retrieve configured interface addresses if conf.exists('address'): dummy['address'] = conf.return_values('address') # retrieve interface description if conf.exists('description'): dummy['description'] = conf.return_value('description') # Disable this interface if conf.exists('disable'): dummy['disable'] = True # Determine interface addresses (currently effective) - to determine which # address is no longer valid and needs to be removed from the interface eff_addr = conf.return_effective_values('address') act_addr = conf.return_values('address') dummy['address_remove'] = list_diff(eff_addr, act_addr) # retrieve VRF instance if conf.exists('vrf'): dummy['vrf'] = conf.return_value('vrf') return dummy
def get_config(): vxlan = deepcopy(default_config_data) conf = Config() # determine tagNode instance if 'VYOS_TAGNODE_VALUE' not in os.environ: raise ConfigError('Interface (VYOS_TAGNODE_VALUE) not specified') vxlan['intf'] = os.environ['VYOS_TAGNODE_VALUE'] # check if interface is member if a bridge vxlan['is_bridge_member'] = is_member(conf, vxlan['intf'], 'bridge') # Check if interface has been removed if not conf.exists('interfaces vxlan ' + vxlan['intf']): vxlan['deleted'] = True return vxlan # set new configuration level conf.set_level('interfaces vxlan ' + vxlan['intf']) # retrieve configured interface addresses if conf.exists('address'): vxlan['address'] = conf.return_values('address') # retrieve interface description if conf.exists('description'): vxlan['description'] = conf.return_value('description') # Disable this interface if conf.exists('disable'): vxlan['disable'] = True # VXLAN multicast grou if conf.exists('group'): vxlan['group'] = conf.return_value('group') # ARP cache entry timeout in seconds if conf.exists('ip arp-cache-timeout'): vxlan['ip_arp_cache_tmo'] = int( conf.return_value('ip arp-cache-timeout')) # ARP filter configuration if conf.exists('ip disable-arp-filter'): vxlan['ip_disable_arp_filter'] = 0 # ARP enable accept if conf.exists('ip enable-arp-accept'): vxlan['ip_enable_arp_accept'] = 1 # ARP enable announce if conf.exists('ip enable-arp-announce'): vxlan['ip_enable_arp_announce'] = 1 # ARP enable ignore if conf.exists('ip enable-arp-ignore'): vxlan['ip_enable_arp_ignore'] = 1 # Enable proxy-arp on this interface if conf.exists('ip enable-proxy-arp'): vxlan['ip_proxy_arp'] = 1 # Enable acquisition of IPv6 address using stateless autoconfig (SLAAC) if conf.exists('ipv6 address autoconf'): vxlan['ipv6_autoconf'] = 1 # Get prefixes for IPv6 addressing based on MAC address (EUI-64) if conf.exists('ipv6 address eui64'): vxlan['ipv6_eui64_prefix'] = conf.return_values('ipv6 address eui64') # Remove the default link-local address if set. if not (conf.exists('ipv6 address no-default-link-local') or vxlan['is_bridge_member']): # add the link-local by default to make IPv6 work vxlan['ipv6_eui64_prefix'].append('fe80::/64') # Disable IPv6 forwarding on this interface if conf.exists('ipv6 disable-forwarding'): vxlan['ipv6_forwarding'] = 0 # IPv6 Duplicate Address Detection (DAD) tries if conf.exists('ipv6 dup-addr-detect-transmits'): vxlan['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 vxlan['ipv6_autoconf'] or 'dhcpv6' in vxlan['address']: vxlan['ipv6_accept_ra'] = 2 # VXLAN source address if conf.exists('source-address'): vxlan['source_address'] = conf.return_value('source-address') # VXLAN underlay interface if conf.exists('source-interface'): vxlan['source_interface'] = conf.return_value('source-interface') # Maximum Transmission Unit (MTU) if conf.exists('mtu'): vxlan['mtu'] = int(conf.return_value('mtu')) # Remote address of VXLAN tunnel if conf.exists('remote'): vxlan['remote'] = conf.return_value('remote') # Remote port of VXLAN tunnel if conf.exists('port'): vxlan['remote_port'] = int(conf.return_value('port')) # Virtual Network Identifier if conf.exists('vni'): vxlan['vni'] = conf.return_value('vni') return vxlan
def get_config(): l2tpv3 = deepcopy(default_config_data) conf = Config() # determine tagNode instance if 'VYOS_TAGNODE_VALUE' not in os.environ: raise ConfigError('Interface (VYOS_TAGNODE_VALUE) not specified') l2tpv3['intf'] = os.environ['VYOS_TAGNODE_VALUE'] # check if interface is member of a bridge l2tpv3['is_bridge_member'] = is_member(conf, l2tpv3['intf'], 'bridge') # Check if interface has been removed if not conf.exists('interfaces l2tpv3 ' + l2tpv3['intf']): l2tpv3['deleted'] = True interface = l2tpv3['intf'] # to delete the l2tpv3 interface we need the current tunnel_id and session_id if conf.exists_effective(f'interfaces l2tpv3 {interface} tunnel-id'): l2tpv3['tunnel_id'] = conf.return_effective_value( f'interfaces l2tpv3 {interface} tunnel-id') if conf.exists_effective(f'interfaces l2tpv3 {interface} session-id'): l2tpv3['session_id'] = conf.return_effective_value( f'interfaces l2tpv3 {interface} session-id') return l2tpv3 # set new configuration level conf.set_level('interfaces l2tpv3 ' + l2tpv3['intf']) # retrieve configured interface addresses if conf.exists('address'): l2tpv3['address'] = conf.return_values('address') # retrieve interface description if conf.exists('description'): l2tpv3['description'] = conf.return_value('description') # get tunnel destination port if conf.exists('destination-port'): l2tpv3['remote_port'] = int(conf.return_value('destination-port')) # Disable this interface if conf.exists('disable'): l2tpv3['disable'] = True # get tunnel encapsulation type if conf.exists('encapsulation'): l2tpv3['encapsulation'] = conf.return_value('encapsulation') # get tunnel local ip address if conf.exists('local-ip'): l2tpv3['local_address'] = conf.return_value('local-ip') # Enable acquisition of IPv6 address using stateless autoconfig (SLAAC) if conf.exists('ipv6 address autoconf'): l2tpv3['ipv6_autoconf'] = 1 # Get prefixes for IPv6 addressing based on MAC address (EUI-64) if conf.exists('ipv6 address eui64'): l2tpv3['ipv6_eui64_prefix'] = conf.return_values('ipv6 address eui64') # Remove the default link-local address if set. if not (conf.exists('ipv6 address no-default-link-local') or l2tpv3['is_bridge_member']): # add the link-local by default to make IPv6 work l2tpv3['ipv6_eui64_prefix'].append('fe80::/64') # Disable IPv6 forwarding on this interface if conf.exists('ipv6 disable-forwarding'): l2tpv3['ipv6_forwarding'] = 0 # IPv6 Duplicate Address Detection (DAD) tries if conf.exists('ipv6 dup-addr-detect-transmits'): l2tpv3['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 l2tpv3['ipv6_autoconf'] or 'dhcpv6' in l2tpv3['address']: l2tpv3['ipv6_accept_ra'] = 2 # Maximum Transmission Unit (MTU) if conf.exists('mtu'): l2tpv3['mtu'] = int(conf.return_value('mtu')) # Remote session id if conf.exists('peer-session-id'): l2tpv3['peer_session_id'] = conf.return_value('peer-session-id') # Remote tunnel id if conf.exists('peer-tunnel-id'): l2tpv3['peer_tunnel_id'] = conf.return_value('peer-tunnel-id') # Remote address of L2TPv3 tunnel if conf.exists('remote-ip'): l2tpv3['remote_address'] = conf.return_value('remote-ip') # Local session id if conf.exists('session-id'): l2tpv3['session_id'] = conf.return_value('session-id') # get local tunnel port if conf.exists('source-port'): l2tpv3['local_port'] = conf.return_value('source-port') # get local tunnel id if conf.exists('tunnel-id'): l2tpv3['tunnel_id'] = conf.return_value('tunnel-id') return l2tpv3
def get_config(): macsec = deepcopy(default_config_data) conf = Config() # determine tagNode instance if 'VYOS_TAGNODE_VALUE' not in os.environ: raise ConfigError('Interface (VYOS_TAGNODE_VALUE) not specified') macsec['intf'] = os.environ['VYOS_TAGNODE_VALUE'] base_path = ['interfaces', 'macsec', macsec['intf']] # check if we are a member of any bridge macsec['is_bridge_member'] = is_member(conf, macsec['intf'], 'bridge') # Check if interface has been removed if not conf.exists(base_path): macsec['deleted'] = True # When stopping wpa_supplicant we need to stop it via the physical # interface - thus we need to retrieve ir from the effective config if conf.exists_effective(base_path + ['source-interface']): macsec['source_interface'] = conf.return_effective_value( base_path + ['source-interface']) return macsec # set new configuration level conf.set_level(base_path) # retrieve configured interface addresses if conf.exists(['address']): macsec['address'] = conf.return_values(['address']) # retrieve interface description if conf.exists(['description']): macsec['description'] = conf.return_value(['description']) # Disable this interface if conf.exists(['disable']): macsec['disable'] = True # retrieve interface cipher if conf.exists(['security', 'cipher']): macsec['security_cipher'] = conf.return_value(['security', 'cipher']) # Enable optional MACsec encryption if conf.exists(['security', 'encrypt']): macsec['security_encrypt'] = True # Secure Connectivity Association Key if conf.exists(['security', 'mka', 'cak']): macsec['security_mka_cak'] = conf.return_value( ['security', 'mka', 'cak']) # Secure Connectivity Association Name if conf.exists(['security', 'mka', 'ckn']): macsec['security_mka_ckn'] = conf.return_value( ['security', 'mka', 'ckn']) # MACsec Key Agreement protocol (MKA) actor priority if conf.exists(['security', 'mka', 'priority']): macsec['security_mka_priority'] = conf.return_value( ['security', 'mka', 'priority']) # IEEE 802.1X/MACsec replay protection if conf.exists(['security', 'replay-window']): macsec['security_replay_window'] = conf.return_value( ['security', 'replay-window']) # Physical interface if conf.exists(['source-interface']): macsec['source_interface'] = conf.return_value(['source-interface']) # Determine interface addresses (currently effective) - to determine which # address is no longer valid and needs to be removed from the interface eff_addr = conf.return_effective_values(['address']) act_addr = conf.return_values(['address']) macsec['address_remove'] = list_diff(eff_addr, act_addr) # retrieve VRF instance if conf.exists(['vrf']): macsec['vrf'] = conf.return_value(['vrf']) return macsec
def verify(bond): if bond['deleted']: if bond['is_bridge_member']: raise ConfigError( (f'Cannot delete interface "{bond["intf"]}" as it is a ' f'member of bridge "{bond["is_bridge_member"]}"!')) return None if len(bond['arp_mon_tgt']) > 16: raise ConfigError('The maximum number of arp-monitor targets is 16') if bond['primary']: if bond['mode'] not in ['active-backup', 'balance-tlb', 'balance-alb']: raise ConfigError( ('Mode dependency failed, primary not supported in mode ' f'"{bond["mode"]}"!')) if (bond['is_bridge_member'] and (bond['address'] or bond['ipv6_eui64_prefix'] or bond['ipv6_autoconf'])): raise ConfigError( (f'Cannot assign address to interface "{bond["intf"]}" ' f'as it is a member of bridge "{bond["is_bridge_member"]}"!')) if bond['vrf']: if bond['vrf'] not in interfaces(): raise ConfigError(f'VRF "{bond["vrf"]}" does not exist') if bond['is_bridge_member']: raise ConfigError( (f'Interface "{bond["intf"]}" cannot be member of VRF ' f'"{bond["vrf"]}" and bridge {bond["is_bridge_member"]} ' f'at the same time!')) # use common function to verify VLAN configuration verify_vlan_config(bond) conf = Config() for intf in bond['member']: # check if member interface is "real" if intf not in interfaces(): raise ConfigError(f'Interface {intf} does not exist!') # a bonding member interface is only allowed to be assigned to one bond! all_bonds = conf.list_nodes('interfaces bonding') # We do not need to check our own bond all_bonds.remove(bond['intf']) for tmp in all_bonds: if conf.exists('interfaces bonding {tmp} member interface {intf}'): raise ConfigError(( f'Cannot add interface "{intf}" to bond "{bond["intf"]}", ' f'it is already a member of bond "{tmp}"!')) # can not add interfaces with an assigned address to a bond if has_address_configured(conf, intf): raise ConfigError( (f'Cannot add interface "{intf}" to bond "{bond["intf"]}", ' f'it has an address assigned!')) # bond members are not allowed to be bridge members tmp = is_member(conf, intf, 'bridge') if tmp: raise ConfigError( (f'Cannot add interface "{intf}" to bond "{bond["intf"]}", ' f'it is already a member of bridge "{tmp}"!')) # bond members are not allowed to be vrrp members for tmp in conf.list_nodes('high-availability vrrp group'): if conf.exists( 'high-availability vrrp group {tmp} interface {intf}'): raise ConfigError(( f'Cannot add interface "{intf}" to bond "{bond["intf"]}", ' f'it is already a member of VRRP group "{tmp}"!')) # bond members are not allowed to be underlaying psuedo-ethernet devices for tmp in conf.list_nodes('interfaces pseudo-ethernet'): if conf.exists('interfaces pseudo-ethernet {tmp} link {intf}'): raise ConfigError(( f'Cannot add interface "{intf}" to bond "{bond["intf"]}", ' f'it is already the link of pseudo-ethernet "{tmp}"!')) # bond members are not allowed to be underlaying vxlan devices for tmp in conf.list_nodes('interfaces vxlan'): if conf.exists('interfaces vxlan {tmp} link {intf}'): raise ConfigError(( f'Cannot add interface "{intf}" to bond "{bond["intf"]}", ' f'it is already the link of VXLAN "{tmp}"!')) if bond['primary']: if bond['primary'] not in bond['member']: raise ConfigError( f'Bond "{bond["intf"]}" primary interface must be a member') if bond['mode'] not in ['active-backup', 'balance-tlb', 'balance-alb']: raise ConfigError('primary interface only works for mode active-backup, ' \ 'transmit-load-balance or adaptive-load-balance') if bond['arp_mon_intvl'] > 0: if bond['mode'] in ['802.3ad', 'balance-tlb', 'balance-alb']: raise ConfigError('ARP link monitoring does not work for mode 802.3ad, ' \ 'transmit-load-balance or adaptive-load-balance') return None
def get_config(): conf = Config() base = ['interfaces', 'wireguard'] # determine tagNode instance if 'VYOS_TAGNODE_VALUE' not in os.environ: raise ConfigError('Interface (VYOS_TAGNODE_VALUE) not specified') wg = deepcopy(default_config_data) wg['intf'] = os.environ['VYOS_TAGNODE_VALUE'] # check if interface is member if a bridge wg['is_bridge_member'] = is_member(conf, wg['intf'], 'bridge') # Check if interface has been removed if not conf.exists(base + [wg['intf']]): wg['deleted'] = True return wg conf.set_level(base + [wg['intf']]) # retrieve configured interface addresses if conf.exists(['address']): wg['address'] = conf.return_values(['address']) # get interface addresses (currently effective) - to determine which # address is no longer valid and needs to be removed eff_addr = conf.return_effective_values(['address']) wg['address_remove'] = list_diff(eff_addr, wg['address']) # retrieve interface description if conf.exists(['description']): wg['description'] = conf.return_value(['description']) # disable interface if conf.exists(['disable']): wg['disable'] = True # local port to listen on if conf.exists(['port']): wg['listen_port'] = conf.return_value(['port']) # fwmark value if conf.exists(['fwmark']): wg['fwmark'] = int(conf.return_value(['fwmark'])) # Maximum Transmission Unit (MTU) if conf.exists('mtu'): wg['mtu'] = int(conf.return_value(['mtu'])) # retrieve VRF instance if conf.exists('vrf'): wg['vrf'] = conf.return_value('vrf') # private key if conf.exists(['private-key']): wg['pk'] = "{0}/{1}/private.key".format( kdir, conf.return_value(['private-key'])) # peer removal, wg identifies peers by its pubkey peer_eff = conf.list_effective_nodes(['peer']) peer_rem = list_diff(peer_eff, conf.list_nodes(['peer'])) for peer in peer_rem: wg['peer_remove'].append( conf.return_effective_value(['peer', peer, 'pubkey'])) # peer settings if conf.exists(['peer']): for p in conf.list_nodes(['peer']): # set new config level for this peer conf.set_level(base + [wg['intf'], 'peer', p]) peer = { 'allowed-ips': [], 'address': '', 'name': p, 'persistent_keepalive': '', 'port': '', 'psk': '', 'pubkey': '' } # peer allowed-ips if conf.exists(['allowed-ips']): peer['allowed-ips'] = conf.return_values(['allowed-ips']) # peer address if conf.exists(['address']): peer['address'] = conf.return_value(['address']) # peer port if conf.exists(['port']): peer['port'] = conf.return_value(['port']) # persistent-keepalive if conf.exists(['persistent-keepalive']): peer['persistent_keepalive'] = conf.return_value(['persistent-keepalive']) # preshared-key if conf.exists(['preshared-key']): peer['psk'] = conf.return_value(['preshared-key']) # peer pubkeys if conf.exists(['pubkey']): key_eff = conf.return_effective_value(['pubkey']) key_cfg = conf.return_value(['pubkey']) peer['pubkey'] = key_cfg # on a pubkey change we need to remove the pubkey first # peers are identified by pubkey, so key update means # peer removal and re-add if key_eff != key_cfg and key_eff != None: wg['peer_remove'].append(key_cfg) # if a peer is disabled, we have to exec a remove for it's pubkey if conf.exists(['disable']): wg['peer_remove'].append(peer['pubkey']) else: wg['peer'].append(peer) return wg
def intf_to_dict(conf, default): """ Common used function which will extract VLAN related information from config and represent the result as Python dictionary. Function call's itself recursively if a vif-s/vif-c pair is detected. """ intf = deepcopy(default) intf['intf'] = ifname_from_config(conf) # retrieve interface description if conf.exists(['description']): intf['description'] = conf.return_value(['description']) # get DHCP client identifier if conf.exists(['dhcp-options', 'client-id']): intf['dhcp_client_id'] = conf.return_value(['dhcp-options', 'client-id']) # DHCP client host name (overrides the system host name) if conf.exists(['dhcp-options', 'host-name']): intf['dhcp_hostname'] = conf.return_value(['dhcp-options', 'host-name']) # DHCP client vendor identifier if conf.exists(['dhcp-options', 'vendor-class-id']): intf['dhcp_vendor_class_id'] = conf.return_value( ['dhcp-options', 'vendor-class-id']) # DHCPv6 only acquire config parameters, no address if conf.exists(['dhcpv6-options', 'parameters-only']): intf['dhcpv6_prm_only'] = True # DHCPv6 prefix delegation (RFC3633) current_level = conf.get_level() if conf.exists(['dhcpv6-options', 'prefix-delegation']): dhcpv6_pd_path = current_level + ['dhcpv6-options', 'prefix-delegation'] conf.set_level(dhcpv6_pd_path) # retriebe DHCPv6-PD prefix helper length as some ISPs only hand out a # /64 by default (https://phabricator.vyos.net/T2506) if conf.exists(['length']): intf['dhcpv6_pd_length'] = conf.return_value(['length']) for interface in conf.list_nodes(['interface']): conf.set_level(dhcpv6_pd_path + ['interface', interface]) pd = { 'ifname': interface, 'sla_id': '', 'sla_len': '', 'if_id': '' } if conf.exists(['sla-id']): pd['sla_id'] = conf.return_value(['sla-id']) if conf.exists(['sla-len']): pd['sla_len'] = conf.return_value(['sla-len']) if conf.exists(['address']): pd['if_id'] = conf.return_value(['address']) intf['dhcpv6_pd_interfaces'].append(pd) # re-set config level conf.set_level(current_level) # DHCPv6 temporary IPv6 address if conf.exists(['dhcpv6-options', 'temporary']): intf['dhcpv6_temporary'] = True # ignore link state changes if conf.exists(['disable-link-detect']): intf['disable_link_detect'] = 2 # ARP filter configuration if conf.exists(['ip', 'disable-arp-filter']): intf['ip_disable_arp_filter'] = 0 # ARP enable accept if conf.exists(['ip', 'enable-arp-accept']): intf['ip_enable_arp_accept'] = 1 # ARP enable announce if conf.exists(['ip', 'enable-arp-announce']): intf['ip_enable_arp_announce'] = 1 # ARP enable ignore if conf.exists(['ip', 'enable-arp-ignore']): intf['ip_enable_arp_ignore'] = 1 # Enable Proxy ARP if conf.exists(['ip', 'enable-proxy-arp']): intf['ip_proxy_arp'] = 1 # Enable acquisition of IPv6 address using stateless autoconfig (SLAAC) if conf.exists(['ipv6', 'address', 'autoconf']): intf['ipv6_autoconf'] = 1 # Disable IPv6 forwarding on this interface if conf.exists(['ipv6', 'disable-forwarding']): intf['ipv6_forwarding'] = 0 # check if interface is member of a bridge intf['is_bridge_member'] = is_member(conf, intf['intf'], 'bridge') # IPv6 Duplicate Address Detection (DAD) tries if conf.exists(['ipv6', 'dup-addr-detect-transmits']): intf['ipv6_dup_addr_detect'] = int( conf.return_value(['ipv6', 'dup-addr-detect-transmits'])) # Media Access Control (MAC) address if conf.exists(['mac']): intf['mac'] = conf.return_value(['mac']) # Maximum Transmission Unit (MTU) if conf.exists(['mtu']): intf['mtu'] = int(conf.return_value(['mtu'])) # retrieve VRF instance if conf.exists(['vrf']): intf['vrf'] = conf.return_value(['vrf']) # egress QoS if conf.exists(['egress-qos']): intf['egress_qos'] = conf.return_value(['egress-qos']) # egress changes QoS require VLAN interface recreation if conf.return_effective_value(['egress-qos']): if intf['egress_qos'] != conf.return_effective_value(['egress-qos']): intf['egress_qos_changed'] = True # ingress QoS if conf.exists(['ingress-qos']): intf['ingress_qos'] = conf.return_value(['ingress-qos']) # ingress changes QoS require VLAN interface recreation if conf.return_effective_value(['ingress-qos']): if intf['ingress_qos'] != conf.return_effective_value(['ingress-qos']): intf['ingress_qos_changed'] = True # Get the interface addresses intf['address'] = conf.return_values(['address']) # addresses to remove - difference between effective and working config intf['address_remove'] = list_diff( conf.return_effective_values(['address']), intf['address']) # Get prefixes for IPv6 addressing based on MAC address (EUI-64) intf['ipv6_eui64_prefix'] = conf.return_values(['ipv6', 'address', 'eui64']) # EUI64 to remove - difference between effective and working config intf['ipv6_eui64_prefix_remove'] = list_diff( conf.return_effective_values(['ipv6', 'address', 'eui64']), intf['ipv6_eui64_prefix']) # Determine if the interface should be disabled disabled = disable_state(conf) if disabled == disable.both: # was and is still disabled intf['disable'] = True elif disabled == disable.now: # it is now disable but was not before intf['disable'] = True elif disabled == disable.was: # it was disable but not anymore intf['disable'] = False else: # normal change intf['disable'] = False # Remove the default link-local address if no-default-link-local is set, # if member of a bridge or if disabled (it may not have a MAC if it's down) if ( conf.exists(['ipv6', 'address', 'no-default-link-local']) or intf.get('is_bridge_member') or intf['disable'] ): intf['ipv6_eui64_prefix_remove'].append('fe80::/64') else: # add the link-local by default to make IPv6 work intf['ipv6_eui64_prefix'].append('fe80::/64') # If MAC has changed, remove and re-add all IPv6 EUI64 addresses try: interface = Interface(intf['intf'], create=False) if intf['mac'] and intf['mac'] != interface.get_mac(): intf['ipv6_eui64_prefix_remove'] += intf['ipv6_eui64_prefix'] except Exception: # If the interface does not exist, it could not have changed pass # to make IPv6 SLAAC and DHCPv6 work with forwarding=1, # accept_ra must be 2 if intf['ipv6_autoconf'] or 'dhcpv6' in intf['address']: intf['ipv6_accept_ra'] = 2 return intf, disable
def get_config(): # determine tagNode instance if 'VYOS_TAGNODE_VALUE' not in os.environ: raise ConfigError('Interface (VYOS_TAGNODE_VALUE) not specified') ifname = os.environ['VYOS_TAGNODE_VALUE'] conf = Config() # check if wireless interface has been removed cfg_base = ['interfaces', 'wireless ', ifname] if not conf.exists(cfg_base): wifi = deepcopy(default_config_data) wifi['intf'] = ifname wifi['deleted'] = True # we need to know if we're a bridge member so we can refuse deletion wifi['is_bridge_member'] = is_member(conf, wifi['intf'], 'bridge') # we can not bail out early as wireless interface can not be removed # Kernel will complain with: RTNETLINK answers: Operation not supported. # Thus we need to remove individual settings return wifi # set new configuration level conf.set_level(cfg_base) # get common interface settings wifi, disabled = intf_to_dict(conf, default_config_data) # 40MHz intolerance, use 20MHz only if conf.exists('capabilities ht 40mhz-incapable'): wifi['cap_ht'] = True wifi['cap_ht_40mhz_incapable'] = True # WMM-PS Unscheduled Automatic Power Save Delivery [U-APSD] if conf.exists('capabilities ht auto-powersave'): wifi['cap_ht'] = True wifi['cap_ht_powersave'] = True # Supported channel set width if conf.exists('capabilities ht channel-set-width'): wifi['cap_ht'] = True wifi['cap_ht_chan_set_width'] = conf.return_values( 'capabilities ht channel-set-width') # HT-delayed Block Ack if conf.exists('capabilities ht delayed-block-ack'): wifi['cap_ht'] = True wifi['cap_ht_delayed_block_ack'] = True # DSSS/CCK Mode in 40 MHz if conf.exists('capabilities ht dsss-cck-40'): wifi['cap_ht'] = True wifi['cap_ht_dsss_cck_40'] = True # HT-greenfield capability if conf.exists('capabilities ht greenfield'): wifi['cap_ht'] = True wifi['cap_ht_greenfield'] = True # LDPC coding capability if conf.exists('capabilities ht ldpc'): wifi['cap_ht'] = True wifi['cap_ht_ldpc'] = True # L-SIG TXOP protection capability if conf.exists('capabilities ht lsig-protection'): wifi['cap_ht'] = True wifi['cap_ht_lsig_protection'] = True # Set Maximum A-MSDU length if conf.exists('capabilities ht max-amsdu'): wifi['cap_ht'] = True wifi['cap_ht_max_amsdu'] = conf.return_value( 'capabilities ht max-amsdu') # Short GI capabilities if conf.exists('capabilities ht short-gi'): wifi['cap_ht'] = True wifi['cap_ht_short_gi'] = conf.return_values( 'capabilities ht short-gi') # Spatial Multiplexing Power Save (SMPS) settings if conf.exists('capabilities ht smps'): wifi['cap_ht'] = True wifi['cap_ht_smps'] = conf.return_value('capabilities ht smps') # Support for receiving PPDU using STBC (Space Time Block Coding) if conf.exists('capabilities ht stbc rx'): wifi['cap_ht'] = True wifi['cap_ht_stbc_rx'] = conf.return_value('capabilities ht stbc rx') # Support for sending PPDU using STBC (Space Time Block Coding) if conf.exists('capabilities ht stbc tx'): wifi['cap_ht'] = True wifi['cap_ht_stbc_tx'] = True # Require stations to support HT PHY (reject association if they do not) if conf.exists('capabilities require-ht'): wifi['cap_req_ht'] = True # Require stations to support VHT PHY (reject association if they do not) if conf.exists('capabilities require-vht'): wifi['cap_req_vht'] = True # Number of antennas on this card if conf.exists('capabilities vht antenna-count'): wifi['cap_vht'] = True wifi['cap_vht_antenna_cnt'] = conf.return_value( 'capabilities vht antenna-count') # set if antenna pattern does not change during the lifetime of an association if conf.exists('capabilities vht antenna-pattern-fixed'): wifi['cap_vht'] = True wifi['cap_vht_antenna_fixed'] = True # Beamforming capabilities if conf.exists('capabilities vht beamform'): wifi['cap_vht'] = True wifi['cap_vht_beamform'] = conf.return_values( 'capabilities vht beamform') # VHT operating channel center frequency - center freq 1 (for use with 80, 80+80 and 160 modes) if conf.exists('capabilities vht center-channel-freq freq-1'): wifi['cap_vht'] = True wifi['cap_vht_center_freq_1'] = conf.return_value( 'capabilities vht center-channel-freq freq-1') # VHT operating channel center frequency - center freq 2 (for use with the 80+80 mode) if conf.exists('capabilities vht center-channel-freq freq-2'): wifi['cap_vht'] = True wifi['cap_vht_center_freq_2'] = conf.return_value( 'capabilities vht center-channel-freq freq-2') # VHT operating Channel width if conf.exists('capabilities vht channel-set-width'): wifi['cap_vht'] = True wifi['cap_vht_chan_set_width'] = conf.return_value( 'capabilities vht channel-set-width') # LDPC coding capability if conf.exists('capabilities vht ldpc'): wifi['cap_vht'] = True wifi['cap_vht_ldpc'] = True # VHT link adaptation capabilities if conf.exists('capabilities vht link-adaptation'): wifi['cap_vht'] = True wifi['cap_vht_link_adaptation'] = conf.return_value( 'capabilities vht link-adaptation') # Set the maximum length of A-MPDU pre-EOF padding that the station can receive if conf.exists('capabilities vht max-mpdu-exp'): wifi['cap_vht'] = True wifi['cap_vht_max_mpdu_exp'] = conf.return_value( 'capabilities vht max-mpdu-exp') # Increase Maximum MPDU length if conf.exists('capabilities vht max-mpdu'): wifi['cap_vht'] = True wifi['cap_vht_max_mpdu'] = conf.return_value( 'capabilities vht max-mpdu') # Increase Maximum MPDU length if conf.exists('capabilities vht short-gi'): wifi['cap_vht'] = True wifi['cap_vht_short_gi'] = conf.return_values( 'capabilities vht short-gi') # Support for receiving PPDU using STBC (Space Time Block Coding) if conf.exists('capabilities vht stbc rx'): wifi['cap_vht'] = True wifi['cap_vht_stbc_rx'] = conf.return_value('capabilities vht stbc rx') # Support for the transmission of at least 2x1 STBC (Space Time Block Coding) if conf.exists('capabilities vht stbc tx'): wifi['cap_vht'] = True wifi['cap_vht_stbc_tx'] = True # Support for VHT TXOP Power Save Mode if conf.exists('capabilities vht tx-powersave'): wifi['cap_vht'] = True wifi['cap_vht_tx_powersave'] = True # STA supports receiving a VHT variant HT Control field if conf.exists('capabilities vht vht-cf'): wifi['cap_vht'] = True wifi['cap_vht_vht_cf'] = True # Wireless radio channel if conf.exists('channel'): wifi['channel'] = conf.return_value('channel') # Disable broadcast of SSID from access-point if conf.exists('disable-broadcast-ssid'): wifi['disable_broadcast_ssid'] = True # Disassociate stations based on excessive transmission failures if conf.exists('expunge-failing-stations'): wifi['expunge_failing_stations'] = True # retrieve real hardware address if conf.exists('hw-id'): wifi['hw_id'] = conf.return_value('hw-id') # Isolate stations on the AP so they cannot see each other if conf.exists('isolate-stations'): wifi['isolate_stations'] = True # Wireless physical device if conf.exists('physical-device'): wifi['phy'] = conf.return_value('physical-device') # Maximum number of wireless radio stations if conf.exists('max-stations'): wifi['max_stations'] = conf.return_value('max-stations') # Management Frame Protection (MFP) according to IEEE 802.11w if conf.exists('mgmt-frame-protection'): wifi['mgmt_frame_protection'] = conf.return_value( 'mgmt-frame-protection') # Wireless radio mode if conf.exists('mode'): wifi['mode'] = conf.return_value('mode') # Transmission power reduction in dBm if conf.exists('reduce-transmit-power'): wifi['reduce_transmit_power'] = conf.return_value( 'reduce-transmit-power') # WEP enabled? if conf.exists('security wep'): wifi['sec_wep'] = True # WEP encryption key(s) if conf.exists('security wep key'): wifi['sec_wep_key'] = conf.return_values('security wep key') # WPA enabled? if conf.exists('security wpa'): wifi['sec_wpa'] = True # WPA Cipher suite if conf.exists('security wpa cipher'): wifi['sec_wpa_cipher'] = conf.return_values('security wpa cipher') # WPA mode if conf.exists('security wpa mode'): wifi['sec_wpa_mode'] = conf.return_value('security wpa mode') # WPA default ciphers depend on WPA mode if not wifi['sec_wpa_cipher']: if wifi['sec_wpa_mode'] == 'wpa': wifi['sec_wpa_cipher'].append('TKIP') wifi['sec_wpa_cipher'].append('CCMP') elif wifi['sec_wpa_mode'] == 'wpa2': wifi['sec_wpa_cipher'].append('CCMP') elif wifi['sec_wpa_mode'] == 'both': wifi['sec_wpa_cipher'].append('CCMP') wifi['sec_wpa_cipher'].append('TKIP') # WPA Group Cipher suite if conf.exists('security wpa group-cipher'): wifi['sec_wpa_group_cipher'] = conf.return_values( 'security wpa group-cipher') # WPA personal shared pass phrase if conf.exists('security wpa passphrase'): wifi['sec_wpa_passphrase'] = conf.return_value( 'security wpa passphrase') # WPA RADIUS source address if conf.exists('security wpa radius source-address'): wifi['sec_wpa_radius_source'] = conf.return_value( 'security wpa radius source-address') # WPA RADIUS server for server in conf.list_nodes('security wpa radius server'): # set new configuration level conf.set_level(cfg_base + ' security wpa radius server ' + server) radius = { 'server': server, 'acc_port': '', 'disabled': False, 'port': 1812, 'key': '' } # RADIUS server port if conf.exists('port'): radius['port'] = int(conf.return_value('port')) # receive RADIUS accounting info if conf.exists('accounting'): radius['acc_port'] = radius['port'] + 1 # Check if RADIUS server was temporary disabled if conf.exists(['disable']): radius['disabled'] = True # RADIUS server shared-secret if conf.exists('key'): radius['key'] = conf.return_value('key') # append RADIUS server to list of servers wifi['sec_wpa_radius'].append(radius) # re-set configuration level to parse new nodes conf.set_level(cfg_base) # Wireless access-point service set identifier (SSID) if conf.exists('ssid'): wifi['ssid'] = conf.return_value('ssid') # Wireless device type for this interface if conf.exists('type'): tmp = conf.return_value('type') if tmp == 'access-point': tmp = 'ap' wifi['op_mode'] = tmp # retrieve configured regulatory domain conf.set_level('system') if conf.exists('wifi-regulatory-domain'): wifi['country_code'] = conf.return_value('wifi-regulatory-domain') return wifi
def get_config(): ifname = os.environ.get('VYOS_TAGNODE_VALUE', '') if not ifname: raise ConfigError('Interface not specified') conf = ConfigurationState('interfaces tunnel ' + ifname, default_config_data) options = conf.options changes = conf.changes options['ifname'] = ifname # set new configuration level conf.set_level(conf.section) if changes['section'] == 'delete': conf.get_effective('type', mapping['type'][0]) conf.set_level('protocols nhrp tunnel') options['nhrp'] = conf.list_nodes('') return conf.to_dict() # load all the configuration option according to the mapping conf.load(mapping) # remove default value if not set and not required afi_local = get_afi(options['local']) if afi_local == IP6: conf.remove_default('ttl', 'tos', 'key') if afi_local == IP4: conf.remove_default('encaplimit', 'flowlabel', 'hoplimit', 'tclass') # if the local-ip is not set, pick one from the interface ! # hopefully there is only one, otherwise it will not be very deterministic # at time of writing the code currently returns ipv4 before ipv6 in the list # XXX: There is no way to trigger an update of the interface source IP if # XXX: the underlying interface IP address does change, I believe this # XXX: limit/issue is present in vyatta too if not options['local'] and options['dhcp-interface']: # XXX: This behaviour changes from vyatta which would return 127.0.0.1 if # XXX: the interface was not DHCP. As there is no easy way to find if an # XXX: interface is using DHCP, and using this feature to get 127.0.0.1 # XXX: makes little sense, I feel the change in behaviour is acceptable picked = get_interface_ip(options['dhcp-interface']) if picked == '': picked = '127.0.0.1' print( 'Could not get an IP address from {dhcp-interface} using 127.0.0.1 instead' ) options['local'] = picked options['dhcp-interface'] = '' # get interface addresses (currently effective) - to determine which # address is no longer valid and needs to be removed # could be done within ConfigurationState eff_addr = conf.return_effective_values('address') options['addresses-del'] = list_diff(eff_addr, options['addresses-add']) # to make IPv6 SLAAC and DHCPv6 work with forwarding=1, # accept_ra must be 2 if options['ipv6_autoconf'] or 'dhcpv6' in options['addresses-add']: options['ipv6_accept_ra'] = 2 # allmulticast fate is linked to multicast options['allmulticast'] = options['multicast'] # check that per encapsulation all local-remote pairs are unique conf.set_level('interfaces tunnel') ct = conf.get_config_dict()['tunnel'] options['tunnel'] = {} # check for bridges options['bridge'] = is_member(conf, ifname, 'bridge') options['interfaces'] = interfaces() for name in ct: tunnel = ct[name] encap = tunnel.get('encapsulation', '') local = tunnel.get('local-ip', '') if not local: local = get_interface_ip(tunnel.get('dhcp-interface', '')) remote = tunnel.get('remote-ip', '<unset>') pair = f'{local}-{remote}' options['tunnel'][encap][pair] = options['tunnel'].setdefault( encap, {}).get(pair, 0) + 1 return conf.to_dict()
def get_config(): openvpn = deepcopy(default_config_data) conf = Config() # determine tagNode instance if 'VYOS_TAGNODE_VALUE' not in os.environ: raise ConfigError('Interface (VYOS_TAGNODE_VALUE) not specified') 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 return openvpn # bridged server should not have a pool by default (but can be specified manually) if openvpn['is_bridge_member']: openvpn['server_pool'] = False openvpn['server_ipv6_pool'] = False # set configuration level conf.set_level('interfaces openvpn ' + openvpn['intf']) # retrieve authentication options - username if conf.exists('authentication username'): openvpn['auth_user'] = conf.return_value('authentication username') openvpn['auth'] = True # retrieve authentication options - username if conf.exists('authentication password'): openvpn['auth_pass'] = conf.return_value('authentication password') openvpn['auth'] = True # retrieve interface description if conf.exists('description'): openvpn['description'] = conf.return_value('description') # interface device-type if conf.exists('device-type'): openvpn['type'] = conf.return_value('device-type') # disable interface if conf.exists('disable'): openvpn['disable'] = True # data encryption algorithm cipher if conf.exists('encryption cipher'): openvpn['encryption'] = conf.return_value('encryption cipher') # disable ncp-ciphers support if conf.exists('encryption disable-ncp'): openvpn['disable_ncp'] = True # data encryption algorithm ncp-list if conf.exists('encryption ncp-ciphers'): _ncp_ciphers = [] for enc in conf.return_values('encryption ncp-ciphers'): if enc == 'des': _ncp_ciphers.append('des-cbc') _ncp_ciphers.append('DES-CBC') elif enc == '3des': _ncp_ciphers.append('des-ede3-cbc') _ncp_ciphers.append('DES-EDE3-CBC') elif enc == 'aes128': _ncp_ciphers.append('aes-128-cbc') _ncp_ciphers.append('AES-128-CBC') elif enc == 'aes128gcm': _ncp_ciphers.append('aes-128-gcm') _ncp_ciphers.append('AES-128-GCM') elif enc == 'aes192': _ncp_ciphers.append('aes-192-cbc') _ncp_ciphers.append('AES-192-CBC') elif enc == 'aes192gcm': _ncp_ciphers.append('aes-192-gcm') _ncp_ciphers.append('AES-192-GCM') elif enc == 'aes256': _ncp_ciphers.append('aes-256-cbc') _ncp_ciphers.append('AES-256-CBC') elif enc == 'aes256gcm': _ncp_ciphers.append('aes-256-gcm') _ncp_ciphers.append('AES-256-GCM') openvpn['ncp_ciphers'] = ':'.join(_ncp_ciphers) # hash algorithm if conf.exists('hash'): openvpn['hash'] = conf.return_value('hash') # Maximum number of keepalive packet failures if conf.exists('keep-alive failure-count') and conf.exists( 'keep-alive interval'): fail_count = conf.return_value('keep-alive failure-count') interval = conf.return_value('keep-alive interval') openvpn['ping_interval'] = interval openvpn['ping_restart'] = int(interval) * int(fail_count) # Local IP address of tunnel - even as it is a tag node - we can only work # on the first address if conf.exists('local-address'): for tmp in conf.list_nodes('local-address'): tmp_ip = ip_address(tmp) if tmp_ip.version == 4: openvpn['local_address'].append(tmp) if conf.exists('local-address {} subnet-mask'.format(tmp)): openvpn['local_address_subnet'] = conf.return_value( 'local-address {} subnet-mask'.format(tmp)) elif tmp_ip.version == 6: # input IPv6 address could be expanded so get the compressed version openvpn['ipv6_local_address'].append(str(tmp_ip)) # Local IP address to accept connections if conf.exists('local-host'): openvpn['local_host'] = conf.return_value('local-host') # Local port number to accept connections if conf.exists('local-port'): openvpn['local_port'] = conf.return_value('local-port') # Enable acquisition of IPv6 address using stateless autoconfig (SLAAC) if conf.exists('ipv6 address autoconf'): openvpn['ipv6_autoconf'] = 1 # Get prefixes for IPv6 addressing based on MAC address (EUI-64) if conf.exists('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'): openvpn['ipv6_forwarding'] = 0 # IPv6 Duplicate Address Detection (DAD) tries 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') # Additional OpenVPN options if conf.exists('openvpn-option'): openvpn['options'] = conf.return_values('openvpn-option') # Do not close and reopen interface if conf.exists('persistent-tunnel'): openvpn['persistent_tunnel'] = True # Communication protocol if conf.exists('protocol'): openvpn['protocol'] = conf.return_value('protocol') # IP address of remote end of tunnel if conf.exists('remote-address'): for tmp in conf.return_values('remote-address'): tmp_ip = ip_address(tmp) if tmp_ip.version == 4: openvpn['remote_address'].append(tmp) elif tmp_ip.version == 6: openvpn['ipv6_remote_address'].append(str(tmp_ip)) # Remote host to connect to (dynamic if not set) if conf.exists('remote-host'): openvpn['remote_host'] = conf.return_values('remote-host') # Remote port number to connect to if conf.exists('remote-port'): openvpn['remote_port'] = conf.return_value('remote-port') # OpenVPN tunnel to be used as the default route # see https://openvpn.net/community-resources/reference-manual-for-openvpn-2-4/ # redirect-gateway flags if conf.exists('replace-default-route'): openvpn['redirect_gateway'] = 'def1' if conf.exists('replace-default-route local'): openvpn['redirect_gateway'] = 'local def1' # Topology for clients if conf.exists('server topology'): openvpn['server_topology'] = conf.return_value('server topology') # Server-mode subnet (from which client IPs are allocated) server_network_v4 = None server_network_v6 = None if conf.exists('server subnet'): for tmp in conf.return_values('server subnet'): tmp_ip = ip_network(tmp) if tmp_ip.version == 4: server_network_v4 = tmp_ip # convert the network to format: "192.0.2.0 255.255.255.0" for later use in template openvpn['server_subnet'].append( tmp_ip.with_netmask.replace(r'/', ' ')) elif tmp_ip.version == 6: server_network_v6 = tmp_ip openvpn['server_ipv6_subnet'].append(str(tmp_ip)) # Client-specific settings for client in conf.list_nodes('server client'): # set configuration level conf.set_level('interfaces openvpn ' + openvpn['intf'] + ' server client ' + client) data = { 'name': client, 'disable': False, 'ip': [], 'ipv6_ip': [], 'ipv6_remote': '', 'ipv6_push_route': [], 'ipv6_subnet': [], 'push_route': [], 'subnet': [], 'remote_netmask': '' } # Option to disable client connection if conf.exists('disable'): data['disable'] = True # IP address of the client for tmp in conf.return_values('ip'): tmp_ip = ip_address(tmp) if tmp_ip.version == 4: data['ip'].append(tmp) elif tmp_ip.version == 6: data['ipv6_ip'].append(str(tmp_ip)) # Route to be pushed to the client for tmp in conf.return_values('push-route'): tmp_ip = ip_network(tmp) if tmp_ip.version == 4: data['push_route'].append( tmp_ip.with_netmask.replace(r'/', ' ')) elif tmp_ip.version == 6: data['ipv6_push_route'].append(str(tmp_ip)) # Subnet belonging to the client for tmp in conf.return_values('subnet'): tmp_ip = ip_network(tmp) if tmp_ip.version == 4: data['subnet'].append(tmp_ip.with_netmask.replace(r'/', ' ')) elif tmp_ip.version == 6: data['ipv6_subnet'].append(str(tmp_ip)) # Append to global client list openvpn['client'].append(data) # re-set configuration level conf.set_level('interfaces openvpn ' + openvpn['intf']) # Server client IP pool if conf.exists('server client-ip-pool'): conf.set_level('interfaces openvpn ' + openvpn['intf'] + ' server client-ip-pool') # enable or disable server_pool where necessary # default is enabled, or disabled in bridge mode openvpn['server_pool'] = not conf.exists('disable') if conf.exists('start'): openvpn['server_pool_start'] = conf.return_value('start') if conf.exists('stop'): openvpn['server_pool_stop'] = conf.return_value('stop') if conf.exists('netmask'): openvpn['server_pool_netmask'] = conf.return_value('netmask') conf.set_level('interfaces openvpn ' + openvpn['intf']) # Server client IPv6 pool if conf.exists('server client-ipv6-pool'): conf.set_level('interfaces openvpn ' + openvpn['intf'] + ' server client-ipv6-pool') openvpn['server_ipv6_pool'] = not conf.exists('disable') if conf.exists('base'): tmp = conf.return_value('base').split('/') openvpn['server_ipv6_pool_base'] = str(IPv6Address(tmp[0])) if 1 < len(tmp): openvpn['server_ipv6_pool_prefixlen'] = tmp[1] conf.set_level('interfaces openvpn ' + openvpn['intf']) # DNS suffix to be pushed to all clients if conf.exists('server domain-name'): openvpn['server_domain'] = conf.return_value('server domain-name') # Number of maximum client connections if conf.exists('server max-connections'): openvpn['server_max_conn'] = conf.return_value( 'server max-connections') # Domain Name Server (DNS) if conf.exists('server name-server'): for tmp in conf.return_values('server name-server'): tmp_ip = ip_address(tmp) if tmp_ip.version == 4: openvpn['server_dns_nameserver'].append(tmp) elif tmp_ip.version == 6: openvpn['server_ipv6_dns_nameserver'].append(str(tmp_ip)) # Route to be pushed to all clients if conf.exists('server push-route'): for tmp in conf.return_values('server push-route'): tmp_ip = ip_network(tmp) if tmp_ip.version == 4: openvpn['server_push_route'].append( tmp_ip.with_netmask.replace(r'/', ' ')) elif tmp_ip.version == 6: openvpn['server_ipv6_push_route'].append(str(tmp_ip)) # Reject connections from clients that are not explicitly configured if conf.exists('server reject-unconfigured-clients'): openvpn['server_reject_unconfigured'] = True # File containing TLS auth static key if conf.exists('tls auth-file'): openvpn['tls_auth'] = conf.return_value('tls auth-file') openvpn['tls'] = True # File containing certificate for Certificate Authority (CA) if conf.exists('tls ca-cert-file'): openvpn['tls_ca_cert'] = conf.return_value('tls ca-cert-file') openvpn['tls'] = True # File containing certificate for this host if conf.exists('tls cert-file'): openvpn['tls_cert'] = conf.return_value('tls cert-file') openvpn['tls'] = True # File containing certificate revocation list (CRL) for this host if conf.exists('tls crl-file'): openvpn['tls_crl'] = conf.return_value('tls crl-file') openvpn['tls'] = True # File containing Diffie Hellman parameters (server only) if conf.exists('tls dh-file'): openvpn['tls_dh'] = conf.return_value('tls dh-file') openvpn['tls'] = True # File containing this host's private key if conf.exists('tls key-file'): openvpn['tls_key'] = conf.return_value('tls key-file') openvpn['tls'] = True # File containing key to encrypt control channel packets if conf.exists('tls crypt-file'): openvpn['tls_crypt'] = conf.return_value('tls crypt-file') openvpn['tls'] = True # Role in TLS negotiation if conf.exists('tls role'): openvpn['tls_role'] = conf.return_value('tls role') openvpn['tls'] = True # Minimum required TLS version if conf.exists('tls tls-version-min'): openvpn['tls_version_min'] = conf.return_value('tls tls-version-min') openvpn['tls'] = True if conf.exists('shared-secret-key-file'): openvpn['shared_secret_file'] = conf.return_value( 'shared-secret-key-file') if conf.exists('use-lzo-compression'): openvpn['compress_lzo'] = True # Special case when using EC certificates: # if key-file is EC and dh-file is unset, set tls_dh to 'none' if not openvpn['tls_dh'] and openvpn['tls_key'] and checkCertHeader( '-----BEGIN EC PRIVATE KEY-----', openvpn['tls_key']): openvpn['tls_dh'] = 'none' # set default server topology to net30 if openvpn['mode'] == 'server' and not openvpn['server_topology']: openvpn['server_topology'] = 'net30' # Convert protocol to real protocol used by openvpn. # To make openvpn listen on both IPv4 and IPv6 we must use *6 protocols # (https://community.openvpn.net/openvpn/ticket/360), unless the local-host # or each of the remote-host in client mode is IPv4 # in which case it must use the standard protocols. if openvpn['protocol'] == 'tcp-active': openvpn['protocol_real'] = 'tcp6-client' elif openvpn['protocol'] == 'tcp-passive': openvpn['protocol_real'] = 'tcp6-server' else: openvpn['protocol_real'] = 'udp6' if (is_ipv4(openvpn['local_host']) or # in client mode test all the remotes instead (openvpn['mode'] == 'client' and all([is_ipv4(h) for h in openvpn['remote_host']]))): # takes out the '6' openvpn['protocol_real'] = openvpn['protocol_real'][:3] + openvpn[ 'protocol_real'][4:] # Set defaults where necessary. # If any of the input parameters are wrong, # this will return False and no defaults will be set. if server_network_v4 and openvpn['server_topology'] and openvpn['type']: default_server = None 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['is_bridge_member']: if not openvpn['server_pool_start']: openvpn['server_pool_start'] = default_server['pool_start'] if not openvpn['server_pool_stop']: openvpn['server_pool_stop'] = default_server['pool_stop'] if not openvpn['server_pool_netmask']: openvpn['server_pool_netmask'] = default_server[ 'pool_netmask'] for client in openvpn['client']: client['remote_netmask'] = default_server[ 'client_remote_netmask'] if server_network_v6: if not openvpn['server_ipv6_local']: openvpn['server_ipv6_local'] = server_network_v6[1] if not openvpn['server_ipv6_prefixlen']: openvpn['server_ipv6_prefixlen'] = server_network_v6.prefixlen if not openvpn['server_ipv6_remote']: openvpn['server_ipv6_remote'] = server_network_v6[2] if openvpn['server_ipv6_pool'] and server_network_v6.prefixlen < 112: if not openvpn['server_ipv6_pool_base']: openvpn['server_ipv6_pool_base'] = server_network_v6[0x1000] if not openvpn['server_ipv6_pool_prefixlen']: openvpn['server_ipv6_pool_prefixlen'] = openvpn[ 'server_ipv6_prefixlen'] for client in openvpn['client']: client['ipv6_remote'] = openvpn['server_ipv6_local'] if openvpn['redirect_gateway']: openvpn['redirect_gateway'] += ' ipv6' # retrieve VRF instance if conf.exists('vrf'): openvpn['vrf'] = conf.return_value('vrf') return openvpn