Page MenuHomeVyOS Platform

ipsec-settings.py
No OneTemporary

Size
10 KB
Referenced Files
None
Subscribers
None

ipsec-settings.py

#!/usr/bin/env python3
#
# Copyright (C) 2018 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
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#
import sys
import re
import os
import jinja2
import syslog as sl
import time
import vyos.config
import vyos.defaults
from vyos import ConfigError
ra_conn_name = "remote-access"
charon_conf_file = "/etc/strongswan.d/charon.conf"
ipsec_secrets_flie = "/etc/ipsec.secrets"
ipsec_ra_conn_dir = "/etc/ipsec.d/tunnels/"
ipsec_ra_conn_file = ipsec_ra_conn_dir + ra_conn_name
ipsec_conf_flie = "/etc/ipsec.conf"
ca_cert_path = "/etc/ipsec.d/cacerts"
server_cert_path = "/etc/ipsec.d/certs"
server_key_path = "/etc/ipsec.d/private"
delim_ipsec_l2tp_begin = "### VyOS L2TP VPN Begin ###"
delim_ipsec_l2tp_end = "### VyOS L2TP VPN End ###"
charon_pidfile = "/var/run/charon.pid"
l2pt_ipsec_conf = '''
{{delim_ipsec_l2tp_begin}}
include {{ipsec_ra_conn_file}}
{{delim_ipsec_l2tp_end}}
'''
l2pt_ipsec_secrets_conf = '''
{{delim_ipsec_l2tp_begin}}
{% if ipsec_l2tp_auth_mode == 'pre-shared-secret' %}
{{outside_addr}} %any : PSK "{{ipsec_l2tp_secret}}"
{% elif ipsec_l2tp_auth_mode == 'x509' %}
: RSA {{server_key_file_copied}}
{% endif%}
{{delim_ipsec_l2tp_end}}
'''
l2tp_ipsec_ra_conn_conf = '''
{{delim_ipsec_l2tp_begin}}
conn {{ra_conn_name}}
type=transport
left={{outside_addr}}
leftsubnet=%dynamic[/1701]
rightsubnet=%dynamic
mark_in=%unique
auto=add
ike=aes256-sha1-modp1024,3des-sha1-modp1024,3des-sha1-modp1024!
dpddelay=15
dpdtimeout=45
dpdaction=clear
esp=aes256-sha1,3des-sha1!
rekey=no
{% if ipsec_l2tp_auth_mode == 'pre-shared-secret' %}
authby=secret
leftauth=psk
rightauth=psk
{% elif ipsec_l2tp_auth_mode == 'x509' %}
authby=rsasig
leftrsasigkey=%cert
rightrsasigkey=%cert
rightca=%same
leftcert={{server_cert_file_copied}}
{% endif %}
ikelifetime={{ipsec_l2tp_ike_lifetime}}
keylife={{ipsec_l2tp_lifetime}}
{{delim_ipsec_l2tp_end}}
'''
def get_config():
config = vyos.config.Config()
data = {"install_routes": "yes"}
if config.exists("vpn ipsec options disable-route-autoinstall"):
data["install_routes"] = "no"
if config.exists("vpn ipsec ipsec-interfaces interface"):
data["ipsec_interfaces"] = config.return_values("vpn ipsec ipsec-interfaces interface")
# Init config variables
data["delim_ipsec_l2tp_begin"] = delim_ipsec_l2tp_begin
data["delim_ipsec_l2tp_end"] = delim_ipsec_l2tp_end
data["ipsec_ra_conn_file"] = ipsec_ra_conn_file
data["ra_conn_name"] = ra_conn_name
# Get l2tp ipsec settings
data["ipsec_l2tp"] = False
conf_ipsec_command = "vpn l2tp remote-access ipsec-settings " #last space is useful
if config.exists(conf_ipsec_command):
data["ipsec_l2tp"] = True
# Authentication params
if config.exists(conf_ipsec_command + "authentication mode"):
data["ipsec_l2tp_auth_mode"] = config.return_value(conf_ipsec_command + "authentication mode")
if config.exists(conf_ipsec_command + "authentication pre-shared-secret"):
data["ipsec_l2tp_secret"] = config.return_value(conf_ipsec_command + "authentication pre-shared-secret")
# mode x509
if config.exists(conf_ipsec_command + "authentication x509 ca-cert-file"):
data["ipsec_l2tp_x509_ca_cert_file"] = config.return_value(conf_ipsec_command + "authentication x509 ca-cert-file")
if config.exists(conf_ipsec_command + "authentication x509 crl-file"):
data["ipsec_l2tp_x509_crl_file"] = config.return_value(conf_ipsec_command + "authentication x509 crl-file")
if config.exists(conf_ipsec_command + "authentication x509 server-cert-file"):
data["ipsec_l2tp_x509_server_cert_file"] = config.return_value(conf_ipsec_command + "authentication x509 server-cert-file")
data["server_cert_file_copied"] = server_cert_path+"/"+re.search('\w+(?:\.\w+)*$', config.return_value(conf_ipsec_command + "authentication x509 server-cert-file")).group(0)
if config.exists(conf_ipsec_command + "authentication x509 server-key-file"):
data["ipsec_l2tp_x509_server_key_file"] = config.return_value(conf_ipsec_command + "authentication x509 server-key-file")
data["server_key_file_copied"] = server_key_path+"/"+re.search('\w+(?:\.\w+)*$', config.return_value(conf_ipsec_command + "authentication x509 server-key-file")).group(0)
if config.exists(conf_ipsec_command + "authentication x509 server-key-password"):
data["ipsec_l2tp_x509_server_key_password"] = config.return_value(conf_ipsec_command + "authentication x509 server-key-password")
# Common l2tp ipsec params
if config.exists(conf_ipsec_command + "ike-lifetime"):
data["ipsec_l2tp_ike_lifetime"] = config.return_value(conf_ipsec_command + "ike-lifetime")
else:
data["ipsec_l2tp_ike_lifetime"] = "3600"
if config.exists(conf_ipsec_command + "lifetime"):
data["ipsec_l2tp_lifetime"] = config.return_value(conf_ipsec_command + "lifetime")
else:
data["ipsec_l2tp_lifetime"] = "3600"
if config.exists("vpn l2tp remote-access outside-address"):
data['outside_addr'] = config.return_value('vpn l2tp remote-access outside-address')
return data
### ipsec secret l2tp
def write_ipsec_secrets(c):
tmpl = jinja2.Template(l2pt_ipsec_secrets_conf, trim_blocks=True)
l2pt_ipsec_secrets_txt = tmpl.render(c)
old_umask = os.umask(0o077)
open(ipsec_secrets_flie,'w').write(l2pt_ipsec_secrets_txt)
os.umask(old_umask)
sl.syslog(sl.LOG_NOTICE, ipsec_secrets_flie + ' written')
### ipsec remote access connection config
def write_ipsec_ra_conn(c):
tmpl = jinja2.Template(l2tp_ipsec_ra_conn_conf, trim_blocks=True)
ipsec_ra_conn_txt = tmpl.render(c)
old_umask = os.umask(0o077)
# Create tunnels directory if does not exist
if not os.path.exists(ipsec_ra_conn_dir):
os.makedirs(ipsec_ra_conn_dir)
sl.syslog(sl.LOG_NOTICE, ipsec_ra_conn_dir + " created")
open(ipsec_ra_conn_file,'w').write(ipsec_ra_conn_txt)
os.umask(old_umask)
sl.syslog(sl.LOG_NOTICE, ipsec_ra_conn_file + ' written')
### Remove config from file by delimiter
def remove_confs(delim_begin, delim_end, conf_file):
os.system("sed -i '/"+delim_begin+"/,/"+delim_end+"/d' "+conf_file)
### Append "include /path/to/ra_conn" to ipsec conf file
def append_ipsec_conf(c):
tmpl = jinja2.Template(l2pt_ipsec_conf, trim_blocks=True)
l2pt_ipsec_conf_txt = tmpl.render(c)
old_umask = os.umask(0o077)
open(ipsec_conf_flie,'a').write(l2pt_ipsec_conf_txt)
os.umask(old_umask)
sl.syslog(sl.LOG_NOTICE, ipsec_conf_flie + ' written')
### Checking certificate storage and notice if certificate not in /config directory
def check_cert_file_store(cert_name, file_path, dts_path):
if not re.search('^\/config\/.+', file_path):
print("Warning: \"" + file_path + "\" lies outside of /config/auth directory. It will not get preserved during image upgrade.")
#Checking file existence
if not os.path.isfile(file_path):
raise ConfigError("L2TP VPN configuration error: Invalid "+cert_name+" \""+file_path+"\"")
else:
### Cpy file to /etc/ipsec.d/certs/ /etc/ipsec.d/cacerts/
# todo make check
ret = os.system('cp -f '+file_path+' '+dts_path)
if ret:
raise ConfigError("L2TP VPN configuration error: Cannot copy "+file_path)
else:
sl.syslog(sl.LOG_NOTICE, file_path + ' copied to '+dts_path)
def verify(data):
# l2tp ipsec check
if data["ipsec_l2tp"]:
# Checking dependecies for "authentication mode pre-shared-secret"
if data.get("ipsec_l2tp_auth_mode") == "pre-shared-secret":
if not data.get("ipsec_l2tp_secret"):
raise ConfigError("pre-shared-secret required")
if not data.get("outside_addr"):
raise ConfigError("outside-address not defined")
# Checking dependecies for "authentication mode x509"
if data.get("ipsec_l2tp_auth_mode") == "x509":
if not data.get("ipsec_l2tp_x509_server_key_file"):
raise ConfigError("L2TP VPN configuration error: \"server-key-file\" not defined.")
else:
check_cert_file_store("server-key-file", data['ipsec_l2tp_x509_server_key_file'], server_key_path)
if not data.get("ipsec_l2tp_x509_server_cert_file"):
raise ConfigError("L2TP VPN configuration error: \"server-cert-file\" not defined.")
else:
check_cert_file_store("server-cert-file", data['ipsec_l2tp_x509_server_cert_file'], server_cert_path)
if not data.get("ipsec_l2tp_x509_ca_cert_file"):
raise ConfigError("L2TP VPN configuration error: \"ca-cert-file\" must be defined for X.509")
else:
check_cert_file_store("ca-cert-file", data['ipsec_l2tp_x509_ca_cert_file'], ca_cert_path)
if not data.get('ipsec_interfaces'):
raise ConfigError("L2TP VPN configuration error: \"vpn ipsec ipsec-interfaces\" must be specified.")
def generate(data):
tmpl_path = os.path.join(vyos.defaults.directories["data"], "templates", "ipsec")
fs_loader = jinja2.FileSystemLoader(tmpl_path)
env = jinja2.Environment(loader=fs_loader)
charon_conf_tmpl = env.get_template("charon.tmpl")
charon_conf = charon_conf_tmpl.render(data)
with open(charon_conf_file, 'w') as f:
f.write(charon_conf)
if data["ipsec_l2tp"]:
remove_confs(delim_ipsec_l2tp_begin, delim_ipsec_l2tp_end, ipsec_conf_flie)
write_ipsec_secrets(data)
write_ipsec_ra_conn(data)
append_ipsec_conf(data)
else:
remove_confs(delim_ipsec_l2tp_begin, delim_ipsec_l2tp_end, ipsec_ra_conn_file)
remove_confs(delim_ipsec_l2tp_begin, delim_ipsec_l2tp_end, ipsec_secrets_flie)
remove_confs(delim_ipsec_l2tp_begin, delim_ipsec_l2tp_end, ipsec_conf_flie)
def restart_ipsec():
os.system("ipsec restart >&/dev/null")
# counter for apply swanctl config
counter = 10
while counter <= 10:
if os.path.exists(charon_pidfile):
os.system("swanctl -q >&/dev/null")
break
counter -=1
time.sleep(1)
if counter == 0:
raise ConfigError('VPN configuration error: IPSec is not running.')
def apply(data):
# Restart IPSec daemon
restart_ipsec()
if __name__ == '__main__':
try:
c = get_config()
verify(c)
generate(c)
apply(c)
except ConfigError as e:
print(e)
sys.exit(1)

File Metadata

Mime Type
text/x-script.python
Expires
Sat, Sep 26, 2:22 PM (1 d, 11 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4283555
Default Alt Text
ipsec-settings.py (10 KB)

Event Timeline