Skip to content

Commit cb5aa9e

Browse files
committed
Support RelayPacket in Auth and World servers.
1 parent dfbd801 commit cb5aa9e

9 files changed

Lines changed: 250 additions & 4 deletions

File tree

src/server/authserver/Server/AuthSession.cpp

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "CryptoRandom.h"
2626
#include "DatabaseEnv.h"
2727
#include "IPLocation.h"
28+
#include "IpAddress.h"
2829
#include "Log.h"
2930
#include "RealmList.h"
3031
#include "SecretMgr.h"
@@ -45,7 +46,8 @@ enum eAuthCmd
4546
XFER_DATA = 0x31,
4647
XFER_ACCEPT = 0x32,
4748
XFER_RESUME = 0x33,
48-
XFER_CANCEL = 0x34
49+
XFER_CANCEL = 0x34,
50+
RELAY_PACKET = 0x64 // Relay packet from relay server to auth server according to the https://github.com/masterking32/WoW-Server-Relay
4951
};
5052

5153
#pragma pack(push, 1)
@@ -110,6 +112,16 @@ typedef struct AUTH_RECONNECT_PROOF_C
110112
} sAuthReconnectProof_C;
111113
static_assert(sizeof(sAuthReconnectProof_C) == (1 + 16 + 20 + 20 + 1));
112114

115+
typedef struct RELAY_PACKET_C
116+
{
117+
uint8 cmd;
118+
uint16 secret_len;
119+
uint16 ip_len;
120+
uint8 secret[1];
121+
uint8 ip[1];
122+
} sRelayPacket_C;
123+
static_assert(sizeof(sRelayPacket_C) == (1 + 2 + 2 + 1 + 1)); // 1 byte for the cmd, 2 bytes for the secret length, 2 bytes for the IP length
124+
113125
#pragma pack(pop)
114126

115127
std::array<uint8, 16> VersionChallenge = { { 0xBA, 0xA3, 0x1E, 0x99, 0xA0, 0x0B, 0x21, 0x57, 0xFC, 0x37, 0x3F, 0xB3, 0x69, 0xCD, 0xD2, 0xF1 } };
@@ -119,10 +131,13 @@ std::array<uint8, 16> VersionChallenge = { { 0xBA, 0xA3, 0x1E, 0x99, 0xA0, 0x0B,
119131
#define AUTH_LOGON_CHALLENGE_INITIAL_SIZE 4
120132
#define REALM_LIST_PACKET_SIZE 5
121133

134+
#define MAX_RELAY_PACKET_SIZE (sizeof(RELAY_PACKET_C) + 64 + 46) // 64 bytes for the secret, 46 bytes for the IP address (Even though IPv6 is 39 bytes, we use 46 bytes to be safe)
135+
122136
std::unordered_map<uint8, AuthHandler> AuthSession::InitHandlers()
123137
{
124138
std::unordered_map<uint8, AuthHandler> handlers;
125139

140+
handlers[RELAY_PACKET] = { STATUS_CHALLENGE, sizeof(RELAY_PACKET_C), &AuthSession::HandleRelayPacket };
126141
handlers[AUTH_LOGON_CHALLENGE] = { STATUS_CHALLENGE, AUTH_LOGON_CHALLENGE_INITIAL_SIZE, &AuthSession::HandleLogonChallenge };
127142
handlers[AUTH_LOGON_PROOF] = { STATUS_LOGON_PROOF, sizeof(AUTH_LOGON_PROOF_C), &AuthSession::HandleLogonProof };
128143
handlers[AUTH_RECONNECT_CHALLENGE] = { STATUS_CHALLENGE, AUTH_LOGON_CHALLENGE_INITIAL_SIZE, &AuthSession::HandleReconnectChallenge };
@@ -243,6 +258,15 @@ void AuthSession::ReadHandler()
243258
CloseSocket();
244259
return;
245260
}
261+
} else if (cmd == RELAY_PACKET)
262+
{
263+
sRelayPacket_C* relayPacket = reinterpret_cast<sRelayPacket_C*>(packet.GetReadPointer());
264+
size += relayPacket->secret_len + relayPacket->ip_len - 2; // -2 because the secret and IP lengths are already included in the size
265+
if (size > MAX_RELAY_PACKET_SIZE)
266+
{
267+
CloseSocket();
268+
return;
269+
}
246270
}
247271

248272
if (packet.GetActiveSize() < size)
@@ -273,6 +297,71 @@ void AuthSession::SendPacket(ByteBuffer& packet)
273297
}
274298
}
275299

