[8389] Implement check really read received packet size and warning it not all data read. Author: VladimirMangos

* This let more easy catch packet structure chnages at client switch.
    * Fixed structure CMSG_GUILD_BANK_SWAP_ITEMS
    * Fixed structure CMSG_SPLIT_ITEM, CMSG_SELL_ITEM
    * Added read data amount fixes for some other packets.

    Thanks to TOM_RUS in help check correct packets structure.

    Note: not all packets possible fixed. Please report for not fixed cases at errors:
    "opcode %s (0x%.4X) have unprocessed tail data (read stop at %u from %u)"

--HG--
branch : trunk
This commit is contained in:
megamage
2009-08-19 17:07:21 -05:00
parent f5085b2f39
commit c911772125
9 changed files with 74 additions and 36 deletions
+10
View File
@@ -97,6 +97,7 @@ void WorldSession::HandleCalendarAddEvent(WorldPacket &recv_data)
{ {
sLog.outDebug("WORLD: CMSG_CALENDAR_ADD_EVENT"); sLog.outDebug("WORLD: CMSG_CALENDAR_ADD_EVENT");
recv_data.hexlike(); recv_data.hexlike();
recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam
//std::string unk1, unk2; //std::string unk1, unk2;
//recv_data >> (std::string)unk1; //recv_data >> (std::string)unk1;
@@ -132,6 +133,7 @@ void WorldSession::HandleCalendarUpdateEvent(WorldPacket &recv_data)
{ {
sLog.outDebug("WORLD: CMSG_CALENDAR_UPDATE_EVENT"); sLog.outDebug("WORLD: CMSG_CALENDAR_UPDATE_EVENT");
recv_data.hexlike(); recv_data.hexlike();
recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam
//recv_data >> uint64 //recv_data >> uint64
//recv_data >> uint64 //recv_data >> uint64
@@ -150,6 +152,7 @@ void WorldSession::HandleCalendarRemoveEvent(WorldPacket &recv_data)
{ {
sLog.outDebug("WORLD: CMSG_CALENDAR_REMOVE_EVENT"); sLog.outDebug("WORLD: CMSG_CALENDAR_REMOVE_EVENT");
recv_data.hexlike(); recv_data.hexlike();
recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam
//recv_data >> uint64 //recv_data >> uint64
//recv_data >> uint64 //recv_data >> uint64
@@ -161,6 +164,7 @@ void WorldSession::HandleCalendarCopyEvent(WorldPacket &recv_data)
{ {
sLog.outDebug("WORLD: CMSG_CALENDAR_COPY_EVENT"); sLog.outDebug("WORLD: CMSG_CALENDAR_COPY_EVENT");
recv_data.hexlike(); recv_data.hexlike();
recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam
//recv_data >> uint64 //recv_data >> uint64
//recv_data >> uint64 //recv_data >> uint64
@@ -172,6 +176,7 @@ void WorldSession::HandleCalendarEventInvite(WorldPacket &recv_data)
{ {
sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_INVITE"); sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_INVITE");
recv_data.hexlike(); recv_data.hexlike();
recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam
//recv_data >> uint64 //recv_data >> uint64
//recv_data >> uint64 //recv_data >> uint64
@@ -185,6 +190,7 @@ void WorldSession::HandleCalendarEventRsvp(WorldPacket &recv_data)
{ {
sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_RSVP"); sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_RSVP");
recv_data.hexlike(); recv_data.hexlike();
recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam
//recv_data >> uint64 //recv_data >> uint64
//recv_data >> uint64 //recv_data >> uint64
@@ -196,6 +202,7 @@ void WorldSession::HandleCalendarEventRemoveInvite(WorldPacket &recv_data)
{ {
sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_REMOVE_INVITE"); sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_REMOVE_INVITE");
recv_data.hexlike(); recv_data.hexlike();
recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam
//recv_data.readPackGUID(guid) //recv_data.readPackGUID(guid)
//recv_data >> uint64 //recv_data >> uint64
@@ -207,6 +214,7 @@ void WorldSession::HandleCalendarEventStatus(WorldPacket &recv_data)
{ {
sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_STATUS"); sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_STATUS");
recv_data.hexlike(); recv_data.hexlike();
recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam
//recv_data.readPackGUID(guid) //recv_data.readPackGUID(guid)
//recv_data >> uint64 //recv_data >> uint64
@@ -219,6 +227,7 @@ void WorldSession::HandleCalendarEventModeratorStatus(WorldPacket &recv_data)
{ {
sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_MODERATOR_STATUS"); sLog.outDebug("WORLD: CMSG_CALENDAR_EVENT_MODERATOR_STATUS");
recv_data.hexlike(); recv_data.hexlike();
recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam
//recv_data.readPackGUID(guid) //recv_data.readPackGUID(guid)
//recv_data >> uint64 //recv_data >> uint64
@@ -231,6 +240,7 @@ void WorldSession::HandleCalendarComplain(WorldPacket &recv_data)
{ {
sLog.outDebug("WORLD: CMSG_CALENDAR_COMPLAIN"); sLog.outDebug("WORLD: CMSG_CALENDAR_COMPLAIN");
recv_data.hexlike(); recv_data.hexlike();
recv_data.rpos(recv_data.wpos()); // set to end to avoid warnings spam
//recv_data >> uint64 //recv_data >> uint64
//recv_data >> uint64 //recv_data >> uint64
+21 -17
View File
@@ -614,12 +614,14 @@ void WorldSession::HandleGuildRankOpcode(WorldPacket& recvPacket)
guild = objmgr.GetGuildById(GetPlayer()->GetGuildId()); guild = objmgr.GetGuildById(GetPlayer()->GetGuildId());
if(!guild) if(!guild)
{ {
recvPacket.rpos(recvPacket.wpos()); // set to end to avoid warnings spam
SendGuildCommandResult(GUILD_CREATE_S, "", GUILD_PLAYER_NOT_IN_GUILD); SendGuildCommandResult(GUILD_CREATE_S, "", GUILD_PLAYER_NOT_IN_GUILD);
return; return;
} }
else if(GetPlayer()->GetGUID() != guild->GetLeader()) else if(GetPlayer()->GetGUID() != guild->GetLeader())
{ {
recvPacket.rpos(recvPacket.wpos()); // set to end to avoid warnings spam
SendGuildCommandResult(GUILD_INVITE_S, "", GUILD_PERMISSIONS); SendGuildCommandResult(GUILD_INVITE_S, "", GUILD_PERMISSIONS);
return; return;
} }
@@ -1026,10 +1028,14 @@ void WorldSession::HandleGuildBankSwapItems( WorldPacket & recv_data )
uint64 GoGuid; uint64 GoGuid;
uint8 BankToBank; uint8 BankToBank;
uint8 BankTab, BankTabSlot, AutoStore, AutoStoreCount, PlayerSlot, PlayerBag, SplitedAmount = 0; uint8 BankTab, BankTabSlot, AutoStore;
uint8 BankTabDst, BankTabSlotDst, unk2, ToChar = 1; uint8 PlayerSlot = NULL_SLOT;
uint8 PlayerBag = NULL_BAG;
uint8 BankTabDst, BankTabSlotDst, unk2;
uint8 ToChar = 1;
uint32 ItemEntry, unk1; uint32 ItemEntry, unk1;
bool BankToChar = false; uint32 AutoStoreCount = 0;
uint32 SplitedAmount = 0;
recv_data >> GoGuid >> BankToBank; recv_data >> GoGuid >> BankToBank;
if (BankToBank) if (BankToBank)
@@ -1043,10 +1049,11 @@ void WorldSession::HandleGuildBankSwapItems( WorldPacket & recv_data )
recv_data >> unk2; // always 0 recv_data >> unk2; // always 0
recv_data >> SplitedAmount; recv_data >> SplitedAmount;
if (BankTabSlotDst >= GUILD_BANK_MAX_SLOTS) if (BankTabSlotDst >= GUILD_BANK_MAX_SLOTS || BankTabDst == BankTab && BankTabSlotDst == BankTabSlot)
return; {
if (BankTabDst == BankTab && BankTabSlotDst == BankTabSlot) recv_data.rpos(recv_data.wpos()); // prevent additional spam at rejected packet
return; return;
}
} }
else else
{ {
@@ -1057,17 +1064,22 @@ void WorldSession::HandleGuildBankSwapItems( WorldPacket & recv_data )
if (AutoStore) if (AutoStore)
{ {
recv_data >> AutoStoreCount; recv_data >> AutoStoreCount;
recv_data.read_skip<uint8>(); // ToChar (?), always and expected to be 1 (autostore only triggered in guild->ToChar)
recv_data.read_skip<uint32>(); // unknown, always 0
} }
recv_data >> PlayerBag; else
recv_data >> PlayerSlot;
if (!AutoStore)
{ {
recv_data >> PlayerBag;
recv_data >> PlayerSlot;
recv_data >> ToChar; recv_data >> ToChar;
recv_data >> SplitedAmount; recv_data >> SplitedAmount;
} }
if (BankTabSlot >= GUILD_BANK_MAX_SLOTS && BankTabSlot != 0xFF) if (BankTabSlot >= GUILD_BANK_MAX_SLOTS && BankTabSlot != 0xFF)
{
recv_data.rpos(recv_data.wpos()); // prevent additional spam at rejected packet
return; return;
}
} }
if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK))
@@ -1202,14 +1214,6 @@ void WorldSession::HandleGuildBankSwapItems( WorldPacket & recv_data )
// Player <-> Bank // Player <-> Bank
// char->bank autostore click return BankTabSlot = 255 = NULL_SLOT
// do similar for bank->char
if(AutoStore && ToChar)
{
PlayerBag = NULL_BAG;
PlayerSlot = NULL_SLOT;
}
// allow work with inventory only // allow work with inventory only
if(!Player::IsInventoryPos(PlayerBag,PlayerSlot) && !(PlayerBag == NULL_BAG && PlayerSlot == NULL_SLOT) ) if(!Player::IsInventoryPos(PlayerBag,PlayerSlot) && !(PlayerBag == NULL_BAG && PlayerSlot == NULL_SLOT) )
{ {
+6 -6
View File
@@ -32,7 +32,8 @@
void WorldSession::HandleSplitItemOpcode( WorldPacket & recv_data ) void WorldSession::HandleSplitItemOpcode( WorldPacket & recv_data )
{ {
//sLog.outDebug("WORLD: CMSG_SPLIT_ITEM"); //sLog.outDebug("WORLD: CMSG_SPLIT_ITEM");
uint8 srcbag, srcslot, dstbag, dstslot, count; uint8 srcbag, srcslot, dstbag, dstslot;
uint32 count;
recv_data >> srcbag >> srcslot >> dstbag >> dstslot >> count; recv_data >> srcbag >> srcslot >> dstbag >> dstslot >> count;
//sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u, dstslot = %u, count = %u", srcbag, srcslot, dstbag, dstslot, count); //sLog.outDebug("STORAGE: receive srcbag = %u, srcslot = %u, dstbag = %u, dstslot = %u, count = %u", srcbag, srcslot, dstbag, dstslot, count);
@@ -490,12 +491,9 @@ void WorldSession::HandleSellItemOpcode( WorldPacket & recv_data )
{ {
sLog.outDebug( "WORLD: Received CMSG_SELL_ITEM" ); sLog.outDebug( "WORLD: Received CMSG_SELL_ITEM" );
uint64 vendorguid, itemguid; uint64 vendorguid, itemguid;
uint8 _count; uint32 count;
recv_data >> vendorguid >> itemguid >> _count; recv_data >> vendorguid >> itemguid >> count;
// prevent possible overflow, as Trinity uses uint32 for item count
uint32 count = _count;
if(!itemguid) if(!itemguid)
return; return;
@@ -971,6 +969,8 @@ void WorldSession::HandleItemNameQueryOpcode(WorldPacket & recv_data)
{ {
uint32 itemid; uint32 itemid;
recv_data >> itemid; recv_data >> itemid;
recv_data.read_skip<uint64>(); // guid
sLog.outDebug("WORLD: CMSG_ITEM_NAME_QUERY %u", itemid); sLog.outDebug("WORLD: CMSG_ITEM_NAME_QUERY %u", itemid);
ItemPrototype const *pProto = objmgr.GetItemPrototype( itemid ); ItemPrototype const *pProto = objmgr.GetItemPrototype( itemid );
if( pProto ) if( pProto )
+6 -1
View File
@@ -931,6 +931,7 @@ void WorldSession::HandleUpdateAccountData(WorldPacket &recv_data)
if(decompressedSize > 0xFFFF) if(decompressedSize > 0xFFFF)
{ {
recv_data.rpos(recv_data.wpos()); // unnneded warning spam in this case
sLog.outError("UAD: Account data packet too big, size %u", decompressedSize); sLog.outError("UAD: Account data packet too big, size %u", decompressedSize);
return; return;
} }
@@ -941,10 +942,13 @@ void WorldSession::HandleUpdateAccountData(WorldPacket &recv_data)
uLongf realSize = decompressedSize; uLongf realSize = decompressedSize;
if(uncompress(const_cast<uint8*>(dest.contents()), &realSize, const_cast<uint8*>(recv_data.contents() + recv_data.rpos()), recv_data.size() - recv_data.rpos()) != Z_OK) if(uncompress(const_cast<uint8*>(dest.contents()), &realSize, const_cast<uint8*>(recv_data.contents() + recv_data.rpos()), recv_data.size() - recv_data.rpos()) != Z_OK)
{ {
recv_data.rpos(recv_data.wpos()); // unnneded warning spam in this case
sLog.outError("UAD: Failed to decompress account data"); sLog.outError("UAD: Failed to decompress account data");
return; return;
} }
recv_data.rpos(recv_data.wpos()); // uncompress read (recv_data.size() - recv_data.rpos())
std::string adata; std::string adata;
dest >> adata; dest >> adata;
@@ -1050,7 +1054,8 @@ void WorldSession::HandleMoveTimeSkippedOpcode( WorldPacket & recv_data )
/* WorldSession::Update( getMSTime() );*/ /* WorldSession::Update( getMSTime() );*/
DEBUG_LOG( "WORLD: Time Lag/Synchronization Resent/Update" ); DEBUG_LOG( "WORLD: Time Lag/Synchronization Resent/Update" );
recv_data.read_skip2<uint64,uint32>(); recv_data.read_skip<uint64>();
recv_data.read_skip<uint32>();
/* /*
uint64 guid; uint64 guid;
uint32 time_skipped; uint32 time_skipped;
+2 -1
View File
@@ -28,7 +28,8 @@ void WorldSession::HandleVoiceSessionEnableOpcode( WorldPacket & recv_data )
{ {
sLog.outDebug("WORLD: CMSG_VOICE_SESSION_ENABLE"); sLog.outDebug("WORLD: CMSG_VOICE_SESSION_ENABLE");
// uint8 isVoiceEnabled, uint8 isMicrophoneEnabled // uint8 isVoiceEnabled, uint8 isMicrophoneEnabled
recv_data.read_skip2<uint8,uint8>(); recv_data.read_skip<uint8>();
recv_data.read_skip<uint8>();
recv_data.hexlike(); recv_data.hexlike();
} }
+25 -6
View File
@@ -147,7 +147,7 @@ void WorldSession::QueuePacket(WorldPacket* new_packet)
} }
/// Logging helper for unexpected opcodes /// Logging helper for unexpected opcodes
void WorldSession::logUnexpectedOpcode(WorldPacket* packet, const char *reason) void WorldSession::LogUnexpectedOpcode(WorldPacket* packet, const char *reason)
{ {
sLog.outError( "SESSION: received unexpected opcode %s (0x%.4X) %s", sLog.outError( "SESSION: received unexpected opcode %s (0x%.4X) %s",
LookupOpcodeName(packet->GetOpcode()), LookupOpcodeName(packet->GetOpcode()),
@@ -155,6 +155,15 @@ void WorldSession::logUnexpectedOpcode(WorldPacket* packet, const char *reason)
reason); reason);
} }
/// Logging helper for unexpected opcodes
void WorldSession::LogUnprocessedTail(WorldPacket *packet)
{
sLog.outError( "SESSION: opcode %s (0x%.4X) have unprocessed tail data (read stop at %u from %u)",
LookupOpcodeName(packet->GetOpcode()),
packet->GetOpcode(),
packet->rpos(),packet->wpos());
}
/// Update the WorldSession (triggered by World update) /// Update the WorldSession (triggered by World update)
bool WorldSession::Update(uint32 /*diff*/) bool WorldSession::Update(uint32 /*diff*/)
{ {
@@ -188,30 +197,40 @@ bool WorldSession::Update(uint32 /*diff*/)
{ {
// skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets
if(!m_playerRecentlyLogout) if(!m_playerRecentlyLogout)
logUnexpectedOpcode(packet, "the player has not logged in yet"); LogUnexpectedOpcode(packet, "the player has not logged in yet");
} }
else if(_player->IsInWorld()) else if(_player->IsInWorld())
{
(this->*opHandle.handler)(*packet); (this->*opHandle.handler)(*packet);
if (sLog.IsOutDebug() && packet->rpos() < packet->wpos())
LogUnprocessedTail(packet);
}
// lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer
break; break;
case STATUS_TRANSFER: case STATUS_TRANSFER:
if(!_player) if(!_player)
logUnexpectedOpcode(packet, "the player has not logged in yet"); LogUnexpectedOpcode(packet, "the player has not logged in yet");
else if(_player->IsInWorld()) else if(_player->IsInWorld())
logUnexpectedOpcode(packet, "the player is still in world"); LogUnexpectedOpcode(packet, "the player is still in world");
else else
{
(this->*opHandle.handler)(*packet); (this->*opHandle.handler)(*packet);
if (sLog.IsOutDebug() && packet->rpos() < packet->wpos())
LogUnprocessedTail(packet);
}
break; break;
case STATUS_AUTHED: case STATUS_AUTHED:
// prevent cheating with skip queue wait // prevent cheating with skip queue wait
if(m_inQueue) if(m_inQueue)
{ {
logUnexpectedOpcode(packet, "the player not pass queue yet"); LogUnexpectedOpcode(packet, "the player not pass queue yet");
break; break;
} }
m_playerRecentlyLogout = false; m_playerRecentlyLogout = false;
(this->*opHandle.handler)(*packet); (this->*opHandle.handler)(*packet);
if (sLog.IsOutDebug() && packet->rpos() < packet->wpos())
LogUnprocessedTail(packet);
break; break;
case STATUS_NEVER: case STATUS_NEVER:
break; break;
@@ -221,7 +240,7 @@ bool WorldSession::Update(uint32 /*diff*/)
break; break;
} }
} }
catch(ByteBufferException &exception) catch(ByteBufferException &)
{ {
sLog.outError("WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.", sLog.outError("WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.",
packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId()); packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId());
+3 -1
View File
@@ -722,7 +722,9 @@ class TRINITY_DLL_SPEC WorldSession
void moveItems(Item* myItems[], Item* hisItems[]); void moveItems(Item* myItems[], Item* hisItems[]);
// logging helper // logging helper
void logUnexpectedOpcode(WorldPacket *packet, const char * reason); void LogUnexpectedOpcode(WorldPacket *packet, const char * reason);
void LogUnprocessedTail(WorldPacket *packet);
Player *_player; Player *_player;
WorldSocket *m_Socket; WorldSocket *m_Socket;
std::string m_Address; std::string m_Address;
+1 -1
View File
@@ -655,7 +655,7 @@ int WorldSocket::ProcessIncoming (WorldPacket* new_pct)
} }
} }
} }
catch(ByteBufferException &exception) catch(ByteBufferException &)
{ {
sLog.outError("WorldSocket::ProcessIncoming ByteBufferException occured while parsing an instant handled packet (opcode: %u) from client %s, accountid=%i. Disconnected client.", sLog.outError("WorldSocket::ProcessIncoming ByteBufferException occured while parsing an instant handled packet (opcode: %u) from client %s, accountid=%i. Disconnected client.",
opcode, GetRemoteAddress().c_str(), m_Session?m_Session->GetAccountId():-1); opcode, GetRemoteAddress().c_str(), m_Session?m_Session->GetAccountId():-1);
-3
View File
@@ -265,9 +265,6 @@ class ByteBuffer
template<typename T> template<typename T>
void read_skip() { read_skip(sizeof(T)); } void read_skip() { read_skip(sizeof(T)); }
template<typename T1, typename T2>
void read_skip2() { read_skip(sizeof(T1)+sizeof(T2)); }
void read_skip(size_t skip) void read_skip(size_t skip)
{ {
if(_rpos + skip > size()) if(_rpos + skip > size())