Skip to content
API Documentation
BastionGuard™
bsc::ui_util::GeoResolver Class Reference

#include <GeoResolver.hpp>

Public Types

using ResolvedCallback = std::function<void(const std::string& ip, const GeoEntry&)>

Public Member Functions

 GeoResolver (const GeoResolver &)=delete
GeoResolver & operator= (const GeoResolver &)=delete
std::optional< GeoEntry > resolve (const std::string &ip)
std::optional< GeoEntry > resolve_self ()
void on_resolved (ResolvedCallback cb)
void stop ()

Static Public Member Functions

static GeoResolver & instance ()

Private Member Functions

 GeoResolver ()
 ~GeoResolver ()
void worker_loop ()
std::optional< GeoEntry > fetch_from_ipapi (const std::string &ip)

Static Private Member Functions

static bool is_private_ip (const std::string &ip)

Private Attributes

std::mutex mu_
std::condition_variable cv_
std::atomic_bool running_ {true}
std::queue< std::string > queue_
std::unordered_set< std::string > in_flight_
std::unordered_map< std::string, GeoEntry > cache_
std::vector< ResolvedCallback > callbacks_
std::thread worker_
std::chrono::steady_clock::time_point last_request_ {}

Detailed Description

Service singleton che risolve IP -> GeoEntry. Ha un worker thread che processa una coda di lookup; la UI si iscrive via on_resolved(callback) per ricevere i risultati mano mano che arrivano.

Definition at line 51 of file GeoResolver.hpp.

Member Typedef Documentation

◆ ResolvedCallback

using bsc::ui_util::GeoResolver::ResolvedCallback = std::function<void(const std::string& ip, const GeoEntry&)>

Definition at line 53 of file GeoResolver.hpp.

Constructor & Destructor Documentation

◆ GeoResolver() [1/2]

bsc::ui_util::GeoResolver::GeoResolver ( const GeoResolver & )
delete

References GeoResolver().

Referenced by GeoResolver(), instance(), and operator=().

◆ GeoResolver() [2/2]

bsc::ui_util::GeoResolver::GeoResolver ( )
private

Definition at line 82 of file GeoResolver.cpp.

83{
84 worker_ = std::thread([this]() { worker_loop(); });
85}

References worker_, and worker_loop().

◆ ~GeoResolver()

bsc::ui_util::GeoResolver::~GeoResolver ( )
private

Definition at line 87 of file GeoResolver.cpp.

References stop().

Member Function Documentation

◆ fetch_from_ipapi()

std::optional< GeoEntry > bsc::ui_util::GeoResolver::fetch_from_ipapi ( const std::string & ip)
private

Definition at line 174 of file GeoResolver.cpp.

174 {
175 using namespace std::chrono;
176 // Rate-limit
177 const auto now = steady_clock::now();
178 const auto since = now - last_request_;
179 if (since < kMinInterval) std::this_thread::sleep_for(kMinInterval - since);
180 last_request_ = steady_clock::now();
181
182 // ip-api.com REST API (http, no TLS per semplicita' e perche' il
183 // free tier e' comunque solo http)
184 // Fields mask: https://ip-api.com/docs/api:json
185 const std::string path = "/json/" + ip +
186 "?fields=status,countryCode,country,regionName,city,lat,lon,isp,as";
187
188 const auto body = http_get("ip-api.com", path, milliseconds(2000));
189 if (body.empty()) return std::nullopt;
190
191 try {
192 auto j = nlohmann::json::parse(body);
193 if (j.value("status", std::string{}) != "success") return std::nullopt;
194
195 GeoEntry e;
196 e.country_code = j.value("countryCode", std::string{});
197 e.country_name = j.value("country", std::string{});
198 e.region = j.value("regionName", std::string{});
199 e.city = j.value("city", std::string{});
200 e.isp = j.value("isp", std::string{});
201 e.asn = j.value("as", std::string{});
202 e.lat = j.value("lat", 0.0);
203 e.lon = j.value("lon", 0.0);
204 e.fetched_at = steady_clock::now();
205 return e;
206 } catch (...) {
207 return std::nullopt;
208 }
209}
std::chrono::steady_clock::time_point last_request_
std::string http_get(const std::string &host, const std::string &path, std::chrono::milliseconds timeout)

References bsc::ui_util::GeoEntry::asn, bsc::ui_util::GeoEntry::city, bsc::ui_util::GeoEntry::country_code, bsc::ui_util::GeoEntry::country_name, bsc::ui_util::GeoEntry::fetched_at, bsc::ui_util::GeoEntry::isp, last_request_, bsc::ui_util::GeoEntry::lat, bsc::ui_util::GeoEntry::lon, and bsc::ui_util::GeoEntry::region.

Referenced by operator=(), and worker_loop().

◆ instance()

GeoResolver & bsc::ui_util::GeoResolver::instance ( )
static

Definition at line 77 of file GeoResolver.cpp.

77 {
78 static GeoResolver inst;
79 return inst;
80}
GeoResolver(const GeoResolver &)=delete

References GeoResolver().

Referenced by NetworkPage::NetworkPage(), NetworkPage::noteConnection(), and NetworkPage::requestSelfLocation().

