fix: audit round 2 - DPAPI secrets, pinned hop probe, gost exe hash, admin guard, PID-scoped browser tracking, emergency disengage button, build sidecar
This commit is contained in:
@@ -161,66 +161,10 @@ def _dns_resolve_via_system(hostname: str, timeout: float = 5.0) -> str | None:
|
||||
return None
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class DnsLeakResult:
|
||||
resolver: str
|
||||
ip_via_proxy: str | None
|
||||
ip_direct: str | None
|
||||
leaked: bool
|
||||
detail: str
|
||||
|
||||
|
||||
def check_dns_leak(
|
||||
proxy_url: str,
|
||||
timeout_seconds: float = 8.0,
|
||||
) -> list[DnsLeakResult]:
|
||||
"""
|
||||
Detect DNS leaks: compare hostname resolution seen through proxy vs direct.
|
||||
A mismatch means DNS is escaping the tunnel.
|
||||
"""
|
||||
test_hosts = [
|
||||
("Cloudflare (1.1.1.1)", "one.one.one.one"),
|
||||
("Google (8.8.8.8)", "dns.google"),
|
||||
("OpenDNS", "resolver1.opendns.com"),
|
||||
]
|
||||
results: list[DnsLeakResult] = []
|
||||
timeout = httpx.Timeout(timeout_seconds, connect=min(6.0, timeout_seconds))
|
||||
|
||||
for label, host in test_hosts:
|
||||
# Get IP via direct system DNS
|
||||
direct_ip = _dns_resolve_via_system(host)
|
||||
|
||||
# Get IP as seen from the proxy path (via http://dns-endpoint)
|
||||
proxy_ip: str | None = None
|
||||
try:
|
||||
with httpx.Client(proxy=proxy_url, timeout=timeout, verify=False, follow_redirects=True) as c:
|
||||
r = c.get(f"https://{host}/")
|
||||
proxy_ip = str(r.headers.get("x-real-ip") or "")
|
||||
if not proxy_ip:
|
||||
# fall back: grab connected IP from response
|
||||
proxy_ip = None
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Simple leak heuristic: if direct resolution works but proxy connection fails, possible leak path
|
||||
leaked = bool(direct_ip and not proxy_ip)
|
||||
if leaked:
|
||||
detail = f"DNS resolved directly to {direct_ip} but proxy could not reach it — possible bypass"
|
||||
elif not direct_ip:
|
||||
detail = "Could not resolve directly"
|
||||
leaked = False
|
||||
else:
|
||||
detail = f"Direct: {direct_ip}"
|
||||
|
||||
results.append(DnsLeakResult(
|
||||
resolver=label,
|
||||
ip_via_proxy=proxy_ip,
|
||||
ip_direct=direct_ip,
|
||||
leaked=leaked,
|
||||
detail=detail,
|
||||
))
|
||||
|
||||
return results
|
||||
# NOTE: removed legacy ``check_dns_leak`` / ``DnsLeakResult`` — they relied on
|
||||
# the ``x-real-ip`` HTTP response header which proxy targets do not set, so
|
||||
# results were meaningless. Use :func:`proxy_chain_manager.dns_leak.run_dns_leak_test`
|
||||
# instead.
|
||||
|
||||
|
||||
def run_ban_tests(
|
||||
|
||||
Reference in New Issue
Block a user