summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/templates/router-advert/radvd.conf.j23
-rw-r--r--interface-definitions/include/interface/address-ipv4-ipv6-dhcp.xml.i2
-rw-r--r--interface-definitions/include/interface/address-ipv4-ipv6.xml.i2
-rw-r--r--interface-definitions/include/pki/ca-certificate-multi.xml.i15
-rw-r--r--interface-definitions/interfaces-bridge.xml.in10
-rw-r--r--interface-definitions/interfaces-openvpn.xml.in2
-rw-r--r--interface-definitions/interfaces-pppoe.xml.in2
-rw-r--r--interface-definitions/interfaces-pseudo-ethernet.xml.in2
-rw-r--r--interface-definitions/interfaces-vti.xml.in16
-rw-r--r--interface-definitions/protocols-mpls.xml.in2
-rw-r--r--interface-definitions/service-conntrack-sync.xml.in (renamed from interface-definitions/service_conntrack-sync.xml.in)0
-rw-r--r--interface-definitions/service-console-server.xml.in (renamed from interface-definitions/service_console-server.xml.in)0
-rw-r--r--interface-definitions/service-ipoe-server.xml.in (renamed from interface-definitions/service_ipoe-server.xml.in)0
-rw-r--r--interface-definitions/service-mdns-repeater.xml.in (renamed from interface-definitions/service_mdns-repeater.xml.in)0
-rw-r--r--interface-definitions/service-monitoring-telegraf.xml.in (renamed from interface-definitions/service_monitoring_telegraf.xml.in)0
-rw-r--r--interface-definitions/service-pppoe-server.xml.in (renamed from interface-definitions/service_pppoe-server.xml.in)0
-rw-r--r--interface-definitions/service-router-advert.xml.in (renamed from interface-definitions/service_router-advert.xml.in)17
-rw-r--r--interface-definitions/service-sla.xml.in (renamed from interface-definitions/service_sla.xml.in)0
-rw-r--r--interface-definitions/service-upnp.xml.in (renamed from interface-definitions/service_upnp.xml.in)0
-rw-r--r--interface-definitions/service-webproxy.xml.in (renamed from interface-definitions/service_webproxy.xml.in)0
-rw-r--r--interface-definitions/system-acceleration-qat.xml.in (renamed from interface-definitions/intel_qat.xml.in)0
-rw-r--r--interface-definitions/vpn-ipsec.xml.in (renamed from interface-definitions/vpn_ipsec.xml.in)0
-rw-r--r--interface-definitions/vpn-l2tp.xml.in (renamed from interface-definitions/vpn_l2tp.xml.in)0
-rw-r--r--interface-definitions/vpn-openconnect.xml.in (renamed from interface-definitions/vpn_openconnect.xml.in)0
-rw-r--r--interface-definitions/vpn-pptp.xml.in (renamed from interface-definitions/vpn_pptp.xml.in)0
-rw-r--r--interface-definitions/vpn-sstp.xml.in (renamed from interface-definitions/vpn_sstp.xml.in)0
-rw-r--r--python/vyos/ifconfig/bridge.py21
-rw-r--r--python/vyos/ifconfig/vti.py6
-rw-r--r--python/vyos/pki.py61
-rw-r--r--python/vyos/util.py4
-rw-r--r--smoketest/configs/dialup-router-medium-vpn4
-rwxr-xr-xsmoketest/scripts/cli/test_service_router-advert.py14
-rwxr-xr-xsrc/conf_mode/container.py11
-rwxr-xr-xsrc/conf_mode/interfaces-openvpn.py43
-rwxr-xr-xsrc/conf_mode/service_router-advert.py34
-rwxr-xr-xsrc/migration-scripts/interfaces/24-to-2537
36 files changed, 242 insertions, 66 deletions
diff --git a/data/templates/router-advert/radvd.conf.j2 b/data/templates/router-advert/radvd.conf.j2
index 6902dc05a..ed15b32f0 100644
--- a/data/templates/router-advert/radvd.conf.j2
+++ b/data/templates/router-advert/radvd.conf.j2
@@ -55,6 +55,9 @@ interface {{ iface }} {
{% endif %}
{% if iface_config.name_server is vyos_defined %}
RDNSS {{ iface_config.name_server | join(" ") }} {
+{% if iface_config.name_server_lifetime is vyos_defined %}
+ AdvRDNSSLifetime {{ iface_config.name_server_lifetime }};
+{% endif %}
};
{% endif %}
{% if iface_config.dnssl is vyos_defined %}
diff --git a/interface-definitions/include/interface/address-ipv4-ipv6-dhcp.xml.i b/interface-definitions/include/interface/address-ipv4-ipv6-dhcp.xml.i
index b9dd59bea..5057ed9ae 100644
--- a/interface-definitions/include/interface/address-ipv4-ipv6-dhcp.xml.i
+++ b/interface-definitions/include/interface/address-ipv4-ipv6-dhcp.xml.i
@@ -1,4 +1,4 @@
-<!-- include start from address-ipv4-ipv6-dhcp.xml.i -->
+<!-- include start from interface/address-ipv4-ipv6-dhcp.xml.i -->
<leafNode name="address">
<properties>
<help>IP address</help>
diff --git a/interface-definitions/include/interface/address-ipv4-ipv6.xml.i b/interface-definitions/include/interface/address-ipv4-ipv6.xml.i
index 519622050..d689da5aa 100644
--- a/interface-definitions/include/interface/address-ipv4-ipv6.xml.i
+++ b/interface-definitions/include/interface/address-ipv4-ipv6.xml.i
@@ -1,4 +1,4 @@
-<!-- include start from address-ipv4-ipv6.xml.i -->
+<!-- include start from interface/address-ipv4-ipv6.xml.i -->
<leafNode name="address">
<properties>
<help>IP address</help>
diff --git a/interface-definitions/include/pki/ca-certificate-multi.xml.i b/interface-definitions/include/pki/ca-certificate-multi.xml.i
new file mode 100644
index 000000000..646131b54
--- /dev/null
+++ b/interface-definitions/include/pki/ca-certificate-multi.xml.i
@@ -0,0 +1,15 @@
+<!-- include start from pki/ca-certificate-multi.xml.i -->
+<leafNode name="ca-certificate">
+ <properties>
+ <help>Certificate Authority chain in PKI configuration</help>
+ <completionHelp>
+ <path>pki ca</path>
+ </completionHelp>
+ <valueHelp>
+ <format>txt</format>
+ <description>Name of CA in PKI configuration</description>
+ </valueHelp>
+ <multi/>
+ </properties>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/interfaces-bridge.xml.in b/interface-definitions/interfaces-bridge.xml.in
index 60edf3ce2..48ee1efbc 100644
--- a/interface-definitions/interfaces-bridge.xml.in
+++ b/interface-definitions/interfaces-bridge.xml.in
@@ -73,12 +73,18 @@
</leafNode>
<node name="igmp">
<properties>
- <help>Internet Group Management Protocol (IGMP) settings</help>
+ <help>Internet Group Management Protocol (IGMP) and Multicast Listener Discovery (MLD) settings</help>
</properties>
<children>
<leafNode name="querier">
<properties>
- <help>Enable IGMP querier</help>
+ <help>Enable IGMP/MLD querier</help>
+ <valueless/>
+ </properties>
+ </leafNode>
+ <leafNode name="snooping">
+ <properties>
+ <help>Enable IGMP/MLD snooping</help>
<valueless/>
</properties>
</leafNode>
diff --git a/interface-definitions/interfaces-openvpn.xml.in b/interface-definitions/interfaces-openvpn.xml.in
index f1cbf8468..6cbd91ff4 100644
--- a/interface-definitions/interfaces-openvpn.xml.in
+++ b/interface-definitions/interfaces-openvpn.xml.in
@@ -741,7 +741,7 @@
</properties>
</leafNode>
#include <include/pki/certificate.xml.i>
- #include <include/pki/ca-certificate.xml.i>
+ #include <include/pki/ca-certificate-multi.xml.i>
<leafNode name="dh-params">
<properties>
<help>Diffie Hellman parameters (server only)</help>
diff --git a/interface-definitions/interfaces-pppoe.xml.in b/interface-definitions/interfaces-pppoe.xml.in
index 664914baa..9674cfc0e 100644
--- a/interface-definitions/interfaces-pppoe.xml.in
+++ b/interface-definitions/interfaces-pppoe.xml.in
@@ -4,7 +4,7 @@
<children>
<tagNode name="pppoe" owner="${vyos_conf_scripts_dir}/interfaces-pppoe.py">
<properties>
- <help>Point-to-Point Protocol over Ethernet (PPPoE)</help>
+ <help>Point-to-Point Protocol over Ethernet (PPPoE) Interface</help>
<priority>322</priority>
<constraint>
<regex>pppoe[0-9]+</regex>
diff --git a/interface-definitions/interfaces-pseudo-ethernet.xml.in b/interface-definitions/interfaces-pseudo-ethernet.xml.in
index 6b62f4c61..53e6445fa 100644
--- a/interface-definitions/interfaces-pseudo-ethernet.xml.in
+++ b/interface-definitions/interfaces-pseudo-ethernet.xml.in
@@ -4,7 +4,7 @@
<children>
<tagNode name="pseudo-ethernet" owner="${vyos_conf_scripts_dir}/interfaces-pseudo-ethernet.py">
<properties>
- <help>Pseudo Ethernet</help>
+ <help>Pseudo Ethernet Interface (Macvlan)</help>
<priority>321</priority>
<constraint>
<regex>peth[0-9]+</regex>
diff --git a/interface-definitions/interfaces-vti.xml.in b/interface-definitions/interfaces-vti.xml.in
index b471c3b92..aa83a04b2 100644
--- a/interface-definitions/interfaces-vti.xml.in
+++ b/interface-definitions/interfaces-vti.xml.in
@@ -4,7 +4,7 @@
<children>
<tagNode name="vti" owner="${vyos_conf_scripts_dir}/interfaces-vti.py">
<properties>
- <help>Virtual Tunnel interface</help>
+ <help>Virtual Tunnel Interface (XFRM)</help>
<priority>381</priority>
<constraint>
<regex>vti[0-9]+</regex>
@@ -16,19 +16,7 @@
</valueHelp>
</properties>
<children>
- <leafNode name="address">
- <properties>
- <help>IP address</help>
- <valueHelp>
- <format>ipv4net</format>
- <description>IPv4 address and prefix length</description>
- </valueHelp>
- <constraint>
- <validator name="ipv4-host"/>
- </constraint>
- <multi/>
- </properties>
- </leafNode>
+ #include <include/interface/address-ipv4-ipv6.xml.i>
#include <include/interface/description.xml.i>
#include <include/interface/disable.xml.i>
#include <include/interface/ipv4-options.xml.i>
diff --git a/interface-definitions/protocols-mpls.xml.in b/interface-definitions/protocols-mpls.xml.in
index be8e30c18..43ca659e9 100644
--- a/interface-definitions/protocols-mpls.xml.in
+++ b/interface-definitions/protocols-mpls.xml.in
@@ -6,7 +6,7 @@
<node name="mpls" owner="${vyos_conf_scripts_dir}/protocols_mpls.py">
<properties>
<help>Multiprotocol Label Switching (MPLS)</help>
- <priority>299</priority>
+ <priority>400</priority>
</properties>
<children>
<node name="ldp">
diff --git a/interface-definitions/service_conntrack-sync.xml.in b/interface-definitions/service-conntrack-sync.xml.in
index 6fa6fc5f9..6fa6fc5f9 100644
--- a/interface-definitions/service_conntrack-sync.xml.in
+++ b/interface-definitions/service-conntrack-sync.xml.in
diff --git a/interface-definitions/service_console-server.xml.in b/interface-definitions/service-console-server.xml.in
index e9591ad87..e9591ad87 100644
--- a/interface-definitions/service_console-server.xml.in
+++ b/interface-definitions/service-console-server.xml.in
diff --git a/interface-definitions/service_ipoe-server.xml.in b/interface-definitions/service-ipoe-server.xml.in
index e222467b1..e222467b1 100644
--- a/interface-definitions/service_ipoe-server.xml.in
+++ b/interface-definitions/service-ipoe-server.xml.in
diff --git a/interface-definitions/service_mdns-repeater.xml.in b/interface-definitions/service-mdns-repeater.xml.in
index 9a94f1488..9a94f1488 100644
--- a/interface-definitions/service_mdns-repeater.xml.in
+++ b/interface-definitions/service-mdns-repeater.xml.in
diff --git a/interface-definitions/service_monitoring_telegraf.xml.in b/interface-definitions/service-monitoring-telegraf.xml.in
index d0d9202c1..d0d9202c1 100644
--- a/interface-definitions/service_monitoring_telegraf.xml.in
+++ b/interface-definitions/service-monitoring-telegraf.xml.in
diff --git a/interface-definitions/service_pppoe-server.xml.in b/interface-definitions/service-pppoe-server.xml.in
index 50f42849b..50f42849b 100644
--- a/interface-definitions/service_pppoe-server.xml.in
+++ b/interface-definitions/service-pppoe-server.xml.in
diff --git a/interface-definitions/service_router-advert.xml.in b/interface-definitions/service-router-advert.xml.in
index 40dac23ca..258b7b749 100644
--- a/interface-definitions/service_router-advert.xml.in
+++ b/interface-definitions/service-router-advert.xml.in
@@ -136,6 +136,23 @@
</children>
</node>
#include <include/name-server-ipv6.xml.i>
+ <leafNode name="name-server-lifetime">
+ <properties>
+ <help>Maximum duration how long the RDNSS entries are used</help>
+ <valueHelp>
+ <format>u32:0</format>
+ <description>Name-servers should no longer be used</description>
+ </valueHelp>
+ <valueHelp>
+ <format>u32:1-7200</format>
+ <description>Maximum interval in seconds</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-7200"/>
+ </constraint>
+ <constraintErrorMessage>Maximum interval must be between 1 and 7200 seconds</constraintErrorMessage>
+ </properties>
+ </leafNode>
<leafNode name="other-config-flag">
<properties>
<help>Hosts use the administered (stateful) protocol for autoconfiguration of other (non-address) information</help>
diff --git a/interface-definitions/service_sla.xml.in b/interface-definitions/service-sla.xml.in
index 0c4f8a591..0c4f8a591 100644
--- a/interface-definitions/service_sla.xml.in
+++ b/interface-definitions/service-sla.xml.in
diff --git a/interface-definitions/service_upnp.xml.in b/interface-definitions/service-upnp.xml.in
index a129b7260..a129b7260 100644
--- a/interface-definitions/service_upnp.xml.in
+++ b/interface-definitions/service-upnp.xml.in
diff --git a/interface-definitions/service_webproxy.xml.in b/interface-definitions/service-webproxy.xml.in
index e4609b699..e4609b699 100644
--- a/interface-definitions/service_webproxy.xml.in
+++ b/interface-definitions/service-webproxy.xml.in
diff --git a/interface-definitions/intel_qat.xml.in b/interface-definitions/system-acceleration-qat.xml.in
index 812484184..812484184 100644
--- a/interface-definitions/intel_qat.xml.in
+++ b/interface-definitions/system-acceleration-qat.xml.in
diff --git a/interface-definitions/vpn_ipsec.xml.in b/interface-definitions/vpn-ipsec.xml.in
index d36fbb024..d36fbb024 100644
--- a/interface-definitions/vpn_ipsec.xml.in
+++ b/interface-definitions/vpn-ipsec.xml.in
diff --git a/interface-definitions/vpn_l2tp.xml.in b/interface-definitions/vpn-l2tp.xml.in
index f734283e7..f734283e7 100644
--- a/interface-definitions/vpn_l2tp.xml.in
+++ b/interface-definitions/vpn-l2tp.xml.in
diff --git a/interface-definitions/vpn_openconnect.xml.in b/interface-definitions/vpn-openconnect.xml.in
index 21b47125d..21b47125d 100644
--- a/interface-definitions/vpn_openconnect.xml.in
+++ b/interface-definitions/vpn-openconnect.xml.in
diff --git a/interface-definitions/vpn_pptp.xml.in b/interface-definitions/vpn-pptp.xml.in
index 28a53acb9..28a53acb9 100644
--- a/interface-definitions/vpn_pptp.xml.in
+++ b/interface-definitions/vpn-pptp.xml.in
diff --git a/interface-definitions/vpn_sstp.xml.in b/interface-definitions/vpn-sstp.xml.in
index 195d581df..195d581df 100644
--- a/interface-definitions/vpn_sstp.xml.in
+++ b/interface-definitions/vpn-sstp.xml.in
diff --git a/python/vyos/ifconfig/bridge.py b/python/vyos/ifconfig/bridge.py
index ffd9c590f..e4db69c1f 100644
--- a/python/vyos/ifconfig/bridge.py
+++ b/python/vyos/ifconfig/bridge.py
@@ -90,6 +90,10 @@ class BridgeIf(Interface):
'validate': assert_boolean,
'location': '/sys/class/net/{ifname}/bridge/multicast_querier',
},
+ 'multicast_snooping': {
+ 'validate': assert_boolean,
+ 'location': '/sys/class/net/{ifname}/bridge/multicast_snooping',
+ },
}}
_command_set = {**Interface._command_set, **{
@@ -198,6 +202,18 @@ class BridgeIf(Interface):
"""
self.set_interface('multicast_querier', enable)
+ def set_multicast_snooping(self, enable):
+ """
+ Enable or disable multicast snooping on the bridge.
+
+ Use enable=1 to enable or enable=0 to disable
+
+ Example:
+ >>> from vyos.ifconfig import Interface
+ >>> BridgeIf('br0').set_multicast_snooping(1)
+ """
+ self.set_interface('multicast_snooping', enable)
+
def add_port(self, interface):
"""
Add physical interface to bridge (member port)
@@ -257,6 +273,11 @@ class BridgeIf(Interface):
value = '1' if 'stp' in config else '0'
self.set_stp(value)
+ # enable or disable multicast snooping
+ tmp = dict_search('igmp.snooping', config)
+ value = '1' if (tmp != None) else '0'
+ self.set_multicast_snooping(value)
+
# enable or disable IGMP querier
tmp = dict_search('igmp.querier', config)
value = '1' if (tmp != None) else '0'
diff --git a/python/vyos/ifconfig/vti.py b/python/vyos/ifconfig/vti.py
index c50cd5ce9..dc99d365a 100644
--- a/python/vyos/ifconfig/vti.py
+++ b/python/vyos/ifconfig/vti.py
@@ -1,4 +1,4 @@
-# Copyright 2021 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2021-2022 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -53,3 +53,7 @@ class VTIIf(Interface):
self._cmd(cmd.format(**self.config))
self.set_interface('admin_state', 'down')
+
+ def get_mac(self):
+ """ Get a synthetic MAC address. """
+ return self.get_mac_synthetic()
diff --git a/python/vyos/pki.py b/python/vyos/pki.py
index fd91fc9bf..cd15e3878 100644
--- a/python/vyos/pki.py
+++ b/python/vyos/pki.py
@@ -332,6 +332,54 @@ def verify_certificate(cert, ca_cert):
except InvalidSignature:
return False
+def verify_crl(crl, ca_cert):
+ # Verify CRL was signed by specified CA
+ if ca_cert.subject != crl.issuer:
+ return False
+
+ ca_public_key = ca_cert.public_key()
+ try:
+ if isinstance(ca_public_key, rsa.RSAPublicKeyWithSerialization):
+ ca_public_key.verify(
+ crl.signature,
+ crl.tbs_certlist_bytes,
+ padding=padding.PKCS1v15(),
+ algorithm=crl.signature_hash_algorithm)
+ elif isinstance(ca_public_key, dsa.DSAPublicKeyWithSerialization):
+ ca_public_key.verify(
+ crl.signature,
+ crl.tbs_certlist_bytes,
+ algorithm=crl.signature_hash_algorithm)
+ elif isinstance(ca_public_key, ec.EllipticCurvePublicKeyWithSerialization):
+ ca_public_key.verify(
+ crl.signature,
+ crl.tbs_certlist_bytes,
+ signature_algorithm=ec.ECDSA(crl.signature_hash_algorithm))
+ else:
+ return False # We cannot verify it
+ return True
+ except InvalidSignature:
+ return False
+
+def verify_ca_chain(sorted_names, pki_node):
+ if len(sorted_names) == 1: # Single cert, no chain
+ return True
+
+ for name in sorted_names:
+ cert = load_certificate(pki_node[name]['certificate'])
+ verified = False
+ for ca_name in sorted_names:
+ if name == ca_name:
+ continue
+ ca_cert = load_certificate(pki_node[ca_name]['certificate'])
+ if verify_certificate(cert, ca_cert):
+ verified = True
+ break
+ if not verified and name != sorted_names[-1]:
+ # Only permit top-most certificate to fail verify (e.g. signed by public CA not explicitly in chain)
+ return False
+ return True
+
# Certificate chain
def find_parent(cert, ca_certs):
@@ -357,3 +405,16 @@ def find_chain(cert, ca_certs):
chain.append(parent)
return chain
+
+def sort_ca_chain(ca_names, pki_node):
+ def ca_cmp(ca_name1, ca_name2, pki_node):
+ cert1 = load_certificate(pki_node[ca_name1]['certificate'])
+ cert2 = load_certificate(pki_node[ca_name2]['certificate'])
+
+ if verify_certificate(cert1, cert2): # cert1 is child of cert2
+ return -1
+ return 1
+
+ from functools import cmp_to_key
+ return sorted(ca_names, key=cmp_to_key(lambda cert1, cert2: ca_cmp(cert1, cert2, pki_node)))
+
diff --git a/python/vyos/util.py b/python/vyos/util.py
index 0d62fbfe9..bee5d7aec 100644
--- a/python/vyos/util.py
+++ b/python/vyos/util.py
@@ -197,7 +197,7 @@ def read_file(fname, defaultonfailure=None):
return defaultonfailure
raise e
-def write_file(fname, data, defaultonfailure=None, user=None, group=None, mode=None):
+def write_file(fname, data, defaultonfailure=None, user=None, group=None, mode=None, append=False):
"""
Write content of data to given fname, should defaultonfailure be not None,
it is returned on failure to read.
@@ -212,7 +212,7 @@ def write_file(fname, data, defaultonfailure=None, user=None, group=None, mode=N
try:
""" Write a file to string """
bytes = 0
- with open(fname, 'w') as f:
+ with open(fname, 'w' if not append else 'a') as f:
bytes = f.write(data)
chown(fname, user, group)
chmod(fname, mode)
diff --git a/smoketest/configs/dialup-router-medium-vpn b/smoketest/configs/dialup-router-medium-vpn
index 63d955738..fb8ed2714 100644
--- a/smoketest/configs/dialup-router-medium-vpn
+++ b/smoketest/configs/dialup-router-medium-vpn
@@ -120,7 +120,7 @@ interfaces {
persistent-tunnel
remote-host 192.0.2.10
tls {
- ca-cert-file /config/auth/ovpn_test_ca.pem
+ ca-cert-file /config/auth/ovpn_test_chain.pem
cert-file /config/auth/ovpn_test_server.pem
key-file /config/auth/ovpn_test_server.key
auth-file /config/auth/ovpn_test_tls_auth.key
@@ -152,7 +152,7 @@ interfaces {
remote-host 01.foo.com
remote-port 1194
tls {
- ca-cert-file /config/auth/ovpn_test_ca.pem
+ ca-cert-file /config/auth/ovpn_test_chain.pem
auth-file /config/auth/ovpn_test_tls_auth.key
}
}
diff --git a/smoketest/scripts/cli/test_service_router-advert.py b/smoketest/scripts/cli/test_service_router-advert.py
index 4875fb5d1..1168c05cd 100755
--- a/smoketest/scripts/cli/test_service_router-advert.py
+++ b/smoketest/scripts/cli/test_service_router-advert.py
@@ -17,6 +17,7 @@
import re
import unittest
+from vyos.configsession import ConfigSessionError
from base_vyostest_shim import VyOSUnitTestSHIM
from vyos.util import read_file
@@ -93,6 +94,7 @@ class TestServiceRADVD(VyOSUnitTestSHIM.TestCase):
def test_dns(self):
nameserver = ['2001:db8::1', '2001:db8::2']
dnssl = ['vyos.net', 'vyos.io']
+ ns_lifetime = '599'
self.cli_set(base_path + ['prefix', '::/64', 'valid-lifetime', 'infinity'])
self.cli_set(base_path + ['other-config-flag'])
@@ -102,6 +104,14 @@ class TestServiceRADVD(VyOSUnitTestSHIM.TestCase):
for sl in dnssl:
self.cli_set(base_path + ['dnssl', sl])
+ self.cli_set(base_path + ['name-server-lifetime', ns_lifetime])
+ # The value, if not 0, must be at least interval max (defaults to 600).
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ ns_lifetime = '600'
+ self.cli_set(base_path + ['name-server-lifetime', ns_lifetime])
+
# commit changes
self.cli_commit()
@@ -110,8 +120,12 @@ class TestServiceRADVD(VyOSUnitTestSHIM.TestCase):
tmp = 'RDNSS ' + ' '.join(nameserver) + ' {'
self.assertIn(tmp, config)
+ tmp = f'AdvRDNSSLifetime {ns_lifetime};'
+ self.assertIn(tmp, config)
+
tmp = 'DNSSL ' + ' '.join(dnssl) + ' {'
self.assertIn(tmp, config)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/conf_mode/container.py b/src/conf_mode/container.py
index 2110fd9e0..ac3dc536b 100755
--- a/src/conf_mode/container.py
+++ b/src/conf_mode/container.py
@@ -90,10 +90,10 @@ def get_config(config=None):
container['name'][name] = dict_merge(default_values, container['name'][name])
# Delete container network, delete containers
- tmp = node_changed(conf, base + ['container', 'network'])
+ tmp = node_changed(conf, base + ['network'])
if tmp: container.update({'network_remove' : tmp})
- tmp = node_changed(conf, base + ['container', 'name'])
+ tmp = node_changed(conf, base + ['name'])
if tmp: container.update({'container_remove' : tmp})
return container
@@ -132,7 +132,7 @@ def verify(container):
# Check if the specified container network exists
network_name = list(container_config['network'])[0]
- if network_name not in container['network']:
+ if network_name not in container.get('network', {}):
raise ConfigError(f'Container network "{network_name}" does not exist!')
if 'address' in container_config['network'][network_name]:
@@ -270,12 +270,13 @@ def apply(container):
# Option "--force" allows to delete containers with any status
if 'container_remove' in container:
for name in container['container_remove']:
- call(f'podman stop {name}')
+ call(f'podman stop --time 3 {name}')
call(f'podman rm --force {name}')
# Delete old networks if needed
if 'network_remove' in container:
for network in container['network_remove']:
+ call(f'podman network rm {network}')
tmp = f'/etc/cni/net.d/{network}.conflist'
if os.path.exists(tmp):
os.unlink(tmp)
@@ -294,7 +295,7 @@ def apply(container):
# check if there is a container by that name running
tmp = _cmd('podman ps -a --format "{{.Names}}"')
if name in tmp:
- _cmd(f'podman stop {name}')
+ _cmd(f'podman stop --time 3 {name}')
_cmd(f'podman rm --force {name}')
continue
diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py
index 4750ca3e8..280a62b9a 100755
--- a/src/conf_mode/interfaces-openvpn.py
+++ b/src/conf_mode/interfaces-openvpn.py
@@ -39,6 +39,8 @@ from vyos.configverify import verify_mirror_redirect
from vyos.ifconfig import VTunIf
from vyos.pki import load_dh_parameters
from vyos.pki import load_private_key
+from vyos.pki import sort_ca_chain
+from vyos.pki import verify_ca_chain
from vyos.pki import wrap_certificate
from vyos.pki import wrap_crl
from vyos.pki import wrap_dh_parameters
@@ -148,8 +150,14 @@ def verify_pki(openvpn):
if 'ca_certificate' not in tls:
raise ConfigError(f'Must specify "tls ca-certificate" on openvpn interface {interface}')
- if tls['ca_certificate'] not in pki['ca']:
- raise ConfigError(f'Invalid CA certificate on openvpn interface {interface}')
+ for ca_name in tls['ca_certificate']:
+ if ca_name not in pki['ca']:
+ raise ConfigError(f'Invalid CA certificate on openvpn interface {interface}')
+
+ if len(tls['ca_certificate']) > 1:
+ sorted_chain = sort_ca_chain(tls['ca_certificate'], pki['ca'])
+ if not verify_ca_chain(sorted_chain, pki['ca']):
+ raise ConfigError(f'CA certificates are not a valid chain')
if mode != 'client' and 'auth_key' not in tls:
if 'certificate' not in tls:
@@ -516,21 +524,28 @@ def generate_pki_files(openvpn):
if tls:
if 'ca_certificate' in tls:
- cert_name = tls['ca_certificate']
- pki_ca = pki['ca'][cert_name]
+ cert_path = os.path.join(cfg_dir, f'{interface}_ca.pem')
+ crl_path = os.path.join(cfg_dir, f'{interface}_crl.pem')
- if 'certificate' in pki_ca:
- cert_path = os.path.join(cfg_dir, f'{interface}_ca.pem')
- write_file(cert_path, wrap_certificate(pki_ca['certificate']),
- user=user, group=group, mode=0o600)
+ if os.path.exists(cert_path):
+ os.unlink(cert_path)
+
+ if os.path.exists(crl_path):
+ os.unlink(crl_path)
+
+ for cert_name in sort_ca_chain(tls['ca_certificate'], pki['ca']):
+ pki_ca = pki['ca'][cert_name]
+
+ if 'certificate' in pki_ca:
+ write_file(cert_path, wrap_certificate(pki_ca['certificate']) + "\n",
+ user=user, group=group, mode=0o600, append=True)
- if 'crl' in pki_ca:
- for crl in pki_ca['crl']:
- crl_path = os.path.join(cfg_dir, f'{interface}_crl.pem')
- write_file(crl_path, wrap_crl(crl), user=user, group=group,
- mode=0o600)
+ if 'crl' in pki_ca:
+ for crl in pki_ca['crl']:
+ write_file(crl_path, wrap_crl(crl) + "\n", user=user, group=group,
+ mode=0o600, append=True)
- openvpn['tls']['crl'] = True
+ openvpn['tls']['crl'] = True
if 'certificate' in tls:
cert_name = tls['certificate']
diff --git a/src/conf_mode/service_router-advert.py b/src/conf_mode/service_router-advert.py
index 71b758399..ff7caaa84 100755
--- a/src/conf_mode/service_router-advert.py
+++ b/src/conf_mode/service_router-advert.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
@@ -17,7 +17,7 @@
import os
from sys import exit
-
+from vyos.base import Warning
from vyos.config import Config
from vyos.configdict import dict_merge
from vyos.template import render
@@ -79,22 +79,35 @@ def verify(rtradv):
if 'interface' not in rtradv:
return None
- for interface in rtradv['interface']:
- interface = rtradv['interface'][interface]
+ for interface, interface_config in rtradv['interface'].items():
if 'prefix' in interface:
- for prefix in interface['prefix']:
- prefix = interface['prefix'][prefix]
- valid_lifetime = prefix['valid_lifetime']
+ for prefix, prefix_config in interface_config['prefix'].items():
+ valid_lifetime = prefix_config['valid_lifetime']
if valid_lifetime == 'infinity':
valid_lifetime = 4294967295
- preferred_lifetime = prefix['preferred_lifetime']
+ preferred_lifetime = prefix_config['preferred_lifetime']
if preferred_lifetime == 'infinity':
preferred_lifetime = 4294967295
if not (int(valid_lifetime) > int(preferred_lifetime)):
raise ConfigError('Prefix valid-lifetime must be greater then preferred-lifetime')
+ if 'name_server_lifetime' in interface_config:
+ # man page states:
+ # The maximum duration how long the RDNSS entries are used for name
+ # resolution. A value of 0 means the nameserver must no longer be
+ # used. The value, if not 0, must be at least MaxRtrAdvInterval. To
+ # ensure stale RDNSS info gets removed in a timely fashion, this
+ # should not be greater than 2*MaxRtrAdvInterval.
+ lifetime = int(interface_config['name_server_lifetime'])
+ interval_max = int(interface_config['interval']['max'])
+ if lifetime > 0:
+ if lifetime < int(interval_max):
+ raise ConfigError(f'RDNSS lifetime must be at least "{interval_max}" seconds!')
+ if lifetime > 2* interval_max:
+ Warning(f'RDNSS lifetime should not exceed "{2 * interval_max}" which is two times "interval max"!')
+
return None
def generate(rtradv):
@@ -105,15 +118,16 @@ def generate(rtradv):
return None
def apply(rtradv):
+ systemd_service = 'radvd.service'
if not rtradv:
# bail out early - looks like removal from running config
- call('systemctl stop radvd.service')
+ call(f'systemctl stop {systemd_service}')
if os.path.exists(config_file):
os.unlink(config_file)
return None
- call('systemctl restart radvd.service')
+ call(f'systemctl reload-or-restart {systemd_service}')
return None
diff --git a/src/migration-scripts/interfaces/24-to-25 b/src/migration-scripts/interfaces/24-to-25
index 93ce9215f..4095f2a3e 100755
--- a/src/migration-scripts/interfaces/24-to-25
+++ b/src/migration-scripts/interfaces/24-to-25
@@ -20,6 +20,7 @@
import os
import sys
from vyos.configtree import ConfigTree
+from vyos.pki import CERT_BEGIN
from vyos.pki import load_certificate
from vyos.pki import load_crl
from vyos.pki import load_dh_parameters
@@ -27,6 +28,7 @@ from vyos.pki import load_private_key
from vyos.pki import encode_certificate
from vyos.pki import encode_dh_parameters
from vyos.pki import encode_private_key
+from vyos.pki import verify_crl
from vyos.util import run
def wrapped_pem_to_config_value(pem):
@@ -129,6 +131,8 @@ if config.exists(base):
config.delete(base + [interface, 'tls', 'crypt-file'])
+ ca_certs = {}
+
if config.exists(x509_base + ['ca-cert-file']):
if not config.exists(pki_base + ['ca']):
config.set(pki_base + ['ca'])
@@ -136,20 +140,27 @@ if config.exists(base):
cert_file = config.return_value(x509_base + ['ca-cert-file'])
cert_path = os.path.join(AUTH_DIR, cert_file)
- cert = None
if os.path.isfile(cert_path):
if not os.access(cert_path, os.R_OK):
run(f'sudo chmod 644 {cert_path}')
with open(cert_path, 'r') as f:
- cert_data = f.read()
- cert = load_certificate(cert_data, wrap_tags=False)
-
- if cert:
- cert_pem = encode_certificate(cert)
- config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
- config.set(x509_base + ['ca-certificate'], value=pki_name)
+ certs_str = f.read()
+ certs_data = certs_str.split(CERT_BEGIN)
+ index = 1
+ for cert_data in certs_data[1:]:
+ cert = load_certificate(CERT_BEGIN + cert_data, wrap_tags=False)
+
+ if cert:
+ ca_certs[f'{pki_name}_{index}'] = cert
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['ca', f'{pki_name}_{index}', 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(x509_base + ['ca-certificate'], value=f'{pki_name}_{index}', replace=False)
+ else:
+ print(f'Failed to migrate CA certificate on openvpn interface {interface}')
+
+ index += 1
else:
print(f'Failed to migrate CA certificate on openvpn interface {interface}')
@@ -163,6 +174,7 @@ if config.exists(base):
crl_file = config.return_value(x509_base + ['crl-file'])
crl_path = os.path.join(AUTH_DIR, crl_file)
crl = None
+ crl_ca_name = None
if os.path.isfile(crl_path):
if not os.access(crl_path, os.R_OK):
@@ -172,9 +184,14 @@ if config.exists(base):
crl_data = f.read()
crl = load_crl(crl_data, wrap_tags=False)
- if crl:
+ for ca_name, ca_cert in ca_certs.items():
+ if verify_crl(crl, ca_cert):
+ crl_ca_name = ca_name
+ break
+
+ if crl and crl_ca_name:
crl_pem = encode_certificate(crl)
- config.set(pki_base + ['ca', pki_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem))
+ config.set(pki_base + ['ca', crl_ca_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem))
else:
print(f'Failed to migrate CRL on openvpn interface {interface}')