Skip to content
API Documentation
BastionGuard™
BastionGuard Namespace Reference

Namespaces

namespace  Activation
namespace  nativehost
namespace  Platform
namespace  RootGuard
namespace  wizard

Classes

class  DnsmasqBackend
struct  OpResult
struct  WgConfigParams
struct  WgKeyPair
struct  WgPeer
struct  WgStatus
struct  WgTunnelSpec
class  WireguardBackend

Typedefs

using AliveFlag = std::shared_ptr<std::atomic<bool>>

Functions

AliveFlag make_alive_flag ()
template<typename Fn>
void if_alive (const AliveFlag &alive, Fn &&fn)
static void load_list_file (const std::string &path, std::vector< std::string > &out, bool is_blacklist)
static void ensure_loaded (const std::string &bl, const std::string &wl)
static bool in_path_ (const char *bin)
static std::string strip_ (std::string s)
static std::vector< std::string > split_csv_ (const std::string &s)
static bool parse_uint_range_ (const std::string &s, unsigned min, unsigned max)
static bool valid_wg_key_ (const std::string &s)
static bool valid_ip_ (const std::string &s)
static bool valid_cidr_ (const std::string &s)
static bool valid_hostname_ (const std::string &host)
static bool valid_endpoint_ (const std::string &endpoint)
static bool valid_iface_ (const std::string &iface)
static bool validate_spec_ (const WgTunnelSpec &sp, std::string *err)
static bool needs_default_route_ (const WgTunnelSpec &sp)

Variables

static std::mutex g_mutex
static std::atomic< bool > g_loaded {false}
static std::vector< std::string > g_blacklist
static std::vector< std::string > g_whitelist
static const char * kKsTable = "bastionguard_ks"

Typedef Documentation

◆ AliveFlag

using BastionGuard::AliveFlag = std::shared_ptr<std::atomic<bool>>

Definition at line 65 of file LifetimeGuard.hpp.

Function Documentation

◆ ensure_loaded()

void BastionGuard::ensure_loaded ( const std::string & bl,
const std::string & wl )
static

Definition at line 79 of file dnsmasq_backend.cpp.

80{
81 if (g_loaded.load()) return;
82
83 std::lock_guard<std::mutex> lock(g_mutex);
84 if (g_loaded) return;
85
86 load_list_file(bl, g_blacklist, true);
87 load_list_file(wl, g_whitelist, false);
88
89 g_loaded = true;
90}
static void load_list_file(const std::string &path, std::vector< std::string > &out, bool is_blacklist)
static std::mutex g_mutex
static std::vector< std::string > g_whitelist
static std::vector< std::string > g_blacklist
static std::atomic< bool > g_loaded

References ensure_loaded(), g_blacklist, g_loaded, g_mutex, g_whitelist, and load_list_file().

Referenced by BastionGuard::DnsmasqBackend::add_to_blacklist(), BastionGuard::DnsmasqBackend::add_to_whitelist(), ensure_loaded(), BastionGuard::DnsmasqBackend::remove_from_blacklist(), and BastionGuard::DnsmasqBackend::remove_from_whitelist().

◆ if_alive()

◆ in_path_()

bool BastionGuard::in_path_ ( const char * bin)
static

Definition at line 109 of file WireguardBackend.cpp.

109 {
110 const char* p = std::getenv("PATH");
111 if (!p) p = "/usr/sbin:/usr/bin:/sbin:/bin";
112 std::string paths(p);
113 size_t start = 0;
114 while (start <= paths.size()) {
115 size_t end = paths.find(':', start);
116 std::string dir = paths.substr(start,
117 end == std::string::npos ? std::string::npos : end - start);
118 if (!dir.empty() && ::access((dir + "/" + bin).c_str(), X_OK) == 0) return true;
119 if (end == std::string::npos) break;
120 start = end + 1;
121 }
122 return false;
123}

References in_path_().

Referenced by in_path_(), and BastionGuard::WireguardBackend::tooling_available().

◆ load_list_file()

