Skip to content

Commit

Permalink
Rename whoisgeolite to geomaxlite and add user mode.
Browse files Browse the repository at this point in the history
  • Loading branch information
revrsefr authored Jan 25, 2025
1 parent 8d287a6 commit e22acb9
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 116 deletions.
146 changes: 146 additions & 0 deletions 4/m_geomaxlite.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/*
* InspIRCd -- Internet Relay Chat Daemon
*
* Copyright (C) 2024 reverse
*
* This file contains a third-party module for InspIRCd. You can
* redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

/// $ModAuthor: reverse <[email protected]>
/// $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

/// $CompilerFlags: find_compiler_flags("libmaxminddb")
/// $LinkerFlags: find_linker_flags("libmaxminddb")

/// $PackageInfo: require_system("alpine") libmaxminddb-dev pkgconf
/// $PackageInfo: require_system("arch") pkgconf libmaxminddb
/// $PackageInfo: require_system("darwin") libmaxminddb pkg-config
/// $PackageInfo: require_system("debian~") libmaxminddb-dev pkg-config
/// $PackageInfo: require_system("rhel~") pkg-config libmaxminddb-devel

#include "inspircd.h"
#include "modules/whois.h"
#include "extension.h"
#include <maxminddb.h>

class ModuleGeoMaxLite final
: public Module
, public Whois::EventListener
{
private:
// 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;

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

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

void ReadConfig(ConfigStatus& status) override
{
// 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)
{
// 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());
}
}

void OnWhois(Whois::Context& whois) override
{
User* target = whois.GetTarget();

// 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())
{
whois.SendLine(RPL_WHOISSPECIAL, "is connecting from " + *info);
}
else
{
whois.SendLine(RPL_WHOISSPECIAL, "City: Unknown, Country: Unknown");
}
}

void OnChangeRemoteAddress(LocalUser* user) override
{
// If the address is not an IP, unset any stored geo info
if (!user->client_sa.is_ip())
{
country_item.Unset(user);
return;
}

int gai_error = 0;
const struct sockaddr* addr = &user->client_sa.sa;
MMDB_lookup_result_s result = MMDB_lookup_sockaddr(&mmdb, addr, &gai_error);

// 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";

// Store
country_item.Set(user, "City: " + city + ", Country: " + country);
}

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

MODULE_INIT(ModuleGeoMaxLite)
116 changes: 0 additions & 116 deletions 4/m_whoisgeolite.cpp

This file was deleted.

0 comments on commit e22acb9

Please sign in to comment.