diff --git a/CMakeLists.txt b/CMakeLists.txt index 94c66ef..189c2b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,5 @@ +option(RAKNET_BUILD_FOR_CLIENT "Build RakNet without server-side functionality" NO) + if(WIN32) add_definitions( -D_CRT_SECURE_NO_WARNINGS @@ -50,7 +52,11 @@ target_include_directories(raknet ) if (WIN32) - target_link_libraries(raknet Ws2_32 OMP-SDK) + target_link_libraries(raknet Ws2_32) +endif() + +if (RAKNET_BUILD_FOR_CLIENT) + target_compile_definitions(raknet PUBLIC -DRAKNET_BUILD_FOR_CLIENT) else() target_link_libraries(raknet OMP-SDK) endif() diff --git a/Include/raknet/RakPeer.h b/Include/raknet/RakPeer.h index 719d5be..d9009a0 100644 --- a/Include/raknet/RakPeer.h +++ b/Include/raknet/RakPeer.h @@ -508,7 +508,9 @@ namespace RakNet bool setAESKey; /// true if security is enabled. RPCMap rpcMap; /// Mapping of RPC calls to single byte integers to save transmission bandwidth. enum ConnectMode {NO_ACTION, DISCONNECT_ASAP, DISCONNECT_ASAP_SILENTLY, DISCONNECT_ON_NO_ACK, REQUESTED_CONNECTION, HANDLING_CONNECTION_REQUEST, UNVERIFIED_SENDER, SET_ENCRYPTION_ON_MULTIPLE_16_BYTE_PACKET, CONNECTED} connectMode; +#ifndef RAKNET_BUILD_FOR_CLIENT SAMPRakNet::RemoteSystemData sampData; +#endif bool isLogon; }; @@ -529,7 +531,9 @@ namespace RakNet friend void* UpdateNetworkLoop( void* arguments ); #endif +#ifndef RAKNET_BUILD_FOR_CLIENT friend bool __stdcall ProcessBan(RakPeer* rakPeer, PlayerID playerId, const char* data, const int length); +#endif // This is done to provide custom RPC handling when in a blocking RPC Packet* ReceiveIgnoreRPC( void ); @@ -543,11 +547,13 @@ namespace RakNet /// \return 0 if none RemoteSystemStruct *GetRemoteSystemFromPlayerID( const PlayerID playerID, bool calledFromNetworkThread, bool onlyActive) const; ///Parse out a connection request packet +#ifndef RAKNET_BUILD_FOR_CLIENT void ParseConnectionRequestPacket( RakPeer::RemoteSystemStruct *remoteSystem, PlayerID playerId, const char *data, int byteSize); bool ParseConnectionAuthPacket(RakPeer::RemoteSystemStruct* remoteSystem, PlayerID playerId, unsigned char* data, int byteSize); ///When we get a connection request from an ip / port, accept it unless full void OnConnectionRequest( RakPeer::RemoteSystemStruct *remoteSystem, unsigned char *AESKey, bool setAESKey ); void AcceptConnectionRequest(RakPeer::RemoteSystemStruct* remoteSystem); +#endif ///Send a reliable disconnect packet to this player and disconnect them when it is delivered void NotifyAndFlagForDisconnect( const PlayerID playerId, bool performImmediate, unsigned char orderingChannel ); ///Returns how many remote systems initiated a connection to us diff --git a/Include/raknet/RakServer.h b/Include/raknet/RakServer.h index d84b7d7..3279c93 100644 --- a/Include/raknet/RakServer.h +++ b/Include/raknet/RakServer.h @@ -435,8 +435,10 @@ namespace RakNet /// \sa RakNetStatistics.h RakNetStatisticsStruct * GetStatistics( const PlayerID playerId ) override; +#ifndef RAKNET_BUILD_FOR_CLIENT /// Return the SAMPRakNet RemoteSystemData for a player ID virtual SAMPRakNet::RemoteSystemData GetSAMPDataFromPlayerID(const PlayerID playerId) override; +#endif /// Get Remote System data for a player from their ID virtual RakPeer::RemoteSystemStruct* GetRemoteSystemFromPlayerID(const PlayerID playerId) override; diff --git a/Include/raknet/RakServerInterface.h b/Include/raknet/RakServerInterface.h index 6142145..cb487dd 100644 --- a/Include/raknet/RakServerInterface.h +++ b/Include/raknet/RakServerInterface.h @@ -429,8 +429,10 @@ namespace RakNet /// \sa RakNetStatistics.h virtual RakNetStatisticsStruct * GetStatistics( const PlayerID playerId )=0; +#ifndef RAKNET_BUILD_FOR_CLIENT /// Get SAMP data for a player from their ID virtual SAMPRakNet::RemoteSystemData GetSAMPDataFromPlayerID(const PlayerID playerId) = 0; +#endif /// Get Remote System data for a player from their ID virtual RakPeer::RemoteSystemStruct* GetRemoteSystemFromPlayerID(const PlayerID playerId) = 0; diff --git a/SAMPRakNet.cpp b/SAMPRakNet.cpp index 8295579..7a95fd2 100644 --- a/SAMPRakNet.cpp +++ b/SAMPRakNet.cpp @@ -11,10 +11,19 @@ uint8_t SAMPRakNet::decryptBuffer_[MAXIMUM_MTU_SIZE]; uint8_t SAMPRakNet::encryptBuffer_[MAXIMUM_MTU_SIZE]; +#ifdef RAKNET_BUILD_FOR_CLIENT +char SAMPRakNet::authkeyBuffer_[AUTHKEY_RESPONSE_LEN]; +bool SAMPRakNet::connectAsNpc_ = false; +#endif +#ifndef RAKNET_BUILD_FOR_CLIENT uint32_t SAMPRakNet::token_; +#endif uint16_t SAMPRakNet::portNumber = 7777; +#ifndef RAKNET_BUILD_FOR_CLIENT Query* SAMPRakNet::query_ = nullptr; +#endif unsigned int SAMPRakNet::timeout_ = 10000; +#ifndef RAKNET_BUILD_FOR_CLIENT unsigned int SAMPRakNet::minConnectionTime_ = 0; unsigned int SAMPRakNet::messagesLimit_ = 500; unsigned int SAMPRakNet::messageHoleLimit_ = 3000; @@ -25,7 +34,7 @@ ICore* SAMPRakNet::core_ = nullptr; FlatHashSet SAMPRakNet::incomingConnections_; RakNet::RakNetTime SAMPRakNet::gracePeriod_ = 0; FlatHashMap SAMPRakNet::ompPlayers_; - +#endif uint16_t SAMPRakNet:: GetPort() @@ -321,7 +330,7 @@ SAMPRakNet:: } return decryptBuffer_; } - +#ifndef RAKNET_BUILD_FOR_CLIENT uint8_t* SAMPRakNet:: Encrypt(const OmpPlayerEncryptionData* encryptionData, uint8_t const* src, int len) @@ -345,7 +354,385 @@ SAMPRakNet:: encryptBuffer_[0] = checksum; return encryptBuffer_; } +#else +uint8_t* +SAMPRakNet:: + Encrypt(uint8_t const* src, int len) +{ + static const uint8_t + key[256] + = { + 0x27, + 0x69, + 0xFD, + 0x87, + 0x60, + 0x7D, + 0x83, + 0x02, + 0xF2, + 0x3F, + 0x71, + 0x99, + 0xA3, + 0x7C, + 0x1B, + 0x9D, + 0x76, + 0x30, + 0x23, + 0x25, + 0xC5, + 0x82, + 0x9B, + 0xEB, + 0x1E, + 0xFA, + 0x46, + 0x4F, + 0x98, + 0xC9, + 0x37, + 0x88, + 0x18, + 0xA2, + 0x68, + 0xD6, + 0xD7, + 0x22, + 0xD1, + 0x74, + 0x7A, + 0x79, + 0x2E, + 0xD2, + 0x6D, + 0x48, + 0x0F, + 0xB1, + 0x62, + 0x97, + 0xBC, + 0x8B, + 0x59, + 0x7F, + 0x29, + 0xB6, + 0xB9, + 0x61, + 0xBE, + 0xC8, + 0xC1, + 0xC6, + 0x40, + 0xEF, + 0x11, + 0x6A, + 0xA5, + 0xC7, + 0x3A, + 0xF4, + 0x4C, + 0x13, + 0x6C, + 0x2B, + 0x1C, + 0x54, + 0x56, + 0x55, + 0x53, + 0xA8, + 0xDC, + 0x9C, + 0x9A, + 0x16, + 0xDD, + 0xB0, + 0xF5, + 0x2D, + 0xFF, + 0xDE, + 0x8A, + 0x90, + 0xFC, + 0x95, + 0xEC, + 0x31, + 0x85, + 0xC2, + 0x01, + 0x06, + 0xDB, + 0x28, + 0xD8, + 0xEA, + 0xA0, + 0xDA, + 0x10, + 0x0E, + 0xF0, + 0x2A, + 0x6B, + 0x21, + 0xF1, + 0x86, + 0xFB, + 0x65, + 0xE1, + 0x6F, + 0xF6, + 0x26, + 0x33, + 0x39, + 0xAE, + 0xBF, + 0xD4, + 0xE4, + 0xE9, + 0x44, + 0x75, + 0x3D, + 0x63, + 0xBD, + 0xC0, + 0x7B, + 0x9E, + 0xA6, + 0x5C, + 0x1F, + 0xB2, + 0xA4, + 0xC4, + 0x8D, + 0xB3, + 0xFE, + 0x8F, + 0x19, + 0x8C, + 0x4D, + 0x5E, + 0x34, + 0xCC, + 0xF9, + 0xB5, + 0xF3, + 0xF8, + 0xA1, + 0x50, + 0x04, + 0x93, + 0x73, + 0xE0, + 0xBA, + 0xCB, + 0x45, + 0x35, + 0x1A, + 0x49, + 0x47, + 0x6E, + 0x2F, + 0x51, + 0x12, + 0xE2, + 0x4A, + 0x72, + 0x05, + 0x66, + 0x70, + 0xB8, + 0xCD, + 0x00, + 0xE5, + 0xBB, + 0x24, + 0x58, + 0xEE, + 0xB4, + 0x80, + 0x81, + 0x36, + 0xA9, + 0x67, + 0x5A, + 0x4B, + 0xE8, + 0xCA, + 0xCF, + 0x9F, + 0xE3, + 0xAC, + 0xAA, + 0x14, + 0x5B, + 0x5F, + 0x0A, + 0x3B, + 0x77, + 0x92, + 0x09, + 0x15, + 0x4E, + 0x94, + 0xAD, + 0x17, + 0x64, + 0x52, + 0xD3, + 0x38, + 0x43, + 0x0D, + 0x0C, + 0x07, + 0x3C, + 0x1D, + 0xAF, + 0xED, + 0xE7, + 0x08, + 0xB7, + 0x03, + 0xE6, + 0x8E, + 0xAB, + 0x91, + 0x89, + 0x3E, + 0x2C, + 0x96, + 0x42, + 0xD9, + 0x78, + 0xDF, + 0xD0, + 0x57, + 0x5D, + 0x84, + 0x41, + 0x7E, + 0xCE, + 0xF7, + 0x32, + 0xC3, + 0xD5, + 0x20, + 0x0B, + 0xA7, + }; + uint8_t + cur, + checksum = 0, + port = GetPort() ^ 0xCC; + for (int i = 0; i != len; ++i) { + // Alternate the mask every byte. + cur = (uint8_t)src[i]; + checksum ^= cur & 0xAA; + cur = key[cur]; + if (i & 1) + cur ^= port; + encryptBuffer_[i + 1] = cur; + } + encryptBuffer_[0] = checksum; + return encryptBuffer_; +} +#endif + +#ifdef RAKNET_BUILD_FOR_CLIENT +inline uint8_t transformAuthSha1(const uint8_t value, const uint8_t xorValue) +{ + static const uint8_t authHashTransformTable[] = { + 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x08, 0x06, 0x00, 0x00, 0x00, 0xE4, 0xB5, 0xB7, 0x0A, 0x00, 0x00, 0x00, + 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0B, 0x13, 0x00, 0x00, 0x0B, + 0x13, 0x01, 0x00, 0x9A, 0x9C, 0x18, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, + 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8E, 0x7C, 0xFB, 0x51, 0x93, 0x00, 0x00, + 0x00, 0x20, 0x63, 0x48, 0x52, 0x4D, 0x00, 0x00, 0x7A, 0x25, 0x00, 0x00, + 0x80, 0x83, 0x00, 0x00, 0xF9, 0xFF, 0x00, 0x00, 0x80, 0xE9, 0x00, 0x00, + 0x75, 0x30, 0x00, 0x00 + }; + + uint8_t result = value; + + for (const uint8_t &entry : authHashTransformTable) { + result = result ^ entry ^ xorValue; + } + + return result; +} + +inline const char * uint8ToHex(const uint8_t num) { + static uint8_t buffer[2]; + + buffer[0] = (num >> 4) & 0xF; + buffer[1] = num & 0xF; + + for (uint8_t &entry : buffer) { + uint8_t result = entry + '0'; + + if (result > '9') + result = entry + '7'; + + entry = result; + } + return (char*)buffer; +} + +char* +SAMPRakNet:: + PrepareAuthkeyResponse(const char* initialKey) +{ + static const uint8_t code_from_CAnimManager_AddAnimation[] = + { + 0xFF, 0x25, 0x34, 0x39, // gta_sa.exe + 0x4D3AA0 + 0x4D, 0x00, 0x90, 0x90, // gta_sa.exe + 0x4D3AA4 + 0x90, 0x90, 0x56, 0x57, // gta_sa.exe + 0x4D3AAC + 0x50, 0x8B, 0x44, 0x24, // gta_sa.exe + 0x4D3AA8 + 0x14, 0x8D, 0x0C, 0x80 // gta_sa.exe + 0x4D3AB0 + }; + + RakNet::CSHA1 sha1; + sha1.Update( (unsigned char*) initialKey, strlen(initialKey) ); + sha1.Final(); + + auto sha1_finalized = (uint32_t*)sha1.GetHash(); + + uint32_t sha1_digits[5]; + for (int i = 0; i < 5; i++) { + uint32_t digit = sha1_finalized[i]; + // Flipping bytes order + digit = ((digit & 0xFF) << 24) | ((digit & 0xFF00) << 8) | + ((digit >> 8) & 0xFF00) | ((digit >> 24) & 0xFF); + sha1_digits[i] = digit; + } + + auto sha1_digits_u8 = (uint8_t*)&sha1_digits; + + static const uint8_t xorValues[] = { + 0x2F, 0x45, 0x6F, 0xDB + }; + + for (int i = 0; i < 20; i++) { + uint8_t xorVal = xorValues[i / 5]; + sha1_digits_u8[i] = transformAuthSha1(sha1_digits_u8[i], xorVal); + sha1_digits_u8[i] ^= code_from_CAnimManager_AddAnimation[i]; + } + + for (int i = 0; i < 40;) { + uint8_t hash = sha1_digits_u8[i / 2]; + const char* hashHex = uint8ToHex(hash); + authkeyBuffer_[i] = hashHex[0]; + i++; + authkeyBuffer_[i] = hashHex[1]; + i++; + } + + return authkeyBuffer_; +} +#endif + +#ifndef RAKNET_BUILD_FOR_CLIENT void SAMPRakNet:: HandleQuery(SOCKET instance, int outsize, const sockaddr_in& client, char const* buf, int insize) { @@ -746,3 +1133,4 @@ bool SAMPRakNet::OnConnectionRequest( return true; } +#endif diff --git a/SAMPRakNet.hpp b/SAMPRakNet.hpp index 430e3bd..e55c4a2 100644 --- a/SAMPRakNet.hpp +++ b/SAMPRakNet.hpp @@ -24,7 +24,13 @@ typedef int SOCKET; #define MAX_AUTH_RESPONSE_LEN (64) +#ifdef RAKNET_BUILD_FOR_CLIENT +#define AUTHKEY_RESPONSE_LEN (40) +#endif + +#ifndef RAKNET_BUILD_FOR_CLIENT #include "../../Server/Components/LegacyNetwork/Query/query.hpp" +#endif #include "Include/raknet/NetworkTypes.h" #include "Include/raknet/GetTime.h" @@ -33,8 +39,6 @@ typedef int SOCKET; #define LOCALHOST (0x0100007fu) -#include - enum class OmpVersion { None = 0, @@ -52,7 +56,7 @@ class SAMPRakNet static constexpr int OMP_PETARDED = 0x6D70; // it's basically 'mp' in 16bit static constexpr int SAMP_PETARDED = 0x6969; // it's from default SAMP... Petarded [S04E06] static constexpr OmpVersion CURRENT_OMP_CLIENT_MOD_VERSION = OmpVersion::v0_1_4; - +#ifndef RAKNET_BUILD_FOR_CLIENT enum AuthType { AuthType_Invalid, @@ -73,7 +77,7 @@ class SAMPRakNet { } }; - +#endif struct OmpPlayerEncryptionData { uint32_t key; @@ -91,7 +95,7 @@ class SAMPRakNet { } }; - +#ifndef RAKNET_BUILD_FOR_CLIENT static void Init(ICore* core) { core_ = core; @@ -102,13 +106,22 @@ class SAMPRakNet { return (static_cast(player.binaryAddress) << 16) | player.port; } +#endif static uint8_t* Decrypt(uint8_t const* src, int len); +#ifndef RAKNET_BUILD_FOR_CLIENT static uint8_t* Encrypt(const OmpPlayerEncryptionData* encryptionData, uint8_t const* src, int len); - +#else + static uint8_t* Encrypt(uint8_t const* src, int len); +#endif static uint16_t GetPort(); static void SetPort(uint16_t value); +#ifdef RAKNET_BUILD_FOR_CLIENT + static char * PrepareAuthkeyResponse(const char* initialKey); +#endif + +#ifndef RAKNET_BUILD_FOR_CLIENT static uint32_t GetToken() { return token_; } static void SeedToken() { token_ = rand(); } @@ -119,10 +132,17 @@ class SAMPRakNet static void SeedCookie(); static uint16_t GetCookie(unsigned int address); +#endif static void SetTimeout(unsigned int timeout) { timeout_ = timeout; } static unsigned int GetTimeout() { return timeout_; } +#ifdef RAKNET_BUILD_FOR_CLIENT + static void SetConnectionAsNpc(bool enabled) { connectAsNpc_ = enabled; } + static bool ShouldConnectAsNpc() { return connectAsNpc_; } +#endif + +#ifndef RAKNET_BUILD_FOR_CLIENT static void SetQuery(Query* query) { query_ = query; } static void SetLogCookies(bool log) { logCookies_ = log; } @@ -229,14 +249,23 @@ class SAMPRakNet const char* data, RakNet::RakNetTime& minConnectionTick, RakNet::RakNetTime& minConnectionLogTick); - +#endif private: static uint8_t decryptBuffer_[MAXIMUM_MTU_SIZE]; static uint8_t encryptBuffer_[MAXIMUM_MTU_SIZE]; +#ifdef RAKNET_BUILD_FOR_CLIENT + static char authkeyBuffer_[AUTHKEY_RESPONSE_LEN]; + static bool connectAsNpc_; +#endif +#ifndef RAKNET_BUILD_FOR_CLIENT static uint32_t token_; +#endif static uint16_t portNumber; +#ifndef RAKNET_BUILD_FOR_CLIENT static Query* query_; +#endif static unsigned int timeout_; +#ifndef RAKNET_BUILD_FOR_CLIENT static bool logCookies_; static unsigned int minConnectionTime_; static unsigned int messagesLimit_; @@ -247,4 +276,5 @@ class SAMPRakNet static FlatHashSet incomingConnections_; static RakNet::RakNetTime gracePeriod_; static FlatHashMap ompPlayers_; +#endif }; diff --git a/Source/RakPeer.cpp b/Source/RakPeer.cpp index 96dd288..ac90c9d 100644 --- a/Source/RakPeer.cpp +++ b/Source/RakPeer.cpp @@ -2658,6 +2658,7 @@ RakPeer::RemoteSystemStruct *RakPeer::GetRemoteSystemFromPlayerID( const PlayerI return 0; } +#ifndef RAKNET_BUILD_FOR_CLIENT // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::ParseConnectionRequestPacket( RakPeer::RemoteSystemStruct *remoteSystem, PlayerID playerId, const char *data, int byteSize ) { @@ -2779,6 +2780,7 @@ void RakPeer::OnConnectionRequest( RakPeer::RemoteSystemStruct *remoteSystem, un } } } +#endif // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- void RakPeer::NotifyAndFlagForDisconnect(const PlayerID playerId, bool performImmediate, unsigned char orderingChannel) @@ -3477,9 +3479,9 @@ void RakPeer::CloseConnectionInternal( const PlayerID target, bool sendDisconnec if ( remoteSystemList == 0 || endThreads == true ) return; - +#ifndef RAKNET_BUILD_FOR_CLIENT SAMPRakNet::ResetOmpPlayerConfiguration(target); - +#endif if (sendDisconnectionNotification) { NotifyAndFlagForDisconnect(target, performImmediate, orderingChannel); @@ -3499,7 +3501,9 @@ void RakPeer::CloseConnectionInternal( const PlayerID target, bool sendDisconnec remoteSystemList[ i ].isActive=false; -- activePeersCount; +#ifndef RAKNET_BUILD_FOR_CLIENT SAMPRakNet::SetRequestingConnection(target.binaryAddress, false); +#endif // Reserve this reliability layer for ourselves //remoteSystemList[ i ].playerId = UNASSIGNED_PLAYER_ID; @@ -3868,6 +3872,7 @@ namespace RakNet } +#ifndef RAKNET_BUILD_FOR_CLIENT bool __stdcall ProcessBan(RakPeer* rakPeer, PlayerID playerId, const char* data, const int length) { if (rakPeer->IsBanned(rakPeer->PlayerIDToDottedIP(playerId))) @@ -3888,6 +3893,7 @@ namespace RakNet return false; } +#endif // -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- #ifdef _WIN32 @@ -3896,8 +3902,10 @@ namespace RakNet void ProcessNetworkPacket( const unsigned int binaryAddress, const unsigned short port, const char *data, const int length, RakPeer *rakPeer ) #endif { +#ifndef RAKNET_BUILD_FOR_CLIENT static RakNetTime minConnectionTick; static RakNetTime minConnectionLogTick; +#endif Packet *packet; PlayerID playerId; @@ -3906,6 +3914,7 @@ namespace RakNet playerId.binaryAddress = binaryAddress; playerId.port = port; +#ifndef RAKNET_BUILD_FOR_CLIENT const bool needsBanCheck = (data[0] == ID_OPEN_CONNECTION_REQUEST || data[0] == ID_OPEN_CONNECTION_REPLY || data[0] == ID_CONNECTION_ATTEMPT_FAILED); #if !defined(_COMPATIBILITY_1) @@ -3914,6 +3923,7 @@ namespace RakNet return; } #endif +#endif // We didn't check this datagram to see if it came from a connected system or not yet. // Therefore, this datagram must be under 17 bits - otherwise it may be normal network traffic as the min size for a raknet send is 17 bits @@ -4064,20 +4074,25 @@ namespace RakNet // Therefore, this datagram must be under 17 bits - otherwise it may be normal network traffic as the min size for a raknet send is 17 bits else if ((unsigned char)(data)[0] == ID_OPEN_CONNECTION_REQUEST && length == sizeof(unsigned char)*3) { +#ifndef RAKNET_BUILD_FOR_CLIENT if (!SAMPRakNet::OnConnectionRequest(rakPeer->connectionSocket, playerId, data, minConnectionTick, minConnectionLogTick)) { return; } +#endif for (i=0; i < rakPeer->messageHandlerList.Size(); i++) rakPeer->messageHandlerList[i]->OnDirectSocketReceive(data, length*8, playerId); // If this guy is already connected and they initiated the connection, ignore the connection request RakPeer::RemoteSystemStruct *rss = rakPeer->GetRemoteSystemFromPlayerID( playerId, true, true ); +#ifndef RAKNET_BUILD_FOR_CLIENT static unsigned int s_uiLastProcessedBinaryAddr = 0; static unsigned int s_uiLastProcessedConnTick = 0; +#endif if (rss==0 || rss->weInitiatedTheConnection==true) { +#ifndef RAKNET_BUILD_FOR_CLIENT if (rakPeer->GetNumberOfUnverifiedInstances(binaryAddress) > 30) { SAMPRakNet::GetCore()->printLn("Blocking %s due to a 'server full' attack (1)", playerId.ToString()); @@ -4093,6 +4108,7 @@ namespace RakNet rakPeer->AddToBanList(rakPeer->PlayerIDToDottedIP(playerId), 120000); return; } +#endif @@ -4103,8 +4119,10 @@ namespace RakNet unsigned char c[2]; if (rss) // If this guy is already connected remote system will be 0 { +#ifndef RAKNET_BUILD_FOR_CLIENT s_uiLastProcessedBinaryAddr = playerId.binaryAddress; s_uiLastProcessedConnTick = RakNet::GetTime(); +#endif c[0] = ID_OPEN_CONNECTION_REPLY; } else @@ -4116,10 +4134,12 @@ namespace RakNet rakPeer->messageHandlerList[i]->OnDirectSocketSend((char*)&c, 16, playerId); SocketLayer::Instance()->SendTo( rakPeer->connectionSocket, (char*)&c, 2, playerId.binaryAddress, playerId.port ); +#ifndef RAKNET_BUILD_FOR_CLIENT if (rss) { SAMPRakNet::SetRequestingConnection(binaryAddress, true); } +#endif return; } @@ -4142,6 +4162,74 @@ namespace RakNet } } +#ifdef RAKNET_BUILD_FOR_CLIENT + // SAMP clientside connection cookie verification + else if ((unsigned char)(data)[0] == ID_OPEN_CONNECTION_COOKIE && length == sizeof(unsigned char)*3) + { + for (i=0; i < rakPeer->messageHandlerList.Size(); i++) + rakPeer->messageHandlerList[i]->OnDirectSocketReceive(data, length*8, playerId); + + unsigned char c[3]; + + c[0] = ID_OPEN_CONNECTION_REQUEST; + *(uint16_t*)&c[1] = (*(uint16_t*)&data[1]) ^ SAMPRakNet::SAMP_PETARDED; + + unsigned i; + for (i=0; i < rakPeer->messageHandlerList.Size(); i++) + rakPeer->messageHandlerList[i]->OnDirectSocketSend((char*)&c, 24, playerId); + + SocketLayer::Instance()->SendTo( rakPeer->connectionSocket, (char*)&c, 3, playerId.binaryAddress, playerId.port ); + return; + } + else if ( + ((unsigned char)(data)[0] == ID_CONNECTION_BANNED || (unsigned char)(data)[0] == ID_NO_FREE_INCOMING_CONNECTIONS) + && length <= sizeof(unsigned char)*2 + ) + { + // Remove the connection attempt from the buffered commands + RakPeer::RequestedConnectionStruct *rcsFirst, *rcs; + rcsFirst = rakPeer->requestedConnectionList.ReadLock(); + rcs=rcsFirst; + bool connectionAttemptCancelled=false; + while (rcs) + { + if (rcs->actionToTake==RakPeer::RequestedConnectionStruct::CONNECT && rcs->playerId==playerId) + { + connectionAttemptCancelled=true; + if (rcs==rcsFirst) + { + rakPeer->requestedConnectionList.ReadUnlock(); + rcsFirst=rakPeer->requestedConnectionList.ReadLock(); + rcs=rcsFirst; + } + else + { + // Hole in the middle + rcs->playerId=UNASSIGNED_PLAYER_ID; + rcs=rakPeer->requestedConnectionList.ReadLock(); + } + + continue; + } + + rcs=rakPeer->requestedConnectionList.ReadLock(); + } + + if (rcsFirst) + rakPeer->requestedConnectionList.CancelReadLock(rcsFirst); + + if (connectionAttemptCancelled) + { + // Tell user of connection attempt failed + packet=AllocPacket(sizeof( char )); + packet->data[ 0 ] = (unsigned char)(data)[0]; // Attempted a connection and couldn't + packet->bitSize = ( sizeof( char ) * 8); + packet->playerId = playerId; + packet->playerIndex = 65535; + rakPeer->AddPacketToProducer(packet); + } + } +#endif // See if this datagram came from a connected system remoteSystem = rakPeer->GetRemoteSystemFromPlayerID( playerId, true, true ); @@ -4181,6 +4269,7 @@ namespace RakNet } } +#ifndef RAKNET_BUILD_FOR_CLIENT if (shouldBanPeer && playerId.binaryAddress != LOCALHOST && GetTime() > SAMPRakNet::GetGracePeriod()) { const char* playerIp = rakPeer->PlayerIDToDottedIP(playerId); @@ -4196,13 +4285,16 @@ namespace RakNet rakPeer->CloseConnectionInternal(playerId, false, true, 0); } +#endif } else { +#ifndef RAKNET_BUILD_FOR_CLIENT if (ProcessBan(rakPeer, playerId, data, length)) { return; } +#endif for (i=0; i < rakPeer->messageHandlerList.Size(); i++) rakPeer->messageHandlerList[i]->OnDirectSocketReceive(data, length*8, playerId); @@ -4312,7 +4404,11 @@ namespace RakNet if ( errorCode != 0 && endThreads == false ) { #ifdef _DO_PRINTF +#ifndef RAKNET_BUILD_FOR_CLIENT SAMPRakNet::GetCore()->printLn( "Server RecvFrom critical failure!" ); +#else + printf( "Server RecvFrom critical failure!\n" ); +#endif #endif // Some kind of critical error // peer->isRecvfromThreadActive=false; @@ -4534,10 +4630,12 @@ namespace RakNet } // else connection shutting down, don't bother telling the user +#ifndef RAKNET_BUILD_FOR_CLIENT #ifdef _DO_PRINTF const char* ipPort = playerId.ToString(true); SAMPRakNet::GetCore()->printLn("Connection dropped for player %s", ipPort); #endif +#endif CloseConnectionInternal( playerId, false, true, 0 ); continue; } @@ -4572,6 +4670,7 @@ namespace RakNet // Ping this guy if it is time to do so if ( remoteSystem->connectMode==RemoteSystemStruct::CONNECTED ) { +#ifndef RAKNET_BUILD_FOR_CLIENT // Taken from SA-MP 0.3.7 changes if (!remoteSystem->isLogon) { @@ -4584,6 +4683,7 @@ namespace RakNet continue; } } +#endif if (timeMS > remoteSystem->nextPingTime && (occasionalPing || remoteSystem->lowestPing == (unsigned short)-1)) { @@ -4648,9 +4748,12 @@ namespace RakNet { if ( (unsigned char)(data)[0] == ID_CONNECTION_REQUEST ) { +#ifndef RAKNET_BUILD_FOR_CLIENT ParseConnectionRequestPacket(remoteSystem, playerId, (const char*)data, byteSize); +#endif delete [] data; } +#ifndef RAKNET_BUILD_FOR_CLIENT else if ((unsigned char)(data)[0] != ID_AUTH_KEY || !ParseConnectionAuthPacket(remoteSystem, playerId, data, byteSize)) { if ((unsigned char)(data)[0] == ID_RPC && remoteSystem->sampData.unverifiedRPCs++ < MAX_UNVERIFIED_RPCS) @@ -4682,6 +4785,18 @@ namespace RakNet delete[] data; } } +#else // !RAKNET_BUILD_FOR_CLIENT + else + { + CloseConnectionInternal(playerId, false, true, 0); + +#if !defined(_COMPATIBILITY_1) + AddToBanList(PlayerIDToDottedIP(playerId), remoteSystem->reliabilityLayer.GetTimeoutTime()); +#endif + if (data) + delete[] data; + } +#endif } else { @@ -4691,8 +4806,10 @@ namespace RakNet { // 04/27/06 This is wrong. With cross connections, we can both have initiated the connection are in state REQUESTED_CONNECTION // 04/28/06 Downgrading connections from connected will close the connection due to security at ((remoteSystem->connectMode!=RemoteSystemStruct::CONNECTED && time > remoteSystem->connectionTime && time - remoteSystem->connectionTime > 10000)) +#ifndef RAKNET_BUILD_FOR_CLIENT if (remoteSystem->connectMode!=RemoteSystemStruct::CONNECTED) ParseConnectionRequestPacket(remoteSystem, playerId, (const char*)data, byteSize); +#endif delete [] data; } else if ( (unsigned char) data[ 0 ] == ID_NEW_INCOMING_CONNECTION && byteSize == sizeof(unsigned char)+sizeof(unsigned int)+sizeof(unsigned short) ) @@ -4707,7 +4824,9 @@ namespace RakNet playerId==myPlayerId) // local system connect { +#ifndef RAKNET_BUILD_FOR_CLIENT SAMPRakNet::SetRequestingConnection(playerId.binaryAddress, false); +#endif remoteSystem->connectMode=RemoteSystemStruct::CONNECTED; PingInternal( playerId, true ); @@ -4903,7 +5022,9 @@ namespace RakNet AESKey[ i ] = data[ 1 + i ] ^ ( ( unsigned char* ) ( message ) ) [ i ]; // Connect this player assuming we have open slots +#ifndef RAKNET_BUILD_FOR_CLIENT OnConnectionRequest( remoteSystem, AESKey, true ); +#endif } delete [] data; } @@ -5008,12 +5129,54 @@ namespace RakNet // Tell the remote system the connection failed NotifyAndFlagForDisconnect(playerId, true, 0); #ifdef _DO_PRINTF +#ifndef RAKNET_BUILD_FOR_CLIENT SAMPRakNet::GetCore()->printLn( "Error: Got a connection accept when we didn't request the connection." ); +#else + printf( "Error: Got a connection accept when we didn't request the connection.\n" ); +#endif #endif if (data) delete [] data; } } +#ifdef RAKNET_BUILD_FOR_CLIENT + else if ( (unsigned char)(data)[0] == ID_AUTH_KEY && byteSize >= sizeof(unsigned char)*4 ) + { + RakNet::BitStream inBitStream( (unsigned char *) data, byteSize, false ); + inBitStream.IgnoreBits(8); + + unsigned char initialAuthKeyLen; + inBitStream.Read(initialAuthKeyLen); + + // Prebuilt server initial authkeys usually have length between 14-16 characters + // But, to support wider range and keep backward compatibility with original SAMP, + // We should make it possible to keep up to 256 chars + char initialAuthKey[256]; + if (initialAuthKeyLen > 1 && inBitStream.Read((char*)initialAuthKey, initialAuthKeyLen)) + { + // Server could send NULL terminator in the middle of string (why?) + // But send larger initialAuthKeyLen than the actual string length + // Original SAMP backward compatibility, so will use strlen() in PrepareAuthkeyResponse instead of initialAuthKeyLen + initialAuthKey[initialAuthKeyLen] = NULL; + + RakNet::BitStream outBitStream(sizeof(unsigned char)+sizeof(unsigned char)+AUTHKEY_RESPONSE_LEN); + outBitStream.Write((unsigned char)ID_AUTH_KEY); + if (!SAMPRakNet::ShouldConnectAsNpc()) + { + const char* response = SAMPRakNet::PrepareAuthkeyResponse(initialAuthKey); + outBitStream.Write((unsigned char)AUTHKEY_RESPONSE_LEN); + outBitStream.Write(response, AUTHKEY_RESPONSE_LEN); + } + else + { + // Server requires length & string including NULL terminator in case of NPC + outBitStream.Write((unsigned char)4); + outBitStream.Write("NPC", 4); + } + SendImmediate( (char*)outBitStream.GetData(), outBitStream.GetNumberOfBitsUsed(), SYSTEM_PRIORITY, RELIABLE, 0, playerId, false, false, RakNet::GetTime() ); + } + } +#endif else { if (data[0]>=(unsigned char)ID_RPC) diff --git a/Source/ReliabilityLayer.cpp b/Source/ReliabilityLayer.cpp index 51cc6ae..36ebba7 100644 --- a/Source/ReliabilityLayer.cpp +++ b/Source/ReliabilityLayer.cpp @@ -344,9 +344,11 @@ bool ReliabilityLayer::HandleSocketReceiveFromConnectedPlayer( const char *buffe shouldBanPeer = false; //int numberOfAcksInFrame = 0; +#ifndef RAKNET_BUILD_FOR_CLIENT unsigned int acksLimit = 0; unsigned int messageHoleLimit = 0; unsigned int messagesLimit = 0; +#endif RakNetTimeNS time; bool indexFound; int count, size; @@ -377,9 +379,11 @@ bool ReliabilityLayer::HandleSocketReceiveFromConnectedPlayer( const char *buffe RakNet::BitStream socketData( (unsigned char*) buffer, length, false ); // Convert the incoming data to a bitstream for easy parsing time = RakNet::GetTimeNS(); +#ifndef RAKNET_BUILD_FOR_CLIENT acksLimit = SAMPRakNet::GetAcksLimit(); messageHoleLimit = SAMPRakNet::GetMessageHoleLimit(); messagesLimit = SAMPRakNet::GetMessagesLimit(); +#endif DataStructures::RangeList incomingAcks; socketData.Read(hasAcks); @@ -398,6 +402,7 @@ bool ReliabilityLayer::HandleSocketReceiveFromConnectedPlayer( const char *buffe statistics.acknowlegementsReceived += incomingAcks.ranges[i].maxIndex - incomingAcks.ranges[i].minIndex; +#ifndef RAKNET_BUILD_FOR_CLIENT if (incomingAcks.ranges[i].maxIndex - incomingAcks.ranges[i].minIndex > messageHoleLimit) { unsigned int receivedAcks = incomingAcks.ranges[i].maxIndex - incomingAcks.ranges[i].minIndex; @@ -407,6 +412,7 @@ bool ReliabilityLayer::HandleSocketReceiveFromConnectedPlayer( const char *buffe shouldBanPeer = true; return 1; } +#endif for (messageNumber=incomingAcks.ranges[i].minIndex; messageNumber >= incomingAcks.ranges[i].minIndex && messageNumber <= incomingAcks.ranges[i].maxIndex; messageNumber++) { @@ -449,6 +455,7 @@ bool ReliabilityLayer::HandleSocketReceiveFromConnectedPlayer( const char *buffe statistics.perFrameAcksLimitCounter = 0; } +#ifndef RAKNET_BUILD_FOR_CLIENT if (statistics.perSecondAcksLimitCounter > acksLimit) { const char * ipPort = playerId.ToString(true); @@ -457,6 +464,7 @@ bool ReliabilityLayer::HandleSocketReceiveFromConnectedPlayer( const char *buffe shouldBanPeer = true; return 1; } +#endif } } @@ -591,6 +599,7 @@ bool ReliabilityLayer::HandleSocketReceiveFromConnectedPlayer( const char *buffe statistics.perSecondMessagesLimitCounter = statistics.perFrameMessagesLimitCounter; statistics.perFrameMessagesLimitCounter = 0; } +#ifndef RAKNET_BUILD_FOR_CLIENT if (statistics.perSecondMessagesLimitCounter > messagesLimit) { const char* ipPort = playerId.ToString(true); @@ -599,6 +608,7 @@ bool ReliabilityLayer::HandleSocketReceiveFromConnectedPlayer( const char *buffe shouldBanPeer = true; return 1; } +#endif statistics.messagesReceived++; if (time - statistics.lastRecvMsgProcess > 1000000) @@ -801,6 +811,7 @@ bool ReliabilityLayer::HandleSocketReceiveFromConnectedPlayer( const char *buffe // RakAssert(waitingForOrderedPacketReadIndex[ internalPacket->orderingChannel ] < internalPacket->orderingIndex); statistics.orderedMessagesOutOfOrder++; +#ifndef RAKNET_BUILD_FOR_CLIENT if (statistics.orderedMessagesOutOfOrder > messageHoleLimit) { const char* ipPort = playerId.ToString(true); @@ -809,6 +820,7 @@ bool ReliabilityLayer::HandleSocketReceiveFromConnectedPlayer( const char *buffe shouldBanPeer = true; return 1; } +#endif // This is a newer ordered packet than we are waiting for. Store it for future use AddToOrderingList( internalPacket ); @@ -1945,12 +1957,14 @@ InternalPacket* ReliabilityLayer::CreateInternalPacketFromBitStream( RakNet::Bit return 0; } +#ifndef RAKNET_BUILD_FOR_CLIENT #ifdef _DEBUG SAMPRakNet::GetCore()->logLn(LogLevel::Warning, "dropping a split packet from client"); #endif internalPacketPool.ReleasePointer(internalPacket); return 0; +#endif } else { diff --git a/Source/SocketLayer.cpp b/Source/SocketLayer.cpp index 8408311..4929a09 100644 --- a/Source/SocketLayer.cpp +++ b/Source/SocketLayer.cpp @@ -370,14 +370,17 @@ int SocketLayer::RecvFrom( const SOCKET s, RakPeer *rakPeer, int *errorCode ) if ( len != SOCKET_ERROR ) { +#ifndef RAKNET_BUILD_FOR_CLIENT if (len > 10 && data[0] == 'S' && data[1] == 'A' && data[2] == 'M' && data[3] == 'P') { SAMPRakNet::HandleQuery(s, len2, sa, data, len); return 1; } +#endif unsigned short portnum; portnum = ntohs( sa.sin_port ); +#ifndef RAKNET_BUILD_FOR_CLIENT uint8_t* decrypted = SAMPRakNet::Decrypt((uint8_t*)data, len); if (decrypted) { ProcessNetworkPacket(sa.sin_addr.s_addr, portnum, (char*)decrypted, len - 1, rakPeer); @@ -387,6 +390,9 @@ int SocketLayer::RecvFrom( const SOCKET s, RakPeer *rakPeer, int *errorCode ) uint8_t* const addr = reinterpret_cast(&sa.sin_addr.s_addr); SAMPRakNet::GetCore()->printLn("Dropping bad packet from %u.%u.%u.%u:%u!", addr[0], addr[1], addr[2], addr[3], sa.sin_port); } +#endif +#else // RAKNET_BUILD_FOR_CLIENT + ProcessNetworkPacket(sa.sin_addr.s_addr, portnum, data, len, rakPeer); #endif return 1; } @@ -456,6 +462,7 @@ int SocketLayer::SendTo( SOCKET s, const char *data, int length, unsigned int bi do { // TODO - use WSASendTo which is faster. +#ifndef RAKNET_BUILD_FOR_CLIENT auto encrypted = (uint8_t*)data; if (SAMPRakNet::IsOmpEncryptionEnabled()) { @@ -474,6 +481,10 @@ int SocketLayer::SendTo( SOCKET s, const char *data, int length, unsigned int bi { len = sendto(s, (char*)encrypted, length, 0, (const sockaddr*)&sa, sizeof(struct sockaddr_in)); } +#else + auto encrypted = SAMPRakNet::Encrypt((uint8_t*)data, length); + len = sendto(s, (char*)encrypted, length + 1, 0, (const sockaddr*)&sa, sizeof(struct sockaddr_in)); +#endif } while ( len == 0 ); diff --git a/Source/rakserver.cpp b/Source/rakserver.cpp index 4e23c44..adf348b 100644 --- a/Source/rakserver.cpp +++ b/Source/rakserver.cpp @@ -459,6 +459,7 @@ RakPeer::RemoteSystemStruct* RakServer::GetRemoteSystemFromPlayerID(const Player return RakPeer::GetRemoteSystemFromPlayerID(playerId, false, false); } +#ifndef RAKNET_BUILD_FOR_CLIENT SAMPRakNet::RemoteSystemData RakServer::GetSAMPDataFromPlayerID(const PlayerID playerId) { RemoteSystemStruct* remoteSystem = RakPeer::GetRemoteSystemFromPlayerID(playerId, false, false); @@ -468,6 +469,7 @@ SAMPRakNet::RemoteSystemData RakServer::GetSAMPDataFromPlayerID(const PlayerID p return remoteSystem->sampData; } +#endif #ifdef _MSC_VER #pragma warning( pop )