Direct httpx2 IP address checking, instead of subprocess for connection tests.
This commit is contained in:
parent
a7b733db0d
commit
ed517f4568
6 changed files with 102 additions and 25 deletions
|
|
@ -5,7 +5,8 @@ from core.services.networking.general_connection_tools.testing_evaluating import
|
|||
from core.services.networking.systemwide.systemwide_wireguard import establish_system_connection, terminate_system_connection
|
||||
from core.services.keys_and_verifications.endpoint_verification import verify_wireguard_endpoint
|
||||
from core.observers.TicketObserver import TicketObserver
|
||||
|
||||
from core.services.networking.systemwide.general_tools.test_any_protocol import test_session_ip
|
||||
from core.models.enum_models import ProtocolChoice
|
||||
|
||||
from collections.abc import Callable
|
||||
from core.Constants import Constants
|
||||
|
|
@ -79,8 +80,6 @@ class ConnectionController:
|
|||
else:
|
||||
from core.services.profiles.profile_connections import disable_profile
|
||||
disable_profile(profile=profile, connection_observer=connection_observer, ticket_observer=ticket_observer)
|
||||
# from core.controllers.ProfileController import ProfileController
|
||||
# ProfileController.disable(profile=profile, connection_observer=connection_observer, ticket_observer=ticket_observer)
|
||||
|
||||
|
||||
if profile.connection.code == 'tor':
|
||||
|
|
@ -107,14 +106,28 @@ class ConnectionController:
|
|||
ConnectionController.establish_proxy_session_connection(profile, session_directory, port_number, proxy_port_number)
|
||||
session_state.network_port_numbers.proxy.append(proxy_port_number)
|
||||
|
||||
if not profile.connection.is_unprotected():
|
||||
# if not profile.connection.is_unprotected():
|
||||
|
||||
if profile.connection.code == 'wireguard':
|
||||
test_result = test_session_ip(port=port_number, profile_id=profile.id, protocol=ProtocolChoice.WIREGUARD, connection_observer=connection_observer)
|
||||
if test_result.valid:
|
||||
logger.info("Connection established.")
|
||||
if connection_observer:
|
||||
connection_observer.notify("connected", "Confirmed")
|
||||
else:
|
||||
logger.error(test_result.message)
|
||||
raise ConnectionError(test_result.message)
|
||||
|
||||
elif profile.connection.code == 'tor':
|
||||
await_connection(proxy_port_number or port_number, connection_observer=connection_observer)
|
||||
|
||||
|
||||
SessionStateController.update_or_create(session_state)
|
||||
|
||||
return proxy_port_number or port_number
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def establish_tor_connection(connection_observer: Optional[ConnectionObserver] = None):
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -1,21 +1,36 @@
|
|||
from core.models.BaseProfile import ProfileType
|
||||
from core.Constants import Constants
|
||||
import os
|
||||
from core.errors.logger import logger
|
||||
|
||||
def extract_endpoint_ip(profile_id: str) -> str | bool:
|
||||
try:
|
||||
profile_path = Constants.HV_PROFILE_CONFIG_HOME + f'/{profile_id}'
|
||||
import os
|
||||
from typing import Optional
|
||||
|
||||
def extract_endpoint_ip(profile_id: str, profile_type: Optional[ProfileType] = None) -> str | bool:
|
||||
|
||||
profile_path = Constants.HV_PROFILE_CONFIG_HOME + f'/{profile_id}'
|
||||
|
||||
if not profile_type: # assumes systemwide:
|
||||
wg_conf_path = f'{profile_path}/wg.conf.bak'
|
||||
print(f"wg_conf_path is {wg_conf_path}")
|
||||
if not os.path.exists(wg_conf_path):
|
||||
return None
|
||||
elif profile_type == ProfileType.SESSION:
|
||||
wg_conf_path = f'{profile_path}/wg.conf'
|
||||
else:
|
||||
return None
|
||||
|
||||
if not os.path.exists(wg_conf_path):
|
||||
logger.error(f"Path doesn't exist: {wg_conf_path}")
|
||||
return None
|
||||
|
||||
try:
|
||||
with open(wg_conf_path, 'r') as f:
|
||||
content = f.read()
|
||||
for line in content.split('\n'):
|
||||
if line.strip().startswith('Endpoint = '):
|
||||
endpoint = line.strip().split(' = ')[1]
|
||||
return endpoint.split(':')[0]
|
||||
logger.error("Found no content.")
|
||||
return None
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
logger.error(f"Unable to parse WG config: {str(e)}")
|
||||
return None
|
||||
|
||||
def extract_dns(profile_id: str) -> str | bool:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ from core.services.networking.httpx.classify_response import classify_response
|
|||
from core.models.Result import Result, ResultError
|
||||
from core.services.networking.api_requests.ApiResponseModel import ApiResponse, ErrorType
|
||||
|
||||
# errors/loggers/observers
|
||||
from core.Constants import Constants
|
||||
from core.errors.logger import logger
|
||||
from essentials.observers.ConnectionObserver import ConnectionObserver
|
||||
|
|
@ -13,6 +12,10 @@ from essentials.observers.ConnectionObserver import ConnectionObserver
|
|||
import time
|
||||
import random
|
||||
import httpx
|
||||
from httpx_socks import AsyncProxyTransport
|
||||
import httpx_socks
|
||||
from httpx_socks import ProxyType
|
||||
|
||||
from typing import Optional
|
||||
|
||||
API_ENDPOINT_FORMATS = {
|
||||
|
|
@ -26,7 +29,7 @@ API_ENDPOINT_FORMATS = {
|
|||
|
||||
MAX_ATTEMPTS = 3
|
||||
|
||||
def test(connection_observer: Optional[ConnectionObserver]) -> Result:
|
||||
def test(connection_observer: Optional[ConnectionObserver], port: Optional[int] = None) -> Result:
|
||||
"""
|
||||
Cycles through 3 possible endpoints,
|
||||
to attempt to get an IP address for the systemwide connection.
|
||||
|
|
@ -35,7 +38,16 @@ def test(connection_observer: Optional[ConnectionObserver]) -> Result:
|
|||
endpoint_index = 0
|
||||
endpoint_list = list(API_ENDPOINT_FORMATS.keys())
|
||||
|
||||
_ip_test_client = httpx.Client(http2=True, timeout=6)
|
||||
if port:
|
||||
transport = httpx_socks.SyncProxyTransport(
|
||||
proxy_type=ProxyType.SOCKS5,
|
||||
proxy_host="127.0.0.1",
|
||||
proxy_port=port,
|
||||
)
|
||||
_ip_test_client = httpx.Client(transport=transport, http2=True, timeout=6)
|
||||
else:
|
||||
_ip_test_client = httpx.Client(http2=True, timeout=6)
|
||||
|
||||
|
||||
while attempt < MAX_ATTEMPTS:
|
||||
endpoint_url = endpoint_list[attempt]
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
from core.services.networking.general_connection_tools.config_tools import extract_endpoint_ip
|
||||
from core.services.networking.general_connection_tools import ip
|
||||
from essentials.observers.ConnectionObserver import ConnectionObserver
|
||||
from core.models.BaseProfile import ProfileType
|
||||
from core.models.enum_models import ProtocolChoice
|
||||
from core.utils.basic_operations.write_or_read_from_json import get_value_from_json_file
|
||||
from core.models.Result import Result, ResultError
|
||||
|
|
@ -11,6 +12,29 @@ from core.Constants import Constants
|
|||
import os
|
||||
|
||||
|
||||
def test_session_ip(port: int, profile_id: int, protocol: ProtocolChoice, connection_observer: ConnectionObserver) -> Result:
|
||||
"""Compare the real vs expected IP address."""
|
||||
|
||||
if protocol == ProtocolChoice.WIREGUARD:
|
||||
expected_ip_address = extract_endpoint_ip(profile_id=profile_id, profile_type=ProfileType.SESSION)
|
||||
else:
|
||||
error_msg = "Not currently supported protocol for test_session_ip"
|
||||
logger.error(error_msg)
|
||||
return Result(valid=False, error_type=ResultError.INVALID_INPUT, message=error_msg)
|
||||
|
||||
if not expected_ip_address:
|
||||
error_msg = "Could not get the expected IP address from local files."
|
||||
logger.error(error_msg)
|
||||
return Result(valid=False, error_type=ResultError.MISSING_DATA, message=error_msg)
|
||||
|
||||
# reality:
|
||||
logger.info(f"testing on port {port}")
|
||||
ip_result = ip.test(connection_observer=connection_observer, port=port)
|
||||
|
||||
return compare_ips(ip_result=ip_result, expected_ip_address=expected_ip_address)
|
||||
|
||||
|
||||
|
||||
def get_singbox_ip(profile_id: int) -> str|None:
|
||||
"""Get the IP address for a Singbox based profile based on local disk."""
|
||||
config_path = f'{Constants.HV_SYSTEM_PROFILE_CONFIG_PATH}/{profile_id}/proxy.json'
|
||||
|
|
@ -26,9 +50,6 @@ def get_singbox_ip(profile_id: int) -> str|None:
|
|||
def test_ip_systemwide_for_any_protocol(profile_id: int, protocol: ProtocolChoice, connection_observer: ConnectionObserver) -> Result:
|
||||
"""Compare the real vs expected IP address."""
|
||||
|
||||
# protocol = profile.type
|
||||
# profile_id = profile.id
|
||||
|
||||
# what's expected:
|
||||
if protocol == ProtocolChoice.WIREGUARD:
|
||||
expected_ip_address = extract_endpoint_ip(profile_id)
|
||||
|
|
@ -45,6 +66,12 @@ def test_ip_systemwide_for_any_protocol(profile_id: int, protocol: ProtocolChoic
|
|||
# reality:
|
||||
ip_result = ip.test(connection_observer)
|
||||
|
||||
return compare_ips(ip_result=ip_result, expected_ip_address=expected_ip_address)
|
||||
|
||||
|
||||
def compare_ips(ip_result: Result, expected_ip_address: str) -> Result:
|
||||
"""Compare the expected to the real IP address."""
|
||||
|
||||
if not ip_result.valid:
|
||||
logger.error(ip_result.message)
|
||||
return ip_result # result object
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ from core.services.keys_and_verifications.endpoint_verification import verify_wi
|
|||
from core.models.Result import Result, ResultError
|
||||
from core.services.networking.systemwide.systemwide_utils import extract_wg_interface_name, check_system_prereqs
|
||||
from core.observers.Notifications import Notifications, EventType
|
||||
from core.services.networking.systemwide.general_tools.test_any_protocol import test_ip_systemwide_for_any_protocol
|
||||
|
||||
|
||||
# from core.services.networking.general_connection_tools.config_tools import extract_endpoint_ip, extract_dns
|
||||
from core.services.networking.systemwide import killswitch
|
||||
|
|
@ -198,13 +200,16 @@ def __establish_system_connection(
|
|||
|
||||
# ============= TESTING =============
|
||||
logger.info("If we made it this far, we have nmcli on, ipv6 sinkhole on, firewall on.")
|
||||
try:
|
||||
if connection_observer:
|
||||
connection_observer.notify("connecting", "Testing Connection Health..")
|
||||
await_connection(connection_observer=connection_observer)
|
||||
if connection_observer:
|
||||
connection_observer.notify("connecting", "Testing Connection Health..")
|
||||
|
||||
except ConnectionError:
|
||||
raise ConnectionError('The connection could not be established.')
|
||||
test_result = test_ip_systemwide_for_any_protocol(
|
||||
profile_id=profile.id,
|
||||
protocol=ProtocolChoice.WIREGUARD,
|
||||
connection_observer=connection_observer
|
||||
)
|
||||
if not test_result.valid:
|
||||
return test_result
|
||||
|
||||
# ============= UPDATE STATE =============
|
||||
if dns_setting and not did_dns_work:
|
||||
|
|
@ -212,6 +217,9 @@ def __establish_system_connection(
|
|||
current_state.dns_set = did_dns_work
|
||||
SystemStateController.update_or_create(current_state)
|
||||
|
||||
if connection_observer:
|
||||
connection_observer.notify("connected", "Confirmed")
|
||||
|
||||
Notifications.emit(EventType.SYSTEM_ENABLE, profile.id)
|
||||
return Result(valid=True, data=current_state)
|
||||
|
||||
|
|
@ -221,6 +229,7 @@ def evaluate_connection_result(connection_result: Result) -> Result:
|
|||
"""In the future, this will raise other error types or filter replies."""
|
||||
if not connection_result.valid:
|
||||
logger.error(f"[SYSTEMWIDE WG] Critical issue, could not establish a connection: {connection_result.message}")
|
||||
time.sleep(1)
|
||||
raise ConnectionError(f"Connection validation failed: {connection_result.message}")
|
||||
else:
|
||||
return connection_result
|
||||
|
|
@ -309,5 +318,5 @@ def establish_system_connection(
|
|||
raise
|
||||
|
||||
terminate_tor_connection()
|
||||
time.sleep(1.0)
|
||||
time.sleep(0.3)
|
||||
return final_result
|
||||
|
|
@ -7,6 +7,7 @@ from core.Constants import Constants
|
|||
from core.models.Result import Result, ResultError
|
||||
from core.errors.logger import logger
|
||||
|
||||
|
||||
def wipe_ticket_cycle() -> Result:
|
||||
"""Wipe the entire global ticketing cycle & all associated tickets."""
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue