tcpcat : scanner réseau eBPF/AF_XDP,
inventaire et analyse d'exposition
Note technique communautaire · v1.5
Statut de ce mémo
Ce document présente tcpcat, un scanner réseau écrit en Go. Cette note communautaire n'est pas une RFC IETF et ne remplace pas Nmap. Le projet est en double licence : AGPL-3.0 ou licence commerciale (OEM).
Résumé
tcpcat énumère les ports ouverts d'un hôte. En mode --ebpf, il forge ses sondes en espace utilisateur et lit les réponses via des sockets AF_XDP, sans passer par la pile TCP/IP du noyau. Surtout, il ne s'arrête pas à « le port est ouvert » : inventory et explain disent quel processus écoute derrière chaque port, et comment fermer ceux qui ne devraient pas l'être.
Démarrage rapide
LocalInstaller
go install github.com/\ NycolazSec/tcpcat/\ cmd/tcpcat@latest
Scanner un hôte
tcpcat -sT -p 1-1000 \ 192.0.2.10
Exporter un rapport
tcpcat -sV \ -j report.json 192.0.2.10
1. Introduction et spécifications
§1
tcpcat construit lui-même chaque paquet de sonde en espace utilisateur. En mode --ebpf, il les envoie et lit les réponses via des sockets AF_XDP plutôt que par les sockets BSD classiques, sans passer par la pile TCP/IP du noyau.
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Port | Destination Port | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Acknowledgment Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Data | |U|A|P|R|S|F| | | Offset| Reserved |R|C|S|S|Y|I| Window | | | |G|K|H|T|N|N| | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Checksum | Urgent Pointer | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Options | Padding | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2. Capacités système
§22.1 Scans et reconnaissance
TCP (SYN, connect, ACK, Window, FIN, Xmas), UDP et ICMP. Découverte d'hôtes, détection de version avec -sV, empreinte d'OS, rapports JSON et SARIF.
2.2 Moteur eBPF / AF_XDP (Linux)
Un hook XDP redirige vers des sockets AF_XDP les réponses aux sondes de tcpcat ; tout le reste du trafic suit la pile normale. Sur un gros scan, cela réduit le coût CPU par paquet. Le programme XDP est assemblé en Go, sans C ni clang.
2.3 Dissecteurs WebAssembly
Un dissecteur est un petit module WebAssembly, en bac à sable, qui parle au port sondé via une fonction hôte unique. Écrit en Go (TinyGo) ou en Rust, il identifie un service et sa version. Voir le SDK.
2.4 Test de visibilité (--evasion)
--evasion applique des contrôles de variation (fragmentation, jitter temporel, leurres) pour vérifier si des défenses autorisées journalisent et alertent sur un scan. À n'utiliser que sur un périmètre approuvé.
3. Exposition : qui écoute, et comment fermer
§3Lancé sur la machine, inventory lit /proc et note quel processus, unité systemd ou conteneur tient chaque socket en écoute. Copié sur un autre poste, explain sonde la machine depuis l'extérieur et recoupe les deux vues : pour chaque port, qui est derrière et quoi faire. Pour un port exposé non prévu, il nomme le responsable et le correctif.
# sur l'hôte
$ tcpcat inventory -o inventory.json
# sur ton poste
$ tcpcat explain inventory.json --expect 22
HOST web-01 · 203.0.113.5
INSIDE 3 listening socket(s)
TO FIX (1) reachable from outside, not declared with --expect
6379/tcp EXPOSED redis-server · redis.service HIGH
reachable from outside · listens on 0.0.0.0
→ Set `bind 127.0.0.1 ::1` and `protected-mode yes`
in redis.conf.
PUBLIC AS EXPECTED (1)
22/tcp EXPOSED sshd · ssh.service
LOCAL ONLY (1) 5432
✗ 1 port(s) reachable that should not be.
explain --remediate écrit en plus la règle nftables, le drop-in systemd ou la NetworkPolicy qui ferme l'exposition. tcpcat n'applique rien lui-même : il produit du texte à relire.
4. Benchmark comparatif
§4Scan SYN des 65 535 ports sur 2 hôtes, même interface et même plafond de débit (25 000 paquets/s) pour les trois outils, 3 exécutions chacun, mesuré avec hyperfine. Chaque exécution est vérifiée : trouve-t-elle bien les 80 ports ouverts ?
| Outil | Moyenne ± σ | CPU | Ports trouvés |
|---|---|---|---|
| nmap | 5.38 s ± 0.03 | 2.7 s | 80/80 |
| tcpcat --ebpf | 5.81 s ± 0.72 | 6.3 s | 80/80 |
| tcpcat -sS | 6.33 s ± 0.10 | 42.3 s | 80/80 |
| naabu | 18.94 s ± 0.39 | 51.5 s | 80/80 |
Commande de mesure exacte
# depuis une copie du dépôt, Docker suffit $ ./benchmarks/run.sh # par outil, l'équivalent de : $ tcpcat -p 1-65535 -sS --ebpf -T 5 --rate 25000 -Pn host1 host2 $ nmap -p 1-65535 -sS -n -Pn -T4 --max-rate 25000 host1 host2 $ naabu -p 1-65535 -rate 25000 -host host1,host2 -silent
--rate est le débit total, tous hôtes et tous ports confondus (global, pas par hôte). Pour N sondes à R paquets/s, un scan ne peut pas finir en moins de N/R secondes : ici 131 070 sondes à 25 000/s, soit un plancher d'environ 5,2 s, cohérent avec les temps ci-dessus.
Chiffres d'un labo Docker (interface veth) sur un portable, reproductibles avec la commande ci-dessus. À débit plafonné, tcpcat et nmap sont au coude-à-coude ; l'intérêt de tcpcat est surtout l'étape explain. Une mesure sur vraie carte réseau reste à faire. Méthode complète : benchmarks/README.md.
5. Référence en ligne de commande
§5sudo tcpcat -sS --top-ports 1000 --rate 100000 target.lan
sudo tcpcat --ebpf -p 1-1000 10.0.0.0/16 -w 128 -T 5
sudo tcpcat -sV -p 22,80,443,3306 192.168.0.0/24 -j report.json --sarif report.sarif
À garder en tête : eBPF/AF_XDP exige Linux et une carte réseau compatible. Une bannière ou une version détectée n'est pas une preuve de vulnérabilité. Le chemin réseau et les privilèges locaux peuvent modifier les résultats.
6. Considérations de sécurité
§6autorisé
uniquement
tcpcat est réservé aux audits de sécurité défensifs, aux tests d'intrusion autorisés et à l'administration d'infrastructures sous mandat explicite. Scanner un réseau sans autorisation est passible de sanctions pénales (art. 323-1 et suivants du Code pénal, CFAA, RGPD). Les auteurs déclinent toute responsabilité en cas d'utilisation illicite.
Le projet est non commercial et ne fournit aucun service de scan hébergé. Voir la notice complète. Références : Nmap, RFC 793, eBPF, AF_XDP.
Annexe A. Folklore réseau (informatif, non normatif)
Ann. A« Il n'y a pas d'endroit comme le 127.0.0.1. » (dans la tradition des RFC humoristiques, cf. RFC 2549, RFC 1149).
RFC 793, le barman TCP
Un paquet entre dans un bar : SYN, « Je voudrais une bière. » SYN-ACK, « Tu veux une bière ? » ACK, « Oui, une bière. » Le barman répond RST (port 80 fermé).
Extension du modèle OSI
Layer 8 : erreur critique identifiée entre la chaise et le clavier. « Avez-vous essayé d'éteindre et de rallumer la table de routage BGP ? »
ICMP Echo Request
64 bytes, icmp_seq=1, ttl=116 : la seule relation stable et sans engagement de ta vie.
RFC 768, le datagramme
« Je te raconterais bien une blague sur l'UDP, mais je ne suis pas sûr que tu la reçoives. »