◆ is_private_ip()

bool bsc::ui_util::GeoResolver::is_private_ip ( const std::string & ip)
staticprivate

Definition at line 95 of file GeoResolver.cpp.

95 {
96 if (ip.empty()) return true;
97 // IPv4 privati: 10/8, 172.16/12, 192.168/16, 127/8, 169.254/16
98 in_addr a4{};
99 if (inet_pton(AF_INET, ip.c_str(), &a4) == 1) {
100 const std::uint32_t h = ntohl(a4.s_addr);
101 if ((h & 0xFF000000) == 0x0A000000) return true; // 10.0.0.0/8
102 if ((h & 0xFFF00000) == 0xAC100000) return true; // 172.16.0.0/12
103 if ((h & 0xFFFF0000) == 0xC0A80000) return true; // 192.168.0.0/16
104 if ((h & 0xFF000000) == 0x7F000000) return true; // 127.0.0.0/8
105 if ((h & 0xFFFF0000) == 0xA9FE0000) return true; // 169.254/16
106 return false;
107 }
108 // IPv6: fe80::/10 link-local, fc00::/7 ULA, ::1 loopback
109 in6_addr a6{};
110 if (inet_pton(AF_INET6, ip.c_str(), &a6) == 1) {
111 if ((a6.s6_addr[0] & 0xFE) == 0xFC) return true; // fc00::/7
112 if (a6.s6_addr[0] == 0xFE && (a6.s6_addr[1] & 0xC0) == 0x80) return true;
113 bool is_loopback = (a6.s6_addr[15] == 1);
114 for (int i = 0; i < 15 && is_loopback; ++i)
115 if (a6.s6_addr[i] != 0) is_loopback = false;
116 if (is_loopback) return true;
117 }
118 return false;
119}
#define AF_INET
Definition bsc_ebpf.c:56
#define AF_INET6
Definition bsc_ebpf.c:57

References AF_INET, and AF_INET6.

Referenced by operator=(), and resolve().

◆ on_resolved()

void bsc::ui_util::GeoResolver::on_resolved ( ResolvedCallback cb)

Registra un callback per i risultati asincroni. Thread-safe.

Definition at line 169 of file GeoResolver.cpp.

169 {
170 std::lock_guard lk(mu_);
171 callbacks_.push_back(std::move(cb));
172}
std::vector< ResolvedCallback > callbacks_

References callbacks_, and mu_.

Referenced by NetworkPage::NetworkPage(), and operator=().

◆ operator=()

GeoResolver & bsc::ui_util::GeoResolver::operator= ( const GeoResolver & )
delete

◆ resolve()

std::optional< GeoEntry > bsc::ui_util::GeoResolver::resolve ( const std::string & ip)

Se l'IP e' gia' in cache ritorna subito la GeoEntry. Altrimenti ritorna nullopt e mette l'IP in coda: il callback registrato via on_resolved sara' chiamato quando il lookup completa.

Gli IP privati/loopback/link-local non vengono mai risolti (ritorno un GeoEntry "locale" con country_code = "" e lat/lon = 0).

Definition at line 121 of file GeoResolver.cpp.

121 {
122 if (ip.empty() || is_private_ip(ip)) {
123 GeoEntry local;
124 local.country_code = "";
125 local.country_name = "Locale";
126 local.fetched_at = std::chrono::steady_clock::now();
127 return local;
128 }
129
130 const auto now = std::chrono::steady_clock::now();
131 {
132 std::lock_guard lk(mu_);
133 auto it = cache_.find(ip);
134 if (it != cache_.end()) {
135 if (now - it->second.fetched_at < kCacheTtl) return it->second;
136 cache_.erase(it);
137 }
138 if (in_flight_.count(ip)) return std::nullopt; // gia' in coda
139 in_flight_.insert(ip);
140 queue_.push(ip);
141 }
142 cv_.notify_one();
143 return std::nullopt;
144}
static bool is_private_ip(const std::string &ip)
std::condition_variable cv_
std::unordered_map< std::string, GeoEntry > cache_
std::queue< std::string > queue_
std::unordered_set< std::string > in_flight_

References cache_, bsc::ui_util::GeoEntry::country_code, bsc::ui_util::GeoEntry::country_name, cv_, bsc::ui_util::GeoEntry::fetched_at, in_flight_, is_private_ip(), mu_, and queue_.

Referenced by operator=().

◆ resolve_self()

std::optional< GeoEntry > bsc::ui_util::GeoResolver::resolve_self ( )

Risolve l'IP pubblico del PC locale e la sua geolocalizzazione. Chiamando ip-api.com senza IP, il servizio geolocalizza il chiamante. Il risultato viene cached come qualsiasi altro IP, sotto la chiave speciale "__self__".

Ritorna subito la cache se presente, altrimenti mette in coda e ritorna nullopt. Il callback on_resolved() sara' chiamato con ip == "__self__" quando la risoluzione completa.

Definition at line 146 of file GeoResolver.cpp.

