Merge branch 'battle.net' into 4.3.4

This commit is contained in:
Shauren
2014-06-08 16:14:24 +02:00
63 changed files with 4346 additions and 259 deletions

View File

@@ -79,4 +79,9 @@ namespace AuthHelper
return NULL;
}
bool IsBuildSupportingBattlenet(int build)
{
return build >= 15595;
}
}

View File

@@ -70,6 +70,96 @@ enum LoginResult
LOGIN_LOCKED_ENFORCED = 0x10
};
enum GameAccountFlags
{
GAMEACCOUNT_FLAG_GM = 0x00000001,
GAMEACCOUNT_FLAG_NOKICK = 0x00000002,
GAMEACCOUNT_FLAG_COLLECTOR = 0x00000004,
GAMEACCOUNT_FLAG_WOW_TRIAL = 0x00000008,
GAMEACCOUNT_FLAG_CANCELLED = 0x00000010,
GAMEACCOUNT_FLAG_IGR = 0x00000020,
GAMEACCOUNT_FLAG_WHOLESALER = 0x00000040,
GAMEACCOUNT_FLAG_PRIVILEGED = 0x00000080,
GAMEACCOUNT_FLAG_EU_FORBID_ELV = 0x00000100,
GAMEACCOUNT_FLAG_EU_FORBID_BILLING = 0x00000200,
GAMEACCOUNT_FLAG_WOW_RESTRICTED = 0x00000400,
GAMEACCOUNT_FLAG_REFERRAL = 0x00000800,
GAMEACCOUNT_FLAG_BLIZZARD = 0x00001000,
GAMEACCOUNT_FLAG_RECURRING_BILLING = 0x00002000,
GAMEACCOUNT_FLAG_NOELECTUP = 0x00004000,
GAMEACCOUNT_FLAG_KR_CERTIFICATE = 0x00008000,
GAMEACCOUNT_FLAG_EXPANSION_COLLECTOR = 0x00010000,
GAMEACCOUNT_FLAG_DISABLE_VOICE = 0x00020000,
GAMEACCOUNT_FLAG_DISABLE_VOICE_SPEAK = 0x00040000,
GAMEACCOUNT_FLAG_REFERRAL_RESURRECT = 0x00080000,
GAMEACCOUNT_FLAG_EU_FORBID_CC = 0x00100000,
GAMEACCOUNT_FLAG_OPENBETA_DELL = 0x00200000,
GAMEACCOUNT_FLAG_PROPASS = 0x00400000,
GAMEACCOUNT_FLAG_PROPASS_LOCK = 0x00800000,
GAMEACCOUNT_FLAG_PENDING_UPGRADE = 0x01000000,
GAMEACCOUNT_FLAG_RETAIL_FROM_TRIAL = 0x02000000,
GAMEACCOUNT_FLAG_EXPANSION2_COLLECTOR = 0x04000000,
GAMEACCOUNT_FLAG_OVERMIND_LINKED = 0x08000000,
GAMEACCOUNT_FLAG_DEMOS = 0x10000000,
GAMEACCOUNT_FLAG_DEATH_KNIGHT_OK = 0x20000000,
};
namespace Battlenet
{
enum AuthResult
{
AUTH_OK = 0,
AUTH_INTERNAL_ERROR = 100,
AUTH_CORRUPTED_MODULE = 102,
AUTH_BAD_SERVER_PROOF = 103,
AUTH_UNKNOWN_ACCOUNT = 104,
AUTH_CLOSED = 105,
AUTH_LOGIN_TIMEOUT = 106,
AUTH_NO_GAME_ACCOUNTS = 107,
AUTH_INVALID_TOKEN = 108,
AUTH_INVALID_PROGRAM = 109,
AUTH_INVALID_OS = 110,
AUTH_UNSUPPORTED_LANGUAGE = 111,
AUTH_REGION_BAD_VERSION = 112,
AUTH_TEMP_OUTAGE = 113,
AUTH_CANT_DOWNLOAD_MODULE = 114,
AUTH_DUPLICATE_LOGON = 115,
AUTH_BAD_CREDENTIALS_2 = 116,
AUTH_VERSION_CHECK_SUCCEEDED = 117,
AUTH_BAD_VERSION_HASH = 118,
AUTH_CANT_RETRIEVE_PORTAL_LIST = 119,
AUTH_DARK_PORTAL_DOES_NOT_EXIST = 120,
AUTH_DARK_PORTAL_FILE_CORRUPTED = 121,
AUTH_BATTLENET_MAINTENANCE = 122,
AUTH_LOGON_TOO_FAST = 123,
AUTH_USE_GRUNT_LOGON = 124,
AUTH_NO_GAME_ACCOUNTS_IN_REGION = 140,
AUTH_ACCOUNT_LOCKED = 141,
LOGIN_SERVER_BUSY = 200,
LOGIN_NO_GAME_ACCOUNT = 201,
LOGIN_BANNED = 202,
LOGIN_SUSPENDED = 203,
LOGIN_GAME_ACCOUNT_LOCKED = 204,
LOGIN_ALREADY_ONLINE = 205,
LOGIN_NOTIME = 206,
LOGIN_EXPIRED = 207,
LOGIN_EXPIRED_2 = 208,
LOGIN_PARENTALCONTROL = 209,
LOGIN_TRIAL_EXPIRED = 210,
LOGIN_ANTI_INDULGENCE = 211,
LOGIN_INCORRECT_REGION = 212,
LOGIN_LOCKED_ENFORCED = 213,
LOGIN_CHARGEBACK = 214,
LOGIN_IGR_WITHOUT_BNET = 215,
LOGIN_UNLOCKABLE_LOCK = 216,
LOGIN_IGR_REQUIRED = 217,
LOGIN_PAYMENT_CHANGED = 218,
LOGIN_INVALID_PAYMENT = 219,
LOGIN_INVALID_ACCOUNT_STATE = 220
};
}
enum ExpansionFlags
{
POST_BC_EXP_FLAG = 0x2,
@@ -92,6 +182,7 @@ namespace AuthHelper
bool IsAcceptedClientBuild(int build);
bool IsPostBCAcceptedClientBuild(int build);
bool IsPreBCAcceptedClientBuild(int build);
bool IsBuildSupportingBattlenet(int build);
}
#endif

View File

