diff options
25 files changed, 227 insertions, 62 deletions
diff --git a/data/templates/accel-ppp/config_shaper_radius.j2 b/data/templates/accel-ppp/config_shaper_radius.j2 index 8de5f5df3..c409c3718 100644 --- a/data/templates/accel-ppp/config_shaper_radius.j2 +++ b/data/templates/accel-ppp/config_shaper_radius.j2 @@ -6,5 +6,8 @@ attr={{ authentication.radius.rate_limit.attribute }} {% if authentication.radius.rate_limit.vendor is defined and authentication.radius.rate_limit.vendor is not none %} vendor={{ authentication.radius.rate_limit.vendor }} {% endif %} +{% if authentication.radius.rate_limit.multiplier is defined and authentication.radius.rate_limit.multiplier is not none %} +rate-multiplier={{ authentication.radius.rate_limit.multiplier }} +{% endif %} {% endif %} {% endif %} diff --git a/data/templates/accel-ppp/ipoe.config.tmpl b/data/templates/accel-ppp/ipoe.config.tmpl index 9fc816a2c..476c922b8 100644 --- a/data/templates/accel-ppp/ipoe.config.tmpl +++ b/data/templates/accel-ppp/ipoe.config.tmpl @@ -127,13 +127,18 @@ bind={{ radius_source_address }} 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 }} -{% if radius_shaper_vendor %} +{% endif %} +{% if radius_shaper_multiplier %} +rate-multiplier={{ radius_shaper_multiplier }} +{% endif %} +{% if radius_shaper_vendor %} vendor={{ radius_shaper_vendor }} -{% endif %} +{% endif %} {% endif %} {% endif %} diff --git a/data/templates/dns-forwarding/recursor.conf.tmpl b/data/templates/dns-forwarding/recursor.conf.tmpl index be0778993..294b228d2 100644 --- a/data/templates/dns-forwarding/recursor.conf.tmpl +++ b/data/templates/dns-forwarding/recursor.conf.tmpl @@ -28,6 +28,11 @@ local-address={{ listen_address | join(',') }} # dnssec dnssec={{ dnssec }} +{% if dns64_prefix is defined %} +# dns64-prefix +dns64-prefix={{ dns64_prefix }} +{% endif %} + {# dns: T3277: #} {% if no_serve_rfc1918 is defined %} # serve-rfc1918 diff --git a/data/templates/netflow/uacctd.conf.tmpl b/data/templates/netflow/uacctd.conf.tmpl index 11fc76769..1ee65a28e 100644 --- a/data/templates/netflow/uacctd.conf.tmpl +++ b/data/templates/netflow/uacctd.conf.tmpl @@ -21,7 +21,7 @@ imt_mem_pools_number: 169 {% endif %} plugins: {% if templatecfg['netflow']['servers'] != none %} {% for server in templatecfg['netflow']['servers'] %} -{% if loop.last %}nfprobe[nf_{{ server['address'] }}]{% else %}nfprobe[nf_{{ server['address'] }}],{% endif %} +{% if loop.last %}nfprobe[nf_{{ server['address'] | dot_colon_to_dash }}]{% else %}nfprobe[nf_{{ server['address'] | dot_colon_to_dash }}],{% endif %} {% endfor %} {% set plugins_presented = true %} {% endif %} @@ -41,35 +41,35 @@ plugins: {% if templatecfg['netflow']['servers'] != none %} {% if templatecfg['netflow']['servers'] != none %} {% for server in templatecfg['netflow']['servers'] %} -nfprobe_receiver[nf_{{ server['address'] }}]: {{ server['address'] }}:{{ server['port'] }} -nfprobe_version[nf_{{ server['address'] }}]: {{ templatecfg['netflow']['version'] }} +nfprobe_receiver[nf_{{ server['address'] | dot_colon_to_dash }}]: {{ server['address'] | bracketize_ipv6 }}:{{ server['port'] }} +nfprobe_version[nf_{{ server['address'] | dot_colon_to_dash }}]: {{ templatecfg['netflow']['version'] }} {% if templatecfg['netflow']['engine-id'] != none %} -nfprobe_engine[nf_{{ server['address'] }}]: {{ templatecfg['netflow']['engine-id'] }} +nfprobe_engine[nf_{{ server['address'] | dot_colon_to_dash }}]: {{ templatecfg['netflow']['engine-id'] }} {% endif %} {% if templatecfg['netflow']['max-flows'] != none %} -nfprobe_maxflows[nf_{{ server['address'] }}]: {{ templatecfg['netflow']['max-flows'] }} +nfprobe_maxflows[nf_{{ server['address'] | dot_colon_to_dash }}]: {{ templatecfg['netflow']['max-flows'] }} {% endif %} {% if templatecfg['netflow']['sampling-rate'] != none %} -sampling_rate[nf_{{ server['address'] }}]: {{ templatecfg['netflow']['sampling-rate'] }} +sampling_rate[nf_{{ server['address'] | dot_colon_to_dash }}]: {{ templatecfg['netflow']['sampling-rate'] }} {% endif %} {% if templatecfg['netflow']['source-ip'] != none %} -nfprobe_source_ip[nf_{{ server['address'] }}]: {{ templatecfg['netflow']['source-ip'] }} +nfprobe_source_ip[nf_{{ server['address'] | dot_colon_to_dash }}]: {{ templatecfg['netflow']['source-ip'] }} {% endif %} {% if templatecfg['netflow']['timeout_string'] != '' %} -nfprobe_timeouts[nf_{{ server['address'] }}]: {{ templatecfg['netflow']['timeout_string'] }} +nfprobe_timeouts[nf_{{ server['address'] | dot_colon_to_dash }}]: {{ templatecfg['netflow']['timeout_string'] }} {% endif %} {% endfor %} {% endif %} {% if templatecfg['sflow']['servers'] != none %} {% for server in templatecfg['sflow']['servers'] %} -sfprobe_receiver[sf_{{ server['address'] }}]: {{ server['address'] }}:{{ server['port'] }} -sfprobe_agentip[sf_{{ server['address'] }}]: {{ templatecfg['sflow']['agent-address'] }} +sfprobe_receiver[sf_{{ server['address'] | dot_colon_to_dash }}]: {{ server['address'] | bracketize_ipv6 }}:{{ server['port'] }} +sfprobe_agentip[sf_{{ server['address'] | dot_colon_to_dash }}]: {{ templatecfg['sflow']['agent-address'] }} {% if templatecfg['sflow']['sampling-rate'] != none %} -sampling_rate[sf_{{ server['address'] }}]: {{ templatecfg['sflow']['sampling-rate'] }} +sampling_rate[sf_{{ server['address'] | dot_colon_to_dash }}]: {{ templatecfg['sflow']['sampling-rate'] }} {% endif %} {% if templatecfg['sflow']['source-address'] != none %} -sfprobe_source_ip[sf_{{ server['address'] }}]: {{ templatecfg['sflow']['source-address'] }} +sfprobe_source_ip[sf_{{ server['address'] | dot_colon_to_dash }}]: {{ templatecfg['sflow']['source-address'] }} {% endif %} {% endfor %} {% endif %} diff --git a/data/templates/ntp/ntpd.conf.tmpl b/data/templates/ntp/ntpd.conf.tmpl index e7afcc16b..30bfd575d 100644 --- a/data/templates/ntp/ntpd.conf.tmpl +++ b/data/templates/ntp/ntpd.conf.tmpl @@ -33,10 +33,17 @@ restrict {{ address|address_from_cidr }} mask {{ address|netmask_from_cidr }} no {% endfor %} {% endif %} -{% if listen_address %} +{% if listen_address is defined or interface is defined %} # NTP should listen on configured addresses only interface ignore wildcard -{% for address in listen_address %} +{% if listen_address is defined %} +{% for address in listen_address %} interface listen {{ address }} -{% endfor %} +{% endfor %} +{% endif %} +{% if interface is defined %} +{% for ifname in interface %} +interface listen {{ ifname }} +{% endfor %} +{% endif %} {% endif %} diff --git a/data/templates/vyos-hostsd/hosts.tmpl b/data/templates/vyos-hostsd/hosts.tmpl index 8b73c6e51..03662d562 100644 --- a/data/templates/vyos-hostsd/hosts.tmpl +++ b/data/templates/vyos-hostsd/hosts.tmpl @@ -17,8 +17,9 @@ ff02::2 ip6-allrouters {% for tag, taghosts in hosts.items() %} # {{ tag }} {% for host, hostprops in taghosts.items() if hostprops.address is defined %} -{{ "%-15s" | format(hostprops.address) }} {{ host }} {{ hostprops.aliases|join(' ') if hostprops.aliases is defined }} +{% for addr in hostprops.address %} +{{ "%-15s" | format(addr) }} {{ host }} {{ hostprops.aliases|join(' ') if hostprops.aliases is defined }} +{% endfor %} {% endfor %} {% endfor %} {% endif %} - diff --git a/interface-definitions/dns-domain-name.xml.in b/interface-definitions/dns-domain-name.xml.in index 2b1644609..005a55ab3 100644 --- a/interface-definitions/dns-domain-name.xml.in +++ b/interface-definitions/dns-domain-name.xml.in @@ -102,11 +102,11 @@ <constraint> <validator name="ip-address"/> </constraint> + <multi/> </properties> </leafNode> </children> </tagNode> - </children> </node> </children> diff --git a/interface-definitions/dns-forwarding.xml.in b/interface-definitions/dns-forwarding.xml.in index 5b0c87597..5a824973a 100644 --- a/interface-definitions/dns-forwarding.xml.in +++ b/interface-definitions/dns-forwarding.xml.in @@ -36,6 +36,18 @@ <multi/> </properties> </leafNode> + <leafNode name="dns64-prefix"> + <properties> + <help>Help to communicate between IPv6-only client and IPv4-only server</help> + <valueHelp> + <format>ipv6net</format> + <description>IPv6 address and /96 only prefix length</description> + </valueHelp> + <constraint> + <validator name="ipv6-prefix"/> + </constraint> + </properties> + </leafNode> <leafNode name="dnssec"> <properties> <help>DNSSEC mode (default: process-no-validate)</help> diff --git a/interface-definitions/include/accel-ppp/radius-additions-rate-limit.xml.i b/interface-definitions/include/accel-ppp/radius-additions-rate-limit.xml.i index be49fce5a..f44920c3f 100644 --- a/interface-definitions/include/accel-ppp/radius-additions-rate-limit.xml.i +++ b/interface-definitions/include/accel-ppp/radius-additions-rate-limit.xml.i @@ -21,6 +21,20 @@ <valueless /> </properties> </leafNode> + <leafNode name="multiplier"> + <properties> + <help>Shaper multiplier</help> + <valueHelp> + <format><0.001-1000></format> + <description>Shaper multiplier</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 0.001-1000 --float"/> + </constraint> + <constraintErrorMessage>Multiplier needs to be between 0.001 and 1000</constraintErrorMessage> + </properties> + <defaultValue>1</defaultValue> + </leafNode> </children> </node> <!-- include end --> diff --git a/interface-definitions/include/generic-interface-multi.xml.i b/interface-definitions/include/generic-interface-multi.xml.i new file mode 100644 index 000000000..65aae28ae --- /dev/null +++ b/interface-definitions/include/generic-interface-multi.xml.i @@ -0,0 +1,18 @@ +<!-- include start from generic-interface-multi.xml.i --> +<leafNode name="interface"> + <properties> + <help>Interface to use</help> + <completionHelp> + <script>${vyos_completion_dir}/list_interfaces.py</script> + </completionHelp> + <valueHelp> + <format>txt</format> + <description>Interface name</description> + </valueHelp> + <constraint> + <validator name="interface-name"/> + </constraint> + <multi/> + </properties> +</leafNode> +<!-- include end --> 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 bdf399d46..b9279793c 100644 --- a/interface-definitions/service_ipoe-server.xml.in +++ b/interface-definitions/service_ipoe-server.xml.in @@ -217,6 +217,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/interface-definitions/service_webproxy.xml.in b/interface-definitions/service_webproxy.xml.in index 3acac7f9d..bd5396291 100644 --- a/interface-definitions/service_webproxy.xml.in +++ b/interface-definitions/service_webproxy.xml.in @@ -488,9 +488,9 @@ <description>Name of source group</description> </valueHelp> <constraint> - <regex>^[^0-9]</regex> + <regex>^(?!-|_|\d)[a-zA-Z_][a-zA-Z0-9][\w\-\.]*</regex> </constraint> - <constraintErrorMessage>URL-filter source-group cannot start with a number!</constraintErrorMessage> + <constraintErrorMessage>URL-filter source-group must start with a letter and can contain dashes or underscores!</constraintErrorMessage> </properties> <children> <leafNode name="address"> diff --git a/op-mode-definitions/webproxy.xml.in b/op-mode-definitions/webproxy.xml.in index f8ec8fb0a..5ae1577d8 100644 --- a/op-mode-definitions/webproxy.xml.in +++ b/op-mode-definitions/webproxy.xml.in @@ -12,7 +12,7 @@ <properties> <help>Monitor the last lines of the squid access log</help> </properties> - <command>if [ -f /var/log/squid3/access.log ]; then sudo tail --follow=name /var/log/squid3/access.log; else echo "WebProxy cache-log does not exist"; fi</command> + <command>if [ -f /var/log/squid/access.log ]; then sudo tail --follow=name /var/log/squid/access.log; else echo "WebProxy access-log does not exist"; fi</command> </node> <node name="background"> <properties> @@ -37,7 +37,7 @@ <properties> <help>Monitor the last lines of the squid cache log</help> </properties> - <command>if [ -f /var/log/squid3/cache.log ]; then sudo tail --follow=name /var/log/squid3/cache.log; else echo "WebProxy cache-log does not exist"; fi</command> + <command>if [ -f /var/log/squid/cache.log ]; then sudo tail --follow=name /var/log/squid/cache.log; else echo "WebProxy cache-log does not exist"; fi</command> </node> </children> </node> diff --git a/python/vyos/template.py b/python/vyos/template.py index f9e754357..88271125c 100644 --- a/python/vyos/template.py +++ b/python/vyos/template.py @@ -151,6 +151,16 @@ def bracketize_ipv6(address): return f'[{address}]' return address +@register_filter('dot_colon_to_dash') +def dot_colon_to_dash(text): + """ Replace dot and colon to dash for string + Example: + 192.0.2.1 => 192-0-2-1, 2001:db8::1 => 2001-db8--1 + """ + text = text.replace(":", "-") + text = text.replace(".", "-") + return text + @register_filter('netmask_from_cidr') def netmask_from_cidr(prefix): """ Take CIDR prefix and convert the prefix length to a "subnet mask". diff --git a/smoketest/scripts/cli/test_service_dns_forwarding.py b/smoketest/scripts/cli/test_service_dns_forwarding.py index 44e27828d..ccbdd16ba 100755 --- a/smoketest/scripts/cli/test_service_dns_forwarding.py +++ b/smoketest/scripts/cli/test_service_dns_forwarding.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2019-2020 VyOS maintainers and contributors +# Copyright (C) 2019-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 @@ -39,7 +39,18 @@ def get_config_value(key, file=CONFIG_FILE): return tmp[0] class TestServicePowerDNS(VyOSUnitTestSHIM.TestCase): + @classmethod + def setUpClass(cls): + super(TestServicePowerDNS, cls).setUpClass() + + # ensure we can also run this test on a live system - so lets clean + # out the current configuration :) + cls.cli_delete(cls, base_path) + def tearDown(self): + # Check for running process + self.assertTrue(process_named_running(PROCESS_NAME)) + # Delete DNS forwarding configuration self.cli_delete(base_path) self.cli_commit() @@ -93,9 +104,6 @@ class TestServicePowerDNS(VyOSUnitTestSHIM.TestCase): tmp = get_config_value('export-etc-hosts') self.assertEqual(tmp, 'no') - # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) - def test_dnssec(self): # DNSSEC option testing @@ -114,9 +122,6 @@ class TestServicePowerDNS(VyOSUnitTestSHIM.TestCase): tmp = get_config_value('dnssec') self.assertEqual(tmp, option) - # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) - def test_external_nameserver(self): # Externe Domain Name Servers (DNS) addresses @@ -140,9 +145,6 @@ class TestServicePowerDNS(VyOSUnitTestSHIM.TestCase): tmp = get_config_value('export-etc-hosts') self.assertEqual(tmp, 'yes') - # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) - def test_domain_forwarding(self): for network in allow_from: self.cli_set(base_path + ['allow-from', network]) @@ -179,9 +181,26 @@ class TestServicePowerDNS(VyOSUnitTestSHIM.TestCase): if domain == domains[1]: self.assertIn(f'addNTA("{domain}", "static")', hosts_conf) - # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) + def test_dns64(self): + dns_prefix = '64:ff9b::/96' + + for network in allow_from: + self.cli_set(base_path + ['allow-from', network]) + for address in listen_adress: + self.cli_set(base_path + ['listen-address', address]) + + # Check dns64-prefix - must be prefix /96 + self.cli_set(base_path + ['dns64-prefix', '2001:db8:aabb::/64']) + with self.assertRaises(ConfigSessionError): + self.cli_commit() + self.cli_set(base_path + ['dns64-prefix', dns_prefix]) + + # commit changes + self.cli_commit() + + # verify dns64-prefix configuration + tmp = get_config_value('dns64-prefix') + self.assertEqual(tmp, dns_prefix) if __name__ == '__main__': unittest.main(verbosity=2) - diff --git a/smoketest/scripts/cli/test_system_flow-accounting.py b/smoketest/scripts/cli/test_system_flow-accounting.py index 57866a198..92a7973fa 100755 --- a/smoketest/scripts/cli/test_system_flow-accounting.py +++ b/smoketest/scripts/cli/test_system_flow-accounting.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021 VyOS maintainers and contributors +# Copyright (C) 2021-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 @@ -64,7 +64,8 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase): # verify configuration tmp = cmd('sudo iptables-save -t raw') for interface in Section.interfaces('ethernet'): - self.assertIn(f'-A VYATTA_CT_PREROUTING_HOOK -i {interface} -m comment --comment FLOW_ACCOUNTING_RULE -j NFLOG --nflog-group 2 --nflog-size 128 --nflog-threshold 100', tmp) + self.assertIn(f'-A VYATTA_CT_PREROUTING_HOOK -i {interface} -m comment --comment FLOW_ACCOUNTING_RULE -j ' + f'NFLOG --nflog-group 2 --nflog-size 128 --nflog-threshold 100', tmp) uacctd = read_file(uacctd_conf) # circular queue size - buffer_size @@ -130,14 +131,15 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase): self.assertNotIn(f'plugins: memory', uacctd) for server, server_config in sflow_server.items(): + tmp_srv = server.replace('.', '-') if 'port' in server_config: - self.assertIn(f'sfprobe_receiver[sf_{server}]: {server}', uacctd) + self.assertIn(f'sfprobe_receiver[sf_{tmp_srv}]: {server}', uacctd) else: - self.assertIn(f'sfprobe_receiver[sf_{server}]: {server}:6343', uacctd) + self.assertIn(f'sfprobe_receiver[sf_{tmp_srv}]: {server}:6343', uacctd) - self.assertIn(f'sfprobe_agentip[sf_{server}]: {agent_address}', uacctd) - self.assertIn(f'sampling_rate[sf_{server}]: {sampling_rate}', uacctd) - self.assertIn(f'sfprobe_source_ip[sf_{server}]: {source_address}', uacctd) + self.assertIn(f'sfprobe_agentip[sf_{tmp_srv}]: {agent_address}', uacctd) + self.assertIn(f'sampling_rate[sf_{tmp_srv}]: {sampling_rate}', uacctd) + self.assertIn(f'sfprobe_source_ip[sf_{tmp_srv}]: {source_address}', uacctd) self.cli_delete(['interfaces', 'dummy', dummy_if]) @@ -203,23 +205,27 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase): tmp = 'plugins: ' for server, server_config in netflow_server.items(): - tmp += f'nfprobe[nf_{server}],' + tmp_srv = server.replace('.', '-') + tmp += f'nfprobe[nf_{tmp_srv}],' tmp += 'memory' self.assertIn(f'{tmp}', uacctd) for server, server_config in netflow_server.items(): - self.assertIn(f'nfprobe_engine[nf_{server}]: {engine_id}', uacctd) - self.assertIn(f'nfprobe_maxflows[nf_{server}]: {max_flows}', uacctd) - self.assertIn(f'sampling_rate[nf_{server}]: {sampling_rate}', uacctd) - self.assertIn(f'nfprobe_source_ip[nf_{server}]: {source_address}', uacctd) - self.assertIn(f'nfprobe_version[nf_{server}]: {version}', uacctd) + tmp_srv = server.replace('.', '-') + self.assertIn(f'nfprobe_engine[nf_{tmp_srv}]: {engine_id}', uacctd) + self.assertIn(f'nfprobe_maxflows[nf_{tmp_srv}]: {max_flows}', uacctd) + self.assertIn(f'sampling_rate[nf_{tmp_srv}]: {sampling_rate}', uacctd) + self.assertIn(f'nfprobe_source_ip[nf_{tmp_srv}]: {source_address}', uacctd) + self.assertIn(f'nfprobe_version[nf_{tmp_srv}]: {version}', uacctd) if 'port' in server_config: - self.assertIn(f'nfprobe_receiver[nf_{server}]: {server}', uacctd) + self.assertIn(f'nfprobe_receiver[nf_{tmp_srv}]: {server}', uacctd) else: - self.assertIn(f'nfprobe_receiver[nf_{server}]: {server}:2055', uacctd) + self.assertIn(f'nfprobe_receiver[nf_{tmp_srv}]: {server}:2055', uacctd) - self.assertIn(f'nfprobe_timeouts[nf_{server}]: expint={tmo_expiry}:general={tmo_flow}:icmp={tmo_icmp}:maxlife={tmo_max}:tcp.fin={tmo_tcp_fin}:tcp={tmo_tcp_generic}:tcp.rst={tmo_tcp_rst}:udp={tmo_udp}', uacctd) + self.assertIn(f'nfprobe_timeouts[nf_{tmp_srv}]: expint={tmo_expiry}:general={tmo_flow}:' + f'icmp={tmo_icmp}:maxlife={tmo_max}:tcp.fin={tmo_tcp_fin}:tcp={tmo_tcp_generic}:' + f'tcp.rst={tmo_tcp_rst}:udp={tmo_udp}', uacctd) self.cli_delete(['interfaces', 'dummy', dummy_if]) diff --git a/smoketest/scripts/cli/test_system_ntp.py b/smoketest/scripts/cli/test_system_ntp.py index c8cf04b7d..0ee96157c 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 bc3821f61..3f3a2e232 100755 --- a/src/conf_mode/dns_forwarding.py +++ b/src/conf_mode/dns_forwarding.py @@ -83,6 +83,12 @@ def verify(dns): if 'server' not in dns['domain'][domain]: raise ConfigError(f'No server configured for domain {domain}!') + if 'dns64_prefix' in dns: + dns_prefix = dns['dns64_prefix'].split('/')[1] + # RFC 6147 requires prefix /96 + if int(dns_prefix) != 96: + raise ConfigError('DNS 6to4 prefix must be of length /96') + if 'system' in dns: if not 'system_name_server' in dns: print('Warning: No "system name-server" configured') diff --git a/src/conf_mode/host_name.py b/src/conf_mode/host_name.py index a7135911d..87bad0dc6 100755 --- a/src/conf_mode/host_name.py +++ b/src/conf_mode/host_name.py @@ -79,7 +79,7 @@ def get_config(config=None): # system static-host-mapping for hn in conf.list_nodes(['system', 'static-host-mapping', 'host-name']): hosts['static_host_mapping'][hn] = {} - hosts['static_host_mapping'][hn]['address'] = conf.return_value(['system', 'static-host-mapping', 'host-name', hn, 'inet']) + hosts['static_host_mapping'][hn]['address'] = conf.return_values(['system', 'static-host-mapping', 'host-name', hn, 'inet']) hosts['static_host_mapping'][hn]['aliases'] = conf.return_values(['system', 'static-host-mapping', 'host-name', hn, 'alias']) return hosts diff --git a/src/conf_mode/ntp.py b/src/conf_mode/ntp.py index 52070aabc..181c9e322 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 2ebee8018..42cfd0f12 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/op_mode/generate_public_key_command.py b/src/op_mode/generate_public_key_command.py index 7a7b6c923..f071ae350 100755 --- a/src/op_mode/generate_public_key_command.py +++ b/src/op_mode/generate_public_key_command.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021 VyOS maintainers and contributors +# 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 @@ -29,8 +29,12 @@ def get_key(path): key_string = vyos.remote.get_remote_config(path) return key_string.split() -username = sys.argv[1] -algorithm, key, identifier = get_key(sys.argv[2]) +try: + username = sys.argv[1] + algorithm, key, identifier = get_key(sys.argv[2]) +except Exception as e: + print("Failed to retrieve the public key: {}".format(e)) + sys.exit(1) print('# To add this key as an embedded key, run the following commands:') print('configure') @@ -39,3 +43,4 @@ print(f'set system login user {username} authentication public-keys {identifier} print('commit') print('save') print('exit') + diff --git a/src/services/vyos-hostsd b/src/services/vyos-hostsd index 4c4bb036e..f4b1d0fc2 100755 --- a/src/services/vyos-hostsd +++ b/src/services/vyos-hostsd @@ -317,7 +317,7 @@ hosts_add_schema = op_type_schema.extend({ 'data': { str: { str: { - 'address': str, + 'address': [str], 'aliases': [str] } } diff --git a/src/utils/vyos-hostsd-client b/src/utils/vyos-hostsd-client index d4d38315a..a0515951a 100755 --- a/src/utils/vyos-hostsd-client +++ b/src/utils/vyos-hostsd-client @@ -129,7 +129,8 @@ try: params = h.split(",") if len(params) < 2: raise ValueError("Malformed host entry") - entry['address'] = params[1] + # Address needs to be a list because of changes made in T2683 + entry['address'] = [params[1]] entry['aliases'] = params[2:] data[params[0]] = entry client.add_hosts({args.tag: data}) |