void BastionGuard::load_list_file ( const std::string & path,
std::vector< std::string > & out,
bool is_blacklist )
static

Definition at line 52 of file dnsmasq_backend.cpp.

55{
56 out.clear();
57
58 if (!fs::exists(path)) return;
59
60 std::ifstream ifs(path);
61 std::string line;
62
63 while (std::getline(ifs, line)) {
64 if (line.empty()) continue;
65
66 if (is_blacklist) {
67 auto a = line.find("address=/");
68 if (a != std::string::npos) {
69 auto b = line.find('/', a + 9);
70 if (b != std::string::npos)
71 out.push_back(line.substr(a + 9, b - (a + 9)));
72 }
73 } else {
74 out.push_back(line);
75 }
76 }
77}

References load_list_file().

Referenced by ensure_loaded(), and load_list_file().

◆ make_alive_flag()

AliveFlag BastionGuard::make_alive_flag ( )
inline

Definition at line 67 of file LifetimeGuard.hpp.

67 {
68 return std::make_shared<std::atomic<bool>>(true);
69}

References make_alive_flag().

Referenced by make_alive_flag().

◆ needs_default_route_()

bool BastionGuard::needs_default_route_ ( const WgTunnelSpec & sp)
static

Definition at line 394 of file WireguardBackend.cpp.

394 {
395 for (const auto& p : sp.peers)
396 for (const auto& a : split_csv_(p.allowed_ips))
397 if (a == "0.0.0.0/0" || a == "::/0") return true;
398 return false;
399}
static std::vector< std::string > split_csv_(const std::string &s)
std::vector< WgPeer > peers

References needs_default_route_(), BastionGuard::WgTunnelSpec::peers, and split_csv_().

Referenced by BastionGuard::WireguardBackend::connect(), and needs_default_route_().

◆ parse_uint_range_()

bool BastionGuard::parse_uint_range_ ( const std::string & s,
unsigned min,
unsigned max )
static

Definition at line 151 of file WireguardBackend.cpp.

151 {
152 if (s.empty() || s.find_first_not_of("0123456789") != std::string::npos)
153 return false;
154 try {
155 unsigned long v = std::stoul(s);
156 return v >= min && v <= max;
157 } catch (...) {
158 return false;
159 }
160}

References parse_uint_range_().

Referenced by parse_uint_range_(), valid_cidr_(), valid_endpoint_(), and validate_spec_().

◆ split_csv_()

std::vector< std::string > BastionGuard::split_csv_ ( const std::string & s)
static

Definition at line 141 of file WireguardBackend.cpp.

141 {
142 std::vector<std::string> out;
143 std::string tok; std::istringstream iss(s);
144 while (std::getline(iss, tok, ',')) {
145 std::string t = strip_(tok);
146 if (!t.empty()) out.push_back(t);
147 }
148 return out;
149}
static std::string strip_(std::string s)

References split_csv_(), and strip_().

Referenced by BastionGuard::WireguardBackend::connect(), BastionGuard::WireguardBackend::load_from_conf(), BastionGuard::WireguardBackend::load_from_params(), needs_default_route_(), split_csv_(), and validate_spec_().

◆ strip_()

std::string BastionGuard::strip_ ( std::string s)
static

Definition at line 134 of file WireguardBackend.cpp.

134 {
135 size_t a = s.find_first_not_of(" \t\r\n");
136 size_t b = s.find_last_not_of(" \t\r\n");
137 if (a == std::string::npos) return {};
138 return s.substr(a, b - a + 1);
139}

References strip_().

Referenced by BastionGuard::WireguardBackend::generate_keys(), BastionGuard::WireguardBackend::load_from_conf(), BastionGuard::WireguardBackend::public_ip(), split_csv_(), BastionGuard::WireguardBackend::status(), and strip_().

◆ valid_cidr_()

bool BastionGuard::valid_cidr_ ( const std::string & s)
static

Definition at line 175 of file WireguardBackend.cpp.

