/* uprobe_nginx.c — Uprobes simplifiés pour capturer le trafic HTTP depuis nginx * * Version simplifiée qui utilise : * - read() syscall pour capturer les données lues par nginx depuis le socket * - Corrélation via fd entre TC (métadonnées L3/L4) et nginx (données L7) * * ============================================================================ */ #include "vmlinux.h" #include #include #include "bpf_types.h" /* Taille maximale d'une capture read() nginx */ #define MAX_NGINX_READ_SIZE 4096 /* ============================================================================ * uprobe_read_entry — Entrée de read() dans nginx * * Sauvegarde les arguments (fd, buf, count) pour l'uretprobe correspondant. * ============================================================================ */ SEC("uprobe/read_entry") int uprobe_read_entry(struct pt_regs *ctx) { __u64 pid_tgid = bpf_get_current_pid_tgid(); /* Sauvegarder les arguments pour l'uretprobe */ struct nginx_read_args args = {}; args.fd = (__s32)PT_REGS_PARM1(ctx); args.buf_ptr = (__u64)PT_REGS_PARM2(ctx); args.count = (__u64)PT_REGS_PARM3(ctx); /* Stocker dans une map hash pour récupération dans l'uretprobe */ bpf_map_update_elem(&nginx_read_args_map, &pid_tgid, &args, BPF_ANY); return 0; } /* ============================================================================ * uretprobe_read_exit — Fin de read() dans nginx * * Capture les données lues depuis le socket client. * Version simplifiée : capture brute des données, parsing HTTP côté userspace. * ============================================================================ */ SEC("uretprobe/read_exit") int uretprobe_read_exit(struct pt_regs *ctx) { __u64 pid_tgid = bpf_get_current_pid_tgid(); /* Récupérer les arguments sauvegardés */ struct nginx_read_args *args = bpf_map_lookup_elem(&nginx_read_args_map, &pid_tgid); if (!args) return 0; /* Vérifier que la lecture a réussi (valeur de retour > 0) */ long retval = PT_REGS_RC(ctx); if (retval <= 0) { bpf_map_delete_elem(&nginx_read_args_map, &pid_tgid); return 0; } /* Limiter la capture */ __u32 data_len = retval; if (data_len > MAX_NGINX_READ_SIZE) data_len = MAX_NGINX_READ_SIZE; /* Buffer PERCPU */ __u32 zero = 0; struct nginx_http_event *evt = bpf_map_lookup_elem(&__nginx_buf, &zero); if (!evt) { bpf_map_delete_elem(&nginx_read_args_map, &pid_tgid); return 0; } /* Initialiser l'événement */ evt->pid_tgid = pid_tgid; evt->fd = args->fd; evt->src_ip = 0; /* Sera rempli via corrélation TC */ evt->src_port = 0; evt->timestamp_ns = bpf_ktime_get_ns(); evt->method_len = 0; evt->uri_len = 0; evt->query_len = 0; evt->body_len = 0; evt->data_len = 0; /* Copier les données brutes depuis le buffer nginx */ if (data_len > 0) { /* Limiter à la taille du champ data (3640 octets) */ __u32 copy_len = data_len; if (copy_len > sizeof(evt->data)) copy_len = sizeof(evt->data); bpf_probe_read_user(evt->data, copy_len, (void *)args->buf_ptr); evt->data_len = copy_len; } /* Émettre l'événement brut vers userspace */ /* Le parsing HTTP sera fait côté userspace pour éviter */ /* de dépasser la limite d'instructions BPF */ bpf_perf_event_output(ctx, &pb_ginx_http, BPF_F_CURRENT_CPU, evt, sizeof(*evt)); bpf_map_delete_elem(&nginx_read_args_map, &pid_tgid); return 0; } char LICENSE[] SEC("license") = "GPL";