feat: pipeline L7 HTTP complet + infrastructure tests VM
Correctifs pipeline L7 (uprobe SSL_read) :
- uprobe_ssl.c : ssl_set_fd ne retourne plus tôt quand fd_conn_map est
vide (accept4 non disponible en Docker). Sauvegarde ssl_ptr→{fd,0,0}
pour permettre le fallback /proc côté Go.
- main.go : consumeSSLEvents reécrit avec routeur magic-bytes complet :
* HTTP/2 preface → extraction SETTINGS + conversion correlation.HTTP2Settings
* HTTP/1.x requête → method, path, query, headers, header_order_sig
* HTTP/1.x réponse → status_code
* Fallback /proc/<tgid>/fd/<fd> quand src_ip=0 (accept4 absent)
- writer/clickhouse.go : export header_order_signature ajouté
Nouveaux packages :
- internal/parser/http1.go : parseur HTTP/1.x (IsHTTP1Request,
ParseHTTP1Request, IsHTTP1Response, ParseHTTP1Response)
- internal/parser/http1_test.go : 11 tests unitaires (28 total passent)
- internal/procutil/proc_lookup.go : résolution fd→IP via /proc avec cache
TTL 5s (FDCache). Supporte /proc/PID/net/tcp et tcp6, IPv4-mappé IPv6.
Infrastructure tests VM (tests/vm/) :
- Vagrantfile : VM Rocky Linux 9 KVM, 4 CPU / 4 GB RAM
- provision.sh : installation toolchain eBPF + Go + Docker + nginx
- run-tests-vm.sh : suite de test complète dans la VM (L3/L4+TLS+L7)
- README.md : guide d'installation et d'utilisation
- Makefile : cibles vm-up, vm-down, vm-ssh, test-vm-nginx, test-vm-all,
vm-rebuild-ja4ebpf
Corrections stack Docker :
- Dockerfiles nginx/apache/nginx-varnish/hitch-varnish : suppression des
références à shared/go/ja4common/ (répertoire supprimé)
- clickhouse-init.sh : restauré depuis git, seed anubis_ua_rules obsolète
supprimé (table REGEXP_TREE supprimée du schéma)
- traffic-gen : ajout HTTP/1.0 (http.client) et HTTP/2 (httpx)
- verify_db.py : script de vérification 35 checks (L3/L4/TLS/L7/corrélation)
- run-stack-tests.sh : phase 6 verify_db ajoutée
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@ -1,8 +1,9 @@
|
||||
/* ============================================================================
|
||||
* uprobe_ssl.c — Uprobes SSL_read/SSL_set_fd et kprobes accept4
|
||||
/* uprobe_ssl.c — Uprobes SSL_read/SSL_set_fd et tracepoints accept4
|
||||
*
|
||||
* Intercepte les appels OpenSSL pour capturer le trafic déchiffré,
|
||||
* et corrige l'association socket ↔ SSL* via accept4.
|
||||
* et corrige l'association socket ↔ SSL* via les tracepoints syscalls/accept4.
|
||||
* Les tracepoints sont plus stables que les kprobes car ils ne dépendent pas
|
||||
* du nom manglé __x64_sys_accept4 (variable selon la version du kernel).
|
||||
* ============================================================================ */
|
||||
|
||||
#include "vmlinux.h"
|
||||
@ -24,11 +25,42 @@ struct {
|
||||
__type(value, __u64); /* pointeur userspace vers sockaddr_in */
|
||||
} accept_args_map SEC(".maps");
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Structs pour les tracepoints syscalls/sys_{enter,exit}_accept4
|
||||
*
|
||||
* Format vérifié avec : /sys/kernel/tracing/events/syscalls/sys_enter_accept4/format
|
||||
* Valable pour les kernels 4.x → 6.x (stable, CO-RE non requis).
|
||||
* ---------------------------------------------------------------------------*/
|
||||
struct sys_enter_accept4_ctx {
|
||||
__u16 common_type;
|
||||
__u8 common_flags;
|
||||
__u8 common_preempt_count;
|
||||
__s32 common_pid;
|
||||
__s32 __syscall_nr;
|
||||
__u32 _pad;
|
||||
__s64 listen_fd;
|
||||
struct sockaddr *upeer_sockaddr; /* adresse userspace du client */
|
||||
int *upeer_addrlen;
|
||||
__s64 flags;
|
||||
};
|
||||
|
||||
struct sys_exit_accept4_ctx {
|
||||
__u16 common_type;
|
||||
__u8 common_flags;
|
||||
__u8 common_preempt_count;
|
||||
__s32 common_pid;
|
||||
__s32 __syscall_nr;
|
||||
__u32 _pad;
|
||||
__s64 ret; /* fd retourné par accept4, ou < 0 si erreur */
|
||||
};
|
||||
|
||||
/* ===========================================================================
|
||||
* uprobe_ssl_set_fd — Intercept SSL_set_fd(SSL *s, int fd)
|
||||
*
|
||||
* Associe un ssl_ptr à ses informations de connexion (fd, src_ip, src_port)
|
||||
* en consultant fd_conn_map.
|
||||
* en consultant fd_conn_map. Si fd_conn_map est vide (accept4 non disponible),
|
||||
* enregistre quand même l'association ssl_ptr → fd avec IP=0 pour que le
|
||||
* Go userspace puisse faire le lookup IP via /proc/<pid>/net/tcp.
|
||||
* ===========================================================================*/
|
||||
SEC("uprobe/SSL_set_fd")
|
||||
int uprobe_ssl_set_fd(struct pt_regs *ctx)
|
||||
@ -36,16 +68,18 @@ int uprobe_ssl_set_fd(struct pt_regs *ctx)
|
||||
__u64 ssl_ptr = ((__u64)PT_REGS_PARM1(ctx));
|
||||
__u32 fd = ((__u32)PT_REGS_PARM2(ctx));
|
||||
|
||||
/* Rechercher les infos de connexion via le fd */
|
||||
struct ssl_conn_info *conn = bpf_map_lookup_elem(&fd_conn_map, &fd);
|
||||
if (!conn)
|
||||
return 0;
|
||||
|
||||
/* Enregistrer l'association ssl_ptr → conn_info */
|
||||
struct ssl_conn_info new_conn = *conn;
|
||||
struct ssl_conn_info new_conn = {};
|
||||
new_conn.fd = fd;
|
||||
bpf_map_update_elem(&ssl_conn_map, &ssl_ptr, &new_conn, BPF_ANY);
|
||||
|
||||
/* Tenter de récupérer les infos de connexion via fd_conn_map (accept4) */
|
||||
struct ssl_conn_info *conn = bpf_map_lookup_elem(&fd_conn_map, &fd);
|
||||
if (conn) {
|
||||
new_conn.src_ip = conn->src_ip;
|
||||
new_conn.src_port = conn->src_port;
|
||||
}
|
||||
/* Sans accept4, src_ip=0 / src_port=0 — le userspace Go fera le lookup /proc */
|
||||
|
||||
bpf_map_update_elem(&ssl_conn_map, &ssl_ptr, &new_conn, BPF_ANY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -127,34 +161,35 @@ int uretprobe_ssl_read_exit(struct pt_regs *ctx)
|
||||
}
|
||||
|
||||
/* ===========================================================================
|
||||
* kprobe_accept4_entry — Entrée de accept4(fd, upeer_sockaddr, upeer_addrlen, flags)
|
||||
* kprobe_accept4_entry — Entrée de accept4 via tracepoint syscalls
|
||||
*
|
||||
* Sauvegarde le pointeur vers la sockaddr pour la récupérer à la sortie.
|
||||
* Utilise SEC("tracepoint/syscalls/sys_enter_accept4") au lieu d'un kprobe
|
||||
* pour éviter la dépendance au nom manglé __x64_sys_accept4 (kernel 5.1+).
|
||||
* Le contexte tracepoint expose directement upeer_sockaddr sans indirection.
|
||||
* ===========================================================================*/
|
||||
SEC("kprobe/accept4")
|
||||
int kprobe_accept4_entry(struct pt_regs *ctx)
|
||||
SEC("tracepoint/syscalls/sys_enter_accept4")
|
||||
int kprobe_accept4_entry(struct sys_enter_accept4_ctx *ctx)
|
||||
{
|
||||
__u64 pid_tgid = bpf_get_current_pid_tgid();
|
||||
/* Deuxième argument : pointeur userspace vers struct sockaddr_in */
|
||||
__u64 sockaddr_ptr = (__u64)PT_REGS_PARM2(ctx);
|
||||
__u64 sockaddr_ptr = (__u64)ctx->upeer_sockaddr;
|
||||
|
||||
bpf_map_update_elem(&accept_args_map, &pid_tgid, &sockaddr_ptr, BPF_ANY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ===========================================================================
|
||||
* kretprobe_accept4_exit — Retour de accept4
|
||||
* kretprobe_accept4_exit — Retour de accept4 via tracepoint syscalls
|
||||
*
|
||||
* Lit la sockaddr_in pour extraire src_ip:src_port du client,
|
||||
* peuple accept_map et fd_conn_map, et émet dans rb_accept.
|
||||
* ===========================================================================*/
|
||||
SEC("kretprobe/accept4")
|
||||
int kretprobe_accept4_exit(struct pt_regs *ctx)
|
||||
SEC("tracepoint/syscalls/sys_exit_accept4")
|
||||
int kretprobe_accept4_exit(struct sys_exit_accept4_ctx *ctx)
|
||||
{
|
||||
__u64 pid_tgid = bpf_get_current_pid_tgid();
|
||||
|
||||
/* Vérifier que accept4 a réussi (fd ≥ 0) */
|
||||
long new_fd = PT_REGS_RC(ctx);
|
||||
long new_fd = ctx->ret;
|
||||
if (new_fd < 0) {
|
||||
bpf_map_delete_elem(&accept_args_map, &pid_tgid);
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user