mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
[Bug Fix] Fix IP Exemptions. (#2189)
* [Bug Fix] Fix IP Exemptions. - IP Exemptions were broken due to GetAccountID() returning 0 in logic somehow, resolved this by setting a variable to GetAccountID() at the beginning of the method. - Fixed weird IP messages where the long form of IP was displayed instead of the string form. - Fixes edge case where IP rule may be set to -1 and this will make anyone get instantly kicked if IP Exemptions were enabled as their IP Count would always be greater than -1. * Update client.cpp * Update client.cpp * Update clientlist.cpp * Update clientlist.cpp
This commit is contained in:
parent
aaaee6c6a4
commit
7de50d0e60
@ -1469,41 +1469,25 @@ uint8 Database::GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16
|
||||
return base_cap;
|
||||
}
|
||||
|
||||
uint32 Database::GetCharacterInfo(
|
||||
const char *iName,
|
||||
uint32 *oAccID,
|
||||
uint32 *oZoneID,
|
||||
uint32 *oInstanceID,
|
||||
float *oX,
|
||||
float *oY,
|
||||
float *oZ
|
||||
)
|
||||
uint32 Database::GetCharacterInfo(std::string character_name, uint32 *account_id, uint32 *zone_id, uint32 *instance_id)
|
||||
{
|
||||
std::string query = StringFormat(
|
||||
"SELECT `id`, `account_id`, `zone_id`, `zone_instance`, `x`, `y`, `z` FROM `character_data` WHERE `name` = '%s'",
|
||||
EscapeString(iName).c_str()
|
||||
auto query = fmt::format(
|
||||
"SELECT `id`, `account_id`, `zone_id`, `zone_instance` FROM `character_data` WHERE `name` = '{}'",
|
||||
EscapeString(character_name)
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success()) {
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (results.RowCount() != 1) {
|
||||
return 0;
|
||||
}
|
||||
auto row = results.begin();
|
||||
auto character_id = std::stoul(row[0]);
|
||||
*account_id = std::stoul(row[1]);
|
||||
*zone_id = std::stoul(row[2]);
|
||||
*instance_id = std::stoul(row[3]);
|
||||
|
||||
auto row = results.begin();
|
||||
uint32 charid = atoi(row[0]);
|
||||
if (oAccID) { *oAccID = atoi(row[1]); }
|
||||
if (oZoneID) { *oZoneID = atoi(row[2]); }
|
||||
if (oInstanceID) { *oInstanceID = atoi(row[3]); }
|
||||
if (oX) { *oX = atof(row[4]); }
|
||||
if (oY) { *oY = atof(row[5]); }
|
||||
if (oZ) { *oZ = atof(row[6]); }
|
||||
|
||||
return charid;
|
||||
return character_id;
|
||||
}
|
||||
|
||||
bool Database::UpdateLiveChar(char* charname, uint32 account_id) {
|
||||
@ -1627,29 +1611,36 @@ uint32 Database::GetGroupID(const char* name){
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
/* Is this really getting used properly... A half implementation ? Akkadius */
|
||||
char* Database::GetGroupLeaderForLogin(const char* name, char* leaderbuf) {
|
||||
strcpy(leaderbuf, "");
|
||||
std::string Database::GetGroupLeaderForLogin(std::string character_name) {
|
||||
uint32 group_id = 0;
|
||||
|
||||
std::string query = StringFormat("SELECT `groupid` FROM `group_id` WHERE `name` = '%s'", name);
|
||||
auto query = fmt::format(
|
||||
"SELECT `groupid` FROM `group_id` WHERE `name` = '{}'",
|
||||
character_name
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
if (row[0])
|
||||
group_id = atoi(row[0]);
|
||||
if (results.Success() && results.RowCount()) {
|
||||
auto row = results.begin();
|
||||
group_id = std::stoul(row[0]);
|
||||
}
|
||||
|
||||
if (group_id == 0)
|
||||
return leaderbuf;
|
||||
if (!group_id) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
query = StringFormat("SELECT `leadername` FROM `group_leaders` WHERE `gid` = '%u' LIMIT 1", group_id);
|
||||
query = fmt::format(
|
||||
"SELECT `leadername` FROM `group_leaders` WHERE `gid` = {} LIMIT 1",
|
||||
group_id
|
||||
);
|
||||
results = QueryDatabase(query);
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
if (row[0])
|
||||
strcpy(leaderbuf, row[0]);
|
||||
if (results.Success() && results.RowCount()) {
|
||||
auto row = results.begin();
|
||||
return row[0];
|
||||
}
|
||||
|
||||
return leaderbuf;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
void Database::SetGroupLeaderName(uint32 gid, const char* name) {
|
||||
@ -2244,28 +2235,32 @@ bool Database::SaveTime(int8 minute, int8 hour, int8 day, int8 month, int16 year
|
||||
}
|
||||
|
||||
int Database::GetIPExemption(std::string account_ip) {
|
||||
std::string query = StringFormat("SELECT `exemption_amount` FROM `ip_exemptions` WHERE `exemption_ip` = '%s'", account_ip.c_str());
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (results.Success() && results.RowCount() > 0) {
|
||||
auto row = results.begin();
|
||||
return atoi(row[0]);
|
||||
}
|
||||
|
||||
return RuleI(World, MaxClientsPerIP);
|
||||
}
|
||||
|
||||
void Database::SetIPExemption(std::string account_ip, int exemption_amount) {
|
||||
std::string query = fmt::format(
|
||||
"SELECT `exemption_id` FROM `ip_exemptions` WHERE `exemption_ip` = '{}'",
|
||||
auto query = fmt::format(
|
||||
"SELECT `exemption_amount` FROM `ip_exemptions` WHERE `exemption_ip` = '{}'",
|
||||
account_ip
|
||||
);
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() || !results.RowCount()) {
|
||||
return RuleI(World, MaxClientsPerIP);
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
return std::stoi(row[0]);
|
||||
}
|
||||
|
||||
void Database::SetIPExemption(std::string account_ip, int exemption_amount) {
|
||||
auto query = fmt::format(
|
||||
"SELECT `exemption_id` FROM `ip_exemptions` WHERE `exemption_ip` = '{}'",
|
||||
account_ip
|
||||
);
|
||||
|
||||
uint32 exemption_id = 0;
|
||||
if (results.Success() && results.RowCount() > 0) {
|
||||
|
||||
auto results = QueryDatabase(query);
|
||||
if (results.Success() && results.RowCount()) {
|
||||
auto row = results.begin();
|
||||
exemption_id = atoi(row[0]);
|
||||
exemption_id = std::stoul(row[0]);
|
||||
}
|
||||
|
||||
query = fmt::format(
|
||||
@ -2274,13 +2269,14 @@ void Database::SetIPExemption(std::string account_ip, int exemption_amount) {
|
||||
exemption_amount
|
||||
);
|
||||
|
||||
if (exemption_id != 0) {
|
||||
if (exemption_id) {
|
||||
query = fmt::format(
|
||||
"UPDATE `ip_exemptions` SET `exemption_amount` = {} WHERE `exemption_ip` = '{}'",
|
||||
exemption_amount,
|
||||
account_ip
|
||||
);
|
||||
}
|
||||
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
|
||||
@ -131,7 +131,7 @@ public:
|
||||
uint32 GetAccountIDByChar(uint32 char_id);
|
||||
uint32 GetAccountIDByName(std::string account_name, std::string loginserver, int16* status = 0, uint32* lsid = 0);
|
||||
uint32 GetCharacterID(const char *name);
|
||||
uint32 GetCharacterInfo(const char* iName, uint32* oAccID = 0, uint32* oZoneID = 0, uint32* oInstanceID = 0, float* oX = 0, float* oY = 0, float* oZ = 0);
|
||||
uint32 GetCharacterInfo(std::string character_name, uint32 *account_id, uint32 *zone_id, uint32 *instance_id);
|
||||
uint32 GetGuildIDByCharID(uint32 char_id);
|
||||
uint32 GetGroupIDByCharID(uint32 char_id);
|
||||
uint32 GetRaidIDByCharID(uint32 char_id);
|
||||
@ -207,8 +207,8 @@ public:
|
||||
|
||||
/* Groups */
|
||||
|
||||
char* GetGroupLeaderForLogin(const char* name,char* leaderbuf);
|
||||
char* GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, char *mentoree = nullptr, int *mentor_percent = nullptr, GroupLeadershipAA_Struct* GLAA = nullptr);
|
||||
std::string GetGroupLeaderForLogin(std::string character_name);
|
||||
char* GetGroupLeadershipInfo(uint32 gid, char* leaderbuf, char* maintank = nullptr, char* assist = nullptr, char* puller = nullptr, char *marknpc = nullptr, char *mentoree = nullptr, int *mentor_percent = nullptr, GroupLeadershipAA_Struct* GLAA = nullptr);
|
||||
|
||||
uint32 GetGroupID(const char* name);
|
||||
|
||||
|
||||
219
world/client.cpp
219
world/client.cpp
@ -721,38 +721,40 @@ bool Client::HandleCharacterCreatePacket(const EQApplicationPacket *app) {
|
||||
}
|
||||
|
||||
bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
if (GetAccountID() == 0) {
|
||||
LogInfo("Enter world with no logged in account");
|
||||
auto account_id = GetAccountID();
|
||||
if (!account_id) {
|
||||
LogInfo("Enter world with no logged in account.");
|
||||
eqs->Close();
|
||||
return true;
|
||||
}
|
||||
|
||||
if(GetAdmin() < 0)
|
||||
{
|
||||
LogInfo("Account banned or suspended");
|
||||
if (GetAdmin() < 0) {
|
||||
LogInfo("Account [{}] is banned or suspended.", account_id);
|
||||
eqs->Close();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (RuleB(World, EnableIPExemptions) || RuleI(World, MaxClientsPerIP) >= 0) {
|
||||
if (
|
||||
RuleB(World, EnableIPExemptions) ||
|
||||
RuleI(World, MaxClientsPerIP) > 0
|
||||
) {
|
||||
client_list.GetCLEIP(GetIP()); //Check current CLE Entry IPs against incoming connection
|
||||
}
|
||||
|
||||
EnterWorld_Struct *ew=(EnterWorld_Struct *)app->pBuffer;
|
||||
strn0cpy(char_name, ew->name, 64);
|
||||
auto ew = (EnterWorld_Struct *) app->pBuffer;
|
||||
strn0cpy(char_name, ew->name, sizeof(char_name));
|
||||
|
||||
EQApplicationPacket *outapp;
|
||||
uint32 tmpaccid = 0;
|
||||
charid = database.GetCharacterInfo(char_name, &tmpaccid, &zone_id, &instance_id);
|
||||
if (charid == 0) {
|
||||
uint32 temporary_account_id = 0;
|
||||
charid = database.GetCharacterInfo(char_name, &temporary_account_id, &zone_id, &instance_id);
|
||||
if (!charid) {
|
||||
LogInfo("Could not get CharInfo for [{}]", char_name);
|
||||
eqs->Close();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Make sure this account owns this character
|
||||
if (tmpaccid != GetAccountID()) {
|
||||
LogInfo("This account does not own the character named [{}]", char_name);
|
||||
if (temporary_account_id != account_id) {
|
||||
LogInfo("Account [{}] does not own the character named [{}] from account [{}]", account_id, char_name, temporary_account_id);
|
||||
eqs->Close();
|
||||
return true;
|
||||
}
|
||||
@ -761,25 +763,26 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
// (This is a literal translation of the original process..I don't see why it can't be changed to a single-target query over account iteration)
|
||||
if (!is_player_zoning) {
|
||||
size_t character_limit = EQ::constants::StaticLookup(eqs->ClientVersion())->CharacterCreationLimit;
|
||||
if (character_limit > EQ::constants::CHARACTER_CREATION_LIMIT) { character_limit = EQ::constants::CHARACTER_CREATION_LIMIT; }
|
||||
if (eqs->ClientVersion() == EQ::versions::ClientVersion::Titanium) { character_limit = Titanium::constants::CHARACTER_CREATION_LIMIT; }
|
||||
if (character_limit > EQ::constants::CHARACTER_CREATION_LIMIT) {
|
||||
character_limit = EQ::constants::CHARACTER_CREATION_LIMIT;
|
||||
}
|
||||
|
||||
std::string tgh_query = StringFormat(
|
||||
"SELECT "
|
||||
"`id`, "
|
||||
"name, "
|
||||
"`level`, "
|
||||
"last_login "
|
||||
"FROM "
|
||||
"character_data "
|
||||
"WHERE `account_id` = %i ORDER BY `name` LIMIT %u", GetAccountID(), character_limit);
|
||||
auto tgh_results = database.QueryDatabase(tgh_query);
|
||||
if (eqs->ClientVersion() == EQ::versions::ClientVersion::Titanium) {
|
||||
character_limit = Titanium::constants::CHARACTER_CREATION_LIMIT;
|
||||
}
|
||||
|
||||
auto query = fmt::format(
|
||||
"SELECT `id`, `name`, `level`, `last_login` FROM character_data WHERE `account_id` = {} ORDER BY `name` LIMIT {}",
|
||||
account_id,
|
||||
character_limit
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
/* Check GoHome */
|
||||
if (ew->return_home && !ew->tutorial) {
|
||||
bool home_enabled = false;
|
||||
for (auto row = tgh_results.begin(); row != tgh_results.end(); ++row) {
|
||||
if (strcasecmp(row[1], char_name) == 0) {
|
||||
for (auto row : results) {
|
||||
if (!strcasecmp(row[1], char_name)) {
|
||||
if (RuleB(World, EnableReturnHomeButton)) {
|
||||
int now = time(nullptr);
|
||||
if ((now - atoi(row[3])) >= RuleI(World, MinOfflineTimeToReturnHome)) {
|
||||
@ -792,9 +795,8 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
|
||||
if (home_enabled) {
|
||||
zone_id = database.MoveCharacterToBind(charid, 4);
|
||||
}
|
||||
else {
|
||||
LogInfo("[{}] is trying to go home before they're able", char_name);
|
||||
} else {
|
||||
LogInfo("[{}] is trying to go home before they're able.", char_name);
|
||||
database.SetHackerFlag(GetAccountName(), char_name, "MQGoHome: player tried to go home before they were able.");
|
||||
eqs->Close();
|
||||
return true;
|
||||
@ -804,9 +806,12 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
/* Check Tutorial*/
|
||||
if (RuleB(World, EnableTutorialButton) && (ew->tutorial || StartInTutorial)) {
|
||||
bool tutorial_enabled = false;
|
||||
for (auto row = tgh_results.begin(); row != tgh_results.end(); ++row) {
|
||||
if (strcasecmp(row[1], char_name) == 0) {
|
||||
if (RuleB(World, EnableTutorialButton) && ((uint8)atoi(row[2]) <= RuleI(World, MaxLevelForTutorial))) {
|
||||
for (auto row : results) {
|
||||
if (!strcasecmp(row[1], char_name)) {
|
||||
if (
|
||||
RuleB(World, EnableTutorialButton) &&
|
||||
std::stoi(row[2]) <= RuleI(World, MaxLevelForTutorial)
|
||||
) {
|
||||
tutorial_enabled = true;
|
||||
break;
|
||||
}
|
||||
@ -816,9 +821,8 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
if (tutorial_enabled) {
|
||||
zone_id = RuleI(World, TutorialZoneID);
|
||||
database.MoveCharacterToZone(charid, zone_id);
|
||||
}
|
||||
else {
|
||||
LogInfo("[{}] is trying to go to tutorial but are not allowed", char_name);
|
||||
} else {
|
||||
LogInfo("[{}] is trying to go to the Tutorial but they are not allowed.", char_name);
|
||||
database.SetHackerFlag(GetAccountName(), char_name, "MQTutorial: player tried to enter the tutorial without having tutorial enabled for this character.");
|
||||
eqs->Close();
|
||||
return true;
|
||||
@ -826,17 +830,17 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
}
|
||||
}
|
||||
|
||||
if (zone_id == 0 || !ZoneName(zone_id)) {
|
||||
if (!zone_id || !ZoneName(zone_id)) {
|
||||
// This is to save people in an invalid zone, once it's removed from the DB
|
||||
database.MoveCharacterToZone(charid, ZoneID("arena"));
|
||||
LogInfo("Zone not found in database zone_id=[{}], moveing char to arena character:[{}]", zone_id, char_name);
|
||||
LogInfo("Zone [{}] not found, moving [{}] to Arena.", zone_id, char_name);
|
||||
}
|
||||
|
||||
if(instance_id > 0)
|
||||
{
|
||||
if (!database.VerifyInstanceAlive(instance_id, GetCharID()) ||
|
||||
!database.VerifyZoneInstance(zone_id, instance_id))
|
||||
{
|
||||
if (instance_id) {
|
||||
if (
|
||||
!database.VerifyInstanceAlive(instance_id, GetCharID()) ||
|
||||
!database.VerifyZoneInstance(zone_id, instance_id)
|
||||
) {
|
||||
zone_id = database.MoveCharacterToInstanceSafeReturn(charid, zone_id, instance_id);
|
||||
instance_id = 0;
|
||||
}
|
||||
@ -845,83 +849,80 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
if(!is_player_zoning) {
|
||||
database.SetGroupID(char_name, 0, charid);
|
||||
database.SetLoginFlags(charid, false, false, 1);
|
||||
}
|
||||
else{
|
||||
uint32 groupid = database.GetGroupID(char_name);
|
||||
if(groupid > 0){
|
||||
char* leader = 0;
|
||||
char leaderbuf[64] = {0};
|
||||
if((leader = database.GetGroupLeaderForLogin(char_name, leaderbuf)) && strlen(leader)>1){
|
||||
auto outapp3 = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct));
|
||||
GroupJoin_Struct* gj=(GroupJoin_Struct*)outapp3->pBuffer;
|
||||
} else {
|
||||
auto group_id = database.GetGroupID(char_name);
|
||||
if (group_id) {
|
||||
auto leader_name = database.GetGroupLeaderForLogin(char_name);
|
||||
if (!leader_name.empty()) {
|
||||
auto pack = new EQApplicationPacket(OP_GroupUpdate, sizeof(GroupJoin_Struct));
|
||||
auto gj = (GroupJoin_Struct*) pack->pBuffer;
|
||||
gj->action=8;
|
||||
strcpy(gj->yourname, char_name);
|
||||
strcpy(gj->membername, leader);
|
||||
QueuePacket(outapp3);
|
||||
safe_delete(outapp3);
|
||||
strn0cpy(gj->yourname, char_name, sizeof(gj->yourname));
|
||||
strn0cpy(gj->membername, leader_name.c_str(), sizeof(gj->membername));
|
||||
QueuePacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outapp = new EQApplicationPacket(OP_MOTD);
|
||||
std::string tmp;
|
||||
if (database.GetVariable("MOTD", tmp)) {
|
||||
outapp->size = tmp.length() + 1;
|
||||
auto outapp = new EQApplicationPacket(OP_MOTD);
|
||||
std::string motd_message;
|
||||
if (database.GetVariable("MOTD", motd_message)) {
|
||||
outapp->size = motd_message.length() + 1;
|
||||
outapp->pBuffer = new uchar[outapp->size];
|
||||
memset(outapp->pBuffer,0,outapp->size);
|
||||
strcpy((char*)outapp->pBuffer, tmp.c_str());
|
||||
|
||||
} else {
|
||||
// Null Message of the Day. :)
|
||||
memset(outapp->pBuffer, 0, outapp->size);
|
||||
strcpy((char*)outapp->pBuffer, motd_message.c_str());
|
||||
} else { // Null Message of the Day. :)
|
||||
outapp->size = 1;
|
||||
outapp->pBuffer = new uchar[outapp->size];
|
||||
outapp->pBuffer[0] = 0;
|
||||
}
|
||||
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
// set mailkey - used for duration of character session
|
||||
int MailKey = emu_random.Int(1, INT_MAX);
|
||||
int mail_key = emu_random.Int(1, INT_MAX);
|
||||
|
||||
database.SetMailKey(charid, GetIP(), MailKey);
|
||||
database.SetMailKey(charid, GetIP(), mail_key);
|
||||
if (UCSServerAvailable_) {
|
||||
const WorldConfig *Config = WorldConfig::get();
|
||||
auto config = WorldConfig::get();
|
||||
std::string buffer;
|
||||
|
||||
EQ::versions::UCSVersion ConnectionType = EQ::versions::ucsUnknown;
|
||||
auto connection_type = EQ::versions::ucsUnknown;
|
||||
|
||||
// chat server packet
|
||||
switch (GetClientVersion()) {
|
||||
case EQ::versions::ClientVersion::Titanium:
|
||||
ConnectionType = EQ::versions::ucsTitaniumChat;
|
||||
break;
|
||||
case EQ::versions::ClientVersion::SoF:
|
||||
ConnectionType = EQ::versions::ucsSoFCombined;
|
||||
break;
|
||||
case EQ::versions::ClientVersion::SoD:
|
||||
ConnectionType = EQ::versions::ucsSoDCombined;
|
||||
break;
|
||||
case EQ::versions::ClientVersion::UF:
|
||||
ConnectionType = EQ::versions::ucsUFCombined;
|
||||
break;
|
||||
case EQ::versions::ClientVersion::RoF:
|
||||
ConnectionType = EQ::versions::ucsRoFCombined;
|
||||
break;
|
||||
case EQ::versions::ClientVersion::RoF2:
|
||||
ConnectionType = EQ::versions::ucsRoF2Combined;
|
||||
break;
|
||||
default:
|
||||
ConnectionType = EQ::versions::ucsUnknown;
|
||||
break;
|
||||
case EQ::versions::ClientVersion::Titanium:
|
||||
connection_type = EQ::versions::ucsTitaniumChat;
|
||||
break;
|
||||
case EQ::versions::ClientVersion::SoF:
|
||||
connection_type = EQ::versions::ucsSoFCombined;
|
||||
break;
|
||||
case EQ::versions::ClientVersion::SoD:
|
||||
connection_type = EQ::versions::ucsSoDCombined;
|
||||
break;
|
||||
case EQ::versions::ClientVersion::UF:
|
||||
connection_type = EQ::versions::ucsUFCombined;
|
||||
break;
|
||||
case EQ::versions::ClientVersion::RoF:
|
||||
connection_type = EQ::versions::ucsRoFCombined;
|
||||
break;
|
||||
case EQ::versions::ClientVersion::RoF2:
|
||||
connection_type = EQ::versions::ucsRoF2Combined;
|
||||
break;
|
||||
default:
|
||||
connection_type = EQ::versions::ucsUnknown;
|
||||
break;
|
||||
}
|
||||
|
||||
buffer = StringFormat("%s,%i,%s.%s,%c%08X",
|
||||
Config->ChatHost.c_str(),
|
||||
Config->ChatPort,
|
||||
Config->ShortName.c_str(),
|
||||
buffer = fmt::format("{},{},{}.{},{}{:08X}",
|
||||
config->ChatHost,
|
||||
config->ChatPort,
|
||||
config->ShortName,
|
||||
GetCharName(),
|
||||
ConnectionType,
|
||||
MailKey
|
||||
static_cast<char>(connection_type),
|
||||
mail_key
|
||||
);
|
||||
|
||||
outapp = new EQApplicationPacket(OP_SetChatServer, (buffer.length() + 1));
|
||||
@ -933,21 +934,21 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
|
||||
|
||||
// mail server packet
|
||||
switch (GetClientVersion()) {
|
||||
case EQ::versions::ClientVersion::Titanium:
|
||||
ConnectionType = EQ::versions::ucsTitaniumMail;
|
||||
break;
|
||||
default:
|
||||
// retain value from previous switch
|
||||
break;
|
||||
case EQ::versions::ClientVersion::Titanium:
|
||||
connection_type = EQ::versions::ucsTitaniumMail;
|
||||
break;
|
||||
default:
|
||||
// retain value from previous switch
|
||||
break;
|
||||
}
|
||||
|
||||
buffer = StringFormat("%s,%i,%s.%s,%c%08X",
|
||||
Config->MailHost.c_str(),
|
||||
Config->MailPort,
|
||||
Config->ShortName.c_str(),
|
||||
buffer = fmt::format("{},{},{}.{},{}{:08X}",
|
||||
config->MailHost,
|
||||
config->MailPort,
|
||||
config->ShortName,
|
||||
GetCharName(),
|
||||
ConnectionType,
|
||||
MailKey
|
||||
static_cast<char>(connection_type),
|
||||
mail_key
|
||||
);
|
||||
|
||||
outapp = new EQApplicationPacket(OP_SetChatServer2, (buffer.length() + 1));
|
||||
|
||||
@ -100,67 +100,101 @@ ClientListEntry* ClientList::GetCLE(uint32 iID) {
|
||||
|
||||
//Check current CLE Entry IPs against incoming connection
|
||||
|
||||
void ClientList::GetCLEIP(uint32 iIP) {
|
||||
ClientListEntry* countCLEIPs = 0;
|
||||
void ClientList::GetCLEIP(uint32 in_ip) {
|
||||
ClientListEntry* cle = nullptr;
|
||||
LinkedListIterator<ClientListEntry*> iterator(clientlist);
|
||||
|
||||
int IPInstances = 0;
|
||||
int count = 0;
|
||||
iterator.Reset();
|
||||
|
||||
while(iterator.MoreElements()) {
|
||||
countCLEIPs = iterator.GetData();
|
||||
if ((countCLEIPs->GetIP() == iIP) && ((countCLEIPs->Admin() < (RuleI(World, ExemptMaxClientsStatus))) || (RuleI(World, ExemptMaxClientsStatus) < 0))) { // If the IP matches, and the connection admin status is below the exempt status, or exempt status is less than 0 (no-one is exempt)
|
||||
IPInstances++; // Increment the occurences of this IP address
|
||||
LogClientLogin("Account ID: [{}] Account Name: [{}] IP: [{}]", countCLEIPs->LSID(), countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str());
|
||||
while (iterator.MoreElements()) {
|
||||
cle = iterator.GetData();
|
||||
if (
|
||||
cle->GetIP() == in_ip &&
|
||||
(
|
||||
cle->Admin() < RuleI(World, ExemptMaxClientsStatus) ||
|
||||
RuleI(World, ExemptMaxClientsStatus) < 0
|
||||
)
|
||||
) { // If the IP matches, and the connection admin status is below the exempt status, or exempt status is less than 0 (no-one is exempt)
|
||||
auto ip_string = long2ip(cle->GetIP());
|
||||
count++; // Increment the occurences of this IP address
|
||||
LogClientLogin("Account ID: [{}] Account Name: [{}] IP: [{}]", cle->LSID(), cle->LSName(), ip_string);
|
||||
|
||||
if (RuleB(World, EnableIPExemptions)) {
|
||||
LogClientLogin("Account ID: [{}] Account Name: [{}] IP: [{}] IP Instances: [{}] Max IP Instances: [{}]", countCLEIPs->LSID(), countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str(), IPInstances, database.GetIPExemption(long2ip(countCLEIPs->GetIP()).c_str()));
|
||||
if (IPInstances > database.GetIPExemption(long2ip(countCLEIPs->GetIP()).c_str())) {
|
||||
if(RuleB(World, IPLimitDisconnectAll)) {
|
||||
LogClientLogin("Disconnect: All accounts on IP [{}]", long2ip(countCLEIPs->GetIP()).c_str());
|
||||
DisconnectByIP(iIP);
|
||||
LogClientLogin(
|
||||
"Account ID: [{}] Account Name: [{}] IP: [{}] IP Instances: [{}] Max IP Instances: [{}]",
|
||||
cle->LSID(),
|
||||
cle->LSName(),
|
||||
ip_string,
|
||||
count,
|
||||
database.GetIPExemption(ip_string)
|
||||
);
|
||||
|
||||
auto exemption_amount = database.GetIPExemption(ip_string);
|
||||
if (exemption_amount > 0 && count > exemption_amount) {
|
||||
if (RuleB(World, IPLimitDisconnectAll)) {
|
||||
LogClientLogin("Disconnect: All Accounts on IP [{}]", ip_string);
|
||||
DisconnectByIP(in_ip);
|
||||
return;
|
||||
} else {
|
||||
LogClientLogin("Disconnect: Account [{}] on IP [{}]", countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str());
|
||||
countCLEIPs->SetOnline(CLE_Status::Offline);
|
||||
LogClientLogin("Disconnect: Account [{}] on IP [{}]", cle->LSName(), ip_string);
|
||||
cle->SetOnline(CLE_Status::Offline);
|
||||
iterator.RemoveCurrent();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (IPInstances > (RuleI(World, MaxClientsPerIP))) { // If the number of connections exceeds the lower limit
|
||||
if (
|
||||
RuleI(World, MaxClientsPerIP) > 0 &&
|
||||
count > RuleI(World, MaxClientsPerIP)
|
||||
) { // If the number of connections exceeds the lower limit
|
||||
if (RuleB(World, MaxClientsSetByStatus)) { // If MaxClientsSetByStatus is set to True, override other IP Limit Rules
|
||||
LogClientLogin("Account ID: [{}] Account Name: [{}] IP: [{}] IP Instances: [{}] Max IP Instances: [{}]", countCLEIPs->LSID(), countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str(), IPInstances, countCLEIPs->Admin());
|
||||
if (IPInstances > countCLEIPs->Admin()) { // The IP Limit is set by the status of the account if status > MaxClientsPerIP
|
||||
if(RuleB(World, IPLimitDisconnectAll)) {
|
||||
LogClientLogin("Disconnect: All accounts on IP [{}]", long2ip(countCLEIPs->GetIP()).c_str());
|
||||
DisconnectByIP(iIP);
|
||||
LogClientLogin(
|
||||
"Account ID: [{}] Account Name: [{}] IP: [{}] IP Instances: [{}] Max IP Instances: [{}]",
|
||||
cle->LSID(),
|
||||
cle->LSName(),
|
||||
ip_string,
|
||||
count,
|
||||
cle->Admin()
|
||||
);
|
||||
|
||||
if (count > cle->Admin()) { // The IP Limit is set by the status of the account if status > MaxClientsPerIP
|
||||
if (RuleB(World, IPLimitDisconnectAll)) {
|
||||
LogClientLogin("Disconnect: All Accounts on IP [{}]", ip_string);
|
||||
DisconnectByIP(in_ip);
|
||||
return;
|
||||
} else {
|
||||
LogClientLogin("Disconnect: Account [{}] on IP [{}]", countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str());
|
||||
countCLEIPs->SetOnline(CLE_Status::Offline); // Remove the connection
|
||||
LogClientLogin("Disconnect: Account [{}] on IP [{}]", cle->LSName(), ip_string);
|
||||
cle->SetOnline(CLE_Status::Offline); // Remove the connection
|
||||
iterator.RemoveCurrent();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else if ((countCLEIPs->Admin() < RuleI(World, AddMaxClientsStatus)) || (RuleI(World, AddMaxClientsStatus) < 0)) { // Else if the Admin status of the connection is not eligible for the higher limit, or there is no higher limit (AddMaxClientStatus < 0)
|
||||
if(RuleB(World, IPLimitDisconnectAll)) {
|
||||
LogClientLogin("Disconnect: All accounts on IP [{}]", long2ip(countCLEIPs->GetIP()).c_str());
|
||||
DisconnectByIP(iIP);
|
||||
} else if (
|
||||
cle->Admin() < RuleI(World, AddMaxClientsStatus) ||
|
||||
RuleI(World, AddMaxClientsStatus) < 0
|
||||
) { // Else if the Admin status of the connection is not eligible for the higher limit, or there is no higher limit (AddMaxClientStatus < 0)
|
||||
if (RuleB(World, IPLimitDisconnectAll)) {
|
||||
LogClientLogin("Disconnect: All Accounts on IP [{}]", ip_string);
|
||||
DisconnectByIP(in_ip);
|
||||
return;
|
||||
} else {
|
||||
LogClientLogin("Disconnect: Account [{}] on IP [{}]", countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str());
|
||||
countCLEIPs->SetOnline(CLE_Status::Offline); // Remove the connection
|
||||
LogClientLogin("Disconnect: Account [{}] on IP [{}]", cle->LSName(), ip_string);
|
||||
cle->SetOnline(CLE_Status::Offline); // Remove the connection
|
||||
iterator.RemoveCurrent();
|
||||
continue;
|
||||
}
|
||||
} else if (IPInstances > RuleI(World, AddMaxClientsPerIP)) { // else they are eligible for the higher limit, but if they exceed that
|
||||
if(RuleB(World, IPLimitDisconnectAll)) {
|
||||
LogClientLogin("Disconnect: All accounts on IP [{}]", long2ip(countCLEIPs->GetIP()).c_str());
|
||||
DisconnectByIP(iIP);
|
||||
} else if (
|
||||
RuleI(World, AddMaxClientsPerIP) > 0 &&
|
||||
count > RuleI(World, AddMaxClientsPerIP)
|
||||
) { // else they are eligible for the higher limit, but if they exceed that
|
||||
if (RuleB(World, IPLimitDisconnectAll)) {
|
||||
LogClientLogin("Disconnect: All Accounts on IP [{}]", ip_string);
|
||||
DisconnectByIP(in_ip);
|
||||
return;
|
||||
} else {
|
||||
LogClientLogin("Disconnect: Account [{}] on IP [{}]", countCLEIPs->LSName(), long2ip(countCLEIPs->GetIP()).c_str());
|
||||
countCLEIPs->SetOnline(CLE_Status::Offline); // Remove the connection
|
||||
LogClientLogin("Disconnect: Account [{}] on IP [{}]", cle->LSName(), ip_string);
|
||||
cle->SetOnline(CLE_Status::Offline); // Remove the connection
|
||||
iterator.RemoveCurrent();
|
||||
continue;
|
||||
}
|
||||
@ -168,46 +202,54 @@ void ClientList::GetCLEIP(uint32 iIP) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iterator.Advance();
|
||||
}
|
||||
}
|
||||
|
||||
uint32 ClientList::GetCLEIPCount(uint32 iIP) {
|
||||
ClientListEntry* countCLEIPs = 0;
|
||||
uint32 ClientList::GetCLEIPCount(uint32 in_ip) {
|
||||
ClientListEntry* cle = nullptr;
|
||||
LinkedListIterator<ClientListEntry*> iterator(clientlist);
|
||||
|
||||
int IPInstances = 0;
|
||||
int count = 0;
|
||||
iterator.Reset();
|
||||
|
||||
while (iterator.MoreElements()) {
|
||||
countCLEIPs = iterator.GetData();
|
||||
if ((countCLEIPs->GetIP() == iIP) && ((countCLEIPs->Admin() < (RuleI(World, ExemptMaxClientsStatus))) || (RuleI(World, ExemptMaxClientsStatus) < 0)) && countCLEIPs->Online() >= CLE_Status::Online) { // If the IP matches, and the connection admin status is below the exempt status, or exempt status is less than 0 (no-one is exempt)
|
||||
IPInstances++; // Increment the occurences of this IP address
|
||||
cle = iterator.GetData();
|
||||
if (
|
||||
cle->GetIP() == in_ip &&
|
||||
(
|
||||
cle->Admin() < RuleI(World, ExemptMaxClientsStatus) ||
|
||||
RuleI(World, ExemptMaxClientsStatus) < 0
|
||||
) &&
|
||||
cle->Online() >= CLE_Status::Online
|
||||
) { // If the IP matches, and the connection admin status is below the exempt status, or exempt status is less than 0 (no-one is exempt)
|
||||
count++; // Increment the occurences of this IP address
|
||||
}
|
||||
iterator.Advance();
|
||||
}
|
||||
|
||||
return IPInstances;
|
||||
return count;
|
||||
}
|
||||
|
||||
void ClientList::DisconnectByIP(uint32 iIP) {
|
||||
ClientListEntry* countCLEIPs = 0;
|
||||
void ClientList::DisconnectByIP(uint32 in_ip) {
|
||||
ClientListEntry* cle = nullptr;
|
||||
LinkedListIterator<ClientListEntry*> iterator(clientlist);
|
||||
iterator.Reset();
|
||||
|
||||
while(iterator.MoreElements()) {
|
||||
countCLEIPs = iterator.GetData();
|
||||
if ((countCLEIPs->GetIP() == iIP)) {
|
||||
if(strlen(countCLEIPs->name())) {
|
||||
while (iterator.MoreElements()) {
|
||||
cle = iterator.GetData();
|
||||
if (cle->GetIP() == in_ip) {
|
||||
if (strlen(cle->name())) {
|
||||
auto pack = new ServerPacket(ServerOP_KickPlayer, sizeof(ServerKickPlayer_Struct));
|
||||
ServerKickPlayer_Struct* skp = (ServerKickPlayer_Struct*) pack->pBuffer;
|
||||
strcpy(skp->adminname, "SessionLimit");
|
||||
strcpy(skp->name, countCLEIPs->name());
|
||||
auto skp = (ServerKickPlayer_Struct*) pack->pBuffer;
|
||||
strn0cpy(skp->adminname, "SessionLimit", sizeof(skp->adminname));
|
||||
strn0cpy(skp->name, cle->name(), sizeof(skp->name));
|
||||
skp->adminrank = 255;
|
||||
zoneserver_list.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
countCLEIPs->SetOnline(CLE_Status::Offline);
|
||||
cle->SetOnline(CLE_Status::Offline);
|
||||
iterator.RemoveCurrent();
|
||||
}
|
||||
iterator.Advance();
|
||||
|
||||
@ -57,9 +57,9 @@ public:
|
||||
ClientListEntry* FindCLEByCharacterID(uint32 iCharID);
|
||||
ClientListEntry* FindCLEByLSID(uint32 iLSID);
|
||||
ClientListEntry* GetCLE(uint32 iID);
|
||||
void GetCLEIP(uint32 iIP);
|
||||
void GetCLEIP(uint32 in_ip);
|
||||
uint32 GetCLEIPCount(uint32 iLSAccountID);
|
||||
void DisconnectByIP(uint32 iIP);
|
||||
void DisconnectByIP(uint32 in_ip);
|
||||
void CLCheckStale();
|
||||
void CLEKeepAlive(uint32 numupdates, uint32* wid);
|
||||
void CLEAdd(uint32 iLSID, const char* iLoginServerName, const char* iLoginName, const char* iLoginKey, int16 iWorldAdmin = AccountStatus::Player, uint32 ip = 0, uint8 local=0);
|
||||
|
||||
@ -44,6 +44,7 @@
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/platform.h"
|
||||
#include "../common/crash.h"
|
||||
#include "../common/misc.h"
|
||||
#include "client.h"
|
||||
#include "worlddb.h"
|
||||
|
||||
@ -658,7 +659,7 @@ int main(int argc, char **argv)
|
||||
eqsm.OnNewConnection(
|
||||
[&stream_identifier](std::shared_ptr<EQ::Net::EQStream> stream) {
|
||||
stream_identifier.AddStream(stream);
|
||||
LogInfo("New connection from IP {0}:{1}", stream->GetRemoteIP(), ntohs(stream->GetRemotePort()));
|
||||
LogInfo("New connection from IP {}:{}", long2ip(stream->GetRemoteIP()), ntohs(stream->GetRemotePort()));
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@ -36,6 +36,7 @@
|
||||
#include "../common/memory_mapped_file.h"
|
||||
#include "../common/spdat.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/misc.h"
|
||||
|
||||
#include "api_service.h"
|
||||
#include "zone_config.h"
|
||||
@ -514,7 +515,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
eqsm->OnNewConnection([&stream_identifier](std::shared_ptr<EQ::Net::EQStream> stream) {
|
||||
stream_identifier.AddStream(stream);
|
||||
LogF(Logs::Detail, Logs::WorldServer, "New connection from IP {0}:{1}", stream->GetRemoteIP(), ntohs(stream->GetRemotePort()));
|
||||
LogInfo("New connection from IP {}:{}", long2ip(stream->GetRemoteIP()), ntohs(stream->GetRemotePort()));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user