Integration of Firewall feature to Systemwide Wireguard
This commit is contained in:
parent
9ba6d7e783
commit
c4ffe9be3c
10 changed files with 216 additions and 57 deletions
|
|
@ -91,3 +91,10 @@ class ConfigurationController:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def update_or_create(configuration):
|
def update_or_create(configuration):
|
||||||
configuration.save()
|
configuration.save()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def change_firewall(new_value):
|
||||||
|
configuration = ConfigurationController.get_or_new()
|
||||||
|
configuration.firewall = new_value
|
||||||
|
configuration.save()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from core.services.networking.systemwide.systemwide_wireguard import terminate_system_connection
|
from core.services.networking.systemwide.systemwide_wireguard import terminate_system_connection
|
||||||
from core.services.networking.general_connection_tools.testing_evaluating import system_uses_wireguard_interface
|
from core.services.networking.general_connection_tools.testing_evaluating import system_uses_wireguard_interface
|
||||||
from core.services.networking.general_connection_tools.connection_enable import establish_connection
|
from core.services.networking.general_connection_tools.connection_enable import establish_connection
|
||||||
|
from core.services.networking.systemwide.systemwide_utils import get_firewall_setting
|
||||||
|
|
||||||
from core.Errors import InvalidSubscriptionError, MissingSubscriptionError, ConnectionTerminationError, ProfileActivationError, ProfileDeactivationError, MissingLocationError, ConnectionUnprotectedError, EndpointVerificationError, ProfileStateConflictError
|
from core.Errors import InvalidSubscriptionError, MissingSubscriptionError, ConnectionTerminationError, ProfileActivationError, ProfileDeactivationError, MissingLocationError, ConnectionUnprotectedError, EndpointVerificationError, ProfileStateConflictError
|
||||||
from core.controllers.ApplicationController import ApplicationController
|
from core.controllers.ApplicationController import ApplicationController
|
||||||
|
|
@ -132,7 +133,8 @@ class ProfileController:
|
||||||
raise ProfileDeactivationError('The profile could not be disabled.')
|
raise ProfileDeactivationError('The profile could not be disabled.')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
terminate_system_connection()
|
firewall_setting = get_firewall_setting()
|
||||||
|
terminate_system_connection(firewall_setting)
|
||||||
except ConnectionTerminationError:
|
except ConnectionTerminationError:
|
||||||
raise ProfileDeactivationError('The profile could not be disabled.')
|
raise ProfileDeactivationError('The profile could not be disabled.')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ class SystemStateController:
|
||||||
return SystemState.exists()
|
return SystemState.exists()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create(profile_id):
|
def create(profile_id: int, firewalled: bool) -> SystemState:
|
||||||
return SystemState(profile_id).save()
|
return SystemState(profile_id, firewalled).save()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def update_or_create(system_state):
|
def update_or_create(system_state):
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
from core.errors.logger import logger
|
||||||
|
|
||||||
from core.Constants import Constants
|
from core.Constants import Constants
|
||||||
from core.Helpers import write_atomically
|
from core.Helpers import write_atomically
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
|
|
@ -47,6 +49,14 @@ class Configuration:
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
firewall: Optional[bool] = field(
|
||||||
|
default=False,
|
||||||
|
metadata=config(
|
||||||
|
undefined=dataclasses_json.Undefined.EXCLUDE,
|
||||||
|
exclude=lambda value: value is None
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def save(self: Self):
|
def save(self: Self):
|
||||||
|
|
||||||
config_file_contents = f'{self.to_json(indent=4)}\n'
|
config_file_contents = f'{self.to_json(indent=4)}\n'
|
||||||
|
|
@ -82,3 +92,31 @@ class Configuration:
|
||||||
def _from_iso_format(datetime_string: str):
|
def _from_iso_format(datetime_string: str):
|
||||||
date_string = datetime_string.replace('Z', '+00:00')
|
date_string = datetime_string.replace('Z', '+00:00')
|
||||||
return datetime.fromisoformat(date_string)
|
return datetime.fromisoformat(date_string)
|
||||||
|
|
||||||
|
|
||||||
|
def read_config():
|
||||||
|
try:
|
||||||
|
config_file_contents = open(f'{Constants.HV_CONFIG_HOME}/config.json', 'r').read()
|
||||||
|
except FileNotFoundError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
configuration = json.loads(config_file_contents)
|
||||||
|
except ValueError:
|
||||||
|
logger.error(f"[CONFIG] Can't load JSON config")
|
||||||
|
|
||||||
|
return configuration
|
||||||
|
|
||||||
|
def get_setting(looking_for):
|
||||||
|
config = read_config()
|
||||||
|
if not config:
|
||||||
|
logger.error(f"[CONFIG] Can't load the entire config")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if looking_for not in config:
|
||||||
|
logger.error(f"[CONFIG] What you want isn't in the config")
|
||||||
|
return None
|
||||||
|
|
||||||
|
result = config[looking_for]
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
from core.models.BaseConnection import BaseConnection
|
from core.models.BaseConnection import BaseConnection
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class SessionConnection(BaseConnection):
|
class SessionConnection(BaseConnection):
|
||||||
|
|
@ -26,6 +25,7 @@ class SessionConnection(BaseConnection):
|
||||||
|
|
||||||
# from dataclasses import dataclass, field
|
# from dataclasses import dataclass, field
|
||||||
# from dataclasses_json import dataclass_json, config
|
# from dataclasses_json import dataclass_json, config
|
||||||
|
# from enum import Enum
|
||||||
|
|
||||||
# class SessionConnectionTypes(str, Enum):
|
# class SessionConnectionTypes(str, Enum):
|
||||||
# WIREGUARD = "wireguard"
|
# WIREGUARD = "wireguard"
|
||||||
|
|
@ -50,8 +50,3 @@ class SessionConnection(BaseConnection):
|
||||||
# # Validation
|
# # Validation
|
||||||
# if self.code not in SessionConnectionTypes:
|
# if self.code not in SessionConnectionTypes:
|
||||||
# raise ValueError(f'Invalid code: {self.code}')
|
# raise ValueError(f'Invalid code: {self.code}')
|
||||||
|
|
||||||
# @dataclass
|
|
||||||
# class SessionConnection(BaseConnection):
|
|
||||||
# code: SessionConnectionTypes
|
|
||||||
# masked: bool
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import pathlib
|
||||||
@dataclass
|
@dataclass
|
||||||
class SystemState:
|
class SystemState:
|
||||||
profile_id: int
|
profile_id: int
|
||||||
|
firewalled: bool
|
||||||
|
|
||||||
def save(self: Self):
|
def save(self: Self):
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,7 @@ def __should_renegotiate(profile: Union[SessionProfile, SystemProfile]):
|
||||||
if not profile.has_subscription():
|
if not profile.has_subscription():
|
||||||
raise MissingSubscriptionError()
|
raise MissingSubscriptionError()
|
||||||
|
|
||||||
if profile.connection.code in wireguard_types and profile.has_wireguard_configuration():
|
if profile.connection.code == "wireguard" and profile.has_wireguard_configuration():
|
||||||
if profile.subscription.has_been_activated():
|
if profile.subscription.has_been_activated():
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -23,19 +23,21 @@ def arm(server_ip: str, tunnel_if: str, internal_subnet: str = None) -> Result:
|
||||||
|
|
||||||
def disarm() -> bool:
|
def disarm() -> bool:
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
["sudo", _C.KILLSWITCH_WRAPPER, "disarm"],
|
["sudo", TESTING_KILLSWITCH, "disarm"],
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
)
|
)
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
print(f"[killswitch] Failed to disarm: {result.stderr.strip()}")
|
error_msg = f"Failed to disarm: {result.stderr.strip()}"
|
||||||
return False
|
logger.error(f"[KILLSWITCH] {error_log}")
|
||||||
return True
|
return Result(valid=False, error_type=ResultError.FIREWALL, message=error_log)
|
||||||
|
else:
|
||||||
|
return Result(valid=True)
|
||||||
|
|
||||||
|
|
||||||
def status() -> bool:
|
def status() -> bool:
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
["sudo", _C.KILLSWITCH_WRAPPER, "status"],
|
["sudo", TESTING_KILLSWITCH, "status"],
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,18 @@ from core.models.Result import Result, ResultError
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
from core.Errors import CommandNotFoundError
|
from core.Errors import CommandNotFoundError
|
||||||
|
from core.models.Configuration import get_setting
|
||||||
|
from core.errors.logger import logger
|
||||||
|
|
||||||
|
|
||||||
|
def get_firewall_setting() -> bool:
|
||||||
|
firewall_setting = get_setting("firewall")
|
||||||
|
logger.info(f"Firewall Setting is {firewall_setting}")
|
||||||
|
if firewall_setting is None:
|
||||||
|
return False
|
||||||
|
return firewall_setting
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def check_system_prereqs():
|
def check_system_prereqs():
|
||||||
if shutil.which('dbus-send') is None:
|
if shutil.which('dbus-send') is None:
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
from core.services.networking.general_connection_tools.testing_evaluating import await_connection, system_uses_wireguard_interface, terminate_tor_connection
|
from core.services.networking.general_connection_tools.testing_evaluating import await_connection, system_uses_wireguard_interface, terminate_tor_connection
|
||||||
from core.services.keys_and_verifications.endpoint_verification import verify_wireguard_endpoint
|
from core.services.keys_and_verifications.endpoint_verification import verify_wireguard_endpoint
|
||||||
from core.models.Result import Result, ResultError
|
from core.models.Result import Result, ResultError
|
||||||
from core.services.networking.systemwide.systemwide_utils import extract_wg_interface_name, check_system_prereqs
|
from core.services.networking.systemwide.systemwide_utils import extract_wg_interface_name, check_system_prereqs, get_firewall_setting
|
||||||
from core.services.networking.general_connection_tools.config_tools import extract_endpoint_ip
|
from core.services.networking.general_connection_tools.config_tools import extract_endpoint_ip
|
||||||
from core.services.networking.systemwide import killswitch
|
from core.services.networking.systemwide import killswitch
|
||||||
from core.errors.logger import logger
|
from core.errors.logger import logger
|
||||||
|
|
||||||
|
|
||||||
from core.Constants import Constants
|
from core.Constants import Constants
|
||||||
from core.Errors import ConnectionTerminationError, CommandNotFoundError
|
from core.Errors import ConnectionTerminationError, CommandNotFoundError
|
||||||
from core.controllers.ConfigurationController import ConfigurationController
|
from core.controllers.ConfigurationController import ConfigurationController
|
||||||
|
|
@ -24,13 +23,73 @@ import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
|
|
||||||
def terminate_system_connection():
|
|
||||||
|
def turn_on_firewall(profile_id: str, process_output: str) -> Result:
|
||||||
|
"""
|
||||||
|
Purpose:
|
||||||
|
This is a wireguard specific function, using the WG interface,
|
||||||
|
but the underlying killswitch.arm function it uses is protocol neutral.
|
||||||
|
|
||||||
|
Steps:
|
||||||
|
1) Get the WG interface from the process output
|
||||||
|
2) Get the server IP from the backup WG config
|
||||||
|
3) Use the killswitch's arm
|
||||||
|
"""
|
||||||
|
logger.info(f"[SYSTEMWIDE WG] Turning on Firewall..")
|
||||||
|
|
||||||
|
wg_interface_result = extract_wg_interface_name(process_output)
|
||||||
|
|
||||||
|
if not wg_interface_result.valid:
|
||||||
|
error_msg = f"WG interface is in the wrong format. This is the raw output: {process_output}"
|
||||||
|
logger.error(f"[SYSTEMWIDE WG] Critical issue, the {error_msg}")
|
||||||
|
raise ConnectionError(error_msg)
|
||||||
|
# or handle the interface being wrong?
|
||||||
|
|
||||||
|
wg_interface_name = wg_interface_result.data
|
||||||
|
server_ip_address = extract_endpoint_ip(profile_id)
|
||||||
|
# print(f"WG Inteface Name: {wg_interface_name}")
|
||||||
|
|
||||||
|
return killswitch.arm(
|
||||||
|
server_ip=server_ip_address,
|
||||||
|
tunnel_if=wg_interface_name,
|
||||||
|
internal_subnet=None
|
||||||
|
)
|
||||||
|
|
||||||
|
# This raises errors on failure.
|
||||||
|
def check_and_kill_firewall():
|
||||||
|
firewall_status = killswitch.status()
|
||||||
|
logger.info(f"Inside check_and_kill_firewall the firewall status is {firewall_status}")
|
||||||
|
|
||||||
|
logger.info(f"Terminate connection ran check_and_kill_firewall which evaluated the status as {firewall_status}")
|
||||||
|
|
||||||
|
# is it even armed? if not, get lost,
|
||||||
|
if firewall_status == "on":
|
||||||
|
# if it's armed, kill it,
|
||||||
|
logger.info(f"Killing the firewall")
|
||||||
|
firewall_results = killswitch.disarm()
|
||||||
|
|
||||||
|
# did that work?
|
||||||
|
if firewall_results.valid:
|
||||||
|
logger.info(f"We disabled the firewall correctly.")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
logger.error(f"[FIREWALL] CRITICAL ISSUE with the Firewall being disabled: {firewall_results.message}")
|
||||||
|
error_msg = f"Firewall couldn't be disabled: {firewall_results.message}"
|
||||||
|
raise ConnectionTerminationError(error_msg)
|
||||||
|
else:
|
||||||
|
logger.info("We are skipping disabling the firewall, because it's already off.")
|
||||||
|
|
||||||
|
def terminate_system_connection(firewall_setting) -> Result:
|
||||||
|
|
||||||
if shutil.which('nmcli') is None:
|
if shutil.which('nmcli') is None:
|
||||||
raise CommandNotFoundError('nmcli')
|
raise CommandNotFoundError('nmcli')
|
||||||
|
|
||||||
if SystemStateController.exists():
|
# ====== FIREWALL =======
|
||||||
|
if firewall_setting:
|
||||||
|
check_and_kill_firewall() # on failure, this raises errors, which then bubble up
|
||||||
|
|
||||||
|
# ====== NMCLI =======
|
||||||
|
if SystemStateController.exists():
|
||||||
process = subprocess.Popen(('nmcli', 'connection', 'delete', 'wg'), stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
process = subprocess.Popen(('nmcli', 'connection', 'delete', 'wg'), stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
||||||
completed_successfully = not bool(os.waitpid(process.pid, 0)[1] >> 8)
|
completed_successfully = not bool(os.waitpid(process.pid, 0)[1] >> 8)
|
||||||
|
|
||||||
|
|
@ -77,10 +136,28 @@ def setup_ipv6_sinkhole(process_output: str) -> Result:
|
||||||
# raise ConnectionError('The connection could not be established.')
|
# raise ConnectionError('The connection could not be established.')
|
||||||
|
|
||||||
|
|
||||||
def __establish_system_connection(profile: SystemProfile, firewall_setting: bool = False, connection_observer: Optional[ConnectionObserver] = None):
|
def __establish_system_connection(
|
||||||
|
profile: SystemProfile,
|
||||||
|
firewall_setting: bool = False,
|
||||||
|
connection_observer: Optional[ConnectionObserver] = None):
|
||||||
|
"""
|
||||||
|
Purpose:
|
||||||
|
Orchestrates the full flow of the connection.
|
||||||
|
|
||||||
|
Steps:
|
||||||
|
1) Check Prereqs
|
||||||
|
2) Disable any pre-existing system connections
|
||||||
|
3) Turn on WG via nmcli
|
||||||
|
4) Turn on IPv6 sinkhole
|
||||||
|
5) Turn on Firewall (if enabled)
|
||||||
|
6) Setup State (JSON file)
|
||||||
|
7) Confirm Firewall is on (if enabled). Raises errors if not.
|
||||||
|
8) Testing, confirming, displaying to the end user.
|
||||||
|
"""
|
||||||
|
|
||||||
check_system_prereqs()
|
check_system_prereqs()
|
||||||
terminate_system_connection()
|
logger.info("[CONNECT] Terming existing connections..")
|
||||||
|
terminate_system_connection(firewall_setting)
|
||||||
|
|
||||||
# ============= INITIAL NMCLI CONNECTION =============
|
# ============= INITIAL NMCLI CONNECTION =============
|
||||||
wg_config_path = profile.get_wireguard_configuration_path()
|
wg_config_path = profile.get_wireguard_configuration_path()
|
||||||
|
|
@ -88,44 +165,55 @@ def __establish_system_connection(profile: SystemProfile, firewall_setting: bool
|
||||||
|
|
||||||
if nmcli_result.valid:
|
if nmcli_result.valid:
|
||||||
process_output = nmcli_result.data
|
process_output = nmcli_result.data
|
||||||
|
logger.info("[CONNECT] Successfully turned on WG with nmcli")
|
||||||
else:
|
else:
|
||||||
logger.error(f"[SYSTEMWIDE WG] Critical issue, the initial nmcli command failed {nmcli_result.message}.")
|
logger.error(f"[SYSTEMWIDE WG] Critical issue, the initial nmcli command failed {nmcli_result.message}.")
|
||||||
return nmcli_result
|
return nmcli_result
|
||||||
|
|
||||||
wg_interface_result = extract_wg_interface_name(process_output)
|
|
||||||
|
|
||||||
if not wg_interface_result.valid:
|
|
||||||
logger.error(f"[SYSTEMWIDE WG] Critical issue, the wg interface is in the wrong format. This is the raw output: {process_output}")
|
|
||||||
raise ConnectionError('The connection could not be established.')
|
|
||||||
# handle the interface being wrong
|
|
||||||
|
|
||||||
# ============= IPv6 SINKHOLE =============
|
# ============= IPv6 SINKHOLE =============
|
||||||
sinkhole_result = setup_ipv6_sinkhole(process_output)
|
sinkhole_result = setup_ipv6_sinkhole(process_output)
|
||||||
if not sinkhole_result:
|
if not sinkhole_result:
|
||||||
raise ConnectionError('IPv6 Could not be protected.')
|
raise ConnectionError('IPv6 Could not be protected.')
|
||||||
|
|
||||||
# ============= FIREWALL =============
|
# ============= FIREWALL =============
|
||||||
|
firewall_tracker = False
|
||||||
if firewall_setting:
|
if firewall_setting:
|
||||||
logger.info(f"[SYSTEMWIDE WG] Turning on Firewall")
|
logger.info("Firewall setting is enabled, let's turn it on..")
|
||||||
|
turn_on_result = turn_on_firewall(
|
||||||
wg_interface_name = wg_interface_result.data
|
profile_id=str(profile.id),
|
||||||
server_ip_address = extract_endpoint_ip(str(profile.id))
|
process_output=process_output
|
||||||
print(f"WG Inteface Name: {wg_interface_name}")
|
|
||||||
print(f"Server IP address: {server_ip_address}")
|
|
||||||
|
|
||||||
firewall_results = killswitch.arm(
|
|
||||||
server_ip=server_ip_address,
|
|
||||||
tunnel_if=wg_interface_name,
|
|
||||||
internal_subnet=None
|
|
||||||
)
|
)
|
||||||
|
logger.info(f"Results of firewall turn on are: {turn_on_result.valid}")
|
||||||
|
if turn_on_result.valid:
|
||||||
|
firewall_tracker = True
|
||||||
|
|
||||||
if not firewall_results.valid:
|
|
||||||
print(f"FAILED to setup Firewall. firewall_results is {firewall_results.message}")
|
|
||||||
# raise ConnectionError('Firewall could not be enabled.')
|
|
||||||
|
|
||||||
# ============= SETUP STATE & TEST =============
|
# ============= SETUP STATE =============
|
||||||
SystemStateController.create(profile.id)
|
# Even if firewall is off, we want to save the fact we turned on the VPN tunnel, before we raise errors.
|
||||||
|
|
||||||
|
logger.info(f"Setting State JSON..")
|
||||||
|
SystemStateController.create(
|
||||||
|
profile_id=profile.id,
|
||||||
|
firewalled=firewall_tracker
|
||||||
|
)
|
||||||
|
|
||||||
|
# ============= CONFIRM ON FIREWALL =============
|
||||||
|
if firewall_setting:
|
||||||
|
logger.info(f"Evaluating Firewall Situation after we tried to turn on it on.")
|
||||||
|
firewall_status = killswitch.status()
|
||||||
|
logger.info(f"""
|
||||||
|
The firewall setting is on.
|
||||||
|
The result of arming it, {turn_on_result.valid}
|
||||||
|
The result of the status {firewall_status}
|
||||||
|
""")
|
||||||
|
if firewall_status:
|
||||||
|
logger.info("Firewall is on. All good.")
|
||||||
|
else:
|
||||||
|
logger.error("Firewall FAILED TO ARM") # TRIES TO RENEGOTIATE WITH DEAD INTERNET !!
|
||||||
|
# raise ConnectionError(f'Firewall failed to arm!! {turn_on_result.message}.') # if this triggers, it tries to renegotiate with dead internet.
|
||||||
|
|
||||||
|
logger.info("If we made it this far, we have nmcli on, ipv6 sinkhole on, firewall on.")
|
||||||
|
# ============= TESTING =============
|
||||||
try:
|
try:
|
||||||
await_connection(connection_observer=connection_observer)
|
await_connection(connection_observer=connection_observer)
|
||||||
|
|
||||||
|
|
@ -139,18 +227,23 @@ def evaluate_connection_result(connection_result: Result):
|
||||||
if not connection_result.valid:
|
if not connection_result.valid:
|
||||||
logger.error(f"[SYSTEMWIDE WG] Critical issue, could not establish a connection: {connection_result.message}")
|
logger.error(f"[SYSTEMWIDE WG] Critical issue, could not establish a connection: {connection_result.message}")
|
||||||
try:
|
try:
|
||||||
terminate_system_connection()
|
terminate_system_connection(firewall_setting)
|
||||||
except ConnectionTerminationError:
|
except ConnectionTerminationError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def establish_system_connection(profile: SystemProfile, ignore: tuple[type[Exception]] = (), connection_observer: Optional[ConnectionObserver] = None):
|
def establish_system_connection(
|
||||||
|
profile: SystemProfile,
|
||||||
|
ignore: tuple[type[Exception]] = (),
|
||||||
|
connection_observer: Optional[ConnectionObserver] = None):
|
||||||
"""
|
"""
|
||||||
Rank:
|
|
||||||
Public Interface Orchestrator
|
|
||||||
|
|
||||||
Purpose:
|
Purpose:
|
||||||
Tries to enable the systemwide connection, retries on failure.
|
Calls the private function with the full flow, so it can be retried on failure.
|
||||||
|
|
||||||
|
Steps)
|
||||||
|
1) Verify Endpoint's encryption
|
||||||
|
2) Pass to private function
|
||||||
|
3) Retry on failure
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# ================= VERIFY ENDPOINT =================
|
# ================= VERIFY ENDPOINT =================
|
||||||
|
|
@ -158,14 +251,19 @@ def establish_system_connection(profile: SystemProfile, ignore: tuple[type[Excep
|
||||||
verify_wireguard_endpoint(profile, ignore=ignore)
|
verify_wireguard_endpoint(profile, ignore=ignore)
|
||||||
|
|
||||||
# ================= CONNECT WG =================
|
# ================= CONNECT WG =================
|
||||||
|
firewall_setting = get_firewall_setting()
|
||||||
try:
|
try:
|
||||||
connection_result = __establish_system_connection(profile, False, connection_observer)
|
connection_result = __establish_system_connection(
|
||||||
|
profile=profile,
|
||||||
|
firewall_setting=firewall_setting,
|
||||||
|
connection_observer=connection_observer
|
||||||
|
)
|
||||||
evaluate_connection_result(connection_result)
|
evaluate_connection_result(connection_result)
|
||||||
|
|
||||||
except ConnectionError:
|
except ConnectionError:
|
||||||
|
# ================= RETRY ON FAILURE =================
|
||||||
try:
|
try:
|
||||||
terminate_system_connection()
|
terminate_system_connection(firewall_setting)
|
||||||
except ConnectionTerminationError:
|
except ConnectionTerminationError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
@ -174,19 +272,23 @@ def establish_system_connection(profile: SystemProfile, ignore: tuple[type[Excep
|
||||||
except CalledProcessError:
|
except CalledProcessError:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
terminate_system_connection()
|
terminate_system_connection(firewall_setting)
|
||||||
except ConnectionTerminationError:
|
except ConnectionTerminationError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# trying again..
|
# trying again..
|
||||||
try:
|
try:
|
||||||
connection_result = __establish_system_connection(profile, False, connection_observer)
|
connection_result = __establish_system_connection(
|
||||||
|
profile=profile,
|
||||||
|
firewall_setting=firewall_setting,
|
||||||
|
connection_observer=connection_observer
|
||||||
|
)
|
||||||
evaluate_connection_result(connection_result)
|
evaluate_connection_result(connection_result)
|
||||||
|
|
||||||
except (ConnectionError, CalledProcessError):
|
except (ConnectionError, CalledProcessError):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
terminate_system_connection()
|
terminate_system_connection(firewall_setting)
|
||||||
except ConnectionTerminationError:
|
except ConnectionTerminationError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue