Save-as-final-hop button, browser proxy policy + QUIC kill, HTTPS tunnel probe
Fixes 'exit proxy never used in chain' and 'browsers break when chain is green'. Chain Builder gets a Save-as-final-hop button that appends the typed exit proxy to the manual chain. On engage, Chromium browsers get pinned to our proxy via HKLM policy (ProxyMode=fixed_servers, ProxyServer, ProxyBypassList) and QuicAllowed=0 so HTTP/3 doesn't bypass HTTP proxies and stall under the kill-switch. Chain start now runs check_https_tunnel and warns clearly when proxies forward HTTP but refuse CONNECT — the real cause of green-chain-yet-blank-browser. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -237,3 +237,41 @@ async def get_direct_ip(check_url: str, timeout_seconds: float = 15.0) -> str |
|
||||
except asyncio.TimeoutError:
|
||||
log.debug("get_direct_ip timed out after %.1fs", budget)
|
||||
return None
|
||||
|
||||
|
||||
async def check_https_tunnel(
|
||||
listen_proxy: str,
|
||||
timeout_seconds: float = 12.0,
|
||||
) -> tuple[bool, str]:
|
||||
"""Return (ok, message). True means the chain successfully tunneled HTTPS.
|
||||
|
||||
Many free proxies pass plain HTTP but refuse HTTP ``CONNECT`` (the method
|
||||
required to tunnel TLS). The chain can look healthy on an IP-check via
|
||||
plain HTTP yet break every HTTPS page a browser tries to load. This probe
|
||||
catches that case at start time so the user gets a clear warning instead
|
||||
of a mystery "browser broken".
|
||||
"""
|
||||
per = max(5.0, min(20.0, float(timeout_seconds)))
|
||||
t = httpx.Timeout(per, connect=min(8.0, per))
|
||||
# Use a tiny, fast, very-common HTTPS endpoint.
|
||||
targets = [
|
||||
"https://www.google.com/generate_204",
|
||||
"https://www.cloudflare.com/cdn-cgi/trace",
|
||||
"https://duckduckgo.com/",
|
||||
]
|
||||
last_err = ""
|
||||
try:
|
||||
async with httpx.AsyncClient(
|
||||
proxy=listen_proxy, timeout=t, verify=False, follow_redirects=True,
|
||||
) as c:
|
||||
for url in targets:
|
||||
try:
|
||||
r = await c.get(url)
|
||||
if 200 <= r.status_code < 400:
|
||||
return True, f"HTTPS OK via {url} ({r.status_code})"
|
||||
except Exception as e:
|
||||
last_err = f"{type(e).__name__}: {e}"
|
||||
continue
|
||||
except Exception as e:
|
||||
last_err = f"{type(e).__name__}: {e}"
|
||||
return False, last_err or "all HTTPS targets failed"
|
||||
|
||||
Reference in New Issue
Block a user