diff options
Diffstat (limited to 'Tools')
-rw-r--r-- | Tools/ProtoProxy/Connection.cpp | 709 | ||||
-rw-r--r-- | Tools/ProtoProxy/Connection.h | 52 | ||||
-rw-r--r-- | Tools/ProtoProxy/Globals.h | 4 |
3 files changed, 471 insertions, 294 deletions
diff --git a/Tools/ProtoProxy/Connection.cpp b/Tools/ProtoProxy/Connection.cpp index c4776949e..4b3442858 100644 --- a/Tools/ProtoProxy/Connection.cpp +++ b/Tools/ProtoProxy/Connection.cpp @@ -52,7 +52,7 @@ #define CLIENTSEND(...) SendData(m_ClientSocket, __VA_ARGS__, "Client") #define SERVERSEND(...) SendData(m_ServerSocket, __VA_ARGS__, "Server") -#define CLIENTENCRYPTSEND(...) SendEncryptedData(m_ClientSocket, m_ClientEncryptor, __VA_ARGS__, "Client") +#define CLIENTENCRYPTSEND(...) SendData(m_ClientSocket, __VA_ARGS__, "Client") // The client conn is always unencrypted #define SERVERENCRYPTSEND(...) SendEncryptedData(m_ServerSocket, m_ServerEncryptor, __VA_ARGS__, "Server") #define COPY_TO_SERVER() \ @@ -99,12 +99,13 @@ CLIENTENCRYPTSEND(ToClient.data(), ToClient.size()); \ break; \ } \ - case csWaitingForEncryption: \ + /* case csWaitingForEncryption: \ { \ Log("Waiting for client encryption, queued %u bytes", ToClient.size()); \ m_ClientEncryptionBuffer.append(ToClient.data(), ToClient.size()); \ break; \ } \ + */ \ } \ DebugSleep(50); \ } @@ -144,15 +145,20 @@ typedef unsigned char Byte; enum { - PACKET_KEEPALIVE = 0x00, - PACKET_LOGIN = 0x01, - PACKET_HANDSHAKE = 0x02, - PACKET_CHAT_MESSAGE = 0x03, - PACKET_TIME_UPDATE = 0x04, - PACKET_ENTITY_EQUIPMENT = 0x05, - PACKET_COMPASS = 0x06, + // client-bound packets: + PACKET_C_KEEPALIVE = 0x00, + PACKET_C_JOIN_GAME = 0x01, + PACKET_C_CHAT_MESSAGE = 0x02, + + // server-bound packets: + PACKET_S_KEEPALIVE = 0x00, // Also the initial handshake, as the very first packet + PACKET_S_CHAT_MESSAGE = 0x01, + + PACKET_TIME_UPDATE = 0x03, + PACKET_ENTITY_EQUIPMENT = 0x04, + PACKET_SPAWN_POSITION = 0x05, + PACKET_UPDATE_HEALTH = 0x06, PACKET_USE_ENTITY = 0x07, - PACKET_UPDATE_HEALTH = 0x08, PACKET_PLAYER_ON_GROUND = 0x0a, PACKET_PLAYER_POSITION = 0x0b, PACKET_PLAYER_LOOK = 0x0c, @@ -270,7 +276,10 @@ cConnection::cConnection(SOCKET a_ClientSocket, cServer & a_Server) : m_Nonce(0), m_ClientBuffer(1024 KiB), m_ServerBuffer(1024 KiB), - m_HasClientPinged(false) + m_HasClientPinged(false), + m_ServerProtocolState(-1), + m_ClientProtocolState(-1), + m_IsServerEncrypted(false) { // Create the Logs subfolder, if not already created: #if defined(_WIN32) @@ -279,7 +288,7 @@ cConnection::cConnection(SOCKET a_ClientSocket, cServer & a_Server) : mkdir("Logs", 0777); #endif - Printf(m_LogNameBase, "Logs/Log_%d", (int)time(NULL)); + Printf(m_LogNameBase, "Logs/Log_%d_%d", (int)time(NULL), a_ClientSocket); AString fnam(m_LogNameBase); fnam.append(".log"); m_LogFile = fopen(fnam.c_str(), "w"); @@ -453,7 +462,6 @@ bool cConnection::RelayFromServer(void) { m_ServerDecryptor.ProcessData((byte *)Buffer, (byte *)Buffer, res); DataLog(Buffer, res, "Decrypted %d bytes from the SERVER", res); - m_ClientEncryptor.ProcessData((byte *)Buffer, (byte *)Buffer, res); return CLIENTSEND(Buffer, res); } } @@ -486,13 +494,10 @@ bool cConnection::RelayFromClient(void) } case csEncryptedUnderstood: { - m_ClientDecryptor.ProcessData((byte *)Buffer, (byte *)Buffer, res); - DataLog(Buffer, res, "Decrypted %d bytes from the CLIENT", res); return DecodeClientsPackets(Buffer, res); } case csEncryptedUnknown: { - m_ClientDecryptor.ProcessData((byte *)Buffer, (byte *)Buffer, res); DataLog(Buffer, res, "Decrypted %d bytes from the CLIENT", res); m_ServerEncryptor.ProcessData((byte *)Buffer, (byte *)Buffer, res); return SERVERSEND(Buffer, res); @@ -517,7 +522,7 @@ double cConnection::GetRelativeTime(void) bool cConnection::SendData(SOCKET a_Socket, const char * a_Data, int a_Size, const char * a_Peer) { - DataLog(a_Data, a_Size, "Sending data to %s", a_Peer); + DataLog(a_Data, a_Size, "Sending data to %s, %d bytes", a_Peer, a_Size); int res = send(a_Socket, a_Data, a_Size, 0); if (res <= 0) @@ -590,38 +595,87 @@ bool cConnection::DecodeClientsPackets(const char * a_Data, int a_Size) while (m_ClientBuffer.CanReadBytes(1)) { - unsigned char PacketType; - m_ClientBuffer.ReadByte(PacketType); - Log("Decoding client's packets, there are now %d bytes in the queue; next packet is 0x%02x", m_ClientBuffer.GetReadableSpace(), PacketType); - switch (PacketType) + UInt32 PacketLen; + if ( + !m_ClientBuffer.ReadVarInt(PacketLen) || + !m_ClientBuffer.CanReadBytes(PacketLen) + ) + { + // Not a complete packet yet + break; + } + UInt32 PacketType; + VERIFY(m_ClientBuffer.ReadVarInt(PacketType)); + Log("Decoding client's packets, there are now %d bytes in the queue; next packet is 0x%0x, %u bytes long", m_ClientBuffer.GetReadableSpace(), PacketType, PacketLen); + switch (m_ClientProtocolState) { - case PACKET_BLOCK_DIG: HANDLE_CLIENT_READ(HandleClientBlockDig); break; - case PACKET_BLOCK_PLACE: HANDLE_CLIENT_READ(HandleClientBlockPlace); break; - case PACKET_CHAT_MESSAGE: HANDLE_CLIENT_READ(HandleClientChatMessage); break; - case PACKET_CLIENT_STATUSES: HANDLE_CLIENT_READ(HandleClientClientStatuses); break; - case PACKET_CREATIVE_INVENTORY_ACTION: HANDLE_CLIENT_READ(HandleClientCreativeInventoryAction); break; - case PACKET_DISCONNECT: HANDLE_CLIENT_READ(HandleClientDisconnect); break; - case PACKET_ENCRYPTION_KEY_RESPONSE: HANDLE_CLIENT_READ(HandleClientEncryptionKeyResponse); break; - case PACKET_ENTITY_ACTION: HANDLE_CLIENT_READ(HandleClientEntityAction); break; - case PACKET_HANDSHAKE: HANDLE_CLIENT_READ(HandleClientHandshake); break; - case PACKET_KEEPALIVE: HANDLE_CLIENT_READ(HandleClientKeepAlive); break; - case PACKET_LOCALE_AND_VIEW: HANDLE_CLIENT_READ(HandleClientLocaleAndView); break; - case PACKET_PING: HANDLE_CLIENT_READ(HandleClientPing); break; - case PACKET_PLAYER_ABILITIES: HANDLE_CLIENT_READ(HandleClientPlayerAbilities); break; - case PACKET_PLAYER_ANIMATION: HANDLE_CLIENT_READ(HandleClientAnimation); break; - case PACKET_PLAYER_LOOK: HANDLE_CLIENT_READ(HandleClientPlayerLook); break; - case PACKET_PLAYER_ON_GROUND: HANDLE_CLIENT_READ(HandleClientPlayerOnGround); break; - case PACKET_PLAYER_POSITION: HANDLE_CLIENT_READ(HandleClientPlayerPosition); break; - case PACKET_PLAYER_POSITION_LOOK: HANDLE_CLIENT_READ(HandleClientPlayerPositionLook); break; - case PACKET_PLUGIN_MESSAGE: HANDLE_CLIENT_READ(HandleClientPluginMessage); break; - case PACKET_SLOT_SELECT: HANDLE_CLIENT_READ(HandleClientSlotSelect); break; - case PACKET_TAB_COMPLETION: HANDLE_CLIENT_READ(HandleClientTabCompletion); break; - case PACKET_UPDATE_SIGN: HANDLE_CLIENT_READ(HandleClientUpdateSign); break; - case PACKET_USE_ENTITY: HANDLE_CLIENT_READ(HandleClientUseEntity); break; - case PACKET_WINDOW_CLICK: HANDLE_CLIENT_READ(HandleClientWindowClick); break; - case PACKET_WINDOW_CLOSE: HANDLE_CLIENT_READ(HandleClientWindowClose); break; + case -1: + { + // No initial handshake received yet + switch (PacketType) + { + case 0: HANDLE_CLIENT_READ(HandleClientHandshake); break; + } + break; + } // case -1 + + case 1: + { + // Status query + switch (PacketType) + { + case 0x00: HANDLE_CLIENT_READ(HandleClientStatusRequest); break; + case 0x01: HANDLE_CLIENT_READ(HandleClientStatusPing); break; + } + break; + } + + case 2: + { + // Login + switch (PacketType) + { + case 0x00: HANDLE_CLIENT_READ(HandleClientLoginStart); break; + case 0x01: HANDLE_CLIENT_READ(HandleClientLoginEncryptionKeyResponse); break; + } + break; + } + + case 3: + { + // Game: + switch (PacketType) + { + case PACKET_BLOCK_DIG: HANDLE_CLIENT_READ(HandleClientBlockDig); break; + case PACKET_BLOCK_PLACE: HANDLE_CLIENT_READ(HandleClientBlockPlace); break; + case PACKET_S_CHAT_MESSAGE: HANDLE_CLIENT_READ(HandleClientChatMessage); break; + case PACKET_CLIENT_STATUSES: HANDLE_CLIENT_READ(HandleClientClientStatuses); break; + case PACKET_CREATIVE_INVENTORY_ACTION: HANDLE_CLIENT_READ(HandleClientCreativeInventoryAction); break; + case PACKET_DISCONNECT: HANDLE_CLIENT_READ(HandleClientDisconnect); break; + case PACKET_ENTITY_ACTION: HANDLE_CLIENT_READ(HandleClientEntityAction); break; + case PACKET_S_KEEPALIVE: HANDLE_CLIENT_READ(HandleClientKeepAlive); break; + case PACKET_LOCALE_AND_VIEW: HANDLE_CLIENT_READ(HandleClientLocaleAndView); break; + case PACKET_PING: HANDLE_CLIENT_READ(HandleClientPing); break; + case PACKET_PLAYER_ABILITIES: HANDLE_CLIENT_READ(HandleClientPlayerAbilities); break; + case PACKET_PLAYER_ANIMATION: HANDLE_CLIENT_READ(HandleClientAnimation); break; + case PACKET_PLAYER_LOOK: HANDLE_CLIENT_READ(HandleClientPlayerLook); break; + case PACKET_PLAYER_ON_GROUND: HANDLE_CLIENT_READ(HandleClientPlayerOnGround); break; + case PACKET_PLAYER_POSITION: HANDLE_CLIENT_READ(HandleClientPlayerPosition); break; + case PACKET_PLAYER_POSITION_LOOK: HANDLE_CLIENT_READ(HandleClientPlayerPositionLook); break; + case PACKET_PLUGIN_MESSAGE: HANDLE_CLIENT_READ(HandleClientPluginMessage); break; + case PACKET_SLOT_SELECT: HANDLE_CLIENT_READ(HandleClientSlotSelect); break; + case PACKET_TAB_COMPLETION: HANDLE_CLIENT_READ(HandleClientTabCompletion); break; + case PACKET_UPDATE_SIGN: HANDLE_CLIENT_READ(HandleClientUpdateSign); break; + case PACKET_USE_ENTITY: HANDLE_CLIENT_READ(HandleClientUseEntity); break; + case PACKET_WINDOW_CLICK: HANDLE_CLIENT_READ(HandleClientWindowClick); break; + case PACKET_WINDOW_CLOSE: HANDLE_CLIENT_READ(HandleClientWindowClose); break; + } + break; + } // case 2 + default: { + // TODO: Move this elsewhere if (m_ClientState == csEncryptedUnderstood) { Log("****************** Unknown packet 0x%02x from the client while encrypted; continuing to relay blind only", PacketType); @@ -646,10 +700,10 @@ bool cConnection::DecodeClientsPackets(const char * a_Data, int a_Size) Log("Unknown packet 0x%02x from the client while unencrypted; aborting connection", PacketType); return false; } - } - } // switch (PacketType) + } // default + } // switch (m_ProtocolState) m_ClientBuffer.CommitRead(); - } // while (CanReadBytes(1)) + } // while (true) return true; } @@ -673,66 +727,114 @@ bool cConnection::DecodeServersPackets(const char * a_Data, int a_Size) // Client hasn't finished encryption handshake yet, don't send them any data yet } - while (m_ServerBuffer.CanReadBytes(1)) + while (true) { - unsigned char PacketType; - m_ServerBuffer.ReadByte(PacketType); - Log("Decoding server's packets, there are now %d bytes in the queue; next packet is 0x%02x", m_ServerBuffer.GetReadableSpace(), PacketType); + UInt32 PacketLen; + if ( + !m_ServerBuffer.ReadVarInt(PacketLen) || + !m_ServerBuffer.CanReadBytes(PacketLen) + ) + { + // Not a complete packet yet + break; + } + UInt32 PacketType; + VERIFY(m_ServerBuffer.ReadVarInt(PacketType)); + Log("Decoding server's packets, there are now %d bytes in the queue; next packet is 0x%0x, %u bytes long", m_ServerBuffer.GetReadableSpace(), PacketType, PacketLen); LogFlush(); - switch (PacketType) + switch (m_ServerProtocolState) { - case PACKET_ATTACH_ENTITY: HANDLE_SERVER_READ(HandleServerAttachEntity); break; - case PACKET_BLOCK_ACTION: HANDLE_SERVER_READ(HandleServerBlockAction); break; - case PACKET_BLOCK_CHANGE: HANDLE_SERVER_READ(HandleServerBlockChange); break; - case PACKET_CHANGE_GAME_STATE: HANDLE_SERVER_READ(HandleServerChangeGameState); break; - case PACKET_CHAT_MESSAGE: HANDLE_SERVER_READ(HandleServerChatMessage); break; - case PACKET_COLLECT_PICKUP: HANDLE_SERVER_READ(HandleServerCollectPickup); break; - case PACKET_COMPASS: HANDLE_SERVER_READ(HandleServerCompass); break; - case PACKET_DESTROY_ENTITIES: HANDLE_SERVER_READ(HandleServerDestroyEntities); break; - case PACKET_ENCRYPTION_KEY_REQUEST: HANDLE_SERVER_READ(HandleServerEncryptionKeyRequest); break; - case PACKET_ENCRYPTION_KEY_RESPONSE: HANDLE_SERVER_READ(HandleServerEncryptionKeyResponse); break; - case PACKET_ENTITY: HANDLE_SERVER_READ(HandleServerEntity); break; - case PACKET_ENTITY_EQUIPMENT: HANDLE_SERVER_READ(HandleServerEntityEquipment); break; - case PACKET_ENTITY_HEAD_LOOK: HANDLE_SERVER_READ(HandleServerEntityHeadLook); break; - case PACKET_ENTITY_LOOK: HANDLE_SERVER_READ(HandleServerEntityLook); break; - case PACKET_ENTITY_METADATA: HANDLE_SERVER_READ(HandleServerEntityMetadata); break; - case PACKET_ENTITY_PROPERTIES: HANDLE_SERVER_READ(HandleServerEntityProperties); break; - case PACKET_ENTITY_RELATIVE_MOVE: HANDLE_SERVER_READ(HandleServerEntityRelativeMove); break; - case PACKET_ENTITY_RELATIVE_MOVE_LOOK: HANDLE_SERVER_READ(HandleServerEntityRelativeMoveLook); break; - case PACKET_ENTITY_STATUS: HANDLE_SERVER_READ(HandleServerEntityStatus); break; - case PACKET_ENTITY_TELEPORT: HANDLE_SERVER_READ(HandleServerEntityTeleport); break; - case PACKET_ENTITY_VELOCITY: HANDLE_SERVER_READ(HandleServerEntityVelocity); break; - case PACKET_EXPLOSION: HANDLE_SERVER_READ(HandleServerExplosion); break; - case PACKET_INCREMENT_STATISTIC: HANDLE_SERVER_READ(HandleServerIncrementStatistic); break; - case PACKET_KEEPALIVE: HANDLE_SERVER_READ(HandleServerKeepAlive); break; - case PACKET_KICK: HANDLE_SERVER_READ(HandleServerKick); break; - case PACKET_LOGIN: HANDLE_SERVER_READ(HandleServerLogin); break; - case PACKET_MAP_CHUNK: HANDLE_SERVER_READ(HandleServerMapChunk); break; - case PACKET_MAP_CHUNK_BULK: HANDLE_SERVER_READ(HandleServerMapChunkBulk); break; - case PACKET_MULTI_BLOCK_CHANGE: HANDLE_SERVER_READ(HandleServerMultiBlockChange); break; - case PACKET_NAMED_SOUND_EFFECT: HANDLE_SERVER_READ(HandleServerNamedSoundEffect); break; - case PACKET_PLAYER_ABILITIES: HANDLE_SERVER_READ(HandleServerPlayerAbilities); break; - case PACKET_PLAYER_ANIMATION: HANDLE_SERVER_READ(HandleServerPlayerAnimation); break; - case PACKET_PLAYER_LIST_ITEM: HANDLE_SERVER_READ(HandleServerPlayerListItem); break; - case PACKET_PLAYER_POSITION_LOOK: HANDLE_SERVER_READ(HandleServerPlayerPositionLook); break; - case PACKET_PLUGIN_MESSAGE: HANDLE_SERVER_READ(HandleServerPluginMessage); break; - case PACKET_SET_EXPERIENCE: HANDLE_SERVER_READ(HandleServerSetExperience); break; - case PACKET_SET_SLOT: HANDLE_SERVER_READ(HandleServerSetSlot); break; - case PACKET_SLOT_SELECT: HANDLE_SERVER_READ(HandleServerSlotSelect); break; - case PACKET_SOUND_EFFECT: HANDLE_SERVER_READ(HandleServerSoundEffect); break; - case PACKET_SPAWN_MOB: HANDLE_SERVER_READ(HandleServerSpawnMob); break; - case PACKET_SPAWN_NAMED_ENTITY: HANDLE_SERVER_READ(HandleServerSpawnNamedEntity); break; - case PACKET_SPAWN_OBJECT_VEHICLE: HANDLE_SERVER_READ(HandleServerSpawnObjectVehicle); break; - case PACKET_SPAWN_PAINTING: HANDLE_SERVER_READ(HandleServerSpawnPainting); break; - case PACKET_SPAWN_PICKUP: HANDLE_SERVER_READ(HandleServerSpawnPickup); break; - case PACKET_TAB_COMPLETION: HANDLE_SERVER_READ(HandleServerTabCompletion); break; - case PACKET_TIME_UPDATE: HANDLE_SERVER_READ(HandleServerTimeUpdate); break; - case PACKET_UPDATE_HEALTH: HANDLE_SERVER_READ(HandleServerUpdateHealth); break; - case PACKET_UPDATE_SIGN: HANDLE_SERVER_READ(HandleServerUpdateSign); break; - case PACKET_UPDATE_TILE_ENTITY: HANDLE_SERVER_READ(HandleServerUpdateTileEntity); break; - case PACKET_WINDOW_CLOSE: HANDLE_SERVER_READ(HandleServerWindowClose); break; - case PACKET_WINDOW_CONTENTS: HANDLE_SERVER_READ(HandleServerWindowContents); break; - case PACKET_WINDOW_OPEN: HANDLE_SERVER_READ(HandleServerWindowOpen); break; + case -1: + { + Log("Receiving data from the server without an initial handshake message!"); + break; + } + + case 1: + { + // Status query: + switch (PacketType) + { + case 0: HANDLE_SERVER_READ(HandleServerStatusResponse); break; + case 1: HANDLE_SERVER_READ(HandleServerStatusPing); break; + } + break; + } + + case 2: + { + // Login: + switch (PacketType) + { + case 0x00: HANDLE_SERVER_READ(HandleServerLoginDisconnect); break; + case 0x01: HANDLE_SERVER_READ(HandleServerLoginEncryptionKeyRequest); break; + case 0x02: HANDLE_SERVER_READ(HandleServerLoginSuccess); break; + } + break; + } + + case 3: + { + // Game: + switch (PacketType) + { + /* + case 0x1b: HANDLE_SERVER_READ(HandleServerAttachEntity); break; + case 0x24: HANDLE_SERVER_READ(HandleServerBlockAction); break; + case 0x23: HANDLE_SERVER_READ(HandleServerBlockChange); break; + case 0x2b: HANDLE_SERVER_READ(HandleServerChangeGameState); break; + case 0x02: HANDLE_SERVER_READ(HandleServerChatMessage); break; + case 0x0d: HANDLE_SERVER_READ(HandleServerCollectPickup); break; + case 0x13: HANDLE_SERVER_READ(HandleServerDestroyEntities); break; + */ + case PACKET_ENTITY: HANDLE_SERVER_READ(HandleServerEntity); break; + case PACKET_ENTITY_EQUIPMENT: HANDLE_SERVER_READ(HandleServerEntityEquipment); break; + case PACKET_ENTITY_HEAD_LOOK: HANDLE_SERVER_READ(HandleServerEntityHeadLook); break; + case PACKET_ENTITY_LOOK: HANDLE_SERVER_READ(HandleServerEntityLook); break; + case PACKET_ENTITY_METADATA: HANDLE_SERVER_READ(HandleServerEntityMetadata); break; + case PACKET_ENTITY_PROPERTIES: HANDLE_SERVER_READ(HandleServerEntityProperties); break; + case PACKET_ENTITY_RELATIVE_MOVE: HANDLE_SERVER_READ(HandleServerEntityRelativeMove); break; + case PACKET_ENTITY_RELATIVE_MOVE_LOOK: HANDLE_SERVER_READ(HandleServerEntityRelativeMoveLook); break; + case PACKET_ENTITY_STATUS: HANDLE_SERVER_READ(HandleServerEntityStatus); break; + case PACKET_ENTITY_TELEPORT: HANDLE_SERVER_READ(HandleServerEntityTeleport); break; + case PACKET_ENTITY_VELOCITY: HANDLE_SERVER_READ(HandleServerEntityVelocity); break; + case PACKET_EXPLOSION: HANDLE_SERVER_READ(HandleServerExplosion); break; + case PACKET_INCREMENT_STATISTIC: HANDLE_SERVER_READ(HandleServerIncrementStatistic); break; + case PACKET_C_JOIN_GAME: HANDLE_SERVER_READ(HandleServerLogin); break; + case PACKET_C_KEEPALIVE: HANDLE_SERVER_READ(HandleServerKeepAlive); break; + case PACKET_KICK: HANDLE_SERVER_READ(HandleServerKick); break; + case PACKET_MAP_CHUNK: HANDLE_SERVER_READ(HandleServerMapChunk); break; + case PACKET_MAP_CHUNK_BULK: HANDLE_SERVER_READ(HandleServerMapChunkBulk); break; + case PACKET_MULTI_BLOCK_CHANGE: HANDLE_SERVER_READ(HandleServerMultiBlockChange); break; + case PACKET_NAMED_SOUND_EFFECT: HANDLE_SERVER_READ(HandleServerNamedSoundEffect); break; + case PACKET_PLAYER_ABILITIES: HANDLE_SERVER_READ(HandleServerPlayerAbilities); break; + case PACKET_PLAYER_ANIMATION: HANDLE_SERVER_READ(HandleServerPlayerAnimation); break; + case PACKET_PLAYER_LIST_ITEM: HANDLE_SERVER_READ(HandleServerPlayerListItem); break; + case PACKET_PLAYER_POSITION_LOOK: HANDLE_SERVER_READ(HandleServerPlayerPositionLook); break; + case PACKET_PLUGIN_MESSAGE: HANDLE_SERVER_READ(HandleServerPluginMessage); break; + case PACKET_SET_EXPERIENCE: HANDLE_SERVER_READ(HandleServerSetExperience); break; + case PACKET_SET_SLOT: HANDLE_SERVER_READ(HandleServerSetSlot); break; + case PACKET_SLOT_SELECT: HANDLE_SERVER_READ(HandleServerSlotSelect); break; + case PACKET_SOUND_EFFECT: HANDLE_SERVER_READ(HandleServerSoundEffect); break; + case PACKET_SPAWN_MOB: HANDLE_SERVER_READ(HandleServerSpawnMob); break; + case PACKET_SPAWN_NAMED_ENTITY: HANDLE_SERVER_READ(HandleServerSpawnNamedEntity); break; + case PACKET_SPAWN_OBJECT_VEHICLE: HANDLE_SERVER_READ(HandleServerSpawnObjectVehicle); break; + case PACKET_SPAWN_PAINTING: HANDLE_SERVER_READ(HandleServerSpawnPainting); break; + case PACKET_SPAWN_PICKUP: HANDLE_SERVER_READ(HandleServerSpawnPickup); break; + case PACKET_SPAWN_POSITION: HANDLE_SERVER_READ(HandleServerCompass); break; + case PACKET_TAB_COMPLETION: HANDLE_SERVER_READ(HandleServerTabCompletion); break; + case PACKET_TIME_UPDATE: HANDLE_SERVER_READ(HandleServerTimeUpdate); break; + case PACKET_UPDATE_HEALTH: HANDLE_SERVER_READ(HandleServerUpdateHealth); break; + case PACKET_UPDATE_SIGN: HANDLE_SERVER_READ(HandleServerUpdateSign); break; + case PACKET_UPDATE_TILE_ENTITY: HANDLE_SERVER_READ(HandleServerUpdateTileEntity); break; + case PACKET_WINDOW_CLOSE: HANDLE_SERVER_READ(HandleServerWindowClose); break; + case PACKET_WINDOW_CONTENTS: HANDLE_SERVER_READ(HandleServerWindowContents); break; + case PACKET_WINDOW_OPEN: HANDLE_SERVER_READ(HandleServerWindowOpen); break; + } // switch (PacketType) + break; + } // case 2 + + // TODO: Move this elsewhere default: { if (m_ServerState == csEncryptedUnderstood) @@ -760,7 +862,8 @@ bool cConnection::DecodeServersPackets(const char * a_Data, int a_Size) return false; } } - } // switch (PacketType) + } // switch (m_ProtocolState) + m_ServerBuffer.CommitRead(); } // while (CanReadBytes(1)) return true; @@ -770,6 +873,76 @@ bool cConnection::DecodeServersPackets(const char * a_Data, int a_Size) +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// packet handling, client-side, initial handshake: + +bool cConnection::HandleClientHandshake(void) +{ + // Read the packet from the client: + HANDLE_CLIENT_PACKET_READ(ReadVarInt, UInt32, ProtocolVersion); + HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, ServerHost); + HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, ServerPort); + HANDLE_CLIENT_PACKET_READ(ReadVarInt, UInt32, NextState); + m_ClientBuffer.CommitRead(); + + Log("Received an initial handshake packet from the client:"); + Log(" ProtocolVersion = %u", ProtocolVersion); + Log(" ServerHost = \"%s\"", ServerHost.c_str()); + Log(" ServerPort = %d", ServerPort); + Log(" NextState = %u", NextState); + + // Send the same packet to the server, but with our port: + cByteBuffer Packet(512); + Packet.WriteVarInt(0); // Packet type - initial handshake + Packet.WriteVarInt(ProtocolVersion); + Packet.WriteVarUTF8String(ServerHost); + Packet.WriteBEShort(m_Server.GetConnectPort()); + Packet.WriteVarInt(NextState); + AString Pkt; + Packet.ReadAll(Pkt); + cByteBuffer ToServer(512); + ToServer.WriteVarUTF8String(Pkt); + SERVERSEND(ToServer); + + m_ClientProtocolState = (int)NextState; + m_ServerProtocolState = (int)NextState; + + return true; +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// packet handling, client-side, login: + +bool cConnection::HandleClientLoginEncryptionKeyResponse(void) +{ + Log("Client: Unexpected packet: encryption key response"); + return true; +} + + + + + +bool cConnection::HandleClientLoginStart(void) +{ + HANDLE_CLIENT_PACKET_READ(ReadVarUTF8String, AString, UserName); + Log("Received a login start packet from the client:"); + Log(" Username = \"%s\"", UserName.c_str()); + COPY_TO_SERVER(); + return true; +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// packet handling, client-side, game: + bool cConnection::HandleClientAnimation(void) { HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, EntityID); @@ -890,33 +1063,6 @@ bool cConnection::HandleClientDisconnect(void) -bool cConnection::HandleClientEncryptionKeyResponse(void) -{ - HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, EncKeyLength); - AString EncKey; - if (!m_ClientBuffer.ReadString(EncKey, EncKeyLength)) - { - return true; - } - HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, EncNonceLength); - AString EncNonce; - if (!m_ClientBuffer.ReadString(EncNonce, EncNonceLength)) - { - return true; - } - if ((EncKeyLength > MAX_ENC_LEN) || (EncNonceLength > MAX_ENC_LEN)) - { - Log("Client: Too long encryption params"); - return true; - } - StartClientEncryption(EncKey, EncNonce); - return true; -} - - - - - bool cConnection::HandleClientEntityAction(void) { HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, PlayerID); @@ -934,37 +1080,6 @@ bool cConnection::HandleClientEntityAction(void) -bool cConnection::HandleClientHandshake(void) -{ - // Read the packet from the client: - HANDLE_CLIENT_PACKET_READ(ReadByte, Byte, ProtocolVersion); - HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, Username); - HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, ServerHost); - HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, ServerPort); - m_ClientBuffer.CommitRead(); - - Log("Received a PACKET_HANDSHAKE from the client:"); - Log(" ProtocolVersion = %d", ProtocolVersion); - Log(" Username = \"%s\"", Username.c_str()); - Log(" ServerHost = \"%s\"", ServerHost.c_str()); - Log(" ServerPort = %d", ServerPort); - - // Send the same packet to the server, but with our port: - cByteBuffer ToServer(512); - ToServer.WriteByte (PACKET_HANDSHAKE); - ToServer.WriteByte (ProtocolVersion); - ToServer.WriteBEUTF16String16(Username); - ToServer.WriteBEUTF16String16(ServerHost); - ToServer.WriteBEInt (m_Server.GetConnectPort()); - SERVERSEND(ToServer); - - return true; -} - - - - - bool cConnection::HandleClientKeepAlive(void) { HANDLE_CLIENT_PACKET_READ(ReadBEInt, int, ID); @@ -1124,6 +1239,30 @@ bool cConnection::HandleClientSlotSelect(void) +bool cConnection::HandleClientStatusPing(void) +{ + HANDLE_CLIENT_PACKET_READ(ReadBEInt64, Int64, Time); + Log("Received the status ping packet from the client:"); + Log(" Time = %lld", Time); + COPY_TO_SERVER(); + return true; +} + + + + + +bool cConnection::HandleClientStatusRequest(void) +{ + Log("Received the status request packet from the client"); + COPY_TO_SERVER(); + return true; +} + + + + + bool cConnection::HandleClientTabCompletion(void) { HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, Query); @@ -1213,6 +1352,84 @@ bool cConnection::HandleClientWindowClose(void) +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// packet handling, server-side, login: + +bool cConnection::HandleServerLoginDisconnect(void) +{ + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Reason); + Log("Received a login-disconnect packet from the server:"); + Log(" Reason = \"%s\"", Reason.c_str()); + COPY_TO_SERVER(); + return true; +} + + + + + +bool cConnection::HandleServerLoginEncryptionKeyRequest(void) +{ + // Read the packet from the server: + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, ServerID); + HANDLE_SERVER_PACKET_READ(ReadBEShort, short, PublicKeyLength); + AString PublicKey; + if (!m_ServerBuffer.ReadString(PublicKey, PublicKeyLength)) + { + return false; + } + HANDLE_SERVER_PACKET_READ(ReadBEShort, short, NonceLength); + AString Nonce; + if (!m_ServerBuffer.ReadString(Nonce, NonceLength)) + { + return false; + } + Log("Got PACKET_ENCRYPTION_KEY_REQUEST from the SERVER:"); + Log(" ServerID = %s", ServerID.c_str()); + + // Reply to the server: + SendEncryptionKeyResponse(PublicKey, Nonce); + + // Do not send to client - we want the client connection open + return true; +} + + + + + +bool cConnection::HandleServerLoginSuccess(void) +{ + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, UUID); + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Username); + Log("Received a login success packet from the server:"); + Log(" UUID = \"%s\"", UUID.c_str()); + Log(" Username = \"%s\"", Username.c_str()); + + Log("Server is now in protocol state Game."); + m_ServerProtocolState = 3; + + if (m_IsServerEncrypted) + { + Log("Server communication is now encrypted"); + m_ServerState = csEncryptedUnderstood; + DataLog(m_ServerEncryptionBuffer.data(), m_ServerEncryptionBuffer.size(), "Sending the queued data to server (%u bytes):", m_ServerEncryptionBuffer.size()); + SERVERENCRYPTSEND(m_ServerEncryptionBuffer.data(), m_ServerEncryptionBuffer.size()); + m_ServerEncryptionBuffer.clear(); + } + COPY_TO_CLIENT(); + Log("Client is now in protocol state Game."); + m_ClientProtocolState = 3; + return true; +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// packet handling, server-side, game: + bool cConnection::HandleServerAttachEntity(void) { HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); @@ -1341,48 +1558,6 @@ bool cConnection::HandleServerDestroyEntities(void) -bool cConnection::HandleServerEncryptionKeyRequest(void) -{ - // Read the packet from the server: - HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, ServerID); - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, PublicKeyLength); - AString PublicKey; - if (!m_ServerBuffer.ReadString(PublicKey, PublicKeyLength)) - { - return false; - } - HANDLE_SERVER_PACKET_READ(ReadBEShort, short, NonceLength); - AString Nonce; - if (!m_ServerBuffer.ReadString(Nonce, NonceLength)) - { - return false; - } - Log("Got PACKET_ENCRYPTION_KEY_REQUEST from the SERVER:"); - Log(" ServerID = %s", ServerID.c_str()); - - // Reply to the server: - SendEncryptionKeyResponse(PublicKey, Nonce); - - // Send a 0xFD Encryption Key Request http://wiki.vg/Protocol#0xFD to the client, using our own key: - Log("Sending PACKET_ENCRYPTION_KEY_REQUEST to the CLIENT"); - AString key; - StringSink sink(key); // GCC won't allow inline instantiation in the following line, damned temporary refs - m_Server.GetPublicKey().Save(sink); - cByteBuffer ToClient(512); - ToClient.WriteByte (PACKET_ENCRYPTION_KEY_REQUEST); - ToClient.WriteBEUTF16String16(ServerID); - ToClient.WriteBEShort ((short)key.size()); - ToClient.WriteBuf (key.data(), key.size()); - ToClient.WriteBEShort (4); - ToClient.WriteBEInt (m_Nonce); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :) - CLIENTSEND(ToClient); - return true; -} - - - - - bool cConnection::HandleServerEntity(void) { HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID); @@ -1667,26 +1842,6 @@ bool cConnection::HandleServerKeepAlive(void) -bool cConnection::HandleServerEncryptionKeyResponse(void) -{ - HANDLE_SERVER_PACKET_READ(ReadBEInt, int, Lengths); - if (Lengths != 0) - { - Log("Lengths are not zero!"); - return true; - } - Log("Server communication is now encrypted"); - m_ServerState = csEncryptedUnderstood; - DataLog(m_ServerEncryptionBuffer.data(), m_ServerEncryptionBuffer.size(), "Sending the queued data to server (%u bytes):", m_ServerEncryptionBuffer.size()); - SERVERENCRYPTSEND(m_ServerEncryptionBuffer.data(), m_ServerEncryptionBuffer.size()); - m_ServerEncryptionBuffer.clear(); - return true; -} - - - - - bool cConnection::HandleServerKick(void) { HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Reason); @@ -2267,6 +2422,46 @@ bool cConnection::HandleServerSpawnPickup(void) +bool cConnection::HandleServerStatusPing(void) +{ + HANDLE_SERVER_PACKET_READ(ReadBEInt64, Int64, Time); + Log("Received server's ping response:"); + Log(" Time = %lld", Time); + COPY_TO_CLIENT(); + return true; +} + + + + + +bool cConnection::HandleServerStatusResponse(void) +{ + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Response); + Log("Received server's status response:"); + Log(" Response: %s", Response.c_str()); + + // Modify the response to show that it's being proto-proxied: + size_t idx = Response.find("\"description\":\""); + if (idx != AString::npos) + { + Response.assign(Response.substr(0, idx + 15) + "ProtoProxy: " + Response.substr(idx + 15)); + } + cByteBuffer Packet(1000); + Packet.WriteVarInt(0); // Packet type - status response + Packet.WriteVarUTF8String(Response); + AString Pkt; + Packet.ReadAll(Pkt); + cByteBuffer ToClient(1000); + ToClient.WriteVarUTF8String(Pkt); + CLIENTSEND(ToClient); + return true; +} + + + + + bool cConnection::HandleServerTabCompletion(void) { HANDLE_SERVER_PACKET_READ(ReadBEUTF16String16, AString, Results); @@ -2674,68 +2869,14 @@ void cConnection::SendEncryptionKeyResponse(const AString & a_ServerPublicKey, c // Send the packet to the server: Log("Sending PACKET_ENCRYPTION_KEY_RESPONSE to the SERVER"); cByteBuffer ToServer(1024); - ToServer.WriteByte(PACKET_ENCRYPTION_KEY_RESPONSE); + ToServer.WriteByte(0x01); // To server: Encryption key response ToServer.WriteBEShort(EncryptedLength); ToServer.WriteBuf(EncryptedSecret, EncryptedLength); ToServer.WriteBEShort(EncryptedLength); ToServer.WriteBuf(EncryptedNonce, EncryptedLength); SERVERSEND(ToServer); - m_ServerState = csWaitingForEncryption; -} - - - - - -void cConnection::StartClientEncryption(const AString & a_EncKey, const AString & a_EncNonce) -{ - // Decrypt EncNonce using privkey - RSAES<PKCS1v15>::Decryptor rsaDecryptor(m_Server.GetPrivateKey()); - time_t CurTime = time(NULL); - RandomPool rng; - rng.Put((const byte *)&CurTime, sizeof(CurTime)); - byte DecryptedNonce[MAX_ENC_LEN]; - DecodingResult res = rsaDecryptor.Decrypt(rng, (const byte *)a_EncNonce.data(), a_EncNonce.size(), DecryptedNonce); - if (!res.isValidCoding || (res.messageLength != 4)) - { - Log("Client: Bad nonce length"); - return; - } - if (ntohl(*((int *)DecryptedNonce)) != m_Nonce) - { - Log("Bad nonce value"); - return; - } - - // Decrypt the symmetric encryption key using privkey: - byte SharedSecret[MAX_ENC_LEN]; - res = rsaDecryptor.Decrypt(rng, (const byte *)a_EncKey.data(), a_EncKey.size(), SharedSecret); - if (!res.isValidCoding || (res.messageLength != 16)) - { - Log("Bad key length"); - return; - } - - // Send encryption key response: - cByteBuffer ToClient(6); - ToClient.WriteByte((char)0xfc); - ToClient.WriteBEShort(0); - ToClient.WriteBEShort(0); - CLIENTSEND(ToClient); - - // Start the encryption: - m_ClientEncryptor.SetKey(SharedSecret, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(SharedSecret, 16))(Name::FeedbackSize(), 1)); - m_ClientDecryptor.SetKey(SharedSecret, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(SharedSecret, 16))(Name::FeedbackSize(), 1)); - Log("Client connection is now encrypted"); - m_ClientState = csEncryptedUnderstood; - - // Send the queued data: - DataLog(m_ClientEncryptionBuffer.data(), m_ClientEncryptionBuffer.size(), "Sending the queued data to client (%u bytes):", m_ClientEncryptionBuffer.size()); - CLIENTENCRYPTSEND(m_ClientEncryptionBuffer.data(), m_ClientEncryptionBuffer.size()); - m_ClientEncryptionBuffer.clear(); - - // Handle all postponed server data - DecodeServersPackets(NULL, 0); + m_ServerState = csEncryptedUnderstood; + m_IsServerEncrypted = true; } diff --git a/Tools/ProtoProxy/Connection.h b/Tools/ProtoProxy/Connection.h index 6093408d6..56d443b86 100644 --- a/Tools/ProtoProxy/Connection.h +++ b/Tools/ProtoProxy/Connection.h @@ -71,14 +71,27 @@ protected: Decryptor m_ServerDecryptor; Encryptor m_ServerEncryptor; - Decryptor m_ClientDecryptor; - Encryptor m_ClientEncryptor; - - AString m_ClientEncryptionBuffer; // Buffer for the data to be sent to the client once encryption is established AString m_ServerEncryptionBuffer; // Buffer for the data to be sent to the server once encryption is established /// Set to true when PACKET_PING is received from the client; will cause special parsing for server kick bool m_HasClientPinged; + + /* + The protocol states can be one of: + -1: no initial handshake received yet + 1: status + 2: login + 3: game + */ + /// State the to-server protocol is in (as defined by the initial handshake / login), -1 if no initial handshake received yet + int m_ServerProtocolState; + + /// State the to-client protocol is in (as defined by the initial handshake / login), -1 if no initial handshake received yet + int m_ClientProtocolState; + + /// True if the server connection has provided encryption keys + bool m_IsServerEncrypted; + bool ConnectToServer(void); @@ -109,7 +122,18 @@ protected: /// Decodes packets coming from the server, sends appropriate counterparts to the client; returns false if the connection is to be dropped bool DecodeServersPackets(const char * a_Data, int a_Size); - // Packet handling, client-side: + // Packet handling, client-side, initial: + bool HandleClientHandshake(void); + + // Packet handling, client-side, status: + bool HandleClientStatusPing(void); + bool HandleClientStatusRequest(void); + + // Packet handling, client-side, login: + bool HandleClientLoginEncryptionKeyResponse(void); + bool HandleClientLoginStart(void); + + // Packet handling, client-side, game: bool HandleClientAnimation(void); bool HandleClientBlockDig(void); bool HandleClientBlockPlace(void); @@ -117,9 +141,7 @@ protected: bool HandleClientClientStatuses(void); bool HandleClientCreativeInventoryAction(void); bool HandleClientDisconnect(void); - bool HandleClientEncryptionKeyResponse(void); bool HandleClientEntityAction(void); - bool HandleClientHandshake(void); bool HandleClientKeepAlive(void); bool HandleClientLocaleAndView(void); bool HandleClientPing(void); @@ -136,7 +158,12 @@ protected: bool HandleClientWindowClick(void); bool HandleClientWindowClose(void); - // Packet handling, server-side: + // Packet handling, server-side, login: + bool HandleServerLoginDisconnect(void); + bool HandleServerLoginEncryptionKeyRequest(void); + bool HandleServerLoginSuccess(void); + + // Packet handling, server-side, game: bool HandleServerAttachEntity(void); bool HandleServerBlockAction(void); bool HandleServerBlockChange(void); @@ -145,8 +172,6 @@ protected: bool HandleServerCollectPickup(void); bool HandleServerCompass(void); bool HandleServerDestroyEntities(void); - bool HandleServerEncryptionKeyRequest(void); - bool HandleServerEncryptionKeyResponse(void); bool HandleServerEntity(void); bool HandleServerEntityEquipment(void); bool HandleServerEntityHeadLook(void); @@ -160,6 +185,7 @@ protected: bool HandleServerEntityVelocity(void); bool HandleServerExplosion(void); bool HandleServerIncrementStatistic(void); + bool HandleServerJoinGame(void); bool HandleServerKeepAlive(void); bool HandleServerKick(void); bool HandleServerLogin(void); @@ -172,20 +198,26 @@ protected: bool HandleServerPlayerListItem(void); bool HandleServerPlayerPositionLook(void); bool HandleServerPluginMessage(void); + bool HandleServerRespawn(void); bool HandleServerSetExperience(void); bool HandleServerSetSlot(void); bool HandleServerSlotSelect(void); bool HandleServerSoundEffect(void); + bool HandleServerSpawnExperienceOrbs(void); bool HandleServerSpawnMob(void); bool HandleServerSpawnNamedEntity(void); bool HandleServerSpawnObjectVehicle(void); bool HandleServerSpawnPainting(void); bool HandleServerSpawnPickup(void); + bool HandleServerStatistics(void); + bool HandleServerStatusPing(void); + bool HandleServerStatusResponse(void); bool HandleServerTabCompletion(void); bool HandleServerTimeUpdate(void); bool HandleServerUpdateHealth(void); bool HandleServerUpdateSign(void); bool HandleServerUpdateTileEntity(void); + bool HandleServerUseBed(void); bool HandleServerWindowClose(void); bool HandleServerWindowContents(void); bool HandleServerWindowOpen(void); diff --git a/Tools/ProtoProxy/Globals.h b/Tools/ProtoProxy/Globals.h index 3b154b866..8424aca81 100644 --- a/Tools/ProtoProxy/Globals.h +++ b/Tools/ProtoProxy/Globals.h @@ -70,6 +70,10 @@ typedef long long Int64; typedef int Int32; typedef short Int16; +typedef unsigned long long UInt64; +typedef unsigned int UInt32; +typedef unsigned short UInt16; + |