diff --git a/src/standalone/spawn.rs b/src/standalone/spawn.rs index b9f39e7..b270c25 100644 --- a/src/standalone/spawn.rs +++ b/src/standalone/spawn.rs @@ -275,22 +275,32 @@ impl StandaloneLS { // With iptables, all outbound traffic is transparently redirected at the // kernel level — setting HTTPS_PROXY on top causes double-proxying. if headless || !platform::supports_uid_isolation() { - // proxy_addr already includes the scheme (e.g. "http://127.0.0.1:8742") - env_vars.push(("HTTPS_PROXY".into(), mitm.proxy_addr.clone())); - env_vars.push(("HTTP_PROXY".into(), mitm.proxy_addr.clone())); - // LD_PRELOAD DNS redirect: hooks getaddrinfo() so Google API domains // resolve to 127.0.0.1. Combined with the port-modified endpoint URL, // this makes the LS connect to our MITM proxy for ALL API calls — // even the CodeAssistClient which has Proxy:nil hardcoded. let so_path = build_dns_redirect_so(); - if let Some(so) = so_path { + if let Some(ref so) = so_path { info!(path = %so, "Enabling LD_PRELOAD DNS redirect for headless MITM"); - env_vars.push(("LD_PRELOAD".into(), so)); + env_vars.push(("LD_PRELOAD".into(), so.clone())); env_vars.push(( "DNS_REDIRECT_LOG".into(), format!("{data_dir}/dns-redirect.log"), )); + // Force Go binaries to use cgo (libc) DNS resolver instead of + // the pure-Go resolver. Without this, LD_PRELOAD getaddrinfo() + // hooks are bypassed because Go resolves DNS internally. + env_vars.push(("GODEBUG".into(), "netdns=cgo".into())); + } + + // Only set HTTPS_PROXY as fallback when DNS redirect is NOT available. + // When DNS redirect IS active, HTTPS_PROXY is redundant and harmful: + // Go's net/http sends HTTP CONNECT through the proxy, but the MITM + // proxy expects direct TLS connections (SNI-based interception). + // This causes OAuth token refresh and other non-gRPC calls to fail. + if so_path.is_none() { + env_vars.push(("HTTPS_PROXY".into(), mitm.proxy_addr.clone())); + env_vars.push(("HTTP_PROXY".into(), mitm.proxy_addr.clone())); } } }