Page MenuHomeVyOS Platform

No OneTemporary

Size
50 KB
Referenced Files
None
Subscribers
None
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

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)

Event Timeline