Page MenuHomeVyOS Platform

No OneTemporary

Size
79 KB
Referenced Files
None
Subscribers
None
diff --git a/data/templates/ipsec/charon/dhcp.conf.tmpl b/data/templates/ipsec/charon/dhcp.conf.tmpl
new file mode 100644
index 000000000..2879550a8
--- /dev/null
+++ b/data/templates/ipsec/charon/dhcp.conf.tmpl
@@ -0,0 +1,23 @@
+dhcp {
+ load = yes
+
+{% if options is defined and options.remote_access is defined and options.remote_access.dhcp_pool is defined %}
+{% if options.remote_access.dhcp_pool.interface is defined %}
+ interface = {{ options.remote_access.dhcp_pool.interface }}
+{% endif %}
+{% if options.remote_access.dhcp_pool.server is defined %}
+ server = {{ options.remote_access.dhcp_pool.server }}
+{% endif %}
+{% endif %}
+
+ # Always use the configured server address.
+ # force_server_address = no
+
+ # Derive user-defined MAC address from hash of IKE identity and send client
+ # identity DHCP option.
+ # identity_lease = no
+
+ # Use the DHCP server port (67) as source port when a unicast server address
+ # is configured.
+ # use_server_port = no
+}
diff --git a/data/templates/ipsec/swanctl.conf.tmpl b/data/templates/ipsec/swanctl.conf.tmpl
index 0eda8479a..00251d44d 100644
--- a/data/templates/ipsec/swanctl.conf.tmpl
+++ b/data/templates/ipsec/swanctl.conf.tmpl
@@ -1,96 +1,106 @@
### Autogenerated by vpn_ipsec.py ###
{% 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 %}
connections {
{% if profile is defined %}
{% for name, profile_conf in profile.items() if profile_conf.disable is not defined and profile_conf.bind is defined and profile_conf.bind.tunnel is defined %}
{{ profile_tmpl.conn(name, profile_conf, ike_group, esp_group) }}
{% endfor %}
{% endif %}
{% if site_to_site is defined and site_to_site.peer is defined %}
{% for peer, peer_conf in site_to_site.peer.items() if peer not in dhcp_no_address and peer_conf.disable is not defined %}
{{ peer_tmpl.conn(peer, peer_conf, ike_group, esp_group) }}
{% endfor %}
{% endif %}
{% if remote_access is defined and remote_access is not none %}
{% for rw, rw_conf in remote_access.items() if rw_conf.disable is not defined %}
{{ remote_access_tmpl.conn(rw, rw_conf, ike_group, esp_group) }}
{% endfor %}
{% endif %}
}
pools {
{% if remote_access is defined %}
-{% for ra, ra_conf in remote_access.items() if remote_access is defined %}
+{% for ra, ra_conf in remote_access.items() if ra_conf.pool.dhcp_enable is not defined %}
ra-{{ ra }} {
addrs = {{ ra_conf.pool.prefix }}
dns = {{ ra_conf.pool.name_server | join(",") }}
{% if ra_conf.pool.exclude is defined %}
split_exclude = {{ ra_conf.pool.exclude | join(",") }}
{% endif %}
}
{% endfor %}
{% endif %}
}
secrets {
{% if profile is defined %}
{% for name, profile_conf in profile.items() if profile_conf.disable is not defined and profile_conf.bind is defined and profile_conf.bind.tunnel is defined %}
{% if profile_conf.authentication.mode == 'pre-shared-secret' %}
{% for interface in profile_conf.bind.tunnel %}
ike-dmvpn-{{ interface }} {
secret = {{ profile_conf.authentication.pre_shared_secret }}
}
{% endfor %}
{% endif %}
{% endfor %}
{% endif %}
{% if site_to_site is defined and site_to_site.peer is defined %}
{% set ns = namespace(local_key_set=False) %}
{% for peer, peer_conf in site_to_site.peer.items() if peer not in dhcp_no_address and peer_conf.disable is not defined %}
{% set peer_name = peer.replace(".", "-").replace("@", "") %}
{% if peer_conf.authentication.mode == 'pre-shared-secret' %}
ike_{{ peer_name }} {
{% if peer_conf.local_address is defined %}
id-local = {{ peer_conf.local_address }} # dhcp:{{ peer_conf.dhcp_interface if 'dhcp_interface' in peer_conf else 'no' }}
{% endif %}
id-remote = {{ peer }}
{% if peer_conf.authentication.id is defined %}
id-localid = {{ peer_conf.authentication.id }}
{% endif %}
{% if peer_conf.authentication.remote_id is defined %}
id-remoteid = {{ peer_conf.authentication.remote_id }}
{% endif %}
secret = "{{ peer_conf.authentication.pre_shared_secret }}"
}
{% elif peer_conf.authentication.mode == 'x509' %}
private_{{ peer_name }} {
file = {{ peer_conf.authentication.x509.certificate }}.pem
{% if peer_conf.authentication.x509.passphrase is defined %}
secret = "{{ peer_conf.authentication.x509.passphrase }}"
{% endif %}
}
{% elif peer_conf.authentication.mode == 'rsa' and not ns.local_key_set %}
{% set ns.local_key_set = True %}
rsa_local {
file = {{ rsa_local_key }}
}
{% endif %}
{% endfor %}
{% endif %}
{% if remote_access is defined %}
{% for ra, ra_conf in remote_access.items() if remote_access is defined %}
-{% if ra_conf.authentication is defined and ra_conf.authentication.local_users is defined and ra_conf.authentication.local_users.username is defined %}
+{% if ra_conf.authentication.server_mode == 'pre-shared-secret' %}
+ ike_{{ ra }} {
+{% if ra_conf.authentication.id is defined %}
+ id = "{{ ra_conf.authentication.id }}"
+{% elif ra_conf.local_address is defined %}
+ id = "{{ ra_conf.local_address }}"
+{% endif %}
+ secret = "{{ ra_conf.authentication.pre_shared_secret }}"
+ }
+{% endif %}
+{% if ra_conf.authentication.client_mode == 'eap-mschapv2' and ra_conf.authentication.local_users is defined and ra_conf.authentication.local_users.username is defined %}
{% for user, user_conf in ra_conf.authentication.local_users.username.items() if user_conf.disable is not defined %}
eap-{{ ra }}-{{ user }} {
secret = "{{ user_conf.password }}"
id-{{ ra }}-{{ user }} = "{{ user }}"
}
{% endfor %}
{% endif %}
{% endfor %}
{% endif %}
}
diff --git a/data/templates/ipsec/swanctl/remote_access.tmpl b/data/templates/ipsec/swanctl/remote_access.tmpl
index a3a1cf0b2..95f2108fb 100644
--- a/data/templates/ipsec/swanctl/remote_access.tmpl
+++ b/data/templates/ipsec/swanctl/remote_access.tmpl
@@ -1,40 +1,48 @@
{% macro conn(name, rw_conf, ike_group, esp_group) %}
{# peer needs to reference the global IKE configuration for certain values #}
{% set ike = ike_group[rw_conf.ike_group] %}
{% set esp = esp_group[rw_conf.esp_group] %}
ra-{{ name }} {
remote_addrs = %any
local_addrs = {{ rw_conf.local_address if rw_conf.local_address is defined else '%any' }}
proposals = {{ ike_group[rw_conf.ike_group] | get_esp_ike_cipher | join(',') }}
version = {{ ike.key_exchange[4:] if ike is defined and ike.key_exchange is defined else "0" }}
send_certreq = no
rekey_time = {{ ike.lifetime }}s
keyingtries = 0
+{% if rw_conf.pool.dhcp_enable is defined %}
+ pools = dhcp
+{% else %}
pools = ra-{{ name }}
+{% endif %}
local {
- auth = pubkey
-{% if rw_conf.authentication is defined and rw_conf.authentication.id is defined and rw_conf.authentication.use_x509_id is not defined %}
+{% if rw_conf.authentication.id is defined and rw_conf.authentication.use_x509_id is not defined %}
id = "{{ rw_conf.authentication.id }}"
{% endif %}
-{% if rw_conf.authentication is defined and rw_conf.authentication.x509 is defined and rw_conf.authentication.x509.certificate is defined %}
+{% if rw_conf.authentication.server_mode == 'x509' %}
+ auth = pubkey
certs = {{ rw_conf.authentication.x509.certificate }}.pem
+{% elif rw_conf.authentication.server_mode == 'pre-shared-secret' %}
+ auth = psk
{% endif %}
}
remote {
- auth = eap-mschapv2
+ auth = {{ rw_conf.authentication.client_mode }}
+{% if rw_conf.authentication.client_mode.startswith("eap") %}
eap_id = %any
+{% endif %}
}
children {
ikev2-vpn {
esp_proposals = {{ esp | get_esp_ike_cipher | join(',') }}
rekey_time = {{ esp.lifetime }}s
rand_time = 540s
dpd_action = clear
{% set local_prefix = rw_conf.local.prefix if rw_conf.local is defined and rw_conf.local.prefix is defined else ['0.0.0.0/0', '::/0'] %}
{% set local_port = rw_conf.local.port if rw_conf.local is defined and rw_conf.local.port is defined else '' %}
{% set local_suffix = '[%any/{1}]'.format(local_port) if local_port else '' %}
local_ts = {{ local_prefix | join(local_suffix + ",") }}{{ local_suffix }}
}
}
}
{% endmacro %}
diff --git a/interface-definitions/vpn_ipsec.xml.in b/interface-definitions/vpn_ipsec.xml.in
index f6b18d1d5..4425ab02a 100644
--- a/interface-definitions/vpn_ipsec.xml.in
+++ b/interface-definitions/vpn_ipsec.xml.in
@@ -1,1043 +1,1125 @@
<?xml version="1.0"?>
<interfaceDefinition>
<node name="vpn">
<properties>
<help>Virtual Private Network (VPN)</help>
</properties>
<children>
<node name="ipsec" owner="${vyos_conf_scripts_dir}/vpn_ipsec.py">
<properties>
<help>VPN IP security (IPsec) parameters</help>
<priority>901</priority>
</properties>
<children>
<leafNode name="auto-update">
<properties>
<help>Set auto-update interval for IPsec daemon</help>
<valueHelp>
<format>u32:30-65535</format>
<description>Auto-update interval (s)</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 30-65535"/>
</constraint>
</properties>
</leafNode>
<leafNode name="disable-uniqreqids">
<properties>
<help>Option to disable requirement for unique IDs in the Security Database</help>
<valueless/>
</properties>
</leafNode>
<tagNode name="esp-group">
<properties>
<help>Name of Encapsulating Security Payload (ESP) group</help>
</properties>
<children>
<leafNode name="compression">
<properties>
<help>ESP compression</help>
<completionHelp>
<list>disable enable</list>
</completionHelp>
<valueHelp>
<format>disable</format>
<description>Disable ESP compression (default)</description>
</valueHelp>
<valueHelp>
<format>enable</format>
<description>Enable ESP compression</description>
</valueHelp>
<constraint>
<regex>^(disable|enable)$</regex>
</constraint>
</properties>
</leafNode>
<leafNode name="lifetime">
<properties>
<help>ESP lifetime</help>
<valueHelp>
<format>u32:30-86400</format>
<description>ESP lifetime in seconds (default 3600)</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 30-86400"/>
</constraint>
</properties>
<defaultValue>3600</defaultValue>
</leafNode>
<leafNode name="mode">
<properties>
<help>ESP mode</help>
<completionHelp>
<list>tunnel transport</list>
</completionHelp>
<valueHelp>
<format>tunnel</format>
<description>Tunnel mode (default)</description>
</valueHelp>
<valueHelp>
<format>transport</format>
<description>Transport mode</description>
</valueHelp>
<constraint>
<regex>^(tunnel|transport)$</regex>
</constraint>
</properties>
<defaultValue>tunnel</defaultValue>
</leafNode>
<leafNode name="pfs">
<properties>
<help>ESP Perfect Forward Secrecy</help>
<completionHelp>
<list>enable dh-group1 dh-group2 dh-group5 dh-group14 dh-group15 dh-group16 dh-group17 dh-group18 dh-group19 dh-group20 dh-group21 dh-group22 dh-group23 dh-group24 dh-group25 dh-group26 dh-group27 dh-group28 dh-group29 dh-group30 dh-group31 dh-group32 disable</list>
</completionHelp>
<valueHelp>
<format>enable</format>
<description>Use Diffie-Hellman group 2 (modp1024) - default</description>
</valueHelp>
<valueHelp>
<format>dh-group1</format>
<description>Use Diffie-Hellman group 1 (modp768)</description>
</valueHelp>
<valueHelp>
<format>dh-group2</format>
<description>Use Diffie-Hellman group 2 (modp1024)</description>
</valueHelp>
<valueHelp>
<format>dh-group5</format>
<description>Use Diffie-Hellman group 5 (modp1536)</description>
</valueHelp>
<valueHelp>
<format>dh-group14</format>
<description>Use Diffie-Hellman group 14 (modp2048)</description>
</valueHelp>
<valueHelp>
<format>dh-group15</format>
<description>Use Diffie-Hellman group 15 (modp3072)</description>
</valueHelp>
<valueHelp>
<format>dh-group16</format>
<description>Use Diffie-Hellman group 16 (modp4096)</description>
</valueHelp>
<valueHelp>
<format>dh-group17</format>
<description>Use Diffie-Hellman group 17 (modp6144)</description>
</valueHelp>
<valueHelp>
<format>dh-group18</format>
<description>Use Diffie-Hellman group 18 (modp8192)</description>
</valueHelp>
<valueHelp>
<format>dh-group19</format>
<description>Use Diffie-Hellman group 19 (ecp256)</description>
</valueHelp>
<valueHelp>
<format>dh-group20</format>
<description>Use Diffie-Hellman group 20 (ecp384)</description>
</valueHelp>
<valueHelp>
<format>dh-group21</format>
<description>Use Diffie-Hellman group 21 (ecp521)</description>
</valueHelp>
<valueHelp>
<format>dh-group22</format>
<description>Use Diffie-Hellman group 22 (modp1024s160)</description>
</valueHelp>
<valueHelp>
<format>dh-group23</format>
<description>Use Diffie-Hellman group 23 (modp2048s224)</description>
</valueHelp>
<valueHelp>
<format>dh-group24</format>
<description>Use Diffie-Hellman group 24 (modp2048s256)</description>
</valueHelp>
<valueHelp>
<format>dh-group25</format>
<description>Use Diffie-Hellman group 25 (ecp192)</description>
</valueHelp>
<valueHelp>
<format>dh-group26</format>
<description>Use Diffie-Hellman group 26 (ecp224)</description>
</valueHelp>
<valueHelp>
<format>dh-group27</format>
<description>Use Diffie-Hellman group 27 (ecp224bp)</description>
</valueHelp>
<valueHelp>
<format>dh-group28</format>
<description>Use Diffie-Hellman group 28 (ecp256bp)</description>
</valueHelp>
<valueHelp>
<format>dh-group29</format>
<description>Use Diffie-Hellman group 29 (ecp384bp)</description>
</valueHelp>
<valueHelp>
<format>dh-group30</format>
<description>Use Diffie-Hellman group 30 (ecp512bp)</description>
</valueHelp>
<valueHelp>
<format>dh-group31</format>
<description>Use Diffie-Hellman group 31 (curve25519)</description>
</valueHelp>
<valueHelp>
<format>dh-group32</format>
<description>Use Diffie-Hellman group 32 (curve448)</description>
</valueHelp>
<valueHelp>
<format>disable</format>
<description>Disable PFS</description>
</valueHelp>
<constraint>
<regex>^(enable|dh-group1|dh-group2|dh-group5|dh-group14|dh-group15|dh-group16|dh-group17|dh-group18|dh-group19|dh-group20|dh-group21|dh-group22|dh-group23|dh-group24|dh-group25|dh-group26|dh-group27|dh-group28|dh-group29|dh-group30|dh-group31|dh-group32|disable)$</regex>
</constraint>
</properties>
<defaultValue>enable</defaultValue>
</leafNode>
<tagNode name="proposal">
<properties>
<help>ESP-group proposal [REQUIRED]</help>
<valueHelp>
<format>u32:1-65535</format>
<description>ESP-group proposal number</description>
</valueHelp>
</properties>
<children>
#include <include/vpn-ipsec-encryption.xml.i>
#include <include/vpn-ipsec-hash.xml.i>
</children>
</tagNode>
</children>
</tagNode>
<tagNode name="ike-group">
<properties>
<help>Name of Internet Key Exchange (IKE) group</help>
</properties>
<children>
<leafNode name="close-action">
<properties>
<help>close-action_help</help>
<completionHelp>
<list>none hold clear restart</list>
</completionHelp>
<valueHelp>
<format>none</format>
<description>Set action to none (default)</description>
</valueHelp>
<valueHelp>
<format>hold</format>
<description>Set action to hold</description>
</valueHelp>
<valueHelp>
<format>clear</format>
<description>Set action to clear</description>
</valueHelp>
<valueHelp>
<format>restart</format>
<description>Set action to restart</description>
</valueHelp>
<constraint>
<regex>^(none|hold|clear|restart)$</regex>
</constraint>
</properties>
</leafNode>
<node name="dead-peer-detection">
<properties>
<help>Dead Peer Detection (DPD)</help>
</properties>
<children>
<leafNode name="action">
<properties>
<help>Keep-alive failure action</help>
<completionHelp>
<list>hold clear restart</list>
</completionHelp>
<valueHelp>
<format>hold</format>
<description>Set action to hold (default)</description>
</valueHelp>
<valueHelp>
<format>clear</format>
<description>Set action to clear</description>
</valueHelp>
<valueHelp>
<format>restart</format>
<description>Set action to restart</description>
</valueHelp>
<constraint>
<regex>^(hold|clear|restart)$</regex>
</constraint>
</properties>
</leafNode>
<leafNode name="interval">
<properties>
<help>Keep-alive interval</help>
<valueHelp>
<format>u32:2-86400</format>
<description>Keep-alive interval in seconds (default 30)</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 2-86400"/>
</constraint>
</properties>
</leafNode>
<leafNode name="timeout">
<properties>
<help>Dead-Peer-Detection keep-alive timeout (IKEv1 only)</help>
<valueHelp>
<format>u32:2-86400</format>
<description>Keep-alive timeout in seconds (default 120)</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 2-86400"/>
</constraint>
</properties>
</leafNode>
</children>
</node>
<leafNode name="ikev2-reauth">
<properties>
<help>ikev2-reauth_help</help>
<completionHelp>
<list>yes no</list>
</completionHelp>
<valueHelp>
<format>yes</format>
<description>Enable remote host re-authentication during an IKE rekey. Currently broken due to a strongswan bug</description>
</valueHelp>
<valueHelp>
<format>no</format>
<description>Disable remote host re-authenticaton during an IKE rekey. (Default)</description>
</valueHelp>
<constraint>
<regex>^(yes|no)$</regex>
</constraint>
</properties>
</leafNode>
<leafNode name="key-exchange">
<properties>
<help>Key Exchange Version</help>
<completionHelp>
<list>ikev1 ikev2</list>
</completionHelp>
<valueHelp>
<format>ikev1</format>
<description>Use IKEv1 for Key Exchange [DEFAULT]</description>
</valueHelp>
<valueHelp>
<format>ikev2</format>
<description>Use IKEv2 for Key Exchange</description>
</valueHelp>
<constraint>
<regex>^(ikev1|ikev2)$</regex>
</constraint>
</properties>
</leafNode>
<leafNode name="lifetime">
<properties>
<help>IKE lifetime</help>
<valueHelp>
<format>u32:30-86400</format>
<description>IKE lifetime in seconds (default 28800)</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 30-86400"/>
</constraint>
</properties>
<defaultValue>28800</defaultValue>
</leafNode>
<leafNode name="mobike">
<properties>
<help>Enable MOBIKE Support. MOBIKE is only available for IKEv2.</help>
<completionHelp>
<list>enable disable</list>
</completionHelp>
<valueHelp>
<format>enable</format>
<description>Enable MOBIKE (default for IKEv2)</description>
</valueHelp>
<valueHelp>
<format>disable</format>
<description>Disable MOBIKE</description>
</valueHelp>
<constraint>
<regex>^(enable|disable)$</regex>
</constraint>
</properties>
</leafNode>
<leafNode name="mode">
<properties>
<help>IKEv1 Phase 1 Mode Selection</help>
<completionHelp>
<list>main aggressive</list>
</completionHelp>
<valueHelp>
<format>main</format>
<description>Use Main mode for Key Exchanges in the IKEv1 Protocol (Recommended Default)</description>
</valueHelp>
<valueHelp>
<format>aggressive</format>
<description>Use Aggressive mode for Key Exchanges in the IKEv1 protocol - We do not recommend users to use aggressive mode as it is much more insecure compared to Main mode.</description>
</valueHelp>
<constraint>
<regex>^(main|aggressive)$</regex>
</constraint>
</properties>
</leafNode>
<tagNode name="proposal">
<properties>
<help>proposal_help</help>
<valueHelp>
<format>u32:1-65535</format>
<description>IKE-group proposal</description>
</valueHelp>
</properties>
<children>
<leafNode name="dh-group">
<defaultValue>2</defaultValue>
<properties>
<help>dh-grouphelp</help>
<completionHelp>
<list>1 2 5 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32</list>
</completionHelp>
<valueHelp>
<format>1</format>
<description>Diffie-Hellman group 1 (modp768)</description>
</valueHelp>
<valueHelp>
<format>2</format>
<description>Diffie-Hellman group 2 (modp1024)</description>
</valueHelp>
<valueHelp>
<format>5</format>
<description>Diffie-Hellman group 5 (modp1536)</description>
</valueHelp>
<valueHelp>
<format>14</format>
<description>Diffie-Hellman group 14 (modp2048)</description>
</valueHelp>
<valueHelp>
<format>15</format>
<description>Diffie-Hellman group 15 (modp3072)</description>
</valueHelp>
<valueHelp>
<format>16</format>
<description>Diffie-Hellman group 16 (modp4096)</description>
</valueHelp>
<valueHelp>
<format>17</format>
<description>Diffie-Hellman group 17 (modp6144)</description>
</valueHelp>
<valueHelp>
<format>18</format>
<description>Diffie-Hellman group 18 (modp8192)</description>
</valueHelp>
<valueHelp>
<format>19</format>
<description>Diffie-Hellman group 19 (ecp256)</description>
</valueHelp>
<valueHelp>
<format>20</format>
<description>Diffie-Hellman group 20 (ecp384)</description>
</valueHelp>
<valueHelp>
<format>21</format>
<description>Diffie-Hellman group 21 (ecp521)</description>
</valueHelp>
<valueHelp>
<format>22</format>
<description>Diffie-Hellman group 22 (modp1024s160)</description>
</valueHelp>
<valueHelp>
<format>23</format>
<description>Diffie-Hellman group 23 (modp2048s224)</description>
</valueHelp>
<valueHelp>
<format>24</format>
<description>Diffie-Hellman group 24 (modp2048s256)</description>
</valueHelp>
<valueHelp>
<format>25</format>
<description>Diffie-Hellman group 25 (ecp192)</description>
</valueHelp>
<valueHelp>
<format>26</format>
<description>Diffie-Hellman group 26 (ecp224)</description>
</valueHelp>
<valueHelp>
<format>27</format>
<description>Diffie-Hellman group 27 (ecp224bp)</description>
</valueHelp>
<valueHelp>
<format>28</format>
<description>Diffie-Hellman group 28 (ecp256bp)</description>
</valueHelp>
<valueHelp>
<format>29</format>
<description>Diffie-Hellman group 29 (ecp384bp)</description>
</valueHelp>
<valueHelp>
<format>30</format>
<description>Diffie-Hellman group 30 (ecp512bp)</description>
</valueHelp>
<valueHelp>
<format>31</format>
<description>Diffie-Hellman group 31 (curve25519)</description>
</valueHelp>
<valueHelp>
<format>32</format>
<description>Diffie-Hellman group 32 (curve448)</description>
</valueHelp>
<constraint>
<regex>^(1|2|5|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32)$</regex>
</constraint>
</properties>
</leafNode>
#include <include/vpn-ipsec-encryption.xml.i>
#include <include/vpn-ipsec-hash.xml.i>
</children>
</tagNode>
</children>
</tagNode>
<leafNode name="include-ipsec-conf">
<properties>
<help>Sets to include an additional configuration directive file for strongSwan. Use an absolute path to specify the included file</help>
</properties>
</leafNode>
<leafNode name="include-ipsec-secrets">
<properties>
<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">
<properties>
<help>Interface to use for VPN [REQUIRED]</help>
</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>
<node name="log">
<properties>
<help>IPsec logging</help>
</properties>
<children>
<leafNode name="level">
<properties>
<help>strongSwan Logger Level</help>
<valueHelp>
<format>u32:0</format>
<description>Very basic auditing logs e.g. SA up/SA down (default)</description>
</valueHelp>
<valueHelp>
<format>u32:1</format>
<description>Generic control flow with errors, a good default to see whats going on</description>
</valueHelp>
<valueHelp>
<format>u32:2</format>
<description>More detailed debugging control flow</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 0-2"/>
</constraint>
</properties>
<defaultValue>0</defaultValue>
</leafNode>
<leafNode name="subsystem">
<properties>
<help>Subsystem in the daemon the log comes from</help>
<completionHelp>
<list>dmn mgr ike chd job cfg knl net asn enc lib esp tls tnc imc imv pts any</list>
</completionHelp>
<valueHelp>
<format>dmn</format>
<description>Main daemon setup/cleanup/signal handling</description>
</valueHelp>
<valueHelp>
<format>mgr</format>
<description>IKE_SA manager, handling synchronization for IKE_SA access</description>
</valueHelp>
<valueHelp>
<format>ike</format>
<description>IKE_SA/ISAKMP SA</description>
</valueHelp>
<valueHelp>
<format>chd</format>
<description>CHILD_SA/IPsec SA</description>
</valueHelp>
<valueHelp>
<format>job</format>
<description>Jobs queuing/processing and thread pool management</description>
</valueHelp>
<valueHelp>
<format>cfg</format>
<description>Configuration management and plugins</description>
</valueHelp>
<valueHelp>
<format>knl</format>
<description>IPsec/Networking kernel interface</description>
</valueHelp>
<valueHelp>
<format>net</format>
<description>IKE network communication</description>
</valueHelp>
<valueHelp>
<format>asn</format>
<description>Low-level encoding/decoding (ASN.1, X.509 etc.)</description>
</valueHelp>
<valueHelp>
<format>enc</format>
<description>Packet encoding/decoding encryption/decryption operations</description>
</valueHelp>
<valueHelp>
<format>lib</format>
<description>libstrongswan library messages</description>
</valueHelp>
<valueHelp>
<format>esp</format>
<description>libipsec library messages</description>
</valueHelp>
<valueHelp>
<format>tls</format>
<description> libtls library messages</description>
</valueHelp>
<valueHelp>
<format>tnc</format>
<description>Trusted Network Connect</description>
</valueHelp>
<valueHelp>
<format>imc</format>
<description>Integrity Measurement Collector</description>
</valueHelp>
<valueHelp>
<format>imv</format>
<description>Integrity Measurement Verifier</description>
</valueHelp>
<valueHelp>
<format>pts</format>
<description> Platform Trust Service</description>
</valueHelp>
<valueHelp>
<format>any</format>
<description>Any subsystem</description>
</valueHelp>
<constraint>
<regex>^(dmn|mgr|ike|chd|job|cfg|knl|net|asn|enc|lib|esp|tls|tnc|imc|imv|pts|any)$</regex>
</constraint>
<multi/>
</properties>
</leafNode>
</children>
</node>
<node name="options">
<properties>
<help>Global IPsec settings</help>
</properties>
<children>
<leafNode name="disable-route-autoinstall">
<properties>
<help>Do not automatically install routes to remote networks</help>
<valueless/>
</properties>
</leafNode>
+ <node name="remote-access">
+ <properties>
+ <help>remote-access global options</help>
+ </properties>
+ <children>
+ <node name="dhcp-pool">
+ <properties>
+ <help>DHCP pool options for remote-access</help>
+ </properties>
+ <children>
+ <leafNode name="interface">
+ <properties>
+ <help>Interface with DHCP server to use</help>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_interfaces.py</script>
+ </completionHelp>
+ </properties>
+ </leafNode>
+ <leafNode name="server">
+ <properties>
+ <help>DHCP server address</help>
+ <valueHelp>
+ <format>ipv4</format>
+ <description>IPv4 address of the DHCP server</description>
+ </valueHelp>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ </children>
+ </node>
</children>
</node>
<tagNode name="profile">
<properties>
<help>VPN IPSec Profile</help>
</properties>
<children>
#include <include/generic-disable-node.xml.i>
<node name="authentication">
<properties>
<help>Authentication [REQUIRED]</help>
</properties>
<children>
<leafNode name="mode">
<properties>
<help>Authentication mode</help>
<completionHelp>
<list>pre-shared-secret</list>
</completionHelp>
<valueHelp>
<format>pre-shared-secret</format>
<description>Use pre shared secret key</description>
</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>
</children>
</node>
<node name="bind">
<properties>
<help>DMVPN crypto configuration</help>
</properties>
<children>
<leafNode name="tunnel">
<properties>
<help>Tunnel interface associated with this configuration profile</help>
<completionHelp>
<path>interfaces tunnel</path>
</completionHelp>
<valueHelp>
<format>txt</format>
<description>Associated interface to this configuration profile</description>
</valueHelp>
<multi/>
</properties>
</leafNode>
</children>
</node>
#include <include/ipsec/esp-group.xml.i>
#include <include/ipsec/ike-group.xml.i>
</children>
</tagNode>
<tagNode name="remote-access">
<properties>
<help>Remote access IKEv2 VPN </help>
</properties>
<children>
<node name="authentication">
<properties>
<help>Authentication for remote access</help>
</properties>
<children>
#include <include/ipsec/authentication-id.xml.i>
#include <include/ipsec/authentication-x509.xml.i>
+ <leafNode name="client-mode">
+ <properties>
+ <help>Client authentication mode</help>
+ <completionHelp>
+ <list>eap-tls eap-mschapv2</list>
+ </completionHelp>
+ <valueHelp>
+ <format>eap-tls</format>
+ <description>EAP-TLS</description>
+ </valueHelp>
+ <valueHelp>
+ <format>eap-mschapv2</format>
+ <description>EAP-MSCHAPv2</description>
+ </valueHelp>
+ <constraint>
+ <regex>^(eap-tls|eap-mschapv2)$</regex>
+ </constraint>
+ </properties>
+ <defaultValue>eap-mschapv2</defaultValue>
+ </leafNode>
<node name="local-users">
<properties>
<help>Local user authentication for PPPoE server</help>
</properties>
<children>
<tagNode name="username">
<properties>
<help>User name for authentication</help>
</properties>
<children>
#include <include/generic-disable-node.xml.i>
<leafNode name="password">
<properties>
<help>Password for authentication</help>
</properties>
</leafNode>
</children>
</tagNode>
</children>
</node>
+ <leafNode name="server-mode">
+ <properties>
+ <help>Server authentication mode</help>
+ <completionHelp>
+ <list>pre-shared-secret x509</list>
+ </completionHelp>
+ <valueHelp>
+ <format>pre-shared-secret</format>
+ <description>pre-shared-secret_description</description>
+ </valueHelp>
+ <valueHelp>
+ <format>x509</format>
+ <description>x509_description</description>
+ </valueHelp>
+ <constraint>
+ <regex>^(pre-shared-secret|x509)$</regex>
+ </constraint>
+ </properties>
+ <defaultValue>x509</defaultValue>
+ </leafNode>
+ <leafNode name="pre-shared-secret">
+ <properties>
+ <help>Pre-shared-secret used for server authentication</help>
+ </properties>
+ </leafNode>
</children>
</node>
#include <include/generic-description.xml.i>
#include <include/generic-disable-node.xml.i>
#include <include/ipsec/esp-group.xml.i>
#include <include/ipsec/ike-group.xml.i>
#include <include/ipsec/local-address.xml.i>
#include <include/ipsec/local-traffic-selector.xml.i>
<node name="pool">
<properties>
<help>IP address pool for remote-access users</help>
</properties>
<children>
+ <leafNode name="dhcp-enable">
+ <properties>
+ <help>Enable DHCP pool for clients on this connection</help>
+ <valueless/>
+ </properties>
+ </leafNode>
<leafNode name="exclude">
<properties>
<help>Local IPv4 or IPv6 pool prefix exclusions</help>
<valueHelp>
<format>ipv4</format>
<description>Local IPv4 pool prefix exclusion</description>
</valueHelp>
<valueHelp>
<format>ipv6</format>
<description>Local IPv6 pool prefix exclusion</description>
</valueHelp>
<constraint>
<validator name="ipv4-prefix"/>
<validator name="ipv6-prefix"/>
</constraint>
<multi/>
</properties>
</leafNode>
<leafNode name="prefix">
<properties>
<help>Local IPv4 or IPv6 pool prefix</help>
<valueHelp>
<format>ipv4</format>
<description>Local IPv4 pool prefix</description>
</valueHelp>
<valueHelp>
<format>ipv6</format>
<description>Local IPv6 pool prefix</description>
</valueHelp>
<constraint>
<validator name="ipv4-prefix"/>
<validator name="ipv6-prefix"/>
</constraint>
</properties>
</leafNode>
<!-- Include Accel-PPP definition here, maybe time for a rename? -->
#include <include/accel-ppp/name-server.xml.i>
</children>
</node>
<leafNode name="timeout">
<properties>
<help>Timeout to close connection if no data is transmitted</help>
<valueHelp>
<format>u32:10-86400</format>
<description>Timeout in seconds (default 28800)</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 10-86400"/>
</constraint>
</properties>
<defaultValue>28800</defaultValue>
</leafNode>
</children>
</tagNode>
<node name="site-to-site">
<properties>
<help>Site-to-site VPN</help>
</properties>
<children>
<tagNode name="peer">
<properties>
<help>VPN peer</help>
<valueHelp>
<format>ipv4</format>
<description>IPv4 address of the peer</description>
</valueHelp>
<valueHelp>
<format>ipv6</format>
<description>IPv6 address of the peer</description>
</valueHelp>
<valueHelp>
<format>txt</format>
<description>Hostname of the peer</description>
</valueHelp>
<valueHelp>
<format>&lt;@text&gt;</format>
<description>ID of the peer</description>
</valueHelp>
</properties>
<children>
#include <include/generic-disable-node.xml.i>
<node name="authentication">
<properties>
<help>Peer authentication [REQUIRED]</help>
</properties>
<children>
#include <include/ipsec/authentication-id.xml.i>
#include <include/ipsec/authentication-x509.xml.i>
<leafNode name="mode">
<properties>
<help>Authentication mode</help>
<completionHelp>
<list>pre-shared-secret rsa x509</list>
</completionHelp>
<valueHelp>
<format>pre-shared-secret</format>
<description>pre-shared-secret_description</description>
</valueHelp>
<valueHelp>
<format>rsa</format>
<description>rsa_description</description>
</valueHelp>
<valueHelp>
<format>x509</format>
<description>x509_description</description>
</valueHelp>
<constraint>
<regex>^(pre-shared-secret|rsa|x509)$</regex>
</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>
<leafNode name="remote-id">
<properties>
<help>ID for remote authentication</help>
<valueHelp>
<format>txt</format>
<description>ID used for peer authentication</description>
</valueHelp>
</properties>
</leafNode>
<leafNode name="rsa-key-name">
<properties>
<help>RSA key name</help>
</properties>
</leafNode>
<leafNode name="use-x509-id">
<properties>
<help>Use certificate common name as ID</help>
<valueless/>
</properties>
</leafNode>
</children>
</node>
<leafNode name="connection-type">
<properties>
<help>Connection type</help>
<completionHelp>
<list>initiate respond</list>
</completionHelp>
<valueHelp>
<format>initiate</format>
<description>initiate_description</description>
</valueHelp>
<valueHelp>
<format>respond</format>
<description>respond_description</description>
</valueHelp>
<constraint>
<regex>^(initiate|respond)$</regex>
</constraint>
</properties>
</leafNode>
<leafNode name="default-esp-group">
<properties>
<help>Defult ESP group name</help>
<completionHelp>
<path>vpn ipsec esp-group</path>
</completionHelp>
</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>
<leafNode name="force-encapsulation">
<properties>
<help>Force UDP Encapsulation for ESP Payloads</help>
<completionHelp>
<list>enable disable</list>
</completionHelp>
<valueHelp>
<format>enable</format>
<description>This endpoint will force UDP encapsulation for this peer</description>
</valueHelp>
<valueHelp>
<format>disable</format>
<description>This endpoint will not force UDP encapsulation for this peer</description>
</valueHelp>
<constraint>
<regex>^(enable|disable)$</regex>
</constraint>
</properties>
</leafNode>
#include <include/ipsec/ike-group.xml.i>
<leafNode name="ikev2-reauth">
<properties>
<help>Re-authentication of the remote peer during an IKE re-key. IKEv2 option only</help>
<completionHelp>
<list>yes no inherit</list>
</completionHelp>
<valueHelp>
<format>yes</format>
<description>Enable remote host re-autentication during an IKE re-key. Currently broken due to a strong swan bug</description>
</valueHelp>
<valueHelp>
<format>no</format>
<description>Disable remote host re-authenticaton during an IKE re-key.</description>
</valueHelp>
<valueHelp>
<format>inherit</format>
<description>Inherit the reauth configuration form your IKE-group (Default)</description>
</valueHelp>
<constraint>
<regex>^(yes|no|inherit)$</regex>
</constraint>
</properties>
</leafNode>
#include <include/ipsec/local-address.xml.i>
<tagNode name="tunnel">
<properties>
<help>Peer tunnel [REQUIRED]</help>
<valueHelp>
<format>u32</format>
<description>Peer tunnel [REQUIRED]</description>
</valueHelp>
</properties>
<children>
#include <include/generic-disable-node.xml.i>
#include <include/ipsec/esp-group.xml.i>
#include <include/ipsec/local-traffic-selector.xml.i>
#include <include/ip-protocol.xml.i>
<node name="remote">
<properties>
<help>Remote parameters for interesting traffic</help>
</properties>
<children>
#include <include/port-number.xml.i>
<leafNode name="prefix">
<properties>
<help>Remote IPv4 or IPv6 prefix</help>
<valueHelp>
<format>ipv4</format>
<description>Remote IPv4 prefix</description>
</valueHelp>
<valueHelp>
<format>ipv6</format>
<description>Remote IPv6 prefix</description>
</valueHelp>
<constraint>
<validator name="ipv4-prefix"/>
<validator name="ipv6-prefix"/>
</constraint>
<multi/>
</properties>
</leafNode>
</children>
</node>
</children>
</tagNode>
<node name="vti">
<properties>
<help>Virtual tunnel interface [REQUIRED]</help>
</properties>
<children>
<leafNode name="bind">
<properties>
<help>VTI tunnel interface associated with this configuration</help>
<completionHelp>
<path>interfaces vti</path>
</completionHelp>
</properties>
</leafNode>
#include <include/ipsec/esp-group.xml.i>
</children>
</node>
</children>
</tagNode>
</children>
</node>
</children>
</node>
</children>
</node>
</interfaceDefinition>
diff --git a/src/conf_mode/vpn_ipsec.py b/src/conf_mode/vpn_ipsec.py
index 76ee64a20..cf23a89c6 100755
--- a/src/conf_mode/vpn_ipsec.py
+++ b/src/conf_mode/vpn_ipsec.py
@@ -1,418 +1,462 @@
#!/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/>.
import ipaddress
import os
from sys import exit
from time import sleep
from vyos.config import Config
from vyos.configdict import leaf_node_changed
from vyos.configverify import verify_interface_exists
from vyos.configdict import dict_merge
from vyos.ifconfig import Interface
from vyos.pki import wrap_certificate
from vyos.pki import wrap_crl
from vyos.pki import wrap_public_key
from vyos.pki import wrap_private_key
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_args
from vyos.util import run
from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
dhcp_wait_attempts = 2
dhcp_wait_sleep = 1
swanctl_dir = '/etc/swanctl'
ipsec_conf = '/etc/ipsec.conf'
ipsec_secrets = '/etc/ipsec.secrets'
+charon_dhcp_conf = '/etc/strongswan.d/charon/dhcp.conf'
interface_conf = '/etc/strongswan.d/interfaces_use.conf'
swanctl_conf = f'{swanctl_dir}/swanctl.conf'
CERT_PATH = f'{swanctl_dir}/x509/'
KEY_PATH = f'{swanctl_dir}/private/'
CA_PATH = f'{swanctl_dir}/x509ca/'
CRL_PATH = f'{swanctl_dir}/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/'
def get_config(config=None):
if config:
conf = config
else:
conf = Config()
base = ['vpn', 'ipsec']
if not conf.exists(base):
return None
# retrieve common dictionary keys
ipsec = conf.get_config_dict(base, key_mangling=('-', '_'),
get_first_key=True, no_tag_node_value_mangle=True)
# We have gathered the dict representation of the CLI, but there are default
# options which we need to update into the dictionary retrived.
default_values = defaults(base)
# XXX: T2665: we must safely remove default values for tag nodes, those are
# added in a more fine grained way later on
del default_values['esp_group']
del default_values['ike_group']
del default_values['remote_access']
ipsec = dict_merge(default_values, ipsec)
if 'esp_group' in ipsec:
default_values = defaults(base + ['esp-group'])
for group in ipsec['esp_group']:
ipsec['esp_group'][group] = dict_merge(default_values,
ipsec['esp_group'][group])
if 'ike_group' in ipsec:
default_values = defaults(base + ['ike-group'])
for group in ipsec['ike_group']:
ipsec['ike_group'][group] = dict_merge(default_values,
ipsec['ike_group'][group])
if 'remote_access' in ipsec:
default_values = defaults(base + ['remote-access'])
for rw in ipsec['remote_access']:
ipsec['remote_access'][rw] = dict_merge(default_values,
ipsec['remote_access'][rw])
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'])
ipsec['pki'] = conf.get_config_dict(['pki'], key_mangling=('-', '_'),
get_first_key=True,
no_tag_node_value_mangle=True)
ipsec['rsa_keys'] = conf.get_config_dict(['vpn', 'rsa-keys'],
key_mangling=('-', '_'),
get_first_key=True,
no_tag_node_value_mangle=True)
return ipsec
def get_rsa_local_key(ipsec):
return dict_search_args(ipsec['rsa_keys'], 'local_key', 'file')
def verify_rsa_local_key(ipsec):
file = get_rsa_local_key(ipsec)
if not file:
return False
for path in LOCAL_KEY_PATHS:
full_path = os.path.join(path, file)
if os.path.exists(full_path):
return full_path
return False
def verify_rsa_key(ipsec, key_name):
return dict_search_args(ipsec['rsa_keys'], 'rsa_key_name', key_name, 'rsa_key')
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_pki(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(ipsec['pki'], 'ca', ca_cert_name, '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(ipsec['pki'], 'certificate', cert_name, 'certificate'):
+ if not dict_search_args(pki, 'certificate', cert_name, 'certificate'):
raise ConfigError(f'Missing certificate on specified PKI certificate "{cert_name}"')
- if not dict_search_args(ipsec['pki'], 'certificate', cert_name, 'private', 'key'):
+ if not dict_search_args(pki, 'certificate', cert_name, 'private', 'key'):
raise ConfigError(f'Missing private key on specified PKI certificate "{cert_name}"')
return True
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:
verify_interface_exists(ifname)
if 'profile' in ipsec:
for profile, profile_conf in ipsec['profile'].items():
if 'esp_group' in profile_conf:
if 'esp_group' not in ipsec or profile_conf['esp_group'] not in ipsec['esp_group']:
raise ConfigError(f"Invalid esp-group on {profile} profile")
else:
raise ConfigError(f"Missing esp-group on {profile} profile")
if 'ike_group' in profile_conf:
if 'ike_group' not in ipsec or profile_conf['ike_group'] not in ipsec['ike_group']:
raise ConfigError(f"Invalid ike-group on {profile} profile")
else:
raise ConfigError(f"Missing ike-group on {profile} profile")
if 'authentication' not in profile_conf:
raise ConfigError(f"Missing authentication on {profile} profile")
+ if 'remote_access' in ipsec:
+ for name, ra_conf in ipsec['remote_access'].items():
+ 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")
+ else:
+ raise ConfigError(f"Missing esp-group on {name} remote-access config")
+
+ if 'ike_group' in ra_conf:
+ if 'ike_group' not in ipsec or ra_conf['ike_group'] not in ipsec['ike_group']:
+ raise ConfigError(f"Invalid ike-group on {name} remote-access config")
+ else:
+ raise ConfigError(f"Missing ike-group on {name} remote-access config")
+
+ if 'authentication' not in ra_conf:
+ raise ConfigError(f"Missing authentication on {name} remote-access config")
+
+ if ra_conf['authentication']['server_mode'] == 'x509':
+ if 'x509' not in ra_conf['authentication']:
+ raise ConfigError(f"Missing x509 settings on {name} remote-access config")
+
+ x509 = ra_conf['authentication']['x509']
+
+ if 'ca_certificate' not in x509 or 'certificate' not in x509:
+ raise ConfigError(f"Missing x509 certificates on {name} remote-access config")
+
+ verify_pki(ipsec['pki'], x509)
+ elif ra_conf['authentication']['server_mode'] == 'pre-shared-secret':
+ if 'pre_shared_secret' not in ra_conf['authentication']:
+ raise ConfigError(f"Missing pre-shared-key on {name} remote-access config")
+
if 'site_to_site' in ipsec and 'peer' in ipsec['site_to_site']:
for peer, peer_conf in ipsec['site_to_site']['peer'].items():
has_default_esp = False
if 'default_esp_group' in peer_conf:
has_default_esp = True
if 'esp_group' not in ipsec or peer_conf['default_esp_group'] not in ipsec['esp_group']:
raise ConfigError(f"Invalid esp-group on site-to-site peer {peer}")
if 'ike_group' in peer_conf:
if 'ike_group' not in ipsec or peer_conf['ike_group'] not in ipsec['ike_group']:
raise ConfigError(f"Invalid ike-group on site-to-site peer {peer}")
else:
raise ConfigError(f"Missing ike-group on site-to-site peer {peer}")
if 'authentication' not in peer_conf or 'mode' not in peer_conf['authentication']:
raise ConfigError(f"Missing authentication on site-to-site peer {peer}")
if peer_conf['authentication']['mode'] == 'x509':
if 'x509' not in peer_conf['authentication']:
raise ConfigError(f"Missing x509 settings on site-to-site peer {peer}")
x509 = peer_conf['authentication']['x509']
if 'ca_certificate' not in x509 or 'certificate' not in x509:
raise ConfigError(f"Missing x509 certificates on site-to-site peer {peer}")
verify_pki(ipsec['pki'], x509)
if peer_conf['authentication']['mode'] == 'rsa':
if not verify_rsa_local_key(ipsec):
raise ConfigError(f"Invalid key on rsa-keys local-key")
if 'rsa_key_name' not in peer_conf['authentication']:
raise ConfigError(f"Missing rsa-key-name on site-to-site peer {peer}")
if not verify_rsa_key(ipsec, peer_conf['authentication']['rsa_key_name']):
raise ConfigError(f"Invalid rsa-key-name on site-to-site peer {peer}")
if 'local_address' not in peer_conf and 'dhcp_interface' not in peer_conf:
raise ConfigError(f"Missing local-address or dhcp-interface on site-to-site peer {peer}")
if 'dhcp_interface' in peer_conf:
dhcp_interface = peer_conf['dhcp_interface']
verify_interface_exists(dhcp_interface)
if not os.path.exists(f'{DHCP_BASE}_{dhcp_interface}.conf'):
raise ConfigError(f"Invalid dhcp-interface on site-to-site peer {peer}")
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'][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:
raise ConfigError(f"A single local-address or dhcp-interface is required when using VTI on site-to-site peer {peer}")
if 'bind' in peer_conf['vti']:
vti_interface = peer_conf['vti']['bind']
if not os.path.exists(f'/sys/class/net/{vti_interface}'):
raise ConfigError(f'VTI interface {vti_interface} for site-to-site peer {peer} does not exist!')
if 'vti' not in peer_conf and 'tunnel' not in peer_conf:
raise ConfigError(f"No VTI or tunnel specified on site-to-site peer {peer}")
if 'tunnel' in peer_conf:
for tunnel, tunnel_conf in peer_conf['tunnel'].items():
if 'esp_group' not in tunnel_conf and not has_default_esp:
raise ConfigError(f"Missing esp-group on tunnel {tunnel} for site-to-site peer {peer}")
esp_group_name = tunnel_conf['esp_group'] if 'esp_group' in tunnel_conf else peer_conf['default_esp_group']
if esp_group_name not in ipsec['esp_group']:
raise ConfigError(f"Invalid esp-group on tunnel {tunnel} for site-to-site peer {peer}")
esp_group = ipsec['esp_group'][esp_group_name]
if 'mode' in esp_group and esp_group['mode'] == 'transport':
if 'protocol' in tunnel_conf and ((peer in ['any', '0.0.0.0']) or ('local_address' not in peer_conf or peer_conf['local_address'] in ['any', '0.0.0.0'])):
raise ConfigError(f"Fixed local-address or peer required when a protocol is defined with ESP transport mode on tunnel {tunnel} for site-to-site peer {peer}")
if ('local' in tunnel_conf and 'prefix' in tunnel_conf['local']) or ('remote' in tunnel_conf and 'prefix' in tunnel_conf['remote']):
raise ConfigError(f"Local/remote prefix cannot be used with ESP transport mode on tunnel {tunnel} for site-to-site peer {peer}")
+def cleanup_pki_files():
+ for path in [CERT_PATH, CA_PATH, CRL_PATH, KEY_PATH]:
+ if not os.path.exists(path):
+ continue
+ for file in os.listdir(path):
+ file_path = os.path.join(path, file)
+ if os.path.isfile(file_path):
+ os.unlink(file_path)
+
def generate_pki_files(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 []
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
with open(os.path.join(CA_PATH, f'{ca_cert_name}.pem'), 'w') as f:
f.write(wrap_certificate(ca_cert_data))
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))
with open(os.path.join(KEY_PATH, f'{cert_name}.pem'), 'w') as f:
f.write(wrap_private_key(key_data, protected))
def generate(ipsec):
+ cleanup_pki_files()
+
if not ipsec:
for config_file in [ipsec_conf, ipsec_secrets, interface_conf, swanctl_conf]:
if os.path.isfile(config_file):
os.unlink(config_file)
return
if ipsec['dhcp_no_address']:
with open(DHCP_HOOK_IFLIST, 'w') as f:
f.write(" ".join(ipsec['dhcp_no_address'].values()))
data = ipsec
data['rsa_local_key'] = verify_rsa_local_key(ipsec)
for path in [swanctl_dir, CERT_PATH, CA_PATH, CRL_PATH]:
if not os.path.exists(path):
os.mkdir(path, mode=0o755)
if not os.path.exists(KEY_PATH):
os.mkdir(KEY_PATH, mode=0o700)
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']:
generate_pki_files(ipsec['pki'], rw_conf['authentication']['x509'])
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':
generate_pki_files(ipsec['pki'], peer_conf['authentication']['x509'])
local_ip = ''
if 'local_address' in peer_conf:
local_ip = peer_conf['local_address']
elif 'dhcp_interface' in peer_conf:
local_ip = get_dhcp_address(peer_conf['dhcp_interface'])
data['site_to_site']['peer'][peer]['local_address'] = local_ip
if 'tunnel' in peer_conf:
for tunnel, tunnel_conf in peer_conf['tunnel'].items():
local_prefixes = dict_search_args(tunnel_conf, 'local', 'prefix')
remote_prefixes = dict_search_args(tunnel_conf, 'remote', 'prefix')
if not local_prefixes or not remote_prefixes:
continue
passthrough = []
for local_prefix in local_prefixes:
for remote_prefix in remote_prefixes:
local_net = ipaddress.ip_network(local_prefix)
remote_net = ipaddress.ip_network(remote_prefix)
if local_net.overlaps(remote_net):
passthrough.append(local_prefix)
data['site_to_site']['peer'][peer]['tunnel'][tunnel]['passthrough'] = passthrough
render(ipsec_conf, 'ipsec/ipsec.conf.tmpl', data)
render(ipsec_secrets, 'ipsec/ipsec.secrets.tmpl', data)
+ render(charon_dhcp_conf, 'ipsec/charon/dhcp.conf.tmpl', data)
render(interface_conf, 'ipsec/interfaces_use.conf.tmpl', data)
render(swanctl_conf, 'ipsec/swanctl.conf.tmpl', data)
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
tmp = run('/usr/libexec/vyos/conf_mode/protocols_nhrp.py')
if tmp > 0:
print('ERROR: failed to reapply NHRP settings!')
def apply(ipsec):
if not ipsec:
call('sudo ipsec stop')
else:
args = ''
if 'auto_update' in ipsec:
args = '--auto-update ' + ipsec['auto_update']
call(f'sudo ipsec restart {args}')
call('sudo ipsec rereadall')
call('sudo ipsec reload')
sleep(5) # Give charon enough time to start
call('sudo swanctl -q')
resync_l2tp(ipsec)
resync_nhrp(ipsec)
if __name__ == '__main__':
try:
ipsec = get_config()
verify(ipsec)
generate(ipsec)
apply(ipsec)
except ConfigError as e:
print(e)
exit(1)

File Metadata

Mime Type
text/x-diff
Expires
Fri, Nov 6, 9:28 AM (17 h, 59 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4621880
Default Alt Text
(79 KB)

Event Timeline