175 {
176 const auto slash = s.rfind('/');
177 if (slash == std::string::npos || slash == 0 || slash + 1 >= s.size())
178 return false;
179 const std::string ip = s.substr(0, slash);
180 const std::string prefix = s.substr(slash + 1);
181 if (!parse_uint_range_(prefix, 0, 128)) return false;
182
183 struct in_addr a4 {};
184 if (::inet_pton(AF_INET, ip.c_str(), &a4) == 1)
185 return std::stoul(prefix) <= 32;
186 struct in6_addr a6 {};
187 if (::inet_pton(AF_INET6, ip.c_str(), &a6) == 1)
188 return std::stoul(prefix) <= 128;
189 return false;
190}
#define AF_INET
Definition bsc_ebpf.c:56
#define AF_INET6
Definition bsc_ebpf.c:57
static bool parse_uint_range_(const std::string &s, unsigned min, unsigned max)

References AF_INET, AF_INET6, parse_uint_range_(), and valid_cidr_().

Referenced by valid_cidr_(), and validate_spec_().

◆ valid_endpoint_()

bool BastionGuard::valid_endpoint_ ( const std::string & endpoint)
static

Definition at line 207 of file WireguardBackend.cpp.

207 {
208 std::string host, port;
209 if (!endpoint.empty() && endpoint.front() == '[') {
210 const auto close = endpoint.find(']');
211 if (close == std::string::npos || close + 1 >= endpoint.size() || endpoint[close + 1] != ':')
212 return false;
213 host = endpoint.substr(1, close - 1);
214 port = endpoint.substr(close + 2);
215 struct in6_addr a6 {};
216 if (::inet_pton(AF_INET6, host.c_str(), &a6) != 1) return false;
217 } else {
218 const auto colon = endpoint.rfind(':');
219 if (colon == std::string::npos || colon == 0 || colon + 1 >= endpoint.size())
220 return false;
221 host = endpoint.substr(0, colon);
222 port = endpoint.substr(colon + 1);
223 struct in_addr a4 {};
224 if (::inet_pton(AF_INET, host.c_str(), &a4) != 1 && !valid_hostname_(host))
225 return false;
226 }
227 return parse_uint_range_(port, 1, 65535);
228}
static bool valid_hostname_(const std::string &host)

References AF_INET, AF_INET6, parse_uint_range_(), valid_endpoint_(), and valid_hostname_().

Referenced by valid_endpoint_(), and validate_spec_().

◆ valid_hostname_()

bool BastionGuard::valid_hostname_ ( const std::string & host)
static

Definition at line 192 of file WireguardBackend.cpp.

192 {
193 if (host.empty() || host.size() > 253 || host.front() == '.' || host.back() == '.')
194 return false;
195 static const std::regex re(R"(^[A-Za-z0-9.-]+$)");
196 if (!std::regex_match(host, re) || host.find("..") != std::string::npos)
197 return false;
198 std::istringstream labels(host);
199 std::string label;
200 while (std::getline(labels, label, '.')) {
201 if (label.empty() || label.size() > 63 || label.front() == '-' || label.back() == '-')
202 return false;
203 }
204 return true;
205}

References valid_hostname_().

Referenced by valid_endpoint_(), and valid_hostname_().

◆ valid_iface_()

bool BastionGuard::valid_iface_ ( const std::string & iface)
static

Definition at line 230 of file WireguardBackend.cpp.

230 {
231 static const std::regex re(R"(^[A-Za-z0-9_.-]{1,15}$)");
232 return std::regex_match(iface, re);
233}

References valid_iface_().

Referenced by BastionGuard::WireguardBackend::connect(), BastionGuard::WireguardBackend::killswitch_enable(), and valid_iface_().

◆ valid_ip_()

bool BastionGuard::valid_ip_ ( const std::string & s)
static

Definition at line 168 of file WireguardBackend.cpp.

168 {
169 struct in_addr a4 {};
170 struct in6_addr a6 {};
171 return ::inet_pton(AF_INET, s.c_str(), &a4) == 1 ||
172 ::inet_pton(AF_INET6, s.c_str(), &a6) == 1;
173}

