Files
ja4-platform/docs/services/ja4ebpf.md
Jacquin Antoine f88b739992 feat(e2e): add distributed E2E test framework with parametric traffic generation
Add run-e2e-test.sh with CLI parameters (--hits, --http-ratio, --dns, --tls,
--src-ips, --keep-analysis, --up) for configurable traffic generation. Traffic
runs from VM endpoints with multiple source IPs (alias IPs on eth0) to produce
distinct sessions for the ML pipeline. Fix curl TLS flags (--tlsv1.2 instead
of --tls-v1-2), skip redundant local verification in distributed mode, and
fix dashboard is_available() cache that never retried after ClickHouse recovery.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 00:09:32 +02:00

13 KiB

ja4ebpf — Agent eBPF CO-RE

Description

ja4ebpf est l'agent de collecte de données de la plateforme ja4-platform. C'est un binaire Go unique qui utilise eBPF CO-RE (Compile Once — Run Everywhere) pour observer passivement le trafic réseau d'un serveur Linux, sans modifier ni interrompre le serveur web cible (Apache, Nginx, Varnish, HAProxy, ou tout processus utilisant OpenSSL/BoringSSL).

Il capture simultanément les métadonnées réseau L3/L4 (TCP SYN), les paramètres TLS L5 (ClientHello), et le contenu applicatif L7 (requêtes HTTP déchiffrées), corr le tout en mémoire par la clé src_ip:src_port, et envoie les données vers ClickHouse en batch.

Architecture interne

  +-----------------+    TC ingress (XDP/TC)     +--------------------+
  |  réseau entrant  |-------------------------->|  bpf/tc_capture.c  |
  |                 |                            |                    |
  |  SYN packet     |  --> rb_tcp_syn  (16 MB)  |  Programme eBPF    |
  |  TLS ClientHello|  --> rb_tls_hello (16 MB) |  CO-RE             |
  |  HTTP port 80   |  --> rb_http_plain (32 MB)|                    |
  +-----------------+                            +--------------------+
                                                           |
  +-----------------+    uprobe SSL_read          +--------------------+
  |  serveur web    |-------------------------->  |  bpf/uprobe_ssl.c  |
  |  (OpenSSL)      |                            |                    |
  |  flux déchiffré |  --> rb_ssl_data  (64 MB) |  Programme eBPF    |
  +-----------------+                            |  CO-RE             |
                                                 +--------------------+
                                                           |
                                               +-----------v-----------+
                                               |     Go userspace       |
                                               |                        |
                                               |  internal/loader/      |
                                               |  - RingBuffer readers  |
                                               |  - 5 goroutines        |
                                               |                        |
                                               |  internal/parser/      |
                                               |  - JA4 calculator      |
                                               |  - H2 preface parser   |
                                               |  - HTTP/1.1 parser     |
                                               |                        |
                                               |  internal/dispatcher/  |
                                               |  - Magic Bytes router  |
                                               |                        |
                                               |  internal/correlation/ |
                                               |  - 256-shard manager   |
                                               |  - GC 100ms            |
                                               |  - timeout 500ms       |
                                               |                        |
                                               |  internal/writer/      |
                                               |  - ClickHouse batch    |
                                               +----------+-------------+
                                                          |
                                               INSERT batch TCP :9000
                                                          |
                                                          v
                                               +----------------------+
                                               |  ja4_logs.           |
                                               |  http_logs_raw       |
                                               +----------------------+

Hooks eBPF

TC ingress — Couches L3/L4/L5

Le programme bpf/tc_capture.c est attaché à l'interface réseau via TC (Traffic Control) en ingress. Il s'exécute pour chaque paquet entrant :

Paquets TCP SYN : extraction des options TCP et métadonnées IP depuis les headers du paquet.

  • bpf_skb_load_bytes() pour lire les options TCP depuis le skb
  • Envoyé dans le RingBuffer rb_tcp_syn (16 MB)

ClientHello TLS : détection du type 0x16 (Handshake) et sous-type 0x01 (ClientHello).

  • bpf_skb_load_bytes() avec tailles en cascade (512 → 256 → 128) pour capturer SNI et extensions
  • La taille réellement copiée est stockée dans payload_len
  • Envoyé dans le RingBuffer rb_tls_hello (16 MB)