300+
bool AuthSession::HandleRelayPacket()
301+
{
302+
sRelayPacket_C* relayPacket = reinterpret_cast<sRelayPacket_C*>(GetReadBuffer().GetReadPointer());
303+
304+
if (relayPacket->secret_len > 64 || relayPacket->ip_len > 46)
305+
{
306+
TC_LOG_DEBUG("server.authserver", "[RelayPacket] Relay packet is too large");
307+
_status = STATUS_CLOSED; // Close the connection if the packet is too large
308+
return false;
309+
}
310+
311+
if (relayPacket->secret_len < 1 || relayPacket->ip_len < 1)
312+
{
313+
TC_LOG_DEBUG("server.authserver", "[RelayPacket] Relay packet is too small");
314+
_status = STATUS_CLOSED; // Close the connection if the packet is too small
315+
return false;
316+
}
317+
318+
std::string secret(reinterpret_cast<char const*>(relayPacket->secret), relayPacket->secret_len);
319+
std::string ip(reinterpret_cast<char const*>(relayPacket->secret + relayPacket->secret_len), relayPacket->ip_len);
320+
std::string configSecretKey = sConfigMgr->GetStringDefault("RelayServerSecret", "secret");
321+
322+
if(configSecretKey.empty() || configSecretKey == "secret")
323+
{
324+
TC_LOG_ERROR("server.authserver", "[RelayPacket] Relay server secret is not set or is default. Please set a unique secret key with a maximum of 64 characters in the authserver.conf configuration file.");
325+
_status = STATUS_CLOSED; // Close the connection if the secret is not set
326+
return false;
327+
}
328+
329+
if (secret != configSecretKey)
330+
{
331+
TC_LOG_DEBUG("server.authserver", "[RelayPacket] Invalid secret");
332+
_status = STATUS_CLOSED; // Close the connection if the secret is invalid
333+
return false;
334+
}
335+
336+
if (ip.empty())
337+
{
338+
TC_LOG_DEBUG("server.authserver", "[RelayPacket] IP is empty");
339+
_status = STATUS_CLOSED; // Close the connection if the IP is empty
340+
return false;
341+
}
342+
343+
boost::system::error_code ip_error;
344+
boost::asio::ip::address ip_address = Trinity::Net::make_address(ip, ip_error);
345+
if (ip_error)
346+
{
347+
TC_LOG_DEBUG("server.authserver", "[RelayPacket] Invalid IP '{}'", ip);
348+
_status = STATUS_CLOSED; // Close the connection if the IP is invalid
349+
return false;
350+
}
351+
352+
std::string RelayIPAddress = GetRemoteIpAddress().to_string();
353+
SetRemoteIpAddress(ip_address); // Change the remote IP address to the one received from the relay server
354+
std::string UserIPAddress = GetRemoteIpAddress().to_string();
355+
TC_LOG_DEBUG("server.authserver", "[RelayPacket] Received relay packet from '{}' for IP '{}'", RelayIPAddress, UserIPAddress);
356+
357+
// We need to check the database once again to determine if the client's IP is banned or not.
358+
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO);
359+
stmt->setString(0, UserIPAddress);
360+
_queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&AuthSession::CheckIpCallback, this, std::placeholders::_1)));
361+
362+
return true;
363+
}
364+
276365
bool AuthSession::HandleLogonChallenge()
277366
{
278367
_status = STATUS_CLOSED;

src/server/authserver/Server/AuthSession.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class AuthSession : public Socket<AuthSession>
7676
void ReadHandler() override;
7777

7878
private:
79+
bool HandleRelayPacket();
7980
bool HandleLogonChallenge();
8081
bool HandleLogonProof();
8182
bool HandleReconnectChallenge();

src/server/authserver/authserver.conf.dist

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# CRYPTOGRAPHY
1313
# UPDATE SETTINGS
1414
# LOGGING SYSTEM SETTINGS
15+
# CONFIGURATION FOR RELAY SERVER
1516
#
1617
###################################################################################################
1718

@@ -397,3 +398,15 @@ Logger.root=3,Console Auth
397398

398399
#
399400
###################################################################################################
401+
402+
###################################################################################################
403+
#
404+
# CONFIGURATION FOR RELAY SERVER
405+
# Secret Key for Relay Server
406+
# Please use a secure key that is between 32 and 64 characters in length. Note that the maximum length allowed is 64 characters.
407+
#
408+
409+
RelayServerSecret = "secret"
410+
411+
#
412+
###################################################################################################

src/server/game/Server/Protocol/Opcodes.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,6 +1439,8 @@ void OpcodeTable::Initialize()
14391439
/*0x51C*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT1, STATUS_NEVER);
14401440
/*0x51D*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT2, STATUS_NEVER);
14411441
/*0x51E*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_MULTIPLE_MOVES, STATUS_NEVER);
1442+
/*0xA32*/ DEFINE_HANDLER(RELAY_SERVER_CMD_WORLD, STATUS_NEVER, PROCESS_THREADUNSAFE, &WorldSession::Handle_EarlyProccess ); // Relay server command
1443+
14421444

14431445
#undef DEFINE_HANDLER
14441446

src/server/game/Server/Protocol/Opcodes.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1337,7 +1337,8 @@ enum Opcodes : uint16
13371337
SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT1 = 0x51C,
13381338
SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT2 = 0x51D,
13391339
SMSG_MULTIPLE_MOVES = 0x51E, // uncompressed version of SMSG_COMPRESSED_MOVES
1340-
NUM_MSG_TYPES = 0x51F
1340+
NUM_MSG_TYPES = 0x51F,
1341+
RELAY_SERVER_CMD_WORLD = 0xA32 // Relay packet from relay server to worldserver according to the https://github.com/masterking32/WoW-Server-Relay
13411342
};
13421343

