Page Menu
Home
VyOS Platform
Search
Configure Global Search
Log In
Files
F119064052
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
48 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/data/templates/l2tp/l2tp.config.tmpl b/data/templates/l2tp/l2tp.config.tmpl
index 0dcff1371..ba78cadcd 100644
--- a/data/templates/l2tp/l2tp.config.tmpl
+++ b/data/templates/l2tp/l2tp.config.tmpl
@@ -1,147 +1,147 @@
### generated by accel_l2tp.py ###
[modules]
log_syslog
l2tp
chap-secrets
{% for proto in auth_proto: %}
{{proto}}
{% endfor%}
{% if auth_mode == 'radius' %}
radius
{% endif -%}
ippool
shaper
ipv6pool
ipv6_nd
ipv6_dhcp
[core]
thread-count={{thread_cnt}}
[log]
syslog=accel-l2tp,daemon
copy=1
level=5
{% if dnsv4 %}
[dns]
{% for dns in dnsv4 -%}
dns{{ loop.index }}={{ dns }}
{% endfor -%}
{% endif %}
{% if dnsv6 %}
[ipv6-dns]
{% for dns in dnsv6 -%}
{{ dns }}
{% endfor -%}
{% endif %}
{% if wins %}
[wins]
{% for server in wins -%}
wins{{ loop.index }}={{ server }}
{% endfor -%}
{% endif %}
[l2tp]
verbose=1
ifname=l2tp%d
ppp-max-mtu={{ mtu }}
mppe={{ ppp_mppe }}
{% if outside_addr %}
bind={{ outside_addr }}
{% endif %}
{% if lns_shared_secret %}
secret={{ lns_shared_secret }}
{% endif %}
[client-ip-range]
0.0.0.0/0
{% if client_ip_pool or client_ip_subnets %}
[ip-pool]
{% if client_ip_pool %}
{{ client_ip_pool }}
{% endif -%}
{% if client_ip_subnets %}
{% for sn in client_ip_subnets %}
{{sn}}
{% endfor -%}
{% endif %}
{% endif %}
{% if gateway_address %}
gw-ip-address={{ gateway_address }}
{% endif %}
{% if auth_mode == 'local' %}
[chap-secrets]
chap-secrets={{ chap_secrets_file }}
{% elif auth_mode == 'radius' %}
[radius]
verbose=1
{% for r in radius_server %}
server={{ r.server }},{{ r.key }},auth-port={{ r.port }},req-limit=0,fail-time={{ r.fail_time }}
{% endfor -%}
{% endif %}
acct-timeout={{ radius_acct_tmo }}
timeout={{ radius_timeout }}
max-try={{ radius_max_try }}
{% if radius_nas_id %}
nas-identifier={{ radius_nas_id }}
{% endif -%}
{% if radius_nas_ip %}
nas-ip-address={{ radius_nas_ip }}
{% endif -%}
{% if radius_source_address %}
bind={{ radius_source_address }}
{% endif -%}
[ppp]
verbose=1
check-ip=1
single-session=replace
lcp-echo-timeout={{ ppp_echo_timeout }}
lcp-echo-interval={{ ppp_echo_interval }}
lcp-echo-failure={{ ppp_echo_failure }}
{% if ccp_disable %}
ccp=0
{% endif %}
{% if client_ipv6_pool %}
ipv6=allow
{% endif %}
{% if client_ipv6_pool %}
[ipv6-pool]
-{% for prefix in client_ipv6_pool %}
-{{ prefix }}
+{% for p in client_ipv6_pool %}
+{{ p.prefix }},{{ p.mask }}
{% endfor %}
-{% for prefix in client_ipv6_delegate_prefix %}
-delegate={{ prefix }}
+{% for p in client_ipv6_delegate_prefix %}
+delegate={{ p.prefix }},{{ p.mask }}
{% endfor %}
{% endif %}
{% if client_ipv6_delegate_prefix %}
[ipv6-dhcp]
verbose=1
{% endif %}
{% if radius_shaper_attr %}
[shaper]
verbose=1
attr={{ radius_shaper_attr }}
{% if radius_shaper_vendor %}
vendor={{ radius_shaper_vendor }}
{% endif -%}
{% endif %}
[cli]
tcp=127.0.0.1:2004
sessions-columns=ifname,username,calling-sid,ip,{{ ip6_column | join(',') }}{{ ',' if ip6_column }}rate-limit,type,comp,state,rx-bytes,tx-bytes,uptime
diff --git a/interface-definitions/vpn-l2tp.xml.in b/interface-definitions/vpn-l2tp.xml.in
index 84dd8187c..d4286a810 100644
--- a/interface-definitions/vpn-l2tp.xml.in
+++ b/interface-definitions/vpn-l2tp.xml.in
@@ -1,530 +1,562 @@
<?xml version="1.0"?>
<interfaceDefinition>
<node name="vpn">
<children>
<node name="l2tp" owner="${vyos_conf_scripts_dir}/vpn_l2tp.py">
<properties>
<help>L2TP Virtual Private Network (VPN)</help>
</properties>
<children>
<node name="remote-access">
<properties>
<help>Remote access L2TP VPN</help>
</properties>
<children>
<leafNode name="mtu">
<properties>
<help>Maximum Transmission Unit (MTU)</help>
<constraint>
<validator name="numeric" argument="--range 128-16384"/>
</constraint>
</properties>
</leafNode>
<leafNode name="outside-address">
<properties>
<help>External IP address to which VPN clients will connect</help>
<constraint>
<validator name="ipv4-address"/>
</constraint>
</properties>
</leafNode>
<leafNode name="gateway-address">
<properties>
<help>Gatway address uses as client tunnel termination point</help>
<constraint>
<validator name="ipv4-address"/>
</constraint>
</properties>
</leafNode>
<leafNode name="name-server">
<properties>
<help>Domain Name Server (DNS) propagated to client</help>
<valueHelp>
<format>ipv4</format>
<description>Domain Name Server (DNS) IPv4 address</description>
</valueHelp>
<valueHelp>
<format>ipv6</format>
<description>Domain Name Server (DNS) IPv6 address</description>
</valueHelp>
<constraint>
<validator name="ipv4-address"/>
<validator name="ipv6-address"/>
</constraint>
<multi/>
</properties>
</leafNode>
<node name="lns">
<properties>
<help>L2TP Network Server (LNS)</help>
</properties>
<children>
<leafNode name="shared-secret">
<properties>
<help>Tunnel password used to authenticate the client (LAC)</help>
</properties>
</leafNode>
</children>
</node>
<leafNode name="ccp-disable">
<properties>
<help>Disable Compression Control Protocol (CCP)</help>
<valueless />
</properties>
</leafNode>
<node name="ipsec-settings">
<properties>
<help>Internet Protocol Security (IPsec) for remote access L2TP VPN</help>
</properties>
<children>
<node name="authentication">
<properties>
<help>IPsec authentication settings</help>
</properties>
<children>
<leafNode name="mode">
<properties>
<help>Authentication mode for IPsec</help>
<valueHelp>
<format>pre-shared-secret</format>
<description>Use pre-shared secret for IPsec authentication</description>
</valueHelp>
<valueHelp>
<format>x509</format>
<description>Use X.509 certificate for IPsec authentication</description>
</valueHelp>
<constraint>
<regex>(pre-shared-secret|x509)</regex>
</constraint>
<completionHelp>
<list>pre-shared-secret x509</list>
</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>
<leafNode name="ca-cert-file">
<properties>
<help>File containing the X.509 certificate for the Certificate Authority (CA)</help>
<valueHelp>
<format><text></format>
<description>File in /config/auth</description>
</valueHelp>
</properties>
</leafNode>
<leafNode name="crl-file">
<properties>
<help>File containing the X.509 Certificate Revocation List (CRL)</help>
<valueHelp>
<format><text></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><text></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><text></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>
</children>
</node>
<leafNode name="ike-lifetime">
<properties>
<help>IKE lifetime</help>
<valueHelp>
<format><30-86400></format>
<description>IKE lifetime in seconds (default 3600)</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 30-86400"/>
</constraint>
</properties>
</leafNode>
<leafNode name="lifetime">
<properties>
<help>ESP lifetime</help>
<valueHelp>
<format><30-86400></format>
<description>IKE lifetime in seconds (default 3600)</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 30-86400"/>
</constraint>
</properties>
</leafNode>
</children>
</node>
<leafNode name="wins-server">
<properties>
<help>Windows Internet Name Service (WINS) servers propagated to client</help>
<valueHelp>
<format>ipv4</format>
<description>Domain Name Server (DNS) IPv4 address</description>
</valueHelp>
<constraint>
<validator name="ipv4-address"/>
</constraint>
<multi/>
</properties>
</leafNode>
<node name="client-ip-pool">
<properties>
<help>Pool of client IP addresses (must be within a /24)</help>
</properties>
<children>
<leafNode name="start">
<properties>
<help>First IP address in the pool (will be used as gateway address)</help>
<constraint>
<validator name="ipv4-address"/>
</constraint>
</properties>
</leafNode>
<leafNode name="stop">
<properties>
<help>Last IP address in the pool</help>
<constraint>
<validator name="ipv4-address"/>
</constraint>
</properties>
</leafNode>
<leafNode name="subnet">
<properties>
<help>Client IP subnet (CIDR notation)</help>
<constraint>
<validator name="ipv4-prefix"/>
</constraint>
<constraintErrorMessage>Not a valid CIDR formatted prefix</constraintErrorMessage>
<valueHelp>
<format>ipv4net</format>
<description>IPv4 subnet address</description>
</valueHelp>
<multi />
</properties>
</leafNode>
</children>
</node>
<node name="client-ipv6-pool">
<properties>
<help>Pool of client IPv6 addresses</help>
</properties>
<children>
- <leafNode name="prefix">
+ <tagNode name="prefix">
<properties>
- <help>IPV6 prefix delegation</help>
+ <help>Pool of addresses used to assign to clients</help>
<valueHelp>
- <format>ipv6prefix/mask,prefix_len</format>
- <description>e.g.: fc00:0:1::/48,64 - divides prefix into /64 subnets for clients</description>
+ <format>ipv6net</format>
+ <description>IPv6 address and prefix length</description>
</valueHelp>
- <multi />
+ <constraint>
+ <validator name="ipv6-prefix"/>
+ </constraint>
</properties>
- </leafNode>
- <leafNode name="delegate-prefix">
+ <children>
+ <leafNode name="mask">
+ <properties>
+ <help>Prefix length used for individual client</help>
+ <valueHelp>
+ <format><48-128></format>
+ <description>Client prefix length (default: 64)</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 48-128"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+ </tagNode>
+ <tagNode name="delegate">
<properties>
- <help>DHCPv6 prefix delegation - rfc3633</help>
+ <help>Subnet used to delegate prefix through DHCPv6-PD (RFC3633)</help>
<valueHelp>
- <format>ipv6prefix/mask,prefix_len</format>
- <description>Delegate to clients through DHCPv6 prefix delegation - rfc3633</description>
+ <format>ipv6net</format>
+ <description>IPv6 address and prefix length</description>
</valueHelp>
- <multi />
+ <constraint>
+ <validator name="ipv6-prefix"/>
+ </constraint>
</properties>
- </leafNode>
+ <children>
+ <leafNode name="delegation-prefix">
+ <properties>
+ <help>Prefix length delegated to client</help>
+ <valueHelp>
+ <format><32-64></format>
+ <description>Delegated prefix length</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 32-64"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+ </tagNode>
</children>
</node>
<leafNode name="description">
<properties>
<help>Description for L2TP remote-access settings</help>
</properties>
</leafNode>
<leafNode name="dhcp-interface">
<properties>
<help>DHCP interface to listen on</help>
</properties>
</leafNode>
<leafNode name="idle">
<properties>
<help>PPP idle timeout</help>
<valueHelp>
<format><30-86400></format>
<description>PPP idle timeout in seconds (default 1800)</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 30-86400"/>
</constraint>
</properties>
</leafNode>
<node name="authentication">
<properties>
<help>Authentication for remote access L2TP VPN</help>
</properties>
<children>
<leafNode name="require">
<properties>
<help>Authentication protocol for remote access peer L2TP VPN</help>
<valueHelp>
<format>pap</format>
<description>Require the peer to authenticate itself using PAP [Password Authentication Protocol].</description>
</valueHelp>
<valueHelp>
<format>chap</format>
<description>Require the peer to authenticate itself using CHAP [Challenge Handshake Authentication Protocol].</description>
</valueHelp>
<valueHelp>
<format>mschap</format>
<description>Require the peer to authenticate itself using CHAP [Challenge Handshake Authentication Protocol].</description>
</valueHelp>
<valueHelp>
<format>mschap-v2</format>
<description>Require the peer to authenticate itself using MS-CHAPv2 [Microsoft Challenge Handshake Authentication Protocol, Version 2].</description>
</valueHelp>
<constraint>
<regex>(pap|chap|mschap|mschap-v2)</regex>
</constraint>
<completionHelp>
<list>pap chap mschap mschap-v2</list>
</completionHelp>
<multi />
</properties>
</leafNode>
<leafNode name="mppe">
<properties>
<help>Specifies mppe negotioation preference. (default require mppe 128-bit stateless</help>
<valueHelp>
<format>deny</format>
<description>deny mppe</description>
</valueHelp>
<valueHelp>
<format>prefer</format>
<description>Ask client for mppe, if it rejects do not fail</description>
</valueHelp>
<valueHelp>
<format>require</format>
<description>ask client for mppe, if it rejects drop connection</description>
</valueHelp>
<constraint>
<regex>(deny|prefer|require)</regex>
</constraint>
<completionHelp>
<list>deny prefer require</list>
</completionHelp>
</properties>
</leafNode>
<leafNode name="mode">
<properties>
<help>Authentication mode for remote access L2TP VPN</help>
<valueHelp>
<format>local</format>
<description>Use local username/password configuration</description>
</valueHelp>
<valueHelp>
<format>radius</format>
<description>Use a RADIUS server to autenticate users</description>
</valueHelp>
<constraint>
<regex>(local|radius)</regex>
</constraint>
<completionHelp>
<list>local radius</list>
</completionHelp>
</properties>
</leafNode>
<node name="local-users">
<properties>
<help>Local user authentication for remote access L2TP VPN</help>
</properties>
<children>
<tagNode name="username">
<properties>
<help>User name for authentication</help>
</properties>
<children>
<leafNode name="disable">
<properties>
<help>Option to disable a L2TP Server user</help>
<valueless/>
</properties>
</leafNode>
<leafNode name="password">
<properties>
<help>Password for authentication</help>
</properties>
</leafNode>
<leafNode name="static-ip">
<properties>
<help>Static client IP address</help>
</properties>
</leafNode>
<node name="rate-limit">
<properties>
<help>Upload/Download speed limits</help>
</properties>
<children>
<leafNode name="upload">
<properties>
<help>Upload bandwidth limit in kbits/sec</help>
<constraint>
<validator name="numeric" argument="--range 1-65535"/>
</constraint>
</properties>
</leafNode>
<leafNode name="download">
<properties>
<help>Download bandwidth limit in kbits/sec</help>
<constraint>
<validator name="numeric" argument="--range 1-65535"/>
</constraint>
</properties>
</leafNode>
</children>
</node>
</children>
</tagNode>
</children>
</node>
#include <include/radius-server.xml.i>
<node name="radius">
<children>
<tagNode name="server">
<children>
<leafNode name="fail-time">
<properties>
<help>Mark server unavailable for <n> seconds on failure</help>
<valueHelp>
<format>0-600</format>
<description>Fail time penalty</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 0-600"/>
</constraint>
<constraintErrorMessage>Fail time must be between 0 and 600 seconds</constraintErrorMessage>
</properties>
</leafNode>
</children>
</tagNode>
<leafNode name="timeout">
<properties>
<help>Timeout to wait response from server (seconds)</help>
</properties>
</leafNode>
<leafNode name="acct-timeout">
<properties>
<help>Timeout to wait reply for Interim-Update packets. (default 3 seconds)</help>
</properties>
</leafNode>
<leafNode name="max-try">
<properties>
<help>Maximum number of tries to send Access-Request/Accounting-Request queries</help>
</properties>
</leafNode>
<leafNode name="nas-identifier">
<properties>
<help>Value to send to RADIUS server in NAS-Identifier attribute and to be matched in DM/CoA requests.</help>
</properties>
</leafNode>
<node name="dae-server">
<properties>
<help>IPv4 address and port to bind Dynamic Authorization Extension server (DM/CoA)</help>
</properties>
<children>
<leafNode name="ip-address">
<properties>
<help>IP address for Dynamic Authorization Extension server (DM/CoA)</help>
</properties>
</leafNode>
<leafNode name="port">
<properties>
<help>Port for Dynamic Authorization Extension server (DM/CoA)</help>
</properties>
</leafNode>
<leafNode name="secret">
<properties>
<help>Secret for Dynamic Authorization Extension server (DM/CoA)</help>
</properties>
</leafNode>
</children>
</node>
<node name="rate-limit">
<properties>
<help>Upload/Download speed limits</help>
</properties>
<children>
<leafNode name="attribute">
<properties>
<help>Specifies which radius attribute contains rate information. (default is Filter-Id)</help>
</properties>
</leafNode>
<leafNode name="vendor">
<properties>
<help>Specifies the vendor dictionary. (dictionary needs to be in /usr/share/accel-ppp/radius)</help>
</properties>
</leafNode>
<leafNode name="enable">
<properties>
<help>Enables Bandwidth shaping via RADIUS</help>
<valueless />
</properties>
</leafNode>
</children>
</node>
</children>
</node>
</children>
</node>
<node name="ppp-options">
<properties>
<help>Advanced protocol options</help>
</properties>
<children>
<leafNode name="lcp-echo-interval">
<properties>
<help>LCP echo-requests/sec</help>
<constraint>
<validator name="numeric" argument="--positive"/>
</constraint>
</properties>
</leafNode>
<leafNode name="lcp-echo-failure">
<properties>
<help>Maximum number of Echo-Requests may be sent without valid reply</help>
<constraint>
<validator name="numeric" argument="--positive"/>
</constraint>
</properties>
</leafNode>
</children>
</node>
</children>
</node>
</children>
</node>
</children>
</node>
</interfaceDefinition>
diff --git a/src/conf_mode/vpn_l2tp.py b/src/conf_mode/vpn_l2tp.py
index 08654e2ff..7cfb4e74e 100755
--- a/src/conf_mode/vpn_l2tp.py
+++ b/src/conf_mode/vpn_l2tp.py
@@ -1,372 +1,394 @@
#!/usr/bin/env python3
#
# Copyright (C) 2019-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 os
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
from jinja2 import FileSystemLoader, Environment
from vyos.config import Config
from vyos.defaults import directories as vyos_data_dir
from vyos.util import call
from vyos.validate import is_ipv4
from vyos import ConfigError
l2tp_conf = '/etc/accel-ppp/l2tp.conf'
l2tp_chap_secrets = '/etc/accel-ppp/l2tp.chap-secrets'
default_config_data = {
'auth_mode': 'local',
'auth_ppp_mppe': 'prefer',
'auth_proto': ['auth_mschap_v2'],
'chap_secrets_file': l2tp_chap_secrets, # used in Jinja2 template
'client_ip_pool': None,
'client_ip_subnets': [],
'client_ipv6_pool': [],
'client_ipv6_delegate_prefix': [],
'dnsv4': [],
'dnsv6': [],
'gateway_address': '10.255.255.0',
'local_users' : [],
'mtu': '1436',
'outside_addr': '',
'ppp_mppe': 'prefer',
'ppp_echo_failure' : '3',
'ppp_echo_interval' : '30',
'ppp_echo_timeout': '0',
'radius_server': [],
'radius_acct_tmo': '3',
'radius_max_try': '3',
'radius_timeout': '3',
'radius_nas_id': '',
'radius_nas_ip': '',
'radius_source_address': '',
'radius_shaper_attr': '',
'radius_shaper_vendor': '',
'radius_dynamic_author': '',
'wins': [],
'ip6_column': [],
'thread_cnt': 1
}
def get_config():
conf = Config()
base_path = ['vpn', 'l2tp', 'remote-access']
if not conf.exists(base_path):
return None
conf.set_level(base_path)
l2tp = deepcopy(default_config_data)
cpu = os.cpu_count()
if cpu > 1:
l2tp['thread_cnt'] = int(cpu/2)
### general options ###
if conf.exists(['name-server']):
for name_server in conf.return_values(['name-server']):
if is_ipv4(name_server):
l2tp['dnsv4'].append(name_server)
else:
l2tp['dnsv6'].append(name_server)
if conf.exists(['wins-server']):
l2tp['wins'] = conf.return_values(['wins-server'])
if conf.exists('outside-address'):
l2tp['outside_addr'] = conf.return_value('outside-address')
if conf.exists(['authentication', 'mode']):
l2tp['auth_mode'] = conf.return_value(['authentication', 'mode'])
if conf.exists(['authentication', 'protocols']):
auth_mods = {
'pap': 'auth_pap',
'chap': 'auth_chap_md5',
'mschap': 'auth_mschap_v1',
'mschap-v2': 'auth_mschap_v2'
}
for proto in conf.return_values(['authentication', 'protocols']):
l2tp['auth_proto'].append(auth_mods[proto])
if conf.exists(['authentication', 'mppe']):
l2tp['auth_ppp_mppe'] = conf.return_value(['authentication', 'mppe'])
#
# local auth
if conf.exists(['authentication', 'local-users']):
for username in conf.list_nodes(['authentication', 'local-users', 'username']):
user = {
'name' : username,
'password' : '',
'state' : 'enabled',
'ip' : '*',
'upload' : None,
'download' : None
}
conf.set_level(base_path + ['authentication', 'local-users', 'username', username])
if conf.exists(['password']):
user['password'] = conf.return_value(['password'])
if conf.exists(['disable']):
user['state'] = 'disable'
if conf.exists(['static-ip']):
user['ip'] = conf.return_value(['static-ip'])
if conf.exists(['rate-limit', 'download']):
user['download'] = conf.return_value(['rate-limit', 'download'])
if conf.exists(['rate-limit', 'upload']):
user['upload'] = conf.return_value(['rate-limit', 'upload'])
l2tp['local_users'].append(user)
#
# RADIUS auth and settings
conf.set_level(base_path + ['authentication', 'radius'])
if conf.exists(['server']):
for server in conf.list_nodes(['server']):
radius = {
'server' : server,
'key' : '',
'fail_time' : 0,
'port' : '1812'
}
conf.set_level(base_path + ['authentication', 'radius', 'server', server])
if conf.exists(['fail-time']):
radius['fail-time'] = conf.return_value(['fail-time'])
if conf.exists(['port']):
radius['port'] = conf.return_value(['port'])
if conf.exists(['key']):
radius['key'] = conf.return_value(['key'])
if not conf.exists(['disable']):
l2tp['radius_server'].append(radius)
#
# advanced radius-setting
conf.set_level(base_path + ['authentication', 'radius'])
if conf.exists(['acct-timeout']):
l2tp['radius_acct_tmo'] = conf.return_value(['acct-timeout'])
if conf.exists(['max-try']):
l2tp['radius_max_try'] = conf.return_value(['max-try'])
if conf.exists(['timeout']):
l2tp['radius_timeout'] = conf.return_value(['timeout'])
if conf.exists(['nas-identifier']):
l2tp['radius_nas_id'] = conf.return_value(['nas-identifier'])
if conf.exists(['nas-ip-address']):
l2tp['radius_nas_ip'] = conf.return_value(['nas-ip-address'])
if conf.exists(['source-address']):
l2tp['radius_source_address'] = conf.return_value(['source-address'])
# Dynamic Authorization Extensions (DOA)/Change Of Authentication (COA)
if conf.exists(['dynamic-author']):
dae = {
'port' : '',
'server' : '',
'key' : ''
}
if conf.exists(['dynamic-author', 'server']):
dae['server'] = conf.return_value(['dynamic-author', 'server'])
if conf.exists(['dynamic-author', 'port']):
dae['port'] = conf.return_value(['dynamic-author', 'port'])
if conf.exists(['dynamic-author', 'key']):
dae['key'] = conf.return_value(['dynamic-author', 'key'])
l2tp['radius_dynamic_author'] = dae
if conf.exists(['rate-limit', 'enable']):
l2tp['radius_shaper_attr'] = 'Filter-Id'
c_attr = ['rate-limit', 'enable', 'attribute']
if conf.exists(c_attr):
l2tp['radius_shaper_attr'] = conf.return_value(c_attr)
c_vendor = ['rate-limit', 'enable', 'vendor']
if conf.exists(c_vendor):
l2tp['radius_shaper_vendor'] = conf.return_value(c_vendor)
conf.set_level(base_path)
if conf.exists(['client-ip-pool']):
if conf.exists(['client-ip-pool', 'start']) and conf.exists(['client-ip-pool', 'stop']):
start = conf.return_value(['client-ip-pool', 'start'])
stop = conf.return_value(['client-ip-pool', 'stop'])
l2tp['client_ip_pool'] = start + '-' + re.search('[0-9]+$', stop).group(0)
if conf.exists(['client-ip-pool', 'subnet']):
l2tp['client_ip_subnets'] = conf.return_values(['client-ip-pool', 'subnet'])
if conf.exists(['client-ipv6-pool', 'prefix']):
- l2tp['client_ipv6_pool'] = conf.return_values(['client-ipv6-pool', 'prefix'])
l2tp['ip6_column'].append('ip6')
+ for prefix in conf.list_nodes(['client-ipv6-pool', 'prefix']):
+ tmp = {
+ 'prefix': prefix,
+ 'mask': '64'
+ }
+
+ if conf.exists(['client-ipv6-pool', 'prefix', prefix, 'mask']):
+ tmp['mask'] = conf.return_value(['client-ipv6-pool', 'prefix', prefix, 'mask'])
- if conf.exists(['client-ipv6-pool', 'delegate-prefix']):
- l2tp['client_ipv6_delegate_prefix'] = conf.return_values(['client-ipv6-pool', 'delegate-prefix'])
- l2tp['ip6_column'].append('ip6-dp')
+ l2tp['client_ipv6_pool'].append(tmp)
+
+ if conf.exists(['client-ipv6-pool', 'delegate']):
+ l2tp['ip6_column'].append('ip6-db')
+ for prefix in conf.list_nodes(['client-ipv6-pool', 'delegate']):
+ tmp = {
+ 'prefix': prefix,
+ 'mask': ''
+ }
+
+ if conf.exists(['client-ipv6-pool', 'delegate', prefix, 'mask']):
+ tmp['mask'] = conf.return_value(['client-ipv6-pool', 'delegate', prefix, 'delegation-prefix'])
+
+ l2tp['client_ipv6_delegate_prefix'].append(tmp)
if conf.exists(['mtu']):
l2tp['mtu'] = conf.return_value(['mtu'])
# gateway address
if conf.exists(['gateway-address']):
l2tp['gateway_address'] = conf.return_value(['gateway-address'])
else:
# calculate gw-ip-address
if conf.exists(['client-ip-pool', 'start']):
# use start ip as gw-ip-address
l2tp['gateway_address'] = conf.return_value(['client-ip-pool', 'start'])
elif conf.exists(['client-ip-pool', 'subnet']):
# use first ip address from first defined pool
subnet = conf.return_values(['client-ip-pool', 'subnet'])[0]
subnet = ip_network(subnet)
l2tp['gateway_address'] = str(list(subnet.hosts())[0])
# LNS secret
if conf.exists(['lns', 'shared-secret']):
l2tp['lns_shared_secret'] = conf.return_value(['lns', 'shared-secret'])
if conf.exists(['ccp-disable']):
l2tp[['ccp_disable']] = True
# PPP options
if conf.exists(['idle']):
l2tp['ppp_echo_timeout'] = conf.return_value(['idle'])
if conf.exists(['ppp-options', 'lcp-echo-failure']):
l2tp['ppp_echo_failure'] = conf.return_value(['ppp-options', 'lcp-echo-failure'])
if conf.exists(['ppp-options', 'lcp-echo-interval']):
l2tp['ppp_echo_interval'] = conf.return_value(['ppp-options', 'lcp-echo-interval'])
return l2tp
def verify(l2tp):
if not l2tp:
return None
if l2tp['auth_mode'] == 'local':
if not l2tp['local_users']:
raise ConfigError('L2TP local auth mode requires local users to be configured!')
for user in l2tp['local_users']:
if not user['password']:
raise ConfigError(f"Password required for user {user['name']}")
elif l2tp['auth_mode'] == 'radius':
if len(l2tp['radius_server']) == 0:
raise ConfigError("RADIUS authentication requires at least one server")
for radius in l2tp['radius_server']:
if not radius['key']:
raise ConfigError(f"Missing RADIUS secret for server {{ radius['key'] }}")
# check for the existence of a client ip pool
if not (l2tp['client_ip_pool'] or l2tp['client_ip_subnets']):
raise ConfigError(
"set vpn l2tp remote-access client-ip-pool requires subnet or start/stop IP pool")
# check ipv6
if l2tp['client_ipv6_delegate_prefix'] and not l2tp['client_ipv6_pool']:
raise ConfigError('IPv6 prefix delegation requires client-ipv6-pool prefix')
+ for prefix in l2tp['client_ipv6_delegate_prefix']:
+ if not prefix['mask']:
+ raise ConfigError('Delegation-prefix required for individual delegated networks')
+
if len(l2tp['wins']) > 2:
raise ConfigError('Not more then two IPv4 WINS name-servers can be configured')
if len(l2tp['dnsv4']) > 2:
raise ConfigError('Not more then two IPv4 DNS name-servers can be configured')
if len(l2tp['dnsv6']) > 3:
raise ConfigError('Not more then three IPv6 DNS name-servers can be configured')
return None
def generate(l2tp):
if not l2tp:
return None
# Prepare Jinja2 template loader from files
tmpl_path = os.path.join(vyos_data_dir['data'], 'templates', 'l2tp')
fs_loader = FileSystemLoader(tmpl_path)
env = Environment(loader=fs_loader, trim_blocks=True)
tmpl = env.get_template('l2tp.config.tmpl')
config_text = tmpl.render(c)
with open(l2tp_conf, 'w') as f:
f.write(config_text)
if l2tp['auth_mode'] == 'local':
tmpl = env.get_template('chap-secrets.tmpl')
config_text = tmpl.render(l2tp)
with open(l2tp_chap_secrets, 'w') as f:
f.write(config_text)
os.chmod(l2tp_chap_secrets, S_IRUSR | S_IWUSR | S_IRGRP)
else:
if os.path.exists(l2tp_chap_secrets):
os.unlink(l2tp_chap_secrets)
return None
def apply(l2tp):
if not l2tp:
call('systemctl stop accel-ppp-l2tp.service')
if os.path.exists(l2tp_conf):
os.unlink(l2tp_conf)
if os.path.exists(l2tp_chap_secrets):
os.unlink(l2tp_chap_secrets)
return None
call('systemctl restart accel-ppp-l2tp.service')
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/migration-scripts/l2tp/2-to-3 b/src/migration-scripts/l2tp/2-to-3
index e24d1ffa9..bd0839e03 100755
--- a/src/migration-scripts/l2tp/2-to-3
+++ b/src/migration-scripts/l2tp/2-to-3
@@ -1,83 +1,111 @@
#!/usr/bin/env python3
#
# Copyright (C) 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/>.
# - remove primary/secondary identifier from nameserver
# - TODO: remove radius server req-limit
import os
import sys
from sys import argv, exit
from vyos.configtree import ConfigTree
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']
if not config.exists(base):
# Nothing to do
exit(0)
else:
# Migrate IPv4 DNS servers
dns_base = base + ['dns-servers']
if config.exists(dns_base):
for server in ['server-1', 'server-2']:
if config.exists(dns_base + [server]):
dns = config.return_value(dns_base + [server])
config.set(base + ['name-server'], value=dns, replace=False)
config.delete(dns_base)
# Migrate IPv6 DNS servers
dns_base = base + ['dnsv6-servers']
if config.exists(dns_base):
for server in config.return_values(dns_base):
config.set(base + ['name-server'], value=server, replace=False)
config.delete(dns_base)
# Migrate IPv4 WINS servers
wins_base = base + ['wins-servers']
if config.exists(wins_base):
for server in ['server-1', 'server-2']:
if config.exists(wins_base + [server]):
wins = config.return_value(wins_base + [server])
config.set(base + ['wins-server'], value=wins, replace=False)
config.delete(wins_base)
# Remove RADIUS server req-limit node
radius_base = base + ['authentication', 'radius']
if config.exists(radius_base):
for server in config.list_nodes(radius_base + ['server']):
if config.exists(radius_base + ['server', server, 'req-limit']):
config.delete(radius_base + ['server', server, 'req-limit'])
+ # Migrate IPv6 prefixes
+ ipv6_base = base + ['client-ipv6-pool']
+ if config.exists(ipv6_base + ['prefix']):
+ prefix_old = config.return_values(ipv6_base + ['prefix'])
+ # delete old prefix CLI nodes
+ config.delete(ipv6_base + ['prefix'])
+ # create ned prefix tag node
+ config.set(ipv6_base + ['prefix'])
+ config.set_tag(ipv6_base + ['prefix'])
+
+ for p in prefix_old:
+ prefix = p.split(',')[0]
+ mask = p.split(',')[1]
+ config.set(ipv6_base + ['prefix', prefix, 'mask'], value=mask)
+
+ if config.exists(ipv6_base + ['delegate-prefix']):
+ prefix_old = config.return_values(ipv6_base + ['delegate-prefix'])
+ # delete old delegate prefix CLI nodes
+ config.delete(ipv6_base + ['delegate-prefix'])
+ # create ned delegation tag node
+ config.set(ipv6_base + ['delegate '])
+ config.set_tag(ipv6_base + ['delegate '])
+
+ for p in prefix_old:
+ prefix = p.split(',')[0]
+ mask = p.split(',')[1]
+ config.set(ipv6_base + ['delegate', prefix, 'mask'], value=mask)
+
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)
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Nov 6, 9:26 AM (19 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4653900
Default Alt Text
(48 KB)
Attached To
Mode
rVYOSONEX vyos-1x
Attached
Detach File
Event Timeline
Log In to Comment