Compare commits
2 commits
bae5bfe7f3
...
5377b7348b
| Author | SHA1 | Date | |
|---|---|---|---|
| 5377b7348b | |||
| 46a84661a0 |
12 changed files with 306 additions and 17 deletions
26
core/assets/sudo_scripts/singbox_runner
Normal file
26
core/assets/sudo_scripts/singbox_runner
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -eo pipefail
|
||||||
|
|
||||||
|
SINGBOX_BIN="/usr/bin/singbox"
|
||||||
|
LOG_FILE="~/.local/share/hydra-veil/singbox.txt"
|
||||||
|
|
||||||
|
run_binary() {
|
||||||
|
"$SINGBOX_BIN" run -c "$1" >> "$LOG_FILE" 2>&1 &
|
||||||
|
_new_pid=$!
|
||||||
|
echo "$_new_pid"
|
||||||
|
}
|
||||||
|
# get result in python: pid = int(result.stdout.strip())
|
||||||
|
|
||||||
|
gracefully_close() {
|
||||||
|
sudo kill -TERM "$1" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
forcefully_kill() {
|
||||||
|
sudo kill -TERM "$1" 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
hello_world_test() {
|
||||||
|
echo "hello world $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
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, get_dns_setting
|
from core.services.networking.systemwide.systemwide_utils import get_firewall_setting, get_dns_setting
|
||||||
|
from core.services.networking.systemwide import killswitch
|
||||||
from core.errors.exceptions import FirewallError
|
from core.errors.exceptions import FirewallError
|
||||||
|
|
||||||
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
|
||||||
|
|
@ -145,7 +146,16 @@ class ProfileController:
|
||||||
raise ProfileDeactivationError('The profile could not be disabled.')
|
raise ProfileDeactivationError('The profile could not be disabled.')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
terminate_system_connection()
|
# ================= SETTINGS =================
|
||||||
|
firewall_setting = get_firewall_setting()
|
||||||
|
dns_setting = get_dns_setting()
|
||||||
|
# ======= KILL SYSTEMWIDE =============
|
||||||
|
terminate_system_connection(
|
||||||
|
firewall_setting=firewall_setting,
|
||||||
|
dns_setting=dns_setting
|
||||||
|
)
|
||||||
|
# ================= UPDATE UI ================
|
||||||
|
# if it made it this far, it worked in theory.
|
||||||
if profile_observer is not None:
|
if profile_observer is not None:
|
||||||
profile_observer.notify('disabled', profile, dict(
|
profile_observer.notify('disabled', profile, dict(
|
||||||
explicitly=explicitly,
|
explicitly=explicitly,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,20 @@
|
||||||
from core.models.Result import Result, ResultError
|
from core.models.Result import Result, ResultError
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
class DNSError(Exception):
|
||||||
|
"""There are issues with DNS"""
|
||||||
|
def __init__(self, result: Optional[Result]):
|
||||||
|
if result:
|
||||||
|
self.result = result
|
||||||
|
if result.message and result.message is not None:
|
||||||
|
error_msg = result.message
|
||||||
|
else:
|
||||||
|
error_msg = result.error_type
|
||||||
|
else:
|
||||||
|
error_msg = "Failed to start DNS"
|
||||||
|
super().__init__(error_msg)
|
||||||
|
|
||||||
|
|
||||||
class FirewallError(Exception):
|
class FirewallError(Exception):
|
||||||
"""There are issues with the Firewall"""
|
"""There are issues with the Firewall"""
|
||||||
def __init__(self, result: Optional[Result]):
|
def __init__(self, result: Optional[Result]):
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ class ResultError(Enum):
|
||||||
DATABASE = "database"
|
DATABASE = "database"
|
||||||
PERMISSION = "permission"
|
PERMISSION = "permission"
|
||||||
SUBSCRIPTION = "subscription"
|
SUBSCRIPTION = "subscription"
|
||||||
|
PROCESS_GOT_KILLED = "process_got_killed"
|
||||||
|
PROCESS_WONT_START = "process_wont_start"
|
||||||
NMCLI = "nmcli_issues"
|
NMCLI = "nmcli_issues"
|
||||||
FIREWALL = "firewall"
|
FIREWALL = "firewall"
|
||||||
CLIENT_DNS = "client_dns"
|
CLIENT_DNS = "client_dns"
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ DNS_SCRIPT = f"/opt/hydra-veil/dns"
|
||||||
def set_on(network_interface: str, dns_should_be: str) -> Result:
|
def set_on(network_interface: str, dns_should_be: str) -> Result:
|
||||||
command = ["sudo", DNS_SCRIPT, "set", network_interface, dns_should_be]
|
command = ["sudo", DNS_SCRIPT, "set", network_interface, dns_should_be]
|
||||||
human_readable_goal = "Set DNS"
|
human_readable_goal = "Set DNS"
|
||||||
return run_generic_command(command, human_readable_goal)
|
return run_generic_command(command, human_readable_goal, timeout=5)
|
||||||
|
|
||||||
|
|
||||||
# requires script to have sudo
|
# requires script to have sudo
|
||||||
|
|
@ -21,7 +21,7 @@ def set_on(network_interface: str, dns_should_be: str) -> Result:
|
||||||
def revert() -> Result:
|
def revert() -> Result:
|
||||||
command = ["sudo", DNS_SCRIPT, "revert"]
|
command = ["sudo", DNS_SCRIPT, "revert"]
|
||||||
human_readable_goal = "DNS revert"
|
human_readable_goal = "DNS revert"
|
||||||
return run_generic_command(command, human_readable_goal)
|
return run_generic_command(command, human_readable_goal, timeout=7)
|
||||||
|
|
||||||
|
|
||||||
# does NOT need sudo
|
# does NOT need sudo
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
from core.services.networking.systemwide.systemwide_errors import systemwide_hell_raiser
|
||||||
|
from core.utils.basic_operations.wrap_with import wrap_with
|
||||||
|
from core.utils.basic_operations.run_generic_command import run_generic_command
|
||||||
|
from core.models.Result import Result, ResultError
|
||||||
|
from core.errors.logger import logger
|
||||||
|
|
||||||
|
SINGBOX_WRAPPER = "/opt/hydra-veil/singbox_runner" # needs chmod 755
|
||||||
|
|
||||||
|
@wrap_with(systemwide_hell_raiser)
|
||||||
|
def start(config_path: str) -> Result:
|
||||||
|
command = ['bash', '-c', f'. {SINGBOX_WRAPPER} && run_binary "{config_path}"']
|
||||||
|
human_readable_goal = "Start running Singbox"
|
||||||
|
return run_generic_command(command, human_readable_goal, timeout=5)
|
||||||
|
|
||||||
|
|
||||||
|
@wrap_with(systemwide_hell_raiser)
|
||||||
|
def turn_off(process_id: str) -> Result:
|
||||||
|
command = ['bash', '-c', f'. {SINGBOX_WRAPPER} && gracefully_close "{process_id}"']
|
||||||
|
human_readable_goal = "Gracefully Stop Singbox"
|
||||||
|
return run_generic_command(command, human_readable_goal, timeout=5)
|
||||||
|
|
||||||
|
|
||||||
|
@wrap_with(systemwide_hell_raiser)
|
||||||
|
def force_kill(process_id: str) -> Result:
|
||||||
|
command = ['bash', '-c', f'. {SINGBOX_WRAPPER} && forcefully_kill "{process_id}"']
|
||||||
|
human_readable_goal = "Force Kill Singbox"
|
||||||
|
return run_generic_command(command, human_readable_goal, timeout=5)
|
||||||
|
|
||||||
|
|
||||||
|
@wrap_with(systemwide_hell_raiser)
|
||||||
|
def hello_world_test(name: str) -> str:
|
||||||
|
command = ['bash', '-c', f'. {SINGBOX_WRAPPER} && hello_world_test "{name}"']
|
||||||
|
human_readable_goal = "Hello world test"
|
||||||
|
return run_generic_command(command, human_readable_goal, timeout=5)
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
from core.services.networking.systemwide.encrypted_proxy import singbox
|
||||||
|
from core.utils.basic_operations import process_tools
|
||||||
|
from core.models.Result import Result, ResultError
|
||||||
|
from core.errors.logger import logger
|
||||||
|
from core.Constants import Constants
|
||||||
|
from core.models.system.SystemState import SystemState
|
||||||
|
from core.controllers.SystemStateController import SystemStateController
|
||||||
|
from core.services.networking.systemwide.systemwide_utils import get_firewall_setting, get_dns_setting
|
||||||
|
from core.services.networking.systemwide import dns
|
||||||
|
from core.services.networking.systemwide.general_connection_tools.general_firewall_dns_tools import generic_enable_firewall_w_retry
|
||||||
|
from core.errors.exceptions import FirewallError, DNSError
|
||||||
|
|
||||||
|
# generic
|
||||||
|
import time
|
||||||
|
|
||||||
|
QUANTITY_OF_ATTEMPTS = 2
|
||||||
|
SINGBOX_TUN_IF = 'tun0'
|
||||||
|
SINGBOX_INTERNAL_SUBNET = '172.19.0.0/30'
|
||||||
|
SINGBOX_INTERNAL_ADDR = '172.19.0.1/30'
|
||||||
|
SINGBOX_DEFAULT_DNS = '9.9.9.9'
|
||||||
|
|
||||||
|
|
||||||
|
def set_dns_for_singbox(current_state: SystemState):
|
||||||
|
do_they_even_use_systemd = dns.is_systemd_enabled()
|
||||||
|
|
||||||
|
if not do_they_even_use_systemd.valid:
|
||||||
|
error_msg = "You don't use SystemD, so we are skipping setting your DNS."
|
||||||
|
logger.info(error_msg)
|
||||||
|
return True
|
||||||
|
|
||||||
|
dns_result = dns.set_on(network_interface=SINGBOX_TUN_IF, dns_should_be=SINGBOX_DEFAULT_DNS)
|
||||||
|
|
||||||
|
if dns_result.valid:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
# Update the state for the DNS failure, but not firewall
|
||||||
|
current_state.firewalled = True
|
||||||
|
current_state.dns_set = False
|
||||||
|
SystemStateController.update_or_create(current_state)
|
||||||
|
raise DNSError(dns_result)
|
||||||
|
|
||||||
|
|
||||||
|
def _attempt_start_with_retry(config_path: str, quantity_of_attempts: int = 2) -> Result:
|
||||||
|
current_attempt = 0
|
||||||
|
|
||||||
|
while current_attempt < quantity_of_attempts:
|
||||||
|
activation_result = singbox.start(config_path)
|
||||||
|
|
||||||
|
if activation_result.valid:
|
||||||
|
return activation_result
|
||||||
|
else:
|
||||||
|
current_attempt = current_attempt + 1
|
||||||
|
logger.error(f"[SINGBOX] Attempt {current_attempt} for Singbox Failed. Because: {activation_result.message}. Trying again..")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def start_singbox(
|
||||||
|
profile_id: int,
|
||||||
|
config_path: str,
|
||||||
|
server_ip: str,
|
||||||
|
connection_observer: Optional[ConnectionObserver] = None
|
||||||
|
) -> Result:
|
||||||
|
"""
|
||||||
|
Purpose:
|
||||||
|
Orchestrates the full flow of the Singbox connection.
|
||||||
|
|
||||||
|
Steps:
|
||||||
|
1) Validate inputs
|
||||||
|
2) Start it with a retry
|
||||||
|
3) Evaluate if the process id is still up.
|
||||||
|
4) If it's up, setup the State JSON
|
||||||
|
5) Turn on Firewall
|
||||||
|
6) Turn on DNS
|
||||||
|
7) Update the State
|
||||||
|
"""
|
||||||
|
|
||||||
|
function_name = "START_SINGBOX"
|
||||||
|
|
||||||
|
# ============= INPUT VALIDATION =============
|
||||||
|
requirements = [profile_id, config_path, server_ip]
|
||||||
|
for each_requirement in requirements:
|
||||||
|
if each_requirement is None:
|
||||||
|
return Result(valid=False, error_type=ResultError.INVALID_INPUT, message=f"Invalid inputs into {function_name}")
|
||||||
|
|
||||||
|
# ============= START PROCESS =============
|
||||||
|
activation_result = _attempt_start_with_retry(config_path=config_path, quantity_of_attempts=QUANTITY_OF_ATTEMPTS)
|
||||||
|
|
||||||
|
if not activation_result.valid:
|
||||||
|
error_msg = f"Singbox failed to start after {QUANTITY_OF_ATTEMPTS} attempts"
|
||||||
|
logger.error(f"[{function_name}] {error_msg}")
|
||||||
|
return Result(valid=False, error_type=ResultError=PROCESS_WONT_START, message=error_msg)
|
||||||
|
|
||||||
|
process_id = activation_result.data
|
||||||
|
time.sleep(2)
|
||||||
|
active = process_tools.is_running(process_id)
|
||||||
|
|
||||||
|
if not active:
|
||||||
|
error_msg = f"While Singbox might have literally allowed the binary to begin, it's killing the process on id {process_id}"
|
||||||
|
logger.error(f"[{function_name}] {error_msg}")
|
||||||
|
return Result(valid=False, error_type=ResultError.PROCESS_GOT_KILLED, message=error_msg, data=process_id)
|
||||||
|
|
||||||
|
# ============= SETUP STATE =============
|
||||||
|
# Even if firewall is off, we want to save the fact we turned Singbox on, before we raise errors.
|
||||||
|
|
||||||
|
logger.info(f"Setting State JSON with INTENDED firewall & Dns settings")
|
||||||
|
current_state = SystemStateController.create(
|
||||||
|
profile_id=profile.id,
|
||||||
|
firewalled=True, # intended setting, not result yet
|
||||||
|
dns_set=True # intended setting, not result yet
|
||||||
|
)
|
||||||
|
|
||||||
|
# ============= FIREWALL =============
|
||||||
|
logger.info(f"[{function_name}] Attempting to enable the Firewall for {SINGBOX_TUN_IF} and {SINGBOX_INTERNAL_SUBNET}...")
|
||||||
|
# this is labeled "generic" for being protocol neutral
|
||||||
|
firewall_result = generic_enable_firewall_w_retry(
|
||||||
|
interface_name=SINGBOX_TUN_IF,
|
||||||
|
server_ip=server_ip,
|
||||||
|
internal_subnet = SINGBOX_INTERNAL_SUBNET,
|
||||||
|
max_retries = 2,
|
||||||
|
connection_observer=connection_observer
|
||||||
|
)
|
||||||
|
|
||||||
|
if not firewall_result.valid:
|
||||||
|
# Update the state of the failure,
|
||||||
|
current_state.firewalled = False
|
||||||
|
current_state.dns_set = False
|
||||||
|
SystemStateController.update_or_create(current_state)
|
||||||
|
raise FirewallError(firewall_result) # Now end the party.
|
||||||
|
|
||||||
|
# ============= DNS =============
|
||||||
|
dns_result = set_dns_for_singbox(current_state)
|
||||||
|
# raises error if not okay.
|
||||||
|
|
||||||
|
# ============= CONCLUSION =============
|
||||||
|
return Result(valid=True, data=current_state)
|
||||||
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
from core.services.networking.systemwide import killswitch
|
||||||
|
from core.errors.logger import logger
|
||||||
|
from core.errors.exceptions import FirewallError
|
||||||
|
from core.models.Result import Result, ResultError
|
||||||
|
|
||||||
|
|
||||||
|
def generic_enable_firewall_w_retry(
|
||||||
|
interface_name: str,
|
||||||
|
server_ip: str,
|
||||||
|
internal_subnet: str = None,
|
||||||
|
max_retries: int = 2
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Purpose:
|
||||||
|
Protocol-neutral, Enable the firewall with automatic retry on failure.
|
||||||
|
|
||||||
|
Called by:
|
||||||
|
start_singbox
|
||||||
|
|
||||||
|
Raises Errors:
|
||||||
|
Yes, FirewallError
|
||||||
|
"""
|
||||||
|
|
||||||
|
last_result = None
|
||||||
|
|
||||||
|
for attempt in range(1, max_retries + 1):
|
||||||
|
logger.info(f"Enabling firewall (attempt {attempt}/{max_retries})")
|
||||||
|
|
||||||
|
turn_on_result = killswitch.arm(
|
||||||
|
server_ip=server_ip,
|
||||||
|
tunnel_if=interface_name,
|
||||||
|
internal_subnet=internal_subnet
|
||||||
|
)
|
||||||
|
|
||||||
|
if turn_on_result is None:
|
||||||
|
logger.error("turn_on_firewall() returned None")
|
||||||
|
continue
|
||||||
|
|
||||||
|
last_result = turn_on_result
|
||||||
|
firewall_status = killswitch.status()
|
||||||
|
|
||||||
|
if turn_on_result.valid and firewall_status:
|
||||||
|
logger.info("Firewall successfully enabled")
|
||||||
|
return last_result
|
||||||
|
|
||||||
|
logger.warning(f"Firewall enable failed on attempt {attempt}, because {turn_on_result.message}")
|
||||||
|
|
||||||
|
return last_result
|
||||||
|
|
||||||
|
|
@ -3,7 +3,7 @@ from core.utils.basic_operations.wrap_with import wrap_with
|
||||||
from core.utils.basic_operations.run_generic_command import run_generic_command
|
from core.utils.basic_operations.run_generic_command import run_generic_command
|
||||||
from core.models.Result import Result, ResultError
|
from core.models.Result import Result, ResultError
|
||||||
from core.errors.logger import logger
|
from core.errors.logger import logger
|
||||||
import subprocess
|
# import subprocess
|
||||||
|
|
||||||
KILLSWITCH_WRAPPER = "/opt/hydra-veil/firewall" # needs chmod 755
|
KILLSWITCH_WRAPPER = "/opt/hydra-veil/firewall" # needs chmod 755
|
||||||
|
|
||||||
|
|
@ -13,13 +13,13 @@ def arm(server_ip: str, tunnel_if: str, internal_subnet: str = None) -> Result:
|
||||||
if internal_subnet:
|
if internal_subnet:
|
||||||
command.append(internal_subnet)
|
command.append(internal_subnet)
|
||||||
human_readable_goal = "Arming the Firewall"
|
human_readable_goal = "Arming the Firewall"
|
||||||
return run_generic_command(command, human_readable_goal)
|
return run_generic_command(command, human_readable_goal, timeout=5)
|
||||||
|
|
||||||
@wrap_with(systemwide_hell_raiser)
|
@wrap_with(systemwide_hell_raiser)
|
||||||
def disarm() -> bool:
|
def disarm() -> bool:
|
||||||
command = ["sudo", KILLSWITCH_WRAPPER, "disarm"]
|
command = ["sudo", KILLSWITCH_WRAPPER, "disarm"]
|
||||||
human_readable_goal = "Disarming the Firewall"
|
human_readable_goal = "Disarming the Firewall"
|
||||||
return run_generic_command(command, human_readable_goal)
|
return run_generic_command(command, human_readable_goal, timeout=5)
|
||||||
|
|
||||||
def status() -> bool:
|
def status() -> bool:
|
||||||
command = ["sudo", KILLSWITCH_WRAPPER, "status"]
|
command = ["sudo", KILLSWITCH_WRAPPER, "status"]
|
||||||
|
|
|
||||||
|
|
@ -29,16 +29,23 @@ import subprocess
|
||||||
import time
|
import time
|
||||||
|
|
||||||
def terminate_system_connection(
|
def terminate_system_connection(
|
||||||
firewall_setting: Optional[bool] = get_firewall_setting(),
|
firewall_setting: Optional[bool] = None,
|
||||||
dns_setting: Optional[bool] = get_dns_setting()
|
dns_setting: Optional[bool] = None
|
||||||
):
|
):
|
||||||
|
|
||||||
|
# ====== PREREQS =======
|
||||||
|
if firewall_setting is None:
|
||||||
|
firewall_setting = get_firewall_setting()
|
||||||
|
|
||||||
|
if dns_setting is None:
|
||||||
|
dns_setting = get_dns_setting()
|
||||||
|
|
||||||
if shutil.which('nmcli') is None:
|
if shutil.which('nmcli') is None:
|
||||||
raise CommandNotFoundError('nmcli')
|
raise CommandNotFoundError('nmcli')
|
||||||
|
|
||||||
# ====== FIREWALL =======
|
# ====== FIREWALL =======
|
||||||
if firewall_setting:
|
if firewall_setting:
|
||||||
check_and_kill_firewall() # on failure, this raises errors, which then bubble up
|
disable_result_object = killswitch.disarm() # raw blind kill
|
||||||
|
|
||||||
# ====== DNS =======
|
# ====== DNS =======
|
||||||
if dns_setting:
|
if dns_setting:
|
||||||
|
|
@ -54,9 +61,9 @@ def terminate_system_connection(
|
||||||
subprocess.run(('nmcli', 'connection', 'delete', 'hv-ipv6-sink'), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
subprocess.run(('nmcli', 'connection', 'delete', 'hv-ipv6-sink'), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||||
terminate_tor_connection()
|
terminate_tor_connection()
|
||||||
|
|
||||||
# confirm check on dns:
|
# confirm firewall is off.
|
||||||
# did_dns_revert = confirm_dns_is_reverted('wg')
|
if firewall_setting:
|
||||||
# print(f"did_dns_revert is {did_dns_revert}")
|
check_and_kill_firewall() # on failure, this raises errors, which then bubble up
|
||||||
|
|
||||||
# finally end that profile's JSON state:
|
# finally end that profile's JSON state:
|
||||||
SystemState.dissolve()
|
SystemState.dissolve()
|
||||||
|
|
@ -162,9 +169,10 @@ def __establish_system_connection(
|
||||||
raise ConnectionError('The connection could not be established.')
|
raise ConnectionError('The connection could not be established.')
|
||||||
|
|
||||||
# ============= UPDATE STATE =============
|
# ============= UPDATE STATE =============
|
||||||
current_state.firewalled = firewall_tracker
|
if dns_setting and not did_dns_work:
|
||||||
current_state.dns_set = did_dns_work
|
current_state.firewalled = firewall_tracker
|
||||||
SystemStateController.update_or_create(current_state)
|
current_state.dns_set = did_dns_work
|
||||||
|
SystemStateController.update_or_create(current_state)
|
||||||
|
|
||||||
return Result(valid=True, data=current_state)
|
return Result(valid=True, data=current_state)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,8 @@ def check_and_kill_firewall():
|
||||||
logger.error(error_msg)
|
logger.error(error_msg)
|
||||||
|
|
||||||
# if the systemwide_raiser didn't catch it with the reason, then..
|
# if the systemwide_raiser didn't catch it with the reason, then..
|
||||||
raise ConnectionTerminationError(error_msg)
|
raise FirewallError(disable_result_object)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.info("We are skipping disabling the firewall, because it's already off.")
|
logger.info("We are skipping disabling the firewall, because it's already off.")
|
||||||
|
|
||||||
|
|
|
||||||
9
core/utils/basic_operations/process_tools.py
Normal file
9
core/utils/basic_operations/process_tools.py
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
from core.errors.logger import logger
|
||||||
|
import os
|
||||||
|
|
||||||
|
def is_running(pid: int) -> bool | None:
|
||||||
|
if not isinstance(pid, int):
|
||||||
|
logger.error("[SUBPROCESS CHECKER] Invalid int passed in for process id!")
|
||||||
|
return None
|
||||||
|
|
||||||
|
return os.path.exists(f"/proc/{pid}")
|
||||||
Loading…
Reference in a new issue