References AF_INET, AF_INET6, and valid_ip_().

Referenced by valid_ip_(), and validate_spec_().

◆ valid_wg_key_()

bool BastionGuard::valid_wg_key_ ( const std::string & s)
static

Definition at line 162 of file WireguardBackend.cpp.

162 {
163 // WireGuard keys are 32 bytes encoded as 44-character base64 strings.
164 static const std::regex re(R"(^[A-Za-z0-9+/]{43}=$)");
165 return std::regex_match(s, re);
166}

References valid_wg_key_().

Referenced by valid_wg_key_(), and validate_spec_().

◆ validate_spec_()

bool BastionGuard::validate_spec_ ( const WgTunnelSpec & sp,
std::string * err )
static

Definition at line 235 of file WireguardBackend.cpp.

235 {
236 auto fail = [&](const char* msg) {
237 if (err) *err = msg;
238 return false;
239 };
240 if (!sp.valid()) return fail("Configurazione WireGuard incompleta.");
241 if (!valid_wg_key_(sp.private_key)) return fail("PrivateKey WireGuard non valida.");
242 if (!sp.listen_port.empty() && !parse_uint_range_(sp.listen_port, 1, 65535))
243 return fail("ListenPort non valida.");
244 if (sp.mtu != 0 && (sp.mtu < 576 || sp.mtu > 9000))
245 return fail("MTU fuori intervallo consentito.");
246
247 for (const auto& a : sp.addresses)
248 if (!valid_cidr_(a)) return fail("Address deve essere un IP/CIDR valido.");
249 for (const auto& ns : sp.dns)
250 if (!valid_ip_(ns)) return fail("DNS deve essere un indirizzo IP valido.");
251
252 for (const auto& peer : sp.peers) {
253 if (!valid_wg_key_(peer.public_key)) return fail("PublicKey peer non valida.");
254 if (!peer.preshared_key.empty() && !valid_wg_key_(peer.preshared_key))
255 return fail("PresharedKey non valida.");
256 if (!valid_endpoint_(peer.endpoint)) return fail("Endpoint WireGuard non valido.");
257 for (const auto& cidr : split_csv_(peer.allowed_ips))
258 if (!valid_cidr_(cidr)) return fail("AllowedIPs contiene un CIDR non valido.");
259 if (!peer.persistent_keepalive.empty() &&
260 !parse_uint_range_(peer.persistent_keepalive, 0, 65535))
261 return fail("PersistentKeepalive non valido.");
262 }
263 return true;
264}
static bool valid_ip_(const std::string &s)
static bool valid_cidr_(const std::string &s)
static bool valid_wg_key_(const std::string &s)
static bool valid_endpoint_(const std::string &endpoint)
std::vector< std::string > dns
std::vector< std::string > addresses

References BastionGuard::WgTunnelSpec::addresses, BastionGuard::WgTunnelSpec::dns, BastionGuard::WgTunnelSpec::listen_port, BastionGuard::WgTunnelSpec::mtu, parse_uint_range_(), BastionGuard::WgTunnelSpec::peers, BastionGuard::WgTunnelSpec::private_key, split_csv_(), BastionGuard::WgTunnelSpec::valid(), valid_cidr_(), valid_endpoint_(), valid_ip_(), valid_wg_key_(), and validate_spec_().

Referenced by BastionGuard::WireguardBackend::connect(), BastionGuard::WireguardBackend::load_from_conf(), BastionGuard::WireguardBackend::load_from_params(), and validate_spec_().

Variable Documentation

◆ g_blacklist

std::vector<std::string> BastionGuard::g_blacklist
static

◆ g_loaded

std::atomic<bool> BastionGuard::g_loaded {false}
static

Definition at line 37 of file dnsmasq_backend.cpp.

Referenced by ensure_loaded().

◆ g_mutex

◆ g_whitelist

std::vector<std::string> BastionGuard::g_whitelist
static

◆ kKsTable