README.md

# httptap

A terminal UI that shows the HTTP(S) traffic of a running process in real
time, using eBPF uretprobes on TLS libraries. No proxy, no cert shenanigans.

    $ sudo httptap --pid 42317

Think of it as `strace -e trace=network` for people who would rather read
a request line than a hex dump.

## Quickstart

Linux, kernel >= 5.8, and root (or CAP_BPF + CAP_PERFMON) are required.

    # build
    make bpf        # compile the bpf object
    make build      # build the static Go binary

    # attach by pid
    sudo ./bin/httptap --pid 42317

    # attach by process name (first match)
    sudo ./bin/httptap --name nginx

    # follow forks
    sudo ./bin/httptap --pid 42317 --follow-forks

Press `?` inside the TUI for keybindings. `q` quits, `/` filters,
`Enter` expands a request, `y` yanks the selected request as a curl
command to the clipboard.

## How it works

httptap attaches uretprobes to well-known functions that see plaintext
before TLS encrypts it:

- OpenSSL `SSL_read` and `SSL_write`
- GnuTLS `gnutls_record_send` and `gnutls_record_recv`
- Go's `crypto/tls.(*Conn).Write` (resolved from the binary's symbols)

On each probe hit, a short BPF program reads the buffer into a ring
buffer. Userspace picks up the bytes, feeds them through a lightweight
HTTP parser, pairs requests with their responses, and renders the result
in a bubbletea-based TUI.

Because the probe sits before encryption on send and after decryption on
receive, you get the plaintext without having to own a key.

## Limitations

- HTTP/2 and HTTP/3 are shown at frame level only; the parser does not
  reconstruct streams. Good enough to see the method and path, not good
  enough for response bodies.
- Static Go binaries stripped of symbols need `--go-symbols path/to/bin`
  to help the resolver.
- BoringSSL isn't auto-detected yet; pass `--probe SSL_read:path/to/lib`
  manually.
- This is a debugging tool. Point it at workloads you already have the
  right to inspect.

## Development

    make test        # unit tests
    make vet         # go vet
    go run ./cmd/httptap --pid $(pgrep -f mything)

The BPF source lives in `internal/tracer/tracer.bpf.c` and is compiled
to a .o object that gets embedded into the Go binary via `go:embed`.

## License

MIT. See `LICENSE`.

## See also

- `strace(1)` — still unbeatable for system call noise
- `bpftrace` — for ad-hoc one-liners
- Wireshark with SSLKEYLOGFILE — if you own the keys