Common: Replace ip2nation by ip2location. (#21957)

Replace ip2nation by ip2location.

Download: https://lite.ip2location.com/database/ip-country
(cherry picked from commit 2fe4ab94c5)
This commit is contained in:
Gooyeth
2018-06-22 17:32:39 -06:00
committed by Shauren
parent 5620eb9463
commit 163c487be7
15 changed files with 223 additions and 100 deletions

View File

@@ -434,58 +434,6 @@ LOCK TABLES `battlenet_item_favorite_appearances` WRITE;
/*!40000 ALTER TABLE `battlenet_item_favorite_appearances` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `ip2nation`
--
DROP TABLE IF EXISTS `ip2nation`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `ip2nation` (
`ip` int(11) unsigned NOT NULL DEFAULT '0',
`country` char(2) NOT NULL DEFAULT '',
KEY `ip` (`ip`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `ip2nation`
--
LOCK TABLES `ip2nation` WRITE;
/*!40000 ALTER TABLE `ip2nation` DISABLE KEYS */;
/*!40000 ALTER TABLE `ip2nation` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `ip2nationCountries`
--
DROP TABLE IF EXISTS `ip2nationCountries`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `ip2nationCountries` (
`code` varchar(4) NOT NULL DEFAULT '',
`iso_code_2` varchar(2) NOT NULL DEFAULT '',
`iso_code_3` varchar(3) DEFAULT '',
`iso_country` varchar(255) NOT NULL DEFAULT '',
`country` varchar(255) NOT NULL DEFAULT '',
`lat` float NOT NULL DEFAULT '0',
`lon` float NOT NULL DEFAULT '0',
PRIMARY KEY (`code`),
KEY `code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `ip2nationCountries`
--
LOCK TABLES `ip2nationCountries` WRITE;
/*!40000 ALTER TABLE `ip2nationCountries` DISABLE KEYS */;
/*!40000 ALTER TABLE `ip2nationCountries` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `ip_banned`
--
@@ -2242,6 +2190,7 @@ INSERT INTO `updates` VALUES
('2018_05_24_00_auth.sql','B98FD71AAA13810856729E034E6B8C9F8D5D4F6B','RELEASED','2018-05-24 22:32:49',0),
('2018_06_14_00_auth.sql','67EAB915BF0C7F2D410BE45F885A1A39D42C8C14','RELEASED','2018-06-14 23:06:59',0),
('2018_06_22_00_auth.sql','9DA24F70B8A365AFDEF58A9B578255CDEDFCA47C','RELEASED','2018-06-22 17:45:45',0),
('2018_06_23_00_auth.sql','BE35312C386A127D047E5A7CE0D14DB41D905F8E','RELEASED','2018-05-23 10:14:39',0),
('2018_06_29_00_auth.sql','03AAEA7E52848FA5522C3F0C6D9C38B988407480','RELEASED','2018-06-29 22:34:04',0),
('2018_12_09_00_auth_2017_01_06_00_auth.sql','6CCFE6A9774EC733C9863D36A0F15F3534189BBD','RELEASED','2018-11-22 22:21:26',0),
('2018_12_09_01_auth.sql','576C2A11BE671D8420FA3EB705E594E381ECCC56','RELEASED','2018-12-09 14:49:17',0);

View File

@@ -0,0 +1,3 @@
--
DROP TABLE IF EXISTS `ip2nation`;
DROP TABLE IF EXISTS `ip2nationCountries`;

View File

@@ -0,0 +1,125 @@
/*
* Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* 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/>.
*/
#include "IPLocation.h"
#include "Config.h"
#include "IpAddress.h"
#include "Log.h"
#include <fstream>
#include <iostream>
IpLocationStore::IpLocationStore()
{
}
IpLocationStore::~IpLocationStore()
{
}
void IpLocationStore::Load()
{
std::string value = sConfigMgr->GetStringDefault("IPLocationFile", ".");
if (value.empty())
return;
_ipLocationStore.clear();
TC_LOG_INFO("server.loading", "Loading IP Location Database...");
// Default folder
if (!value.compare("."))
value.append("/IP2LOCATION-LITE-DB1.CSV");
// Check file name
if (value.find("IP2LOCATION-LITE-DB1.CSV") == std::string::npos)
{
TC_LOG_ERROR("server.loading", "IPLocation:: File name is not valid, must be IP2LOCATION-LITE-DB1.CSV");
return;
}
// Check if file exists
std::ifstream ipfile(value);
if (!ipfile)
{
TC_LOG_ERROR("server.loading", "IPLocation:: No database file exists.");
return;
}
if (!ipfile.is_open())
{
TC_LOG_ERROR("server.loading", "IPLocation:: The file can not be opened.");
return;
}
std::string ip_from;
std::string ip_to;
std::string country_code;
std::string country_name;
while (ipfile.good())
{
// Read lines
std::getline(ipfile, ip_from, ',');
std::getline(ipfile, ip_to, ',');
std::getline(ipfile, country_code, ',');
std::getline(ipfile, country_name, '\n');
// Remove new lines and return
country_name.erase(std::remove(country_name.begin(), country_name.end(), '\r'), country_name.end());
country_name.erase(std::remove(country_name.begin(), country_name.end(), '\n'), country_name.end());
// Remove quotation marks
ip_from.erase(std::remove(ip_from.begin(), ip_from.end(), '"'), ip_from.end());
ip_to.erase(std::remove(ip_to.begin(), ip_to.end(), '"'), ip_to.end());
country_code.erase(std::remove(country_code.begin(), country_code.end(), '"'), country_code.end());
country_name.erase(std::remove(country_name.begin(), country_name.end(), '"'), country_name.end());
// Convert country code to lowercase
std::transform(country_code.begin(), country_code.end(), country_code.begin(), ::tolower);
IpLocationRecord data;
data.ip_from = (uint32)atoull(ip_from.c_str());
data.ip_to = (uint32)atoull(ip_to.c_str());
data.country_code = country_code;
data.country_name = country_name;
_ipLocationStore.push_back(data);
}
std::sort(_ipLocationStore.begin(), _ipLocationStore.end(), [](IpLocationRecord const& a, IpLocationRecord const& b) { return a.ip_from < b.ip_from; });
ipfile.close();
TC_LOG_INFO("server.loading", ">> Loaded %u entries.", uint32(_ipLocationStore.size()));
}
IpLocationRecord* IpLocationStore::GetData(std::string const& ipAddress)
{
if (_ipLocationStore.empty())
return nullptr;
uint32 ip = Trinity::Net::address_to_uint(Trinity::Net::make_address_v4(ipAddress));
auto itr = std::upper_bound(_ipLocationStore.begin(), _ipLocationStore.end(), ip, [](uint32 ip, IpLocationRecord const& loc) { return loc.ip_to >= ip; });
ASSERT(&(*itr));
return &(*itr);
}
IpLocationStore* IpLocationStore::instance()
{
static IpLocationStore instance;
return &instance;
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* 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/>.
*/
#include "Define.h"
#include <string>
struct IpLocationRecord
{
uint32 ip_from;
uint32 ip_to;
std::string country_code;
std::string country_name;
};
class TC_COMMON_API IpLocationStore
{
public:
IpLocationStore();
~IpLocationStore();
static IpLocationStore* instance();
void Load();
IpLocationRecord* GetData(std::string const& ipAddress);
private:
std::vector<IpLocationRecord> _ipLocationStore;
};
#define sIPLocation IpLocationStore::instance()

View File

@@ -29,6 +29,7 @@
#include "DatabaseEnv.h"
#include "DatabaseLoader.h"
#include "GitRevision.h"
#include "IPLocation.h"
#include "LoginRESTService.h"
#include "MySQLThreading.h"
#include "ProcessPriority.h"
@@ -151,6 +152,9 @@ int main(int argc, char** argv)
if (!StartDB())
return 1;
// Load IP Location Database
sIPLocation->Load();
std::shared_ptr<void> dbHandle(nullptr, [](void*) { StopDB(); });
std::shared_ptr<Trinity::Asio::IoContext> ioContext = std::make_shared<Trinity::Asio::IoContext>();

View File

@@ -20,6 +20,7 @@
#include "ByteConverter.h"
#include "DatabaseEnv.h"
#include "Errors.h"
#include "IPLocation.h"
#include "QueryCallback.h"
#include "LoginRESTService.h"
#include "ProtobufJSON.h"
@@ -92,7 +93,6 @@ void Battlenet::Session::Start()
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO);
stmt->setString(0, ip_address);
stmt->setUInt32(1, inet_addr(ip_address.c_str()));
_queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&Battlenet::Session::CheckIpCallback, this, std::placeholders::_1)));
}
@@ -108,9 +108,6 @@ void Battlenet::Session::CheckIpCallback(PreparedQueryResult result)
if (fields[0].GetUInt64() != 0)
banned = true;
if (!fields[1].GetString().empty())
_ipCountry = fields[1].GetString();
} while (result->NextRow());
if (banned)
@@ -339,6 +336,9 @@ uint32 Battlenet::Session::VerifyWebCredentials(std::string const& webCredential
}
else
{
if (IpLocationRecord* location = sIPLocation->GetData(ip_address))
_ipCountry = location->country_code;
TC_LOG_DEBUG("session", "[Session::HandleVerifyWebCredentials] Account '%s' is not locked to ip", _accountInfo->Login.c_str());
if (_accountInfo->LockCountry.empty() || _accountInfo->LockCountry == "00")
TC_LOG_DEBUG("session", "[Session::HandleVerifyWebCredentials] Account '%s' is not locked to country", _accountInfo->Login.c_str());

View File

@@ -197,6 +197,16 @@ SourceDirectory = ""
MySQLExecutable = ""
#
# IPLocationFile
# Description: The path to your IP2Location database CSV file.
# Example: "C:/Trinity/IP2Location.csv"
# "/home/trinity/IP2Location.csv"
# Default: "." - (Current core directory)
# "" - (Disabled)
IPLocationFile = "."
#
###################################################################################################

View File

@@ -26,9 +26,7 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_SEL_REALMLIST, "SELECT id, name, address, localAddress, localSubnetMask, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild, Region, Battlegroup FROM realmlist WHERE flag <> 3 ORDER BY name", CONNECTION_SYNCH);
PrepareStatement(LOGIN_DEL_EXPIRED_IP_BANS, "DELETE FROM ip_banned WHERE unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS, "UPDATE account_banned SET active = 0 WHERE active = 1 AND unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_IP_INFO, "(SELECT unbandate > UNIX_TIMESTAMP() OR unbandate = bandate AS banned, NULL as country FROM ip_banned WHERE ip = ?) "
"UNION "
"(SELECT NULL AS banned, country FROM ip2nation WHERE INET_NTOA(ip) = ?)", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_IP_INFO, "SELECT unbandate > UNIX_TIMESTAMP() OR unbandate = bandate AS banned, NULL as country FROM ip_banned WHERE ip = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_INS_IP_AUTO_BANNED, "INSERT INTO ip_banned (ip, bandate, unbandate, bannedby, banreason) VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, 'Trinity Auth', 'Failed login autoban')", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_IP_BANNED_ALL, "SELECT ip, bandate, unbandate, bannedby, banreason FROM ip_banned WHERE (bandate = unbandate OR unbandate > UNIX_TIMESTAMP()) ORDER BY unbandate", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_IP_BANNED_BY_IP, "SELECT ip, bandate, unbandate, bannedby, banreason FROM ip_banned WHERE (bandate = unbandate OR unbandate > UNIX_TIMESTAMP()) AND ip LIKE CONCAT('%%', ?, '%%') ORDER BY unbandate", CONNECTION_SYNCH);
@@ -38,7 +36,6 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_UPD_ACCOUNT_INFO_CONTINUED_SESSION, "UPDATE account SET sessionkey = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_CONTINUED_SESSION, "SELECT username, sessionkey FROM account WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_VS, "UPDATE account SET v = ?, s = ? WHERE username = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_LOGON_COUNTRY, "SELECT country FROM ip2nation WHERE ip < ? ORDER BY ip DESC LIMIT 0,1", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME, "SELECT id FROM account WHERE username = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_NAME, "SELECT id, username FROM account WHERE username = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT a.id, a.sessionkey, ba.last_ip, ba.locked, ba.lock_country, a.expansion, a.mutetime, ba.locale, a.recruiter, a.os, ba.id, aa.gmLevel, "
@@ -95,7 +92,6 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_SEL_LAST_IP, "SELECT last_ip FROM account WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_REALMLIST_SECURITY_LEVEL, "SELECT allowedSecurityLevel from realmlist WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_DEL_ACCOUNT, "DELETE FROM account WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_IP2NATION_COUNTRY, "SELECT c.country FROM ip2nationCountries c, ip2nation i WHERE i.ip < ? AND c.code = i.country ORDER BY i.ip DESC LIMIT 0,1", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_AUTOBROADCAST, "SELECT id, weight, text FROM autobroadcast WHERE realmid = ? OR realmid = -1", CONNECTION_SYNCH);
PrepareStatement(LOGIN_GET_EMAIL_BY_ID, "SELECT email FROM account WHERE id = ?", CONNECTION_SYNCH);
// 0: uint32, 1: uint32, 2: uint8, 3: uint32, 4: string // Complete name: "Login_Insert_AccountLoginDeLete_IP_Logging"