@@ -151,7 +151,8 @@ extern int main(int argc, char** argv)
}
// Launch the listening network socket
RealmAcceptor acceptor;
RealmAcceptor<AuthSocket> acceptor;
RealmAcceptor<Battlenet::Socket> bnetacceptor;
int32 rmport = sConfigMgr->GetIntDefault("RealmServerPort", 3724);
if (rmport < 0 || rmport > 0xFFFF)
@@ -170,6 +171,13 @@ extern int main(int argc, char** argv)
return 1;
}
bind_addr.set_port_number(1119);
if (bnetacceptor.open(bind_addr, ACE_Reactor::instance(), ACE_NONBLOCK) == -1)
{
TC_LOG_ERROR("server.authserver", "Auth server can not bind to %s:%d", bind_ip.c_str(), 1119);
return 1;
}
// Initialize the signal handlers
AuthServerSignalHandler SignalINT, SignalTERM;
@@ -246,6 +254,8 @@ extern int main(int argc, char** argv)
#endif
#endif
sBattlenetMgr->Load();
// maximum counter for next ping
uint32 numLoops = (sConfigMgr->GetIntDefault("MaxPingTime", 30) * (MINUTE * 1000000 / 100000));
uint32 loopCounter = 0;

View File

@@ -18,9 +18,29 @@
#include "Common.h"
#include "RealmList.h"
#include "BattlenetManager.h"
#include "Database/DatabaseEnv.h"
#include "Util.h"
RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)) { }
ACE_INET_Addr const& Realm::GetAddressForClient(ACE_INET_Addr const& clientAddr) const
{
// Attempt to send best address for client
if (clientAddr.is_loopback())
// Assume that user connecting from the machine that authserver is located on
// has all realms available in his local network
return LocalAddress;
// Check if connecting client is in the same network
if (IsIPAddrInNetwork(LocalAddress, clientAddr, LocalSubnetMask))
return LocalAddress;
// Return external IP
return ExternalAddress;
}
RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL))
{
}
// Load the realm list from the database
void RealmList::Initialize(uint32 updateInterval)
@@ -31,7 +51,7 @@ void RealmList::Initialize(uint32 updateInterval)
UpdateRealms(true);
}
void RealmList::UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build)
void RealmList::UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build, uint8 region, uint8 battlegroup)
{
// Create new if not exist or update existed
Realm& realm = m_realms[name];
@@ -49,6 +69,8 @@ void RealmList::UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr co
realm.LocalAddress = localAddr;
realm.LocalSubnetMask = localSubmask;
realm.gamebuild = build;
realm.Region = region;
realm.Battlegroup = battlegroup;
}
void RealmList::UpdateIfNeed()
@@ -91,12 +113,14 @@ void RealmList::UpdateRealms(bool init)
uint8 allowedSecurityLevel = fields[9].GetUInt8();
float pop = fields[10].GetFloat();
uint32 build = fields[11].GetUInt32();
uint8 region = fields[12].GetUInt8();
uint8 battlegroup = fields[13].GetUInt8();
ACE_INET_Addr externalAddr(port, externalAddress.c_str(), AF_INET);
ACE_INET_Addr localAddr(port, localAddress.c_str(), AF_INET);
ACE_INET_Addr submask(0, localSubmask.c_str(), AF_INET);
UpdateRealm(realmId, name, externalAddr, localAddr, submask, icon, flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build);
UpdateRealm(realmId, name, externalAddr, localAddr, submask, icon, flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build, region, battlegroup);
if (init)
TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.get_host_addr(), port);
@@ -104,3 +128,16 @@ void RealmList::UpdateRealms(bool init)
while (result->NextRow());
}
}
Realm const* RealmList::GetRealm(Battlenet::RealmId const& id) const
{
auto itr = std::find_if(m_realms.begin(), m_realms.end(), [id](RealmMap::value_type const& pair)
{
return pair.second.Region == id.Region && pair.second.Battlegroup == id.Battlegroup && pair.second.m_ID == id.Index;
});
if (itr != m_realms.end())
return &itr->second;
return NULL;
}

View File

@@ -51,8 +51,17 @@ struct Realm
AccountTypes allowedSecurityLevel;
float populationLevel;
uint32 gamebuild;
uint8 Region;
uint8 Battlegroup;
ACE_INET_Addr const& GetAddressForClient(ACE_INET_Addr const& clientAddr) const;
};
namespace Battlenet
{
struct RealmId;
}
/// Storage object for the list of realms on the server
class RealmList
{
@@ -71,10 +80,11 @@ public:
RealmMap::const_iterator begin() const { return m_realms.begin(); }
RealmMap::const_iterator end() const { return m_realms.end(); }
uint32 size() const { return m_realms.size(); }
Realm const* GetRealm(Battlenet::RealmId const& id) const;
private:
void UpdateRealms(bool init=false);
void UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build);
void UpdateRealm(uint32 id, const std::string& name, ACE_INET_Addr const& address, ACE_INET_Addr const& localAddr, ACE_INET_Addr const& localSubmask, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float popu, uint32 build, uint8 region, uint8 battlegroup);
RealmMap m_realms;
uint32 m_UpdateInterval;

View File

