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:
@@ -171,6 +171,66 @@ def _reset_winhttp_proxy() -> None:
|
||||
pass
|
||||
|
||||
|
||||
# ── browser-policy proxy (Chrome / Edge) ─────────────────────────────────────
|
||||
#
|
||||
# Why this exists: when you set WebRTC policy on Chrome/Edge, the browser sees
|
||||
# itself as "managed". Some managed-Chrome builds then *ignore* the system
|
||||
# proxy unless an explicit ``ProxyServer`` policy is also set. They also keep
|
||||
# trying HTTP/3 over QUIC (UDP/443), which bypasses HTTP proxies entirely —
|
||||
# under the kill-switch those UDP packets get dropped and pages hang forever.
|
||||
#
|
||||
# Setting these policy values pins the browser to our chain (HTTP proxy) and
|
||||
# forces it off QUIC. Cleared cleanly on disengage.
|
||||
_BROWSER_POLICY_PATHS = (
|
||||
r"SOFTWARE\Policies\Google\Chrome",
|
||||
r"SOFTWARE\Policies\Microsoft\Edge",
|
||||
r"SOFTWARE\Policies\Chromium",
|
||||
)
|
||||
|
||||
def _set_browser_proxy_policy(host: str, port: int, bypass: str) -> int:
|
||||
"""Pin Chromium-based browsers (Chrome, Edge, Chromium) to our local proxy
|
||||
via Group Policy registry, and disable QUIC. Returns count of keys updated.
|
||||
|
||||
Requires Admin to write under HKLM\\SOFTWARE\\Policies. Silently skips when
|
||||
not elevated — the user gets a warning in the service log instead.
|
||||
"""
|
||||
if not _is_admin():
|
||||
return 0
|
||||
proxy_value = f"http={host}:{port};https={host}:{port}"
|
||||
bypass_value = bypass.replace(";", ",")
|
||||
written = 0
|
||||
for path in _BROWSER_POLICY_PATHS:
|
||||
try:
|
||||
with winreg.CreateKeyEx(
|
||||
winreg.HKEY_LOCAL_MACHINE, path, 0, winreg.KEY_SET_VALUE
|
||||
) as key:
|
||||
winreg.SetValueEx(key, "ProxyMode", 0, winreg.REG_SZ, "fixed_servers")
|
||||
winreg.SetValueEx(key, "ProxyServer", 0, winreg.REG_SZ, proxy_value)
|
||||
winreg.SetValueEx(key, "ProxyBypassList", 0, winreg.REG_SZ, bypass_value)
|
||||
winreg.SetValueEx(key, "QuicAllowed", 0, winreg.REG_DWORD, 0)
|
||||
written += 1
|
||||
except OSError:
|
||||
continue
|
||||
return written
|
||||
|
||||
|
||||
def _clear_browser_proxy_policy() -> None:
|
||||
if not _is_admin():
|
||||
return
|
||||
for path in _BROWSER_POLICY_PATHS:
|
||||
try:
|
||||
with winreg.OpenKey(
|
||||
winreg.HKEY_LOCAL_MACHINE, path, 0, winreg.KEY_SET_VALUE
|
||||
) as key:
|
||||
for name in ("ProxyMode", "ProxyServer", "ProxyBypassList", "QuicAllowed"):
|
||||
try:
|
||||
winreg.DeleteValue(key, name)
|
||||
except OSError:
|
||||
pass
|
||||
except OSError:
|
||||
continue
|
||||
|
||||
|
||||
def _read_proxy_settings_per_user() -> int | None:
|
||||
"""``HKLM\\…\\Internet Settings\\ProxySettingsPerUser``.
|
||||
|
||||
@@ -382,8 +442,12 @@ def set_system_proxy(
|
||||
_write_conn_blob(winreg.HKEY_LOCAL_MACHINE, _HKLM_CONN_PATH, proxy, bypass)
|
||||
|
||||
_set_winhttp_proxy(host, port, bypass)
|
||||
n_browser = _set_browser_proxy_policy(host, port, bypass)
|
||||
_broadcast()
|
||||
log.info("System proxy set %s (bypass=%s) — HKCU + HKLM(adm) + Connections + WinHTTP", proxy, bypass)
|
||||
log.info(
|
||||
"System proxy set %s (bypass=%s) — HKCU + HKLM(adm) + Connections + WinHTTP + %d browser policy",
|
||||
proxy, bypass, n_browser,
|
||||
)
|
||||
|
||||
|
||||
def clear_system_proxy() -> None:
|
||||
@@ -401,8 +465,9 @@ def clear_system_proxy() -> None:
|
||||
_clear_hklm_root()
|
||||
_clear_conn_blob(winreg.HKEY_LOCAL_MACHINE, _HKLM_CONN_PATH)
|
||||
_reset_winhttp_proxy()
|
||||
_clear_browser_proxy_policy()
|
||||
_broadcast()
|
||||
log.info("System proxy cleared — HKCU + HKLM(adm) + Connections + WinHTTP")
|
||||
log.info("System proxy cleared — HKCU + HKLM(adm) + Connections + WinHTTP + browser policy")
|
||||
|
||||
|
||||
def is_system_proxy_set() -> bool:
|
||||
|
||||
Reference in New Issue
Block a user