Page Menu
Home
VyOS Platform
Search
Configure Global Search
Log In
Files
F119063228
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
50 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/data/templates/accel-ppp/config_ip_pool.j2 b/data/templates/accel-ppp/config_ip_pool.j2
index 51fe67334..973bc0071 100644
--- a/data/templates/accel-ppp/config_ip_pool.j2
+++ b/data/templates/accel-ppp/config_ip_pool.j2
@@ -1,14 +1,14 @@
{% if client_ip_pool is defined and client_ip_pool is not none %}
[ip-pool]
-{% if local_ip is defined and local_ip is not none %}
-gw-ip-address={{ local_ip }}
+{% if gateway_address is defined and gateway_address is not none %}
+gw-ip-address={{ gateway_address }}
{% endif %}
{% if client_ip_pool.start is defined and client_ip_pool.stop is defined and client_ip_pool.start is not none and client_ip_pool.stop is not none %}
{{ client_ip_pool.start }}-{{ client_ip_pool.stop }}
-{% endif -%}
+{% endif %}
{% if client_ip_pool.subnet is defined and client_ip_pool.subnet is not none %}
{% for subnet in client_ip_pool.subnet %}
{{ subnet }}
{% endfor %}
{% endif %}
{% endif %}
diff --git a/data/templates/accel-ppp/pppoe.config.tmpl b/data/templates/accel-ppp/pppoe.config.tmpl
index acc7df0a2..8f1b9e7c5 100644
--- a/data/templates/accel-ppp/pppoe.config.tmpl
+++ b/data/templates/accel-ppp/pppoe.config.tmpl
@@ -1,174 +1,174 @@
### generated by accel_pppoe.py ###
[modules]
log_syslog
pppoe
{{ "radius" if authentication.mode is defined and authentication.mode == 'radius' }}
chap-secrets
ippool
{% if ppp_options.ipv6 is defined and ppp_options.ipv6 != 'deny' %}
ipv6pool
ipv6_nd
ipv6_dhcp
{% endif %}
{% for protocol in authentication.protocols %}
{# this should be fixed in the CLI by a migrator #}
{% if protocol == 'chap' %}
auth_chap_md5
{% elif protocol == 'mschap' %}
auth_mschap_v1
{% else %}
auth_{{ protocol.replace('-', '_') }}
{% endif %}
{% endfor %}
shaper
{% if snmp is defined %}
net-snmp
{% endif %}
{% if limits is defined %}
connlimit
{% endif %}
[core]
thread-count={{ thread_count }}
[log]
syslog=accel-pppoe,daemon
copy=1
level=5
{% if snmp is defined and snmp.master_agent is defined %}
[snmp]
master=1
{% endif %}
[client-ip-range]
disable
{# Common IP pool definitions #}
{% include 'accel-ppp/config_ip_pool.j2' %}
{# Common IPv6 pool definitions #}
{% include 'accel-ppp/config_ipv6_pool.j2' %}
{# Common DNS name-server definition #}
{% include 'accel-ppp/config_name_server.j2' %}
{% if wins_server is defined and wins_server is not none %}
[wins]
{% for server in wins_server %}
wins{{ loop.index }}={{ server }}
{% endfor %}
{% endif %}
{% if authentication.mode is defined and authentication.mode == 'local' %}
[chap-secrets]
chap-secrets={{ chap_secrets_file }}
{% elif authentication.mode is defined and authentication.mode == 'radius' %}
[radius]
verbose=1
{% for server, options in authentication.radius.server.items() if not options.disable is defined %}
server={{ server }},{{ options.key }},auth-port={{ options.port }},acct-port={{ options.acct_port }},req-limit=0,fail-time={{ options.fail_time }}
{% endfor %}
{% if authentication.radius.acct_interim_jitter is defined and authentication.radius.acct_interim_jitter is not none %}
acct-interim-jitter={{ authentication.radius.acct_interim_jitter }}
{% endif %}
acct-timeout={{ authentication.radius.acct_timeout }}
timeout={{ authentication.radius.timeout }}
max-try={{ authentication.radius.max_try }}
{% if authentication.radius.nas_identifier is defined and authentication.radius.nas_identifier is not none %}
nas-identifier={{ authentication.radius.nas_identifier }}
{% endif %}
{% if authentication.radius.nas_ip_address is defined and authentication.radius.nas_ip_address is not none %}
nas-ip-address={{ authentication.radius.nas_ip_address }}
{% endif %}
{% if authentication.radius.source_address is defined and authentication.radius.source_address is not none %}
bind={{ authentication.radius.source_address }}
{% endif %}
{% if authentication.radius.called_sid_format is defined and authentication.radius.called_sid_format is not none %}
called-sid={{ authentication.radius.called_sid_format }}
{% endif %}
{% if authentication.radius.dynamic_author.server is defined and authentication.radius.dynamic_author.server is not none %}
dae-server={{ authentication.radius.dynamic_author.server }}:{{ authentication.radius.dynamic_author.port }},{{ authentication.radius.dynamic_author.key }}
{% endif -%}
{% endif %}
-{% if local_ip is defined and local_ip is not none %}
-gw-ip-address={{ local_ip }}
+{% if gateway_address is defined and gateway_address is not none %}
+gw-ip-address={{ gateway_address }}
{% endif %}
{% if session_control is defined and session_control != 'disable' %}
[common]
single-session={{ session_control }}
{% endif %}
[ppp]
verbose=1
check-ip=1
ccp={{ "1" if ppp_options.ccp is defined else "0" }}
unit-preallocate={{ "1" if authentication.radius.preallocate_vif is defined else "0" }}
{% if ppp_options.min_mtu is defined and ppp_options.min_mtu is not none %}
min-mtu={{ ppp_options.min_mtu }}
{% else %}
min-mtu={{ mtu }}
{% endif %}
{% if ppp_options.mru is defined and ppp_options.mru is not none %}
mru={{ ppp_options.mru }}
{% endif %}
mppe={{ ppp_options.mppe }}
lcp-echo-interval={{ ppp_options.lcp_echo_interval }}
lcp-echo-timeout={{ ppp_options.lcp_echo_timeout }}
lcp-echo-failure={{ ppp_options.lcp_echo_failure }}
{% if ppp_options.ipv4 is defined and ppp_options.ipv4 is not none %}
ipv4={{ ppp_options.ipv4 }}
{% endif %}
{# IPv6 #}
{% if ppp_options.ipv6 is defined and ppp_options.ipv6 is not none %}
ipv6={{ ppp_options.ipv6 }}
{% if ppp_options.ipv6_intf_id is defined and ppp_options.ipv6_intf_id is not none %}
ipv6-intf-id={{ ppp_options.ipv6_intf_id }}
{% endif %}
{% if ppp_options.ipv6_peer_intf_id is defined and ppp_options.ipv6_peer_intf_id is not none %}
ipv6-peer-intf-id={{ ppp_options.ipv6_peer_intf_id }}
{% endif %}
ipv6-accept-peer-intf-id={{ "1" if ppp_options.ipv6_accept_peer_intf_id is defined else "0" }}
{% endif %}
{# MTU #}
mtu={{ mtu }}
[pppoe]
verbose=1
ac-name={{ access_concentrator }}
{% if interface %}
{% for iface in interface %}
interface={{ iface }}
{% if interface[iface].vlan_id is defined or interface[iface].vlan_range is defined %}
vlan-mon={{ iface }},{{ interface[iface].vlan_id | join(',') }},{{ interface[iface].vlan_range | join(',') }}
interface=re:{{ interface.name }}\.\d+
{% endif %}
{% endfor %}
{% endif %}
{% if service_name %}
service-name={{ service_name | join(',') }}
{% endif -%}
{% if pado_delay %}
pado-delay={{ pado_delay }}
{% endif %}
{% if limits is defined %}
[connlimit]
{% if limits.connection_limit is defined and limits.connection_limit is not none %}
limit={{ limits.connection_limit }}
{% endif %}
{% if limits.burst is defined and limits.burst %}
burst={{ limits.burst }}
{% endif %}
{% if limits.timeout is defined and limits.timeout is not none %}
timeout={{ limits.timeout }}
{% endif %}
{% endif %}
[cli]
tcp=127.0.0.1:2001
diff --git a/interface-definitions/service_pppoe-server.xml.in b/interface-definitions/service_pppoe-server.xml.in
index 3a9c25496..78bbda089 100644
--- a/interface-definitions/service_pppoe-server.xml.in
+++ b/interface-definitions/service_pppoe-server.xml.in
@@ -1,371 +1,364 @@
<?xml version="1.0"?>
<interfaceDefinition>
<node name="service">
<children>
<node name="pppoe-server" owner="${vyos_conf_scripts_dir}/service_pppoe-server.py">
<properties>
<help>Point to Point over Ethernet (PPPoE) Server</help>
<priority>900</priority>
</properties>
<children>
<leafNode name="access-concentrator">
<properties>
<help>Access concentrator name</help>
<constraint>
<regex>[a-zA-Z0-9]{1,100}</regex>
</constraint>
<constraintErrorMessage>access-concentrator name limited to alphanumerical characters only (max. 100)</constraintErrorMessage>
</properties>
<defaultValue>vyos-ac</defaultValue>
</leafNode>
<node name="authentication">
<properties>
<help>Authentication for remote access PPPoE Server</help>
</properties>
<children>
#include <include/accel-auth-local-users.xml.i>
#include <include/accel-auth-mode.xml.i>
#include <include/accel-auth-protocols.xml.i>
#include <include/radius-server.xml.i>
#include <include/accel-radius-additions.xml.i>
<node name="radius">
<children>
#include <include/accel-radius-additions-rate-limit.xml.i>
<leafNode name="called-sid-format">
<properties>
<help>Format of Called-Station-Id attribute</help>
<completionHelp>
<list>ifname ifname:mac</list>
</completionHelp>
<constraint>
<regex>(ifname|ifname:mac)</regex>
</constraint>
<constraintErrorMessage>Invalid Called-Station-Id format</constraintErrorMessage>
<valueHelp>
<format>ifname</format>
<description>NAS-Port-Id - should contain root interface name (NAS-Port-Id=eth1)</description>
</valueHelp>
<valueHelp>
<format>ifname:mac</format>
<description>NAS-Port-Id - should contain root interface name and mac address (NAS-Port-Id=eth1:00:00:00:00:00:00)</description>
</valueHelp>
</properties>
</leafNode>
</children>
</node>
</children>
</node>
<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</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>
#include <include/accel-client-subnet.xml.i>
</children>
</node>
#include <include/accel-client-ipv6-pool.xml.i>
#include <include/accel-name-server.xml.i>
<tagNode name="interface">
<properties>
<help>interface(s) to listen on</help>
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces.py</script>
</completionHelp>
</properties>
<children>
<leafNode name="vlan-id">
<properties>
<help>VLAN monitor for the automatic creation of vlans (user per vlan)</help>
<constraint>
<validator name="numeric" argument="--range 1-4096"/>
</constraint>
<constraintErrorMessage>VLAN ID needs to be between 1 and 4096</constraintErrorMessage>
<multi/>
</properties>
</leafNode>
<leafNode name="vlan-range">
<properties>
<help>VLAN monitor for the automatic creation of vlans (user per vlan)</help>
<constraint>
<regex>(409[0-6]|40[0-8][0-9]|[1-3][0-9]{3}|[1-9][0-9]{0,2})-(409[0-6]|40[0-8][0-9]|[1-3][0-9]{3}|[1-9][0-9]{0,2})</regex>
</constraint>
<multi/>
</properties>
</leafNode>
</children>
</tagNode>
- <leafNode name="local-ip">
- <properties>
- <help>local gateway address</help>
- <constraint>
- <validator name="ipv4-address"/>
- </constraint>
- </properties>
- </leafNode>
+ #include <include/accel-gateway-address.xml.i>
<leafNode name="mtu">
<properties>
<help>Maximum Transmission Unit (MTU) - default 1492</help>
<constraint>
<validator name="numeric" argument="--range 128-16384"/>
</constraint>
</properties>
<defaultValue>1492</defaultValue>
</leafNode>
<node name="limits">
<properties>
<help>Limits the connection rate from a single source</help>
</properties>
<children>
<leafNode name="connection-limit">
<properties>
<help>Acceptable rate of connections (e.g. 1/min, 60/sec)</help>
<constraint>
<regex>[0-9]+\/(min|sec)$</regex>
</constraint>
<constraintErrorMessage>illegal value</constraintErrorMessage>
</properties>
</leafNode>
<leafNode name="burst">
<properties>
<help>Burst count</help>
</properties>
</leafNode>
<leafNode name="timeout">
<properties>
<help>Timeout in seconds</help>
</properties>
</leafNode>
</children>
</node>
<leafNode name="service-name">
<properties>
<help>Service name</help>
<constraint>
<regex>[a-zA-Z0-9\-]{1,100}</regex>
</constraint>
<constraintErrorMessage>servicename can contain aplhanumerical characters and dashes only (max. 100)</constraintErrorMessage>
<multi/>
</properties>
</leafNode>
#include <include/accel-wins-server.xml.i>
<node name="ppp-options">
<properties>
<help>Advanced protocol options</help>
</properties>
<children>
<leafNode name="min-mtu">
<properties>
<help>Minimum acceptable MTU (68-65535)</help>
<constraint>
<validator name="numeric" argument="--range 68-65535"/>
</constraint>
</properties>
</leafNode>
<leafNode name="mru">
<properties>
<help>Preferred MRU (68-65535)</help>
<constraint>
<validator name="numeric" argument="--range 68-65535"/>
</constraint>
</properties>
</leafNode>
<leafNode name="ccp">
<properties>
<help>CCP negotiation (default disabled)</help>
<valueless />
</properties>
</leafNode>
#include <include/accel-ppp-mppe.xml.i>
#include <include/accel-lcp-echo-interval-failure.xml.i>
#include <include/accel-lcp-echo-timeout.xml.i>
<leafNode name="ipv4">
<properties>
<help>IPv4 (IPCP) negotiation algorithm</help>
<constraint>
<regex>(deny|allow|prefer|require)</regex>
</constraint>
<constraintErrorMessage>invalid value</constraintErrorMessage>
<valueHelp>
<format>deny</format>
<description>Do not negotiate IPv4</description>
</valueHelp>
<valueHelp>
<format>allow</format>
<description>Negotiate IPv4 only if client requests</description>
</valueHelp>
<valueHelp>
<format>prefer</format>
<description>Ask client for IPv4 negotiation, do not fail if it rejects</description>
</valueHelp>
<valueHelp>
<format>require</format>
<description>Require IPv4 negotiation</description>
</valueHelp>
<completionHelp>
<list>deny allow prefer require</list>
</completionHelp>
</properties>
</leafNode>
<leafNode name="ipv6">
<properties>
<help>IPv6 (IPCP6) negotiation algorithm</help>
<constraint>
<regex>(deny|allow|prefer|require)</regex>
</constraint>
<constraintErrorMessage>invalid value</constraintErrorMessage>
<valueHelp>
<format>deny</format>
<description>Do not negotiate IPv6</description>
</valueHelp>
<valueHelp>
<format>allow</format>
<description>Negotiate IPv6 only if client requests</description>
</valueHelp>
<valueHelp>
<format>prefer</format>
<description>Ask client for IPv6 negotiation, do not fail if it rejects</description>
</valueHelp>
<valueHelp>
<format>require</format>
<description>Require IPv6 negotiation</description>
</valueHelp>
<completionHelp>
<list>deny allow prefer require</list>
</completionHelp>
</properties>
</leafNode>
<leafNode name="ipv6-intf-id">
<properties>
<help>Fixed or random interface identifier for IPv6</help>
<completionHelp>
<list>random</list>
</completionHelp>
<valueHelp>
<format>random</format>
<description>Random interface identifier for IPv6</description>
</valueHelp>
<valueHelp>
<format>x:x:x:x</format>
<description>specify interface identifier for IPv6</description>
</valueHelp>
</properties>
</leafNode>
<leafNode name="ipv6-peer-intf-id">
<properties>
<help>Peer interface identifier for IPv6</help>
<completionHelp>
<list>random calling-sid ipv4</list>
</completionHelp>
<valueHelp>
<format>x:x:x:x</format>
<description>Interface identifier for IPv6</description>
</valueHelp>
<valueHelp>
<format>random</format>
<description>Use a random interface identifier for IPv6</description>
</valueHelp>
<valueHelp>
<format>ipv4</format>
<description>Calculate interface identifier from IPv4 address, for example 192:168:0:1</description>
</valueHelp>
<valueHelp>
<format>calling-sid</format>
<description>Calculate interface identifier from calling-station-id</description>
</valueHelp>
</properties>
</leafNode>
<leafNode name="ipv6-accept-peer-intf-id">
<properties>
<help>Accept peer interface identifier</help>
<valueless />
</properties>
</leafNode>
</children>
</node>
<tagNode name="pado-delay">
<properties>
<help>PADO delays</help>
<valueHelp>
<format>1-999999</format>
<description>Number in ms</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 1-999999"/>
</constraint>
<constraintErrorMessage>Invalid PADO delay</constraintErrorMessage>
</properties>
<children>
<leafNode name="sessions">
<properties>
<help>Number of sessions</help>
<valueHelp>
<format>1-999999</format>
<description>Number of sessions</description>
</valueHelp>
<constraint>
<validator name="numeric" argument="--range 1-999999"/>
</constraint>
<constraintErrorMessage>Invalid number of delayed sessions</constraintErrorMessage>
</properties>
</leafNode>
</children>
</tagNode>
<leafNode name="session-control">
<properties>
<help>control sessions count</help>
<constraint>
<regex>^(deny|disable|replace)$</regex>
</constraint>
<constraintErrorMessage>Invalid value</constraintErrorMessage>
<valueHelp>
<format>disable</format>
<description>Disables session control</description>
</valueHelp>
<valueHelp>
<format>deny</format>
<description>Deny second session authorization</description>
</valueHelp>
<valueHelp>
<format>replace</format>
<description>Terminate first session when second is authorized</description>
</valueHelp>
<completionHelp>
<list>deny disable replace</list>
</completionHelp>
</properties>
<defaultValue>replace</defaultValue>
</leafNode>
<node name="snmp">
<properties>
<help>Enable SNMP</help>
</properties>
<children>
<leafNode name="master-agent">
<properties>
<help>enable SNMP master agent mode</help>
<valueless />
</properties>
</leafNode>
</children>
</node>
</children>
</node>
</children>
</node>
</interfaceDefinition>
diff --git a/smoketest/scripts/cli/base_accel_ppp_test.py b/smoketest/scripts/cli/base_accel_ppp_test.py
index 94834ad4c..cf401b0d8 100644
--- a/smoketest/scripts/cli/base_accel_ppp_test.py
+++ b/smoketest/scripts/cli/base_accel_ppp_test.py
@@ -1,175 +1,177 @@
# 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/>.
import os
import re
import unittest
from configparser import ConfigParser
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
from vyos.util import cmd
from vyos.util import get_half_cpus
from vyos.util import process_named_running
from vyos.validate import is_ipv4
class BasicAccelPPPTest:
class BaseTest(unittest.TestCase):
def setUp(self):
self.session = ConfigSession(os.getpid())
+ self._gateway = '192.0.2.1'
+
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
self.session.delete(self._base_path)
def tearDown(self):
self.session.delete(self._base_path)
self.session.commit()
del self.session
def set(self, path):
self.session.set(self._base_path + path)
def basic_config(self):
# PPPoE local auth mode requires local users to be configured!
self.set(['authentication', 'local-users', 'username', 'vyos', 'password', 'vyos'])
self.set(['authentication', 'mode', 'local'])
-
+ self.set(['gateway-address', self._gateway])
def verify(self, conf):
self.assertEqual(conf['core']['thread-count'], str(get_half_cpus()))
def test_name_servers(self):
""" Verify proper Name-Server configuration for IPv4 and IPv6 """
self.basic_config()
nameserver = ['192.0.2.1', '192.0.2.2', '2001:db8::1']
for ns in nameserver:
self.set(['name-server', ns])
# commit changes
self.session.commit()
# Validate configuration values
conf = ConfigParser(allow_no_value=True, delimiters='=')
conf.read(self._config_file)
# IPv4 and IPv6 nameservers must be checked individually
for ns in nameserver:
if is_ipv4(ns):
self.assertIn(ns, [conf['dns']['dns1'], conf['dns']['dns2']])
else:
self.assertEqual(conf['ipv6-dns'][ns], None)
def test_authentication_local(self):
""" Test configuration of local authentication """
self.basic_config()
# upload / download limit
user = 'test'
password = 'test2'
static_ip = '100.100.100.101'
upload = '5000'
download = '10000'
self.set(['authentication', 'local-users', 'username', user, 'password', password])
self.set(['authentication', 'local-users', 'username', user, 'static-ip', static_ip])
self.set(['authentication', 'local-users', 'username', user, 'rate-limit', 'upload', upload])
# upload rate-limit requires also download rate-limit
with self.assertRaises(ConfigSessionError):
self.session.commit()
self.set(['authentication', 'local-users', 'username', user, 'rate-limit', 'download', download])
# commit changes
self.session.commit()
# Validate configuration values
conf = ConfigParser(allow_no_value=True, delimiters='=')
conf.read(self._config_file)
# check proper path to chap-secrets file
self.assertEqual(conf['chap-secrets']['chap-secrets'], self._chap_secrets)
# basic verification
self.verify(conf)
# check local users
tmp = cmd(f'sudo cat {self._chap_secrets}')
regex = f'{user}\s+\*\s+{password}\s+{static_ip}\s+{download}/{upload}'
tmp = re.findall(regex, tmp)
self.assertTrue(tmp)
# Check for running process
self.assertTrue(process_named_running(self._process_name))
def test_authentication_radius(self):
""" Test configuration of RADIUS authentication for PPPoE server """
self.basic_config()
radius_server = '192.0.2.22'
radius_key = 'secretVyOS'
radius_port = '2000'
radius_port_acc = '3000'
self.set(['authentication', 'mode', 'radius'])
self.set(['authentication', 'radius', 'server', radius_server, 'key', radius_key])
self.set(['authentication', 'radius', 'server', radius_server, 'port', radius_port])
self.set(['authentication', 'radius', 'server', radius_server, 'acct-port', radius_port_acc])
coa_server = '4.4.4.4'
coa_key = 'testCoA'
self.set(['authentication', 'radius', 'dynamic-author', 'server', coa_server])
self.set(['authentication', 'radius', 'dynamic-author', 'key', coa_key])
nas_id = 'VyOS-PPPoE'
nas_ip = '7.7.7.7'
self.set(['authentication', 'radius', 'nas-identifier', nas_id])
self.set(['authentication', 'radius', 'nas-ip-address', nas_ip])
source_address = '1.2.3.4'
self.set(['authentication', 'radius', 'source-address', source_address])
# commit changes
self.session.commit()
# Validate configuration values
conf = ConfigParser(allow_no_value=True, delimiters='=')
conf.read(self._config_file)
# basic verification
self.verify(conf)
# check auth
self.assertTrue(conf['radius'].getboolean('verbose'))
self.assertEqual(conf['radius']['acct-timeout'], '3')
self.assertEqual(conf['radius']['timeout'], '3')
self.assertEqual(conf['radius']['max-try'], '3')
self.assertEqual(conf['radius']['dae-server'], f'{coa_server}:1700,{coa_key}')
self.assertEqual(conf['radius']['nas-identifier'], nas_id)
self.assertEqual(conf['radius']['nas-ip-address'], nas_ip)
self.assertEqual(conf['radius']['bind'], source_address)
server = conf['radius']['server'].split(',')
self.assertEqual(radius_server, server[0])
self.assertEqual(radius_key, server[1])
self.assertEqual(f'auth-port={radius_port}', server[2])
self.assertEqual(f'acct-port={radius_port_acc}', server[3])
self.assertEqual(f'req-limit=0', server[4])
self.assertEqual(f'fail-time=0', server[5])
# Check for running process
self.assertTrue(process_named_running(self._process_name))
diff --git a/smoketest/scripts/cli/test_service_pppoe-server.py b/smoketest/scripts/cli/test_service_pppoe-server.py
index dea8d838e..8db002b57 100755
--- a/smoketest/scripts/cli/test_service_pppoe-server.py
+++ b/smoketest/scripts/cli/test_service_pppoe-server.py
@@ -1,235 +1,233 @@
#!/usr/bin/env python3
#
# Copyright (C) 020 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 unittest
from base_accel_ppp_test import BasicAccelPPPTest
from configparser import ConfigParser
from vyos.configsession import ConfigSessionError
from vyos.util import process_named_running
from vyos.util import cmd
local_if = ['interfaces', 'dummy', 'dum667']
ac_name = 'ACN'
-gateway = '192.0.2.1'
interface = 'eth0'
class TestServicePPPoEServer(BasicAccelPPPTest.BaseTest):
def setUp(self):
self._base_path = ['service', 'pppoe-server']
self._process_name = 'accel-pppd'
self._config_file = '/run/accel-pppd/pppoe.conf'
self._chap_secrets = '/run/accel-pppd/pppoe.chap-secrets'
super().setUp()
def tearDown(self):
self.session.delete(local_if)
super().tearDown()
def verify(self, conf):
mtu = '1492'
# validate some common values in the configuration
for tmp in ['log_syslog', 'pppoe', 'chap-secrets', 'ippool',
'auth_mschap_v2', 'auth_mschap_v1', 'auth_chap_md5',
'auth_pap', 'shaper']:
# Settings without values provide None
self.assertEqual(conf['modules'][tmp], None)
# check Access Concentrator setting
self.assertTrue(conf['pppoe']['ac-name'] == ac_name)
self.assertTrue(conf['pppoe'].getboolean('verbose'))
self.assertTrue(conf['pppoe']['interface'], interface)
# check ppp
self.assertTrue(conf['ppp'].getboolean('verbose'))
self.assertTrue(conf['ppp'].getboolean('check-ip'))
self.assertEqual(conf['ppp']['mtu'], mtu)
self.assertEqual(conf['ppp']['lcp-echo-interval'], '30')
self.assertEqual(conf['ppp']['lcp-echo-timeout'], '0')
self.assertEqual(conf['ppp']['lcp-echo-failure'], '3')
super().verify(conf)
def basic_config(self):
self.session.set(local_if + ['address', '192.0.2.1/32'])
self.set(['access-concentrator', ac_name])
self.set(['interface', interface])
- self.set(['local-ip', gateway])
super().basic_config()
def test_ppp_options(self):
""" Test configuration of local authentication for PPPoE server """
self.basic_config()
# other settings
mppe = 'require'
self.set(['ppp-options', 'ccp'])
self.set(['ppp-options', 'mppe', mppe])
self.set(['limits', 'connection-limit', '20/min'])
# min-mtu
min_mtu = '1400'
self.set(['ppp-options', 'min-mtu', min_mtu])
# mru
mru = '9000'
self.set(['ppp-options', 'mru', mru])
# commit changes
self.session.commit()
# Validate configuration values
conf = ConfigParser(allow_no_value=True, delimiters='=')
conf.read(self._config_file)
# basic verification
self.verify(conf)
- self.assertEqual(conf['chap-secrets']['gw-ip-address'], gateway)
+ self.assertEqual(conf['chap-secrets']['gw-ip-address'], self._gateway)
# check ppp
self.assertEqual(conf['ppp']['mppe'], mppe)
self.assertEqual(conf['ppp']['min-mtu'], min_mtu)
self.assertEqual(conf['ppp']['mru'], mru)
self.assertTrue(conf['ppp'].getboolean('ccp'))
# check other settings
self.assertEqual(conf['connlimit']['limit'], '20/min')
# Check for running process
self.assertTrue(process_named_running(self._process_name))
def test_authentication_protocols(self):
""" Test configuration of local authentication for PPPoE server """
self.basic_config()
# explicitly test mschap-v2 - no special reason
self.set( ['authentication', 'protocols', 'mschap-v2'])
# commit changes
self.session.commit()
# Validate configuration values
conf = ConfigParser(allow_no_value=True)
conf.read(self._config_file)
self.assertEqual(conf['modules']['auth_mschap_v2'], None)
# Check for running process
self.assertTrue(process_named_running(self._process_name))
def test_client_ip_pool(self):
""" Test configuration of IPv6 client pools """
self.basic_config()
subnet = '172.18.0.0/24'
self.set(['client-ip-pool', 'subnet', subnet])
start = '192.0.2.10'
stop = '192.0.2.20'
start_stop = f'{start}-{stop}'
self.set(['client-ip-pool', 'start', start])
self.set(['client-ip-pool', 'stop', stop])
# commit changes
self.session.commit()
# Validate configuration values
conf = ConfigParser(allow_no_value=True)
conf.read(self._config_file)
# check configured subnet
self.assertEqual(conf['ip-pool'][subnet], None)
self.assertEqual(conf['ip-pool'][start_stop], None)
- self.assertEqual(conf['ip-pool']['gw-ip-address'], gateway)
+ self.assertEqual(conf['ip-pool']['gw-ip-address'], self._gateway)
# Check for running process
self.assertTrue(process_named_running(self._process_name))
def test_client_ipv6_pool(self):
""" Test configuration of IPv6 client pools """
self.basic_config()
# Enable IPv6
allow_ipv6 = 'allow'
random = 'random'
self.set(['ppp-options', 'ipv6', allow_ipv6])
self.set(['ppp-options', 'ipv6-intf-id', random])
self.set(['ppp-options', 'ipv6-accept-peer-intf-id'])
self.set(['ppp-options', 'ipv6-peer-intf-id', random])
prefix = '2001:db8:ffff::/64'
prefix_mask = '128'
client_prefix = f'{prefix},{prefix_mask}'
self.set(['client-ipv6-pool', 'prefix', prefix, 'mask', prefix_mask])
delegate_prefix = '2001:db8::/40'
delegate_mask = '56'
self.set(['client-ipv6-pool', 'delegate', delegate_prefix, 'delegation-prefix', delegate_mask])
# commit changes
self.session.commit()
# Validate configuration values
conf = ConfigParser(allow_no_value=True, delimiters='=')
conf.read(self._config_file)
for tmp in ['ipv6pool', 'ipv6_nd', 'ipv6_dhcp']:
self.assertEqual(conf['modules'][tmp], None)
self.assertEqual(conf['ppp']['ipv6'], allow_ipv6)
self.assertEqual(conf['ppp']['ipv6-intf-id'], random)
self.assertEqual(conf['ppp']['ipv6-peer-intf-id'], random)
self.assertTrue(conf['ppp'].getboolean('ipv6-accept-peer-intf-id'))
self.assertEqual(conf['ipv6-pool'][client_prefix], None)
self.assertEqual(conf['ipv6-pool']['delegate'], f'{delegate_prefix},{delegate_mask}')
# Check for running process
self.assertTrue(process_named_running(self._process_name))
def test_authentication_radius(self):
radius_called_sid = 'ifname:mac'
radius_acct_interim_jitter = '9'
self.set(['authentication', 'radius', 'called-sid-format', radius_called_sid])
self.set(['authentication', 'radius', 'acct-interim-jitter', radius_acct_interim_jitter])
# run common tests
super().test_authentication_radius()
# Validate configuration values
conf = ConfigParser(allow_no_value=True, delimiters='=')
conf.read(self._config_file)
# Validate configuration
self.assertEqual(conf['radius']['called-sid'], radius_called_sid)
self.assertEqual(conf['radius']['acct-interim-jitter'], radius_acct_interim_jitter)
if __name__ == '__main__':
unittest.main()
diff --git a/smoketest/scripts/cli/test_vpn_sstp.py b/smoketest/scripts/cli/test_vpn_sstp.py
index 03ed23495..83be4c248 100755
--- a/smoketest/scripts/cli/test_vpn_sstp.py
+++ b/smoketest/scripts/cli/test_vpn_sstp.py
@@ -1,65 +1,63 @@
#!/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/>.
import unittest
from base_accel_ppp_test import BasicAccelPPPTest
from vyos.util import cmd
process_name = 'accel-pppd'
ca_cert = '/tmp/ca.crt'
ssl_cert = '/tmp/server.crt'
ssl_key = '/tmp/server.key'
class TestVPNSSTPServer(BasicAccelPPPTest.BaseTest):
def setUp(self):
self._base_path = ['vpn', 'sstp']
self._process_name = 'accel-pppd'
self._config_file = '/run/accel-pppd/sstp.conf'
self._chap_secrets = '/run/accel-pppd/sstp.chap-secrets'
super().setUp()
def tearDown(self):
super().tearDown()
def basic_config(self):
# SSL is mandatory
self.set(['ssl', 'ca-cert-file', ca_cert])
self.set(['ssl', 'cert-file', ssl_cert])
self.set(['ssl', 'key-file', ssl_key])
-
self.set(['client-ip-pool', 'subnet', '192.0.2.0/24'])
- self.set(['gateway-address', '1.1.1.1'])
super().basic_config()
if __name__ == '__main__':
# Our SSL certificates need a subject ...
subject = '/C=DE/ST=BY/O=VyOS/localityName=Cloud/commonName=vyos/' \
'organizationalUnitName=VyOS/emailAddress=maintainers@vyos.io/'
# Generate mandatory SSL certificate
tmp = f'openssl req -newkey rsa:4096 -new -nodes -x509 -days 3650 '\
f'-keyout {ssl_key} -out {ssl_cert} -subj {subject}'
cmd(tmp)
# Generate "CA"
tmp = f'openssl req -new -x509 -key {ssl_key} -out {ca_cert} '\
f'-subj {subject}'
cmd(tmp)
unittest.main()
diff --git a/src/conf_mode/service_pppoe-server.py b/src/conf_mode/service_pppoe-server.py
index 8ed8c6812..445311391 100755
--- a/src/conf_mode/service_pppoe-server.py
+++ b/src/conf_mode/service_pppoe-server.py
@@ -1,194 +1,194 @@
#!/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 os
from sys import exit
from vyos.config import Config
from vyos.configdict import dict_merge
from vyos.validate import is_ipv4
from vyos.template import render
from vyos.util import call
from vyos.util import get_half_cpus
from vyos.util import vyos_dict_search
from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
pppoe_conf = r'/run/accel-pppd/pppoe.conf'
pppoe_chap_secrets = r'/run/accel-pppd/pppoe.chap-secrets'
def get_config(config=None):
if config:
conf = config
else:
conf = Config()
base = ['service', 'pppoe-server']
if not conf.exists(base):
return None
pppoe = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=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)
# defaults include RADIUS server specifics per TAG node which need to be
# added to individual RADIUS servers instead - so we can simply delete them
if vyos_dict_search('authentication.radius.server', default_values):
del default_values['authentication']['radius']['server']
# defaults include static-ip address per TAG node which need to be added to
# individual local users instead - so we can simply delete them
if vyos_dict_search('authentication.local_users.username', default_values):
del default_values['authentication']['local_users']['username']
pppoe = dict_merge(default_values, pppoe)
# set CPUs cores to process requests
pppoe.update({'thread_count' : get_half_cpus()})
# we need to store the path to the secrets file
pppoe.update({'chap_secrets_file' : pppoe_chap_secrets})
# We can only have two IPv4 and three IPv6 nameservers - also they are
# configured in a different way in the configuration, this is why we split
# the configuration
if 'name_server' in pppoe:
ns_v4 = []
ns_v6 = []
for ns in pppoe['name_server']:
if is_ipv4(ns): ns_v4.append(ns)
else: ns_v6.append(ns)
pppoe.update({'name_server_ipv4' : ns_v4, 'name_server_ipv6' : ns_v6})
del pppoe['name_server']
# Add individual RADIUS server default values
if vyos_dict_search('authentication.radius.server', pppoe):
default_values = defaults(base + ['authentication', 'radius', 'server'])
for server in vyos_dict_search('authentication.radius.server', pppoe):
pppoe['authentication']['radius']['server'][server] = dict_merge(
default_values, pppoe['authentication']['radius']['server'][server])
# Add individual local-user default values
if vyos_dict_search('authentication.local_users.username', pppoe):
default_values = defaults(base + ['authentication', 'local_users', 'username'])
for username in vyos_dict_search('authentication.local_users.username', pppoe):
pppoe['authentication']['local_users']['username'][username] = dict_merge(
default_values, pppoe['authentication']['local_users']['username'][username])
return pppoe
def verify(pppoe):
if not pppoe:
return None
# vertify auth settings
if vyos_dict_search('authentication.mode', pppoe) == 'local':
if not vyos_dict_search('authentication.local_users', pppoe):
raise ConfigError('PPPoE local auth mode requires local users to be configured!')
for user in vyos_dict_search('authentication.local_users.username', pppoe):
user_config = pppoe['authentication']['local_users']['username'][user]
if 'password' not in user_config:
raise ConfigError(f'Password required for local user "{user}"')
if 'rate_limit' in user_config:
# if up/download is set, check that both have a value
if not {'upload', 'download'} <= set(user_config['rate_limit']):
raise ConfigError(f'User "{user}" has rate-limit configured for only one ' \
'direction but both upload and download must be given!')
elif vyos_dict_search('authentication.mode', pppoe) == 'radius':
if not vyos_dict_search('authentication.radius.server', pppoe):
raise ConfigError('RADIUS authentication requires at least one server')
for server in vyos_dict_search('authentication.radius.server', pppoe):
radius_config = pppoe['authentication']['radius']['server'][server]
if 'key' not in radius_config:
raise ConfigError(f'Missing RADIUS secret key for server "{server}"')
if 'wins_server' in pppoe and len(pppoe['wins_server']) > 2:
raise ConfigError('Not more then two IPv4 WINS name-servers can be configured')
if 'name_server_ipv4' in pppoe:
if len(pppoe['name_server_ipv4']) > 2:
raise ConfigError('Not more then two IPv4 DNS name-servers ' \
'can be configured')
if 'name_server_ipv6' in pppoe:
if len(pppoe['name_server_ipv6']) > 3:
raise ConfigError('Not more then three IPv6 DNS name-servers ' \
'can be configured')
if 'interface' not in pppoe:
raise ConfigError('At least one listen interface must be defined!')
- if 'local_ip' not in pppoe:
- raise ConfigError('PPPoE server requires local-ip to be configured!')
+ if 'gateway_address' not in pppoe:
+ raise ConfigError('PPPoE server requires gateway-address to be configured!')
# local ippool and gateway settings config checks
if not (vyos_dict_search('client_ip_pool.subnet', pppoe) or
(vyos_dict_search('client_ip_pool.start', pppoe) and
vyos_dict_search('client_ip_pool.stop', pppoe))):
print('Warning: No PPPoE client pool defined')
if vyos_dict_search('authentication.radius.dynamic_author.server', pppoe):
if not vyos_dict_search('authentication.radius.dynamic_author.key', pppoe):
raise ConfigError('DA/CoE server key required!')
return None
def generate(pppoe):
if not pppoe:
return None
render(pppoe_conf, 'accel-ppp/pppoe.config.tmpl', pppoe, trim_blocks=True)
if vyos_dict_search('authentication.mode', pppoe) == 'local':
render(pppoe_chap_secrets, 'accel-ppp/chap-secrets.pppoe.tmpl', pppoe, trim_blocks=True, permission=0o640)
else:
if os.path.exists(pppoe_chap_secrets):
os.unlink(pppoe_chap_secrets)
return None
def apply(pppoe):
if not pppoe:
call('systemctl stop accel-ppp@pppoe.service')
for file in [pppoe_conf, pppoe_chap_secrets]:
if os.path.exists(file):
os.unlink(file)
return None
call('systemctl restart accel-ppp@pppoe.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/pppoe-server/4-to-5 b/src/migration-scripts/pppoe-server/4-to-5
new file mode 100755
index 000000000..05e9c17d6
--- /dev/null
+++ b/src/migration-scripts/pppoe-server/4-to-5
@@ -0,0 +1,49 @@
+#!/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/>.
+
+# - rename local-ip to gateway-address
+
+from vyos.configtree import ConfigTree
+from sys import argv
+from sys import exit
+
+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_path = ['service', 'pppoe-server']
+if not config.exists(base_path):
+ # Nothing to do
+ exit(0)
+else:
+ config_gw = base_path + ['local-ip']
+ if config.exists(config_gw):
+ config.rename(config_gw, 'gateway-address')
+ config.delete(config_gw)
+
+ 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, 8:14 AM (1 d, 21 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4644988
Default Alt Text
(50 KB)
Attached To
Mode
rVYOSONEX vyos-1x
Attached
Detach File
Event Timeline
Log In to Comment