Files
zerogravity/docs/mitm-interception-status.md

243 lines
8.3 KiB
Markdown

# MITM Traffic Interception — Research & Status
## Goal
Capture the LS's LLM API traffic (requests + responses, including system prompts
and token usage) by routing it through our MITM proxy.
## Key Discovery: How the LS Makes LLM API Calls
The LS does **NOT** use gRPC for LLM API calls. It uses:
- **Protocol**: Standard HTTPS POST with Server-Sent Events (SSE)
- **Endpoint**: `https://daily-cloudcode-pa.googleapis.com/v1internal:streamGenerateContent?alt=sse`
- **HTTP client**: `ApiServerClientV2` — a Go HTTP client that creates its own `tls.Config`
and transport, **ignoring `HTTPS_PROXY` by default**
The Go HTTP client for LLM API calls is separate from the one used for Unleash
(feature flags) and other auxiliary traffic. The Unleash client respects proxy
settings, but the LLM client does not.
## What We Tried
### 1. Extension Patch — `detectAndUseProxy` ✅ Partial
**Status**: Applied and still active. Harmless.
The extension sends a protobuf field `detect_and_use_proxy` (field 34) to the LS
during initialization. By default, it's set to `UNSPECIFIED` (0), meaning the LS
ignores proxy env vars.
**Patch applied:**
```bash
sudo sed -i 's/detectAndUseProxy=pe.UNSPECIFIED/detectAndUseProxy=1/' \
/usr/share/antigravity/resources/app/extensions/antigravity/dist/extension.js
```
**Enum values:**
- 0 = `DETECT_AND_USE_PROXY_UNSPECIFIED` (default, ignore proxy)
- 1 = `DETECT_AND_USE_PROXY_ENABLED`
- 2 = `DETECT_AND_USE_PROXY_DISABLED`
**Result:** Unleash/aux traffic now routes through `HTTPS_PROXY`. But the LLM API
client (`ApiServerClientV2`) has its own transport that ignores this flag. LLM
calls still go direct to Google.
**Verify:** `grep -o 'detectAndUseProxy=[^;]*' /usr/share/antigravity/resources/app/extensions/antigravity/dist/extension.js`
→ should show `detectAndUseProxy=1`
**Re-apply after updates:** Yes, must re-apply after every Antigravity update.
### 2. MITM Wrapper (`mitm-wrapper.sh`) ✅ Works for Env Vars
Sets `HTTPS_PROXY` and `SSL_CERT_FILE` on the LS process by wrapping the binary.
**How it works:**
1. Renames real binary to `.real`
2. Places a shell script wrapper at the original path
3. Wrapper sets env vars and execs the real binary with all original args
**Result:** The wrapper correctly sets env vars on the LS process (verified via
`/proc/<PID>/environ`). Combined with the extension patch, Unleash traffic routes
through the proxy. But LLM API calls still bypass — the `ApiServerClientV2` Go
HTTP client doesn't honor `HTTPS_PROXY`.
### 3. iptables REDIRECT — ALL Port 443 ❌ Failed
Redirected all outbound port 443 traffic from the user's UID to the MITM proxy.
**Problems encountered:**
1. **Redirect loop** — proxy's own upstream connections got caught by iptables,
creating infinite loops → fd exhaustion → crash
2. **Fixed loop with GID bypass** — running proxy with `sg mitm-bypass` and
excluding GID in iptables. This fixed the loop.
3. **Broke Antigravity** — ALL HTTPS traffic (telegram, discord, microsoft
telemetry, extension marketplace, etc.) went through the proxy. The TLS
passthrough worked technically but was too disruptive.
4. **TLS trust failure** — even with the MITM wrapper setting `SSL_CERT_FILE`,
the LS's Go LLM client likely uses a custom `tls.Config` with its own root
CAs, not the system pool. So it rejected our MITM CA cert.
**Abandoned.** Too disruptive, and the fundamental TLS trust issue remained.
### 4. DNS Redirect (`/etc/hosts`) ❌ Failed
Redirected only `daily-cloudcode-pa.googleapis.com` to 127.0.0.1 via `/etc/hosts`,
then used a targeted iptables rule for `127.0.0.1:443` only.
**Problems:**
- Same TLS trust issue — the Go LLM client rejected our MITM CA
- Needed `dig @8.8.8.8` bypass for upstream resolution (implemented but untested)
**Abandoned.** TLS trust is the blocker.
## The Core Blocker
**The LS's Go LLM HTTP client (`ApiServerClientV2`) uses a custom `tls.Config`
that does NOT read from `SSL_CERT_FILE` or the system CA store.** It likely has
its own hardcoded/embedded root CAs.
This means:
- Even if we redirect traffic to our MITM proxy ✅
- Even if the MITM generates valid certs for the domain ✅
- The LS rejects the cert because it doesn't trust our CA ❌
## Potential Solutions (Untried)
### A. Binary Patching
Patch the Go binary to accept our CA or disable cert verification.
- Find the `tls.Config` setup in the binary
- Modify `InsecureSkipVerify` to `true`, or inject our CA cert DER bytes
- Very fragile, breaks on updates
### B. LD_PRELOAD Hook
Hook `connect()` syscall to redirect traffic.
- **Won't work** for Go — Go uses raw syscalls, not libc wrappers
### C. Network Namespace
Run the LS in an isolated network namespace with custom routing.
- Complex setup, but clean isolation
- The standalone LS work would feed into this
### D. Standalone LS with Full Control
Get standalone LS cascades working (see `docs/standalone-ls-todo.md`), then
have full control over the process environment, including:
- Custom CA trust
- Custom DNS resolution
- Custom proxy settings
- Network namespace isolation
**This is probably the best long-term approach.**
### E. Kernel-level TLS Interception (eBPF)
Use eBPF to intercept TLS records pre-encryption.
- Very powerful, can read plaintext before encryption
- Complex, requires kernel support (>= 4.18)
- Tools: `bpftrace`, custom eBPF programs, `ecapture`
### F. `SSLKEYLOGFILE` + Passive Capture
- Go doesn't support `SSLKEYLOGFILE` (confirmed by testing)
- Could patch the binary to enable it, but same fragility as option A
### G. ptrace-based Interception
Use `ptrace` to intercept `write()`/`sendmsg()` syscalls on TLS sockets.
- Can read plaintext data being written to TLS connections
- Tools: `strace -e trace=write -p <PID>` (but output is messy)
- Better: custom ptrace tool that filters for TLS socket FDs
## Technical Details
### Model IDs
| Placeholder | Model |
| ------------------------- | ------------------- |
| `MODEL_PLACEHOLDER_M18` | Gemini 3 Flash |
| `MODEL_PLACEHOLDER_M8` | Gemini 3 Pro (High) |
| `MODEL_PLACEHOLDER_M7` | Gemini 3 Pro (Low) |
| `MODEL_PLACEHOLDER_M26` | Claude Opus 4.6 |
| `MODEL_PLACEHOLDER_M12` | Claude Opus 4.5 |
| `MODEL_CLAUDE_4_5_SONNET` | Claude Sonnet 4.5 |
### LS Binary Location
`/usr/share/antigravity/resources/app/extensions/antigravity/bin/language_server_linux_x64`
### API Endpoint
`https://daily-cloudcode-pa.googleapis.com/v1internal:streamGenerateContent?alt=sse`
### Protobuf Field 34 — `detect_and_use_proxy`
- Part of the init metadata sent from extension to LS via stdin
- Enum: `DetectAndUseProxy` (0=UNSPECIFIED, 1=ENABLED, 2=DISABLED)
- Controls whether auxiliary HTTP clients honor `HTTPS_PROXY`
- Does NOT control the LLM API client
### Unleash Feature Flags
- Authorization: `*:production.e44558998bfc35ea9584dc65858e4485fdaa5d7ef46903e0c67712d1`
- Endpoint: `antigravity-unleash.goog`
- App name: `codeium-language-server`
### Files Modified (Current State)
- `extension.js``detectAndUseProxy=1` (harmless, keeps working)
- Everything else — clean/reverted
## Code Changes Made (in the proxy)
1. **Transparent proxy mode** (`src/mitm/proxy.rs`) — supports iptables REDIRECT
by detecting raw TLS ClientHello and extracting SNI
2. **CryptoProvider init** (`src/main.rs`) — prevents rustls panic under load
3. **PID detection fix** (`src/backend.rs`) — prefers `.real` binary PID over
wrapper shell script PID
4. **SS fallback** (`src/backend.rs`) — discovers LS port via `ss` when log file
doesn't have it
5. **DNS bypass** (`src/mitm/proxy.rs`) — `connect_upstream` resolves via
`dig @8.8.8.8` to bypass `/etc/hosts`
6. **Scripts**`dns-redirect.sh`, `iptables-redirect.sh` (both functional)
## Cleanup Checklist
If things are broken, undo in this order:
```bash
# 1. Remove iptables rules
sudo ./scripts/iptables-redirect.sh uninstall
sudo ./scripts/dns-redirect.sh uninstall
# 2. Remove /etc/hosts entries (verify manually)
sudo grep -v "antigravity-mitm" /etc/hosts | sudo tee /etc/hosts.tmp && sudo mv /etc/hosts.tmp /etc/hosts
# 3. Uninstall wrapper
sudo ./scripts/mitm-wrapper.sh uninstall
# 4. Remove system CA
sudo rm -f /usr/local/share/ca-certificates/antigravity-mitm.crt
sudo update-ca-certificates
# 5. Restart Antigravity
```
## Next Steps
→ See `docs/standalone-ls-todo.md` for standalone LS isolation work