Skip to content

Commit

Permalink
Add IO::Networking::DNS::ResolveDomain (vmangos#2722)
Browse files Browse the repository at this point in the history
  • Loading branch information
0blu authored Aug 26, 2024
1 parent fdce76d commit 4dd18c9
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 30 deletions.
23 changes: 10 additions & 13 deletions src/game/Protocol/WorldSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "Database/DatabaseEnv.h"
#include "DBCStores.h"
#include "ace/OS_NS_netdb.h"
#include "IO/Networking/DNS.h"
#include "WorldSocketMgr.h"

#if defined( __GNUC__ )
Expand Down Expand Up @@ -197,26 +198,22 @@ WorldSocket::HandlerResult WorldSocket::_HandleCompleteReceivedPacket(std::uniqu
MANGOS_ASSERT(false); // This should never be reached
}

/// This function will resolve the ip-addresse of the current host
/// For example if you hostname is called "world.mycoolserver.com" and it points to 123.45.66.7 it will be added to the server list
/// Also 127.0.0.1 will be added as a fallback
/// This list is later used to determine if clients try to connect to this server without registering at realmd first
static std::set<std::string> GetServerAddresses()
{
std::set<std::string> addresses;
char hostName[MAXHOSTNAMELEN] = {};
addresses.insert("127.0.0.1");

if (ACE_OS::hostname(hostName, MAXHOSTNAMELEN) != -1)
std::string myHostname = IO::Networking::DNS::GetOwnHostname();
std::vector<IO::Networking::IpAddress> ipAddresses = IO::Networking::DNS::ResolveDomain(myHostname, IO::Networking::IpAddress::Type::IPv4);
for (auto const& ipAddress : ipAddresses)
{
if (hostent* hp = ACE_OS::gethostbyname(hostName))
{
for (int i = 0; hp->h_addr_list[i] != 0; ++i)
{
in_addr addr;
memcpy(&addr, hp->h_addr_list[i], sizeof(in_addr));
addresses.insert(ACE_OS::inet_ntoa(addr));
}
}
addresses.insert(ipAddress.toString());
}

addresses.insert("127.0.0.1");

return addresses;
}

Expand Down
4 changes: 4 additions & 0 deletions src/shared/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ set (shared_SRCS
IO/Context/IoContext_windows.cpp
IO/SystemErrorToString.h
IO/SystemErrorToString.cpp
IO/Networking/Internal.h
IO/Networking/Internal.cpp
IO/Networking/AsyncServerListener.h
IO/Networking/AsyncSocket.h
IO/Networking/NetworkError.h
Expand All @@ -119,6 +121,8 @@ set (shared_SRCS
IO/Networking/Utils.cpp
IO/Networking/IpAddress.h
IO/Networking/IpAddress.cpp
IO/Networking/DNS.h
IO/Networking/DNS.cpp
IO/Multithreading/CreateThread.h
IO/Multithreading/CreateThread.cpp
IO/Timer/impl/windows/AsyncSystemTimer.cpp
Expand Down
51 changes: 51 additions & 0 deletions src/shared/IO/Networking/DNS.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "./DNS.h"
#include "./Internal.h"
#include "Log.h"
#include "Errors.h"
#include "IO/SystemErrorToString.h"

#if defined(WIN32)
#include <WinSock2.h>
#include <ws2tcpip.h>
#endif

std::string IO::Networking::DNS::GetOwnHostname()
{
char hostname[1024];
if (::gethostname(hostname, sizeof(hostname)) == -1)
{
sLog.Out(LogType::LOG_NETWORK, LOG_LVL_ERROR, "IO ERROR: ::gethostname(...): %s", SystemErrorToString(errno).c_str());
MANGOS_ASSERT(false);
}
return hostname;
}

std::vector<IO::Networking::IpAddress> IO::Networking::DNS::ResolveDomain(std::string const& domainName, IO::Networking::IpAddress::Type type)
{
MANGOS_ASSERT(type == IpAddress::Type::IPv4);

addrinfo hints = {};
hints.ai_family = type == IpAddress::Type::IPv4 ? AF_INET : AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;

addrinfo* dnsResult = nullptr;
if (::getaddrinfo(domainName.c_str(), nullptr, &hints, &dnsResult) != 0)
{
sLog.Out(LogType::LOG_NETWORK, LOG_LVL_ERROR, "IO ERROR: ::getaddrinfo(...): %s", SystemErrorToString(errno).c_str());
MANGOS_ASSERT(false);
}

std::vector<IO::Networking::IpAddress> list;

for (addrinfo* ptr = dnsResult; ptr != nullptr; ptr = ptr->ai_next)
{
sockaddr_in* sockaddr_ipv4 = reinterpret_cast<sockaddr_in*>(ptr->ai_addr);
IpAddress ip = IO::Networking::Internal::inet_ntop(&(sockaddr_ipv4->sin_addr));
list.emplace_back(ip);
}

freeaddrinfo(dnsResult);

return list;
}
14 changes: 14 additions & 0 deletions src/shared/IO/Networking/DNS.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef MANGOS_IO_NETWORKING_DNS_H
#define MANGOS_IO_NETWORKING_DNS_H

#include <vector>
#include <experimental/vector>
#include "./IpAddress.h"

namespace IO { namespace Networking { namespace DNS
{
std::string GetOwnHostname();
std::vector<IO::Networking::IpAddress> ResolveDomain(std::string const& domainName, IO::Networking::IpAddress::Type type);
}}} // namespace IO::Networking

#endif // MANGOS_IO_NETWORKING_DNS_H
23 changes: 23 additions & 0 deletions src/shared/IO/Networking/Internal.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include "Errors.h"
#include "./Internal.h"

/// Converts a native IN_ADDR to a IO::Networking::IpAddress
IO::Networking::IpAddress IO::Networking::Internal::inet_ntop(in_addr const* nativeAddress)
{
#if defined(WIN32)
// We cant use ::inet_ntoa(...) because it's not thread safe. We cant use ::inet_ntop(...) because it's not WinXP compatible, so we have to do it ourselves.
int constexpr MAX_IPV4_LENGTH = 16; // "255.255.255.255" = length 15 + 1 for null-terminator
char ipv4AddressString[MAX_IPV4_LENGTH];
{ // impl was taken from ACE, should be universal
uint8_t const* p = reinterpret_cast<uint8_t const*>(nativeAddress);
snprintf(ipv4AddressString, MAX_IPV4_LENGTH, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
}
auto ipAddress = IO::Networking::IpAddress::TryParseFromString(ipv4AddressString);
#else
char ipv4AddressString[INET_ADDRSTRLEN];
::inet_ntop(AF_INET, nativeAddress, ipv4AddressString, INET_ADDRSTRLEN);
auto ipAddress = IO::Networking::IpAddress::TryParseFromString(ipv4AddressString);
#endif
MANGOS_ASSERT(ipAddress.has_value()); // this should never fail, since we got a valid IP from IN_ADDR
return ipAddress.value();
}
15 changes: 15 additions & 0 deletions src/shared/IO/Networking/Internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#ifndef MANGOS_IO_NETWORKING_INTERNAL_H
#define MANGOS_IO_NETWORKING_INTERNAL_H

#include "./IpAddress.h"

struct in_addr;

namespace IO { namespace Networking { namespace Internal
{
/// Converts a native IN_ADDR to a IO::Networking::IpAddress
IO::Networking::IpAddress inet_ntop(in_addr const* nativeAddress);

}}} // IO::Networking::Internal

#endif // MANGOS_IO_NETWORKING_INTERNAL_H
9 changes: 3 additions & 6 deletions src/shared/IO/Networking/impl/unix/AsyncServerListener_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "IO/Context/IoContext.h"
#include "IO/Networking/SocketDescriptor.h"
#include "IO/Networking/IpAddress.h"
#include "IO/Networking/Internal.h"
#include "IO/SystemErrorToString.h"

#if defined(__linux__)
Expand Down Expand Up @@ -109,14 +110,10 @@ void IO::Networking::AsyncServerListener<TClientSocket>::OnNewClientToAcceptAvai
return;
}

char ipv4AddressString[INET_ADDRSTRLEN];
::inet_ntop(AF_INET, &(peerAddress.sin_addr), ipv4AddressString, INET_ADDRSTRLEN);
auto peerIpAddress = IO::Networking::IpAddress::TryParseFromString(ipv4AddressString);
IO::Networking::IpAddress peerIpAddress = IO::Networking::Internal::inet_ntop(&(peerAddress.sin_addr));
uint16_t peerPort = ntohs(peerAddress.sin_port);

MANGOS_ASSERT(peerIpAddress.has_value());

IO::Networking::IpEndpoint peerEndpoint(peerIpAddress.value(), peerPort);
IO::Networking::IpEndpoint peerEndpoint(peerIpAddress, peerPort);
IO::Networking::SocketDescriptor socketDescriptor{peerEndpoint, nativePeerSocket};

std::shared_ptr<TClientSocket> client = std::make_shared<TClientSocket>(m_ctx, socketDescriptor);
Expand Down
14 changes: 3 additions & 11 deletions src/shared/IO/Networking/impl/windows/AsyncServerListener_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <chrono>
#include <WinSock2.h>
#include "Errors.h"
#include "IO/Networking/Internal.h"
#include "IO/Context/AsyncIoOperation.h"
#include "IO/Networking/IpAddress.h"
#include "IO/Networking/SocketDescriptor.h"
Expand Down Expand Up @@ -119,20 +120,11 @@ void IO::Networking::AsyncServerListener<TClientSocket>::StartAcceptOperation()
return;
}

// We cant use ::inet_ntoa(...) because it's not thread safe. We cant use ::inet_ntop(...) because it's not WinXP compatible, so we have to do it ourselves.
int constexpr MAX_IPV4_LENGTH = 16; // "255.255.255.255" = length 15 + 1 for null-terminator
char ipv4AddressString[MAX_IPV4_LENGTH];
{ // impl was taken from ACE, should be universal
uint8_t const* const p = reinterpret_cast<uint8_t const*>(&addrBuffer->peerAddress.sin_addr);
snprintf(ipv4AddressString, MAX_IPV4_LENGTH, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
}
auto peerIpAddress = IO::Networking::IpAddress::TryParseFromString(ipv4AddressString);
IO::Networking::IpAddress peerIpAddress = IO::Networking::Internal::inet_ntop(&(addrBuffer->peerAddress.sin_addr));
uint16_t peerPort = ntohs(addrBuffer->peerAddress.sin_port);

delete addrBuffer;
MANGOS_ASSERT(peerIpAddress.has_value());

IO::Networking::IpEndpoint peerEndpoint(peerIpAddress.value(), peerPort);
IO::Networking::IpEndpoint peerEndpoint(peerIpAddress, peerPort);
IO::Networking::SocketDescriptor socketDescriptor{ peerEndpoint, nativePeerSocket };

std::shared_ptr<TClientSocket> client = std::make_shared<TClientSocket>(m_ctx, socketDescriptor);
Expand Down

0 comments on commit 4dd18c9

Please sign in to comment.