#pragma once /* * BastionGuard™ Secure Connection — EBPFMon * Copyright (C) 2025–2026 Calogero Scarnà * GPL-3.0 * * Loader userspace per il programma eBPF bsc_ebpf.o. * Apre il pinned BPF object (o lo carica dal skel generato da bpftool), * fa attach di TUTTI i programmi presenti nell'oggetto (tracepoint + * kprobes TCP connect + kprobes UDP sendmsg), e drena la ring buffer * in un thread background. * * INTERFACCIA PUBBLICA: * EBPFMon mon; * if (mon.start()) { ... } // avvia draining thread * auto events = mon.drain(); // consuma gli eventi accumulati * mon.stop(); // join thread, detach bpf * * drain() e' lock-free dal punto di vista del chiamante: scambia * atomicamente il buffer interno con uno vuoto — O(1) e senza copie. * * NOTA: se libbpf non e' disponibile a compile-time (BSC_HAS_EBPF non * definito), tutte le implementazioni sono no-op e drain() ritorna * sempre un vettore vuoto. Il resto del daemon non nota la differenza. */ #include "bsc/model/Connection.hpp" #include #include #include #include #include #include // Questa struttura DEVE essere identica a bsc_conn_event in bsc_ebpf.c // Viene usata per interpretare i byte della ring buffer. // // NB: layout conservato rispetto alla v1: // la v1 aveva uint8_t _pad[2] // la v2 ha uint8_t event_kind + uint8_t _pad[1] // Stessa dimensione totale, stessi offset → un loader v2 legge un // oggetto v1 con event_kind=0 (valore di padding), retro-compat OK. namespace bsc::ebpf { enum EventKind : uint8_t { EVT_TP_SET_STATE = 0, // tracepoint inet_sock_set_state EVT_TCP_CONNECT = 1, // kprobe tcp_v{4,6}_connect EVT_UDP_SENDMSG = 2, // kprobe udp{,v6}_sendmsg }; struct ConnEvent { uint32_t pid; uint32_t tid; uint32_t uid; uint32_t gid; char comm[16]; uint8_t family; // AF_INET=2, AF_INET6=10 uint8_t proto; // IPPROTO_TCP=6, IPPROTO_UDP=17 uint8_t event_kind; // vedi EventKind uint8_t _pad[1]; uint16_t src_port; uint16_t dst_port; uint8_t src_addr[16]; uint8_t dst_addr[16]; uint64_t ts_ns; }; /* * Converte un ConnEvent in un bsc::model::Connection parzialmente * arricchita (process_id, process_comm, user_id, src/dst IP, src/dst * port gia' valorizzati). Il chiamante (SocketSnapshot o DaemonService) * completa con process_path, dns, ecc. */ bsc::model::Connection event_to_connection(const ConnEvent& ev); class EBPFMon { public: EBPFMon(); ~EBPFMon(); EBPFMon(const EBPFMon&) = delete; EBPFMon& operator=(const EBPFMon&) = delete; /* * Carica il programma eBPF e avvia il thread di draining. * obj_path: percorso del .o compilato dal kernel eBPF. * Default: /usr/lib/bastionguard-sc/bsc_ebpf.o * Ritorna true se il setup e' riuscito (anche parziale: se alcuni * kprobe non possono essere attaccati — es. simbolo assente nel * kernel — proseguiamo comunque con quelli disponibili). * Ritorna false solo se non siamo riusciti ad attaccare nemmeno un * programma o se il load del .o e' fallito. * In caso di fallimento il daemon prosegue normalmente senza eBPF. */ bool start(const std::string& obj_path = "/usr/lib/bastionguard-sc/bsc_ebpf.o"); /* * Ferma il thread di draining e fa detach del programma BPF. * Idempotente (sicuro da chiamare se start() ha fallito). */ void stop(); /* * Consuma tutti gli eventi accumulati dalla ring buffer. * Scambia atomicamente il buffer interno con uno vuoto — O(1). * Thread-safe. */ std::vector drain(); /* true se start() ha avuto successo e il monitor e' attivo */ bool active() const noexcept { return active_.load(); } private: void drain_loop(); // corpo del thread background // Callback C per libbpf ring_buffer__new — deve accedere ai membri privati friend int ringbuf_callback(void* ctx, void* data, size_t size); std::atomic_bool active_{false}; std::atomic_bool stop_{false}; std::thread thread_; mutable std::mutex buf_mutex_; std::vector buf_; // accumulo eventi // Puntatori opachi a strutture libbpf — non esponiamo libbpf // all'esterno per non inquinare tutti gli header con #include void* bpf_obj_{nullptr}; // struct bpf_object* void* ring_buf_{nullptr}; // struct ring_buffer* // Manteniamo TUTTI i bpf_link attivi (tracepoint + kprobes) cosi' possiamo // fare detach in stop(). In v1 ne tenevamo uno solo. std::vector links_; // vector }; } // namespace bsc::ebpf