summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--data/templates/ipsec/interfaces_use.conf.tmpl5
-rw-r--r--data/templates/ipsec/ipsec.conf.tmpl6
-rw-r--r--data/templates/ipsec/ipsec.secrets.tmpl10
-rw-r--r--data/templates/ipsec/remote-access.tmpl28
-rw-r--r--data/templates/ipsec/swanctl.conf.tmpl20
-rw-r--r--data/templates/ipsec/swanctl/l2tp.tmpl30
-rw-r--r--interface-definitions/containers.xml.in1
-rw-r--r--interface-definitions/include/dhcp-interface.xml.i15
-rw-r--r--interface-definitions/include/ipsec/authentication-pre-shared-secret.xml.i11
-rw-r--r--interface-definitions/include/static/static-route.xml.i16
-rw-r--r--interface-definitions/interfaces-tunnel.xml.in16
-rw-r--r--interface-definitions/vpn_ipsec.xml.in57
-rw-r--r--interface-definitions/vpn_l2tp.xml.in57
-rw-r--r--python/vyos/airbag.py24
-rw-r--r--python/vyos/ifconfig/vrrp.py9
-rw-r--r--python/vyos/util.py4
-rw-r--r--smoketest/configs/pki-ipsec27
-rwxr-xr-xsmoketest/scripts/cli/test_protocols_nhrp.py2
-rwxr-xr-xsmoketest/scripts/cli/test_vpn_ipsec.py2
-rwxr-xr-xsrc/conf_mode/interfaces-vxlan.py21
-rwxr-xr-xsrc/conf_mode/ipsec-settings.py224
-rw-r--r--[-rwxr-xr-x]src/conf_mode/vpn_ipsec.py70
-rwxr-xr-xsrc/conf_mode/vpn_l2tp.py1
-rwxr-xr-xsrc/etc/vmware-tools/scripts/resume-vm-default.d/ether-resume.py11
-rwxr-xr-xsrc/migration-scripts/ipsec/5-to-66
-rwxr-xr-xsrc/migration-scripts/l2tp/3-to-4169
27 files changed, 394 insertions, 450 deletions
diff --git a/Makefile b/Makefile
index 84dbab401..32bc58be0 100644
--- a/Makefile
+++ b/Makefile
@@ -86,7 +86,7 @@ clean:
.PHONY: test
test:
- set -e; python3 -m compileall -q .
+ set -e; python3 -m compileall -q -x '/vmware-tools/scripts/' .
PYTHONPATH=python/ python3 -m "nose" --with-xunit src --with-coverage --cover-erase --cover-xml --cover-package src/conf_mode,src/op_mode,src/completion,src/helpers,src/validators,src/tests --verbose
.PHONY: sonar
diff --git a/data/templates/ipsec/interfaces_use.conf.tmpl b/data/templates/ipsec/interfaces_use.conf.tmpl
index 3d285b9be..a77102396 100644
--- a/data/templates/ipsec/interfaces_use.conf.tmpl
+++ b/data/templates/ipsec/interfaces_use.conf.tmpl
@@ -1,6 +1,5 @@
-{% if ipsec_interfaces is defined and 'interface' in ipsec_interfaces %}
-{% set interfaces = ipsec_interfaces['interface'] %}
+{% if interface is defined %}
charon {
- interfaces_use = {{ ', '.join(interfaces) if interfaces is not string else interfaces }}
+ interfaces_use = {{ ', '.join(interface) }}
}
{% endif %} \ No newline at end of file
diff --git a/data/templates/ipsec/ipsec.conf.tmpl b/data/templates/ipsec/ipsec.conf.tmpl
index a9ea1aac7..1cb531e76 100644
--- a/data/templates/ipsec/ipsec.conf.tmpl
+++ b/data/templates/ipsec/ipsec.conf.tmpl
@@ -16,9 +16,3 @@ config setup
{% if include_ipsec_conf is defined %}
include {{ include_ipsec_conf }}
{% endif %}
-
-{% if delim_ipsec_l2tp_begin is defined %}
-{{delim_ipsec_l2tp_begin}}
-include {{ipsec_ra_conn_file}}
-{{delim_ipsec_l2tp_end}}
-{% endif %}
diff --git a/data/templates/ipsec/ipsec.secrets.tmpl b/data/templates/ipsec/ipsec.secrets.tmpl
index 43b5fe0d2..057e291ed 100644
--- a/data/templates/ipsec/ipsec.secrets.tmpl
+++ b/data/templates/ipsec/ipsec.secrets.tmpl
@@ -3,13 +3,3 @@
{% if include_ipsec_secrets is defined %}
include {{ include_ipsec_secrets }}
{% endif %}
-
-{% if delim_ipsec_l2tp_begin is defined %}
-{{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}}
-{% endif %}
diff --git a/data/templates/ipsec/remote-access.tmpl b/data/templates/ipsec/remote-access.tmpl
deleted file mode 100644
index fae48232f..000000000
--- a/data/templates/ipsec/remote-access.tmpl
+++ /dev/null
@@ -1,28 +0,0 @@
-{{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}}
diff --git a/data/templates/ipsec/swanctl.conf.tmpl b/data/templates/ipsec/swanctl.conf.tmpl
index a6ab73cc2..102d7583f 100644
--- a/data/templates/ipsec/swanctl.conf.tmpl
+++ b/data/templates/ipsec/swanctl.conf.tmpl
@@ -1,4 +1,5 @@
### Autogenerated by vpn_ipsec.py ###
+{% import 'ipsec/swanctl/l2tp.tmpl' as l2tp_tmpl %}
{% import 'ipsec/swanctl/profile.tmpl' as profile_tmpl %}
{% import 'ipsec/swanctl/peer.tmpl' as peer_tmpl %}
{% import 'ipsec/swanctl/remote_access.tmpl' as remote_access_tmpl %}
@@ -19,6 +20,9 @@ connections {
{{ remote_access_tmpl.conn(rw, rw_conf, ike_group, esp_group) }}
{% endfor %}
{% endif %}
+{% if l2tp %}
+{{ l2tp_tmpl.conn(l2tp, l2tp_outside_address, l2tp_ike_default, l2tp_esp_default, ike_group, esp_group) }}
+{% endif %}
}
pools {
@@ -103,5 +107,21 @@ secrets {
{% endif %}
{% endfor %}
{% endif %}
+{% if l2tp %}
+{% if l2tp.authentication.mode == 'pre-shared-secret' %}
+ ike_l2tp_remote_access {
+ id = "{{ l2tp_outside_address }}"
+ secret = "{{ l2tp.authentication.pre_shared_secret }}"
+ }
+{% elif l2tp.authentication.mode == 'x509' %}
+ private_l2tp_remote_access {
+ id = "{{ l2tp_outside_address }}"
+ file = {{ l2tp.authentication.x509.certificate }}.pem
+{% if l2tp.authentication.x509.passphrase is defined %}
+ secret = "{{ l2tp.authentication.x509.passphrase }}"
+{% endif %}
+ }
+{% endif %}
+{% endif %}
}
diff --git a/data/templates/ipsec/swanctl/l2tp.tmpl b/data/templates/ipsec/swanctl/l2tp.tmpl
new file mode 100644
index 000000000..2df5c2a4d
--- /dev/null
+++ b/data/templates/ipsec/swanctl/l2tp.tmpl
@@ -0,0 +1,30 @@
+{% macro conn(l2tp, l2tp_outside_address, l2tp_ike_default, l2tp_esp_default, ike_group, esp_group) %}
+{% set l2tp_ike = ike_group[l2tp.ike_group] if l2tp.ike_group is defined else None %}
+{% set l2tp_esp = esp_group[l2tp.esp_group] if l2tp.esp_group is defined else None %}
+ l2tp_remote_access {
+ proposals = {{ l2tp_ike | get_esp_ike_cipher | join(',') if l2tp_ike else l2tp_ike_default }}
+ local_addrs = {{ l2tp_outside_address }}
+ dpd_delay = 15s
+ dpd_timeout = 45s
+ rekey_time = {{ l2tp_ike.lifetime if l2tp_ike else l2tp.ike_lifetime }}s
+ reauth_time = 0
+ local {
+ auth = {{ 'psk' if l2tp.authentication.mode == 'pre-shared-secret' else 'pubkey' }}
+{% if l2tp.authentication.mode == 'x509' %}
+ certs = {{ l2tp.authentication.x509.certificate }}.pem
+{% endif %}
+ }
+ remote {
+ auth = {{ 'psk' if l2tp.authentication.mode == 'pre-shared-secret' else 'pubkey' }}
+ }
+ children {
+ l2tp_remote_access_esp {
+ mode = transport
+ esp_proposals = {{ l2tp_esp | get_esp_ike_cipher | join(',') if l2tp_esp else l2tp_esp_default }}
+ life_time = {{ l2tp_esp.lifetime if l2tp_esp else l2tp.lifetime }}s
+ local_ts = dynamic[/1701]
+ remote_ts = dynamic
+ }
+ }
+ }
+{% endmacro %}
diff --git a/interface-definitions/containers.xml.in b/interface-definitions/containers.xml.in
index 6fc53c105..124b1f65e 100644
--- a/interface-definitions/containers.xml.in
+++ b/interface-definitions/containers.xml.in
@@ -3,6 +3,7 @@
<node name="container" owner="${vyos_conf_scripts_dir}/containers.py">
<properties>
<help>Container applications</help>
+ <priority>1280</priority>
</properties>
<children>
<tagNode name="name">
diff --git a/interface-definitions/include/dhcp-interface.xml.i b/interface-definitions/include/dhcp-interface.xml.i
new file mode 100644
index 000000000..939b45f15
--- /dev/null
+++ b/interface-definitions/include/dhcp-interface.xml.i
@@ -0,0 +1,15 @@
+ <leafNode name="dhcp-interface">
+ <properties>
+ <help>DHCP interface supplying next-hop IP address</help>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_interfaces.py</script>
+ </completionHelp>
+ <valueHelp>
+ <format>txt</format>
+ <description>DHCP interface name</description>
+ </valueHelp>
+ <constraint>
+ <validator name="interface-name"/>
+ </constraint>
+ </properties>
+ </leafNode>
diff --git a/interface-definitions/include/ipsec/authentication-pre-shared-secret.xml.i b/interface-definitions/include/ipsec/authentication-pre-shared-secret.xml.i
new file mode 100644
index 000000000..af2669335
--- /dev/null
+++ b/interface-definitions/include/ipsec/authentication-pre-shared-secret.xml.i
@@ -0,0 +1,11 @@
+<!-- include start from ipsec/authentication-pre-shared-secret.xml.i -->
+<leafNode name="pre-shared-secret">
+ <properties>
+ <help>Pre-shared secret key</help>
+ <valueHelp>
+ <format>txt</format>
+ <description>Pre-shared secret key</description>
+ </valueHelp>
+ </properties>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/include/static/static-route.xml.i b/interface-definitions/include/static/static-route.xml.i
index 254ea3163..21babc015 100644
--- a/interface-definitions/include/static/static-route.xml.i
+++ b/interface-definitions/include/static/static-route.xml.i
@@ -31,21 +31,7 @@
</leafNode>
</children>
</node>
- <leafNode name="dhcp-interface">
- <properties>
- <help>DHCP interface supplying next-hop IP address</help>
- <completionHelp>
- <script>${vyos_completion_dir}/list_interfaces.py</script>
- </completionHelp>
- <valueHelp>
- <format>txt</format>
- <description>DHCP interface name</description>
- </valueHelp>
- <constraint>
- <validator name="interface-name"/>
- </constraint>
- </properties>
- </leafNode>
+ #include <include/dhcp-interface.xml.i>
<tagNode name="interface">
<properties>
<help>Next-hop IPv4 router interface</help>
diff --git a/interface-definitions/interfaces-tunnel.xml.in b/interface-definitions/interfaces-tunnel.xml.in
index 56f8ea79c..6851c0354 100644
--- a/interface-definitions/interfaces-tunnel.xml.in
+++ b/interface-definitions/interfaces-tunnel.xml.in
@@ -61,21 +61,7 @@
</constraint>
</properties>
</leafNode>
- <leafNode name="dhcp-interface">
- <properties>
- <help>dhcp interface</help>
- <valueHelp>
- <format>interface</format>
- <description>DHCP interface that supplies the local IP address for this tunnel</description>
- </valueHelp>
- <completionHelp>
- <script>${vyos_completion_dir}/list_interfaces.py</script>
- </completionHelp>
- <constraint>
- <regex>^(en|eth|br|bond|gnv|vxlan|wg|tun)[0-9]+$</regex>
- </constraint>
- </properties>
- </leafNode>
+ #include <include/dhcp-interface.xml.i>
<leafNode name="encapsulation">
<properties>
<help>Encapsulation of this tunnel interface</help>
diff --git a/interface-definitions/vpn_ipsec.xml.in b/interface-definitions/vpn_ipsec.xml.in
index 147f351f2..9dbebdc0f 100644
--- a/interface-definitions/vpn_ipsec.xml.in
+++ b/interface-definitions/vpn_ipsec.xml.in
@@ -52,6 +52,7 @@
<regex>^(disable|enable)$</regex>
</constraint>
</properties>
+ <defaultValue>disable</defaultValue>
</leafNode>
<leafNode name="lifetime">
<properties>
@@ -509,22 +510,15 @@
<help>Sets to include an additional secrets file for strongSwan. Use an absolute path to specify the included file.</help>
</properties>
</leafNode>
- <node name="ipsec-interfaces">
+ <leafNode name="interface">
<properties>
- <help>Interface to use for VPN [REQUIRED]</help>
+ <help>Onterface used for IPsec communication</help>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_interfaces.py</script>
+ </completionHelp>
+ <multi/>
</properties>
- <children>
- <leafNode name="interface">
- <properties>
- <help>IPsec interface [REQUIRED]</help>
- <completionHelp>
- <script>${vyos_completion_dir}/list_interfaces.py</script>
- </completionHelp>
- <multi/>
- </properties>
- </leafNode>
- </children>
- </node>
+ </leafNode>
<node name="log">
<properties>
<help>IPsec logging</help>
@@ -704,15 +698,7 @@
</valueHelp>
</properties>
</leafNode>
- <leafNode name="pre-shared-secret">
- <properties>
- <help>Pre-shared secret key</help>
- <valueHelp>
- <format>txt</format>
- <description>Pre-shared secret key</description>
- </valueHelp>
- </properties>
- </leafNode>
+ #include <include/ipsec/authentication-pre-shared-secret.xml.i>
</children>
</node>
<node name="bind">
@@ -811,11 +797,7 @@
</properties>
<defaultValue>x509</defaultValue>
</leafNode>
- <leafNode name="pre-shared-secret">
- <properties>
- <help>Pre-shared-secret used for server authentication</help>
- </properties>
- </leafNode>
+ #include <include/ipsec/authentication-pre-shared-secret.xml.i>
</children>
</node>
#include <include/generic-description.xml.i>
@@ -947,15 +929,7 @@
</constraint>
</properties>
</leafNode>
- <leafNode name="pre-shared-secret">
- <properties>
- <help>Pre-shared secret key</help>
- <valueHelp>
- <format>txt</format>
- <description>Pre-shared secret key</description>
- </valueHelp>
- </properties>
- </leafNode>
+ #include <include/ipsec/authentication-pre-shared-secret.xml.i>
<leafNode name="remote-id">
<properties>
<help>ID for remote authentication</help>
@@ -1001,14 +975,7 @@
</properties>
</leafNode>
#include <include/generic-description.xml.i>
- <leafNode name="dhcp-interface">
- <properties>
- <help>DHCP interface to listen on</help>
- <completionHelp>
- <script>${vyos_completion_dir}/list_interfaces.py</script>
- </completionHelp>
- </properties>
- </leafNode>
+ #include <include/dhcp-interface.xml.i>
<leafNode name="force-encapsulation">
<properties>
<help>Force UDP Encapsulation for ESP Payloads</help>
diff --git a/interface-definitions/vpn_l2tp.xml.in b/interface-definitions/vpn_l2tp.xml.in
index 4fbf3fa44..6cf5218ff 100644
--- a/interface-definitions/vpn_l2tp.xml.in
+++ b/interface-definitions/vpn_l2tp.xml.in
@@ -70,51 +70,8 @@
</completionHelp>
</properties>
</leafNode>
- <leafNode name="pre-shared-secret">
- <properties>
- <help>Pre-shared secret for IPsec</help>
- </properties>
- </leafNode>
- <node name="x509">
- <properties>
- <help>X.509 certificate</help>
- </properties>
- <children>
- #include <include/certificate-ca.xml.i>
- <leafNode name="crl-file">
- <properties>
- <help>File containing the X.509 Certificate Revocation List (CRL)</help>
- <valueHelp>
- <format>txt</format>
- <description>File in /config/auth</description>
- </valueHelp>
- </properties>
- </leafNode>
- <leafNode name="server-cert-file">
- <properties>
- <help>File containing the X.509 certificate for the remote access VPN server (this host)</help>
- <valueHelp>
- <format>txt</format>
- <description>File in /config/auth</description>
- </valueHelp>
- </properties>
- </leafNode>
- <leafNode name="server-key-file">
- <properties>
- <help>File containing the private key for the X.509 certificate for the remote access VPN server (this host)</help>
- <valueHelp>
- <format>txt</format>
- <description>File in /config/auth</description>
- </valueHelp>
- </properties>
- </leafNode>
- <leafNode name="server-key-password">
- <properties>
- <help>Password that protects the private key</help>
- </properties>
- </leafNode>
- </children>
- </node>
+ #include <include/ipsec/authentication-pre-shared-secret.xml.i>
+ #include <include/ipsec/authentication-x509.xml.i>
</children>
</node>
<leafNode name="ike-lifetime">
@@ -128,6 +85,7 @@
<validator name="numeric" argument="--range 30-86400"/>
</constraint>
</properties>
+ <defaultValue>3600</defaultValue>
</leafNode>
<leafNode name="lifetime">
<properties>
@@ -140,7 +98,10 @@
<validator name="numeric" argument="--range 30-86400"/>
</constraint>
</properties>
+ <defaultValue>3600</defaultValue>
</leafNode>
+ #include <include/ipsec/esp-group.xml.i>
+ #include <include/ipsec/ike-group.xml.i>
</children>
</node>
#include <include/accel-ppp/wins-server.xml.i>
@@ -159,11 +120,7 @@
<help>Description for L2TP remote-access settings</help>
</properties>
</leafNode>
- <leafNode name="dhcp-interface">
- <properties>
- <help>DHCP interface to listen on</help>
- </properties>
- </leafNode>
+ #include <include/dhcp-interface.xml.i>
<leafNode name="idle">
<properties>
<help>PPP idle timeout</help>
diff --git a/python/vyos/airbag.py b/python/vyos/airbag.py
index 510ab7f46..a20f44207 100644
--- a/python/vyos/airbag.py
+++ b/python/vyos/airbag.py
@@ -18,7 +18,6 @@ from datetime import datetime
from vyos import debug
from vyos.logger import syslog
-from vyos.version import get_version
from vyos.version import get_full_version_data
@@ -78,7 +77,7 @@ def bug_report(dtype, value, trace):
information.update({
'date': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
'trace': trace,
- 'instructions': COMMUNITY if 'rolling' in get_version() else SUPPORTED,
+ 'instructions': INSTRUCTIONS,
'note': note,
})
@@ -162,20 +161,13 @@ When reporting problems, please include as much information as possible:
"""
-COMMUNITY = """\
-- Make sure you are running the latest version of the code available at
- https://downloads.vyos.io/rolling/current/amd64/vyos-rolling-latest.iso
-- Consult the forum to see how to handle this issue
- https://forum.vyos.io
-- Join our community on slack where our users exchange help and advice
- https://vyos.slack.com
-""".strip()
-
-SUPPORTED = """\
-- Make sure you are running the latest stable version of VyOS
- the code is available at https://downloads.vyos.io/?dir=release/current
-- Contact us using the online help desk
+INSTRUCTIONS = """\
+- Contact us using the online help desk if you have a subscription:
https://support.vyos.io/
-- Join our community on slack where our users exchange help and advice
+- Make sure you are running the latest version of VyOS available at:
+ https://vyos.net/get/
+- Consult the community forum to see how to handle this issue:
+ https://forum.vyos.io
+- Join us on Slack where our users exchange help and advice:
https://vyos.slack.com
""".strip()
diff --git a/python/vyos/ifconfig/vrrp.py b/python/vyos/ifconfig/vrrp.py
index d3e9d5df2..b522cc1ab 100644
--- a/python/vyos/ifconfig/vrrp.py
+++ b/python/vyos/ifconfig/vrrp.py
@@ -92,11 +92,14 @@ class VRRP(object):
try:
# send signal to generate the configuration file
pid = util.read_file(cls.location['pid'])
- os.kill(int(pid), cls._signal[what])
+ util.wait_for_file_write_complete(fname,
+ pre_hook=(lambda: os.kill(int(pid), cls._signal[what])),
+ timeout=30)
- # should look for file size change?
- sleep(0.2)
return util.read_file(fname)
+ except OSError:
+ # raised by vyos.util.read_file
+ raise VRRPNoData("VRRP data is not available (wait time exceeded)")
except FileNotFoundError:
raise VRRPNoData("VRRP data is not available (process not running or no active groups)")
except Exception:
diff --git a/python/vyos/util.py b/python/vyos/util.py
index 5a96013ea..d5cd46a6c 100644
--- a/python/vyos/util.py
+++ b/python/vyos/util.py
@@ -515,6 +515,7 @@ def wait_for_inotify(file_path, pre_hook=None, event_type=None, timeout=None, sl
from inotify.adapters import Inotify
from time import time
+ from time import sleep
time_start = time()
@@ -530,11 +531,14 @@ def wait_for_inotify(file_path, pre_hook=None, event_type=None, timeout=None, sl
# the file failed to have been written to and closed within the timeout
raise OSError("Waiting for file {} to be written has failed".format(file_path))
+ # Most such events don't take much time, so it's better to check right away
+ # and sleep later.
if event is not None:
(_, type_names, path, filename) = event
if filename == os.path.basename(file_path):
if event_type in type_names:
return
+ sleep(sleep_interval)
def wait_for_file_write_complete(file_path, pre_hook=None, timeout=None, sleep_interval=0.1):
""" Waits for a process to close a file after opening it in write mode. """
diff --git a/smoketest/configs/pki-ipsec b/smoketest/configs/pki-ipsec
index 5025117f7..6fc239d27 100644
--- a/smoketest/configs/pki-ipsec
+++ b/smoketest/configs/pki-ipsec
@@ -105,6 +105,33 @@ vpn {
}
}
}
+ l2tp {
+ remote-access {
+ authentication {
+ local-users {
+ username alice {
+ password notsecure
+ }
+ }
+ mode local
+ }
+ client-ip-pool {
+ start 192.168.255.2
+ stop 192.168.255.254
+ }
+ ipsec-settings {
+ authentication {
+ mode x509
+ x509 {
+ ca-cert-file /config/auth/ovpn_test_ca.pem
+ server-cert-file /config/auth/ovpn_test_server.pem
+ server-key-file /config/auth/ovpn_test_server.key
+ }
+ }
+ }
+ outside-address 192.168.150.1
+ }
+ }
rsa-keys {
local-key {
file /config/auth/ovpn_test_server.key
diff --git a/smoketest/scripts/cli/test_protocols_nhrp.py b/smoketest/scripts/cli/test_protocols_nhrp.py
index 8389e42e9..aa0ac268d 100755
--- a/smoketest/scripts/cli/test_protocols_nhrp.py
+++ b/smoketest/scripts/cli/test_protocols_nhrp.py
@@ -68,7 +68,7 @@ class TestProtocolsNHRP(VyOSUnitTestSHIM.TestCase):
self.cli_set(vpn_path + ["ike-group", "IKE-HUB", "proposal", "2", "hash", "sha1"])
# Profile - Not doing full DMVPN checks here, just want to verify the profile name in the output
- self.cli_set(vpn_path + ["ipsec-interfaces", "interface", "eth0"])
+ self.cli_set(vpn_path + ["interface", "eth0"])
self.cli_set(vpn_path + ["profile", "NHRPVPN", "authentication", "mode", "pre-shared-secret"])
self.cli_set(vpn_path + ["profile", "NHRPVPN", "authentication", "pre-shared-secret", "secret"])
self.cli_set(vpn_path + ["profile", "NHRPVPN", "bind", "tunnel", "tun100"])
diff --git a/smoketest/scripts/cli/test_vpn_ipsec.py b/smoketest/scripts/cli/test_vpn_ipsec.py
index fda8b74b1..a34387dc9 100755
--- a/smoketest/scripts/cli/test_vpn_ipsec.py
+++ b/smoketest/scripts/cli/test_vpn_ipsec.py
@@ -112,7 +112,7 @@ rgiyCHemtMepq57Pl1Nmj49eEA==
class TestVPNIPsec(VyOSUnitTestSHIM.TestCase):
def setUp(self):
- self.cli_set(base_path + ['ipsec-interfaces', 'interface', f'{interface}.{vif}'])
+ self.cli_set(base_path + ['interface', f'{interface}.{vif}'])
# Set IKE/ESP Groups
self.cli_set(base_path + ['esp-group', esp_group, 'proposal', '1', 'encryption', 'aes128'])
diff --git a/src/conf_mode/interfaces-vxlan.py b/src/conf_mode/interfaces-vxlan.py
index 8e6247a30..804f2d14f 100755
--- a/src/conf_mode/interfaces-vxlan.py
+++ b/src/conf_mode/interfaces-vxlan.py
@@ -25,7 +25,9 @@ from vyos.configverify import verify_address
from vyos.configverify import verify_bridge_delete
from vyos.configverify import verify_mtu_ipv6
from vyos.configverify import verify_source_interface
-from vyos.ifconfig import VXLANIf, Interface
+from vyos.ifconfig import Interface
+from vyos.ifconfig import VXLANIf
+from vyos.template import is_ipv6
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -65,12 +67,19 @@ def verify(vxlan):
raise ConfigError('Must configure VNI for VXLAN')
if 'source_interface' in vxlan:
- # VXLAN adds a 50 byte overhead - we need to check the underlaying MTU
- # if our configured MTU is at least 50 bytes less
+ # VXLAN adds at least an overhead of 50 byte - we need to check the
+ # underlaying device if our VXLAN package is not going to be fragmented!
+ vxlan_overhead = 50
+ if 'source_address' in vxlan and is_ipv6(vxlan['source_address']):
+ # IPv6 adds an extra 20 bytes overhead because the IPv6 header is 20
+ # bytes larger than the IPv4 header - assuming no extra options are
+ # in use.
+ vxlan_overhead += 20
+
lower_mtu = Interface(vxlan['source_interface']).get_mtu()
- if lower_mtu < (int(vxlan['mtu']) + 50):
- raise ConfigError('VXLAN has a 50 byte overhead, underlaying device ' \
- f'MTU is to small ({lower_mtu} bytes)')
+ if lower_mtu < (int(vxlan['mtu']) + vxlan_overhead):
+ raise ConfigError(f'Underlaying device MTU is to small ({lower_mtu} '\
+ f'bytes) for VXLAN overhead ({vxlan_overhead} bytes!)')
verify_mtu_ipv6(vxlan)
verify_address(vxlan)
diff --git a/src/conf_mode/ipsec-settings.py b/src/conf_mode/ipsec-settings.py
deleted file mode 100755
index 0599bf101..000000000
--- a/src/conf_mode/ipsec-settings.py
+++ /dev/null
@@ -1,224 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2018-2020 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 re
-import os
-
-from time import sleep
-from sys import exit
-
-from vyos.config import Config
-from vyos import ConfigError
-from vyos.util import call
-from vyos.template import render
-
-from vyos import airbag
-airbag.enable()
-
-ra_conn_name = "remote-access"
-ipsec_secrets_file = "/etc/ipsec.secrets"
-ipsec_ra_conn_dir = "/etc/ipsec.d/tunnels/"
-ipsec_ra_conn_file = ipsec_ra_conn_dir + ra_conn_name
-ipsec_conf_file = "/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"
-
-def get_config(config=None):
- if config:
- config = config
- else:
- config = Config()
-
- data = {}
- 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
-
-def write_ipsec_secrets(c):
- if c.get("ipsec_l2tp_auth_mode") == "pre-shared-secret":
- secret_txt = "{0}\n{1} %any : PSK \"{2}\"\n{3}\n".format(delim_ipsec_l2tp_begin, c['outside_addr'], c['ipsec_l2tp_secret'], delim_ipsec_l2tp_end)
- elif c.get("ipsec_l2tp_auth_mode") == "x509":
- secret_txt = "{0}\n: RSA {1}\n{2}\n".format(delim_ipsec_l2tp_begin, c['server_key_file_copied'], delim_ipsec_l2tp_end)
-
- old_umask = os.umask(0o077)
- with open(ipsec_secrets_file, 'a+') as f:
- f.write(secret_txt)
- os.umask(old_umask)
-
-def write_ipsec_conf(c):
- ipsec_confg_txt = "{0}\ninclude {1}\n{2}\n".format(delim_ipsec_l2tp_begin, ipsec_ra_conn_file, delim_ipsec_l2tp_end)
-
- old_umask = os.umask(0o077)
- with open(ipsec_conf_file, 'a+') as f:
- f.write(ipsec_confg_txt)
- os.umask(old_umask)
-
-### Remove config from file by delimiter
-def remove_confs(delim_begin, delim_end, conf_file):
- call("sed -i '/"+delim_begin+"/,/"+delim_end+"/d' "+conf_file)
-
-
-### 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 = call('cp -f '+file_path+' '+dts_path)
- if ret:
- raise ConfigError("L2TP VPN configuration error: Cannot copy "+file_path)
-
-def verify(data):
- # l2tp ipsec check
- if 'ipsec_l2tp' in data:
- # 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):
- if 'ipsec_l2tp' in data:
- remove_confs(delim_ipsec_l2tp_begin, delim_ipsec_l2tp_end, ipsec_secrets_file)
- # old_umask = os.umask(0o077)
- # render(ipsec_secrets_file, 'ipsec/ipsec.secrets.tmpl', data)
- # os.umask(old_umask)
- ## Use this method while IPSec CLI handler won't be overwritten to python
- write_ipsec_secrets(data)
-
- 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)
-
- render(ipsec_ra_conn_file, 'ipsec/remote-access.tmpl', data)
- os.umask(old_umask)
-
- remove_confs(delim_ipsec_l2tp_begin, delim_ipsec_l2tp_end, ipsec_conf_file)
- # old_umask = os.umask(0o077)
- # render(ipsec_conf_file, 'ipsec/ipsec.conf.tmpl', data)
- # os.umask(old_umask)
- ## Use this method while IPSec CLI handler won't be overwritten to python
- write_ipsec_conf(data)
-
- else:
- if os.path.exists(ipsec_ra_conn_file):
- 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_file)
- remove_confs(delim_ipsec_l2tp_begin, delim_ipsec_l2tp_end, ipsec_conf_file)
-
-def restart_ipsec():
- call('ipsec restart >&/dev/null')
- # counter for apply swanctl config
- counter = 10
- while counter <= 10:
- if os.path.exists(charon_pidfile):
- call('swanctl -q >&/dev/null')
- break
- counter -=1
- 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)
- exit(1)
diff --git a/src/conf_mode/vpn_ipsec.py b/src/conf_mode/vpn_ipsec.py
index 3fab8e868..a359361f3 100755..100644
--- a/src/conf_mode/vpn_ipsec.py
+++ b/src/conf_mode/vpn_ipsec.py
@@ -73,6 +73,7 @@ def get_config(config=None):
else:
conf = Config()
base = ['vpn', 'ipsec']
+ l2tp_base = ['vpn', 'l2tp', 'remote-access', 'ipsec-settings']
if not conf.exists(base):
return None
@@ -108,15 +109,22 @@ def get_config(config=None):
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 + ['ipsec-interfaces',
- 'interface'])
- ipsec['l2tp_exists'] = conf.exists(['vpn', 'l2tp', 'remote-access',
- 'ipsec-settings'])
+ ipsec['interface_change'] = leaf_node_changed(conf, base + ['interface'])
ipsec['nhrp_exists'] = conf.exists(['protocols', 'nhrp', 'tunnel'])
ipsec['pki'] = conf.get_config_dict(['pki'], key_mangling=('-', '_'),
get_first_key=True,
no_tag_node_value_mangle=True)
+ ipsec['l2tp'] = conf.get_config_dict(l2tp_base, key_mangling=('-', '_'),
+ get_first_key=True,
+ no_tag_node_value_mangle=True)
+ if ipsec['l2tp']:
+ l2tp_defaults = defaults(l2tp_base)
+ ipsec['l2tp'] = dict_merge(l2tp_defaults, ipsec['l2tp'])
+ ipsec['l2tp_outside_address'] = conf.return_value(['vpn', 'l2tp', 'remote-access', 'outside-address'])
+ ipsec['l2tp_ike_default'] = 'aes256-sha1-modp1024,3des-sha1-modp1024,3des-sha1-modp1024'
+ ipsec['l2tp_esp_default'] = 'aes256-sha1,3des-sha1'
+
return ipsec
def get_dhcp_address(iface):
@@ -165,14 +173,43 @@ def verify(ipsec):
if not ipsec:
return None
- if 'ipsec_interfaces' in ipsec and 'interface' in ipsec['ipsec_interfaces']:
- interfaces = ipsec['ipsec_interfaces']['interface']
- if isinstance(interfaces, str):
- interfaces = [interfaces]
-
- for ifname in interfaces:
+ if 'interfaces' in ipsec :
+ for ifname in ipsec['interface']:
verify_interface_exists(ifname)
+ if ipsec['l2tp']:
+ if 'esp_group' in ipsec['l2tp']:
+ if 'esp_group' not in ipsec or ipsec['l2tp']['esp_group'] not in ipsec['esp_group']:
+ raise ConfigError(f"Invalid esp-group on L2TP remote-access config")
+
+ if 'ike_group' in ipsec['l2tp']:
+ if 'ike_group' not in ipsec or ipsec['l2tp']['ike_group'] not in ipsec['ike_group']:
+ raise ConfigError(f"Invalid ike-group on L2TP remote-access config")
+
+ if 'authentication' not in ipsec['l2tp']:
+ raise ConfigError(f'Missing authentication settings on L2TP remote-access config')
+
+ if 'mode' not in ipsec['l2tp']['authentication']:
+ raise ConfigError(f'Missing authentication mode on L2TP remote-access config')
+
+ if not ipsec['l2tp_outside_address']:
+ raise ConfigError(f'Missing outside-address on L2TP remote-access config')
+
+ if ipsec['l2tp']['authentication']['mode'] == 'pre-shared-secret':
+ if 'pre_shared_secret' not in ipsec['l2tp']['authentication']:
+ raise ConfigError(f'Missing pre shared secret on L2TP remote-access config')
+
+ if ipsec['l2tp']['authentication']['mode'] == 'x509':
+ if 'x509' not in ipsec['l2tp']['authentication']:
+ raise ConfigError(f'Missing x509 settings on L2TP remote-access config')
+
+ x509 = ipsec['l2tp']['authentication']['x509']
+
+ if 'ca_certificate' not in x509 or 'certificate' not in x509:
+ raise ConfigError(f'Missing x509 certificates on L2TP remote-access config')
+
+ verify_pki_x509(ipsec['pki'], x509)
+
if 'profile' in ipsec:
for profile, profile_conf in ipsec['profile'].items():
if 'esp_group' in profile_conf:
@@ -389,6 +426,10 @@ def generate(ipsec):
if not os.path.exists(KEY_PATH):
os.mkdir(KEY_PATH, mode=0o700)
+ if ipsec['l2tp']:
+ if 'authentication' in ipsec['l2tp'] and 'x509' in ipsec['l2tp']['authentication']:
+ generate_pki_files_x509(ipsec['pki'], ipsec['l2tp']['authentication']['x509'])
+
if 'remote_access' in ipsec:
for rw, rw_conf in ipsec['remote_access'].items():
if 'authentication' in rw_conf and 'x509' in rw_conf['authentication']:
@@ -439,14 +480,6 @@ def generate(ipsec):
render(interface_conf, 'ipsec/interfaces_use.conf.tmpl', ipsec)
render(swanctl_conf, 'ipsec/swanctl.conf.tmpl', ipsec)
-def resync_l2tp(ipsec):
- if ipsec and not ipsec['l2tp_exists']:
- return
-
- tmp = run('/usr/libexec/vyos/conf_mode/ipsec-settings.py')
- if tmp > 0:
- print('ERROR: failed to reapply L2TP IPSec settings!')
-
def resync_nhrp(ipsec):
if ipsec and not ipsec['nhrp_exists']:
return
@@ -480,7 +513,6 @@ def apply(ipsec):
if wait_for_vici_socket():
call('sudo swanctl -q')
- resync_l2tp(ipsec)
resync_nhrp(ipsec)
if __name__ == '__main__':
diff --git a/src/conf_mode/vpn_l2tp.py b/src/conf_mode/vpn_l2tp.py
index e970d2ef5..9c52f77ca 100755
--- a/src/conf_mode/vpn_l2tp.py
+++ b/src/conf_mode/vpn_l2tp.py
@@ -20,7 +20,6 @@ import re
from copy import deepcopy
from stat import S_IRUSR, S_IWUSR, S_IRGRP
from sys import exit
-from time import sleep
from ipaddress import ip_network
diff --git a/src/etc/vmware-tools/scripts/resume-vm-default.d/ether-resume.py b/src/etc/vmware-tools/scripts/resume-vm-default.d/ether-resume.py
index ec33906ba..4e7fb117c 100755
--- a/src/etc/vmware-tools/scripts/resume-vm-default.d/ether-resume.py
+++ b/src/etc/vmware-tools/scripts/resume-vm-default.d/ether-resume.py
@@ -25,9 +25,8 @@ def get_config():
c = Config()
interfaces = dict()
for intf in c.list_effective_nodes('interfaces ethernet'):
- # skip interfaces that are disabled or is configured for dhcp
+ # skip interfaces that are disabled
check_disable = f'interfaces ethernet {intf} disable'
- check_dhcp = f'interfaces ethernet {intf} address dhcp'
if c.exists_effective(check_disable):
continue
@@ -49,10 +48,10 @@ def apply(config):
# add configured addresses to interface
for addr in addresses:
- if addr == 'dhcp':
- cmd = ['dhclient', intf]
- else:
- cmd = f'ip address add {addr} dev {intf}'
+ # dhcp is handled by netplug
+ if addr in ['dhcp', 'dhcpv6']:
+ continue
+ cmd = f'ip address add {addr} dev {intf}'
syslog.syslog(cmd)
run(cmd)
diff --git a/src/migration-scripts/ipsec/5-to-6 b/src/migration-scripts/ipsec/5-to-6
index ba5ce0fca..76ee9ecba 100755
--- a/src/migration-scripts/ipsec/5-to-6
+++ b/src/migration-scripts/ipsec/5-to-6
@@ -74,6 +74,12 @@ log_mode = log + ['log-modes']
if config.exists(log_mode):
config.rename(log_mode, 'subsystem')
+# Rename "ipsec-interfaces interface" to "interface"
+base_interfaces = base + ['ipsec-interfaces', 'interface']
+if config.exists(base_interfaces):
+ config.copy(base_interfaces, base + ['interface'])
+ config.delete(base_interfaces)
+
try:
with open(file_name, 'w') as f:
f.write(config.to_string())
diff --git a/src/migration-scripts/l2tp/3-to-4 b/src/migration-scripts/l2tp/3-to-4
new file mode 100755
index 000000000..18eabadec
--- /dev/null
+++ b/src/migration-scripts/l2tp/3-to-4
@@ -0,0 +1,169 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 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/>.
+
+# - remove primary/secondary identifier from nameserver
+# - TODO: remove radius server req-limit
+
+import os
+
+from sys import argv
+from sys import exit
+from vyos.configtree import ConfigTree
+from vyos.pki import load_certificate
+from vyos.pki import load_crl
+from vyos.pki import load_private_key
+from vyos.pki import encode_certificate
+from vyos.pki import encode_private_key
+from vyos.util import run
+
+if (len(argv) < 1):
+ print("Must specify file name!")
+ exit(1)
+
+file_name = argv[1]
+
+with open(file_name, 'r') as f:
+ config_file = f.read()
+
+config = ConfigTree(config_file)
+base = ['vpn', 'l2tp', 'remote-access', 'ipsec-settings']
+pki_base = ['pki']
+
+if not config.exists(base):
+ exit(0)
+
+AUTH_DIR = '/config/auth'
+
+def wrapped_pem_to_config_value(pem):
+ return "".join(pem.strip().split("\n")[1:-1])
+
+if not config.exists(base + ['authentication', 'x509']):
+ exit(0)
+
+x509_base = base + ['authentication', 'x509']
+pki_name = 'l2tp_remote_access'
+
+if not config.exists(pki_base + ['ca']):
+ config.set(pki_base + ['ca'])
+ config.set_tag(pki_base + ['ca'])
+
+if not config.exists(pki_base + ['certificate']):
+ config.set(pki_base + ['certificate'])
+ config.set_tag(pki_base + ['certificate'])
+
+if config.exists(x509_base + ['ca-cert-file']):
+ cert_file = config.return_value(x509_base + ['ca-cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['ca-certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate CA certificate on l2tp remote-access config')
+
+ config.delete(x509_base + ['ca-cert-file'])
+
+if config.exists(x509_base + ['crl-file']):
+ crl_file = config.return_value(x509_base + ['crl-file'])
+ crl_path = os.path.join(AUTH_DIR, crl_file)
+ crl = None
+
+ if os.path.isfile(crl_path):
+ if not os.access(crl_path, os.R_OK):
+ run(f'sudo chmod 644 {crl_path}')
+
+ with open(crl_path, 'r') as f:
+ crl_data = f.read()
+ crl = load_certificate(crl_data, wrap_tags=False)
+
+ if crl:
+ crl_pem = encode_certificate(crl)
+ config.set(pki_base + ['ca', pki_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem))
+ else:
+ print(f'Failed to migrate CRL on l2tp remote-access config')
+
+ config.delete(x509_base + ['crl-file'])
+
+if config.exists(x509_base + ['server-cert-file']):
+ cert_file = config.return_value(x509_base + ['server-cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ if os.path.isfile(cert_path):
+ if not os.access(cert_path, os.R_OK):
+ run(f'sudo chmod 644 {cert_path}')
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ if cert:
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['certificate'], value=pki_name)
+ else:
+ print(f'Failed to migrate certificate on l2tp remote-access config')
+
+ config.delete(x509_base + ['server-cert-file'])
+
+if config.exists(x509_base + ['server-key-file']):
+ key_file = config.return_value(x509_base + ['server-key-file'])
+ key_passphrase = None
+
+ if config.exists(x509_base + ['server-key-password']):
+ key_passphrase = config.return_value(x509_base + ['server-key-password'])
+
+ key_path = os.path.join(AUTH_DIR, key_file)
+ key = None
+
+ if os.path.isfile(key_path):
+ if not os.access(key_path, os.R_OK):
+ run(f'sudo chmod 644 {key_path}')
+
+ with open(key_path, 'r') as f:
+ key_data = f.read()
+ key = load_private_key(key_data, passphrase=key_passphrase, wrap_tags=False)
+
+ if key:
+ key_pem = encode_private_key(key, passphrase=key_passphrase)
+ config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
+
+ if key_passphrase:
+ config.set(pki_base + ['certificate', pki_name, 'private', 'password-protected'])
+ config.set(x509_base + ['private-key-passphrase'], value=key_passphrase)
+ else:
+ print(f'Failed to migrate private key on l2tp remote-access config')
+
+ config.delete(x509_base + ['server-key-file'])
+ if config.exists(x509_base + ['server-key-password']):
+ config.delete(x509_base + ['server-key-password'])
+
+try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+except OSError as e:
+ print("Failed to save the modified config: {}".format(e))
+ exit(1)