@@ -293,19 +293,11 @@ void AuthSocket::_SetVSFields(const std::string& rI)
x.SetBinary(sha.GetDigest(), sha.GetLength());
v = g.ModExp(x, N);
// No SQL injection (username escaped)
char *v_hex, *s_hex;
v_hex = v.AsHexStr();
s_hex = s.AsHexStr();
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_VS);
stmt->setString(0, v_hex);
stmt->setString(1, s_hex);
stmt->setString(0, v.AsHexStr());
stmt->setString(1, s.AsHexStr());
stmt->setString(2, _login);
LoginDatabase.Execute(stmt);
OPENSSL_free(v_hex);
OPENSSL_free(s_hex);
}
// Logon Challenge command handler
@@ -488,7 +480,9 @@ bool AuthSocket::_HandleLogonChallenge()
unk3.SetRand(16 * 8);
// Fill the response packet with the result
if (AuthHelper::IsAcceptedClientBuild(_build))
if (fields[9].GetUInt32() && AuthHelper::IsBuildSupportingBattlenet(_build))
pkt << uint8(WOW_FAIL_USE_BATTLENET);
else if (AuthHelper::IsAcceptedClientBuild(_build))
pkt << uint8(WOW_SUCCESS);
else
pkt << uint8(WOW_FAIL_VERSION_INVALID);
@@ -650,19 +644,14 @@ bool AuthSocket::_HandleLogonProof()
TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str());
// Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account
// No SQL injection (escaped user name) and IP address as received by socket
const char *K_hex = K.AsHexStr();
PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF);
stmt->setString(0, K_hex);
stmt->setString(0, K.AsHexStr());
stmt->setString(1, socket().getRemoteAddress().c_str());
stmt->setUInt32(2, GetLocaleByName(_localizationName));
stmt->setString(3, _os);
stmt->setString(4, _login);
LoginDatabase.DirectExecute(stmt);
OPENSSL_free((void*)K_hex);
// Finish SRP6 and send the final result to the client
sha.Initialize();
sha.UpdateBigNumbers(&A, &M, &K, NULL);
@@ -693,7 +682,7 @@ bool AuthSocket::_HandleLogonProof()
memcpy(proof.M2, sha.GetDigest(), 20);
proof.cmd = AUTH_LOGON_PROOF;
proof.error = 0;
proof.unk1 = 0x00800000; // Accountflags. 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament)
proof.unk1 = GAMEACCOUNT_FLAG_PROPASS_LOCK;
proof.unk2 = 0x00; // SurveyId
proof.unk3 = 0x00;
socket().send((char *)&proof, sizeof(proof));
@@ -879,28 +868,6 @@ bool AuthSocket::_HandleReconnectProof()
}
}
ACE_INET_Addr const& AuthSocket::GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr)
{
// Attempt to send best address for client
if (clientAddr.is_loopback())
{
// Try guessing if realm is also connected locally
if (realm.LocalAddress.is_loopback() || realm.ExternalAddress.is_loopback())
return clientAddr;
// Assume that user connecting from the machine that authserver is located on
// has all realms available in his local network
return realm.LocalAddress;
}
// Check if connecting client is in the same network
if (IsIPAddrInNetwork(realm.LocalAddress, clientAddr, realm.LocalSubnetMask))
return realm.LocalAddress;
// Return external IP
return realm.ExternalAddress;
}
// Realm List command handler
bool AuthSocket::_HandleRealmList()
{
@@ -981,12 +948,12 @@ bool AuthSocket::_HandleRealmList()
pkt << lock; // if 1, then realm locked
pkt << uint8(flag); // RealmFlags
pkt << name;
pkt << GetAddressString(GetAddressForClient(realm, clientAddr));
pkt << GetAddressString(realm.GetAddressForClient(clientAddr));
pkt << realm.populationLevel;
pkt << AmountOfCharacters;
pkt << realm.timezone; // realm category
if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients
pkt << uint8(0x2C); // unk, may be realm number/id?
pkt << uint8(realm.m_ID);
else
pkt << uint8(0x0); // 1.12.1 and 1.12.2 clients

View File

@@ -39,8 +39,6 @@ public:
virtual void OnAccept(void);
virtual void OnClose(void);
static ACE_INET_Addr const& GetAddressForClient(Realm const& realm, ACE_INET_Addr const& clientAddr);
bool _HandleLogonChallenge();
bool _HandleLogonProof();
bool _HandleReconnectChallenge();

View File

@@ -0,0 +1,220 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://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/>.
*/
#ifndef __BATTLENETBITSTREAM_H__
#define __BATTLENETBITSTREAM_H__
#include "ByteConverter.h"
#include <exception>
#include <string>
#include <vector>
#include <type_traits>
#include <ace/Auto_Ptr.h>
#include <ace/Stack_Trace.h>
namespace Battlenet
{
class BitStreamPositionException : public std::exception
{
public:
BitStreamPositionException() : st(1) { }
char const* what() const
{
return st.c_str();
}
ACE_Stack_Trace st;
};
class BitStream
{
public:
static uint32 const MaxSize = 0x1000;
// length : The maximum number of bytes to read
BitStream(uint32 length) : _numBits(length * 8), _readPos(0), _writePos(0)
{
_buffer.resize(length, 0);
}
BitStream() : _numBits(0), _readPos(0), _writePos(0)
{
_buffer.reserve(0x1000);
}
void AlignToNextByte()
{
_readPos = (_readPos + 7) & ~7;
_writePos = (_writePos + 7) & ~7;
}
std::string ReadString(uint32 bitCount, int32 baseLength = 0)
{
uint32 len = Read<uint32>(bitCount) + baseLength;
AlignToNextByte();
std::string str(reinterpret_cast<char*>(&_buffer[_readPos >> 3]), len);
_readPos += len * 8;
return str;
}
ACE_Auto_Array_Ptr<uint8> ReadBytes(uint32 count)
{
AlignToNextByte();
if (_readPos + count * 8 > _numBits)
throw BitStreamPositionException();
ACE_Auto_Array_Ptr<uint8> buf(new uint8[count]);
memcpy(buf.get(), &_buffer[_readPos >> 3], count);
_readPos += count * 8;
return buf;
}
float ReadFloat()
{
uint32 val = Read<uint32>(32);
return *reinterpret_cast<float*>(&val);
}
std::string ReadFourCC()
{
uint32 fcc = Read<uint32>(32);
EndianConvertReverse(fcc);
size_t len = 4;
while (!(fcc & 0xFF))
{
fcc >>= 8;
--len;
}
return std::string(reinterpret_cast<char*>(&fcc), len);
}
template<typename T>
T Read(uint32 bitCount)
{
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "T must be an integer type");
uint64 ret = 0;
while (bitCount != 0)
{
uint32 bitPos = (_readPos & 7);
uint32 bitsLeftInByte = 8 - bitPos;
if (bitsLeftInByte >= bitCount)
bitsLeftInByte = bitCount;
bitCount -= bitsLeftInByte;
ret |= (uint64)(_buffer[_readPos >> 3] >> bitPos & (uint32)((uint8)(1 << bitsLeftInByte) - 1)) << bitCount;
_readPos += bitsLeftInByte;
}
return static_cast<T>(ret);
}
void WriteString(std::string const& str, uint32 bitCount, int32 baseLength = 0)
{
Write(str.length() + baseLength, bitCount);
WriteBytes(str.c_str(), str.length());
}
template<typename T>
void WriteBytes(T* data, uint32 count)
{
AlignToNextByte();
if (!count || !data)
return;
if ((_writePos >> 3) + count > MaxSize)
throw BitStreamPositionException();
_buffer.resize(_buffer.size() + count);
memcpy(&_buffer[_writePos >> 3], data, count);
_writePos += count * 8;
}
void WriteFloat(float value)
{
uint32 intVal = *reinterpret_cast<uint32*>(&value);
Write(intVal, 32);
}
void WriteFourCC(std::string const& fcc)
{
uint32 intVal = *(uint32*)fcc.c_str();
size_t len = fcc.length();
EndianConvertReverse(intVal);
// Add padding
while (len++ < 4)
intVal >>= 8;
Write(intVal, 32);
}
template<typename T>
void Write(T value, uint32 bitCount)
{
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "T must be an integer type");
if (_writePos + bitCount >= 8 * MaxSize)
throw BitStreamPositionException();
while (bitCount != 0)
{
uint32 bitPos = (_writePos & 7);
uint32 bitsLeftInByte = 8 - bitPos;
if (bitsLeftInByte >= bitCount)
bitsLeftInByte = bitCount;
bitCount -= bitsLeftInByte;
uint8 firstHalf = (uint8)(~(((uint8)(1 << bitsLeftInByte) - 1) << bitPos));
uint8 secondHalf = (uint8)((((uint8)(1 << bitsLeftInByte) - 1) & (uint8)(value >> bitCount)) << bitPos);
if (_buffer.size() > (_writePos >> 3))
_buffer[_writePos >> 3] = (uint8)(_buffer[_writePos >> 3] & firstHalf | secondHalf);
else
_buffer.push_back(secondHalf);
_writePos += bitsLeftInByte;
}
}
void SetReadPos(uint32 bits)
{
if (bits >= _numBits)
throw BitStreamPositionException();
_readPos = bits;
}
bool IsRead() const { return _readPos >= _numBits; }
uint8* GetBuffer() { return _buffer.data(); }
size_t GetSize() const { return _buffer.size(); }
void FinishReading() { _readPos = _numBits; }
private:
std::vector<uint8> _buffer;
uint32 _numBits;
uint32 _readPos;
uint32 _writePos;
};
}
#endif // __BATTLENETBITSTREAM_H__