HTTP en clair (port 80/8080) : pour les connexions non chiffrées.

  • SYN/FIN/RST exclus (uniquement les segments porteurs de données)
  • bpf_skb_load_bytes() avec tailles en cascade (256 → 128 → 64)
  • La taille réellement copiée est stockée dans payload_len
  • Envoyé dans le RingBuffer rb_http_plain (32 MB)

Uprobe SSL_read — Couche L7

Les uprobes s'attachent dynamiquement à SSL_read (ou SSL_read_ex) dans le processus du serveur web. Elles s'exécutent après le déchiffrement TLS, capturant le flux HTTP en clair dans rb_ssl_data (64 MB).

La clé de corrélation src_ip:src_port est extraite depuis la structure SSL* → file descriptor → socket noyau via bpf_probe_read_kernel().

Kprobe accept4

Un kprobe sur accept4 peuple rb_accept (4 MB) avec le tuple (src_ip, src_port, fd, pid_tgid), permettant d'associer chaque fd SSL à une connexion TCP.

Corrélation in-memory

Le gestionnaire internal/correlation maintient un état par connexion :

Mécanisme Valeur
Sharding 256 buckets (hash src_ip:src_port)
Timeout orphelin 500 ms (→ correlated=0)
Détection Slowloris 10 s (export partiel)
GC interval 100 ms
Keep-Alive max_keepalives incrémenté par requête

Routeur Magic Bytes (dispatcher)

Buffer reçu (SSL data ou HTTP plain)
    |
    +-- starts with "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" --> ProtoHTTP2
    |
    +-- starts with "GET " / "POST " / "PUT " / ...      --> ProtoHTTP1
    |
    +-- partial H2 preface prefix                         --> ProtoHTTP2 (buffer)
    |
    +-- autre                                              --> ProtoUnknown (ignoré)

Fingerprinting HTTP/2 passif : après détection du preface PRI * HTTP/2.0..., le parser itère les frames :

  • Frame SETTINGS (type 0x04) : extraction des 7 paramètres, valeur -1 si absent
  • Frame WINDOW_UPDATE (type 0x08, stream 0) : incrément de fenêtre connexion
  • Frame HEADERS (type 0x01) : ordre des pseudo-headers (m,a,s,p)

Données collectées

L3/L4 (TCP SYN)

Champ Description
src_ip, src_port Clé de corrélation
dst_ip, dst_port Destination IP et port (extrait du SYN)
ttl Time To Live initial
df_bit Don't Fragment bit
ip_id IP Identification (0 = Linux/VPN/spoofé)
window_size Taille fenêtre TCP SYN
window_scale Option Window Scale (RFC 1323)
mss Maximum Segment Size
tcp_options Options TCP brutes (40 octets max)
tcp_jitter_variance Variance jitter inter-SYN
syn_timing_cv Délai SYN→ClientHello (ns)

L5 (TLS ClientHello)

Champ Description
tls_version Version TLS la plus haute annoncée (extrait des SupportedVersions)
ciphers Liste suites cryptographiques
extensions Liste extensions TLS
elliptic_curves Courbes elliptiques supportées
point_formats Formats de points EC
alpn ALPN list (h2, http/1.1, ...)
sni Server Name Indication
ja4 Empreinte JA4 calculée Go-side
ja4t Empreinte JA4T (TCP) calculée Go-side

L7 HTTP/1.1

Champ Description
method Méthode HTTP
path Chemin
query_string Paramètres query
http_version HTTP/1.0 ou HTTP/1.1
headers_raw En-têtes dans leur ordre d'émission
header_order_signature Hash de l'ordre
status_code Code de statut
response_size Taille réponse (octets)
duration_ms Durée requête
timestamp_ns Horodatage ns absolu

L7 HTTP/2 (preface client)

Champ Description
h2_header_table_size SETTINGS ID 1 (nil si absent du preface, omis dans le JSON)
h2_enable_push SETTINGS ID 2
h2_max_concurrent_streams SETTINGS ID 3
h2_initial_window_size SETTINGS ID 4
h2_max_frame_size SETTINGS ID 5
h2_max_header_list_size SETTINGS ID 6
h2_enable_connect_protocol SETTINGS ID 8 (RFC 8441)
h2_window_update Incrément WINDOW_UPDATE connexion
h2_has_priority Flag PRIORITY dans HEADERS frame
h2_pseudo_order Ordre pseudo-headers (ex: m,a,s,p)

eBPF CO-RE

