-
-
Notifications
You must be signed in to change notification settings - Fork 71
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rename whoisgeolite to geomaxlite and add user mode.
- Loading branch information
Showing
2 changed files
with
146 additions
and
116 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file was deleted.
Oops, something went wrong.