summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/templates/accel-ppp/ipoe.config.j28
-rw-r--r--data/templates/ntp/ntpd.conf.j213
-rw-r--r--debian/vyos-1x-smoketest.install1
-rw-r--r--interface-definitions/dns-forwarding.xml.in12
-rw-r--r--interface-definitions/include/generic-interface-multi.xml.i2
-rw-r--r--interface-definitions/include/generic-interface.xml.i2
-rw-r--r--interface-definitions/ntp.xml.in1
-rw-r--r--interface-definitions/service-ipoe-server.xml.in5
-rwxr-xr-xsmoketest/bin/vyos-configtest-pki100
-rw-r--r--smoketest/configs/dialup-router-medium-vpn1
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_bridge.py74
-rwxr-xr-xsmoketest/scripts/cli/test_system_ntp.py17
-rwxr-xr-xsrc/conf_mode/dns_forwarding.py3
-rwxr-xr-xsrc/conf_mode/ntp.py20
-rwxr-xr-xsrc/conf_mode/service_ipoe-server.py14
-rwxr-xr-xsrc/system/vyos-event-handler.py10
-rw-r--r--src/systemd/dhclient@.service2
17 files changed, 270 insertions, 15 deletions
diff --git a/data/templates/accel-ppp/ipoe.config.j2 b/data/templates/accel-ppp/ipoe.config.j2
index 3c0d47b27..6df12db2c 100644
--- a/data/templates/accel-ppp/ipoe.config.j2
+++ b/data/templates/accel-ppp/ipoe.config.j2
@@ -128,10 +128,16 @@ bind={{ radius_source_address }}
{% if radius_dynamic_author %}
dae-server={{ radius_dynamic_author.server }}:{{ radius_dynamic_author.port }},{{ radius_dynamic_author.key }}
{% endif %}
-{% if radius_shaper_attr %}
+
+{% if radius_shaper_enable %}
[shaper]
verbose=1
+{% if radius_shaper_attr %}
attr={{ radius_shaper_attr }}
+{% endif %}
+{% if radius_shaper_multiplier %}
+rate-multiplier={{ radius_shaper_multiplier }}
+{% endif %}
{% if radius_shaper_vendor %}
vendor={{ radius_shaper_vendor }}
{% endif %}
diff --git a/data/templates/ntp/ntpd.conf.j2 b/data/templates/ntp/ntpd.conf.j2
index da610051e..8921826fa 100644
--- a/data/templates/ntp/ntpd.conf.j2
+++ b/data/templates/ntp/ntpd.conf.j2
@@ -33,10 +33,17 @@ restrict {{ address | address_from_cidr }} mask {{ address | netmask_from_cidr }
{% endfor %}
{% endif %}
-{% if listen_address %}
+{% if listen_address is vyos_defined or interface is vyos_defined %}
# NTP should listen on configured addresses only
interface ignore wildcard
-{% for address in listen_address %}
+{% if listen_address is vyos_defined %}
+{% for address in listen_address %}
interface listen {{ address }}
-{% endfor %}
+{% endfor %}
+{% endif %}
+{% if interface is vyos_defined %}
+{% for ifname in interface %}
+interface listen {{ ifname }}
+{% endfor %}
+{% endif %}
{% endif %}
diff --git a/debian/vyos-1x-smoketest.install b/debian/vyos-1x-smoketest.install
index 3739763b9..406fef4be 100644
--- a/debian/vyos-1x-smoketest.install
+++ b/debian/vyos-1x-smoketest.install
@@ -1,4 +1,5 @@
usr/bin/vyos-smoketest
usr/bin/vyos-configtest
+usr/bin/vyos-configtest-pki
usr/libexec/vyos/tests/smoke
usr/libexec/vyos/tests/config
diff --git a/interface-definitions/dns-forwarding.xml.in b/interface-definitions/dns-forwarding.xml.in
index 12dc11de5..baff4a841 100644
--- a/interface-definitions/dns-forwarding.xml.in
+++ b/interface-definitions/dns-forwarding.xml.in
@@ -133,8 +133,12 @@
<format>@</format>
<description>Root record</description>
</valueHelp>
+ <valueHelp>
+ <format>any</format>
+ <description>Wildcard record (any subdomain)</description>
+ </valueHelp>
<constraint>
- <regex>([-_a-zA-Z0-9.]{1,63}|@)(?&lt;!\.)</regex>
+ <regex>([-_a-zA-Z0-9.]{1,63}|@|any)(?&lt;!\.)</regex>
</constraint>
</properties>
<children>
@@ -166,8 +170,12 @@
<format>@</format>
<description>Root record</description>
</valueHelp>
+ <valueHelp>
+ <format>any</format>
+ <description>Wildcard record (any subdomain)</description>
+ </valueHelp>
<constraint>
- <regex>([-_a-zA-Z0-9.]{1,63}|@)(?&lt;!\.)</regex>
+ <regex>([-_a-zA-Z0-9.]{1,63}|@|any)(?&lt;!\.)</regex>
</constraint>
</properties>
<children>
diff --git a/interface-definitions/include/generic-interface-multi.xml.i b/interface-definitions/include/generic-interface-multi.xml.i
index 44e87775c..65aae28ae 100644
--- a/interface-definitions/include/generic-interface-multi.xml.i
+++ b/interface-definitions/include/generic-interface-multi.xml.i
@@ -1,7 +1,7 @@
<!-- include start from generic-interface-multi.xml.i -->
<leafNode name="interface">
<properties>
- <help>Interface Name to use</help>
+ <help>Interface to use</help>
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces.py</script>
</completionHelp>
diff --git a/interface-definitions/include/generic-interface.xml.i b/interface-definitions/include/generic-interface.xml.i
index 50af718a5..8b4cf1d65 100644
--- a/interface-definitions/include/generic-interface.xml.i
+++ b/interface-definitions/include/generic-interface.xml.i
@@ -1,7 +1,7 @@
<!-- include start from generic-interface.xml.i -->
<leafNode name="interface">
<properties>
- <help>Interface Name to use</help>
+ <help>Interface to use</help>
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces.py</script>
</completionHelp>
diff --git a/interface-definitions/ntp.xml.in b/interface-definitions/ntp.xml.in
index a518a9def..85636a50f 100644
--- a/interface-definitions/ntp.xml.in
+++ b/interface-definitions/ntp.xml.in
@@ -81,6 +81,7 @@
</leafNode>
</children>
</node>
+ #include <include/generic-interface-multi.xml.i>
#include <include/listen-address.xml.i>
#include <include/interface/vrf.xml.i>
</children>
diff --git a/interface-definitions/service-ipoe-server.xml.in b/interface-definitions/service-ipoe-server.xml.in
index e222467b1..cd3aa3638 100644
--- a/interface-definitions/service-ipoe-server.xml.in
+++ b/interface-definitions/service-ipoe-server.xml.in
@@ -213,6 +213,11 @@
</tagNode>
</children>
</tagNode>
+ <node name="radius">
+ <children>
+ #include <include/accel-ppp/radius-additions-rate-limit.xml.i>
+ </children>
+ </node>
#include <include/radius-server-ipv4.xml.i>
#include <include/accel-ppp/radius-additions.xml.i>
</children>
diff --git a/smoketest/bin/vyos-configtest-pki b/smoketest/bin/vyos-configtest-pki
new file mode 100755
index 000000000..2f8af0e61
--- /dev/null
+++ b/smoketest/bin/vyos-configtest-pki
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2022, 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/>.
+
+from os import system
+from vyos.pki import create_private_key
+from vyos.pki import create_certificate_request
+from vyos.pki import create_certificate
+from vyos.pki import create_certificate_revocation_list
+from vyos.pki import create_dh_parameters
+from vyos.pki import encode_certificate
+from vyos.pki import encode_dh_parameters
+from vyos.pki import encode_private_key
+
+subject = {'country': 'DE', 'state': 'BY', 'locality': 'Cloud', 'organization': 'VyOS', 'common_name': 'vyos'}
+ca_subject = {'country': 'DE', 'state': 'BY', 'locality': 'Cloud', 'organization': 'VyOS', 'common_name': 'vyos CA'}
+subca_subject = {'country': 'DE', 'state': 'BY', 'locality': 'Cloud', 'organization': 'VyOS', 'common_name': 'vyos SubCA'}
+
+ca_cert = '/config/auth/ovpn_test_ca.pem'
+ca_key = '/config/auth/ovpn_test_ca.key'
+ca_cert_chain = '/config/auth/ovpn_test_chain.pem'
+ca_crl = '/config/auth/ovpn_test_ca.crl'
+subca_cert = '/config/auth/ovpn_test_subca.pem'
+subca_csr = '/tmp/subca.csr'
+subca_key = '/config/auth/ovpn_test_subca.key'
+ssl_cert = '/config/auth/ovpn_test_server.pem'
+ssl_key = '/config/auth/ovpn_test_server.key'
+dh_pem = '/config/auth/ovpn_test_dh.pem'
+s2s_key = '/config/auth/ovpn_test_site2site.key'
+auth_key = '/config/auth/ovpn_test_tls_auth.key'
+
+def create_cert(subject, cert_path, key_path, sign_by=None, sign_by_key=None, ca=False, sub_ca=False):
+ priv_key = create_private_key('rsa', 2048)
+ cert_req = create_certificate_request(subject, priv_key)
+ cert = create_certificate(
+ cert_req,
+ sign_by if sign_by else cert_req,
+ sign_by_key if sign_by_key else priv_key,
+ is_ca=ca, is_sub_ca=sub_ca)
+
+ with open(cert_path, 'w') as f:
+ f.write(encode_certificate(cert))
+
+ with open(key_path, 'w') as f:
+ f.write(encode_private_key(priv_key))
+
+ return cert, priv_key
+
+def create_empty_crl(crl_path, sign_by, sign_by_key):
+ crl = create_certificate_revocation_list(sign_by, sign_by_key, [1])
+
+ with open(crl_path, 'w') as f:
+ f.write(encode_certificate(crl))
+
+ return crl
+
+if __name__ == '__main__':
+ # Create Root CA
+ ca_cert_obj, ca_key_obj = create_cert(ca_subject, ca_cert, ca_key, ca=True)
+
+ # Create Empty CRL
+ create_empty_crl(ca_crl, ca_cert_obj, ca_key_obj)
+
+ # Create Intermediate CA
+ subca_cert_obj, subca_key_obj = create_cert(
+ subca_subject, subca_cert, subca_key,
+ sign_by=ca_cert_obj, sign_by_key=ca_key_obj,
+ ca=True, sub_ca=True)
+
+ # Create Chain
+ with open(ca_cert_chain, 'w') as f:
+ f.write(encode_certificate(subca_cert_obj) + "\n")
+ f.write(encode_certificate(ca_cert_obj) + "\n")
+
+ # Create Server Cert
+ create_cert(subject, ssl_cert, ssl_key, sign_by=subca_cert_obj, sign_by_key=subca_key_obj)
+
+ # Create DH params
+ dh_params = create_dh_parameters()
+
+ with open(dh_pem, 'w') as f:
+ f.write(encode_dh_parameters(dh_params))
+
+ # OpenVPN S2S Key
+ system(f'openvpn --genkey secret {s2s_key}')
+
+ # OpenVPN Auth Key
+ system(f'openvpn --genkey secret {auth_key}')
diff --git a/smoketest/configs/dialup-router-medium-vpn b/smoketest/configs/dialup-router-medium-vpn
index fb8ed2714..56722d222 100644
--- a/smoketest/configs/dialup-router-medium-vpn
+++ b/smoketest/configs/dialup-router-medium-vpn
@@ -122,6 +122,7 @@ interfaces {
tls {
ca-cert-file /config/auth/ovpn_test_chain.pem
cert-file /config/auth/ovpn_test_server.pem
+ crl-file /config/auth/ovpn_test_ca.crl
key-file /config/auth/ovpn_test_server.key
auth-file /config/auth/ovpn_test_tls_auth.key
}
diff --git a/smoketest/scripts/cli/test_interfaces_bridge.py b/smoketest/scripts/cli/test_interfaces_bridge.py
index ca0ead9e8..26d3a23c9 100755
--- a/smoketest/scripts/cli/test_interfaces_bridge.py
+++ b/smoketest/scripts/cli/test_interfaces_bridge.py
@@ -86,9 +86,83 @@ class BridgeInterfaceTest(BasicInterfaceTest.TestCase):
# validate member interface configuration
for member in self._members:
tmp = get_interface_config(member)
+ # verify member is assigned to the bridge
+ self.assertEqual(interface, tmp['master'])
# Isolated must be enabled as configured above
self.assertTrue(tmp['linkinfo']['info_slave_data']['isolated'])
+ def test_igmp_querier_snooping(self):
+ # Add member interfaces to bridge
+ for interface in self._interfaces:
+ base = self._base_path + [interface]
+
+ # assign members to bridge interface
+ for member in self._members:
+ base_member = base + ['member', 'interface', member]
+ self.cli_set(base_member)
+
+ # commit config
+ self.cli_commit()
+
+ for interface in self._interfaces:
+ # Verify IGMP default configuration
+ tmp = read_file(f'/sys/class/net/{interface}/bridge/multicast_snooping')
+ self.assertEqual(tmp, '0')
+ tmp = read_file(f'/sys/class/net/{interface}/bridge/multicast_querier')
+ self.assertEqual(tmp, '0')
+
+ # Enable IGMP snooping
+ for interface in self._interfaces:
+ base = self._base_path + [interface]
+ self.cli_set(base + ['igmp', 'snooping'])
+
+ # commit config
+ self.cli_commit()
+
+ for interface in self._interfaces:
+ # Verify IGMP snooping configuration
+ # Verify IGMP default configuration
+ tmp = read_file(f'/sys/class/net/{interface}/bridge/multicast_snooping')
+ self.assertEqual(tmp, '1')
+ tmp = read_file(f'/sys/class/net/{interface}/bridge/multicast_querier')
+ self.assertEqual(tmp, '0')
+
+ # Enable IGMP querieer
+ for interface in self._interfaces:
+ base = self._base_path + [interface]
+ self.cli_set(base + ['igmp', 'querier'])
+
+ # commit config
+ self.cli_commit()
+
+ for interface in self._interfaces:
+ # Verify IGMP snooping & querier configuration
+ tmp = read_file(f'/sys/class/net/{interface}/bridge/multicast_snooping')
+ self.assertEqual(tmp, '1')
+ tmp = read_file(f'/sys/class/net/{interface}/bridge/multicast_querier')
+ self.assertEqual(tmp, '1')
+
+ # Disable IGMP
+ for interface in self._interfaces:
+ base = self._base_path + [interface]
+ self.cli_delete(base + ['igmp'])
+
+ # commit config
+ self.cli_commit()
+
+ for interface in self._interfaces:
+ # Verify IGMP snooping & querier configuration
+ tmp = read_file(f'/sys/class/net/{interface}/bridge/multicast_snooping')
+ self.assertEqual(tmp, '0')
+ tmp = read_file(f'/sys/class/net/{interface}/bridge/multicast_querier')
+ self.assertEqual(tmp, '0')
+
+ # validate member interface configuration
+ for member in self._members:
+ tmp = get_interface_config(member)
+ # verify member is assigned to the bridge
+ self.assertEqual(interface, tmp['master'])
+
def test_add_remove_bridge_member(self):
# Add member interfaces to bridge and set STP cost/priority
diff --git a/smoketest/scripts/cli/test_system_ntp.py b/smoketest/scripts/cli/test_system_ntp.py
index e2821687c..a0806acf0 100755
--- a/smoketest/scripts/cli/test_system_ntp.py
+++ b/smoketest/scripts/cli/test_system_ntp.py
@@ -108,5 +108,22 @@ class TestSystemNTP(VyOSUnitTestSHIM.TestCase):
for listen in listen_address:
self.assertIn(f'interface listen {listen}', config)
+ def test_03_ntp_interface(self):
+ interfaces = ['eth0', 'eth1']
+ for interface in interfaces:
+ self.cli_set(base_path + ['interface', interface])
+
+ servers = ['time1.vyos.net', 'time2.vyos.net']
+ for server in servers:
+ self.cli_set(base_path + ['server', server])
+
+ self.cli_commit()
+
+ # Check generated client address configuration
+ config = read_file(NTP_CONF)
+ self.assertIn('interface ignore wildcard', config)
+ for interface in interfaces:
+ self.assertIn(f'interface listen {interface}', config)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/conf_mode/dns_forwarding.py b/src/conf_mode/dns_forwarding.py
index f1c2d1f43..41023c135 100755
--- a/src/conf_mode/dns_forwarding.py
+++ b/src/conf_mode/dns_forwarding.py
@@ -98,6 +98,9 @@ def get_config(config=None):
dns['authoritative_zone_errors'].append('{}.{}: at least one address is required'.format(subnode, node))
continue
+ if subnode == 'any':
+ subnode = '*'
+
for address in rdata['address']:
zone['records'].append({
'name': subnode,
diff --git a/src/conf_mode/ntp.py b/src/conf_mode/ntp.py
index 0d6ec9ace..5490a794d 100755
--- a/src/conf_mode/ntp.py
+++ b/src/conf_mode/ntp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2021 VyOS maintainers and contributors
+# Copyright (C) 2018-2022 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
@@ -18,9 +18,11 @@ import os
from vyos.config import Config
from vyos.configverify import verify_vrf
-from vyos import ConfigError
+from vyos.configverify import verify_interface_exists
from vyos.util import call
+from vyos.util import get_interface_config
from vyos.template import render
+from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -49,6 +51,20 @@ def verify(ntp):
raise ConfigError('NTP server not configured')
verify_vrf(ntp)
+
+ if 'interface' in ntp:
+ # If ntpd should listen on a given interface, ensure it exists
+ for interface in ntp['interface']:
+ verify_interface_exists(interface)
+
+ # If we run in a VRF, our interface must belong to this VRF, too
+ if 'vrf' in ntp:
+ tmp = get_interface_config(interface)
+ vrf_name = ntp['vrf']
+ if 'master' not in tmp or tmp['master'] != vrf_name:
+ raise ConfigError(f'NTP runs in VRF "{vrf_name}" - "{interface}" '\
+ f'does not belong to this VRF!')
+
return None
def generate(ntp):
diff --git a/src/conf_mode/service_ipoe-server.py b/src/conf_mode/service_ipoe-server.py
index 559d1bcd5..61f484129 100755
--- a/src/conf_mode/service_ipoe-server.py
+++ b/src/conf_mode/service_ipoe-server.py
@@ -53,6 +53,8 @@ default_config_data = {
'radius_nas_ip': '',
'radius_source_address': '',
'radius_shaper_attr': '',
+ 'radius_shaper_enable': False,
+ 'radius_shaper_multiplier': '',
'radius_shaper_vendor': '',
'radius_dynamic_author': '',
'thread_cnt': get_half_cpus()
@@ -196,6 +198,18 @@ def get_config(config=None):
if conf.exists(['nas-ip-address']):
ipoe['radius_nas_ip'] = conf.return_value(['nas-ip-address'])
+ if conf.exists(['rate-limit', 'attribute']):
+ ipoe['radius_shaper_attr'] = conf.return_value(['rate-limit', 'attribute'])
+
+ if conf.exists(['rate-limit', 'enable']):
+ ipoe['radius_shaper_enable'] = True
+
+ if conf.exists(['rate-limit', 'multiplier']):
+ ipoe['radius_shaper_multiplier'] = conf.return_value(['rate-limit', 'multiplier'])
+
+ if conf.exists(['rate-limit', 'vendor']):
+ ipoe['radius_shaper_vendor'] = conf.return_value(['rate-limit', 'vendor'])
+
if conf.exists(['source-address']):
ipoe['radius_source_address'] = conf.return_value(['source-address'])
diff --git a/src/system/vyos-event-handler.py b/src/system/vyos-event-handler.py
index 507fdc652..1c85380bc 100755
--- a/src/system/vyos-event-handler.py
+++ b/src/system/vyos-event-handler.py
@@ -15,14 +15,16 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import argparse
-import select
-import re
import json
+import re
+import select
+from copy import deepcopy
from os import getpid, environ
from pathlib import Path
from signal import signal, SIGTERM, SIGINT
-from systemd import journal
from sys import exit
+from systemd import journal
+
from vyos.util import run, dict_search
# Identify this script
@@ -54,7 +56,7 @@ class Analyzer:
script_arguments = dict_search('script.arguments', event_config)
script = f'{script} {script_arguments}'
# Prepare environment
- environment = environ
+ environment = deepcopy(environ)
# Check for additional environment options
if dict_search('script.environment', event_config):
for env_variable, env_value in dict_search(
diff --git a/src/systemd/dhclient@.service b/src/systemd/dhclient@.service
index 5cc7869cb..23cd4cfc3 100644
--- a/src/systemd/dhclient@.service
+++ b/src/systemd/dhclient@.service
@@ -14,7 +14,7 @@ ExecStart=/sbin/dhclient -4 $DHCLIENT_OPTS
ExecStop=/sbin/dhclient -4 $DHCLIENT_OPTS -r
Restart=always
TimeoutStopSec=20
-SendSIGKILL=SIGKILL
+SendSIGKILL=true
FinalKillSignal=SIGABRT
[Install]