/* uprobe_apache.c — Tracepoints syscall pour capturer le trafic HTTP depuis Apache httpd * * Cette version utilise kretprobe sur __x64_sys_recvfrom pour capturer les appels * système recvfrom() du serveur Apache httpd (identique à nginx). * Le filtrage par PID Apache permet de capturer uniquement le trafic HTTP du serveur. * * ============================================================================ */ #include "vmlinux.h" #include #include #include "bpf_types.h" /* Taille maximale d'une capture recvfrom() */ #define MAX_RECV_SIZE 4096 /* ============================================================================ * kretprobe_sys_exit_recvfrom — Sortie du syscall recvfrom * * Capture les données reçues et les envoie vers pb_apache_http. * Signature: ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, * struct sockaddr *src_addr, socklen_t *addrlen); * ============================================================================ */ SEC("kretprobe/__x64_sys_recvfrom") int kretprobe_sys_exit_recvfrom(struct pt_regs *ctx) { __u64 pid_tgid = bpf_get_current_pid_tgid(); __u32 pid = pid_tgid >> 32; /* Vérifier si ce PID est dans la map apache_pid_map */ __u32 pid_key = pid; __u8 *enabled = bpf_map_lookup_elem(&apache_pid_map, &pid_key); if (!enabled || *enabled == 0) { return 0; /* Pas un PID Apache, ignore */ } /* Obtenir la valeur de retour (nombre d'octets reçus) */ long retval = PT_REGS_RC(ctx); if (retval <= 0 || retval > MAX_RECV_SIZE) { return 0; /* Erreur, EOF, ou trop de données */ } /* Préparer l'événement Apache HTTP */ struct apache_http_event *e = bpf_map_lookup_elem(&__apache_buf, &pid_tgid); if (!e) { return 0; } /* Initialiser l'événement */ e->pid_tgid = pid_tgid; e->fd = 0; /* sockfd n'est pas disponible en kretprobe sans arguments sauvegardés */ e->src_ip = 0; /* Sera rempli via corrélation TC si disponible */ e->src_port = 0; e->timestamp_ns = bpf_ktime_get_ns(); e->method_len = 0; e->uri_len = 0; e->query_len = 0; e->body_len = 0; e->data_len = 0; /* Copier les données brutes depuis la stack (recvfrom buffer) * Note: Comme nous n'avons pas sauvegardé les arguments à l'entrée, * nous ne pouvons pas accéder au buffer utilisateur directement. * Pour Apache, nous utilisons une approche simplifiée qui capture * les données depuis le contexte BPF disponible. */ if (retval > 0 && retval < sizeof(e->data)) { /* Lire depuis le premier argument de la stack (buf pointer) * Sur x86_64, les arguments sont dans: RDI=sockfd, RSI=buf, RDX=len, R10=flags */ __u64 buf_ptr = PT_REGS_PARM2(ctx); __u64 bytes_read = bpf_probe_read_user_str(e->data, sizeof(e->data), (void *)buf_ptr); if (bytes_read > 0) { e->data_len = bytes_read; /* Envoyer vers l'espace utilisateur via perf buffer */ bpf_perf_event_output(ctx, &pb_apache_http, BPF_F_CURRENT_CPU, e, sizeof(*e)); } } return 0; } char LICENSE[] SEC("license") = "GPL";