summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLucas Christian <lucas@lucasec.com>2024-07-03 23:14:45 -0700
committerLucas Christian <lucas@lucasec.com>2024-07-26 18:26:30 -0700
commit376e2d898f26c13a31f80d877f4e2621fd6efb0f (patch)
tree8537e50f3c62b4dc880af60b57c4ccce612bdf44 /src
parent4d2c89dcd50d3c158dc76ac5ab843dd66105bc02 (diff)
downloadvyos-1x-376e2d898f26c13a31f80d877f4e2621fd6efb0f.tar.gz
vyos-1x-376e2d898f26c13a31f80d877f4e2621fd6efb0f.zip
T5873: vpn ipsec: re-write of ipsec updown hook
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/vpn_ipsec.py54
-rwxr-xr-xsrc/etc/ipsec.d/vti-up-down53
2 files changed, 73 insertions, 34 deletions
diff --git a/src/conf_mode/vpn_ipsec.py b/src/conf_mode/vpn_ipsec.py
index 2c1ddc245..789d37a77 100755
--- a/src/conf_mode/vpn_ipsec.py
+++ b/src/conf_mode/vpn_ipsec.py
@@ -30,6 +30,7 @@ from vyos.config import Config
from vyos.config import config_dict_merge
from vyos.configdep import set_dependents
from vyos.configdep import call_dependents
+from vyos.configdict import get_interface_dict
from vyos.configdict import leaf_node_changed
from vyos.configverify import verify_interface_exists
from vyos.configverify import dynamic_interface_pattern
@@ -50,6 +51,9 @@ from vyos.utils.network import interface_exists
from vyos.utils.dict import dict_search
from vyos.utils.dict import dict_search_args
from vyos.utils.process import call
+from vyos.utils.vti_updown_db import vti_updown_db_exists
+from vyos.utils.vti_updown_db import open_vti_updown_db_for_create_or_update
+from vyos.utils.vti_updown_db import remove_vti_updown_db
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -107,6 +111,8 @@ def get_config(config=None):
ipsec = config_dict_merge(default_values, ipsec)
ipsec['dhcp_interfaces'] = set()
+ ipsec['enabled_vti_interfaces'] = set()
+ ipsec['persistent_vti_interfaces'] = set()
ipsec['dhcp_no_address'] = {}
ipsec['install_routes'] = 'no' if conf.exists(base + ["options", "disable-route-autoinstall"]) else default_install_routes
ipsec['interface_change'] = leaf_node_changed(conf, base + ['interface'])
@@ -124,6 +130,28 @@ def get_config(config=None):
ipsec['l2tp_ike_default'] = 'aes256-sha1-modp1024,3des-sha1-modp1024'
ipsec['l2tp_esp_default'] = 'aes256-sha1,3des-sha1'
+ # Collect the interface dicts for any refernced VTI interfaces in
+ # case we need to bring the interface up
+ ipsec['vti_interface_dicts'] = {}
+
+ 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:
+ if 'bind' in peer_conf['vti']:
+ vti_interface = peer_conf['vti']['bind']
+ if vti_interface not in ipsec['vti_interface_dicts']:
+ _, vti = get_interface_dict(conf, ['interfaces', 'vti'], vti_interface)
+ ipsec['vti_interface_dicts'][vti_interface] = vti
+
+ if 'remote_access' in ipsec:
+ if 'connection' in ipsec['remote_access']:
+ for name, ra_conf in ipsec['remote_access']['connection'].items():
+ if 'bind' in ra_conf:
+ vti_interface = ra_conf['bind']
+ if vti_interface not in ipsec['vti_interface_dicts']:
+ _, vti = get_interface_dict(conf, ['interfaces', 'vti'], vti_interface)
+ ipsec['vti_interface_dicts'][vti_interface] = vti
+
return ipsec
def get_dhcp_address(iface):
@@ -308,13 +336,14 @@ def verify(ipsec):
raise ConfigError('RADIUS authentication requires at least one server')
if 'bind' in ra_conf:
- if dict_search('options.disable_route_autoinstall', ipsec) == None:
- Warning('It\'s recommended to use ipsec vti with the next command\n[set vpn ipsec option disable-route-autoinstall]')
-
vti_interface = ra_conf['bind']
- if not os.path.exists(f'/sys/class/net/{vti_interface}'):
+ if not interface_exists(vti_interface):
raise ConfigError(f'VTI interface {vti_interface} for remote-access connection {name} does not exist!')
+ ipsec['enabled_vti_interfaces'].add(vti_interface)
+ # remote access VPN interfaces are always up regardless of whether clients are connected
+ ipsec['persistent_vti_interfaces'].add(vti_interface)
+
if 'pool' in ra_conf:
if {'dhcp', 'radius'} <= set(ra_conf['pool']):
raise ConfigError(f'Can not use both DHCP and RADIUS for address allocation '\
@@ -496,14 +525,11 @@ def verify(ipsec):
if 'local_address' in peer_conf and 'dhcp_interface' in peer_conf:
raise ConfigError(f"A single local-address or dhcp-interface is required when using VTI on site-to-site peer {peer}")
- if dict_search('options.disable_route_autoinstall',
- ipsec) == None:
- Warning('It\'s recommended to use ipsec vti with the next command\n[set vpn ipsec option disable-route-autoinstall]')
-
if 'bind' in peer_conf['vti']:
vti_interface = peer_conf['vti']['bind']
if not interface_exists(vti_interface):
raise ConfigError(f'VTI interface {vti_interface} for site-to-site peer {peer} does not exist!')
+ ipsec['enabled_vti_interfaces'].add(vti_interface)
if 'vti' not in peer_conf and 'tunnel' not in peer_conf:
raise ConfigError(f"No VTI or tunnel specified on site-to-site peer {peer}")
@@ -681,9 +707,21 @@ def apply(ipsec):
systemd_service = 'strongswan.service'
if not ipsec:
call(f'systemctl stop {systemd_service}')
+
+ if vti_updown_db_exists():
+ remove_vti_updown_db()
+
else:
call(f'systemctl reload-or-restart {systemd_service}')
+ if ipsec['enabled_vti_interfaces']:
+ with open_vti_updown_db_for_create_or_update() as db:
+ db.removeAllOtherInterfaces(ipsec['enabled_vti_interfaces'])
+ db.setPersistentInterfaces(ipsec['persistent_vti_interfaces'])
+ db.commit(lambda interface: ipsec['vti_interface_dicts'][interface])
+ elif vti_updown_db_exists():
+ remove_vti_updown_db()
+
if ipsec.get('nhrp_exists', False):
try:
call_dependents()
diff --git a/src/etc/ipsec.d/vti-up-down b/src/etc/ipsec.d/vti-up-down
index 01e9543c9..e1765ae85 100755
--- a/src/etc/ipsec.d/vti-up-down
+++ b/src/etc/ipsec.d/vti-up-down
@@ -27,40 +27,41 @@ from syslog import LOG_INFO
from vyos.configquery import ConfigTreeQuery
from vyos.configdict import get_interface_dict
-from vyos.ifconfig import VTIIf
+from vyos.utils.commit import wait_for_commit_lock
from vyos.utils.process import call
-from vyos.utils.network import get_interface_config
+from vyos.utils.vti_updown_db import open_vti_updown_db_for_update
+
+def supply_interface_dict(interface):
+ # Lazy-load the running config on first invocation
+ try:
+ conf = supply_interface_dict.cached_config
+ except AttributeError:
+ conf = ConfigTreeQuery()
+ supply_interface_dict.cached_config = conf
+
+ _, vti = get_interface_dict(conf.config, ['interfaces', 'vti'], interface)
+ return vti
if __name__ == '__main__':
verb = os.getenv('PLUTO_VERB')
connection = os.getenv('PLUTO_CONNECTION')
interface = sys.argv[1]
+ if verb.endswith('-v6'):
+ protocol = 'v6'
+ else:
+ protocol = 'v4'
+
openlog(ident=f'vti-up-down', logoption=LOG_PID, facility=LOG_INFO)
syslog(f'Interface {interface} {verb} {connection}')
- if verb in ['up-client', 'up-host']:
- call('sudo ip route delete default table 220')
-
- vti_link = get_interface_config(interface)
-
- if not vti_link:
- syslog(f'Interface {interface} not found')
- sys.exit(0)
-
- vti_link_up = (vti_link['operstate'] != 'DOWN' if 'operstate' in vti_link else False)
+ wait_for_commit_lock()
- if verb in ['up-client', 'up-host']:
- if not vti_link_up:
- conf = ConfigTreeQuery()
- _, vti = get_interface_dict(conf.config, ['interfaces', 'vti'], interface)
- if 'disable' not in vti:
- tmp = VTIIf(interface)
- tmp.update(vti)
- call(f'sudo ip link set {interface} up')
- else:
- call(f'sudo ip link set {interface} down')
- syslog(f'Interface {interface} is admin down ...')
- elif verb in ['down-client', 'down-host']:
- if vti_link_up:
- call(f'sudo ip link set {interface} down')
+ if verb in ['up-client', 'up-client-v6', 'up-host', 'up-host-v6']:
+ with open_vti_updown_db_for_update() as db:
+ db.add(interface, connection, protocol)
+ db.commit(supply_interface_dict)
+ elif verb in ['down-client', 'down-client-v6', 'down-host', 'down-host-v6']:
+ with open_vti_updown_db_for_update() as db:
+ db.remove(interface, connection, protocol)
+ db.commit(supply_interface_dict)