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.py92
1 files changed, 58 insertions, 34 deletions
diff --git a/src/conf_mode/vpn_ipsec.py b/src/conf_mode/vpn_ipsec.py
index 388f2a709..dc78c755e 100755
--- a/src/conf_mode/vpn_ipsec.py
+++ b/src/conf_mode/vpn_ipsec.py
@@ -21,7 +21,6 @@ import jmespath
from sys import exit
from time import sleep
-from time import time
from vyos.base import Warning
from vyos.config import Config
@@ -32,10 +31,7 @@ from vyos.configverify import verify_interface_exists
from vyos.configverify import dynamic_interface_pattern
from vyos.defaults import directories
from vyos.ifconfig import Interface
-from vyos.pki import encode_certificate
from vyos.pki import encode_public_key
-from vyos.pki import find_chain
-from vyos.pki import load_certificate
from vyos.pki import load_private_key
from vyos.pki import wrap_certificate
from vyos.pki import wrap_crl
@@ -50,7 +46,6 @@ 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.process import run
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -75,7 +70,7 @@ KEY_PATH = f'{swanctl_dir}/private/'
CA_PATH = f'{swanctl_dir}/x509ca/'
CRL_PATH = f'{swanctl_dir}/x509crl/'
-DHCP_HOOK_IFLIST = '/tmp/ipsec_dhcp_waiting'
+DHCP_HOOK_IFLIST = '/tmp/ipsec_dhcp_interfaces'
def get_config(config=None):
if config:
@@ -94,6 +89,7 @@ def get_config(config=None):
with_recursive_defaults=True,
with_pki=True)
+ ipsec['dhcp_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'])
@@ -126,11 +122,11 @@ def verify_pki_x509(pki, x509_conf):
if not pki or 'ca' not in pki or 'certificate' not in pki:
raise ConfigError(f'PKI is not configured')
- ca_cert_name = x509_conf['ca_certificate']
cert_name = x509_conf['certificate']
- if not dict_search_args(pki, 'ca', ca_cert_name, 'certificate'):
- raise ConfigError(f'Missing CA certificate on specified PKI CA certificate "{ca_cert_name}"')
+ for ca_cert_name in x509_conf['ca_certificate']:
+ if not dict_search_args(pki, 'ca', ca_cert_name, 'certificate'):
+ raise ConfigError(f'Missing CA certificate on specified PKI CA certificate "{ca_cert_name}"')
if not dict_search_args(pki, 'certificate', cert_name, 'certificate'):
raise ConfigError(f'Missing certificate on specified PKI certificate "{cert_name}"')
@@ -170,9 +166,7 @@ def verify(ipsec):
for interface in ipsec['interface']:
# exclude check interface for dynamic interfaces
if tmp.match(interface):
- if not interface_exists(interface):
- Warning(f'Interface "{interface}" does not exist yet and cannot be used '
- f'for IPsec until it is up!')
+ verify_interface_exists(interface, warning_only=True)
else:
verify_interface_exists(interface)
@@ -229,6 +223,32 @@ def verify(ipsec):
if 'remote_access' in ipsec:
if 'connection' in ipsec['remote_access']:
for name, ra_conf in ipsec['remote_access']['connection'].items():
+ if 'local_address' not in ra_conf and 'dhcp_interface' not in ra_conf:
+ raise ConfigError(f"Missing local-address or dhcp-interface on remote-access connection {name}")
+
+ if 'dhcp_interface' in ra_conf:
+ dhcp_interface = ra_conf['dhcp_interface']
+
+ verify_interface_exists(dhcp_interface)
+ dhcp_base = directories['isc_dhclient_dir']
+
+ if not os.path.exists(f'{dhcp_base}/dhclient_{dhcp_interface}.conf'):
+ raise ConfigError(f"Invalid dhcp-interface on remote-access connection {name}")
+
+ ipsec['dhcp_interfaces'].add(dhcp_interface)
+
+ address = get_dhcp_address(dhcp_interface)
+ count = 0
+ while not address and count < dhcp_wait_attempts:
+ address = get_dhcp_address(dhcp_interface)
+ count += 1
+ sleep(dhcp_wait_sleep)
+
+ if not address:
+ ipsec['dhcp_no_address'][f'ra_{name}'] = dhcp_interface
+ print(f"Failed to get address from dhcp-interface on remote-access connection {name} -- skipped")
+ continue
+
if 'esp_group' in ra_conf:
if 'esp_group' not in ipsec or ra_conf['esp_group'] not in ipsec['esp_group']:
raise ConfigError(f"Invalid esp-group on {name} remote-access config")
@@ -386,6 +406,8 @@ def verify(ipsec):
if not os.path.exists(f'{dhcp_base}/dhclient_{dhcp_interface}.conf'):
raise ConfigError(f"Invalid dhcp-interface on site-to-site peer {peer}")
+ ipsec['dhcp_interfaces'].add(dhcp_interface)
+
address = get_dhcp_address(dhcp_interface)
count = 0
while not address and count < dhcp_wait_attempts:
@@ -394,7 +416,7 @@ def verify(ipsec):
sleep(dhcp_wait_sleep)
if not address:
- ipsec['dhcp_no_address'][peer] = dhcp_interface
+ ipsec['dhcp_no_address'][f'peer_{peer}'] = dhcp_interface
print(f"Failed to get address from dhcp-interface on site-to-site peer {peer} -- skipped")
continue
@@ -443,32 +465,24 @@ def cleanup_pki_files():
os.unlink(file_path)
def generate_pki_files_x509(pki, x509_conf):
- ca_cert_name = x509_conf['ca_certificate']
- ca_cert_data = dict_search_args(pki, 'ca', ca_cert_name, 'certificate')
- ca_cert_crls = dict_search_args(pki, 'ca', ca_cert_name, 'crl') or []
- ca_index = 1
- crl_index = 1
+ for ca_cert_name in x509_conf['ca_certificate']:
+ ca_cert_data = dict_search_args(pki, 'ca', ca_cert_name, 'certificate')
+ ca_cert_crls = dict_search_args(pki, 'ca', ca_cert_name, 'crl') or []
+ crl_index = 1
- ca_cert = load_certificate(ca_cert_data)
- pki_ca_certs = [load_certificate(ca['certificate']) for ca in pki['ca'].values()]
+ with open(os.path.join(CA_PATH, f'{ca_cert_name}.pem'), 'w') as f:
+ f.write(wrap_certificate(ca_cert_data))
- ca_cert_chain = find_chain(ca_cert, pki_ca_certs)
+ for crl in ca_cert_crls:
+ with open(os.path.join(CRL_PATH, f'{ca_cert_name}_{crl_index}.pem'), 'w') as f:
+ f.write(wrap_crl(crl))
+ crl_index += 1
cert_name = x509_conf['certificate']
cert_data = dict_search_args(pki, 'certificate', cert_name, 'certificate')
key_data = dict_search_args(pki, 'certificate', cert_name, 'private', 'key')
protected = 'passphrase' in x509_conf
- for ca_cert_obj in ca_cert_chain:
- with open(os.path.join(CA_PATH, f'{ca_cert_name}_{ca_index}.pem'), 'w') as f:
- f.write(encode_certificate(ca_cert_obj))
- ca_index += 1
-
- for crl in ca_cert_crls:
- with open(os.path.join(CRL_PATH, f'{ca_cert_name}_{crl_index}.pem'), 'w') as f:
- f.write(wrap_crl(crl))
- crl_index += 1
-
with open(os.path.join(CERT_PATH, f'{cert_name}.pem'), 'w') as f:
f.write(wrap_certificate(cert_data))
@@ -503,9 +517,9 @@ def generate(ipsec):
render(charon_conf, 'ipsec/charon.j2', {'install_routes': default_install_routes})
return
- if ipsec['dhcp_no_address']:
+ if ipsec['dhcp_interfaces']:
with open(DHCP_HOOK_IFLIST, 'w') as f:
- f.write(" ".join(ipsec['dhcp_no_address'].values()))
+ f.write(" ".join(ipsec['dhcp_interfaces']))
elif os.path.exists(DHCP_HOOK_IFLIST):
os.unlink(DHCP_HOOK_IFLIST)
@@ -522,13 +536,23 @@ def generate(ipsec):
if 'remote_access' in ipsec and 'connection' in ipsec['remote_access']:
for rw, rw_conf in ipsec['remote_access']['connection'].items():
+ if f'ra_{rw}' in ipsec['dhcp_no_address']:
+ continue
+
+ local_ip = ''
+ if 'local_address' in rw_conf:
+ local_ip = rw_conf['local_address']
+ elif 'dhcp_interface' in rw_conf:
+ local_ip = get_dhcp_address(rw_conf['dhcp_interface'])
+
+ ipsec['remote_access']['connection'][rw]['local_address'] = local_ip
if 'authentication' in rw_conf and 'x509' in rw_conf['authentication']:
generate_pki_files_x509(ipsec['pki'], rw_conf['authentication']['x509'])
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 peer in ipsec['dhcp_no_address']:
+ if f'peer_{peer}' in ipsec['dhcp_no_address']:
continue
if peer_conf['authentication']['mode'] == 'x509':