diff options
20 files changed, 318 insertions, 122 deletions
diff --git a/.github/workflows/trigger-pr-mirror-repo-sync.yml b/.github/workflows/trigger-pr-mirror-repo-sync.yml index f74895987..978be0582 100644 --- a/.github/workflows/trigger-pr-mirror-repo-sync.yml +++ b/.github/workflows/trigger-pr-mirror-repo-sync.yml @@ -6,6 +6,11 @@ on: branches: - current +permissions: + pull-requests: write + contents: write + issues: write + jobs: call-trigger-mirror-pr-repo-sync: if: github.repository_owner == 'vyos' && github.event.pull_request.merged == true diff --git a/data/templates/dhcp-client/ipv6.override.conf.j2 b/data/templates/dhcp-client/ipv6.override.conf.j2 index b0c0e0544..d270a55fc 100644 --- a/data/templates/dhcp-client/ipv6.override.conf.j2 +++ b/data/templates/dhcp-client/ipv6.override.conf.j2 @@ -4,6 +4,9 @@ [Unit] ConditionPathExists={{ dhcp6_client_dir }}/dhcp6c.%i.conf +{% if ifname.startswith('pppoe') %} +After=ppp@{{ ifname }}.service +{% endif %} [Service] ExecStart= diff --git a/data/templates/dhcp-server/kea-ctrl-agent.conf.j2 b/data/templates/dhcp-server/kea-ctrl-agent.conf.j2 deleted file mode 100644 index b37cf4798..000000000 --- a/data/templates/dhcp-server/kea-ctrl-agent.conf.j2 +++ /dev/null @@ -1,14 +0,0 @@ -{ - "Control-agent": { -{% if high_availability is vyos_defined %} - "http-host": "{{ high_availability.source_address }}", - "http-port": 647, - "control-sockets": { - "dhcp4": { - "socket-type": "unix", - "socket-name": "/run/kea/dhcp4-ctrl-socket" - } - } -{% endif %} - } -} diff --git a/data/templates/dhcp-server/kea-dhcp4.conf.j2 b/data/templates/dhcp-server/kea-dhcp4.conf.j2 index 2e10d58e0..8d9ffb194 100644 --- a/data/templates/dhcp-server/kea-dhcp4.conf.j2 +++ b/data/templates/dhcp-server/kea-dhcp4.conf.j2 @@ -25,20 +25,6 @@ }, "option-def": [ { - "name": "rfc3442-static-route", - "code": 121, - "type": "record", - "array": true, - "record-types": "uint8,uint8,uint8,uint8,uint8,uint8,uint8" - }, - { - "name": "windows-static-route", - "code": 249, - "type": "record", - "array": true, - "record-types": "uint8,uint8,uint8,uint8,uint8,uint8,uint8" - }, - { "name": "wpad-url", "code": 252, "type": "string" @@ -69,6 +55,16 @@ }, {% endif %} { + "library": "/usr/lib/{{ machine }}-linux-gnu/kea/hooks/libdhcp_ping_check.so", + "parameters": { + "enable-ping-check" : false, + "min-ping-requests" : 1, + "reply-timeout" : 100, + "ping-cltt-secs" : 60, + "ping-channel-threads" : 0 + } + }, + { "library": "/usr/lib/{{ machine }}-linux-gnu/kea/hooks/libdhcp_lease_cmds.so", "parameters": {} } diff --git a/data/templates/ipsec/swanctl/peer.j2 b/data/templates/ipsec/swanctl/peer.j2 index 3a9af2c94..cf0865c88 100644 --- a/data/templates/ipsec/swanctl/peer.j2 +++ b/data/templates/ipsec/swanctl/peer.j2 @@ -68,8 +68,19 @@ rekey_packets = 0 rekey_time = 0s {% endif %} - local_ts = 0.0.0.0/0,::/0 - remote_ts = 0.0.0.0/0,::/0 +{# set default traffic-selectors #} +{% set local_ts = '0.0.0.0/0,::/0' %} +{% set remote_ts = '0.0.0.0/0,::/0' %} +{% if peer_conf.vti.traffic_selector is vyos_defined %} +{% if peer_conf.vti.traffic_selector.local is vyos_defined and peer_conf.vti.traffic_selector.local.prefix is vyos_defined %} +{% set local_ts = peer_conf.vti.traffic_selector.local.prefix | join(',') %} +{% endif %} +{% if peer_conf.vti.traffic_selector.remote is vyos_defined and peer_conf.vti.traffic_selector.remote.prefix is vyos_defined %} +{% set remote_ts = peer_conf.vti.traffic_selector.remote.prefix | join(',') %} +{% endif %} +{% endif %} + local_ts = {{ local_ts }} + remote_ts = {{ remote_ts }} updown = "/etc/ipsec.d/vti-up-down {{ peer_conf.vti.bind }}" {# The key defaults to 0 and will match any policies which similarly do not have a lookup key configuration. #} {# Thus we simply shift the key by one to also support a vti0 interface #} diff --git a/interface-definitions/include/dhcp/ping-check.xml.i b/interface-definitions/include/dhcp/ping-check.xml.i new file mode 100644 index 000000000..a506f68e4 --- /dev/null +++ b/interface-definitions/include/dhcp/ping-check.xml.i @@ -0,0 +1,8 @@ +<!-- include start from dhcp/ping-check.xml.i --> +<leafNode name="ping-check"> + <properties> + <help>Sends ICMP Echo request to the address being assigned</help> + <valueless/> + </properties> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/service_dhcp-server.xml.in b/interface-definitions/service_dhcp-server.xml.in index 9a194de4f..c0ab7c048 100644 --- a/interface-definitions/service_dhcp-server.xml.in +++ b/interface-definitions/service_dhcp-server.xml.in @@ -112,6 +112,7 @@ </properties> </leafNode> #include <include/dhcp/option-v4.xml.i> + #include <include/dhcp/ping-check.xml.i> #include <include/generic-description.xml.i> #include <include/generic-disable-node.xml.i> <tagNode name="subnet"> @@ -128,6 +129,7 @@ </properties> <children> #include <include/dhcp/option-v4.xml.i> + #include <include/dhcp/ping-check.xml.i> #include <include/generic-description.xml.i> #include <include/generic-disable-node.xml.i> <leafNode name="exclude"> diff --git a/interface-definitions/vpn_ipsec.xml.in b/interface-definitions/vpn_ipsec.xml.in index 0cf526fad..873a4f882 100644 --- a/interface-definitions/vpn_ipsec.xml.in +++ b/interface-definitions/vpn_ipsec.xml.in @@ -1244,6 +1244,63 @@ <children> #include <include/ipsec/bind.xml.i> #include <include/ipsec/esp-group.xml.i> + <node name="traffic-selector"> + <properties> + <help>Traffic-selectors parameters</help> + </properties> + <children> + <node name="local"> + <properties> + <help>Local parameters for interesting traffic</help> + </properties> + <children> + <leafNode name="prefix"> + <properties> + <help>Local IPv4 or IPv6 prefix</help> + <valueHelp> + <format>ipv4net</format> + <description>Local IPv4 prefix</description> + </valueHelp> + <valueHelp> + <format>ipv6net</format> + <description>Local IPv6 prefix</description> + </valueHelp> + <constraint> + <validator name="ipv4-prefix"/> + <validator name="ipv6-prefix"/> + </constraint> + <multi/> + </properties> + </leafNode> + </children> + </node> + <node name="remote"> + <properties> + <help>Remote parameters for interesting traffic</help> + </properties> + <children> + <leafNode name="prefix"> + <properties> + <help>Remote IPv4 or IPv6 prefix</help> + <valueHelp> + <format>ipv4net</format> + <description>Remote IPv4 prefix</description> + </valueHelp> + <valueHelp> + <format>ipv6net</format> + <description>Remote IPv6 prefix</description> + </valueHelp> + <constraint> + <validator name="ipv4-prefix"/> + <validator name="ipv6-prefix"/> + </constraint> + <multi/> + </properties> + </leafNode> + </children> + </node> + </children> + </node> </children> </node> </children> diff --git a/op-mode-definitions/show-log.xml.in b/op-mode-definitions/show-log.xml.in index c43ceaf32..ee2e2bf70 100755 --- a/op-mode-definitions/show-log.xml.in +++ b/op-mode-definitions/show-log.xml.in @@ -50,6 +50,39 @@ </properties> <command>cat $(printf "%s\n" /var/log/messages* | sort -nr) | grep -e heartbeat -e cl_status -e mach_down -e ha_log</command> </leafNode> + <node name="conntrack"> + <properties> + <help>Show log for conntrack events</help> + </properties> + <command>journalctl --no-hostname --boot -t vyos-conntrack-logger --grep='\[(NEW|UPDATE|DESTROY)\]'</command> + <children> + <node name="event"> + <properties> + <help>Show log for conntrack events</help> + </properties> + <children> + <leafNode name="new"> + <properties> + <help>Show log for conntrack events</help> + </properties> + <command>journalctl --no-hostname --boot -t vyos-conntrack-logger --grep='\[(NEW)\]'</command> + </leafNode> + <leafNode name="update"> + <properties> + <help>Show log for conntrack events</help> + </properties> + <command>journalctl --no-hostname --boot -t vyos-conntrack-logger --grep='\[(UPDATE)\]'</command> + </leafNode> + <leafNode name="destroy"> + <properties> + <help>Show log for Conntrack Events</help> + </properties> + <command>journalctl --no-hostname --boot -t vyos-conntrack-logger --grep='\[(DESTROY)\]'</command> + </leafNode> + </children> + </node> + </children> + </node> <leafNode name="conntrack-sync"> <properties> <help>Show log for Conntrack-sync</help> @@ -126,7 +159,7 @@ <properties> <help>Show log for Firewall</help> </properties> - <command>journalctl --no-hostname --boot -k | egrep "(ipv[46]|bri)-(FWD|INP|OUT|NAM)"</command> + <command>journalctl --no-hostname --boot -k --grep='(ipv[46]|bri)-(FWD|INP|OUT|NAM)|STATE-POLICY'</command> <children> <node name="bridge"> <properties> diff --git a/op-mode-definitions/system-image.xml.in b/op-mode-definitions/system-image.xml.in index 44b055be6..847029dcd 100644 --- a/op-mode-definitions/system-image.xml.in +++ b/op-mode-definitions/system-image.xml.in @@ -193,7 +193,7 @@ <properties> <help>Show installed VyOS images</help> </properties> - <command>sudo ${vyos_op_scripts_dir}/image_info.py show_images_summary</command> + <command>${vyos_op_scripts_dir}/image_info.py show_images_summary</command> <children> <node name="details"> <properties> diff --git a/python/vyos/kea.py b/python/vyos/kea.py index de397d8f9..2b0cac7e6 100644 --- a/python/vyos/kea.py +++ b/python/vyos/kea.py @@ -21,7 +21,6 @@ from datetime import datetime from datetime import timezone from vyos.template import is_ipv6 -from vyos.template import isc_static_route from vyos.template import netmask_from_cidr from vyos.utils.dict import dict_search_args from vyos.utils.file import file_permissions @@ -113,22 +112,21 @@ def kea_parse_options(config): default_route = '' if 'default_router' in config: - default_route = isc_static_route('0.0.0.0/0', config['default_router']) + default_route = f'0.0.0.0/0 - {config["default_router"]}' routes = [ - isc_static_route(route, route_options['next_hop']) + f'{route} - {route_options["next_hop"]}' for route, route_options in config['static_route'].items() ] options.append( { - 'name': 'rfc3442-static-route', + 'name': 'classless-static-route', 'data': ', '.join( routes if not default_route else routes + [default_route] ), } ) - options.append({'name': 'windows-static-route', 'data': ', '.join(routes)}) if 'time_zone' in config: with open('/usr/share/zoneinfo/' + config['time_zone'], 'rb') as f: @@ -149,7 +147,7 @@ def kea_parse_options(config): def kea_parse_subnet(subnet, config): - out = {'subnet': subnet, 'id': int(config['subnet_id'])} + out = {'subnet': subnet, 'id': int(config['subnet_id']), 'user-context': {}} if 'option' in config: out['option-data'] = kea_parse_options(config['option']) @@ -167,6 +165,9 @@ def kea_parse_subnet(subnet, config): out['valid-lifetime'] = int(config['lease']) out['max-valid-lifetime'] = int(config['lease']) + if 'ping_check' in config: + out['user-context']['enable-ping-check'] = True + if 'range' in config: pools = [] for num, range_config in config['range'].items(): diff --git a/python/vyos/system/grub_util.py b/python/vyos/system/grub_util.py index 4a3d8795e..ad95bb4f9 100644 --- a/python/vyos/system/grub_util.py +++ b/python/vyos/system/grub_util.py @@ -56,13 +56,12 @@ def set_kernel_cmdline_options(cmdline_options: str, version: str = '', @image.if_not_live_boot def update_kernel_cmdline_options(cmdline_options: str, - root_dir: str = '') -> None: + root_dir: str = '', + version = image.get_running_image()) -> None: """Update Kernel custom cmdline options""" if not root_dir: root_dir = disk.find_persistence() - version = image.get_running_image() - boot_opts_current = grub.get_boot_opts(version, root_dir) boot_opts_proposed = grub.BOOT_OPTS_STEM + f'{version} {cmdline_options}' diff --git a/python/vyos/template.py b/python/vyos/template.py index e75db1a8d..7ba85a046 100755 --- a/python/vyos/template.py +++ b/python/vyos/template.py @@ -390,28 +390,6 @@ def compare_netmask(netmask1, netmask2): except: return False -@register_filter('isc_static_route') -def isc_static_route(subnet, router): - # https://ercpe.de/blog/pushing-static-routes-with-isc-dhcp-server - # Option format is: - # <netmask>, <network-byte1>, <network-byte2>, <network-byte3>, <router-byte1>, <router-byte2>, <router-byte3> - # where bytes with the value 0 are omitted. - from ipaddress import ip_network - net = ip_network(subnet) - # add netmask - string = str(net.prefixlen) + ',' - # add network bytes - if net.prefixlen: - width = net.prefixlen // 8 - if net.prefixlen % 8: - width += 1 - string += ','.join(map(str,tuple(net.network_address.packed)[:width])) + ',' - - # add router bytes - string += ','.join(router.split('.')) - - return string - @register_filter('is_file') def is_file(filename): if os.path.exists(filename): @@ -895,7 +873,8 @@ def kea_shared_network_json(shared_networks): network = { 'name': name, 'authoritative': ('authoritative' in config), - 'subnet4': [] + 'subnet4': [], + 'user-context': {} } if 'option' in config: @@ -907,6 +886,9 @@ def kea_shared_network_json(shared_networks): if 'bootfile_server' in config['option']: network['next-server'] = config['option']['bootfile_server'] + if 'ping_check' in config: + network['user-context']['enable-ping-check'] = True + if 'subnet' in config: for subnet, subnet_config in config['subnet'].items(): if 'disable' in subnet_config: diff --git a/smoketest/scripts/cli/test_service_dhcp-server.py b/smoketest/scripts/cli/test_service_dhcp-server.py index 7bb850b22..935be6227 100755 --- a/smoketest/scripts/cli/test_service_dhcp-server.py +++ b/smoketest/scripts/cli/test_service_dhcp-server.py @@ -32,7 +32,6 @@ from vyos.template import inc_ip from vyos.template import dec_ip PROCESS_NAME = 'kea-dhcp4' -CTRL_PROCESS_NAME = 'kea-ctrl-agent' KEA4_CONF = '/run/kea/kea-dhcp4.conf' KEA4_CTRL = '/run/kea/dhcp4-ctrl-socket' HOSTSD_CLIENT = '/usr/bin/vyos-hostsd-client' @@ -96,6 +95,10 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase): self.assertTrue(key in base_obj) self.assertEqual(base_obj[key], value) + def verify_service_running(self): + tmp = cmd('tail -n 100 /var/log/messages | grep kea') + self.assertTrue(process_named_running(PROCESS_NAME), msg=f'Service not running, log: {tmp}') + def test_dhcp_single_pool_range(self): shared_net_name = 'SMOKE-1' @@ -106,9 +109,12 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase): self.cli_set(base_path + ['listen-interface', interface]) + self.cli_set(base_path + ['shared-network-name', shared_net_name, 'ping-check']) + pool = base_path + ['shared-network-name', shared_net_name, 'subnet', subnet] self.cli_set(pool + ['subnet-id', '1']) self.cli_set(pool + ['ignore-client-id']) + self.cli_set(pool + ['ping-check']) # we use the first subnet IP address as default gateway self.cli_set(pool + ['option', 'default-router', router]) self.cli_set(pool + ['option', 'name-server', dns_1]) @@ -151,6 +157,21 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase): obj, ['Dhcp4', 'shared-networks', 0, 'subnet4'], 'max-valid-lifetime', 86400 ) + # Verify ping-check + self.verify_config_value( + obj, + ['Dhcp4', 'shared-networks', 0, 'user-context'], + 'enable-ping-check', + True + ) + + self.verify_config_value( + obj, + ['Dhcp4', 'shared-networks', 0, 'subnet4', 0, 'user-context'], + 'enable-ping-check', + True + ) + # Verify options self.verify_config_object( obj, @@ -181,7 +202,7 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase): ) # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) + self.verify_service_running() def test_dhcp_single_pool_options(self): shared_net_name = 'SMOKE-0815' @@ -221,8 +242,11 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase): pool + ['option', 'capwap-controller', capwap_access_controller] ) + static_route = '10.0.0.0/24' + static_route_nexthop = '192.0.2.1' + self.cli_set( - pool + ['option', 'static-route', '10.0.0.0/24', 'next-hop', '192.0.2.1'] + pool + ['option', 'static-route', static_route, 'next-hop', static_route_nexthop] ) self.cli_set(pool + ['option', 'ipv6-only-preferred', ipv6_only_preferred]) self.cli_set(pool + ['option', 'time-zone', 'Europe/London']) @@ -321,18 +345,13 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase): obj, ['Dhcp4', 'shared-networks', 0, 'subnet4', 0, 'option-data'], { - 'name': 'rfc3442-static-route', - 'data': '24,10,0,0,192,0,2,1, 0,192,0,2,1', + 'name': 'classless-static-route', + 'data': f'{static_route} - {static_route_nexthop}, 0.0.0.0/0 - {router}', }, ) self.verify_config_object( obj, ['Dhcp4', 'shared-networks', 0, 'subnet4', 0, 'option-data'], - {'name': 'windows-static-route', 'data': '24,10,0,0,192,0,2,1'}, - ) - self.verify_config_object( - obj, - ['Dhcp4', 'shared-networks', 0, 'subnet4', 0, 'option-data'], {'name': 'v6-only-preferred', 'data': ipv6_only_preferred}, ) self.verify_config_object( @@ -361,7 +380,7 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase): ) # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) + self.verify_service_running() def test_dhcp_single_pool_options_scoped(self): shared_net_name = 'SMOKE-2' @@ -447,7 +466,7 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase): ) # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) + self.verify_service_running() def test_dhcp_single_pool_static_mapping(self): shared_net_name = 'SMOKE-2' @@ -593,7 +612,7 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase): client_base += 1 # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) + self.verify_service_running() def test_dhcp_multiple_pools(self): lease_time = '14400' @@ -735,7 +754,7 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase): client_base += 1 # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) + self.verify_service_running() def test_dhcp_exclude_not_in_range(self): # T3180: verify else path when slicing DHCP ranges and exclude address @@ -782,7 +801,7 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase): ) # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) + self.verify_service_running() def test_dhcp_exclude_in_range(self): # T3180: verify else path when slicing DHCP ranges and exclude address @@ -845,7 +864,7 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase): ) # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) + self.verify_service_running() def test_dhcp_relay_server(self): # Listen on specific address and return DHCP leases from a non @@ -893,7 +912,7 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase): ) # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) + self.verify_service_running() def test_dhcp_high_availability(self): shared_net_name = 'FAILOVER' @@ -996,8 +1015,7 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase): ) # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) - self.assertTrue(process_named_running(CTRL_PROCESS_NAME)) + self.verify_service_running() def test_dhcp_high_availability_standby(self): shared_net_name = 'FAILOVER' @@ -1096,8 +1114,7 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase): ) # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) - self.assertTrue(process_named_running(CTRL_PROCESS_NAME)) + self.verify_service_running() def test_dhcp_on_interface_with_vrf(self): self.cli_set(['interfaces', 'ethernet', 'eth1', 'address', '10.1.1.1/30']) @@ -1259,7 +1276,7 @@ class TestServiceDHCPServer(VyOSUnitTestSHIM.TestCase): ) # Check for running process - self.assertTrue(process_named_running(PROCESS_NAME)) + self.verify_service_running() # All up and running, now test vyos-hostsd store diff --git a/smoketest/scripts/cli/test_vpn_ipsec.py b/smoketest/scripts/cli/test_vpn_ipsec.py index 91a76e6f6..c1d943bde 100755 --- a/smoketest/scripts/cli/test_vpn_ipsec.py +++ b/smoketest/scripts/cli/test_vpn_ipsec.py @@ -352,6 +352,94 @@ class TestVPNIPsec(VyOSUnitTestSHIM.TestCase): self.tearDownPKI() + def test_site_to_site_vti_ts_afi(self): + local_address = '192.0.2.10' + vti = 'vti10' + # IKE + self.cli_set(base_path + ['ike-group', ike_group, 'key-exchange', 'ikev2']) + self.cli_set(base_path + ['ike-group', ike_group, 'disable-mobike']) + # ESP + self.cli_set(base_path + ['esp-group', esp_group, 'compression']) + # VTI interface + self.cli_set(vti_path + [vti, 'address', '10.1.1.1/24']) + + # vpn ipsec auth psk <tag> id <x.x.x.x> + self.cli_set(base_path + ['authentication', 'psk', connection_name, 'id', local_id]) + self.cli_set(base_path + ['authentication', 'psk', connection_name, 'id', remote_id]) + self.cli_set(base_path + ['authentication', 'psk', connection_name, 'id', peer_ip]) + self.cli_set(base_path + ['authentication', 'psk', connection_name, 'secret', secret]) + + # Site to site + peer_base_path = base_path + ['site-to-site', 'peer', connection_name] + self.cli_set(peer_base_path + ['authentication', 'mode', 'pre-shared-secret']) + self.cli_set(peer_base_path + ['connection-type', 'none']) + self.cli_set(peer_base_path + ['force-udp-encapsulation']) + self.cli_set(peer_base_path + ['ike-group', ike_group]) + self.cli_set(peer_base_path + ['default-esp-group', esp_group]) + self.cli_set(peer_base_path + ['local-address', local_address]) + self.cli_set(peer_base_path + ['remote-address', peer_ip]) + self.cli_set(peer_base_path + ['vti', 'bind', vti]) + self.cli_set(peer_base_path + ['vti', 'esp-group', esp_group]) + self.cli_set(peer_base_path + ['vti', 'traffic-selector', 'local', 'prefix', '0.0.0.0/0']) + self.cli_set(peer_base_path + ['vti', 'traffic-selector', 'remote', 'prefix', '192.0.2.1/32']) + self.cli_set(peer_base_path + ['vti', 'traffic-selector', 'remote', 'prefix', '192.0.2.3/32']) + + self.cli_commit() + + swanctl_conf = read_file(swanctl_file) + if_id = vti.lstrip('vti') + # The key defaults to 0 and will match any policies which similarly do + # not have a lookup key configuration - thus we shift the key by one + # to also support a vti0 interface + if_id = str(int(if_id) +1) + swanctl_conf_lines = [ + f'version = 2', + f'auth = psk', + f'proposals = aes128-sha1-modp1024', + f'esp_proposals = aes128-sha1-modp1024', + f'local_addrs = {local_address} # dhcp:no', + f'mobike = no', + f'remote_addrs = {peer_ip}', + f'mode = tunnel', + f'local_ts = 0.0.0.0/0', + f'remote_ts = 192.0.2.1/32,192.0.2.3/32', + f'ipcomp = yes', + f'start_action = none', + f'replay_window = 32', + f'if_id_in = {if_id}', # will be 11 for vti10 - shifted by one + f'if_id_out = {if_id}', + f'updown = "/etc/ipsec.d/vti-up-down {vti}"' + ] + for line in swanctl_conf_lines: + self.assertIn(line, swanctl_conf) + + # Check IPv6 TS + self.cli_delete(peer_base_path + ['vti', 'traffic-selector']) + self.cli_set(peer_base_path + ['vti', 'traffic-selector', 'local', 'prefix', '::/0']) + self.cli_set(peer_base_path + ['vti', 'traffic-selector', 'remote', 'prefix', '::/0']) + self.cli_commit() + swanctl_conf = read_file(swanctl_file) + swanctl_conf_lines = [ + f'local_ts = ::/0', + f'remote_ts = ::/0', + f'updown = "/etc/ipsec.d/vti-up-down {vti}"' + ] + for line in swanctl_conf_lines: + self.assertIn(line, swanctl_conf) + + # Check both TS (IPv4 + IPv6) + self.cli_delete(peer_base_path + ['vti', 'traffic-selector']) + self.cli_commit() + swanctl_conf = read_file(swanctl_file) + swanctl_conf_lines = [ + f'local_ts = 0.0.0.0/0,::/0', + f'remote_ts = 0.0.0.0/0,::/0', + f'updown = "/etc/ipsec.d/vti-up-down {vti}"' + ] + for line in swanctl_conf_lines: + self.assertIn(line, swanctl_conf) + + def test_dmvpn(self): ike_lifetime = '3600' esp_lifetime = '1800' diff --git a/src/conf_mode/service_dhcp-server.py b/src/conf_mode/service_dhcp-server.py index 5a729af74..e46d916fd 100755 --- a/src/conf_mode/service_dhcp-server.py +++ b/src/conf_mode/service_dhcp-server.py @@ -41,7 +41,6 @@ from vyos import airbag airbag.enable() -ctrl_config_file = '/run/kea/kea-ctrl-agent.conf' ctrl_socket = '/run/kea/dhcp4-ctrl-socket' config_file = '/run/kea/kea-dhcp4.conf' lease_file = '/config/dhcp/dhcp4-leases.csv' @@ -480,13 +479,6 @@ def generate(dhcp): dhcp['high_availability']['ca_cert_file'] = ca_cert_file render( - ctrl_config_file, - 'dhcp-server/kea-ctrl-agent.conf.j2', - dhcp, - user=user_group, - group=user_group, - ) - render( config_file, 'dhcp-server/kea-dhcp4.conf.j2', dhcp, @@ -498,7 +490,7 @@ def generate(dhcp): def apply(dhcp): - services = ['kea-ctrl-agent', 'kea-dhcp4-server', 'kea-dhcp-ddns-server'] + services = ['kea-dhcp4-server', 'kea-dhcp-ddns-server'] if not dhcp or 'disable' in dhcp: for service in services: @@ -515,9 +507,6 @@ def apply(dhcp): if service == 'kea-dhcp-ddns-server' and 'dynamic_dns_update' not in dhcp: action = 'stop' - if service == 'kea-ctrl-agent' and 'high_availability' not in dhcp: - action = 'stop' - call(f'systemctl {action} {service}.service') return None diff --git a/src/conf_mode/system_option.py b/src/conf_mode/system_option.py index 064a1aa91..b45a9d8a6 100755 --- a/src/conf_mode/system_option.py +++ b/src/conf_mode/system_option.py @@ -122,6 +122,10 @@ def generate(options): render(ssh_config, 'system/ssh_config.j2', options) render(usb_autosuspend, 'system/40_usb_autosuspend.j2', options) + # XXX: This code path and if statements must be kept in sync with the Kernel + # option handling in image_installer.py:get_cli_kernel_options(). This + # occurance is used for having the appropriate options passed to GRUB + # when re-configuring options on the CLI. cmdline_options = [] if 'kernel' in options: if 'disable_mitigations' in options['kernel']: @@ -131,8 +135,7 @@ def generate(options): if 'amd_pstate_driver' in options['kernel']: mode = options['kernel']['amd_pstate_driver'] cmdline_options.append( - f'initcall_blacklist=acpi_cpufreq_init amd_pstate={mode}' - ) + f'initcall_blacklist=acpi_cpufreq_init amd_pstate={mode}') grub_util.update_kernel_cmdline_options(' '.join(cmdline_options)) return None diff --git a/src/etc/systemd/system/kea-ctrl-agent.service.d/override.conf b/src/etc/systemd/system/kea-ctrl-agent.service.d/override.conf deleted file mode 100644 index c74fafb42..000000000 --- a/src/etc/systemd/system/kea-ctrl-agent.service.d/override.conf +++ /dev/null @@ -1,10 +0,0 @@ -[Unit] -After= -After=vyos-router.service -ConditionFileNotEmpty= - -[Service] -ExecStart= -ExecStart=/usr/sbin/kea-ctrl-agent -c /run/kea/kea-ctrl-agent.conf -AmbientCapabilities=CAP_NET_BIND_SERVICE -CapabilityBoundingSet=CAP_NET_BIND_SERVICE diff --git a/src/migration-scripts/dhcp-server/7-to-8 b/src/migration-scripts/dhcp-server/7-to-8 index 7fcb62e86..d0f9455bb 100644 --- a/src/migration-scripts/dhcp-server/7-to-8 +++ b/src/migration-scripts/dhcp-server/7-to-8 @@ -41,9 +41,6 @@ def migrate(config: ConfigTree) -> None: for network in config.list_nodes(base + ['shared-network-name']): base_network = base + ['shared-network-name', network] - if config.exists(base_network + ['ping-check']): - config.delete(base_network + ['ping-check']) - if config.exists(base_network + ['shared-network-parameters']): config.delete(base_network +['shared-network-parameters']) @@ -57,9 +54,6 @@ def migrate(config: ConfigTree) -> None: if config.exists(base_subnet + ['enable-failover']): config.delete(base_subnet + ['enable-failover']) - if config.exists(base_subnet + ['ping-check']): - config.delete(base_subnet + ['ping-check']) - if config.exists(base_subnet + ['subnet-parameters']): config.delete(base_subnet + ['subnet-parameters']) diff --git a/src/op_mode/image_installer.py b/src/op_mode/image_installer.py index 179913f15..2660309a5 100755 --- a/src/op_mode/image_installer.py +++ b/src/op_mode/image_installer.py @@ -24,7 +24,9 @@ from glob import glob from sys import exit from os import environ from os import readlink -from os import getpid, getppid +from os import getpid +from os import getppid +from json import loads from typing import Union from urllib.parse import urlparse from passlib.hosts import linux_context @@ -35,15 +37,23 @@ from psutil import disk_partitions from vyos.base import Warning from vyos.configtree import ConfigTree from vyos.remote import download -from vyos.system import disk, grub, image, compat, raid, SYSTEM_CFG_VER +from vyos.system import disk +from vyos.system import grub +from vyos.system import image +from vyos.system import compat +from vyos.system import raid +from vyos.system import SYSTEM_CFG_VER +from vyos.system import grub_util from vyos.template import render from vyos.utils.auth import ( DEFAULT_PASSWORD, EPasswdStrength, evaluate_strength ) +from vyos.utils.dict import dict_search from vyos.utils.io import ask_input, ask_yes_no, select_entry from vyos.utils.file import chmod_2775 +from vyos.utils.file import read_file from vyos.utils.process import cmd, run, rc_cmd from vyos.version import get_version_data @@ -477,6 +487,25 @@ def setup_grub(root_dir: str) -> None: render(grub_cfg_menu, grub.TMPL_GRUB_MENU, {}) render(grub_cfg_options, grub.TMPL_GRUB_OPTS, {}) +def get_cli_kernel_options(config_file: str) -> list: + config = ConfigTree(read_file(config_file)) + config_dict = loads(config.to_json()) + kernel_options = dict_search('system.option.kernel', config_dict) + cmdline_options = [] + + # XXX: This code path and if statements must be kept in sync with the Kernel + # option handling in system_options.py:generate(). This occurance is used + # for having the appropriate options passed to GRUB after an image upgrade! + if 'disable-mitigations' in kernel_options: + cmdline_options.append('mitigations=off') + if 'disable-power-saving' in kernel_options: + cmdline_options.append('intel_idle.max_cstate=0 processor.max_cstate=1') + if 'amd-pstate-driver' in kernel_options: + mode = kernel_options['amd-pstate-driver'] + cmdline_options.append( + f'initcall_blacklist=acpi_cpufreq_init amd_pstate={mode}') + + return cmdline_options def configure_authentication(config_file: str, password: str) -> None: """Write encrypted password to config file @@ -491,10 +520,7 @@ def configure_authentication(config_file: str, password: str) -> None: plaintext exposed """ encrypted_password = linux_context.hash(password) - - with open(config_file) as f: - config_string = f.read() - + config_string = read_file(config_file) config = ConfigTree(config_string) config.set([ 'system', 'login', 'user', 'vyos', 'authentication', @@ -1045,6 +1071,12 @@ def add_image(image_path: str, vrf: str = None, username: str = '', if set_as_default: grub.set_default(image_name, root_dir) + cmdline_options = get_cli_kernel_options( + f'{target_config_dir}/config.boot') + grub_util.update_kernel_cmdline_options(' '.join(cmdline_options), + root_dir=root_dir, + version=image_name) + except OSError as e: # if no space error, remove image dir and cleanup if e.errno == ENOSPC: |