From a116597a38958d995a48ff0af4aeacb18b922397 Mon Sep 17 00:00:00 2001 From: SimplifiedPrivacy Date: Sun, 19 Jul 2026 15:33:36 -0400 Subject: [PATCH] Fixing proxy subscriptions --- .../connection_enable.py | 37 ++++-- .../systemwide/firewall_isolated.sh | 118 ++++++++++++++++++ pyproject.toml | 4 +- 3 files changed, 144 insertions(+), 15 deletions(-) create mode 100644 core/services/networking/systemwide/firewall_isolated.sh diff --git a/core/services/networking/general_connection_tools/connection_enable.py b/core/services/networking/general_connection_tools/connection_enable.py index 94e7b7a..0fc7295 100644 --- a/core/services/networking/general_connection_tools/connection_enable.py +++ b/core/services/networking/general_connection_tools/connection_enable.py @@ -59,18 +59,21 @@ def _ensure_proxy_configured( if not profile.connection.needs_proxy_configuration(): return - _ensure_subscription_ready(profile, connection_observer) - - proxy_config = ConnectionController.with_preferred_connection( - profile.subscription.billing_code, - task=WebServiceApiService.get_proxy_configuration, - connection_observer=connection_observer - ) - - if proxy_config is None: - raise InvalidSubscriptionError() - - profile.attach_proxy_configuration(proxy_config) + if not profile.has_proxy_configuration(): + logger.info(f"[CONNECTION] You need a new proxy configuration") + _ensure_subscription_ready(profile, connection_observer) + + logger.info(f"[CONNECTION] Getting a proxy config from web service..") + proxy_config = ConnectionController.with_preferred_connection( + profile.subscription.billing_code, + task=WebServiceApiService.get_proxy_configuration, + connection_observer=connection_observer + ) + + if proxy_config is None: + raise InvalidSubscriptionError() + + profile.attach_proxy_configuration(proxy_config) def _ensure_wireguard_configured( @@ -126,4 +129,12 @@ def __should_renegotiate(profile: Union[SessionProfile, SystemProfile]): if profile.subscription.has_been_activated(): return True else: - return False \ No newline at end of file + return False + + + +# Enums +# if profile.type == ProfileType.SYSTEM: +# print("This is a system profile") +# elif profile.type == ProfileType.SESSION: +# print("This is a session profile") diff --git a/core/services/networking/systemwide/firewall_isolated.sh b/core/services/networking/systemwide/firewall_isolated.sh new file mode 100644 index 0000000..6ae9a34 --- /dev/null +++ b/core/services/networking/systemwide/firewall_isolated.sh @@ -0,0 +1,118 @@ +#!/bin/bash +set -euo pipefail + +# root check +if [[ "$EUID" -ne 0 ]]; then + echo "[killswitch] ERROR: must be run as root" >&2 + exit 1 +fi + +ACTION="${1:-}" +SERVER_IP="${2:-}" +TUNNEL_IF="${3:-}" +TABLE="hydraveil" + +# Confirm the action is among the valid choices: +if [[ "$ACTION" != "arm" && "$ACTION" != "disarm" && "$ACTION" != "status" ]]; then + echo "[killswitch] ERROR: invalid action '$ACTION'. Usage: arm | disarm | status" >&2 + exit 1 +fi + +# This function gets the default route. The function is used during the arm phase later on. +_default_iface() { + ip route show default 2>/dev/null | awk 'NR==1{print $5}' +} + +# Log changes in the rules: +_log() { + local level="$1"; shift + echo "[killswitch] [$level] $* — $(date '+%Y-%m-%d %H:%M:%S')" >&2 +} + +# use the presence of the table to detect if the rules are active, which we define as "armed" +if [[ "$ACTION" == "status" ]]; then + if nft list table inet "$TABLE" &>/dev/null 2>&1; then + echo "armed" + else + echo "disarmed" + fi + exit 0 +fi + +# If disarm is chosen, then check if the table rules exist, and if so, delete the table. Then log it. +if [[ "$ACTION" == "disarm" ]]; then + if nft list table inet "$TABLE" &>/dev/null 2>&1; then + nft delete table inet "$TABLE" + _log "INFO" "disarmed" + else + _log "INFO" "already disarmed" + fi + exit 0 +fi + +# Check the pre-reqs exist. We need a server IP and a tunnel interface. +[[ -z "$SERVER_IP" ]] && { _log "ERROR" "server_ip required for arm"; exit 1; } +[[ -z "$TUNNEL_IF" ]] && { _log "ERROR" "tunnel_if required for arm"; exit 1; } + +# Confirm the IPv4 address is a valid format. But does NOT check if it's actually a live server. +# Just that it looks like an IPv4 address. +if ! [[ "$SERVER_IP" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then + _log "ERROR" "invalid IPv4: $SERVER_IP" + exit 1 +fi + +IFS='.' read -r o1 o2 o3 o4 <<< "$SERVER_IP" +for oct in "$o1" "$o2" "$o3" "$o4"; do + if (( oct > 255 )); then + _log "ERROR" "invalid IPv4 octet ($oct) in $SERVER_IP" + exit 1 + fi +done + +# This uses the function at the top of the file to get the default WAN interface, and then checks that it got a result. +WAN_IFACE=$(_default_iface) +if [[ -z "$WAN_IFACE" ]]; then + _log "ERROR" "could not detect primary network interface" + exit 1 +fi + +# Either list out the table rules and delete them, or return True. +nft list table inet "$TABLE" &>/dev/null 2>&1 && nft delete table inet "$TABLE" || true + +table inet ${TABLE} { + chain output { + type filter hook output priority filter; policy drop; + # Allow all loopback traffic (localhost) + oifname "lo" accept + + # Drop all IPv6 except loopback (::1). This blocks IPv6 from leaving the system entirely + ip6 daddr != ::1 drop + + # Allow IPv4 traffic to the server IP on the WAN interface + oifname "${WAN_IFACE}" ip daddr ${SERVER_IP} accept + + # Allow all traffic (IPv4 and IPv6) on the WireGuard tunnel interface + oifname "${TUNNEL_IF}" accept + } + chain input { + type filter hook input priority filter; policy drop; + # Allow all loopback traffic (localhost) + iifname "lo" accept + + # Drop all IPv6 except loopback (::1). This blocks IPv6 from entering the system entirely + ip6 saddr != ::1 drop + + # Allow established and related connections (stateful firewall tracking) + ct state established,related accept + + # Allow IPv4 traffic from the server IP on the WAN interface + iifname "${WAN_IFACE}" ip saddr ${SERVER_IP} accept + + # Allow all traffic (IPv4 and IPv6) from the WireGuard tunnel interface + iifname "${TUNNEL_IF}" accept + } + chain forward { + type filter hook forward priority filter; policy drop; + # Drop all forwarded traffic (nothing is routed through this system) + } +} diff --git a/pyproject.toml b/pyproject.toml index be0f0df..d8cd0c5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,7 +45,7 @@ dependencies = [ "typing-inspection==0.4.2", "typing_extensions==4.15.0", "urllib3==2.6.3", - "httpx==0.28.1", + "httpx[http2]==0.28.1", "dnspython==2.8.0", "socksio==1.0.0", ] @@ -59,4 +59,4 @@ requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] -packages = ["core"] +packages = ["core"]-