View File

@@ -39,7 +39,6 @@ enum LoginDatabaseStatements : uint32
LOGIN_UPD_ACCOUNT_INFO_CONTINUED_SESSION,
LOGIN_SEL_ACCOUNT_INFO_CONTINUED_SESSION,
LOGIN_UPD_VS,
LOGIN_SEL_LOGON_COUNTRY,
LOGIN_SEL_ACCOUNT_ID_BY_NAME,
LOGIN_SEL_ACCOUNT_LIST_BY_NAME,
LOGIN_SEL_ACCOUNT_INFO_BY_NAME,
@@ -91,7 +90,6 @@ enum LoginDatabaseStatements : uint32
LOGIN_SEL_ACCOUNT_WHOIS,
LOGIN_SEL_REALMLIST_SECURITY_LEVEL,
LOGIN_DEL_ACCOUNT,
LOGIN_SEL_IP2NATION_COUNTRY,
LOGIN_SEL_AUTOBROADCAST,
LOGIN_SEL_LAST_ATTEMPT_IP,
LOGIN_SEL_LAST_IP,

View File

@@ -23,6 +23,7 @@
#include "DatabaseEnv.h"
#include "Errors.h"
#include "HmacHash.h"
#include "IPLocation.h"
#include "PacketLog.h"
#include "Realm.h"
#include "RBAC.h"
@@ -95,7 +96,6 @@ void WorldSocket::Start()
std::string ip_address = GetRemoteIpAddress().to_string();
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO);
stmt->setString(0, ip_address);
stmt->setUInt32(1, inet_addr(ip_address.c_str()));
_queryProcessor.AddQuery(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::CheckIpCallback, this, std::placeholders::_1)));
}
@@ -111,9 +111,6 @@ void WorldSocket::CheckIpCallback(PreparedQueryResult result)
if (fields[0].GetUInt64() != 0)
banned = true;
if (!fields[1].GetString().empty())
_ipCountry = fields[1].GetString();
} while (result->NextRow());
if (banned)
@@ -746,6 +743,9 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth::
return;
}
if (IpLocationRecord* location = sIPLocation->GetData(address))
_ipCountry = location->country_code;
///- Re-check ip locking (same check as in auth).
if (account.BattleNet.IsLockedToIP)
{

View File

@@ -56,6 +56,7 @@
#include "GuildFinderMgr.h"
#include "GuildMgr.h"
#include "InstanceSaveMgr.h"
#include "IPLocation.h"
#include "Language.h"
#include "LFGMgr.h"
#include "LootMgr.h"
@@ -1580,6 +1581,8 @@ void World::SetInitialWorldSettings()
//Load weighted graph on taxi nodes path
sTaxiPathGraph.Initialize();
// Load IP Location Database
sIPLocation->Load();
std::unordered_map<uint32, std::vector<uint32>> mapData;
for (MapEntry const* mapEntry : sMapStore)

View File

@@ -26,6 +26,7 @@ EndScriptData */
#include "Chat.h"
#include "DatabaseEnv.h"
#include "IpAddress.h"
#include "IPLocation.h"
#include "Language.h"
#include "Log.h"
#include "Player.h"
@@ -290,25 +291,18 @@ public:
{
if (param == "on")
{
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGON_COUNTRY);
uint32 ip = Trinity::Net::address_to_uint(Trinity::Net::make_address_v4(handler->GetSession()->GetRemoteAddress()));
EndianConvertReverse(ip);
stmt->setUInt32(0, ip);
PreparedQueryResult result = LoginDatabase.Query(stmt);
if (result)
if (IpLocationRecord* location = sIPLocation->GetData(handler->GetSession()->GetRemoteAddress()))
{
Field* fields = result->Fetch();
std::string country = fields[0].GetString();
stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_LOCK_CONTRY);
stmt->setString(0, country);
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_LOCK_CONTRY);
stmt->setString(0, location->country_code);
stmt->setUInt32(1, handler->GetSession()->GetAccountId());
LoginDatabase.Execute(stmt);
handler->PSendSysMessage(LANG_COMMAND_ACCLOCKLOCKED);
}
else
{
handler->PSendSysMessage("[IP2NATION] Table empty");
TC_LOG_DEBUG("server.bnetserver", "[IP2NATION] Table empty");
handler->PSendSysMessage("IP2Location] No information");
TC_LOG_DEBUG("server.bnetserver", "IP2Location] No information");
}
}
else if (param == "off")

