From ce5fe544e4d6c0bd8e6425ec97d0bdfd130630a4 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Fri, 28 May 2021 21:52:42 +0200 Subject: vti: ipsec: T2816: interfaces must be created using the vyos.ifconfig library --- python/vyos/ifconfig/vti.py | 32 ++++++++++++++++++++++++++++++++ src/conf_mode/interfaces-vti.py | 23 +++++++++++++++++++++++ src/conf_mode/vpn_ipsec.py | 39 ++------------------------------------- 3 files changed, 57 insertions(+), 37 deletions(-) diff --git a/python/vyos/ifconfig/vti.py b/python/vyos/ifconfig/vti.py index e2090c889..9eafcd11b 100644 --- a/python/vyos/ifconfig/vti.py +++ b/python/vyos/ifconfig/vti.py @@ -14,6 +14,7 @@ # License along with this library. If not, see . from vyos.ifconfig.interface import Interface +from vyos.util import dict_search @Interface.register class VTIIf(Interface): @@ -25,3 +26,34 @@ class VTIIf(Interface): 'prefixes': ['vti', ], }, } + + def _create(self): + # This table represents a mapping from VyOS internal config dict to + # arguments used by iproute2. For more information please refer to: + # - https://man7.org/linux/man-pages/man8/ip-link.8.html + # - https://man7.org/linux/man-pages/man8/ip-tunnel.8.html + mapping = { + 'source_address' : 'local', + 'source_interface' : 'dev', + 'remote' : 'remote', + 'key' : 'key', + } + + cmd = 'ip link add {ifname} type vti' + for vyos_key, iproute2_key in mapping.items(): + # dict_search will return an empty dict "{}" for valueless nodes like + # "parameters.nolearning" - thus we need to test the nodes existence + # by using isinstance() + tmp = dict_search(vyos_key, self.config) + if isinstance(tmp, dict): + cmd += f' {iproute2_key}' + elif tmp != None: + cmd += f' {iproute2_key} {tmp}' + + self._cmd(cmd.format(**self.config)) + self.set_interface('admin_state', 'down') + + def set_admin_state(self, state): + # function is not implemented for VTI interfaces as this is entirely + # handled by the ipsec up/down scripts + pass diff --git a/src/conf_mode/interfaces-vti.py b/src/conf_mode/interfaces-vti.py index 432d113e8..acd4a9790 100755 --- a/src/conf_mode/interfaces-vti.py +++ b/src/conf_mode/interfaces-vti.py @@ -19,6 +19,7 @@ from sys import exit from vyos.config import Config from vyos.configdict import get_interface_dict from vyos.ifconfig import VTIIf +from vyos.util import dict_search from vyos import ConfigError from vyos import airbag airbag.enable() @@ -34,6 +35,23 @@ def get_config(config=None): conf = Config() base = ['interfaces', 'vti'] vti = get_interface_dict(conf, base) + + # VTI is more then an interface - we retrieve the "real" configuration from + # the IPsec peer configuration which binds this VTI + conf.set_level([]) + tmp = conf.get_config_dict(['vpn', 'ipsec', 'site-to-site', 'peer'], + key_mangling=('-', '_'), get_first_key=True, + no_tag_node_value_mangle=True) + + for peer, peer_config in tmp.items(): + if dict_search('vti.bind', peer_config) == vti['ifname']: + vti['remote'] = peer + if 'local_address' in peer_config: + vti['source_address'] = peer_config['local_address'] + # we also need to "calculate" a per vti individual key + base = 0x900000 + vti['key'] = base + int(vti['ifname'].lstrip('vti')) + return vti def verify(vti): @@ -46,6 +64,11 @@ def generate(vti): return None def apply(vti): + tmp = VTIIf(**vti) + tmp.remove() + if 'deleted' not in vti: + tmp.update(vti) + return None if __name__ == '__main__': diff --git a/src/conf_mode/vpn_ipsec.py b/src/conf_mode/vpn_ipsec.py index a1c36ea3b..ccbcd7f44 100755 --- a/src/conf_mode/vpn_ipsec.py +++ b/src/conf_mode/vpn_ipsec.py @@ -132,7 +132,7 @@ def get_config(config=None): if pfs == 'enable': pfs = default_ike_pfs - + if 'proposal' in esp_conf: ciphers = [] for i in esp_conf['proposal']: @@ -360,9 +360,7 @@ def apply(ipsec): should_start = ('profile' in ipsec or ('site_to_site' in ipsec and 'peer' in ipsec['site_to_site'])) - if should_start: - apply_vti_interfaces(ipsec) - else: + if not should_start: cleanup_vti_interfaces() if not process_named_running('charon'): @@ -388,39 +386,6 @@ def apply(ipsec): resync_l2tp(conf) resync_nhrp(conf) -def apply_vti_interfaces(ipsec): - # While vyatta-vti-config.pl is still active, this interface will get deleted by cleanupVtiNotConfigured() - if 'site_to_site' in ipsec and 'peer' in ipsec['site_to_site']: - for peer, peer_conf in ipsec['site_to_site']['peer'].items(): - if 'vti' in peer_conf and 'bind' in peer_conf['vti']: - vti_interface = peer_conf['vti']['bind'] - vti_conf = get_vti_interface(vti_interface) - if not vti_conf: - continue - vti_mtu = vti_conf['mtu'] if 'mtu' in vti_conf else 1500 - mark = get_mark(vti_interface) - - local_ip = '' - if 'local_address' in peer_conf: - local_ip = peer_conf['local_address'] - elif 'dhcp_interface' in peer_conf: - local_ip = get_dhcp_address(peer_conf['dhcp_interface']) - - call(f'sudo /usr/sbin/ip link delete {vti_interface} type vti', stderr=DEVNULL) - call(f'sudo /usr/sbin/ip link add {vti_interface} type vti local {local_ip} remote {peer} okey {mark} ikey {mark}') - call(f'sudo /usr/sbin/ip link set {vti_interface} mtu {vti_mtu}') - if 'address' in vti_conf: - address = vti_conf['address'] - if isinstance(address, list): - for addr in address: - call(f'sudo /usr/sbin/ip addr add {addr} dev {vti_interface}') - else: - call(f'sudo /usr/sbin/ip addr add {address} dev {vti_interface}') - - if 'description' in vti_conf: - description = vti_conf['description'] - call(f'sudo echo "{description}" > /sys/class/net/{vti_interface}/ifalias') - def get_vti_interface(vti_interface): global conf section = conf.get_config_dict(['interfaces', 'vti'], get_first_key=True) -- cgit v1.2.3