Skip to content
API Documentation
BastionGuard™
WireguardBackend.hpp
Go to the documentation of this file.
1/*
2 * BastionGuard™
3 * Copyright (C) 2025–2026 Calogero Scarnà
4 *
5 * GPL v3. BastionGuard™ is a trademark of Calogero Scarnà.
6 */
7
8#pragma once
9
10#include <string>
11#include <vector>
12#include <optional>
13#include <cstdint>
14
15namespace BastionGuard {
16
17// Coppia di chiavi WireGuard del client.
18struct WgKeyPair {
19 std::string private_key;
20 std::string public_key;
21};
22
23// Parametri di un peer (lato server) come letti dal .conf.
24struct WgPeer {
25 std::string public_key;
26 std::string preshared_key; // opzionale
27 std::string endpoint; // host:port
28 std::string allowed_ips; // "0.0.0.0/0, ::/0" tipico
29 std::string persistent_keepalive; // numero in secondi (stringa)
30};
31
32// Specifica completa di un tunnel, ottenuta dal parser di un .conf.
33// È l'unica "fonte di verità": niente file in /etc/wireguard/.
35 // [Interface]
36 std::string private_key;
37 std::vector<std::string> addresses; // es. {"10.104.3.74/32"}
38 std::vector<std::string> dns; // es. {"1.1.1.1","8.8.8.8"}
39 std::string listen_port; // opzionale, lato client di solito vuoto
40 int mtu = 0; // 0 = default
41
42 // [Peer] (uno o più)
43 std::vector<WgPeer> peers;
44
45 bool valid() const {
46 return !private_key.empty() && !addresses.empty() && !peers.empty()
47 && !peers[0].public_key.empty() && !peers[0].endpoint.empty();
48 }
49};
50
51// Stato sintetico dell'interfaccia WireGuard.
52struct WgStatus {
53 bool up = false;
54 std::string interface;
55 std::string endpoint;
56 std::string last_handshake;
57 std::uint64_t rx_bytes = 0;
58 std::uint64_t tx_bytes = 0;
59};
60
61// Parametri opzionali per costruire una WgTunnelSpec dalla UI "Configurazione".
63 std::string private_key;
64 std::string address;
65 std::string dns;
66 std::string listen_port;
67 std::string server_public_key;
68 std::string endpoint;
69 std::string allowed_ips = "0.0.0.0/0, ::/0";
70 std::string persistent_keepalive = "25";
71};
72
73// Risultato di un'operazione (per la UI).
74struct OpResult {
75 bool ok = false;
76 int exit_code = 0;
77 std::string output;
78};
79
80/*
81 * WireguardBackend
82 * ----------------
83 * Gestione "diretta" del tunnel WireGuard via `ip` + `wg`, SENZA passare per
84 * wg-quick. Vantaggi:
85 * - nessuna dipendenza da resolvconf / systemd-resolved
86 * - nessun script esterno da generare/installare
87 * - nessun PostUp/PostDown con quoting fragile
88 * - DNS gestito direttamente in C++ con backup/ripristino di /etc/resolv.conf
89 *
90 * Stato:
91 * - lo "spec" del tunnel viene caricato in memoria (load_from_conf/from_params)
92 * - connect() applica lo spec all'interfaccia wg0
93 * - disconnect() butta giù tutto e ripristina /etc/resolv.conf
94 */
96public:
97 explicit WireguardBackend(std::string iface = "wg0");
98
99 // Verifica la presenza dei binari richiesti (wg, ip).
100 bool tooling_available(std::string* missing = nullptr) const;
101
102 // --- Configurazione ------------------------------------------------
103 // Carica uno spec da un file .conf WireGuard standard (parser robusto:
104 // gestisce spazi attorno all'=, righe vuote, commenti #/;).
105 bool load_from_conf(const std::string& conf_path, std::string* err = nullptr);
106
107 // Carica uno spec dai campi del form "Configurazione" dell'app.
108 bool load_from_params(const WgConfigParams& p, std::string* err = nullptr);
109
110 // True se uno spec è caricato.
111 bool has_spec() const { return spec_.valid(); }
112
113 // Endpoint del primo peer come da configurazione caricata (host:port),
114 // utile per la UI quando `wg show` non è leggibile senza privilegi.
115 std::string configured_endpoint() const {
116 return spec_.peers.empty() ? std::string{} : spec_.peers[0].endpoint;
117 }
118
119 // --- Chiavi ---------------------------------------------------------
120 std::optional<WgKeyPair> generate_keys() const;
121
122 // --- Connect / Disconnect ------------------------------------------
123 // Porta su il tunnel usando lo spec caricato.
125 // Butta giù il tunnel e ripristina /etc/resolv.conf.
127
128 // --- Stato ----------------------------------------------------------
129 WgStatus status() const;
130 std::optional<std::string> public_ip() const;
131
132 // --- Kill-switch ---------------------------------------------------
135 bool killswitch_active() const;
136
137 const std::string& interface_name() const { return iface_; }
138
139private:
140 std::string iface_;
142
143 // Esegue argv catturando output. Se `privileged` antepone pkexec.
144 OpResult run(const std::vector<std::string>& argv, bool privileged) const;
145
146 // Come run(), ma scrive `stdin_data` sullo standard input del processo.
147 OpResult run_with_stdin(const std::vector<std::string>& argv,
148 const std::string& stdin_data,
149 bool privileged) const;
150
151 // Costruisce il testo "wg setconf"-compatibile dallo spec (solo PrivateKey
152 // e Peer; niente Address/DNS che `wg` non capisce).
153 std::string build_wg_setconf_text() const;
154};
155
156} // namespace BastionGuard
OpResult run(const std::vector< std::string > &argv, bool privileged) const
std::string configured_endpoint() const
bool load_from_conf(const std::string &conf_path, std::string *err=nullptr)
WireguardBackend(std::string iface="wg0")
OpResult run_with_stdin(const std::vector< std::string > &argv, const std::string &stdin_data, bool privileged) const
bool load_from_params(const WgConfigParams &p, std::string *err=nullptr)
bool tooling_available(std::string *missing=nullptr) const
std::optional< WgKeyPair > generate_keys() const
std::optional< std::string > public_ip() const
const std::string & interface_name() const
std::string build_wg_setconf_text() const
std::vector< WgPeer > peers
std::vector< std::string > dns
std::vector< std::string > addresses