tinytap

module
v0.6.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 11, 2026 License: MIT

README

tinytap

Test codecov Go Report Card Go Reference OpenSSF Scorecard OpenSSF Best Practices

A tiny eBPF-based HTTP traffic capture tool for local development.

An ordinary app calls an API over HTTPS; tinytap's TUI (output = "tui" in the config file — see Configuration) shows the exact bytes that app sent — the request line, every header including Authorization: Bearer, and the decoded JSON body — in plaintext, with no proxy and no CA certificate installed. In the request table j/k scroll and Enter opens the detail panel (b toggles the hex body view). See scripts/demo/ for how the gif is recorded.

Quick start

Install it with:

curl -fsSL https://raw.githubusercontent.com/shinagawa-web/tinytap/main/scripts/install.sh | sh

Grant it the capabilities it needs, then run it — no full root required:

sudo setcap cap_dac_read_search,cap_perfmon,cap_bpf,cap_sys_admin,cap_syslog=eip $(command -v tinytap)
tinytap

That's the full set — plaintext HTTP and HTTPS (via the libssl uprobes, cap_sys_admin) both work out of the box. See Running Without Full Root on the docs site if you want the smaller plaintext-only set instead.

With no config file, that opens the TUI shown at the top of this README — j/k to scroll, Enter for the detail panel, q or Ctrl-C to quit — as long as your terminal is at least 120x24. In a smaller or non-interactive terminal it prints guidance and exits instead of silently streaming; see Configuration to switch to the line-oriented stdout mode.

Didn't work? Run tinytap doctor first for a read-only preflight report (kernel version, capabilities, libssl execute bit, etc.) — see Troubleshooting.

Linux amd64/arm64 only — on macOS/Windows, see Where tinytap Runs. Want a specific version, or to verify a release download? See the docs site below.

Where tinytap Runs

tinytap requires a Linux kernel. It cannot run natively on macOS or Windows, because eBPF is a Linux kernel technology. But that's less restrictive than it sounds, because Linux kernels are everywhere:

Where the user works How tinytap runs there
Linux (desktop, laptop, workstation, or server) Native. Just run the binary.
Mac (Intel or Apple Silicon) Inside a Linux VM — Docker Desktop's VM, OrbStack, Lima, UTM, Multipass, etc.
Windows Inside WSL2 (which is a real Linux kernel).

Containers need no special handling either — eBPF sees every process on the host kernel, containerized or not, so tinytap doesn't need to run inside a container or as a sidecar. See Where tinytap Runs on the docs site for the full container story and kernel requirements.

What it does today

tinytap attaches eBPF probes to a process's socket syscalls (accept4/read/write/close/recvfrom/sendto/recvmsg/sendmsg), parses the payload bytes as HTTP/1.1, pairs each request with its response, and renders the exchange live — either in the terminal TUI above or as a line-oriented stream:

12:47:57.005  python3[27122]  GET   /                        200    1304B     0.3ms
12:47:57.005  curl[1234]       GET   /api                     ABANDONED     12.3ms  (peer closed)