View File

@@ -0,0 +1,96 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://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 "BattlenetManager.h"
#include "DatabaseEnv.h"
BattlenetMgr::~BattlenetMgr()
{
for (Battlenet::Component* component : _components)
delete component;
for (auto const& m : _modules)
delete m.second;
}
void BattlenetMgr::Load()
{
LoadComponents();
LoadModules();
}
void BattlenetMgr::LoadComponents()
{
QueryResult result = LoginDatabase.Query("SELECT Program, Platform, Build FROM battlenet_components");
if (result)
{
do
{
Field* fields = result->Fetch();
Battlenet::Component* component = new Battlenet::Component();
component->Program = fields[0].GetString();
component->Platform = fields[1].GetString();
component->Build = fields[2].GetUInt32();
_components.insert(component);
_programs.insert(component->Program);
_platforms.insert(component->Platform);
} while (result->NextRow());
}
}
void BattlenetMgr::LoadModules()
{
QueryResult result = LoginDatabase.Query("SELECT `Hash`, `Name`, `Type`, `System`, `Data` FROM battlenet_modules");
if (result)
{
do
{
Field* fields = result->Fetch();
Battlenet::ModuleInfo* module = new Battlenet::ModuleInfo();
module->Type = fields[2].GetString();
HexStrToByteArray(fields[0].GetString(), module->ModuleId);
std::string data = fields[4].GetString();
module->DataSize = data.length() / 2;
if (module->DataSize)
{
module->Data = new uint8[data.length() / 2];
HexStrToByteArray(data, module->Data);
}
_modules[{ fields[3].GetString(), fields[1].GetString() }] = module;
} while (result->NextRow());
}
}
bool BattlenetMgr::HasComponent(Battlenet::Component const* component) const
{
for (Battlenet::Component const* c : _components)
if (component->Program == c->Program && component->Platform == c->Platform && component->Build == c->Build)
return true;
return false;
}
Battlenet::ModuleInfo* BattlenetMgr::CreateModule(std::string const& os, std::string const& name) const
{
Battlenet::ModuleKey key { os, name };
ASSERT(_modules.count(key));
return new Battlenet::ModuleInfo(*_modules.at(key));
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://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/>.
*/
#ifndef __BATTLENETMANAGER_H__
#define __BATTLENETMANAGER_H__
#include "Define.h"
#include <ace/Singleton.h>
#include <string>
#include <set>
#include <map>
namespace Battlenet
{
struct Component
{
std::string Program;
std::string Platform;
uint32 Build;
};
struct ModuleKey
{
std::string Platform;
std::string Name;
bool operator<(ModuleKey const& right) const
{
int32 res = Platform.compare(right.Platform);
if (res < 0)
return true;
else if (res > 0)
return false;
return Name < right.Name;
}
};
struct ModuleInfo
{
ModuleInfo() : Region("EU"), DataSize(0), Data(nullptr) { }
ModuleInfo(ModuleInfo const& right) : Type(right.Type), Region(right.Region), DataSize(right.DataSize), Data(nullptr)
{
memcpy(ModuleId, right.ModuleId, 32);
if (DataSize)
{
Data = new uint8[DataSize];
memcpy(Data, right.Data, DataSize);
}
}
~ModuleInfo()
{
delete Data;
}
std::string Type;
std::string Region;
uint8 ModuleId[32];
uint32 DataSize;
uint8* Data;
};
struct RealmId
{
uint8 Region;
uint8 Battlegroup;
uint32 Index;
uint32 Build;
};
}
class BattlenetMgr
{
friend class ACE_Singleton<BattlenetMgr, ACE_Null_Mutex>;
BattlenetMgr() { }
~BattlenetMgr();
public:
void Load();
bool HasComponent(Battlenet::Component const* component) const;
bool HasProgram(std::string const& program) const { return _programs.count(program); }
bool HasPlatform(std::string const& platform) const { return _platforms.count(platform); }
Battlenet::ModuleInfo* CreateModule(std::string const& os, std::string const& name) const;
private:
void LoadComponents();
void LoadModules();
std::set<Battlenet::Component*> _components;
std::set<std::string> _programs;
std::set<std::string> _platforms;
std::map<Battlenet::ModuleKey, Battlenet::ModuleInfo*> _modules;
};
#define sBattlenetMgr ACE_Singleton<BattlenetMgr, ACE_Null_Mutex>::instance()
#endif // __BATTLENETMANAGER_H__

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://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 "BattlenetPacketCrypt.h"
#include "Cryptography/HmacHash.h"
#include "Cryptography/BigNumber.h"
Battlenet::PacketCrypt::PacketCrypt() : ::PacketCrypt(SHA256_DIGEST_LENGTH)
{
}
void Battlenet::PacketCrypt::Init(BigNumber* K)
{
uint8 ServerEncryptionKey[SEED_KEY_SIZE] = { 0x68, 0xE0, 0xC7, 0x2E, 0xDD, 0xD6, 0xD2, 0xF3, 0x1E, 0x5A, 0xB1, 0x55, 0xB1, 0x8B, 0x63, 0x1E };
uint8 ClientDecryptionKey[SEED_KEY_SIZE] = { 0xDE, 0xA9, 0x65, 0xAE, 0x54, 0x3A, 0x1E, 0x93, 0x9E, 0x69, 0x0C, 0xAA, 0x68, 0xDE, 0x78, 0x39 };
HmacSha256 serverEncryptHmac(K->GetNumBytes(), K->AsByteArray().get());
serverEncryptHmac.UpdateData(ServerEncryptionKey, SEED_KEY_SIZE);
serverEncryptHmac.Finalize();
HmacSha256 clientDecryptHmac(K->GetNumBytes(), K->AsByteArray().get());
clientDecryptHmac.UpdateData(ClientDecryptionKey, SEED_KEY_SIZE);
clientDecryptHmac.Finalize();
_clientDecrypt.Init(clientDecryptHmac.GetDigest());
_serverEncrypt.Init(serverEncryptHmac.GetDigest());
_initialized = true;
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://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/>.
*/
#ifndef __BATTLENETPACKETCRYPT_H__
#define __BATTLENETPACKETCRYPT_H__
#include "PacketCrypt.h"
class BigNumber;
namespace Battlenet
{
class PacketCrypt : public ::PacketCrypt
{
public:
PacketCrypt();
void Init(BigNumber* K) override;
};
}
#endif // __BATTLENETPACKETCRYPT_H__

View File

@@ -0,0 +1,449 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://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 "BattlenetPackets.h"
#include "Common.h"
#include "Util.h"
#include <limits>
#include <sstream>
std::string Battlenet::PacketHeader::ToString() const
{
std::ostringstream stream;
stream << "Battlenet::PacketHeader opcode: " << Opcode << ", channel: " << Channel;
return stream.str();
}
Battlenet::ServerPacket::ServerPacket(PacketHeader const& header) : Packet(header, *new BitStream())
{
_stream.Write(header.Opcode, 6);
_stream.Write(1, 1);
_stream.Write(header.Channel, 4);
}
Battlenet::ServerPacket::~ServerPacket()
{
delete &_stream;
}
void Battlenet::AuthChallenge::Read()
{
Program = _stream.ReadFourCC();
Platform = _stream.ReadFourCC();
Locale = _stream.ReadFourCC();
Components.resize(_stream.Read<uint32>(6));
for (size_t i = 0; i < Components.size(); ++i)
{
Component& component = Components[i];
component.Program = _stream.ReadFourCC();
component.Platform = _stream.ReadFourCC();
component.Build = _stream.Read<uint32>(32);
}
if (_stream.Read<uint32>(1))
Login = _stream.ReadString(9, 3);
}
std::string Battlenet::AuthChallenge::ToString() const
{
std::ostringstream stream;
stream << "Battlenet::AuthChallenge Program: " << Program << ", Platform: " << Platform << ", Locale: " << Locale;
for (Component const& component : Components)
stream << std::endl << "Battlenet::Component Program: " << component.Program << ", Platform: " << component.Platform << ", Build: " << component.Build;
if (!Login.empty())
stream << std::endl << "Battlenet::AuthChallenge Login: " << Login;
return stream.str();
}
void Battlenet::AuthResumeInfo::Read()
{
Program = _stream.ReadFourCC();
Platform = _stream.ReadFourCC();
Locale = _stream.ReadFourCC();
Components.resize(_stream.Read<uint32>(6));
for (size_t i = 0; i < Components.size(); ++i)
{
Component& component = Components[i];
component.Program = _stream.ReadFourCC();
component.Platform = _stream.ReadFourCC();
component.Build = _stream.Read<uint32>(32);
}
Login = _stream.ReadString(9, 3);
Region = _stream.Read<uint8>(8);
GameAccountName = _stream.ReadString(5, 1);
}
std::string Battlenet::AuthResumeInfo::ToString() const
{
std::ostringstream stream;
stream << "Battlenet::AuthReconnect Program: " << Program << ", Platform: " << Platform << ", Locale: " << Locale;
for (Component const& component : Components)
stream << std::endl << "Battlenet::Component Program: " << component.Program << ", Platform: " << component.Platform << ", Build: " << component.Build;
stream << std::endl << "Battlenet::AuthReconnect Login: " << Login;
stream << std::endl << "Battlenet::AuthReconnect Region: " << uint32(Region);
stream << std::endl << "Battlenet::AuthReconnect GameAccountName: " << GameAccountName;
return stream.str();
}
Battlenet::ProofRequest::~ProofRequest()
{
for (size_t i = 0; i < Modules.size(); ++i)
delete Modules[i];
}
void Battlenet::ProofRequest::Write()
{
_stream.Write(Modules.size(), 3);
for (ModuleInfo const* info : Modules)
{
_stream.WriteBytes(info->Type.c_str(), 4);
_stream.WriteFourCC(info->Region);
_stream.WriteBytes(info->ModuleId, 32);
_stream.Write(info->DataSize, 10);
_stream.WriteBytes(info->Data, info->DataSize);
}
}
std::string Battlenet::ProofRequest::ToString() const
{
std::ostringstream stream;
stream << "Battlenet::ProofRequest modules " << Modules.size();
for (ModuleInfo const* module : Modules)
stream << std::endl << "Battlenet::ModuleInfo Locale " << module->Region.c_str() << ", ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << ", DataSize " << module->DataSize << ", Data " << ByteArrayToHexStr(module->Data, module->DataSize);
return stream.str();
}
Battlenet::ProofResponse::~ProofResponse()
{
for (size_t i = 0; i < Modules.size(); ++i)
delete Modules[i];
}
void Battlenet::ProofResponse::Read()
{
Modules.resize(_stream.Read<uint32>(3));
for (size_t i = 0; i < Modules.size(); ++i)
{
BitStream*& dataStream = Modules[i];
dataStream = new BitStream(_stream.Read<uint32>(10));
memcpy(dataStream->GetBuffer(), _stream.ReadBytes(dataStream->GetSize()).get(), dataStream->GetSize());
}
}
std::string Battlenet::ProofResponse::ToString() const
{
std::ostringstream stream;
stream << "Battlenet::ProofResponse Modules " << Modules.size();
for (BitStream* module : Modules)
{
std::string hexStr = ByteArrayToHexStr(module->GetBuffer(), module->GetSize());
stream << std::endl << "Battlenet::ProofResponse::ModuleData Size: " << module->GetSize() << ", Data: " << hexStr;
}
return stream.str();
}
Battlenet::AuthComplete::~AuthComplete()
{
for (ModuleInfo* m : Modules)
delete m;
}
void Battlenet::AuthComplete::Write()
{
_stream.Write(Result != 0, 1);
if (Result == 0)
{
_stream.Write(Modules.size(), 3);
for (size_t i = 0; i < Modules.size(); ++i)
{
ModuleInfo* info = Modules[i];
_stream.WriteBytes(info->Type.c_str(), 4);
_stream.WriteFourCC(info->Region);
_stream.WriteBytes(info->ModuleId, 32);
_stream.Write(info->DataSize, 10);
_stream.WriteBytes(info->Data, info->DataSize);
}
_stream.Write(PingTimeout + std::numeric_limits<int32>::min(), 32);
_stream.Write(1, 1);
// if written == 1
{
_stream.Write(1, 1);
// if written == 1
{
_stream.Write(Threshold, 32);
_stream.Write(Rate, 32);
}
}
_stream.WriteString(FirstName, 8); // First name
_stream.WriteString(LastName, 8); // Last name - not set for WoW
_stream.Write(AccountId, 32);
_stream.Write(Region, 8);
_stream.Write(0, 64);
_stream.Write(GameAccountRegion, 8);
_stream.WriteString(GameAccountName, 5, -1);
_stream.Write(GameAccountFlags, 64);
_stream.Write(0, 32);
}
else
{
_stream.Write(!Modules.empty(), 1);
if (!Modules.empty())
{
ModuleInfo* info = Modules[0];
_stream.WriteBytes(info->Type.c_str(), 4);
_stream.WriteFourCC(info->Region);
_stream.WriteBytes(info->ModuleId, 32);
}
_stream.Write(ErrorType, 2);
if (ErrorType == 1)
{
_stream.Write(Result, 16);
_stream.Write(0x80000000, 32);
}
}
}
std::string Battlenet::AuthComplete::ToString() const
{
std::ostringstream stream;
stream << "Battlenet::AuthComplete AuthResult " << Result << " PingTimeout " << PingTimeout << " Threshold " << Threshold << " Rate " << Rate
<< " FirstName " << FirstName << " LastName " << LastName << " AccountId " << AccountId << " Region " << uint32(Region) << " GameAccountName " << GameAccountName
<< " GameAccountFlags " << GameAccountFlags << " Modules " << Modules.size();
for (ModuleInfo const* module : Modules)
stream << std::endl << "Battlenet::ModuleInfo Locale " << module->Region.c_str() << ", ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << ", DataSize " << module->DataSize << ", Data " << ByteArrayToHexStr(module->Data, module->DataSize);
return stream.str();
}
void Battlenet::AuthComplete::SetAuthResult(AuthResult result)
{
ErrorType = result != AUTH_OK ? 1 : 0;
Result = result;
}
Battlenet::AuthResume::~AuthResume()
{
for (ModuleInfo* m : Modules)
delete m;
}
void Battlenet::AuthResume::Write()
{
_stream.Write(Result != 0, 1);
if (Result == 0)
{
_stream.Write(Modules.size(), 3);
for (size_t i = 0; i < Modules.size(); ++i)
{
ModuleInfo* info = Modules[i];
_stream.WriteBytes(info->Type.c_str(), 4);
_stream.WriteFourCC(info->Region);
_stream.WriteBytes(info->ModuleId, 32);
_stream.Write(info->DataSize, 10);
_stream.WriteBytes(info->Data, info->DataSize);
}
_stream.Write(PingTimeout + std::numeric_limits<int32>::min(), 32);
_stream.Write(1, 1);
// if written == 1
{
_stream.Write(1, 1);
// if written == 1
{
_stream.Write(Threshold, 32);
_stream.Write(Rate, 32);
}
}
}
else
{
_stream.Write(!Modules.empty(), 1);
if (!Modules.empty())
{
ModuleInfo* info = Modules[0];
_stream.WriteBytes(info->Type.c_str(), 4);
_stream.WriteFourCC(info->Region);
_stream.WriteBytes(info->ModuleId, 32);
}
_stream.Write(ErrorType, 2);
if (ErrorType == 1)
{
_stream.Write(Result, 16);
_stream.Write(0x80000000, 32);
}
}
}
std::string Battlenet::AuthResume::ToString() const
{
std::ostringstream stream;
stream << "Battlenet::AuthResume AuthResult " << Result << " PingTimeout " << PingTimeout << " Threshold " << Threshold << " Rate " << Rate << " Modules " << Modules.size();
for (ModuleInfo const* module : Modules)
stream << std::endl << "Battlenet::ModuleInfo Locale " << module->Region.c_str() << ", ModuleId " << ByteArrayToHexStr(module->ModuleId, 32) << ", DataSize " << module->DataSize << ", Data " << ByteArrayToHexStr(module->Data, module->DataSize);
return stream.str();
}
void Battlenet::AuthResume::SetAuthResult(AuthResult result)
{
ErrorType = result != AUTH_OK ? 1 : 0;
Result = result;
}
Battlenet::RealmCharacterCounts::~RealmCharacterCounts()
{
for (ServerPacket* realmData : RealmData)
delete realmData;
}
void Battlenet::RealmCharacterCounts::Write()
{
_stream.Write(false, 1); // failure
_stream.Write(CharacterCounts.size(), 7);
for (CharacterCountEntry const& entry : CharacterCounts)
{
_stream.Write(entry.Realm.Battlegroup, 8);
_stream.Write(entry.Realm.Index, 32);
_stream.Write(entry.Realm.Region, 8);
_stream.Write(entry.CharacterCount, 16);
}
for (ServerPacket* realmData : RealmData)
{
realmData->Write();
_stream.WriteBytes(realmData->GetData(), realmData->GetSize());
}
}
std::string Battlenet::RealmCharacterCounts::ToString() const
{
std::ostringstream stream;
stream << "Battlenet::RealmCharacterCounts Realms " << CharacterCounts.size();
for (CharacterCountEntry const& entry : CharacterCounts)
stream << std::endl << "Region " << uint32(entry.Realm.Region) << " Battlegroup " << uint32(entry.Realm.Region) << " Index " << entry.Realm.Index << " Characters " << entry.CharacterCount;
for (ServerPacket* realmData : RealmData)
stream << std::endl << realmData->ToString();
return stream.str().c_str();
}
void Battlenet::RealmUpdate::Write()
{
_stream.Write(true, 1); // Success
_stream.Write(Type + -std::numeric_limits<int32>::min(), 32);
_stream.WriteFloat(Population);
_stream.Write(Flags, 8);
_stream.Write(Lock, 8);
_stream.Write(Timezone, 32);
_stream.Write(!Version.empty(), 1);
if (!Version.empty())
{
_stream.WriteString(Version, 5);
_stream.Write(Build, 32);
uint32 ip = Address.get_ip_address();
uint16 port = Address.get_port_number();
EndianConvertReverse(ip);
EndianConvertReverse(port);
_stream.WriteBytes(&ip, 4);
_stream.WriteBytes(&port, 2);
}
_stream.WriteString(Name, 10);
_stream.Write(Battlegroup, 8);
_stream.Write(Index, 32);
_stream.Write(Region, 8);
}
std::string Battlenet::RealmUpdate::ToString() const
{
std::ostringstream stream;
stream << "Battlenet::RealmUpdate Timezone " << Timezone << " Population " << Population << " Lock " << uint32(Lock) << " Type " << Type << " Name " << Name
<< " Flags " << uint32(Flags) << " Region " << uint32(Region) << " Battlegroup " << uint32(Battlegroup) << " Index " << Index;
if (!Version.empty())
stream << " Version " << Version;
return stream.str().c_str();
}
void Battlenet::RealmJoinRequest::Read()
{
Realm.Battlegroup = _stream.Read<uint8>(8);
Realm.Index = _stream.Read<uint32>(32);
Realm.Region = _stream.Read<uint8>(8);
ClientSeed = _stream.Read<uint32>(32);
}
std::string Battlenet::RealmJoinRequest::ToString() const
{
std::ostringstream stream;
stream << "Battlenet::RealmJoinRequest ClientSeed " << ClientSeed << " Region " << uint32(Realm.Region) << " Battlegroup " << uint32(Realm.Battlegroup) << " Index " << Realm.Index;
return stream.str().c_str();
}
void Battlenet::RealmJoinResult::Write()
{
_stream.Write(0, 27);
_stream.Write(0, 1); // Fail
_stream.Write(ServerSeed, 32);
_stream.Write(0, 5); // IPv6 addresses
_stream.Write(IPv4.size(), 5);
for (ACE_INET_Addr const& addr : IPv4)
{
uint32 ip = addr.get_ip_address();
uint16 port = addr.get_port_number();
EndianConvertReverse(ip);
EndianConvertReverse(port);
_stream.WriteBytes(&ip, 4);
_stream.WriteBytes(&port, 2);
}
}
std::string Battlenet::RealmJoinResult::ToString() const
{
std::ostringstream stream;
stream << "Battlenet::RealmJoinResult ServerSeed " << ServerSeed << " IPv4 Addresses " << IPv4.size();
for (ACE_INET_Addr const& addr : IPv4)
stream << std::endl << "Battlenet::RealmJoinResult::Address " << GetAddressString(addr);
return stream.str().c_str();
}

View File

@@ -0,0 +1,360 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://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/>.
*/
#ifndef __BATTLENETPACKETS_H__
#define __BATTLENETPACKETS_H__
#include "AuthCodes.h"
#include "BattlenetBitStream.h"
#include "BattlenetManager.h"
#include "Define.h"
#include "Errors.h"
#include <string>
namespace Battlenet
{
class BitStream;
enum Channel
{
AUTHENTICATION = 0,
CREEP = 1,
WOW = 2
};
enum AuthOpcode
{
CMSG_AUTH_CHALLENGE = 0x0,
CMSG_AUTH_RECONNECT = 0x1,
CMSG_AUTH_PROOF_RESPONSE = 0x2,
SMSG_AUTH_COMPLETE = 0x0,
SMSG_AUTH_RESUME = 0x1,
SMSG_AUTH_PROOF_REQUEST = 0x2
};
enum CreepOpcodes
{
CMSG_PING = 0x0,
CMSG_ENABLE_ENCRYPTION = 0x5,
CMSG_DISCONNECT = 0x6,
CMSG_INVALID_PACKET = 0x9,
SMSG_PONG = 0x0
};
enum WoWOpcodes
{
CMSG_REALM_UPDATE_SUBSCRIBE = 0x0,
CMSG_REALM_UPDATE_UNSUBSCRIBE = 0x1,
CMSG_JOIN_REQUEST = 0x8,
SMSG_CHARACTER_COUNTS = 0x0,
SMSG_REALM_UPDATE = 0x2,
SMSG_REALM_UPDATE_END = 0x3,
SMSG_JOIN_RESULT = 0x8
};
struct PacketHeader
{
PacketHeader(uint32 opcode, uint32 channel) : Opcode(opcode), Channel(channel) { }
PacketHeader() : Opcode(0), Channel(AUTHENTICATION) { }
uint32 Opcode;
int32 Channel;
bool operator<(PacketHeader const& right) const
{
if (Opcode < right.Opcode)
return true;
if (Opcode > right.Opcode)
return false;
return Channel < right.Channel;
}
bool operator==(PacketHeader const& right) const
{
return Opcode == right.Opcode && Channel == right.Channel;
}
std::string ToString() const;
};
class Packet
{
public:
Packet(PacketHeader const& header, BitStream& stream) : _header(header), _stream(stream) { }
virtual ~Packet() { }
PacketHeader const& GetHeader() const { return _header; }
virtual void Write() = 0;
virtual void Read() = 0;
virtual std::string ToString() const = 0;
protected:
PacketHeader _header;
BitStream& _stream;
private:
Packet(Packet const& right);
Packet& operator=(Packet const& right);
};
class ClientPacket : public Packet
{
public:
ClientPacket(PacketHeader const& header, BitStream& stream) : Packet(header, stream) { }
void Write() override final { ASSERT(!"Write not implemented for this packet."); }
};
class ServerPacket : public Packet
{
public:
ServerPacket(PacketHeader const& header);
~ServerPacket();
void Read() override final { ASSERT(!"Read not implemented for server packets."); }
uint8 const* GetData() const { return _stream.GetBuffer(); }
size_t GetSize() const { return _stream.GetSize(); }
};
class AuthChallenge final : public ClientPacket
{
public:
AuthChallenge(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream)
{
ASSERT(header == PacketHeader(CMSG_AUTH_CHALLENGE, AUTHENTICATION) && "Invalid packet header for AuthChallenge");
}
void Read() override;
std::string ToString() const override;
std::string Program;
std::string Platform;
std::string Locale;
std::vector<Component> Components;
std::string Login;
};
class AuthResumeInfo final : public ClientPacket
{
public:
AuthResumeInfo(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream)
{
ASSERT(header == PacketHeader(CMSG_AUTH_RECONNECT, AUTHENTICATION) && "Invalid packet header for AuthResumeInfo");
}
void Read() override;
std::string ToString() const override;
std::string Program;
std::string Platform;
std::string Locale;
std::vector<Component> Components;
std::string Login;
uint8 Region;
std::string GameAccountName;
};
class ProofRequest final : public ServerPacket
{
public:
ProofRequest() : ServerPacket(PacketHeader(SMSG_AUTH_PROOF_REQUEST, AUTHENTICATION)) { }
~ProofRequest();
void Write() override;
std::string ToString() const override;
std::vector<ModuleInfo*> Modules;
};
class ProofResponse final : public ClientPacket
{
public:
ProofResponse(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream)
{
ASSERT(header == PacketHeader(CMSG_AUTH_PROOF_RESPONSE, AUTHENTICATION) && "Invalid packet header for ProofResponse");
}
~ProofResponse();
void Read() override;
std::string ToString() const override;
std::vector<BitStream*> Modules;
};
class AuthComplete final : public ServerPacket
{
public:
AuthComplete() : ServerPacket(PacketHeader(SMSG_AUTH_COMPLETE, AUTHENTICATION)),
Result(AUTH_OK), ErrorType(0), PingTimeout(120000), Threshold(25000000), Rate(1000),
FirstName(""), LastName(""), AccountId(0), Region(2), GameAccountRegion(2), GameAccountName("")
{
}
~AuthComplete();
void Write() override;
std::string ToString() const override;
std::vector<ModuleInfo*> Modules;
void SetAuthResult(AuthResult result);
AuthResult Result;
uint32 ErrorType;
int32 PingTimeout;
uint32 Threshold;
uint32 Rate;
std::string FirstName;
std::string LastName;
uint32 AccountId;
uint8 Region;
uint8 GameAccountRegion;
std::string GameAccountName;
uint64 GameAccountFlags;
};
class AuthResume final : public ServerPacket
{
public:
AuthResume() : ServerPacket(PacketHeader(SMSG_AUTH_RESUME, AUTHENTICATION)),
Result(AUTH_OK), ErrorType(0), PingTimeout(120000), Threshold(25000000), Rate(1000)
{
}
~AuthResume();
void Write() override;
std::string ToString() const override;
std::vector<ModuleInfo*> Modules;
void SetAuthResult(AuthResult result);
AuthResult Result;
uint32 ErrorType;
int32 PingTimeout;
uint32 Threshold;
uint32 Rate;
};
class Pong final : public ServerPacket
{
public:
Pong() : ServerPacket(PacketHeader(SMSG_PONG, CREEP))
{
}
void Write() override { }
std::string ToString() const override { return "Battlenet::Pong"; }
};
class RealmCharacterCounts final : public ServerPacket
{
public:
RealmCharacterCounts() : ServerPacket(PacketHeader(SMSG_CHARACTER_COUNTS, WOW))
{
}
~RealmCharacterCounts();
struct CharacterCountEntry
{
RealmId Realm;
uint32 CharacterCount;
};
void Write() override;
std::string ToString() const override;
std::vector<CharacterCountEntry> CharacterCounts;
std::vector<ServerPacket*> RealmData;
};
class RealmUpdate final : public ServerPacket
{
public:
RealmUpdate() : ServerPacket(PacketHeader(SMSG_REALM_UPDATE, WOW)),
Timezone(0), Population(0.0f), Lock(0), Type(0), Name(""), Version(""),
Address(), Flags(0), Region(0), Battlegroup(0), Index(0), Build(0)
{
}
void Write() override;
std::string ToString() const override;
uint32 Timezone;
float Population;
uint8 Lock;
uint32 Type;
std::string Name;
std::string Version;
ACE_INET_Addr Address;
uint8 Flags;
uint8 Region;
uint8 Battlegroup;
uint32 Index;
uint32 Build;
};
class RealmUpdateComplete final : public ServerPacket
{
public:
RealmUpdateComplete() : ServerPacket(PacketHeader(SMSG_REALM_UPDATE_END, WOW))
{
}
void Write() override { }
std::string ToString() const override { return "Battlenet::RealmUpdateComplete"; }
};
class RealmJoinRequest final : public ClientPacket
{
public:
RealmJoinRequest(PacketHeader const& header, BitStream& stream) : ClientPacket(header, stream)
{
ASSERT(header == PacketHeader(CMSG_JOIN_REQUEST, WOW) && "Invalid packet header for RealmJoinRequest");
}
void Read() override;
std::string ToString() const override;
uint32 ClientSeed;
uint32 Unknown;
RealmId Realm;
};
class RealmJoinResult final : public ServerPacket
{
public:
RealmJoinResult() : ServerPacket(PacketHeader(SMSG_JOIN_RESULT, WOW)), ServerSeed(0)
{
}
void Write() override;
std::string ToString() const override;
uint32 ServerSeed;
std::vector<ACE_INET_Addr> IPv4;
};
}
#endif // __BATTLENETPACKETS_H__

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,120 @@
/*
* Copyright (C) 2008-2014 TrinityCore <http://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/>.
*/
#ifndef _BATTLENETSOCKET_H
#define _BATTLENETSOCKET_H
#include "RealmSocket.h"
#include "BattlenetPackets.h"
#include "BattlenetPacketCrypt.h"
#include "BigNumber.h"
class ACE_INET_Addr;
namespace Battlenet
{
struct PacketHeader;
class BitStream;
enum ModuleType
{
MODULE_PASSWORD,
MODULE_TOKEN,
MODULE_THUMBPRINT,
MODULE_SELECT_GAME_ACCOUNT,
MODULE_RISK_FINGERPRINT,
MODULE_RESUME,
MODULE_COUNT
};
class Socket : public RealmSocket::Session
{
public:
static uint32 const SRP6_V_Size;
static uint32 const SRP6_S_Size;
explicit Socket(RealmSocket& socket);
typedef bool(Socket::*PacketHandler)(PacketHeader& socket, BitStream& packet);
// Auth
bool HandleAuthChallenge(PacketHeader& header, BitStream& packet);
bool HandleAuthReconnect(PacketHeader& header, BitStream& packet);
bool HandleAuthProofResponse(PacketHeader& header, BitStream& packet);
// Creep
bool HandlePing(PacketHeader& header, BitStream& packet);
bool HandleEnableEncryption(PacketHeader& header, BitStream& packet);
bool HandleDisconnect(PacketHeader& header, BitStream& packet);
// WoW
bool HandleRealmUpdateSubscribe(PacketHeader& header, BitStream& packet);
bool HandleRealmJoinRequest(PacketHeader& header, BitStream& packet);
void OnRead() override;
void OnAccept() override;
void OnClose() override;
void Send(ServerPacket& packet);
private:
void _SetVSFields(std::string const& rI);
typedef bool(Socket::*ModuleHandler)(BitStream* dataStream, ServerPacket** response);
static ModuleHandler const ModuleHandlers[MODULE_COUNT];
bool HandlePasswordModule(BitStream* dataStream, ServerPacket** response);
bool HandleSelectGameAccountModule(BitStream* dataStream, ServerPacket** response);
bool HandleRiskFingerprintModule(BitStream* dataStream, ServerPacket** response);
bool HandleResumeModule(BitStream* dataStream, ServerPacket** response);
bool UnhandledModule(BitStream* dataStream, ServerPacket** response);
RealmSocket& _socket;
uint32 _accountId;
std::string _accountName;
std::string _locale;
std::string _os;
uint32 _build;
uint32 _gameAccountId;
uint8 _gameAccountIndex;
AccountTypes _accountSecurityLevel;
BigNumber N;
BigNumber g;
BigNumber k;
BigNumber I;
BigNumber s;
BigNumber v;
BigNumber b;
BigNumber B;
BigNumber K; // session key
BigNumber _reconnectProof;
std::queue<ModuleType> _modulesWaitingForData;
PacketCrypt _crypt;
bool _authed;
};
}
#endif // _BATTLENETSOCKET_H

View File

@@ -24,7 +24,9 @@
#include "RealmSocket.h"
#include "AuthSocket.h"
#include "BattlenetSocket.h"
template<class LoginType>
class RealmAcceptor : public ACE_Acceptor<RealmSocket, ACE_SOCK_Acceptor>
{
public:
@@ -42,7 +44,7 @@ protected:
ACE_NEW_RETURN(sh, RealmSocket, -1);
sh->reactor(reactor());
sh->set_session(new AuthSocket(*sh));
sh->set_session(new LoginType(*sh));
return 0;
}