diff --git a/.gitmodules b/.gitmodules index dc4ad5b4c..757a3da15 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,7 +6,7 @@ url = https://github.com/openmultiplayer/pawn-natives.git [submodule "lib/RakNet"] path = lib/RakNet - url = https://github.com/openmultiplayer/RakNet.git + url = https://github.com/Knogle/RakNet.git [submodule "lib/ttmath"] path = lib/ttmath url = https://github.com/openmultiplayer/ttmath.git diff --git a/Server/Components/LegacyNetwork/Query/query.cpp b/Server/Components/LegacyNetwork/Query/query.cpp index 9c6e4e2bb..1e9d0e87f 100644 --- a/Server/Components/LegacyNetwork/Query/query.cpp +++ b/Server/Components/LegacyNetwork/Query/query.cpp @@ -8,6 +8,7 @@ #include "query.hpp" #include +#include const size_t MAX_ACCEPTABLE_HOSTNAME_SIZE = 63; const size_t MAX_ACCEPTABLE_LANGUAGE_SIZE = 39; @@ -210,26 +211,66 @@ void Query::buildRulesBuffer() } } -constexpr Span getBuffer(Span input, std::unique_ptr& buffer, size_t length) +struct QueryLayout +{ + size_t baseSize; + size_t typeIndex; + size_t copyTo; +}; + +QueryLayout getQueryLayout(Span input) +{ + if (input.size() >= BASE_QUERY6_SIZE && std::memcmp(input.data(), "SAMP6", 5) == 0) + { + return { BASE_QUERY6_SIZE, QUERY6_TYPE_INDEX, QUERY6_COPY_TO }; + } + + return { BASE_QUERY_SIZE, QUERY_TYPE_INDEX, QUERY_COPY_TO }; +} + +std::string DescribeClient(const sockaddr_storage& client, int tolen) +{ + char host[NI_MAXHOST]; + char service[NI_MAXSERV]; + if (getnameinfo(reinterpret_cast(&client), tolen, host, sizeof(host), service, sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV) != 0) + return ""; + + if (client.ss_family == AF_INET6) + return std::string("[") + host + "]:" + service; + return std::string(host) + ":" + service; +} + +Span getBuffer(Span input, std::unique_ptr& buffer, size_t length, std::unique_ptr& responseBuffer, size_t& responseBufferLength) { if (!buffer) { return Span(); } - char* buf = buffer.get(); - memcpy(buf, input.data(), QUERY_COPY_TO); - return Span(buf, length); + const QueryLayout layout = getQueryLayout(input); + if (layout.baseSize == BASE_QUERY_SIZE) + { + char* buf = buffer.get(); + std::memcpy(buf, input.data(), QUERY_COPY_TO); + return Span(buf, length); + } + + responseBufferLength = layout.copyTo + (length - QUERY_COPY_TO); + responseBuffer.reset(new char[responseBufferLength]); + char* output = responseBuffer.get(); + std::memcpy(output, input.data(), layout.copyTo); + std::memcpy(output + layout.copyTo, buffer.get() + QUERY_COPY_TO, length - QUERY_COPY_TO); + return Span(output, responseBufferLength); } struct LegacyConsoleMessageHandler : ConsoleMessageHandler { uint32_t sock; - const sockaddr_in& client; + const sockaddr_storage& client; Span packet; int tolen; - LegacyConsoleMessageHandler(uint32_t sock, const sockaddr_in& client, int tolen, Span data) + LegacyConsoleMessageHandler(uint32_t sock, const sockaddr_storage& client, int tolen, Span data) : sock(sock) , client(client) , packet(data) @@ -249,11 +290,12 @@ struct LegacyConsoleMessageHandler : ConsoleMessageHandler } }; -void Query::handleRCON(Span buffer, uint32_t sock, const sockaddr_in& client, int tolen) +void Query::handleRCON(Span buffer, uint32_t sock, const sockaddr_storage& client, int tolen) { - if (buffer.size() >= BASE_QUERY_SIZE + sizeof(uint16_t)) + const QueryLayout layout = getQueryLayout(buffer); + if (buffer.size() >= layout.baseSize + sizeof(uint16_t)) { - Span subbuf = buffer.subspan(BASE_QUERY_SIZE); + Span subbuf = buffer.subspan(layout.baseSize); size_t offset = 0; uint16_t passLen; if (readFromBuffer(subbuf, offset, passLen)) @@ -270,7 +312,7 @@ void Query::handleRCON(Span buffer, uint32_t sock, const sockaddr_in if (subbuf.size() - offset == cmdLen) { StringView cmd(&subbuf.data()[offset], cmdLen); - LegacyConsoleMessageHandler handler(sock, client, tolen, buffer.subspan(0, BASE_QUERY_SIZE)); + LegacyConsoleMessageHandler handler(sock, client, tolen, buffer.subspan(0, layout.baseSize)); console->send(cmd, ConsoleCommandSenderData(handler)); } } @@ -278,65 +320,67 @@ void Query::handleRCON(Span buffer, uint32_t sock, const sockaddr_in } } - LegacyConsoleMessageHandler handler(sock, client, tolen, buffer.subspan(0, BASE_QUERY_SIZE)); + LegacyConsoleMessageHandler handler(sock, client, tolen, buffer.subspan(0, layout.baseSize)); handler.handleConsoleMessage("Invalid RCON password."); } } } -Span Query::handleQuery(Span buffer, uint32_t sock, const sockaddr_in& client, int tolen) +Span Query::handleQuery(Span buffer, uint32_t sock, const sockaddr_storage& client, int tolen) { if (core == nullptr) { return Span(); } + const QueryLayout layout = getQueryLayout(buffer); + if (buffer.size() < layout.baseSize) + { + return Span(); + } + if (logQueries) { - PeerAddress::AddressString addrString; - PeerAddress addr; - addr.ipv6 = false; - addr.v4 = client.sin_addr.s_addr; - PeerAddress::ToString(addr, addrString); - core->printLn("[query:%c] from %.*s", buffer[QUERY_TYPE_INDEX], PRINT_VIEW(addrString)); + const std::string addrString = DescribeClient(client, tolen); + core->printLn("[query:%c] from %s", buffer[layout.typeIndex], addrString.c_str()); } // Ping - if (buffer[QUERY_TYPE_INDEX] == 'p') + if (buffer[layout.typeIndex] == 'p') { - if (buffer.size() != BASE_QUERY_SIZE + sizeof(uint32_t)) + if (buffer.size() != layout.baseSize + sizeof(uint32_t)) { return Span(); } return buffer; } - else if (buffer.size() == BASE_QUERY_SIZE) + else if (buffer.size() == layout.baseSize) { // This is how we detect open.mp, but also let's send some extra data - if (buffer[QUERY_TYPE_INDEX] == 'o') + if (buffer[layout.typeIndex] == 'o') { - return getBuffer(buffer, extraInfoBuffer, extraInfoBufferLength); + return getBuffer(buffer, extraInfoBuffer, extraInfoBufferLength, responseBuffer, responseBufferLength); } // Server info - else if (buffer[QUERY_TYPE_INDEX] == 'i') + else if (buffer[layout.typeIndex] == 'i') { - return getBuffer(buffer, serverInfoBuffer, serverInfoBufferLength); + return getBuffer(buffer, serverInfoBuffer, serverInfoBufferLength, responseBuffer, responseBufferLength); } // Players - else if (buffer[QUERY_TYPE_INDEX] == 'c') + else if (buffer[layout.typeIndex] == 'c') { - return getBuffer(buffer, playerListBuffer, playerListBufferLength); + return getBuffer(buffer, playerListBuffer, playerListBufferLength, responseBuffer, responseBufferLength); } // Rules - else if (buffer[QUERY_TYPE_INDEX] == 'r' && rulesBuffer) + else if (buffer[layout.typeIndex] == 'r' && rulesBuffer) { - return getBuffer(buffer, rulesBuffer, rulesBufferLength); + return getBuffer(buffer, rulesBuffer, rulesBufferLength, responseBuffer, responseBufferLength); } } - else if (buffer[QUERY_TYPE_INDEX] == 'x' && console && rconEnabled) + else if (buffer[layout.typeIndex] == 'x' && console && rconEnabled) { // RCON handleRCON(buffer, sock, client, tolen); diff --git a/Server/Components/LegacyNetwork/Query/query.hpp b/Server/Components/LegacyNetwork/Query/query.hpp index 72e0b5fe1..c6dbc44ac 100644 --- a/Server/Components/LegacyNetwork/Query/query.hpp +++ b/Server/Components/LegacyNetwork/Query/query.hpp @@ -10,12 +10,16 @@ #include "Server/Components/Console/console.hpp" #include "sdk.hpp" #include +#include using namespace Impl; constexpr size_t BASE_QUERY_SIZE = 11; constexpr size_t QUERY_TYPE_INDEX = 10; constexpr size_t QUERY_COPY_TO = 10; +constexpr size_t BASE_QUERY6_SIZE = 24; +constexpr size_t QUERY6_TYPE_INDEX = 23; +constexpr size_t QUERY6_COPY_TO = 23; class Query : NoCopy { @@ -35,8 +39,8 @@ class Query : NoCopy return console; } - Span handleQuery(Span buffer, uint32_t sock, const sockaddr_in& client, int tolen); - void handleRCON(Span buffer, uint32_t sock, const sockaddr_in& client, int tolen); + Span handleQuery(Span buffer, uint32_t sock, const sockaddr_storage& client, int tolen); + void handleRCON(Span buffer, uint32_t sock, const sockaddr_storage& client, int tolen); void buildRulesBuffer(); void buildPlayerDependentBuffers(IPlayer* except = nullptr) @@ -194,6 +198,8 @@ class Query : NoCopy std::unique_ptr extraInfoBuffer; size_t extraInfoBufferLength = 0; + std::unique_ptr responseBuffer; + size_t responseBufferLength = 0; void buildPlayerInfoBuffer(IPlayer* except = nullptr); void updateServerInfoBufferPlayerCount(IPlayer* except = nullptr); diff --git a/lib/RakNet b/lib/RakNet index f1d225dbc..d2feb0198 160000 --- a/lib/RakNet +++ b/lib/RakNet @@ -1 +1 @@ -Subproject commit f1d225dbcbdd0cff32eb535d94317ebcff81abed +Subproject commit d2feb0198f6ff31c242a70440b036004976447ed