View File

@@ -21,6 +21,7 @@
#include "Chat.h"
#include "DatabaseEnv.h"
#include "IpAddress.h"
#include "IPLocation.h"
#include "Language.h"
#include "Log.h"
#include "Player.h"
@@ -143,25 +144,18 @@ public:
{
if (param == "on")
{
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGON_COUNTRY);
uint32 ip = Trinity::Net::address_to_uint(Trinity::Net::make_address_v4(handler->GetSession()->GetRemoteAddress()));
EndianConvertReverse(ip);
stmt->setUInt32(0, ip);
PreparedQueryResult result = LoginDatabase.Query(stmt);
if (result)
if (IpLocationRecord const* location = sIPLocation->GetLocationRecord(handler->GetSession()->GetRemoteAddress()))
{
Field* fields = result->Fetch();
std::string country = fields[0].GetString();
stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_ACCOUNT_LOCK_CONTRY);
stmt->setString(0, country);
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_ACCOUNT_LOCK_CONTRY);
stmt->setString(0, location->CountryCode);
stmt->setUInt32(1, handler->GetSession()->GetBattlenetAccountId());
LoginDatabase.Execute(stmt);
handler->PSendSysMessage(LANG_COMMAND_ACCLOCKLOCKED);
}
else
{
handler->PSendSysMessage("[IP2NATION] Table empty");
TC_LOG_DEBUG("server.bnetserver", "[IP2NATION] Table empty");
handler->PSendSysMessage("IP2Location] No information");
TC_LOG_DEBUG("server.bnetserver", "IP2Location] No information");
}
}
else if (param == "off")

