summaryrefslogtreecommitdiff
path: root/src/conf_mode/vpn_ipsec.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/conf_mode/vpn_ipsec.py')
-rwxr-xr-xsrc/conf_mode/vpn_ipsec.py53
1 files changed, 32 insertions, 21 deletions
diff --git a/src/conf_mode/vpn_ipsec.py b/src/conf_mode/vpn_ipsec.py
index cfefcfbe8..d207c63df 100755
--- a/src/conf_mode/vpn_ipsec.py
+++ b/src/conf_mode/vpn_ipsec.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2022 VyOS maintainers and contributors
+# 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
@@ -17,11 +17,13 @@
import ipaddress
import os
import re
+import jmespath
from sys import exit
from time import sleep
from time import time
+from vyos.base import Warning
from vyos.config import Config
from vyos.configdict import leaf_node_changed
from vyos.configverify import verify_interface_exists
@@ -51,8 +53,6 @@ dhcp_wait_attempts = 2
dhcp_wait_sleep = 1
swanctl_dir = '/etc/swanctl'
-ipsec_conf = '/etc/ipsec.conf'
-ipsec_secrets = '/etc/ipsec.secrets'
charon_conf = '/etc/strongswan.d/charon.conf'
charon_dhcp_conf = '/etc/strongswan.d/charon/dhcp.conf'
charon_radius_conf = '/etc/strongswan.d/charon/eap-radius.conf'
@@ -94,6 +94,7 @@ def get_config(config=None):
del default_values['esp_group']
del default_values['ike_group']
del default_values['remote_access']
+ del default_values['site_to_site']
ipsec = dict_merge(default_values, ipsec)
if 'esp_group' in ipsec:
@@ -142,6 +143,14 @@ def get_config(config=None):
ipsec['remote_access']['radius']['server'][server] = dict_merge(default_values,
ipsec['remote_access']['radius']['server'][server])
+ # XXX: T2665: we can not safely rely on the defaults() when there are
+ # tagNodes in place, it is better to blend in the defaults manually.
+ if dict_search('site_to_site.peer', ipsec):
+ default_values = defaults(base + ['site-to-site', 'peer'])
+ for peer in ipsec['site_to_site']['peer']:
+ ipsec['site_to_site']['peer'][peer] = dict_merge(default_values,
+ ipsec['site_to_site']['peer'][peer])
+
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'])
@@ -209,6 +218,12 @@ def verify(ipsec):
if not ipsec:
return None
+ if 'authentication' in ipsec:
+ if 'psk' in ipsec['authentication']:
+ for psk, psk_config in ipsec['authentication']['psk'].items():
+ if 'id' not in psk_config or 'secret' not in psk_config:
+ raise ConfigError(f'Authentication psk "{psk}" missing "id" or "secret"')
+
if 'interfaces' in ipsec :
for ifname in ipsec['interface']:
verify_interface_exists(ifname)
@@ -438,6 +453,10 @@ 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 vty 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 os.path.exists(f'/sys/class/net/{vti_interface}'):
@@ -521,8 +540,7 @@ def generate(ipsec):
cleanup_pki_files()
if not ipsec:
- for config_file in [ipsec_conf, ipsec_secrets, charon_dhcp_conf,
- charon_radius_conf, interface_conf, swanctl_conf]:
+ for config_file in [charon_dhcp_conf, charon_radius_conf, interface_conf, swanctl_conf]:
if os.path.isfile(config_file):
os.unlink(config_file)
render(charon_conf, 'ipsec/charon.j2', {'install_routes': default_install_routes})
@@ -588,9 +606,15 @@ def generate(ipsec):
ipsec['site_to_site']['peer'][peer]['tunnel'][tunnel]['passthrough'] = passthrough
+ # auth psk <tag> dhcp-interface <xxx>
+ if jmespath.search('authentication.psk.*.dhcp_interface', ipsec):
+ for psk, psk_config in ipsec['authentication']['psk'].items():
+ if 'dhcp_interface' in psk_config:
+ for iface in psk_config['dhcp_interface']:
+ id = get_dhcp_address(iface)
+ if id:
+ ipsec['authentication']['psk'][psk]['id'].append(id)
- render(ipsec_conf, 'ipsec/ipsec.conf.j2', ipsec)
- render(ipsec_secrets, 'ipsec/ipsec.secrets.j2', ipsec)
render(charon_conf, 'ipsec/charon.j2', ipsec)
render(charon_dhcp_conf, 'ipsec/charon/dhcp.conf.j2', ipsec)
render(charon_radius_conf, 'ipsec/charon/eap-radius.conf.j2', ipsec)
@@ -605,25 +629,12 @@ def resync_nhrp(ipsec):
if tmp > 0:
print('ERROR: failed to reapply NHRP settings!')
-def wait_for_vici_socket(timeout=5, sleep_interval=0.1):
- start_time = time()
- test_command = f'sudo socat -u OPEN:/dev/null UNIX-CONNECT:{vici_socket}'
- while True:
- if (start_time + timeout) < time():
- return None
- result = run(test_command)
- if result == 0:
- return True
- sleep(sleep_interval)
-
def apply(ipsec):
- systemd_service = 'strongswan-starter.service'
+ systemd_service = 'strongswan.service'
if not ipsec:
call(f'systemctl stop {systemd_service}')
else:
call(f'systemctl reload-or-restart {systemd_service}')
- if wait_for_vici_socket():
- call('sudo swanctl -q')
resync_nhrp(ipsec)