**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>
11 KiB
11 KiB
Guide : Capture HTTP Nginx et Apache httpd via ja4ebpf
Vue d'ensemble
ja4ebpf peut capturer le trafic HTTP complet depuis deux serveurs web différents :
- Nginx ✅ : via
recvfrom()syscall (kretprobe sur__x64_sys_recvfrom) - Apache httpd ✅ : via
apr_socket_recv()uprobe dans libapr-1.so.0
Statut de validation
| 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
Configuration YAML
uprobes:
enabled: true
servers: ["nginx", "apache"] # Active les deux serveurs
Variables d'environnement
JA4EBPF_UPROBES_ENABLED=true
JA4EBPF_UPROBES_SERVERS=nginx,apache
Architecture de capture
Nginx (kretprobe)
┌─────────────┐
│ nginx worker │─┐
└─────────────┘ │
├─ recvfrom() ──┐
│ │
┌──────▼──────┐ │
│ kretprobe │ │
│ __x64_sys │ │
│ recvfrom │ │
└─────────────┘ │
│
┌───────▼──────┐
│ ja4ebpf │
│ user space │
└─────────────┘
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
Scénario 1 : ja4ebpf sur chaque serveur web
┌─────────────────┐ ┌─────────────────┐
│ rocky9 (nginx) │ │ centos8 (apache)│
│ │ │ │
│ ┌────────────┐ │ │ ┌────────────┐ │
│ │ nginx │ │ │ │ Apache │ │
│ └─────┬──────┘ │ │ └─────┬──────┘ │
│ │ │ │ │ │
│ ┌─────▼──────┐ │ │ ┌─────▼──────┐ │
│ │ ja4ebpf │ │ │ │ ja4ebpf │ │
│ └────────────┘ │ │ └────────────┘ │
│ │ │ │
│ capture: recvfrom│ │ capture: apr_socket_recv
└──────────────────┘ └──────────────────┘
IP: 192.168.42.40 IP: 192.168.42.228
Configuration :
# rocky9
JA4EBPF_UPROBES_SERVERS=nginx
# centos8
JA4EBPF_UPROBES_SERVERS=apache
Scénario 2 : ja4ebpf sur machine tierce (recommandé)
┌─────────────────────────────────────────────────┐
│ analysis VM (ja4ebpf) │
│ │
│ ┌────────────┐ ┌─────────────┐ │
│ │ nginx │ │ Apache │ │
│ └──────┬─────┘ └──────┬──────┘ │
│ │ │ │
│ └───────┬───────┘ │
│ │ │
│ ┌───────▼──────────┐ │
│ │ ja4ebpf │ │
│ │ (nginx/Apache) │ │
│ └─────────────────┘ │
└───────────────────────────────────────────────────┘
Configuration :
uprobes:
enabled: true
servers: ["nginx", "apache"]
Validation
Vérification nginx
# Vérifier que nginx capture
curl http://192.168.42.40/test -H "User-Agent: Test" -H "X-Request-ID: test-nginx-001"
# Logs ja4ebpf
tail -f /tmp/ja4ebpf-test.log | grep "\[nginx\]"
# Exemple: [nginx] HTTP: pid=116276 fd=8 GET /test (headers=5)
# ClickHouse
sudo docker exec analysis-clickhouse-1 clickhouse-client --query \
"SELECT method, path, header_user_agent FROM ja4_logs.http_logs \
WHERE time > now() - INTERVAL 1 MINUTE ORDER BY time DESC LIMIT 10"
Vérification Apache
# Vérifier que Apache capture
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=71850 GET /server-status (data_len=420)
# ClickHouse
sudo docker exec analysis-clickhouse-1 clickhouse-client --query \
"SELECT method, path, header_user_agent FROM ja4_logs.http_logs \
WHERE time > now() - INTERVAL 1 MINUTE ORDER BY time DESC LIMIT 10"
Tests de validation
Test 1 : Headers complets
# Test nginx (20+ headers)
curl http://192.168.42.40/api/test \
-H "User-Agent: Mozilla/5.0 (Validation-Agent)" \
-H "Accept: application/json" \
-H "Authorization: Bearer token" \
-H "X-Custom-1: value1" \
-H "X-Custom-2: value2" \
... (jusqu'à 20 headers)
# Test Apache (20+ headers)
curl http://192.168.42.228/api/test \
-H "User-Agent: Mozilla/5.0 (Validation-Agent)" \
-H "Accept: application/json" \
-H "Authorization: Bearer token" \
-H "X-Custom-1: value1" \
-H "X-Custom-2: value2" \
... (jusqu'à 20 headers)
Test 2 : Path et query longs
# nginx
curl "http://192.168.42.40/api/v1/users/12345/profile/preferences?include=all&filter=active&sort=desc"
# Apache
curl "http://192.168.42.228/api/v1/users/12345/profile/preferences?include=all&filter=active&sort=desc"
Validation ClickHouse
-- Requête pour vérifier la capture
SELECT
src_ip,
method,
path,
query,
substring(header_user_agent, 1, 40) as ua_preview,
length(header_order_signature) as header_count,
substring(header_order_signature, 1, 60) as headers_preview
FROM ja4_logs.http_logs
WHERE time > now() - INTERVAL 5 MINUTE
ORDER BY time DESC
LIMIT 20
FORMAT Pretty
Résultats de validation
Nginx (via recvfrom) - ✅ VALIDÉ sur Rocky Linux 9
- ✅ Méthode HTTP capturée
- ✅ Path complet sans troncature
- ✅ Query string complète
- ✅ Tous les headers capturés (y compris custom X-*)
- ✅ User-Agent complet
- ✅ Ordre des headers préservé
- ✅ Données ClickHouse sans troncature
Exemple de capture validée :
SELECT method, path, host,
length(header_order_signature) as headers_count,
header_order_signature
FROM ja4_logs.http_logs
WHERE path = '/test-nginx-final'
-- Résultat : headers_count=6
-- header_order_signature: host;accept;user-agent;x-request-id;x-custom-1;x-custom-2
Apache httpd (via apr_socket_recv) - ✅ VALIDÉ
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
# Vérifier que Apache httpd utilise libapr
sudo lsof -p $(pgrep httpd | head -1) | grep libapr
# Vérifier que libapr-1.so.0 existe
ls -la /usr/lib64/libapr-1.so.0
# 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
# Vérifier les kretprobes attachés
sudo bpftool prog show | grep recvfrom
# Vérifier les PIDs nginx
pgrep -a nginx | wc -l
# Vérifier les logs ja4ebpf
tail -f /tmp/ja4ebpf-test.log | grep nginx
Fichiers BPF
uprobe_nginx.c
SEC("tp/syscalls/sys_enter_recvfrom"): Sauvegarde arguments recvfromSEC("kretprobe/__x64_sys_recvfrom"): Capture données + envoi vers pb_nginx_http
uprobe_apache.c
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
- Architecture nginx : Le kretprobe
__x64_sys_recvfromest spécifique à l'architecture x86_64 - Local : La capture doit se faire sur la même machine que le serveur web (pour accéder aux syscalls/fonctions)
- Performance : Chaque syscall/appel lu génère un événement BPF - le trafic très élevé peut impacter les performances
- Apache only RedHat : libapr-1.so.0 paths configurés pour RHEL/CentOS/Rocky/AlmaLinux uniquement
Références
- 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