output = "auto" (the default) picks the TUI when stdout/stdin are an interactive terminal of at least 120x24; otherwise it prints guidance and exits rather than silently streaming — the line stream is opt-in via output = "stdout". output = "tui" forces the TUI (and exits the same way if the terminal can't host it); verbose = true hangs the full request/response headers under each stdout line. --version prints the build's version, commit, and date, and exits without needing root.

Configuration

Session settings (output, verbose) live in a TOML config file, not CLI flags. tinytap config init writes one, fully populated with defaults, so tinytap config init && tinytap just works:

tinytap config init          # writes ./tinytap.toml
tinytap config init path/to/config.toml   # or a specific path
tinytap config init --force  # overwrite an existing file

Search order when --config <path> isn't given: ./tinytap.toml, then $XDG_CONFIG_HOME/tinytap/config.toml (falling back to ~/.config/tinytap/config.toml) — finding neither is not an error, the defaults below apply.

output = "auto"   # auto | stdout | tui
verbose = false

The only CLI surface is one-shot actions, not session settings: --config <path> (point at an alternate config file), --version (build metadata, exits before any eBPF load), config init (above), and doctor (see Troubleshooting).

Current limitations

HTTP/1.1 only (no HTTP/2/gRPC yet), single-host only, and TLS capture needs a dynamically linked libssl.so (statically linked stacks like Go's crypto/tls are invisible). Full list, including per-server body-visibility details, on the docs site.

Status & Roadmap

Released so far: v0.1.0 (HTTP request/response visible) through v0.6.0 (production readiness). v0.7.0 (real-hardware bring-up) is in progress — see #198. Full roadmap in #19.

Documentation

Full documentation is available at shinagawa-web.github.io/tinytap:

Toolchain

Component Choice Why
eBPF lib github.com/cilium/ebpf Pure Go, modern, standard for new projects
Build bpf2go (part of cilium/ebpf) Generates Go bindings from C code
Compiler clang 17+ Standard for eBPF, supports BTF. clang-14 compiles cleanly but the emitted bpf_probe_read_user call fails the kernel verifier (R2 unbounded memory access) — CI pins 17 (#207); 15/16 untested
Go 1.24+
Kernel Linux 5.8+ Required for BPF_MAP_TYPE_RINGBUF, tinytap's event transport
Architecture amd64 + arm64 Need arm64 for Apple Silicon Lima VM
Release builds GoReleaser v2 Cross-compiles linux/amd64 + linux/arm64 on tag push (.goreleaser.yml) — the release workflow regenerates the bpf2go artifacts from source first (#260), then it's a plain go build; GoReleaser itself needs no clang/libbpf step
Dev environment

Mac (Apple Silicon) + Lima with Ubuntu 24.04. Build and run inside the Lima VM. Edit code on Mac via VS Code's remote SSH or the auto-mounted filesystem. This is private to the maintainer's workflow — it does not constrain users; see Where tinytap Runs for how tinytap runs on a user's machine.

Setup commands are:

# Mac side
brew install lima
limactl start --name=tinytap template://ubuntu
limactl shell tinytap

# Inside the VM
sudo apt update
sudo apt install -y llvm linux-headers-$(uname -r) build-essential git pkg-config

# clang 17 from the official LLVM repo — Ubuntu's own `clang` package isn't
# guaranteed to be 17, and clang-14 is known to fail the eBPF verifier (#207)
wget -O /tmp/llvm.sh https://apt.llvm.org/llvm.sh
echo "9474ecd78b52aba6e923976b1e9773f5613027cc7e237b9956986cb536e02a36  /tmp/llvm.sh" | sha256sum -c -
chmod +x /tmp/llvm.sh
sudo /tmp/llvm.sh 17

# libbpf 1.6.2 headers — Ubuntu's libbpf-dev predates the BPF_UPROBE macro
# bpf/tinytap_uprobe.bpf.c uses
git clone --depth 1 --branch v1.6.2 https://github.com/libbpf/libbpf.git /tmp/libbpf
sudo make -C /tmp/libbpf/src install_headers PREFIX=/usr

# Go (apt version is old)
GO_VERSION=1.24.0
ARCH=$(dpkg --print-architecture)  # arm64 on Apple Silicon
wget https://go.dev/dl/go${GO_VERSION}.linux-${ARCH}.tar.gz
sudo tar -C /usr/local -xzf go${GO_VERSION}.linux-${ARCH}.tar.gz
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
source ~/.bashrc

Building from source

Build and run inside the Lima VM (see Toolchain above for setup):

# Regenerate Go bindings from C — required before every build/test, not just
# after editing bpf/*.c: the generated files aren't committed (needs clang-17
# + libbpf 1.6.2, see Toolchain above)
cd ~/tinytap && make generate

# Build (go build ./... alone won't write a ./tinytap binary — it builds
# every package in the module to check they compile, without picking one
# to write out; -o plus a single package path produces the binary)
go build -o tinytap ./cmd/tinytap

# Run (requires root — eBPF needs CAP_BPF/CAP_PERFMON or root)
sudo ./tinytap

Root isn't actually required — see Running Without Full Root for the minimal setcap invocation.

Or via make:

make run       # orchestrated smoke test: starts a demo HTTP server, fires a request, shows the capture
make run-raw   # build + run with output = "stdout" against whatever's already running

Run make install once per checkout (or worktree) to install the pre-push hook that runs lint, tests, and coverage checks before every push.

License

MIT — see LICENSE. Exception: bpf/vmlinux.h is generated from the Linux kernel's BTF info and is distributed under the kernel's GPL-2.0 license instead.

References

Directories

Path Synopsis
cmd
tinytap command
internal
loader/bpf
Package bpf holds the bpf2go-generated bindings for the kernel-side program in bpf/tinytap.bpf.c.
Package bpf holds the bpf2go-generated bindings for the kernel-side program in bpf/tinytap.bpf.c.
loader/bpf/fixture
Package fixture holds the bpf2go-generated bindings for the integration-test fixture program in fixture.bpf.c.
Package fixture holds the bpf2go-generated bindings for the integration-test fixture program in fixture.bpf.c.
tls

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL