Skip to content

Commit

Permalink
Testing native ip
Browse files Browse the repository at this point in the history
  • Loading branch information
0blu committed Sep 17, 2024
1 parent 5465f01 commit 05d617f
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 11 deletions.
27 changes: 19 additions & 8 deletions src/realmd/AuthSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "IO/Networking/AsyncSocket.h"
#include "IO/Timer/AsyncSystemTimer.h"
#include "IO/Filesystem/FileSystem.h"
#include "ProxyProtocol/ProxyV2Reader.h"

#ifdef USE_SENDGRID
#include "MailerService.h"
Expand Down Expand Up @@ -81,16 +82,26 @@ void AuthSocket::Start()
return; // implicit close()
}

if (int secs = sConfig.GetIntDefault("MaxSessionDuration", 300))
ProxyProtocol::ReadProxyV2Handshake(&m_socket, [self = shared_from_this()](nonstd::expected<IO::Networking::IpAddress, IO::NetworkError> const& maybeIp)
{
this->m_sessionDurationTimeout = sAsyncSystemTimer.ScheduleFunctionOnce(std::chrono::seconds(secs), [this]()
if (!maybeIp.has_value())
{
sLog.Out(LOG_BASIC, LOG_LVL_BASIC, "[%s] Connection has reached MaxSessionDuration. Closing socket...", GetRemoteIpString().c_str());
// It's correct that we capture _this_ and not a shared_ptr, since the timer will be canceled in destructor
this->CloseSocket();
});
}
DoRecvIncomingData();
sLog.Out(LOG_BASIC, LOG_LVL_BASIC, "[%s] Error %s", self->GetRemoteIpString().c_str(), maybeIp.error().ToString().c_str());
return;
}
sLog.Out(LOG_BASIC, LOG_LVL_MINIMAL, "RealIP: %s", maybeIp.value().toString().c_str());

if (int secs = sConfig.GetIntDefault("MaxSessionDuration", 300))
{
self->m_sessionDurationTimeout = sAsyncSystemTimer.ScheduleFunctionOnce(std::chrono::seconds(secs), [self]()
{
sLog.Out(LOG_BASIC, LOG_LVL_BASIC, "[%s] Connection has reached MaxSessionDuration. Closing socket...", self->GetRemoteIpString().c_str());
// It's correct that we capture _this_ and not a shared_ptr, since the timer will be canceled in destructor
self->CloseSocket();
});
}
self->DoRecvIncomingData();
});
}

AuthSocket::~AuthSocket()
Expand Down
2 changes: 2 additions & 0 deletions src/shared/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ set (shared_SRCS
IO/Filesystem/impl/windows/FileHandle.cpp
IO/Filesystem/impl/unix/FileSystem.cpp
IO/Filesystem/impl/unix/FileHandle.cpp
ProxyProtocol/ProxyV2Reader.h
ProxyProtocol/ProxyV2Reader.cpp
ArgparserForServer.h
ArgparserForServer.cpp
Memory/ArrayDeleter.h
Expand Down
13 changes: 10 additions & 3 deletions src/shared/IO/Networking/NetworkError.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,17 @@ std::string const& GetErrorBaseString(IO::NetworkError::ErrorType errorType)
static std::string txt = "OnlyOneTransferPerDirectionAllowed";
return txt;
}
case IO::NetworkError::ErrorType::Timeout:
{
static std::string txt = "Timeout";
return txt;
}
case IO::NetworkError::ErrorType::InvalidProtocolBehavior:
{
static std::string txt = "InvalidProtocolBehavior";
return txt;
}
}

static std::string undefined = "<UNDEFINED>";
return undefined;
}

std::string IO::NetworkError::ToString() const
Expand Down
1 change: 1 addition & 0 deletions src/shared/IO/Networking/NetworkError.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace IO
SocketClosed,
OnlyOneTransferPerDirectionAllowed,
Timeout,
InvalidProtocolBehavior,
};
public:
explicit constexpr NetworkError(ErrorType errorType) : NetworkError(errorType, 0) {};
Expand Down
105 changes: 105 additions & 0 deletions src/shared/ProxyProtocol/ProxyV2Reader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#include "ProxyV2Reader.h"
#include "Log.h"

// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform
#if defined( __GNUC__ )
#pragma pack(1)
#else
#pragma pack(push,1)
#endif

struct proxy_hdr_v2 {
uint8_t sig[12]; /* hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A */
uint8_t ver_cmd; /* protocol version and command */
uint8_t fam; /* protocol family and address */
uint16_t len; /* number of following bytes part of the header */
};

union proxy_addr {
struct { /* for TCP/UDP over IPv4, len = 12 */
uint32_t src_addr;
uint32_t dst_addr;
uint16_t src_port;
uint16_t dst_port;
} ipv4_addr;
struct { /* for TCP/UDP over IPv6, len = 36 */
uint8_t src_addr[16];
uint8_t dst_addr[16];
uint16_t src_port;
uint16_t dst_port;
} ipv6_addr;
struct { /* for AF_UNIX sockets, len = 216 */
uint8_t src_addr[108];
uint8_t dst_addr[108];
} unix_addr;
};

// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
#if defined( __GNUC__ )
#pragma pack()
#else
#pragma pack(pop)
#endif

// https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt

void ProxyProtocol::ReadProxyV2Handshake(IO::Networking::AsyncSocket* socket, std::function<void(nonstd::expected<IO::Networking::IpAddress, IO::NetworkError> const&)> const& callback)
{
std::shared_ptr<proxy_hdr_v2> proxyHeader(new proxy_hdr_v2());
socket->Read((char*)(proxyHeader.get()), sizeof(proxyHeader), [socket, callback, proxyHeader](IO::NetworkError const& error, size_t)
{
if (error)
{
callback(nonstd::make_unexpected(error));
return;
}

constexpr uint8_t expectedSignature[12] = { 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A };
// We have a valid signature
if (std::memcmp(proxyHeader->sig, expectedSignature, sizeof(expectedSignature)) != 0)
{
sLog.Out(LOG_NETWORK, LOG_LVL_ERROR, "ProxyV2 invalid signature");
callback(nonstd::make_unexpected(IO::NetworkError(IO::NetworkError::ErrorType::InvalidProtocolBehavior)));
return;
}

// Check if we have IPv4_TCP which is currently the only one supported by the vanilla client
constexpr uint8_t PROXY_V2_TCP_OVER_IPV4 = 0x11;
if (proxyHeader->fam != PROXY_V2_TCP_OVER_IPV4)
{
sLog.Out(LOG_NETWORK, LOG_LVL_ERROR, "ProxyV2 unexpected familyAndProtocol");
callback(nonstd::make_unexpected(IO::NetworkError(IO::NetworkError::ErrorType::InvalidProtocolBehavior)));
return;
}

// Check cmd version
if (proxyHeader->ver_cmd != 0x21)
{
sLog.Out(LOG_NETWORK, LOG_LVL_ERROR, "ProxyV2 unexpected ver_cmd");
callback(nonstd::make_unexpected(IO::NetworkError(IO::NetworkError::ErrorType::InvalidProtocolBehavior)));
return;
}

// Unexpected body size
uint16_t headerLength = ::ntohs(proxyHeader->len);
if (headerLength != 12)
{
sLog.Out(LOG_NETWORK, LOG_LVL_ERROR, "ProxyV2 unexpected body size");
callback(nonstd::make_unexpected(IO::NetworkError(IO::NetworkError::ErrorType::InvalidProtocolBehavior)));
return;
}

// Now we can read the actual payload
std::shared_ptr<proxy_addr> addressBody(new proxy_addr());
socket->Read((char*)(addressBody.get()), headerLength, [callback, addressBody](IO::NetworkError const& error, size_t)
{
if (error)
{
callback(nonstd::make_unexpected(error));
return;
}
IO::Networking::IpAddress ipAddress = IO::Networking::IpAddress::FromIpv4Uint32(::ntohl(addressBody->ipv4_addr.src_addr));
callback(ipAddress);
});
});
}
15 changes: 15 additions & 0 deletions src/shared/ProxyProtocol/ProxyV2Reader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#ifndef MANGOS_PROXYPROTOCOL_PROXYV2READER_H
#define MANGOS_PROXYPROTOCOL_PROXYV2READER_H

#include "IO/Networking/AsyncSocket.h"

#include "nonstd/expected.hpp"

namespace ProxyProtocol
{
/// Allows you to read the proxy protocol V2
/// Keep in mind that this must be from a trusted source
void ReadProxyV2Handshake(IO::Networking::AsyncSocket* socket, std::function<void(nonstd::expected<IO::Networking::IpAddress, IO::NetworkError> const&)> const& callback);
}

#endif //MANGOS_PROXYPROTOCOL_PROXYV2READER_H

0 comments on commit 05d617f

Please sign in to comment.