docs: update documentation for kretprobe recvfrom fix

Update all documentation to reflect the resolved HTTP nginx capture
issue via kretprobe on __x64_sys_recvfrom.

Changes:
- README.md: Update HTTP status table showing kretprobe is now working
- docs/services/ja4ebpf.md: Replace tracepoint with kretprobe in hooks table,
  mark issue as resolved with validation reference
- docs/architecture.md: Clarify TC HTTP plain capture is packet-level only

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jacquin Antoine
2026-04-20 13:30:02 +02:00
parent 3e00e7bc7b
commit bb2160efbc
3 changed files with 50 additions and 5 deletions

View File

@ -50,7 +50,8 @@
| Service | Langage | Description | Interface | | Service | Langage | Description | Interface |
|---------|---------|-------------|-----------| |---------|---------|-------------|-----------|
| [ja4ebpf](docs/services/ja4ebpf.md) | Go 1.24 + C eBPF (CO-RE) | Agent eBPF passif : TC ingress (L3/L4/L5), uprobe SSL_read (L7 HTTPS), TC port 80/8080 (HTTP clair), corrélation in-memory, insert ClickHouse | INSERT batch ClickHouse | | [ja4ebpf](docs/services/ja4ebpf.md) | Go 1.24 + C eBPF (CO-RE) | Agent eBPF passif : TC ingress (L3/L4/L5), uprobe SSL_read (L7 HTTPS), kretprobe recvfrom (L7 HTTP nginx), corrélation in-memory, insert ClickHouse | INSERT batch ClickHouse |
| **État HTTP** : ✅ HTTPS via SSL uprobes (headers complets) — ✅ HTTP nginx via kretprobe recvfrom (headers complets) — ⚠️ HTTP plain via TC (paquets bruts) |
| [bot-detector](docs/services/bot-detector.md) | Python 3.11 | Ensemble ML triple-voix (EIF+AE+XGB), clustering HDBSCAN, explicabilité SHAP | ClickHouse read/write, HTTP `:8080` | | [bot-detector](docs/services/bot-detector.md) | Python 3.11 | Ensemble ML triple-voix (EIF+AE+XGB), clustering HDBSCAN, explicabilité SHAP | ClickHouse read/write, HTTP `:8080` |
| [dashboard](docs/services/dashboard.md) | Python 3.11 | Tableau de bord SOC : 9 endpoints JSON, 8 pages HTML | HTTP `:8000` | | [dashboard](docs/services/dashboard.md) | Python 3.11 | Tableau de bord SOC : 9 endpoints JSON, 8 pages HTML | HTTP `:8000` |

View File

@ -16,7 +16,7 @@ ja4-platform est un pipeline de sécurité qui capture le trafic réseau en temp
| | (eBPF CO-RE) | | | | (eBPF CO-RE) | |
| | TC ingress |<-- L3/L4/L5 (SYN, TLS CH) | | | TC ingress |<-- L3/L4/L5 (SYN, TLS CH) |
| | uprobe SSL_read|<-- L7 HTTPS (déchiffré) | | | uprobe SSL_read|<-- L7 HTTPS (déchiffré) |
| | kprobe tcp_recv|<-- L7 HTTP port 80/8080 | | | TC HTTP plain |<-- L7 HTTP port 80/8080 (paquets) |
| | 256-shard mgr | corrélation src_ip:src_port | | | 256-shard mgr | corrélation src_ip:src_port |
| +--------+--------+ | | +--------+--------+ |
| | | | | |
@ -70,7 +70,7 @@ INSERT (Native TCP :9000)
2. **ja4ebpf uprobes SSL_read/SSL_write** sattachent à `SSL_read` et `SSL_write` dans la bibliothèque OpenSSL/BoringSSL du serveur web. Les données déchiffrées sont écrites dans un PerfEventArray eBPF. Des tracepoints sur `accept4` fournissent la correspondance `fd → src_ip:src_port` pour annoter chaque buffer L7. 2. **ja4ebpf uprobes SSL_read/SSL_write** sattachent à `SSL_read` et `SSL_write` dans la bibliothèque OpenSSL/BoringSSL du serveur web. Les données déchiffrées sont écrites dans un PerfEventArray eBPF. Des tracepoints sur `accept4` fournissent la correspondance `fd → src_ip:src_port` pour annoter chaque buffer L7.
3. **ja4ebpf TC ingress HTTP plain** (port 80/8080) capture les payloads TCP en clair directement depuis le hook TC ingress pour les connexions non chiffrées. 3. **ja4ebpf TC ingress HTTP plain** (port 80/8080) capture les payloads TCP en clair directement depuis le hook TC ingress pour les connexions non chiffrées. Limité aux segments de données TCP (pas de reconstitution de flux multi-paquets).
### Phase 2 — Corrélation en mémoire ### Phase 2 — Corrélation en mémoire
@ -262,7 +262,7 @@ Les deux empreintes sont générées par **ja4ebpf** (espace utilisateur Go) à
| Composant | Technologie | | Composant | Technologie |
|-----------|-------------| |-----------|-------------|
| Capture réseau (L3/L4/L5) | Go 1.24.6 + eBPF CO-RE (TC ingress, cilium/ebpf) | | Capture réseau (L3/L4/L5) | Go 1.24.6 + eBPF CO-RE (TC ingress, cilium/ebpf) |
| Capture applicative (L7) | eBPF uprobe SSL_read + kprobe tcp_recvmsg | | Capture applicative (L7) | eBPF uprobe SSL_read + TC HTTP plain |
| Corrélation en mémoire | Go 1.24.6 (256-shard manager, goroutines) | | Corrélation en mémoire | Go 1.24.6 (256-shard manager, goroutines) |
| Détection ML — EIF | Python 3.11 + isotree | | Détection ML — EIF | Python 3.11 + isotree |
| Détection ML — NFEnsemble | Python 3.11 + PyTorch | | Détection ML — NFEnsemble | Python 3.11 + PyTorch |

