feat(ja4ebpf): add SSL_write uprobe, HPACK decoder, and AcceptCache for session correlation

Add uprobe_ssl_write_entry/uretprobe_ssl_write_exit to capture server HTTP
responses via SSL_write with direction=1. Implement full HPACK decoder
(RFC 7541 static table, multi-byte integers, literal representations) for
HTTP/2 header extraction. Add AcceptCache mapping {tgid,fd}→SessionKey
from accept4 events as authoritative source for SSL correlation when BPF
ssl_conn_map has src_ip=0. Add ip_total_length to tcp_syn_event BPF struct.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jacquin Antoine
2026-04-15 03:34:43 +02:00
parent a02423fd18
commit 24306ef390
7 changed files with 847 additions and 16 deletions

View File

@ -174,6 +174,81 @@ int uretprobe_ssl_read_exit(struct pt_regs *ctx)
return 0;
}
/* ===========================================================================
* uprobe_ssl_write_entry — Entrée de SSL_write(SSL *ssl, const void *buf, int num)
*
* Sauvegarde les arguments pour l'uretprobe correspondant.
* Réutilise ssl_args_map (même format que SSL_read — un seul thread à la fois).
* ===========================================================================*/
SEC("uprobe/SSL_write")
int uprobe_ssl_write_entry(struct pt_regs *ctx)
{
__u64 pid_tgid = bpf_get_current_pid_tgid();
struct ssl_read_args args = {};
args.ssl_ptr = (__u64)PT_REGS_PARM1(ctx);
args.buf_ptr = (__u64)PT_REGS_PARM2(ctx);
args.num = (__u32)PT_REGS_PARM3(ctx);
bpf_map_update_elem(&ssl_args_map, &pid_tgid, &args, BPF_ANY);
return 0;
}
/* ===========================================================================
* uretprobe_ssl_write_exit — Retour de SSL_write
*
* Lit le buffer de réponse et l'émet via perf_event_output avec direction=1.
* Les données sont les réponses HTTP du serveur (status, headers, body).
* ===========================================================================*/
SEC("uretprobe/SSL_write")
int uretprobe_ssl_write_exit(struct pt_regs *ctx)
{
__u64 pid_tgid = bpf_get_current_pid_tgid();
struct ssl_read_args *args = bpf_map_lookup_elem(&ssl_args_map, &pid_tgid);
if (!args)
return 0;
long retval = PT_REGS_RC(ctx);
if (retval <= 0) {
bpf_map_delete_elem(&ssl_args_map, &pid_tgid);
return 0;
}
__u32 zero = 0;
struct ssl_data_event *evt = bpf_map_lookup_elem(&__ssl_buf, &zero);
if (!evt) {
bpf_map_delete_elem(&ssl_args_map, &pid_tgid);
return 0;
}
evt->pid_tgid = pid_tgid;
evt->direction = 1; /* écriture = serveur vers client */
evt->timestamp_ns = bpf_ktime_get_ns();
__u32 data_len = (retval > MAX_SSL_DATA) ? MAX_SSL_DATA : (__u32)retval;
evt->data_len = data_len;
bpf_probe_read_user(evt->data, data_len & (MAX_SSL_DATA - 1), (void *)args->buf_ptr);
struct ssl_conn_info *conn = bpf_map_lookup_elem(&ssl_conn_map, &args->ssl_ptr);
if (conn) {
evt->fd = conn->fd;
evt->src_ip = conn->src_ip;
evt->src_port = conn->src_port;
} else {
evt->fd = 0;
evt->src_ip = 0;
evt->src_port = 0;
}
bpf_perf_event_output(ctx, &pb_ssl_data, BPF_F_CURRENT_CPU,
evt, sizeof(*evt));
bpf_map_delete_elem(&ssl_args_map, &pid_tgid);
return 0;
}
/* ===========================================================================
* kprobe_accept4_entry — Entrée de accept4 via tracepoint syscalls
*