2008-03-30 09:00:22 +02:00
/**
* vim : set ts = 4 :
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* SourceMod GeoIP Extension
* Copyright ( C ) 2004 - 2008 AlliedModders LLC . All rights reserved .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*
* This program is free software ; you can redistribute it and / or modify it under
* the terms of the GNU General Public License , version 3.0 , as published by the
* Free Software Foundation .
*
* 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/>.
*
* As a special exception , AlliedModders LLC gives you permission to link the
* code of this program ( as well as its derivative works ) to " Half-Life 2, " the
* " Source Engine, " the " SourcePawn JIT, " and any Game MODs that run on software
* by the Valve Corporation . You must obey the GNU General Public License in
* all respects for all other code used . Additionally , AlliedModders LLC grants
* this exception to all derivative works . AlliedModders LLC defines further
* exceptions , found in LICENSE . txt ( as of this writing , version JULY - 31 - 2007 ) ,
* or < http : //www.sourcemod.net/license.php>.
*
* Version : $ Id $
*/
2021-06-30 13:01:12 +02:00
# define _USE_MATH_DEFINES
2009-08-30 09:21:42 +02:00
# include <sourcemod_version.h>
2021-06-30 13:01:12 +02:00
# include <cmath>
2008-03-30 09:00:22 +02:00
# include "extension.h"
2021-06-30 13:01:12 +02:00
# include "geoip_util.h"
2008-03-30 09:00:22 +02:00
2022-06-30 08:22:51 +02:00
// Log a message if the database is older than the set amount of days.
# define DATABASE_MAX_AGE 90
2008-03-30 09:00:22 +02:00
/**
* @ file extension . cpp
* @ brief Implement extension code here .
*/
GeoIP_Extension g_GeoIP ;
2021-06-30 13:01:12 +02:00
MMDB_s mmdb ;
2008-03-30 09:00:22 +02:00
SMEXT_LINK ( & g_GeoIP ) ;
bool GeoIP_Extension : : SDK_OnLoad ( char * error , size_t maxlength , bool late )
{
2021-06-30 13:01:12 +02:00
if ( mmdb . filename ) // Already loaded.
{
return true ;
}
char m_GeoipDir [ PLATFORM_MAX_PATH ] ;
g_pSM - > BuildPath ( Path_SM , m_GeoipDir , sizeof ( m_GeoipDir ) , " configs/geoip " ) ;
bool hasEntry = false ;
IDirectory * dir = libsys - > OpenDirectory ( m_GeoipDir ) ;
if ( dir )
{
while ( dir - > MoreFiles ( ) )
{
if ( dir - > IsEntryFile ( ) )
{
const char * name = dir - > GetEntryName ( ) ;
size_t len = strlen ( name ) ;
if ( len > = 5 & & strcmp ( & name [ len - 5 ] , " .mmdb " ) = = 0 )
{
char database [ PLATFORM_MAX_PATH ] ;
libsys - > PathFormat ( database , sizeof ( database ) , " %s/%s " , m_GeoipDir , name ) ;
int status = MMDB_open ( database , MMDB_MODE_MMAP , & mmdb ) ;
2008-03-30 09:00:22 +02:00
2021-06-30 13:01:12 +02:00
if ( status ! = MMDB_SUCCESS )
{
2022-06-30 08:22:51 +02:00
ke : : SafeSprintf ( error , maxlength , " Failed to open GeoIP2 database %s: %s " , database , MMDB_strerror ( status ) ) ;
2021-06-30 13:01:12 +02:00
libsys - > CloseDirectory ( dir ) ;
return false ;
}
2008-03-30 09:00:22 +02:00
2021-06-30 13:01:12 +02:00
hasEntry = true ;
break ;
}
}
dir - > NextEntry ( ) ;
}
libsys - > CloseDirectory ( dir ) ;
}
if ( ! hasEntry )
2008-03-30 09:00:22 +02:00
{
2021-06-30 13:01:12 +02:00
ke : : SafeStrcpy ( error , maxlength , " Could not find GeoIP2 database. " ) ;
2008-03-30 09:00:22 +02:00
return false ;
}
g_pShareSys - > AddNatives ( myself , geoip_natives ) ;
g_pShareSys - > RegisterLibrary ( myself , " GeoIP " ) ;
2021-06-30 13:01:12 +02:00
char date [ 40 ] ;
const time_t epoch = ( const time_t ) mmdb . metadata . build_epoch ;
strftime ( date , 40 , " %F %T UTC " , gmtime ( & epoch ) ) ;
2022-06-30 08:22:51 +02:00
g_pSM - > LogMessage ( myself , " GeoIP2 database loaded: %s (%s) (%s) " , mmdb . metadata . database_type , date , mmdb . filename ) ;
2021-06-30 13:01:12 +02:00
if ( mmdb . metadata . languages . count > 0 )
{
char buf [ 64 ] ;
for ( size_t i = 0 ; i < mmdb . metadata . languages . count ; i + + )
{
if ( i = = 0 )
{
strcpy ( buf , mmdb . metadata . languages . names [ i ] ) ;
}
else
{
strcat ( buf , " " ) ;
strcat ( buf , mmdb . metadata . languages . names [ i ] ) ;
}
}
g_pSM - > LogMessage ( myself , " GeoIP2 supported languages: %s " , buf ) ;
}
2008-03-30 09:00:22 +02:00
2022-06-30 08:22:51 +02:00
time_t now = time ( NULL ) ;
double days_since_update = difftime ( now , epoch ) / ( 60 * 60 * 24 ) ;
if ( days_since_update > DATABASE_MAX_AGE )
smutils - > LogMessage ( myself , " Your database is older than %u days. You should consider downloading a newer version from e.g. https://dev.maxmind.com/geoip/geolite2-free-geolocation-data " , DATABASE_MAX_AGE ) ;
2008-03-30 09:00:22 +02:00
return true ;
}
void GeoIP_Extension : : SDK_OnUnload ( )
{
2021-06-30 13:01:12 +02:00
MMDB_close ( & mmdb ) ;
2008-03-30 09:00:22 +02:00
}
2009-08-30 10:54:45 +02:00
const char * GeoIP_Extension : : GetExtensionVerString ( )
2009-08-30 09:21:42 +02:00
{
2013-12-30 23:51:00 +01:00
return SOURCEMOD_VERSION ;
2009-08-30 09:21:42 +02:00
}
2009-08-30 10:54:45 +02:00
const char * GeoIP_Extension : : GetExtensionDateString ( )
2009-08-30 09:21:42 +02:00
{
2013-12-30 23:51:00 +01:00
return SOURCEMOD_BUILD_TIME ;
2009-08-30 09:21:42 +02:00
}
2008-03-30 09:00:22 +02:00
/*******************************
* *
* GEOIP NATIVE IMPLEMENTATIONS *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
inline void StripPort ( char * ip )
{
char * tmp = strchr ( ip , ' : ' ) ;
if ( ! tmp )
return ;
* tmp = ' \0 ' ;
}
static cell_t sm_Geoip_Code2 ( IPluginContext * pCtx , const cell_t * params )
{
char * ip ;
pCtx - > LocalToString ( params [ 1 ] , & ip ) ;
StripPort ( ip ) ;
2021-06-30 13:01:12 +02:00
const char * path [ ] = { " country " , " iso_code " , NULL } ;
std : : string str = lookupString ( ip , path ) ;
const char * ccode = str . c_str ( ) ;
2008-03-30 09:00:22 +02:00
2021-06-30 13:01:12 +02:00
pCtx - > StringToLocalUTF8 ( params [ 2 ] , 3 , ccode , NULL ) ;
2008-03-30 09:00:22 +02:00
2021-06-30 13:01:12 +02:00
return ( str . length ( ) ! = 0 ) ? 1 : 0 ;
2008-03-30 09:00:22 +02:00
}
static cell_t sm_Geoip_Code3 ( IPluginContext * pCtx , const cell_t * params )
{
char * ip ;
2021-06-30 13:01:12 +02:00
pCtx - > LocalToString ( params [ 1 ] , & ip ) ;
StripPort ( ip ) ;
const char * path [ ] = { " country " , " iso_code " , NULL } ;
std : : string str = lookupString ( ip , path ) ;
const char * ccode = str . c_str ( ) ;
for ( size_t i = 0 ; i < SM_ARRAYSIZE ( GeoIPCountryCode ) ; i + + )
{
if ( ! strncmp ( ccode , GeoIPCountryCode [ i ] , 2 ) )
{
ccode = GeoIPCountryCode3 [ i ] ;
break ;
}
}
pCtx - > StringToLocalUTF8 ( params [ 2 ] , 4 , ccode , NULL ) ;
2008-03-30 09:00:22 +02:00
2021-06-30 13:01:12 +02:00
return ( str . length ( ) ! = 0 ) ? 1 : 0 ;
}
static cell_t sm_Geoip_RegionCode ( IPluginContext * pCtx , const cell_t * params )
{
char * ip ;
2008-03-30 09:00:22 +02:00
pCtx - > LocalToString ( params [ 1 ] , & ip ) ;
StripPort ( ip ) ;
2021-06-30 13:01:12 +02:00
size_t length = 0 ;
char ccode [ 12 ] = { 0 } ;
const char * pathCountry [ ] = { " country " , " iso_code " , NULL } ;
std : : string countryCode = lookupString ( ip , pathCountry ) ;
if ( countryCode . length ( ) ! = 0 )
{
const char * pathRegion [ ] = { " subdivisions " , " 0 " , " iso_code " , NULL } ;
std : : string regionCode = lookupString ( ip , pathRegion ) ;
2008-03-30 09:00:22 +02:00
2021-06-30 13:01:12 +02:00
length = regionCode . length ( ) ;
if ( length ! = 0 )
{
ke : : SafeSprintf ( ccode , sizeof ( ccode ) , " %s-%s " , countryCode . c_str ( ) , regionCode . c_str ( ) ) ;
}
}
pCtx - > StringToLocalUTF8 ( params [ 2 ] , sizeof ( ccode ) , ccode , NULL ) ;
return ( length ! = 0 ) ? 1 : 0 ;
}
static cell_t sm_Geoip_ContinentCode ( IPluginContext * pCtx , const cell_t * params )
{
char * ip ;
pCtx - > LocalToString ( params [ 1 ] , & ip ) ;
StripPort ( ip ) ;
const char * path [ ] = { " continent " , " code " , NULL } ;
std : : string str = lookupString ( ip , path ) ;
const char * ccode = str . c_str ( ) ;
pCtx - > StringToLocalUTF8 ( params [ 2 ] , 3 , ccode , NULL ) ;
return getContinentId ( ccode ) ;
2008-03-30 09:00:22 +02:00
}
static cell_t sm_Geoip_Country ( IPluginContext * pCtx , const cell_t * params )
{
char * ip ;
2021-06-30 13:01:12 +02:00
pCtx - > LocalToString ( params [ 1 ] , & ip ) ;
StripPort ( ip ) ;
const char * path [ ] = { " country " , " names " , " en " , NULL } ;
std : : string str = lookupString ( ip , path ) ;
const char * ccode = str . c_str ( ) ;
pCtx - > StringToLocalUTF8 ( params [ 2 ] , params [ 3 ] , ccode , NULL ) ;
return ( str . length ( ) ! = 0 ) ? 1 : 0 ;
}
static cell_t sm_Geoip_CountryEx ( IPluginContext * pCtx , const cell_t * params )
{
char * ip ;
pCtx - > LocalToString ( params [ 1 ] , & ip ) ;
StripPort ( ip ) ;
if ( params [ 4 ] > 0 )
{
IGamePlayer * player = playerhelpers - > GetGamePlayer ( params [ 4 ] ) ;
if ( ! player | | ! player - > IsConnected ( ) )
{
return pCtx - > ThrowNativeError ( " Invalid client index %d " , params [ 4 ] ) ;
}
}
const char * path [ ] = { " country " , " names " , getLang ( params [ 4 ] ) , NULL } ;
std : : string str = lookupString ( ip , path ) ;
const char * ccode = str . c_str ( ) ;
pCtx - > StringToLocalUTF8 ( params [ 2 ] , params [ 3 ] , ccode , NULL ) ;
return ( str . length ( ) ! = 0 ) ? 1 : 0 ;
}
static cell_t sm_Geoip_Continent ( IPluginContext * pCtx , const cell_t * params )
{
char * ip ;
pCtx - > LocalToString ( params [ 1 ] , & ip ) ;
StripPort ( ip ) ;
if ( params [ 4 ] > 0 )
{
IGamePlayer * player = playerhelpers - > GetGamePlayer ( params [ 4 ] ) ;
if ( ! player | | ! player - > IsConnected ( ) )
{
return pCtx - > ThrowNativeError ( " Invalid client index %d " , params [ 4 ] ) ;
}
}
const char * path [ ] = { " continent " , " names " , getLang ( params [ 4 ] ) , NULL } ;
std : : string str = lookupString ( ip , path ) ;
const char * ccode = str . c_str ( ) ;
pCtx - > StringToLocalUTF8 ( params [ 2 ] , params [ 3 ] , ccode , NULL ) ;
return ( str . length ( ) ! = 0 ) ? 1 : 0 ;
}
2008-03-30 09:00:22 +02:00
2021-06-30 13:01:12 +02:00
static cell_t sm_Geoip_Region ( IPluginContext * pCtx , const cell_t * params )
{
char * ip ;
2008-03-30 09:00:22 +02:00
pCtx - > LocalToString ( params [ 1 ] , & ip ) ;
StripPort ( ip ) ;
2021-06-30 13:01:12 +02:00
if ( params [ 4 ] > 0 )
{
IGamePlayer * player = playerhelpers - > GetGamePlayer ( params [ 4 ] ) ;
if ( ! player | | ! player - > IsConnected ( ) )
{
return pCtx - > ThrowNativeError ( " Invalid client index %d " , params [ 4 ] ) ;
}
}
const char * path [ ] = { " subdivisions " , " 0 " , " names " , getLang ( params [ 4 ] ) , NULL } ;
std : : string str = lookupString ( ip , path ) ;
const char * ccode = str . c_str ( ) ;
pCtx - > StringToLocalUTF8 ( params [ 2 ] , params [ 3 ] , ccode , NULL ) ;
return ( str . length ( ) ! = 0 ) ? 1 : 0 ;
}
static cell_t sm_Geoip_City ( IPluginContext * pCtx , const cell_t * params )
{
char * ip ;
pCtx - > LocalToString ( params [ 1 ] , & ip ) ;
StripPort ( ip ) ;
if ( params [ 4 ] > 0 )
{
IGamePlayer * player = playerhelpers - > GetGamePlayer ( params [ 4 ] ) ;
if ( ! player | | ! player - > IsConnected ( ) )
{
return pCtx - > ThrowNativeError ( " Invalid client index %d " , params [ 4 ] ) ;
}
}
const char * path [ ] = { " city " , " names " , getLang ( params [ 4 ] ) , NULL } ;
std : : string str = lookupString ( ip , path ) ;
const char * ccode = str . c_str ( ) ;
pCtx - > StringToLocalUTF8 ( params [ 2 ] , params [ 3 ] , ccode , NULL ) ;
return ( str . length ( ) ! = 0 ) ? 1 : 0 ;
}
static cell_t sm_Geoip_Timezone ( IPluginContext * pCtx , const cell_t * params )
{
char * ip ;
pCtx - > LocalToString ( params [ 1 ] , & ip ) ;
StripPort ( ip ) ;
const char * path [ ] = { " location " , " time_zone " , NULL } ;
std : : string str = lookupString ( ip , path ) ;
const char * ccode = str . c_str ( ) ;
pCtx - > StringToLocalUTF8 ( params [ 2 ] , params [ 3 ] , ccode , NULL ) ;
return ( str . length ( ) ! = 0 ) ? 1 : 0 ;
}
static cell_t sm_Geoip_Latitude ( IPluginContext * pCtx , const cell_t * params )
{
char * ip ;
pCtx - > LocalToString ( params [ 1 ] , & ip ) ;
StripPort ( ip ) ;
const char * path [ ] = { " location " , " latitude " , NULL } ;
double latitude = lookupDouble ( ip , path ) ;
return sp_ftoc ( latitude ) ;
}
static cell_t sm_Geoip_Longitude ( IPluginContext * pCtx , const cell_t * params )
{
char * ip ;
pCtx - > LocalToString ( params [ 1 ] , & ip ) ;
StripPort ( ip ) ;
const char * path [ ] = { " location " , " longitude " , NULL } ;
double longitude = lookupDouble ( ip , path ) ;
return sp_ftoc ( longitude ) ;
}
static cell_t sm_Geoip_Distance ( IPluginContext * pCtx , const cell_t * params )
{
float earthRadius = params [ 5 ] ? 3958.0 : 6370.997 ; // miles / km
float lat1 = sp_ctof ( params [ 1 ] ) * ( M_PI / 180 ) ;
float lon1 = sp_ctof ( params [ 2 ] ) * ( M_PI / 180 ) ;
float lat2 = sp_ctof ( params [ 3 ] ) * ( M_PI / 180 ) ;
float lon2 = sp_ctof ( params [ 4 ] ) * ( M_PI / 180 ) ;
2008-03-30 09:00:22 +02:00
2021-06-30 13:01:12 +02:00
return sp_ftoc ( earthRadius * acos ( sin ( lat1 ) * sin ( lat2 ) + cos ( lat1 ) * cos ( lat2 ) * cos ( lon2 - lon1 ) ) ) ;
2008-03-30 09:00:22 +02:00
}
const sp_nativeinfo_t geoip_natives [ ] =
{
{ " GeoipCode2 " , sm_Geoip_Code2 } ,
{ " GeoipCode3 " , sm_Geoip_Code3 } ,
2021-06-30 13:01:12 +02:00
{ " GeoipRegionCode " , sm_Geoip_RegionCode } ,
{ " GeoipContinentCode " , sm_Geoip_ContinentCode } ,
2008-03-30 09:00:22 +02:00
{ " GeoipCountry " , sm_Geoip_Country } ,
2021-06-30 13:01:12 +02:00
{ " GeoipCountryEx " , sm_Geoip_CountryEx } ,
{ " GeoipContinent " , sm_Geoip_Continent } ,
{ " GeoipRegion " , sm_Geoip_Region } ,
{ " GeoipCity " , sm_Geoip_City } ,
{ " GeoipTimezone " , sm_Geoip_Timezone } ,
{ " GeoipLatitude " , sm_Geoip_Latitude } ,
{ " GeoipLongitude " , sm_Geoip_Longitude } ,
{ " GeoipDistance " , sm_Geoip_Distance } ,
2008-03-30 09:00:22 +02:00
{ NULL , NULL } ,
} ;
2009-08-30 09:21:42 +02:00