13431344
enum OpcodeMisc : uint16

src/server/game/Server/WorldSocket.cpp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "CryptoHash.h"
2323
#include "CryptoRandom.h"
2424
#include "IPLocation.h"
25+
#include "IpAddress.h"
2526
#include "Opcodes.h"
2627
#include "PacketLog.h"
2728
#include "Random.h"
@@ -31,6 +32,7 @@
3132
#include "World.h"
3233
#include "WorldSession.h"
3334
#include <memory>
35+
#include <Config.h>
3436

3537
using boost::asio::ip::tcp;
3638

@@ -242,6 +244,12 @@ struct AuthSession
242244
ByteBuffer AddonInfo;
243245
};
244246

247+
struct RelayPacketInfo
248+
{
249+
std::string SecretKey;
250+
std::string UserIP;
251+
};
252+
245253
struct AccountInfo
246254
{
247255
uint32 Id;
@@ -322,6 +330,26 @@ WorldSocket::ReadDataHandlerResult WorldSocket::ReadDataHandler()
322330
TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed CMSG_PING", GetRemoteIpAddress().to_string());
323331
return ReadDataHandlerResult::Error;
324332
}
333+
case RELAY_SERVER_CMD_WORLD:
334+
{
335+
LogOpcodeText(opcode, sessionGuard);
336+
337+
if (_authed)
338+
{
339+
return ReadDataHandlerResult::Error;
340+
}
341+
342+
try
343+
{
344+
HandleRelayPacket(packet);
345+
return ReadDataHandlerResult::WaitingForQuery;
346+
}
347+
catch (ByteBufferException const&)
348+
{
349+
}
350+
TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client {} sent malformed RELAY_SERVER_CMD_WORLD", GetRemoteIpAddress().to_string());
351+
return ReadDataHandlerResult::Error;
352+
}
325353
case CMSG_AUTH_SESSION:
326354
{
327355
LogOpcodeText(opcode, sessionGuard);
@@ -421,6 +449,88 @@ void WorldSocket::SendPacket(WorldPacket const& packet)
421449
_bufferQueue.Enqueue(new EncryptablePacket(packet, _authCrypt.IsInitialized()));
422450
}
423451

452+
void WorldSocket::HandleRelayPacket(WorldPacket& recvPacket)
453+
{
454+
std::shared_ptr<RelayPacketInfo> relayPacketInfo = std::make_shared<RelayPacketInfo>();
455+
456+
// Read the content of the packet
457+
recvPacket >> relayPacketInfo->SecretKey; // Secret key used to authenticate the relay server
458+
recvPacket >> relayPacketInfo->UserIP; // User IP sent by the relay server
459+
460+
std::string ConfigSecretKey = sConfigMgr->GetStringDefault("RelayServerSecret", "secret"); // Get the secret key from the configuration file
461+
462+
if(ConfigSecretKey.empty() || ConfigSecretKey == "secret")
463+
{
464+
SendAuthResponseError(AUTH_REJECT);
465+
TC_LOG_ERROR("network", "WorldSocket::HandleRelayPacket: Relay server secret is not set or is default. Please set a unique secret key with a maximum of 64 characters in the worldserver.conf configuration file.");
466+
DelayedCloseSocket();
467+
return;
468+
}
469+
470+
if (relayPacketInfo->SecretKey.empty() || relayPacketInfo->SecretKey != ConfigSecretKey)
471+
{
472+
SendAuthResponseError(AUTH_REJECT);
473+
TC_LOG_ERROR("network", "WorldSocket::HandleRelayPacket: Sent Auth Response (invalid secret key).");
474+
DelayedCloseSocket();
475+
return;
476+
}
477+
478+
if(relayPacketInfo->UserIP.empty())
479+
{
480+
SendAuthResponseError(AUTH_REJECT);
481+
TC_LOG_ERROR("network", "WorldSocket::HandleRelayPacket: Sent Auth Response (invalid user IP).");
482+
DelayedCloseSocket();
483+
return;
484+
}
485+
486+
boost::system::error_code ip_error;
487+
boost::asio::ip::address ip_address = Trinity::Net::make_address(relayPacketInfo->UserIP, ip_error);
488+
489+
if (ip_error)
490+
{
491+
SendAuthResponseError(AUTH_REJECT);
492+
TC_LOG_ERROR("network", "WorldSocket::HandleRelayPacket: Sent Auth Response (invalid user IP).");
493+
DelayedCloseSocket();
494+
return;
495+
}
496+
497+
std::string RelayIPAddress = GetRemoteIpAddress().to_string();
498+
SetRemoteIpAddress(ip_address); // Change the remote IP address to the one received from the relay server
499+
std::string UserIPAddress = GetRemoteIpAddress().to_string();
500+
501+
TC_LOG_DEBUG("network", "WorldSocket::HandleRelayPacket: Changed remote IP address from '{}' to '{}'.", RelayIPAddress, UserIPAddress);
502+
503+
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_INFO);
504+
stmt->setString(0, UserIPAddress);
505+
506+
_queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::CheckIpCallbackRelay, this, std::placeholders::_1)));
507+
}
508+
509+
void WorldSocket::CheckIpCallbackRelay(PreparedQueryResult result)
510+
{
511+
if (result)
512+
{
513+
bool banned = false;
514+
do
515+
{
516+
Field* fields = result->Fetch();
517+
if (fields[0].GetUInt64() != 0)
518+
banned = true;
519+
520+
} while (result->NextRow());
521+
522+
if (banned)
523+
{
524+
SendAuthResponseError(AUTH_REJECT);
525+
TC_LOG_ERROR("network", "WorldSocket::CheckIpCallbackRelay: Sent Auth Response (IP {} banned).", GetRemoteIpAddress().to_string());
526+
DelayedCloseSocket();
527+
return;
528+
}
529+
}
530+
531+
AsyncRead();
532+
}
533+
424534
void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
425535
{
426536
std::shared_ptr<AuthSession> authSession = std::make_shared<AuthSession>();

src/server/game/Server/WorldSocket.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ struct ClientPktHeader
5757
uint32 cmd;
5858

5959
bool IsValidSize() const { return size >= 4 && size < 10240; }
60-
bool IsValidOpcode() const { return cmd < NUM_OPCODE_HANDLERS; }
60+
bool IsValidOpcode() const { return cmd < NUM_OPCODE_HANDLERS || cmd == RELAY_SERVER_CMD_WORLD; }
6161
};
6262

6363
#pragma pack(pop)
@@ -98,13 +98,15 @@ class TC_GAME_API WorldSocket : public Socket<WorldSocket>
9898

9999
private:
100100
void CheckIpCallback(PreparedQueryResult result);
101+
void CheckIpCallbackRelay(PreparedQueryResult result);
101102

102103
/// writes network.opcode log
103104
/// accessing WorldSession is not threadsafe, only do it when holding _worldSessionLock
104105
void LogOpcodeText(OpcodeClient opcode, std::unique_lock<std::mutex> const& guard) const;
105106
/// sends and logs network.opcode without accessing WorldSession
106107
void SendPacketAndLogOpcode(WorldPacket const& packet);
107108
void HandleSendAuthSession();
109+
void HandleRelayPacket(WorldPacket& recvPacket);
108110
void HandleAuthSession(WorldPacket& recvPacket);
109111
void HandleAuthSessionCallback(std::shared_ptr<AuthSession> authSession, PreparedQueryResult result);
110112
void LoadSessionPermissionsCallback(PreparedQueryResult result);

src/server/shared/Networking/Socket.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,21 @@ class Socket : public std::enable_shared_from_this<T>
7171

7272
boost::asio::ip::address GetRemoteIpAddress() const
7373
{
74-
return _remoteAddress;
74+
if(_RealRemoteAddress.is_unspecified())
75+
return _remoteAddress;
76+
77+
return _RealRemoteAddress;
78+
}
79+
80+
bool SetRemoteIpAddress(const boost::asio::ip::address& address)
81+
{
82+
if(_RealRemoteAddress.is_unspecified())
83+
{
84+
_RealRemoteAddress = address;
85+
return true;
86+
}
87+
88+
return false;
7589
}
7690

7791
uint16 GetRemotePort() const
@@ -258,6 +272,7 @@ class Socket : public std::enable_shared_from_this<T>
258272
tcp::socket _socket;
259273

260274
boost::asio::ip::address _remoteAddress;
275+
boost::asio::ip::address _RealRemoteAddress;
261276
uint16 _remotePort;
262277

263278
MessageBuffer _readBuffer;

0 commit comments

Comments
 (0)