Skip to content

Commit

Permalink
full rename and reviews from Sadies
Browse files Browse the repository at this point in the history
  • Loading branch information
revrsefr committed Jan 25, 2025
1 parent 44b9457 commit 9ffb776
Showing 1 changed file with 54 additions and 39 deletions.
93 changes: 54 additions & 39 deletions 4/‎m_geomaxlite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
*/

/// $ModAuthor: reverse <[email protected]>
/// $ModDesc: Adds city and country information to WHOIS using local MaxMind database and with it's own usermode +y.
/// $ModConfig: <geolite dbpath="path/geodata/GeoLite2-City.mmdb">
/// $ModDesc: Adds city and country information to WHOIS using a local MaxMind GeoLite2 database with user mode +y.
/// $ModConfig: <geomaxlite dbpath="path/geodata/GeoLite2-City.mmdb">
/// $ModDepends: core 4

/// $LinkerFlags: -lmaxminddb
Expand All @@ -34,40 +34,45 @@
#include "extension.h"
#include <maxminddb.h>

class GeoLiteMode final : public SimpleUserMode
{
public:
GeoLiteMode(Module* mod)
: SimpleUserMode(mod, "geolite", 'y', false)
{
}
};

class ModuleWhoisGeoLite final : public Module, public Whois::EventListener
class ModuleGeoMaxLite final
: public Module
, public Whois::EventListener
{
private:
MMDB_s mmdb;
std::string dbpath;
// MaxMind DB handle
MMDB_s mmdb;

// Path to the MaxMind database file
std::string dbpath;

// Extension item to store a user's city/country info
StringExtItem country_item;
GeoLiteMode geolite_mode;

// +y user mode for enabling GeoMaxLite lookups
SimpleUserMode geomaxlite_mode;

public:
ModuleWhoisGeoLite()
: Module(VF_OPTCOMMON, "Adds city and country information to WHOIS using the MaxMind database.")
ModuleGeoMaxLite()
: Module(VF_OPTCOMMON, "Adds city and country information to WHOIS using a local MaxMind GeoLite2 database.")
, Whois::EventListener(this)
, country_item(this, "geo-lite-country", ExtensionType::USER, true) // Sync across servers
, geolite_mode(this)
, country_item(this, "geomaxlite-country", ExtensionType::USER, true)
, geomaxlite_mode(this, "geomaxlite", 'y', false)
{
}

void ReadConfig(ConfigStatus& status) override
{
auto& tag = ServerInstance->Config->ConfValue("geolite");
dbpath = ServerInstance->Config->Paths.PrependConfig(tag->getString("dbpath", "data/GeoLite2-City.mmdb"));
// Read the <geomaxlite> block from the config
auto& tag = ServerInstance->Config->ConfValue("geomaxlite");
dbpath = ServerInstance->Config->Paths.PrependConfig(
tag->getString("dbpath", "data/GeoLite2-City.mmdb"));

int status_open = MMDB_open(dbpath.c_str(), MMDB_MODE_MMAP, &mmdb);
if (status_open != MMDB_SUCCESS) {
std::string error_msg = "GeoLite2: Failed to open GeoLite2 database: " + std::string(MMDB_strerror(status_open));
if (status_open != MMDB_SUCCESS)
{
// If the database can't be opened, throw a module exception
std::string error_msg = "GeoMaxLite: Failed to open GeoLite2 database: "
+ std::string(MMDB_strerror(status_open));
throw ModuleException(this, error_msg.c_str());
}
}
Expand All @@ -76,21 +81,26 @@ class ModuleWhoisGeoLite final : public Module, public Whois::EventListener
{
User* target = whois.GetTarget();

// Check if the target user has +y mode set
if (!target->IsModeSet(geolite_mode))
// Only display city/country data if the target user has +y (geomaxlite) set
if (!target->IsModeSet(geomaxlite_mode))
return;

const std::string* info = country_item.Get(target);
if (info && !info->empty()) {
if (info && !info->empty())
{
whois.SendLine(RPL_WHOISSPECIAL, "is connecting from " + *info);
} else {
}
else
{
whois.SendLine(RPL_WHOISSPECIAL, "City: Unknown, Country: Unknown");
}
}

void OnChangeRemoteAddress(LocalUser* user) override
{
if (!user->client_sa.is_ip()) {
// If the address is not an IP, unset any stored geo info
if (!user->client_sa.is_ip())
{
country_item.Unset(user);
return;
}
Expand All @@ -99,32 +109,37 @@ class ModuleWhoisGeoLite final : public Module, public Whois::EventListener
const struct sockaddr* addr = &user->client_sa.sa;
MMDB_lookup_result_s result = MMDB_lookup_sockaddr(&mmdb, addr, &gai_error);

if (gai_error != 0 || !result.found_entry) {
// Unset if we got a lookup error or didn't find anything
if (gai_error != 0 || !result.found_entry)
{
country_item.Unset(user);
return;
}

// Fetch city and country strings (in English)
MMDB_entry_data_s city_data = {};
MMDB_entry_data_s country_data = {};

int status_city = MMDB_get_value(&result.entry, &city_data, "city", "names", "en", nullptr);
int status_country = MMDB_get_value(&result.entry, &country_data, "country", "names", "en", nullptr);

std::string city = (status_city == MMDB_SUCCESS && city_data.has_data) ? std::string(city_data.utf8_string, city_data.data_size) : "Unknown";
std::string country = (status_country == MMDB_SUCCESS && country_data.has_data) ? std::string(country_data.utf8_string, country_data.data_size) : "Unknown";
std::string city = (status_city == MMDB_SUCCESS && city_data.has_data)
? std::string(city_data.utf8_string, city_data.data_size)
: "Unknown";

country_item.Set(user, "City: " + city + ", Country: " + country);
}
std::string country = (status_country == MMDB_SUCCESS && country_data.has_data)
? std::string(country_data.utf8_string, country_data.data_size)
: "Unknown";

void OnUserQuit(User* user, const std::string& message, const std::string& opermessage) override
{
if (user->IsModeSet(geolite_mode))
country_item.Unset(user);
// Store
country_item.Set(user, "City: " + city + ", Country: " + country);
}

~ModuleWhoisGeoLite() override
~ModuleGeoMaxLite() override
{
// Close the MaxMind DB on unload
MMDB_close(&mmdb);
}
};

MODULE_INIT(ModuleWhoisGeoLite)
MODULE_INIT(ModuleGeoMaxLite)

0 comments on commit 9ffb776

Please sign in to comment.