feat(ebpf): Apache HTTP capture + nginx multi-kernel validation

**Apache HTTP capture via apr_socket_recv** :
- Uprobe sur libapr-1.so.0 (Apache Portable Runtime)
- Compatible tous kernels 4.18+ (CentOS 8, Rocky 9/10)
- Configuration unifiée : servers: ["nginx", "apache"]

**nginx HTTP capture validation multi-kernel** :
- Kretprobe __x64_sys_recvfrom validé sur CentOS 8 (4.18)
- Rocky 9 (5.14) et Rocky 10 (6.12) confirmés
- Contourne limitation tracepoint sys_exit_recvfrom

**Documentation** :
- docs/TEST_BUILD_STACK.md : stack complète test/build (VMs, Docker, RPMs)
- services/ja4ebpf/docs/APACHE_HTTP_VALIDATION.md : validation Apache
- services/ja4ebpf/docs/NGINX_MULTI_KERNEL_VALIDATION.md : validation nginx
- docs/architecture.md + docs/services/ja4ebpf.md mis à jour

**Tests unitaires Apache** :
- internal/loader/apache_test.go : tests libapr, paths, structures BPF
- internal/correlation/apache_test.go : tests corrélation HTTP Apache

**Packaging** :
- RPM spec mis à jour (version 0.3.0-1, changelog complet)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jacquin Antoine
2026-04-20 19:49:40 +02:00
parent 4d30d9a7cb
commit 4a41e31822
12 changed files with 1240 additions and 134 deletions

View File

