Skip to content
API Documentation
BastionGuard™
EBPFMon.hpp
Go to the documentation of this file.
1#pragma once
2/*
3 * BastionGuard™ Secure Connection — EBPFMon
4 * Copyright (C) 2025–2026 Calogero Scarnà
5 * GPL-3.0
6 *
7 * Loader userspace per il programma eBPF bsc_ebpf.o.
8 * Apre il pinned BPF object (o lo carica dal skel generato da bpftool),
9 * fa attach di TUTTI i programmi presenti nell'oggetto (tracepoint +
10 * kprobes TCP connect + kprobes UDP sendmsg), e drena la ring buffer
11 * in un thread background.
12 *
13 * INTERFACCIA PUBBLICA:
14 * EBPFMon mon;
15 * if (mon.start()) { ... } // avvia draining thread
16 * auto events = mon.drain(); // consuma gli eventi accumulati
17 * mon.stop(); // join thread, detach bpf
18 *
19 * drain() e' lock-free dal punto di vista del chiamante: scambia
20 * atomicamente il buffer interno con uno vuoto — O(1) e senza copie.
21 *
22 * NOTA: se libbpf non e' disponibile a compile-time (BSC_HAS_EBPF non
23 * definito), tutte le implementazioni sono no-op e drain() ritorna
24 * sempre un vettore vuoto. Il resto del daemon non nota la differenza.
25 */
26
28#include <atomic>
29#include <functional>
30#include <mutex>
31#include <string>
32#include <thread>
33#include <vector>
34
35// Questa struttura DEVE essere identica a bsc_conn_event in bsc_ebpf.c
36// Viene usata per interpretare i byte della ring buffer.
37//
38// NB: layout conservato rispetto alla v1:
39// la v1 aveva uint8_t _pad[2]
40// la v2 ha uint8_t event_kind + uint8_t _pad[1]
41// Stessa dimensione totale, stessi offset → un loader v2 legge un
42// oggetto v1 con event_kind=0 (valore di padding), retro-compat OK.
43namespace bsc::ebpf {
44
45enum EventKind : uint8_t {
46 EVT_TP_SET_STATE = 0, // tracepoint inet_sock_set_state
47 EVT_TCP_CONNECT = 1, // kprobe tcp_v{4,6}_connect
48 EVT_UDP_SENDMSG = 2, // kprobe udp{,v6}_sendmsg
49};
50
51struct ConnEvent {
52 uint32_t pid;
53 uint32_t tid;
54 uint32_t uid;
55 uint32_t gid;
56 char comm[16];
57 uint8_t family; // AF_INET=2, AF_INET6=10
58 uint8_t proto; // IPPROTO_TCP=6, IPPROTO_UDP=17
59 uint8_t event_kind; // vedi EventKind
60 uint8_t _pad[1];
61 uint16_t src_port;
62 uint16_t dst_port;
63 uint8_t src_addr[16];
64 uint8_t dst_addr[16];
65 uint64_t ts_ns;
66};
67
68/*
69 * Converte un ConnEvent in un bsc::model::Connection parzialmente
70 * arricchita (process_id, process_comm, user_id, src/dst IP, src/dst
71 * port gia' valorizzati). Il chiamante (SocketSnapshot o DaemonService)
72 * completa con process_path, dns, ecc.
73 */
75
76class EBPFMon {
77 public:
79 ~EBPFMon();
80
81 EBPFMon(const EBPFMon&) = delete;
82 EBPFMon& operator=(const EBPFMon&) = delete;
83
84 /*
85 * Carica il programma eBPF e avvia il thread di draining.
86 * obj_path: percorso del .o compilato dal kernel eBPF.
87 * Default: /usr/lib/bastionguard-sc/bsc_ebpf.o
88 * Ritorna true se il setup e' riuscito (anche parziale: se alcuni
89 * kprobe non possono essere attaccati — es. simbolo assente nel
90 * kernel — proseguiamo comunque con quelli disponibili).
91 * Ritorna false solo se non siamo riusciti ad attaccare nemmeno un
92 * programma o se il load del .o e' fallito.
93 * In caso di fallimento il daemon prosegue normalmente senza eBPF.
94 */
95 bool start(const std::string& obj_path =
96 "/usr/lib/bastionguard-sc/bsc_ebpf.o");
97
98 /*
99 * Ferma il thread di draining e fa detach del programma BPF.
100 * Idempotente (sicuro da chiamare se start() ha fallito).
101 */
102 void stop();
103
104 /*
105 * Consuma tutti gli eventi accumulati dalla ring buffer.
106 * Scambia atomicamente il buffer interno con uno vuoto — O(1).
107 * Thread-safe.
108 */
109 std::vector<bsc::model::Connection> drain();
110
111 /* true se start() ha avuto successo e il monitor e' attivo */
112 bool active() const noexcept { return active_.load(); }
113
114 private:
115 void drain_loop(); // corpo del thread background
116
117 // Callback C per libbpf ring_buffer__new — deve accedere ai membri privati
118 friend int ringbuf_callback(void* ctx, void* data, size_t size);
119
120 std::atomic_bool active_{false};
121 std::atomic_bool stop_{false};
122 std::thread thread_;
123
124 mutable std::mutex buf_mutex_;
125 std::vector<bsc::model::Connection> buf_; // accumulo eventi
126
127 // Puntatori opachi a strutture libbpf — non esponiamo libbpf
128 // all'esterno per non inquinare tutti gli header con #include <bpf/libbpf.h>
129 void* bpf_obj_{nullptr}; // struct bpf_object*
130 void* ring_buf_{nullptr}; // struct ring_buffer*
131
132 // Manteniamo TUTTI i bpf_link attivi (tracepoint + kprobes) cosi' possiamo
133 // fare detach in stop(). In v1 ne tenevamo uno solo.
134 std::vector<void*> links_; // vector<struct bpf_link*>
135};
136
137} // namespace bsc::ebpf
EBPFMon & operator=(const EBPFMon &)=delete
std::atomic_bool active_
Definition EBPFMon.hpp:120
bool active() const noexcept
Definition EBPFMon.hpp:112
std::thread thread_
Definition EBPFMon.hpp:122
friend int ringbuf_callback(void *ctx, void *data, size_t size)
std::vector< bsc::model::Connection > drain()
Definition EBPFMon.cpp:286
bool start(const std::string &obj_path="/usr/lib/bastionguard-sc/bsc_ebpf.o")
Definition EBPFMon.cpp:277
EBPFMon(const EBPFMon &)=delete
std::atomic_bool stop_
Definition EBPFMon.hpp:121
std::vector< void * > links_
Definition EBPFMon.hpp:134
std::mutex buf_mutex_
Definition EBPFMon.hpp:124
std::vector< bsc::model::Connection > buf_
Definition EBPFMon.hpp:125
@ EVT_UDP_SENDMSG
Definition EBPFMon.hpp:48
@ EVT_TCP_CONNECT
Definition EBPFMon.hpp:47
@ EVT_TP_SET_STATE
Definition EBPFMon.hpp:46
bsc::model::Connection event_to_connection(const ConnEvent &ev)
Definition EBPFMon.cpp:34
uint8_t dst_addr[16]
Definition EBPFMon.hpp:64
uint8_t src_addr[16]
Definition EBPFMon.hpp:63