From 35c42c1f23f74877d8820942b47acaca849b0e2d Mon Sep 17 00:00:00 2001 From: Minho Kang Date: Sat, 26 Aug 2017 15:06:27 +0900 Subject: [PATCH] Replace UtilNetwork with GamePacketParser --- .../Network/GamePacketParser.cpp | 161 ++++++++++++++++++ .../Server_Common/Network/GamePacketParser.h | 64 +++++++ .../Server_Common/Util/UtilNetwork.cpp | 35 ---- src/servers/Server_Common/Util/UtilNetwork.h | 18 -- src/servers/Server_Lobby/GameConnection.cpp | 42 ++++- .../Server_Zone/Network/GameConnection.cpp | 39 +++-- 6 files changed, 289 insertions(+), 70 deletions(-) create mode 100644 src/servers/Server_Common/Network/GamePacketParser.cpp create mode 100644 src/servers/Server_Common/Network/GamePacketParser.h delete mode 100644 src/servers/Server_Common/Util/UtilNetwork.cpp delete mode 100644 src/servers/Server_Common/Util/UtilNetwork.h diff --git a/src/servers/Server_Common/Network/GamePacketParser.cpp b/src/servers/Server_Common/Network/GamePacketParser.cpp new file mode 100644 index 00000000..99d58b6a --- /dev/null +++ b/src/servers/Server_Common/Network/GamePacketParser.cpp @@ -0,0 +1,161 @@ +#include "CommonNetwork.h" +#include "GamePacketParser.h" + +using namespace Core::Network::Packets; + +namespace Core +{ + namespace Network + { + namespace Packets + { + PacketParseResult getHeader( + const std::vector< uint8_t > &buffer, + const uint32_t offset, + FFXIVARR_PACKET_HEADER &header) + { + const auto headerSize = sizeof( FFXIVARR_PACKET_HEADER ); + + // Check if we have enough bytes in the buffer. + auto remainingBytes = buffer.size() - offset; + if ( remainingBytes < headerSize ) + { + return Incomplete; + } + + // Copy packet header. + memcpy( &header, buffer.data() + offset, headerSize ); + + if ( !checkHeader(header) ) + { + return Malformed; + } + + return Success; + } + + PacketParseResult getSegmentHeader( + const std::vector< uint8_t > &buffer, + const uint32_t offset, + FFXIVARR_PACKET_SEGMENT_HEADER &header) + { + const auto headerSize = sizeof( FFXIVARR_PACKET_SEGMENT_HEADER ); + + // Check if we have enough bytes in the buffer. + auto remainingBytes = buffer.size() - offset; + if (remainingBytes < headerSize) + { + return Incomplete; + } + + // Copy segment header + memcpy(&header, buffer.data() + offset, headerSize); + + return Success; + } + + PacketParseResult getPackets( + const std::vector< uint8_t > &buffer, + const uint32_t offset, + const FFXIVARR_PACKET_HEADER &packetHeader, + std::vector< FFXIVARR_PACKET_RAW > &packets) + { + // sanity check: check there's enough bytes in the buffer + const auto bytesExpected = packetHeader.size - sizeof(struct FFXIVARR_PACKET_HEADER); + if ( buffer.size() - offset < bytesExpected ) + { + return Incomplete; + } + + // Loop each message + uint32_t count = 0; + uint32_t bytesProcessed = 0; + while ( count < packetHeader.count ) + { + FFXIVARR_PACKET_RAW rawPacket; + + // Copy ipc packet message + const auto packetResult = getPacket(buffer, offset + bytesProcessed, rawPacket); + if ( packetResult != Success ) + { + return packetResult; + } + + // NOTE: isn't rawPacket is allocated on stack? + // why is okay to do this? + packets.push_back( rawPacket ); + + // Add message size and count + bytesProcessed += rawPacket.segHdr.size; + count += 1; + } + + // sanity check: check if we processed all bytes. + // this check can fail if size of messages don't add up to size reported from packet header. + if ( bytesExpected != bytesProcessed ) + { + return Malformed; + } + + return Success; + } + + PacketParseResult getPacket( + const std::vector< uint8_t > &buffer, + const uint32_t offset, + FFXIVARR_PACKET_RAW &packet + ) + { + // Copy segment header + const auto headerResult = getSegmentHeader(buffer, offset, packet.segHdr); + if ( headerResult != Success ) + { + return headerResult; + } + + // Check header sanity and it's size + if ( !checkSegmentHeader( packet.segHdr ) ) + { + return Malformed; + } + + const auto dataOffset = offset + sizeof(struct FFXIVARR_PACKET_SEGMENT_HEADER); + const auto dataSize = packet.segHdr.size; + + // Allocate data buffer and copy + packet.data.resize( dataSize ); + memcpy( packet.data.data(), buffer.data() + dataOffset, dataSize ); + + return Success; + } + + bool checkHeader(const FFXIVARR_PACKET_HEADER &header) + { + // Max size of the packet is capped at 1MB for now. + if ( header.size > 1 * 1024 * 1024 ) + { + return false; + } + + // Max number of message is capped at 255 for now. + if ( header.count > 255 ) + { + return false; + } + + return true; + } + + bool checkSegmentHeader(const FFXIVARR_PACKET_SEGMENT_HEADER &header) + { + // Max size of individual message is capped at 256KB for now. + if ( header.size > 256 * 1024 ) + { + return false; + } + + return true; + } + } + } +} diff --git a/src/servers/Server_Common/Network/GamePacketParser.h b/src/servers/Server_Common/Network/GamePacketParser.h new file mode 100644 index 00000000..1ffda893 --- /dev/null +++ b/src/servers/Server_Common/Network/GamePacketParser.h @@ -0,0 +1,64 @@ +#ifndef _GAMEPACKETPARSER_H +#define _GAMEPACKETPARSER_H +#include "CommonNetwork.h" + +namespace Core +{ + namespace Network + { + namespace Packets + { + enum PacketParseResult + { + /// Dissected game packet successfully + Success, + + /// Buffer is too short to dissect a message. + Incomplete, + + /// Invalid data detected. + Malformed + }; + + /// Read packet header from buffer with given offset. + /// Buffer with given offset must be pointing to start of the new FFXIV packet. + PacketParseResult getHeader( + const std::vector< uint8_t > &buffer, + const uint32_t offset, + FFXIVARR_PACKET_HEADER &header + ); + + /// Read packet header from buffer with given offset. + /// Buffer with given offset must be pointing to start of FFXIVARR_PACKET_SEGMENT_HEADER data. + /// Keep in mind that this function does check for data validity. Call checkSegmentHeader() if that's needed. + PacketParseResult getSegmentHeader( + const std::vector< uint8_t > &buffer, + const uint32_t offset, + FFXIVARR_PACKET_SEGMENT_HEADER &header + ); + + /// Read packets from the buffer with given offset. + /// Buffer with given offset must be pointing to end of FFXIVARR_PACKET_HEADER data. + PacketParseResult getPackets( + const std::vector< uint8_t > &buffer, + const uint32_t offset, + const FFXIVARR_PACKET_HEADER &header, + std::vector< Packets::FFXIVARR_PACKET_RAW > &packets); + + /// Read single packet from the buffer with given offset. + /// Buffer with an offset must be pointing to start of FFXIVARR_PACKET_SEGMENT_HEADER data. + PacketParseResult getPacket( + const std::vector< uint8_t > &buffer, + const uint32_t offset, + FFXIVARR_PACKET_RAW &packet + ); + + bool checkHeader(const FFXIVARR_PACKET_HEADER &header); + bool checkSegmentHeader(const FFXIVARR_PACKET_SEGMENT_HEADER &header); + + } + } +} + + +#endif \ No newline at end of file diff --git a/src/servers/Server_Common/Util/UtilNetwork.cpp b/src/servers/Server_Common/Util/UtilNetwork.cpp deleted file mode 100644 index 84905726..00000000 --- a/src/servers/Server_Common/Util/UtilNetwork.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "UtilNetwork.h" -#include - -bool Core::Network::Util::bufferToPacketList( const std::vector< uint8_t > &buffer, - Packets::FFXIVARR_PACKET_HEADER &ipcHeader, - std::vector< Packets::FFXIVARR_PACKET_RAW > &packetList ) -{ - memcpy( &ipcHeader, ( uint8_t* ) &buffer[0], sizeof( struct Packets::FFXIVARR_PACKET_HEADER ) ); - - uint16_t offset = 0; - for( std::size_t x = 0; x < ipcHeader.count; x++ ) - { - Packets::FFXIVARR_PACKET_RAW packet; - - uint32_t headerSize = sizeof( struct Packets::FFXIVARR_PACKET_HEADER ); - uint32_t headerSegSize = sizeof( struct Packets::FFXIVARR_PACKET_SEGMENT_HEADER ); - memcpy( &packet.segHdr, ( uint8_t* ) &buffer[headerSize + offset], headerSegSize ); - - std::vector packetData; - - uint16_t startOff = sizeof( struct Packets::FFXIVARR_PACKET_HEADER ) + offset; - - for( std::size_t y = 0; y < packet.segHdr.size - sizeof( struct Packets::FFXIVARR_PACKET_SEGMENT_HEADER ); y++ ) - { - packet.data.push_back( buffer.at( startOff + y + sizeof( struct Packets::FFXIVARR_PACKET_SEGMENT_HEADER ) ) ); - } - - offset += packet.segHdr.size; - - packetList.push_back( packet ); - - } - - return true; -} diff --git a/src/servers/Server_Common/Util/UtilNetwork.h b/src/servers/Server_Common/Util/UtilNetwork.h deleted file mode 100644 index 2244e730..00000000 --- a/src/servers/Server_Common/Util/UtilNetwork.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _UTILNETWORK_H -#define _UTILNETWORK_H - -#include "src/servers/Server_Common/Network/CommonNetwork.h" - -namespace Core { -namespace Network { -namespace Util { - - - bool bufferToPacketList( const std::vector< uint8_t > &buffer, - Packets::FFXIVARR_PACKET_HEADER &ipcHeader, - std::vector< Packets::FFXIVARR_PACKET_RAW > &packetList ); -} -} -} - -#endif \ No newline at end of file diff --git a/src/servers/Server_Lobby/GameConnection.cpp b/src/servers/Server_Lobby/GameConnection.cpp index 9af5a4c2..d0c6fe23 100644 --- a/src/servers/Server_Lobby/GameConnection.cpp +++ b/src/servers/Server_Lobby/GameConnection.cpp @@ -1,11 +1,11 @@ #include #include #include -#include #include #include #include #include +#include "Server_Common/Network/GamePacketParser.h" #include #include @@ -25,7 +25,6 @@ - extern Core::Logger g_log; extern Core::ServerLobby g_serverLobby; extern Core::Network::RestConnector g_restConnector; @@ -65,12 +64,45 @@ void Core::Network::GameConnection::OnDisconnect() void Core::Network::GameConnection::OnRecv( std::vector< uint8_t > & buffer ) { - Packets::FFXIVARR_PACKET_HEADER ipcHeader; + Packets::FFXIVARR_PACKET_HEADER packetHeader; + const auto headerResult = Packets::getHeader(buffer, 0, packetHeader); + + if (headerResult == Incomplete) + { + g_log.info("Dropping connection due to incomplete packet header."); + g_log.info("FIXME: Packet message bounary is not implemented."); + Disconnect(); + return; + } + + if (headerResult == Malformed) + { + g_log.info("Dropping connection due to malformed packet header."); + Disconnect(); + return; + } + + // Dissect packet list std::vector< Packets::FFXIVARR_PACKET_RAW > packetList; + const auto packetResult = Packets::getPackets(buffer, sizeof(struct FFXIVARR_PACKET_HEADER), packetHeader, packetList); - Network::Util::bufferToPacketList( buffer, ipcHeader, packetList ); + if (packetResult == Incomplete) + { + g_log.info("Dropping connection due to incomplete packets."); + g_log.info("FIXME: Packet message bounary is not implemented."); + Disconnect(); + return; + } - handlePackets( ipcHeader, packetList ); + if (packetResult == Malformed) + { + g_log.info("Dropping connection due to malformed packets."); + Disconnect(); + return; + } + + // Handle it + handlePackets(packetHeader, packetList); } diff --git a/src/servers/Server_Zone/Network/GameConnection.cpp b/src/servers/Server_Zone/Network/GameConnection.cpp index dec30f51..b70e5c07 100644 --- a/src/servers/Server_Zone/Network/GameConnection.cpp +++ b/src/servers/Server_Zone/Network/GameConnection.cpp @@ -2,9 +2,9 @@ #include #include #include -#include #include #include +#include #include #include "GameConnection.h" @@ -112,30 +112,45 @@ void Core::Network::GameConnection::OnRecv( std::vector< uint8_t > & buffer ) { // This is assumed packet always start with valid FFXIVARR_PACKET_HEADER for now. - // not enough bytes for packet header, drop connection for now. - // TODO: buffer it + Packets::FFXIVARR_PACKET_HEADER packetHeader; + const auto headerResult = Packets::getHeader(buffer, 0, packetHeader); - // Dissect packet header - Packets::FFXIVARR_PACKET_HEADER ipcHeader; - if ( !Network::Util::bufferToPacketHeader( buffer, ipcHeader ) ) + if (headerResult == Incomplete) { - g_log.info("FIXME: Dropping connection due to incomplete packet header."); - g_log.info("See https://github.com/SapphireMordred/Sapphire/issues/24 for more info."); + g_log.info("Dropping connection due to incomplete packet header."); + g_log.info("FIXME: Packet message bounary is not implemented."); Disconnect(); return; } - + + if (headerResult == Malformed) + { + g_log.info("Dropping connection due to malformed packet header."); + Disconnect(); + return; + } + // Dissect packet list std::vector< Packets::FFXIVARR_PACKET_RAW > packetList; - if ( !Network::Util::bufferToPacketList( buffer, ipcHeader, packetList ) ) + const auto packetResult = Packets::getPackets(buffer, sizeof(struct FFXIVARR_PACKET_HEADER), packetHeader, packetList); + + if (packetResult == Incomplete) { - g_log.info("Dropping connection due to incomplete message."); + g_log.info("Dropping connection due to incomplete packets."); + g_log.info("FIXME: Packet message bounary is not implemented."); Disconnect(); return; } + if (packetResult == Malformed) + { + g_log.info("Dropping connection due to malformed packets."); + Disconnect(); + return; + } + // Handle it - handlePackets( ipcHeader, packetList ); + handlePackets( packetHeader, packetList ); } void Core::Network::GameConnection::OnError( const boost::system::error_code & error )