# 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