Aspect Détail
Compilateur clang + llvm
Target bpf (architecture BPF 64 bits)
BTF source /sys/kernel/btf/vmlinux (disponible RHEL 8+)
Relocations cilium/ebpf résout automatiquement les offsets struct
Embed go:generate génère bpf_bpfel.go avec bytecode embarqué
Compatibilité Rocky/RHEL Linux 8, 9, 10 (kernel 4.18+)

Configuration

# /etc/ja4ebpf/config.yml
interface: eth0
target_binary: /usr/sbin/httpd

clickhouse:
  dsn: clickhouse://data_writer:pwd@localhost:9000/ja4_logs
  table: http_logs_raw
  batch_size: 500
  flush_interval_ms: 200

correlation:
  session_timeout_ms: 500
  slowloris_threshold_s: 10
  gc_interval_ms: 100

Variables d'environnement

Variable Défaut Description
JA4EBPF_INTERFACE eth0 Interface réseau
JA4EBPF_TARGET_BINARY /usr/sbin/httpd Binaire à hooker (uprobe SSL_read)
JA4EBPF_CLICKHOUSE_DSN DSN ClickHouse
JA4EBPF_BATCH_SIZE 500 Taille des batchs d'insertion
JA4EBPF_FLUSH_INTERVAL_MS 200 Intervalle de flush (ms)
JA4EBPF_SESSION_TIMEOUT_MS 500 Timeout session orpheline
JA4EBPF_SLOWLORIS_THRESHOLD_S 10 Seuil détection Slowloris (s)

Build

# Build complet (bytecode eBPF + binaire Go) — Docker Rocky Linux
make build-ja4ebpf

# Tests unitaires (nécessite NET_RAW/NET_ADMIN/BPF capabilities)
make test-ja4ebpf

# Build RPMs el8/el9/el10
make rpm-ja4ebpf
# → services/ja4ebpf/dist/rpm/el{8,9,10}/

Structure du code

services/ja4ebpf/
├── bpf/
│   ├── bpf_types.h            # Structs C partagées + déclarations maps eBPF
│   ├── tc_capture.c           # Programme TC ingress (L3/L4/L5 + HTTP plain)
│   └── uprobe_ssl.c           # Programme uprobe SSL_read (L7 déchiffré)
├── cmd/ja4ebpf/
│   └── main.go                # Point d'entrée : 5 goroutines consumer
├── internal/
│   ├── loader/
│   │   └── loader.go          # Chargement eBPF + RingBuffer readers + désérialisation
│   ├── parser/
│   │   ├── ja4.go             # Calcul empreintes JA4 / JA4T
│   │   ├── http2.go           # Parser HTTP/2 preface (SETTINGS, WINDOW_UPDATE, HEADERS)
│   │   └── http1.go           # Parser HTTP/1.1
│   ├── dispatcher/
│   │   └── dispatcher.go      # Routeur Magic Bytes (ProtoHTTP1/2/Unknown)
│   ├── correlation/
│   │   ├── manager.go         # Gestionnaire sessions 256-shard
│   │   └── session.go         # Structs L3L4, TLSInfo, SessionState
│   └── writer/
│       └── writer.go          # Writer ClickHouse (batch + retry)
├── packaging/
│   ├── rpm/ja4ebpf.spec       # Spec RPM (el8/el9/el10)
│   └── systemd/ja4ebpf.service # Unit systemd
├── Dockerfile                 # Image de production
├── Dockerfile.tests           # Image de tests
├── Dockerfile.package         # Build RPM multi-distro (5 stages)
└── Makefile

Capabilities Linux requises (SELinux Enforcing)

L'agent tourne sous l'utilisateur ja4ebpf (UID/GID 490 fixe). Les capabilities Linux accordées via AmbientCapabilities :

Capability Raison
CAP_BPF Chargement des programmes eBPF (kernel 5.8+)
CAP_SYS_ADMIN Uprobes + RHEL 8 (kernel 4.18, pré-CAP_BPF)
CAP_NET_ADMIN Attachement hooks TC ingress
CAP_PERFMON Accès perf events pour les uprobes

LimitMEMLOCK=infinity est requis pour le mlock() des maps eBPF.

Tests d'intégration

Stacks Docker Compose testant l'agent contre différents serveurs web :

make test-integration     # Apache httpd (référence)
make test-nginx           # Nginx
make test-nginx-varnish   # Nginx + Varnish (reverse proxy)
make test-hitch-varnish   # Hitch (TLS) + Varnish
make test-all-stacks      # Les 4 stacks en séquence