View File

@@ -27,6 +27,7 @@
#include "GroupMgr.h"
#include "InstanceSaveMgr.h"
#include "IpAddress.h"
#include "IPLocation.h"
#include "Item.h"
#include "Language.h"
#include "LFG.h"
@@ -1768,17 +1769,10 @@ public:
lastIp = fields[4].GetString();
lastLogin = fields[5].GetString();
uint32 ip = Trinity::Net::address_to_uint(Trinity::Net::make_address_v4(lastIp));
EndianConvertReverse(ip);
// If ip2nation table is populated, it displays the country
stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP2NATION_COUNTRY);
stmt->setUInt32(0, ip);
if (PreparedQueryResult result2 = LoginDatabase.Query(stmt))
if (IpLocationRecord* location = sIPLocation->GetData(lastIp))
{
Field* fields2 = result2->Fetch();
lastIp.append(" (");
lastIp.append(fields2[0].GetString());
lastIp.append(location->country_name);
lastIp.append(")");
}
}

View File

@@ -226,6 +226,16 @@ SourceDirectory = ""
MySQLExecutable = ""
#
# IPLocationFile
# Description: The path to your IP2Location database CSV file.
# Example: "C:/Trinity/IP2Location.csv"
# "/home/trinity/IP2Location.csv"
# Default: "." - (Current core directory)
# "" - (Disabled)
IPLocationFile = "."
#
###################################################################################################