146 {
147 // Chiave speciale per la posizione del PC locale. Il worker
148 // vedendo "__self__" in coda chiama fetch_from_ipapi("") — ip-api
149 // interpreta la richiesta senza IP come "geolocalizza il chiamante"
150 // dall'IP pubblico dal quale arriva la connessione.
151 const std::string kSelfKey = "__self__";
152
153 const auto now = std::chrono::steady_clock::now();
154 {
155 std::lock_guard lk(mu_);
156 auto it = cache_.find(kSelfKey);
157 if (it != cache_.end()) {
158 if (now - it->second.fetched_at < kCacheTtl) return it->second;
159 cache_.erase(it);
160 }
161 if (in_flight_.count(kSelfKey)) return std::nullopt;
162 in_flight_.insert(kSelfKey);
163 queue_.push(kSelfKey);
164 }
165 cv_.notify_one();
166 return std::nullopt;
167}

References cache_, cv_, in_flight_, mu_, and queue_.

Referenced by operator=().

◆ stop()

void bsc::ui_util::GeoResolver::stop ( )

Shutdown ordinato del worker thread.

Definition at line 89 of file GeoResolver.cpp.

89 {
90 running_ = false;
91 cv_.notify_all();
92 if (worker_.joinable()) worker_.join();
93}
std::atomic_bool running_

References cv_, running_, and worker_.

Referenced by operator=(), and ~GeoResolver().

◆ worker_loop()

void bsc::ui_util::GeoResolver::worker_loop ( )
private

Definition at line 211 of file GeoResolver.cpp.

211 {
212 while (running_) {
213 std::string ip;
214 {
215 std::unique_lock lk(mu_);
216 cv_.wait(lk, [this]() { return !running_ || !queue_.empty(); });
217 if (!running_) return;
218 ip = queue_.front();
219 queue_.pop();
220 }
221
222 // "__self__" = richiesta speciale per il PC locale: si chiama
223 // ip-api.com senza specificare IP, il servizio geolocalizza il
224 // chiamante dall'IP sorgente della richiesta HTTP.
225 const bool is_self = (ip == "__self__");
226 auto maybe = fetch_from_ipapi(is_self ? std::string{} : ip);
227
228 std::vector<ResolvedCallback> cbs_snapshot;
229 GeoEntry entry;
230 bool have_entry = false;
231
232 {
233 std::lock_guard lk(mu_);
234 in_flight_.erase(ip);
235 if (maybe) {
236 cache_[ip] = *maybe;
237 entry = *maybe;
238 have_entry = true;
239 }
240 cbs_snapshot = callbacks_;
241 }
242
243 if (have_entry) {
244 for (auto& cb : cbs_snapshot) {
245 try { cb(ip, entry); } catch (...) {}
246 }
247 }
248 }
249}
std::optional< GeoEntry > fetch_from_ipapi(const std::string &ip)

References cache_, callbacks_, cv_, fetch_from_ipapi(), in_flight_, mu_, queue_, and running_.

Referenced by GeoResolver(), and operator=().

Member Data Documentation

◆ cache_

std::unordered_map<std::string, GeoEntry> bsc::ui_util::GeoResolver::cache_
private

Definition at line 101 of file GeoResolver.hpp.

Referenced by resolve(), resolve_self(), and worker_loop().

◆ callbacks_

std::vector<ResolvedCallback> bsc::ui_util::GeoResolver::callbacks_
private

Definition at line 102 of file GeoResolver.hpp.

Referenced by on_resolved(), and worker_loop().

◆ cv_

std::condition_variable bsc::ui_util::GeoResolver::cv_
private

Definition at line 97 of file GeoResolver.hpp.

Referenced by resolve(), resolve_self(), stop(), and worker_loop().

◆ in_flight_

std::unordered_set<std::string> bsc::ui_util::GeoResolver::in_flight_
private

Definition at line 100 of file GeoResolver.hpp.

Referenced by resolve(), resolve_self(), and worker_loop().

◆ last_request_

std::chrono::steady_clock::time_point bsc::ui_util::GeoResolver::last_request_ {}
private

Definition at line 106 of file GeoResolver.hpp.

Referenced by fetch_from_ipapi().

◆ mu_

std::mutex bsc::ui_util::GeoResolver::mu_
private

Definition at line 96 of file GeoResolver.hpp.

Referenced by on_resolved(), resolve(), resolve_self(), and worker_loop().

◆ queue_

std::queue<std::string> bsc::ui_util::GeoResolver::queue_
private

Definition at line 99 of file GeoResolver.hpp.

Referenced by resolve(), resolve_self(), and worker_loop().

◆ running_

std::atomic_bool bsc::ui_util::GeoResolver::running_ {true}
private

Definition at line 98 of file GeoResolver.hpp.

Referenced by stop(), and worker_loop().

◆ worker_

std::thread bsc::ui_util::GeoResolver::worker_
private

Definition at line 103 of file GeoResolver.hpp.

Referenced by GeoResolver(), and stop().


The documentation for this class was generated from the following files:
  • BastionGuard/thirdparty/bastionguard-secure-connection/ui/src/util/GeoResolver.hpp
  • BastionGuard/thirdparty/bastionguard-secure-connection/ui/src/util/GeoResolver.cpp