Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-proton-vpn-killswitch-network-manager for openSUSE:Factory checked in at 2024-05-22 21:33:10 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-proton-vpn-killswitch-network-manager (Old) and /work/SRC/openSUSE:Factory/.python-proton-vpn-killswitch-network-manager.new.1880 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-proton-vpn-killswitch-network-manager" Wed May 22 21:33:10 2024 rev:2 rq:1175825 version:0.4.4 Changes: -------- --- /work/SRC/openSUSE:Factory/python-proton-vpn-killswitch-network-manager/python-proton-vpn-killswitch-network-manager.changes 2024-03-21 17:00:45.805097873 +0100 +++ /work/SRC/openSUSE:Factory/.python-proton-vpn-killswitch-network-manager.new.1880/python-proton-vpn-killswitch-network-manager.changes 2024-05-22 21:33:34.164376436 +0200 @@ -1,0 +2,6 @@ +Wed May 22 11:40:07 UTC 2024 - Alexandre Vicenzi <alexandre.vice...@suse.com> + +- Update to 0.4.4 + * Fix random crashes when enabling/disabling the kill switch + +------------------------------------------------------------------- Old: ---- v0.4.3.tar.gz New: ---- v0.4.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-proton-vpn-killswitch-network-manager.spec ++++++ --- /var/tmp/diff_new_pack.3lqpE5/_old 2024-05-22 21:33:35.228415354 +0200 +++ /var/tmp/diff_new_pack.3lqpE5/_new 2024-05-22 21:33:35.228415354 +0200 @@ -19,7 +19,7 @@ %define skip_python2 1 %{?sle15_python_module_pythons} Name: python-proton-vpn-killswitch-network-manager -Version: 0.4.3 +Version: 0.4.4 Release: 0 Summary: Proton VPN kill switch interface using NetworkManager License: GPL-3.0-or-later ++++++ v0.4.3.tar.gz -> v0.4.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-proton-vpn-killswitch-network-manager-0.4.3/debian/changelog new/python-proton-vpn-killswitch-network-manager-0.4.4/debian/changelog --- old/python-proton-vpn-killswitch-network-manager-0.4.3/debian/changelog 2024-03-06 10:45:22.000000000 +0100 +++ new/python-proton-vpn-killswitch-network-manager-0.4.4/debian/changelog 2024-04-30 15:26:05.000000000 +0200 @@ -1,3 +1,9 @@ +proton-vpn-killswitch-network-manager (0.4.4) unstable; urgency=medium + + * Fix random crashes when enabling/disabling the kill switch + + -- Josep Llaneras <josep.llane...@proton.ch> Tue, 30 Apr 2024 15:24:53 +0200 + proton-vpn-killswitch-network-manager (0.4.3) unstable; urgency=medium * Fix crash on older distros when disabling connectivity checking diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-proton-vpn-killswitch-network-manager-0.4.3/integration/run.sh new/python-proton-vpn-killswitch-network-manager-0.4.4/integration/run.sh --- old/python-proton-vpn-killswitch-network-manager-0.4.3/integration/run.sh 2024-03-06 10:45:22.000000000 +0100 +++ new/python-proton-vpn-killswitch-network-manager-0.4.4/integration/run.sh 1970-01-01 01:00:00.000000000 +0100 @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -if [[ "$CI" == "true" ]] -then - # Only run these commands in CI - # The following dir is required by the system bus dbus daemon. - sudo mkdir -p /var/run/dbus - # Run system bus dbus daemon as it's required by NetworkManager. - sudo dbus-daemon --config-file=/usr/share/dbus-1/system.conf --print-address - # Run network manager as it's required by the integration tests. - NetworkManager -fi - -python3 -m pytest tests/integration/test_killswitch_connection.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-proton-vpn-killswitch-network-manager-0.4.3/integration/test_killswitch_connection.py new/python-proton-vpn-killswitch-network-manager-0.4.4/integration/test_killswitch_connection.py --- old/python-proton-vpn-killswitch-network-manager-0.4.3/integration/test_killswitch_connection.py 2024-03-06 10:45:22.000000000 +0100 +++ new/python-proton-vpn-killswitch-network-manager-0.4.4/integration/test_killswitch_connection.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,98 +0,0 @@ -import os - -import pytest -import subprocess - -from proton.vpn.killswitch.backend.linux.networkmanager.killswitch_connection import ( - KillSwitchConfig, KillSwitchConnectionHandler) -from proton.vpn.killswitch.interface.exceptions import KillSwitchException - - -TEST_HUMAN_READEABLE_ID = "test-pvpn-killswitch" -TEST_INTERFACE_NAME = "testpvpn0" - - -def _assert_connection_exist(): - output = int(os.system(f"nmcli -g GENERAL.STATE c s \"{TEST_HUMAN_READEABLE_ID}\"")) - assert output == 0 - - -def _assert_connection_does_not_exist(): - output = int(os.system(f"nmcli -g GENERAL.STATE c s \"{TEST_HUMAN_READEABLE_ID}\"")) - assert output != 0 - - -def _nmcli_del_connection(): - os.system(f"nmcli c del {TEST_HUMAN_READEABLE_ID}") - - -class TestIntegrationKillSwitchConnectionHandler: - def setup_class(cls): - _nmcli_del_connection() - _assert_connection_does_not_exist() - - def teardown_class(cls): - _nmcli_del_connection() - _assert_connection_does_not_exist() - - @pytest.fixture - def cleanup_env(self): - yield {} - _nmcli_del_connection() - _assert_connection_does_not_exist() - - @pytest.fixture - def test_killswitch_config(self): - cfg = KillSwitchConfig() - cfg.human_readable_id = TEST_HUMAN_READEABLE_ID - cfg.interface_name = TEST_INTERFACE_NAME - yield cfg - - def _nmcli_add_connection(self): - os.system(f"nmcli c a type dummy ifname {TEST_INTERFACE_NAME} con-name {TEST_HUMAN_READEABLE_ID}") - - def get_ipv4_addresses(self): - nmcli_string = f"nmcli -g ipv4.addresses c s {TEST_HUMAN_READEABLE_ID}" - ipv4_addresses = subprocess.check_output(nmcli_string.split(" ")).decode().strip("\n").split(",") - ipv4_addresses = tuple([addr.replace(" ", "") for addr in ipv4_addresses]) - return ipv4_addresses - - @pytest.mark.parametrize("arg", [None, KillSwitchConfig()]) - def test_init_expected_args(self, arg): - KillSwitchConnectionHandler(arg) - - @pytest.mark.parametrize("arg", [False, "TestString"]) - def test_init_with_raises_exception(self, arg): - with pytest.raises(TypeError): - KillSwitchConnectionHandler(arg) - - def test_add_and_remove_connection(self, cleanup_env, test_killswitch_config): - handler = KillSwitchConnectionHandler(test_killswitch_config) - handler.add() - _assert_connection_exist() - handler.remove() - _assert_connection_does_not_exist() - - def test_update_connection(self, cleanup_env, test_killswitch_config): - handler = KillSwitchConnectionHandler(test_killswitch_config) - handler.add() - ipv4_addresses = self.get_ipv4_addresses() - handler.update("192.168.1.1") - updated_ipv4_addresses = self.get_ipv4_addresses() - assert ipv4_addresses != updated_ipv4_addresses - - def test_add_connection_and_connection_exists_raises_exception(self, cleanup_env, test_killswitch_config): - self._nmcli_add_connection() - handler = KillSwitchConnectionHandler(test_killswitch_config) - with pytest.raises(KillSwitchException): - handler.add() - - def test_update_connection_and_connection_does_not_exist_raises_exception(self, cleanup_env, test_killswitch_config): - handler = KillSwitchConnectionHandler(test_killswitch_config) - with pytest.raises(KillSwitchException): - handler.update("192.149.1.1") - - def test_remove_connection_and_connection_does_not_exist_raises_exception(self, cleanup_env, test_killswitch_config): - handler = KillSwitchConnectionHandler(test_killswitch_config) - with pytest.raises(KillSwitchException): - handler.remove() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-proton-vpn-killswitch-network-manager-0.4.3/proton/vpn/killswitch/backend/linux/networkmanager/killswitch_connection_handler.py new/python-proton-vpn-killswitch-network-manager-0.4.4/proton/vpn/killswitch/backend/linux/networkmanager/killswitch_connection_handler.py --- old/python-proton-vpn-killswitch-network-manager-0.4.3/proton/vpn/killswitch/backend/linux/networkmanager/killswitch_connection_handler.py 2024-03-06 10:45:22.000000000 +0100 +++ new/python-proton-vpn-killswitch-network-manager-0.4.4/proton/vpn/killswitch/backend/linux/networkmanager/killswitch_connection_handler.py 2024-04-30 15:26:05.000000000 +0200 @@ -32,11 +32,11 @@ logger = logging.getLogger(__name__) -def _get_connection_id(permanent: bool, ipv6: bool = False, routed: bool = False): +def _get_connection_id(prefix: str, permanent: bool, ipv6: bool = False, routed: bool = False): if ipv6: - return f"pvpn-killswitch-ipv6{'-perm' if permanent else ''}" + return f"{prefix}-killswitch-ipv6{'-perm' if permanent else ''}" - return f"pvpn{'-routed' if routed else ''}-killswitch{'-perm' if permanent else ''}" + return f"{prefix}{'-routed' if routed else ''}-killswitch{'-perm' if permanent else ''}" def _get_interface_name(permanent: bool, ipv6: bool = False, routed: bool = False): @@ -57,8 +57,9 @@ class KillSwitchConnectionHandler: """Kill switch connection management.""" - def __init__(self, nm_client: NMClient = None): + def __init__(self, nm_client: NMClient = None, connection_prefix: str = None): self._nm_client = nm_client + self._connection_prefix = connection_prefix or "pvpn" self._ipv6_ks_settings = KillSwitchIPConfig( addresses=["fdeb:446c:912d:08da::/64"], dns=["::1"], @@ -80,7 +81,7 @@ return KillSwitchIPConfig( addresses=["100.85.0.1/24"], - dns=["0.0.0.0"], + dns=["0.0.0.0"], # nosec hardcoded_bind_all_interfaces dns_priority=-1400, gateway=gateway, ignore_auto_dns=True, @@ -112,7 +113,7 @@ require to be bonded to the VPN interface..""" await self._ensure_connectivity_check_is_disabled() - connection_id = _get_connection_id(permanent) + connection_id = _get_connection_id(self._connection_prefix, permanent) connection = self.nm_client.get_active_connection( conn_id=connection_id ) @@ -135,9 +136,10 @@ await _wrap_future( self.nm_client.add_connection_async(kill_switch.connection, save_to_disk=permanent) ) + logger.debug(f"{'Permanent' if permanent else 'Non-permanent'} kill switch added.") await self._remove_connection( - connection_id=_get_connection_id(permanent=not permanent) + connection_id=_get_connection_id(self._connection_prefix, permanent=not permanent) ) logger.debug(f"{'Non-permanent' if permanent else 'Permanent'} kill switch removed.") @@ -152,7 +154,7 @@ await self._ensure_connectivity_check_is_disabled() general_config = KillSwitchGeneralConfig( - human_readable_id=_get_connection_id(permanent, routed=True), + human_readable_id=_get_connection_id(self._connection_prefix, permanent, routed=True), interface_name=_get_interface_name(permanent, routed=True) ) kill_switch = KillSwitchConnection( @@ -170,7 +172,9 @@ to prevent IPv6 leaks while using IPv4.""" await self._ensure_connectivity_check_is_disabled() - connection_id = _get_connection_id(permanent=False, ipv6=True) + connection_id = _get_connection_id( + self._connection_prefix, permanent=False, ipv6=True + ) connection = self.nm_client.get_active_connection( conn_id=connection_id) @@ -198,21 +202,31 @@ async def remove_full_killswitch_connection(self): """Removes full kill switch connection.""" logger.debug("Removing full kill switch...") - await self._remove_connection(_get_connection_id(permanent=True)) - await self._remove_connection(_get_connection_id(permanent=False)) + await self._remove_connection( + _get_connection_id(self._connection_prefix, permanent=True) + ) + await self._remove_connection( + _get_connection_id(self._connection_prefix, permanent=False) + ) logger.debug("Full kill switch removed.") async def remove_routed_killswitch_connection(self): """Removes routed kill switch connection.""" logger.debug("Removing routed kill switch...") - await self._remove_connection(_get_connection_id(permanent=True, routed=True)) - await self._remove_connection(_get_connection_id(permanent=False, routed=True)) + await self._remove_connection( + _get_connection_id(self._connection_prefix, permanent=True, routed=True) + ) + await self._remove_connection( + _get_connection_id(self._connection_prefix, permanent=False, routed=True) + ) logger.debug("Routed kill switch removed.") async def remove_ipv6_leak_protection(self): """Removes IPv6 kill switch connection.""" logger.debug("Removing IPv6 leak protection...") - await self._remove_connection(_get_connection_id(permanent=False, ipv6=True)) + await self._remove_connection( + _get_connection_id(self._connection_prefix, permanent=False, ipv6=True) + ) logger.debug("IP6 leak protection removed.") async def _remove_connection(self, connection_id: str): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-proton-vpn-killswitch-network-manager-0.4.3/proton/vpn/killswitch/backend/linux/networkmanager/nmclient.py new/python-proton-vpn-killswitch-network-manager-0.4.4/proton/vpn/killswitch/backend/linux/networkmanager/nmclient.py --- old/python-proton-vpn-killswitch-network-manager-0.4.3/proton/vpn/killswitch/backend/linux/networkmanager/nmclient.py 2024-03-06 10:45:22.000000000 +0100 +++ new/python-proton-vpn-killswitch-network-manager-0.4.4/proton/vpn/killswitch/backend/linux/networkmanager/nmclient.py 2024-04-30 15:26:05.000000000 +0200 @@ -106,7 +106,8 @@ For more info: https://developer.gnome.org/documentation/tutorials/main-contexts.html#checking-threading """ - assert cls._main_context.is_owner() + if not cls._main_context.is_owner(): + raise RuntimeError("Code being run outside GLib's main loop.") @classmethod def _run_on_glib_loop_thread(cls, function, *args, **kwargs) -> Future: @@ -137,28 +138,32 @@ """ future_conn_activated = _create_future() - def _on_connection_added(nm_client, res, _user_data): + def _on_interface_state_changed(_device, new_state, _old_state, _reason): + """ + Monitors kill switch interface state changes and resolves + the future as soon as the interface reaches the activated state + """ + logger.debug( + f"{connection.get_interface_name()} interface state changed " + f"to {NM.DeviceState(new_state).value_name}" + ) if ( - not nm_client or not res or - not (remote_connection := nm_client.add_connection_finish(res)) + NM.DeviceState(new_state) == NM.DeviceState.ACTIVATED + and not future_conn_activated.done() ): - future_conn_activated.set_exception( - RuntimeError(f"Error setting adding KS connection: {nm_client=}, {res=}") - ) - return + future_conn_activated.set_result(None) - def _on_interface_state_changed(_device, new_state, _old_state, _reason): - logger.debug( - f"{remote_connection.get_interface_name()} interface state changed " - f"to {NM.DeviceState(new_state).value_name}" - ) - if ( - NM.DeviceState(new_state) == NM.DeviceState.ACTIVATED - and not future_conn_activated.done() - ): - future_conn_activated.set_result(remote_connection) + def _on_interface_added(_nm_client, device): + """ + Monitors interface creation. As soon as the kill switch interface + is created it sets up the call back to monitor interface state changes. + """ + logger.debug( + f"{device.get_iface()} interface added in state {device.get_state().value_name}" + ) + if not device.get_iface() == connection.get_interface_name(): + return - device = self._nm_client.get_device_by_iface(remote_connection.get_interface_name()) handler_id = device.connect("state-changed", _on_interface_state_changed) future_conn_activated.add_done_callback( lambda f: self._run_on_glib_loop_thread( @@ -166,11 +171,29 @@ ).result() ) - # The callback is manually called here because sometimes is never called. I assume that - # when we connect to the state-changes signal the interface has already been activated. - _on_interface_state_changed(device, device.get_state().real, None, None) + def _on_connection_added(nm_client, res, _user_data): + try: + # Make sure exceptions creating the connection are passed to the future. + nm_client.add_connection_finish(res) + except Exception as exc: # pylint: disable=broad-except + future_conn_activated.set_exception( + RuntimeError( + f"Error setting adding KS connection: {nm_client=}, {res=}" + ).with_traceback(exc.__traceback__) + ) + return def _add_connection_async(): + # Set up interface connection monitoring, which resolves the future + # once the kill switch is active. + handler_id = self._nm_client.connect("device-added", _on_interface_added) + future_conn_activated.add_done_callback( + lambda f: self._run_on_glib_loop_thread( + GObject.signal_handler_disconnect, self._nm_client, handler_id + ).result() + ) + + # Add kill switch connection asynchronously. self._nm_client.add_connection_async( connection=connection, save_to_disk=save_to_disk, @@ -195,29 +218,27 @@ future_interface_removed = _create_future() def _on_connection_removed(connection, result, _user_data): - if not connection or not result or not connection.delete_finish(result): + try: + connection.delete_finish(result) + except Exception as exc: # pylint: disable=broad-except future_interface_removed.set_exception( - RuntimeError(f"Error removing KS connection: {connection=}, {result=}") + RuntimeError( + f"Error removing KS connection: {connection=}, {result=}" + ).with_traceback(exc.__traceback__) ) - return - def _on_interface_state_changed(device, new_state, _old_state, _reason): + def _on_interface_removed(_nm_client, device): logger.debug( - f"{device.get_iface()} interface state changed to " - f"{NM.DeviceState(new_state).value_name}" + f"{device.get_iface()} was removed." ) - if ( - NM.DeviceState(new_state) == NM.DeviceState.DISCONNECTED - and not future_interface_removed.done() - ): + if device.get_iface() == connection.get_interface_name(): future_interface_removed.set_result(None) def _remove_connection_async(): - device = self._nm_client.get_device_by_iface(connection.get_interface_name()) - handler_id = device.connect("state-changed", _on_interface_state_changed) + handler_id = self._nm_client.connect("device-removed", _on_interface_removed) future_interface_removed.add_done_callback( lambda f: self._run_on_glib_loop_thread( - GObject.signal_handler_disconnect, device, handler_id + GObject.signal_handler_disconnect, self._nm_client, handler_id ).result() ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-proton-vpn-killswitch-network-manager-0.4.3/rpmbuild/SPECS/package.spec new/python-proton-vpn-killswitch-network-manager-0.4.4/rpmbuild/SPECS/package.spec --- old/python-proton-vpn-killswitch-network-manager-0.4.3/rpmbuild/SPECS/package.spec 2024-03-06 10:45:22.000000000 +0100 +++ new/python-proton-vpn-killswitch-network-manager-0.4.4/rpmbuild/SPECS/package.spec 2024-04-30 15:26:05.000000000 +0200 @@ -1,5 +1,5 @@ %define unmangled_name proton-vpn-killswitch-network-manager -%define version 0.4.3 +%define version 0.4.4 %define release 1 Prefix: %{_prefix} @@ -52,6 +52,9 @@ %defattr(-,root,root) %changelog +* Tue Apr 30 2024 Josep Llaneras <josep.llane...@proton.ch> 0.4.4 +- Fix random crashes when enabling/disabling the kill switch + * Wed Mar 06 2024 Josep Llaneras <josep.llane...@proton.ch> 0.4.3 - Fix crash on older distros when disabling connectivity checking diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-proton-vpn-killswitch-network-manager-0.4.3/setup.py new/python-proton-vpn-killswitch-network-manager-0.4.4/setup.py --- old/python-proton-vpn-killswitch-network-manager-0.4.3/setup.py 2024-03-06 10:45:22.000000000 +0100 +++ new/python-proton-vpn-killswitch-network-manager-0.4.4/setup.py 2024-04-30 15:26:05.000000000 +0200 @@ -4,7 +4,7 @@ setup( name="proton-vpn-killswitch-network-manager", - version="0.4.3", + version="0.4.4", description="Proton Technologies VPN connector for linux", author="Proton Technologies", author_email="cont...@protonmail.com", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-proton-vpn-killswitch-network-manager-0.4.3/tests/integration/run.sh new/python-proton-vpn-killswitch-network-manager-0.4.4/tests/integration/run.sh --- old/python-proton-vpn-killswitch-network-manager-0.4.3/tests/integration/run.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/python-proton-vpn-killswitch-network-manager-0.4.4/tests/integration/run.sh 2024-04-30 15:26:05.000000000 +0200 @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +if [[ "$CI" == "true" ]] +then + # Only run these commands in CI + # The following dir is required by the system bus dbus daemon. + sudo mkdir -p /var/run/dbus + # Run system bus dbus daemon as it's required by NetworkManager. + sudo dbus-daemon --config-file=/usr/share/dbus-1/system.conf --print-address + # Run network manager as it's required by the integration tests. + NetworkManager +fi + +python3 -m pytest tests/integration/test_killswitch_connection.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/python-proton-vpn-killswitch-network-manager-0.4.3/tests/integration/test_killswitch_connection.py new/python-proton-vpn-killswitch-network-manager-0.4.4/tests/integration/test_killswitch_connection.py --- old/python-proton-vpn-killswitch-network-manager-0.4.3/tests/integration/test_killswitch_connection.py 1970-01-01 01:00:00.000000000 +0100 +++ new/python-proton-vpn-killswitch-network-manager-0.4.4/tests/integration/test_killswitch_connection.py 2024-04-30 15:26:05.000000000 +0200 @@ -0,0 +1,94 @@ +import pytest +import subprocess + +from proton.vpn.killswitch.backend.linux.networkmanager.killswitch_connection_handler import KillSwitchConnectionHandler + +FULL_KS_CONNECTION_ID = "test-killswitch" +ROUTED_KS_CONNECTION_ID = "test-routed-killswitch" +IPV6_KS_CONNECTION_ID = "test-killswitch-ipv6" +TEST_INTERFACE_NAME = "testpvpn0" + + +def _assert_connection_exist(connection_id): + subprocess.run( + ["nmcli", "-g", "GENERAL.STATE", "c", "s", f"{connection_id}"], + capture_output=True, check=True + ) + + +def _assert_connection_does_not_exist(connection_id): + with pytest.raises(subprocess.CalledProcessError): + subprocess.run( + ["nmcli", "-g", "GENERAL.STATE", "c", "s", f"{connection_id}"], + capture_output=True, check=True + ) + + +def _nmcli_add_connection(connection_id): + subprocess.run( + [ + "nmcli", "c", "a", "type", "dummy", "ifname", f"{TEST_INTERFACE_NAME}", + "con-name", f"{connection_id}" + ], + capture_output=True, check=True + ) + + +def _nmcli_del_connection(connection_id): + subprocess.run(["nmcli", "c", "del", f"{connection_id}"], capture_output=True) + + +@pytest.fixture +def cleanup_env(): + _nmcli_del_connection(FULL_KS_CONNECTION_ID) + _nmcli_del_connection(ROUTED_KS_CONNECTION_ID) + _nmcli_del_connection(IPV6_KS_CONNECTION_ID) + yield {} + _nmcli_del_connection(FULL_KS_CONNECTION_ID) + _nmcli_del_connection(ROUTED_KS_CONNECTION_ID) + _nmcli_del_connection(IPV6_KS_CONNECTION_ID) + + +@pytest.mark.asyncio +async def test_add_full_killswitch_connection(cleanup_env): + handler = KillSwitchConnectionHandler(connection_prefix="test") + await handler.add_full_killswitch_connection(permanent=False) + _assert_connection_exist(FULL_KS_CONNECTION_ID) + + +@pytest.mark.asyncio +async def test_remove_full_killswitch_connection(cleanup_env): + _nmcli_add_connection(FULL_KS_CONNECTION_ID) + handler = KillSwitchConnectionHandler(connection_prefix="test") + await handler.remove_full_killswitch_connection() + _assert_connection_does_not_exist(FULL_KS_CONNECTION_ID) + + +@pytest.mark.asyncio +async def test_add_routed_killswitch_connection(cleanup_env): + handler = KillSwitchConnectionHandler(connection_prefix="test") + await handler.add_routed_killswitch_connection(server_ip="192.168.1.1", permanent=False) + _assert_connection_exist(ROUTED_KS_CONNECTION_ID) + + +@pytest.mark.asyncio +async def test_remove_routed_killswitch_connection(cleanup_env): + _nmcli_add_connection(ROUTED_KS_CONNECTION_ID) + handler = KillSwitchConnectionHandler(connection_prefix="test") + await handler.remove_routed_killswitch_connection() + _assert_connection_does_not_exist(ROUTED_KS_CONNECTION_ID) + + +@pytest.mark.asyncio +async def test_add_ipv6_killswitch_connection(cleanup_env): + handler = KillSwitchConnectionHandler(connection_prefix="test") + await handler.add_ipv6_leak_protection() + _assert_connection_exist(IPV6_KS_CONNECTION_ID) + + +@pytest.mark.asyncio +async def test_remove_routed_killswitch_connection(cleanup_env): + _nmcli_add_connection(IPV6_KS_CONNECTION_ID) + handler = KillSwitchConnectionHandler(connection_prefix="test") + await handler.remove_ipv6_leak_protection() + _assert_connection_does_not_exist(IPV6_KS_CONNECTION_ID)