@ -4,15 +4,18 @@
ja4ebpf peut capturer le trafic HTTP complet depuis deux serveurs web différents :
- **Nginx** ✅ : via `recvfrom()` syscall (kretprobe sur `__x64_sys_recvfrom`)
- **Apache httpd** ⚠️ : en cours de validation - kretprobe `__x64_sys_recvfrom`
- **Apache httpd** : via `apr_socket_recv()` uprobe dans libapr-1.so.0
### Statut de validation
| Serveur | Kernel | Statut | Headers capturés |
|---------|--------|--------|------------------|
| nginx | Rocky Linux 9 (5.14+) | ✅ Validé | Tous (sans troncature) |
| Apache httpd | CentOS 8 (4.18) | ⚠️ En cours | Investigation nécessaire |
| Apache httpd | Rocky Linux 9 (5.14+) | ⚠️ À tester | - |
| Serveur | Kernel | Statut | Méthode | Headers capturés |
|---------|--------|--------|---------|------------------|
| nginx | CentOS 8 (4.18) | ✅ Validé | kretprobe `__x64_sys_recvfrom` | Tous (sans troncature) |
| nginx | Rocky Linux 9 (5.14+) | ✅ Validé | kretprobe `__x64_sys_recvfrom` | Tous (sans troncature) |
| nginx | Rocky Linux 10 (6.12) | ✅ Validé | kretprobe `__x64_sys_recvfrom` | Tous (sans troncature) |
| Apache httpd | CentOS 8 (4.18) | ✅ Validé | uprobe `apr_socket_recv` | Tous (sans troncature) |
| Apache httpd | Rocky Linux 10 (6.12) | ✅ Validé | uprobe `apr_socket_recv` | Tous (sans troncature) |
| Apache httpd | Rocky Linux 9 (5.14+) | ✅ Compatible | uprobe `apr_socket_recv` | Même méthode |
## Configuration
@ -28,34 +31,15 @@ uprobes:
```bash
JA4EBPF_UPROBES_ENABLED=true
JA4EBPF_UPROBES_SERVERS=nginx,apache # ou "both" pour les deux
JA4EBPF_UPROBES_SERVERS=nginx,apache
```
## Architecture de capture
### Nginx (rocky9: 192.168.42.40)
### Nginx (kretprobe)
```
┌─────────────┐
│ nginx worker │─┐
└─────────────┘ │
├─ read() ──┐
│ │
┌──────▼──────┐ │
│ kretprobe │ │
│ sys_exit │ │
│ recvfrom │ │
└─────────────┘ │
┌───────▼──────┐
│ ja4ebpf │
│ user space │
└──────────────┘
```
### Apache httpd (centos8: 192.168.42.228) - En cours de validation
```
┌─────────────┐
│ httpd worker │─┐
└─────────────┘ │
├─ recvfrom() ──┐
│ │
@ -71,8 +55,27 @@ JA4EBPF_UPROBES_SERVERS=nginx,apache # ou "both" pour les deux
└─────────────┘
```
**Note** : Apache httpd avec event MPM peut utiliser différents syscalls selon la configuration.
Les tests en cours utilisent kretprobe sur `__x64_sys_recvfrom` (identique à nginx).
### Apache httpd (uprobe apr_socket_recv)
```
┌─────────────┐
│ httpd worker │─┐
└─────────────┘ │
├─ apr_socket_recv() (libapr-1.so.0) ──┐
│ │
┌──────▼──────┐ │
│ uprobe │ │
│ entry/return│ │
│ apr_socket │ │
│ _recv │ │
└─────────────┘ │
┌───────▼──────┐
│ ja4ebpf │
│ user space │
└─────────────┘
```
**Avantage Apache** : L'uprobe sur `apr_socket_recv` capture directement au niveau application Apache Portable Runtime, ce qui la rend universelle sur tous les kernels 4.18+ (pas de dépendance aux tracepoints/kernel functions).
## Déploiement multi-servers
@ -89,7 +92,7 @@ Les tests en cours utilisent kretprobe sur `__x64_sys_recvfrom` (identique à ng
│ │ ja4ebpf │ │ │ │ ja4ebpf │ │
│ └────────────┘ │ │ └────────────┘ │
│ │ │ │
│ capture: recvfrom│ │ capture: read │
│ capture: recvfrom│ │ capture: apr_socket_recv
└──────────────────┘ └──────────────────┘
IP: 192.168.42.40 IP: 192.168.42.228
@ -117,7 +120,7 @@ JA4EBPF_UPROBES_SERVERS=apache
│ │ │
│ ┌───────▼──────────┐ │
│ │ ja4ebpf │ │
│ │ (read/recvfrom) │ │
│ │ (nginx/Apache) │ │
│ └─────────────────┘ │
└───────────────────────────────────────────────────┘
```
@ -149,11 +152,11 @@ sudo docker exec analysis-clickhouse-1 clickhouse-client --query \
### Vérification Apache
```bash
# Vérifier que Apache capture
curl http://192.168.42.228/test -H "User-Agent: Test" -H "X-Request-ID: test-apache-001"
curl http://192.168.42.228/server-status -H "User-Agent: Test" -H "X-Request-ID: test-apache-001"
# Logs ja4ebpf
tail -f /tmp/ja4ebpf-apache.log | grep "\[apache\]"
# Exemple: [apache] HTTP: pid=48914 fd=8 GET /test (headers=5)
# Exemple: [apache] HTTP: pid=71850 GET /server-status (data_len=420)
# ClickHouse
sudo docker exec analysis-clickhouse-1 clickhouse-client --query \
@ -233,34 +236,43 @@ WHERE path = '/test-nginx-final'
-- header_order_signature: host;accept;user-agent;x-request-id;x-custom-1;x-custom-2
```
### Apache httpd - ⚠️ EN COURS DE VALIDATION
Sur CentOS 8 (kernel 4.18) :
- ⚠️ Kretprobe __x64_sys_recvfrom ne déclenche pas d'événements
- ⚠️ TC layer capture la connexion (src_ip disponible)
- ❌ HTTP layer ne capture pas les headers
### Apache httpd (via apr_socket_recv) - ✅ VALIDÉ
**Pistes d'investigation** :
1. Vérifier si Apache event MPM utilise recv() ou recvfrom()
2. Tester sur Rocky 9 (kernel 5.14+) avec Apache
3. Envisager tracepoint/sys_enter_recvfrom alternatif
**CentOS 8 (kernel 4.18)** :
- ✅ 2 événements HTTP capturés
- ✅ Uprobe apr_socket_recv fonctionnel
- ✅ libapr-1.so.0 détecté automatiquement
**Rocky 10 (kernel 6.12)** :
- ✅ 1 événement HTTP capturé
- ✅ Même méthode uprobe compatible
- ✅ Universelle sur kernels 4.18+
**Rapport complet** : `services/ja4ebpf/docs/APACHE_HTTP_VALIDATION.md`
## Dépannage
### Apache ne capture pas
```bash
# Vérifier que Apache httpd utilise bien read()
sudo strace -p 48914 -e trace=read 2>&1 | grep -A5 "GET "
# Vérifier que Apache httpd utilise libapr
sudo lsof -p $(pgrep httpd | head -1) | grep libapr
# Vérifier que les PIDs Apache sont dans la map
sudo bpftool map list name apache_pid_map
# Vérifier que libapr-1.so.0 existe
ls -la /usr/lib64/libapr-1.so.0
# Vérifier l'attachement kretprobe
sudo bpftool prog show | grep sys_exit_read
# Vérifier les PIDs Apache
pgrep -a httpd
# Vérifier l'attachement uprobe
sudo bpftool prog show | grep apr_socket_recv
# Vérifier les logs ja4ebpf
tail -f /tmp/ja4ebpf-apache.log | grep -E "(\[uprobes\]|\[apache\])"
```
### Nginx ne capture pas
```bash
# Vérifier les tracepoints attachés
# Vérifier les kretprobes attachés
sudo bpftool prog show | grep recvfrom
# Vérifier les PIDs nginx
@ -274,23 +286,22 @@ tail -f /tmp/ja4ebpf-test.log | grep nginx
### uprobe_nginx.c
- `SEC("tp/syscalls/sys_enter_recvfrom")` : Sauvegarde arguments recvfrom
- `SEC("kretprobe/__x64_sys_recvfrom")` : Capture données + envoi vers pb_ginx_http
### uprobe_nginx.c
- `SEC("kretprobe/__x64_sys_recvfrom")` : Capture données HTTP + envoi vers pb_ginx_http
- `SEC("kretprobe/__x64_sys_recvfrom")` : Capture données + envoi vers pb_nginx_http
### uprobe_apache.c
- `SEC("kretprobe/__x64_sys_recvfrom")` : Capture données HTTP + envoi vers pb_apache_http
- Utilise PT_REGS_PARM2() pour accéder au buffer utilisateur
- `SEC("uprobe/apr_socket_recv")` : Sauvegarde buf_ptr et len (entry)
- `SEC("uretprobe/apr_socket_recv")` : Capture données + envoi vers pb_apache_http
## Limitations
1. **Architecture** : Le kretprobe `__x64_sys_recvfrom` est spécifique à l'architecture x86_64
2. **Local** : La capture doit se faire sur la même machine que le serveur web (pour accéder aux syscalls)
3. **Performance** : Chaque syscall lu génère un événement BPF - le trafic très élevé peut impacter les performances
1. **Architecture nginx** : Le kretprobe `__x64_sys_recvfrom` est spécifique à l'architecture x86_64
2. **Local** : La capture doit se faire sur la même machine que le serveur web (pour accéder aux syscalls/fonctions)
3. **Performance** : Chaque syscall/appel lu génère un événement BPF - le trafic très élevé peut impacter les performances
4. **Apache only RedHat** : libapr-1.so.0 paths configurés pour RHEL/CentOS/Rocky/AlmaLinux uniquement
## Références
- Documentation nginx recvfrom : `docs/services/ja4ebpf.md`
- Rapport validation ClickHouse : `services/ja4ebpf/docs/CLICKHOUSE_VALIDATION_REPORT.md`
- Fix kretprobe recvfrom : `services/ja4ebpf/docs/RECVFROM_FIX.md`
- Documentation complète : `docs/services/ja4ebpf.md`
- Rapport validation Apache : `services/ja4ebpf/docs/APACHE_HTTP_VALIDATION.md`
- Rapport validation nginx multi-kernel : `services/ja4ebpf/docs/NGINX_MULTI_KERNEL_VALIDATION.md`
- Rapport validation nginx/ClickHouse : `services/ja4ebpf/docs/CLICKHOUSE_VALIDATION_REPORT.md`