tcpcat.
Document type: Systems note
N. — NycolazSec
Project: tcpcat
github.com/NycolazSec/tcpcat

Internals

Packet path — kernel bypass, hand-assembled

How a scan gets from a Go struct to a live packet on the wire and back — bytecode assembled by hand, loaded straight into the kernel, and read through a shared memory ring instead of a socket.

userspace Go (tcpcat) Linux kernel scan pipeline

Load path — once, at startup

Bytecode, hand-assembled

internal/scan/xdp_asm.go builds eBPF instructions directly with cilium/ebpf/asm — no C source, no clang -target bpf step.

ebpf.CollectionSpec

The assembled instructions plus a map layout, still just Go values in memory.

ProgramXDP redirect hook
Mapsxsks_map

cilium/ebpf (Go library)

Loads the program and creates the maps in one bpf() syscall — the only part of this path clang would normally have done for you.

bpf(BPF_PROG_LOAD)

Data path — per scan

tcpcat process

Crafts SYN / RST / ACK / ICMP frames by hand, parses replies, scores OS fingerprints, paces itself with an RTT/AIMD rate controller — all plain userspace Go.

cmd/tcpcat · internal/scan · internal/osdetect
socket(AF_XDP) · bind() · poll()
LINUX KERNEL

Verifier

Statically proves the program can't crash the kernel or loop forever.

passes

JIT compiler

Turns the verified bytecode into native machine code for the NIC's core.

attaches

XDP hook

Runs on every inbound frame, at the driver — before the kernel's own TCP/IP stack ever sees it.

reads / writes queue → socket FD mapping

eBPF maps

xsks_map — a tiny lookup the hook uses to decide which socket owns a given RX queue.

redirect

AF_XDP socket

A UMEM region shared with the process: fill, RX, TX and completion rings, mapped once and never copied per packet.

frames move through shared UMEM rings — zero copy, no per-packet syscall

Anything the hook doesn't claim — every other process's traffic — falls through to the normal socket / TCP-IP stack, untouched.

What tcpcat does with those frames

Everything below runs in the userspace process, on results the kernel path above hands it.

01

Host discovery

ICMP echo + SYN/443 + ACK/80 fired together over the same ring.

02

Half-open SYN scan

Reads the SYN/ACK, then sends its own crafted RST — never a full connection.

03

OS fingerprint

TTL, window, MSS and option order scored against a small signature table.

04

Adaptive rate

RFC 6298 RTT estimate feeds an AIMD limiter that paces the next batch.

05

Service detect

Open ports get a real TCP connection for a banner — back on ordinary sockets.

06

Vuln correlate

Banner versions checked against OSV, Vulners, and an offline CVE database.

07

Report

JSON, SARIF, XML or console — one result set, several writers.

!

No Linux, no root, or no compatible NIC driver? tcpcat drops the whole kernel-bypass path above and runs the same pipeline over SOCK_RAW or a plain TCP connect scan instead — slower, but no eBPF required.