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.py78
1 files changed, 61 insertions, 17 deletions
diff --git a/src/conf_mode/vpn_ipsec.py b/src/conf_mode/vpn_ipsec.py
index 4efedd995..433c51e7e 100755
--- a/src/conf_mode/vpn_ipsec.py
+++ b/src/conf_mode/vpn_ipsec.py
@@ -23,10 +23,11 @@ from vyos.config import Config
from vyos.configdict import leaf_node_changed
from vyos.configverify import verify_interface_exists
from vyos.ifconfig import Interface
+from vyos.template import ip_from_cidr
from vyos.template import render
+from vyos.validate import is_ipv6_link_local
from vyos.util import call
from vyos.util import dict_search
-from vyos.util import get_interface_address
from vyos.util import process_named_running
from vyos.util import run
from vyos.util import cidr_fit
@@ -35,9 +36,9 @@ from vyos import airbag
airbag.enable()
authby_translate = {
- 'pre-shared-secret': 'secret',
- 'rsa': 'rsasig',
- 'x509': 'rsasig'
+ 'pre-shared-secret': 'psk',
+ 'rsa': 'pubkey',
+ 'x509': 'pubkey'
}
default_pfs = 'dh-group2'
pfs_translate = {
@@ -73,12 +74,18 @@ any_log_modes = [
ike_ciphers = {}
esp_ciphers = {}
+dhcp_wait_attempts = 2
+dhcp_wait_sleep = 1
+
mark_base = 0x900000
-CA_PATH = "/etc/ipsec.d/cacerts/"
-CRL_PATH = "/etc/ipsec.d/crls/"
+CERT_PATH="/etc/swanctl/x509/"
+KEY_PATH="/etc/swanctl/private/"
+CA_PATH = "/etc/swanctl/x509ca/"
+CRL_PATH = "/etc/swanctl/x509crl/"
DHCP_BASE = "/var/lib/dhcp/dhclient"
+DHCP_HOOK_IFLIST="/tmp/ipsec_dhcp_waiting"
LOCAL_KEY_PATHS = ['/config/auth/', '/config/ipsec.d/rsa-keys/']
X509_PATH = '/config/auth/'
@@ -96,6 +103,7 @@ def get_config(config=None):
ipsec = conf.get_config_dict(base, key_mangling=('-', '_'),
get_first_key=True, no_tag_node_value_mangle=True)
+ ipsec['dhcp_no_address'] = {}
ipsec['interface_change'] = leaf_node_changed(conf, base + ['ipsec-interfaces', 'interface'])
ipsec['l2tp_exists'] = conf.exists('vpn l2tp remote-access ipsec-settings ')
ipsec['nhrp_exists'] = conf.exists('protocols nhrp tunnel')
@@ -119,7 +127,7 @@ def get_config(config=None):
if enc and hash:
ciphers.append(f"{enc}-{hash}-{pfs_translate[pfs]}" if pfs else f"{enc}-{hash}")
- ike_ciphers[group] = ','.join(ciphers) + '!'
+ ike_ciphers[group] = ','.join(ciphers)
if 'esp_group' in ipsec:
for group, esp_conf in ipsec['esp_group'].items():
@@ -139,7 +147,7 @@ def get_config(config=None):
hash = proposal['hash'] if 'hash' in proposal else None
if enc and hash:
ciphers.append(f"{enc}-{hash}-{pfs_translate[pfs]}" if pfs else f"{enc}-{hash}")
- esp_ciphers[group] = ','.join(ciphers) + '!'
+ esp_ciphers[group] = ','.join(ciphers)
return ipsec
@@ -162,6 +170,15 @@ def verify_rsa_local_key(ipsec):
def verify_rsa_key(ipsec, key_name):
return dict_search(f'rsa_key_name.{key_name}.rsa_key', ipsec['rsa_keys'])
+def get_dhcp_address(iface):
+ addresses = Interface(iface).get_addr()
+ if not addresses:
+ return None
+ for address in addresses:
+ if not is_ipv6_link_local(address):
+ return ip_from_cidr(address)
+ return None
+
def verify(ipsec):
if not ipsec:
return None
@@ -252,9 +269,17 @@ def verify(ipsec):
if not os.path.exists(f'{DHCP_BASE}_{dhcp_interface}.conf'):
raise ConfigError(f"Invalid dhcp-interface on site-to-site peer {peer}")
- address = Interface(dhcp_interface).get_addr()
+ 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:
- raise ConfigError(f"Failed to get address from dhcp-interface on site-to-site peer {peer}")
+ ipsec['dhcp_no_address'][peer] = dhcp_interface
+ print(f"Failed to get address from dhcp-interface on site-to-site peer {peer} -- skipped")
+ continue
if 'vti' in peer_conf:
if 'local_address' in peer_conf and 'dhcp_interface' in peer_conf:
@@ -291,16 +316,28 @@ def generate(ipsec):
data = {}
if ipsec:
+ if ipsec['dhcp_no_address']:
+ with open(DHCP_HOOK_IFLIST, 'w') as f:
+ f.write(" ".join(ipsec['dhcp_no_address'].values()))
+
data = ipsec
data['authby'] = authby_translate
data['ciphers'] = {'ike': ike_ciphers, 'esp': esp_ciphers}
data['marks'] = {}
data['rsa_local_key'] = verify_rsa_local_key(ipsec)
- data['x509_path'] = X509_PATH
if 'site_to_site' in data and 'peer' in data['site_to_site']:
for peer, peer_conf in ipsec['site_to_site']['peer'].items():
+ if peer in ipsec['dhcp_no_address']:
+ continue
+
if peer_conf['authentication']['mode'] == 'x509':
+ cert_file = os.path.join(X509_PATH, peer_conf['authentication']['x509']['cert_file'])
+ call(f'cp -f {cert_file} {CERT_PATH}')
+
+ key_file = os.path.join(X509_PATH, peer_conf['authentication']['x509']['key']['file'])
+ call(f'cp -f {key_file} {KEY_PATH}')
+
ca_cert_file = os.path.join(X509_PATH, peer_conf['authentication']['x509']['ca_cert_file'])
call(f'cp -f {ca_cert_file} {CA_PATH}')
@@ -312,22 +349,29 @@ def generate(ipsec):
if 'local_address' in peer_conf:
local_ip = peer_conf['local_address']
elif 'dhcp_interface' in peer_conf:
- local_ip = Interface(peer_conf['dhcp_interface']).get_addr()
+ local_ip = get_dhcp_address(peer_conf['dhcp_interface'])
data['site_to_site']['peer'][peer]['local_address'] = local_ip
if 'vti' in peer_conf and 'bind' in peer_conf['vti']:
vti_interface = peer_conf['vti']['bind']
data['marks'][vti_interface] = get_mark(vti_interface)
- else:
+
+ if 'tunnel' in peer_conf:
for tunnel, tunnel_conf in peer_conf['tunnel'].items():
- local_prefix = dict_search('local.prefix', tunnel_conf)
- remote_prefix = dict_search('remote.prefix', tunnel_conf)
+ local_prefixes = dict_search('local.prefix', tunnel_conf)
+ remote_prefixes = dict_search('remote.prefix', tunnel_conf)
- if not local_prefix or not remote_prefix:
+ if not local_prefixes or not remote_prefixes:
continue
- passthrough = cidr_fit(local_prefix, remote_prefix)
+ passthrough = []
+
+ for local_prefix in local_prefixes:
+ for remote_prefix in remote_prefixes:
+ if cidr_fit(local_prefix, remote_prefix):
+ passthrough.append(local_prefix)
+
data['site_to_site']['peer'][peer]['tunnel'][tunnel]['passthrough'] = passthrough
if 'logging' in ipsec and 'log_modes' in ipsec['logging']: