diff options
-rw-r--r-- | data/templates/load-balancing/haproxy.cfg.j2 | 10 | ||||
-rw-r--r-- | data/templates/ocserv/ocserv_config.j2 | 8 | ||||
-rw-r--r-- | interface-definitions/include/pppoe-access-concentrator.xml.i | 4 | ||||
-rw-r--r-- | interface-definitions/include/tls-version-min.xml.i | 29 | ||||
-rw-r--r-- | interface-definitions/include/version/openconnect-version.xml.i | 2 | ||||
-rw-r--r-- | interface-definitions/interfaces_openvpn.xml.in | 28 | ||||
-rw-r--r-- | interface-definitions/service_dns_forwarding.xml.in | 2 | ||||
-rw-r--r-- | interface-definitions/vpn_openconnect.xml.in | 4 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_load-balancing_reverse-proxy.py | 5 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_vpn_openconnect.py | 11 | ||||
-rwxr-xr-x | src/conf_mode/interfaces_wireless.py | 10 | ||||
-rwxr-xr-x | src/conf_mode/service_ipoe-server.py | 2 | ||||
-rwxr-xr-x | src/conf_mode/service_pppoe-server.py | 2 | ||||
-rwxr-xr-x | src/migration-scripts/openconnect/2-to-3 | 50 | ||||
-rwxr-xr-x | src/services/vyos-configd | 2 |
15 files changed, 130 insertions, 39 deletions
diff --git a/data/templates/load-balancing/haproxy.cfg.j2 b/data/templates/load-balancing/haproxy.cfg.j2 index e8622ba7b..7917c8257 100644 --- a/data/templates/load-balancing/haproxy.cfg.j2 +++ b/data/templates/load-balancing/haproxy.cfg.j2 @@ -85,7 +85,7 @@ frontend {{ front }} {% if front_config.rule is vyos_defined %} {% for rule, rule_config in front_config.rule.items() %} # rule {{ rule }} -{% if rule_config.domain_name is vyos_defined and rule_config.set.backend is vyos_defined %} +{% if rule_config.domain_name is vyos_defined %} {% set rule_options = 'hdr(host)' %} {% if rule_config.ssl is vyos_defined %} {% set ssl_rule_translate = {'req-ssl-sni': 'req_ssl_sni', 'ssl-fc-sni': 'ssl_fc_sni', 'ssl-fc-sni-end': 'ssl_fc_sni_end'} %} @@ -94,16 +94,20 @@ frontend {{ front }} {% for domain in rule_config.domain_name %} acl {{ rule }} {{ rule_options }} -i {{ domain }} {% endfor %} - use_backend {{ rule_config.set.backend }} if {{ rule }} {% endif %} {# path url #} -{% if rule_config.url_path is vyos_defined and rule_config.set.redirect_location is vyos_defined %} +{% if rule_config.url_path is vyos_defined %} {% set path_mod_translate = {'begin': '-i -m beg', 'end': '-i -m end', 'exact': ''} %} {% for path, path_config in rule_config.url_path.items() %} {% for url in path_config %} acl {{ rule }} path {{ path_mod_translate[path] }} {{ url }} {% endfor %} {% endfor %} +{% endif %} +{% if rule_config.set.backend is vyos_defined %} + use_backend {{ rule_config.set.backend }} if {{ rule }} +{% endif %} +{% if rule_config.set.redirect_location is vyos_defined %} http-request redirect location {{ rule_config.set.redirect_location }} code 301 if {{ rule }} {% endif %} {# endpath #} diff --git a/data/templates/ocserv/ocserv_config.j2 b/data/templates/ocserv/ocserv_config.j2 index b5e890c32..81f777031 100644 --- a/data/templates/ocserv/ocserv_config.j2 +++ b/data/templates/ocserv/ocserv_config.j2 @@ -61,7 +61,15 @@ keepalive = 300 dpd = 60 mobile-dpd = 300 switch-to-tcp-timeout = 30 +{% if tls_version_min == '1.0' %} tls-priorities = "NORMAL:%SERVER_PRECEDENCE:%COMPAT:-RSA:-VERS-SSL3.0:-ARCFOUR-128" +{% elif tls_version_min == '1.1' %} +tls-priorities = "NORMAL:%SERVER_PRECEDENCE:%COMPAT:-RSA:-VERS-SSL3.0:-ARCFOUR-128:-VERS-TLS1.0" +{% elif tls_version_min == '1.2' %} +tls-priorities = "NORMAL:%SERVER_PRECEDENCE:%COMPAT:-RSA:-VERS-SSL3.0:-ARCFOUR-128:-VERS-TLS1.0:-VERS-TLS1.1" +{% elif tls_version_min == '1.3' %} +tls-priorities = "NORMAL:%SERVER_PRECEDENCE:%COMPAT:-RSA:-VERS-SSL3.0:-ARCFOUR-128:-VERS-TLS1.0:-VERS-TLS1.1:-VERS-TLS1.2" +{% endif %} auth-timeout = 240 idle-timeout = 1200 mobile-idle-timeout = 1800 diff --git a/interface-definitions/include/pppoe-access-concentrator.xml.i b/interface-definitions/include/pppoe-access-concentrator.xml.i index ccfcc1c49..8a75dae08 100644 --- a/interface-definitions/include/pppoe-access-concentrator.xml.i +++ b/interface-definitions/include/pppoe-access-concentrator.xml.i @@ -3,9 +3,9 @@ <properties> <help>Access concentrator name</help> <constraint> - <regex>[a-zA-Z0-9]{1,100}</regex> + #include <include/constraint/alpha-numeric-hyphen-underscore.xml.i> </constraint> - <constraintErrorMessage>Access-concentrator name must be alphanumerical only (max. 100 characters)</constraintErrorMessage> + <constraintErrorMessage>Access-concentrator name can only contain alpha-numeric letters, hyphen and underscores(max. 100 characters)</constraintErrorMessage> </properties> </leafNode> <!-- include end --> diff --git a/interface-definitions/include/tls-version-min.xml.i b/interface-definitions/include/tls-version-min.xml.i new file mode 100644 index 000000000..b3dcbad49 --- /dev/null +++ b/interface-definitions/include/tls-version-min.xml.i @@ -0,0 +1,29 @@ +<!-- include start from tls-version-min.xml.i --> +<leafNode name="tls-version-min"> + <properties> + <help>Specify the minimum required TLS version</help> + <completionHelp> + <list>1.0 1.1 1.2 1.3</list> + </completionHelp> + <valueHelp> + <format>1.0</format> + <description>TLS v1.0</description> + </valueHelp> + <valueHelp> + <format>1.1</format> + <description>TLS v1.1</description> + </valueHelp> + <valueHelp> + <format>1.2</format> + <description>TLS v1.2</description> + </valueHelp> + <valueHelp> + <format>1.3</format> + <description>TLS v1.3</description> + </valueHelp> + <constraint> + <regex>(1.0|1.1|1.2|1.3)</regex> + </constraint> + </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/include/version/openconnect-version.xml.i b/interface-definitions/include/version/openconnect-version.xml.i index 654806278..15097eebe 100644 --- a/interface-definitions/include/version/openconnect-version.xml.i +++ b/interface-definitions/include/version/openconnect-version.xml.i @@ -1,3 +1,3 @@ <!-- include start from include/version/openconnect-version.xml.i --> -<syntaxVersion component='openconnect' version='2'></syntaxVersion> +<syntaxVersion component='openconnect' version='3'></syntaxVersion> <!-- include end --> diff --git a/interface-definitions/interfaces_openvpn.xml.in b/interface-definitions/interfaces_openvpn.xml.in index 389b5b5c9..7b46f32b3 100644 --- a/interface-definitions/interfaces_openvpn.xml.in +++ b/interface-definitions/interfaces_openvpn.xml.in @@ -739,33 +739,7 @@ <constraintErrorMessage>Peer certificate fingerprint must be a colon-separated SHA256 hex digest</constraintErrorMessage> </properties> </leafNode> - <leafNode name="tls-version-min"> - <properties> - <help>Specify the minimum required TLS version</help> - <completionHelp> - <list>1.0 1.1 1.2 1.3</list> - </completionHelp> - <valueHelp> - <format>1.0</format> - <description>TLS v1.0</description> - </valueHelp> - <valueHelp> - <format>1.1</format> - <description>TLS v1.1</description> - </valueHelp> - <valueHelp> - <format>1.2</format> - <description>TLS v1.2</description> - </valueHelp> - <valueHelp> - <format>1.3</format> - <description>TLS v1.3</description> - </valueHelp> - <constraint> - <regex>(1.0|1.1|1.2|1.3)</regex> - </constraint> - </properties> - </leafNode> + #include <include/tls-version-min.xml.i> <leafNode name="role"> <properties> <help>TLS negotiation role</help> diff --git a/interface-definitions/service_dns_forwarding.xml.in b/interface-definitions/service_dns_forwarding.xml.in index a54618e82..b52b4bda3 100644 --- a/interface-definitions/service_dns_forwarding.xml.in +++ b/interface-definitions/service_dns_forwarding.xml.in @@ -115,7 +115,7 @@ <description>An absolute DNS domain name</description> </valueHelp> <constraint> - <validator name="fqdn"/> + <regex>((?!-)[-_a-zA-Z0-9.]{1,63}|@|any)(?<!\.)</regex> </constraint> </properties> <children> diff --git a/interface-definitions/vpn_openconnect.xml.in b/interface-definitions/vpn_openconnect.xml.in index 736084f8b..7849d6886 100644 --- a/interface-definitions/vpn_openconnect.xml.in +++ b/interface-definitions/vpn_openconnect.xml.in @@ -266,6 +266,10 @@ <valueless/> </properties> </leafNode> + #include <include/tls-version-min.xml.i> + <leafNode name="tls-version-min"> + <defaultValue>1.2</defaultValue> + </leafNode> <node name="ssl"> <properties> <help>SSL Certificate, SSL Key and CA</help> diff --git a/smoketest/scripts/cli/test_load-balancing_reverse-proxy.py b/smoketest/scripts/cli/test_load-balancing_reverse-proxy.py index f9f163782..c8b17316f 100755 --- a/smoketest/scripts/cli/test_load-balancing_reverse-proxy.py +++ b/smoketest/scripts/cli/test_load-balancing_reverse-proxy.py @@ -180,6 +180,7 @@ class TestLoadBalancingReverseProxy(VyOSUnitTestSHIM.TestCase): mode = 'http' rule_ten = '10' rule_twenty = '20' + rule_thirty = '30' send_proxy = 'send-proxy' max_connections = '1000' @@ -192,6 +193,8 @@ class TestLoadBalancingReverseProxy(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + ['service', frontend, 'rule', rule_ten, 'set', 'backend', bk_first_name]) self.cli_set(base_path + ['service', frontend, 'rule', rule_twenty, 'domain-name', domain_bk_second]) self.cli_set(base_path + ['service', frontend, 'rule', rule_twenty, 'set', 'backend', bk_second_name]) + self.cli_set(base_path + ['service', frontend, 'rule', rule_thirty, 'url-path', 'end', '/test']) + self.cli_set(base_path + ['service', frontend, 'rule', rule_thirty, 'set', 'backend', bk_second_name]) self.cli_set(back_base + [bk_first_name, 'mode', mode]) self.cli_set(back_base + [bk_first_name, 'server', bk_first_name, 'address', bk_server_first]) @@ -222,6 +225,8 @@ class TestLoadBalancingReverseProxy(VyOSUnitTestSHIM.TestCase): self.assertIn(f'use_backend {bk_first_name} if {rule_ten}', config) self.assertIn(f'acl {rule_twenty} hdr(host) -i {domain_bk_second}', config) self.assertIn(f'use_backend {bk_second_name} if {rule_twenty}', config) + self.assertIn(f'acl {rule_thirty} path -i -m end /test', config) + self.assertIn(f'use_backend {bk_second_name} if {rule_thirty}', config) # Backend self.assertIn(f'backend {bk_first_name}', config) diff --git a/smoketest/scripts/cli/test_vpn_openconnect.py b/smoketest/scripts/cli/test_vpn_openconnect.py index 96e858fdb..a2e426dc7 100755 --- a/smoketest/scripts/cli/test_vpn_openconnect.py +++ b/smoketest/scripts/cli/test_vpn_openconnect.py @@ -210,6 +210,9 @@ class TestVPNOpenConnect(VyOSUnitTestSHIM.TestCase): # Verify configuration daemon_config = read_file(config_file) + # Verify TLS string (with default setting) + self.assertIn('tls-priorities = "NORMAL:%SERVER_PRECEDENCE:%COMPAT:-RSA:-VERS-SSL3.0:-ARCFOUR-128:-VERS-TLS1.0:-VERS-TLS1.1"', daemon_config) + # authentication mode local password-otp self.assertIn(f'auth = "plain[passwd=/run/ocserv/ocpasswd,otp=/run/ocserv/users.oath]"', daemon_config) self.assertIn(f'listen-host = {listen_ip_no_cidr}', daemon_config) @@ -253,5 +256,13 @@ class TestVPNOpenConnect(VyOSUnitTestSHIM.TestCase): self.assertIn('included-http-headers = Pragma: no-cache', daemon_config) self.assertIn('included-http-headers = Cache-control: no-store, no-cache', daemon_config) + # Set TLS version to the highest security (v1.3 min) + self.cli_set(base_path + ['tls-version-min', '1.3']) + self.cli_commit() + + # Verify TLS string + daemon_config = read_file(config_file) + self.assertIn('tls-priorities = "NORMAL:%SERVER_PRECEDENCE:%COMPAT:-RSA:-VERS-SSL3.0:-ARCFOUR-128:-VERS-TLS1.0:-VERS-TLS1.1:-VERS-TLS1.2"', daemon_config) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/conf_mode/interfaces_wireless.py b/src/conf_mode/interfaces_wireless.py index 02b4a2500..c0a17c0bc 100755 --- a/src/conf_mode/interfaces_wireless.py +++ b/src/conf_mode/interfaces_wireless.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2019-2020 VyOS maintainers and contributors +# Copyright (C) 2019-2024 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 @@ -31,8 +31,9 @@ from vyos.configverify import verify_vrf from vyos.configverify import verify_bond_bridge_member from vyos.ifconfig import WiFiIf from vyos.template import render -from vyos.utils.process import call from vyos.utils.dict import dict_search +from vyos.utils.kernel import check_kmod +from vyos.utils.process import call from vyos import ConfigError from vyos import airbag airbag.enable() @@ -118,6 +119,10 @@ def verify(wifi): if 'physical_device' not in wifi: raise ConfigError('You must specify a physical-device "phy"') + physical_device = wifi['physical_device'] + if not os.path.exists(f'/sys/class/ieee80211/{physical_device}'): + raise ConfigError(f'Wirelss interface PHY "{physical_device}" does not exist!') + if 'type' not in wifi: raise ConfigError('You must specify a WiFi mode') @@ -266,6 +271,7 @@ def apply(wifi): if __name__ == '__main__': try: + check_kmod('mac80211') c = get_config() verify(c) generate(c) diff --git a/src/conf_mode/service_ipoe-server.py b/src/conf_mode/service_ipoe-server.py index 11e950782..28b7fb03c 100755 --- a/src/conf_mode/service_ipoe-server.py +++ b/src/conf_mode/service_ipoe-server.py @@ -66,7 +66,7 @@ def verify(ipoe): raise ConfigError('No IPoE interface configured') for interface, iface_config in ipoe['interface'].items(): - verify_interface_exists(interface) + verify_interface_exists(interface, warning_only=True) if 'client_subnet' in iface_config and 'vlan' in iface_config: raise ConfigError('Option "client-subnet" and "vlan" are mutually exclusive, ' 'use "client-ip-pool" instead!') diff --git a/src/conf_mode/service_pppoe-server.py b/src/conf_mode/service_pppoe-server.py index b9d174933..328487985 100755 --- a/src/conf_mode/service_pppoe-server.py +++ b/src/conf_mode/service_pppoe-server.py @@ -105,7 +105,7 @@ def verify(pppoe): # Check is interface exists in the system for interface in pppoe['interface']: - verify_interface_exists(interface) + verify_interface_exists(interface, warning_only=True) return None diff --git a/src/migration-scripts/openconnect/2-to-3 b/src/migration-scripts/openconnect/2-to-3 new file mode 100755 index 000000000..e78fc8a91 --- /dev/null +++ b/src/migration-scripts/openconnect/2-to-3 @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2024 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/>. + +# T4982: Retain prior default TLS version (v1.0) when upgrading installations with existing openconnect configurations + +import sys + +from vyos.configtree import ConfigTree + +if len(sys.argv) < 2: + print("Must specify file name!") + sys.exit(1) + +file_name = sys.argv[1] + +with open(file_name, 'r') as f: + config_file = f.read() + + +config = ConfigTree(config_file) +cfg_base = ['vpn', 'openconnect'] + +# bail out early if service is unconfigured +if not config.exists(cfg_base): + sys.exit(0) + +# new default is TLS 1.2 - set explicit old default value of TLS 1.0 for upgraded configurations to keep compatibility +tls_min_path = cfg_base + ['tls-version-min'] +if not config.exists(tls_min_path): + config.set(tls_min_path, value='1.0') + +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)) + sys.exit(1) diff --git a/src/services/vyos-configd b/src/services/vyos-configd index 648a017d5..c89c486e5 100755 --- a/src/services/vyos-configd +++ b/src/services/vyos-configd @@ -236,7 +236,7 @@ def process_node_data(config, data, last: bool = False) -> int: with stdout_redirected(session_out, session_mode): result = run_script(conf_mode_scripts[script_name], config, args) - if last: + if last and result == R_SUCCESS: call_dependents(dependent_func=config.dependent_func) return result |