srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/internal/proxy/proxy.go
AgeCommit message (Collapse)AuthorFilesLines
2024-02-14History view: SQLite storage, daemon/TUI split over Unix socketsrdusr1-71/+198
Implements build-order step 3. Adds: - internal/store: SQLite (WAL, single-writer) history table, raw request/response blobs plus metadata for the list view. - internal/proxy: request/response capture wired into forward(). HTTP/1.1 legs are captured byte-exact via a teeConn that records wire bytes as they're read, taken right after the message is fully drained (so no manual re-reading/replaying is needed - RoundTrip's own streaming does the draining). HTTP/2 legs (no meaningful "raw bytes" of their own - multiplexed, HPACK-compressed framing) are reconstructed instead, and marked as such in storage. - internal/ipc: JSON-over-Unix-socket protocol between mitmuxd (owns the proxy and the DB) and any client - list/get for queries, subscribe for a live push stream of newly captured entries. Keeps the proxy engine independent of the UI, per the architecture sketch. - cmd/mitmux: Bubble Tea TUI - a live-updating history table and a request/response detail view with raw bytes. Two real bugs surfaced during testing and got fixed before commit: 1. http.Transport's HTTP/2 auto-dispatch does a literal *tls.Conn type assertion on the dialed connection; wrapping it in a capturing teeConn broke that silently, and HTTP/2 framing got parsed as HTTP/1.1 text. Fixed by dropping http.Transport for the upstream leg entirely in favor of an explicit per-protocol round trip (see PLAN.md stack note). 2. singleConnListener wrapped the client teeConn *inside* a closeSignalConn, so ConnContext's type assertion for it silently failed and HTTP/1.1 client-side capture never activated. Fixed the wrap order; verified via direct SQLite inspection that request_exact flips back to 1 and the stored bytes are genuinely wire-exact (preserved chunked-encoding framing, original header casing/order). Verified live: plain HTTP, HTTPS H1.1, HTTPS H2, and a POST with a body, checked against the raw stored bytes directly in SQLite; IPC list/get/ subscribe against a throwaway client; and the TUI driven end-to-end in a tmux session (list, detail view, tab between request/response, live update on a new request while sitting on the list).
2024-01-27TLS interception: per-host leaf certs, terminate-and-resign MITM, native HTTP/2srdusr1-26/+157
Implements build-order step 2. CA gains LeafFor(host), signing and caching per-host leaf certificates on demand. The proxy's CONNECT handler now terminates TLS with the client using a matching leaf cert instead of tunneling raw bytes, and forwards each request upstream over its own independently negotiated TLS connection. Client-side and upstream-side ALPN are negotiated separately rather than one being forced to mirror the other: an http.Transport configured via http2.ConfigureTransport auto-bridges HTTP/1.1 and HTTP/2 on each side independently, so e.g. an HTTP/1.1-only client reaching an HTTP/2-preferring origin still works instead of failing the handshake (caught by testing curl --http1.1 against example.com before this fix). Verified live: plain HTTP passthrough, HTTPS with default (H2) and forced HTTP/1.1 clients, and that requests without the mitmux CA trusted are correctly rejected.
2024-01-16Scaffold mitmux: proxy daemon, CA generation, HTTP/CONNECT passthroughsrdusr1-0/+153
Implements build-order step 1: headless proxy daemon (mitmuxd) with plaintext HTTP passthrough and raw CONNECT tunneling, plus root CA generation/persistence for later TLS interception. Verified live against real HTTP and HTTPS requests through the proxy.