View File

@ -93,6 +93,19 @@ Les uprobes s'attachent dynamiquement aux fonctions OpenSSL dans `libssl.so` :
| `SSL_read` | uprobe + uretprobe | Capture les requêtes du client (direction=0) | | `SSL_read` | uprobe + uretprobe | Capture les requêtes du client (direction=0) |
| `SSL_write` | uprobe + uretprobe | Capture les réponses du serveur (direction=1) | | `SSL_write` | uprobe + uretprobe | Capture les réponses du serveur (direction=1) |
### Tracepoints/Kretprobe recvfrom (Nginx HTTP en clair)
Les hooks `sys_enter_recvfrom` / `sys_exit_recvfrom` capturent les appels système `recvfrom()` du serveur Nginx pour capturer le trafic HTTP en clair complet :
| Hook | Type | État | Rôle |
|------|------|------|------|
| `tp_syscalls_sys_enter_recvfrom` | tracepoint | ✅ Fonctionnel | Sauvegarde les arguments recvfrom (sockfd, buf_ptr, len) |
| `tp_sys_exit_recvfrom` | kretprobe | ✅ Fonctionnel | Capture les données lues + émet vers pb_ginx_http |
**Note** : Le kretprobe sur `__x64_sys_recvfrom` remplace le tracepoint `sys_exit_recvfrom` qui échouait avec "permission denied" sur Rocky Linux 9+.
**Filtrage par PID nginx** : La map `nginx_pid_map` ne permet que les processus nginx identifiés via `/proc/<pid>/cmdline`.
**Corrélation `fd → src_ip:src_port`** (3 niveaux de priorité) : **Corrélation `fd → src_ip:src_port`** (3 niveaux de priorité) :
1. `ssl_conn_map[ssl_ptr]` — si `SSL_set_fd` a été appelé et que `fd_conn_map[fd]` contient l'IP (via accept4) 1. `ssl_conn_map[ssl_ptr]` — si `SSL_set_fd` a été appelé et que `fd_conn_map[fd]` contient l'IP (via accept4)
2. `accept_map[{pid_tgid, fd}]` — cache accept4 (tracepoint kernel) 2. `accept_map[{pid_tgid, fd}]` — cache accept4 (tracepoint kernel)
@ -387,7 +400,38 @@ services/ja4ebpf/
└── Makefile └── Makefile
``` ```
## Capabilities Linux requises (SELinux Enforcing) ## Problèmes connus
### ✅ HTTP Nginx via recvfrom — RÉSOLU (2026-04-20)
**Solution implémentée** : Remplacement du tracepoint `sys_exit_recvfrom` par un kretprobe sur `__x64_sys_recvfrom`.
**Détails** : Le tracepoint exit échouait avec "permission denied" sur Rocky Linux 9+. Le kretprobe contourne cette limitation en s'attachant directement à la fonction kernel.
**Validation** :
- ✅ Toutes les données HTTP capturées sans troncature (path jusqu'à 39 chars, query jusqu'à 244 chars)
- ✅ Headers custom (X-Request-ID, X-Custom-Header) complets
- ✅ Tests unitaires Go ajoutés et validés
- ✅ Rapport de validation : `services/ja4ebpf/docs/CLICKHOUSE_VALIDATION_REPORT.md`
### Maps eBPF résumé
| Map | Type | Rôle |
|-----|------|------|
| `allowed_ports` | HASH (key=u16, val=u8) | Ports TCP autorisés (peuplée depuis Go) |
| `ignored_src` | LPM_TRIE (key={prefixlen, data[4]}, val=u8) | CIDR/IP sources à ignorer (peuplée depuis Go) |
| `tc_stats` | PERCPU_ARRAY (7 compteurs) | Statistiques de debug BPF |
| `ssl_conn_map` | HASH (key=ssl_ptr, val=ssl_conn_info) | Association SSL* → fd + IP |
| `fd_conn_map` | HASH (key=fd, val=ssl_conn_info) | Association fd → IP (depuis accept4) |
| `accept_map` | HASH (key={pid_tgid,fd}, val=accept_event) | Cache accept4 côté BPF |
| `ssl_args_map` | HASH (key=pid_tgid, val=ssl_read_args) | Sauvegarde arguments SSL_read/Write entry |
| `nginx_pid_map` | HASH (key=u32, val=u8) | Filtrage recvfrom par PID nginx |
| `nginx_read_args_map` | HASH (key=pid_tgid, val=nginx_read_args) | Sauvegarde arguments recvfrom entry |
| `__tls_buf` | PERCPU_ARRAY (1 entrée) | Buffer temp > 512o (stack eBPF limit) |
| `__http_buf` | PERCPU_ARRAY (1 entrée) | Buffer temp HTTP plain |
| `__ssl_buf` | PERCPU_ARRAY (1 entrée) | Buffer temp SSL data |
| `__nginx_buf` | PERCPU_ARRAY (1 entrée) | Buffer temp nginx HTTP |
L'agent tourne sous l'utilisateur `ja4ebpf` (UID/GID 490 fixe). Les capabilities Linux accordées via `AmbientCapabilities` : L'agent tourne sous l'utilisateur `ja4ebpf` (UID/GID 490 fixe). Les capabilities Linux accordées via `AmbientCapabilities` :