aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2023-07-15 00:45:16 +0200
committerShauren <shauren.trinity@gmail.com>2023-07-15 00:45:16 +0200
commit6be536a73bc8a6e331ce20e7d19e2ea56b99b4d0 (patch)
tree2ad2ae6d9f4096c97235063eff60e7d69641a2b9
parentcdfaecda52e165bb04381e1677108ff87b8bdf13 (diff)
Core/Network: Refactor local/remote ip address selection code and allow using hostnames in LoginREST bnetserver config options
-rw-r--r--src/common/Asio/AsioHacksFwd.h5
-rw-r--r--src/common/Asio/IpAddress.h1
-rw-r--r--src/common/Asio/IpNetwork.cpp284
-rw-r--r--src/common/Asio/IpNetwork.h44
-rw-r--r--src/server/bnetserver/Main.cpp3
-rw-r--r--src/server/bnetserver/REST/LoginRESTService.cpp54
-rw-r--r--src/server/bnetserver/REST/LoginRESTService.h10
-rw-r--r--src/server/bnetserver/Server/Session.cpp4
-rw-r--r--src/server/database/Database/Implementation/LoginDatabase.cpp2
-rw-r--r--src/server/shared/Realm/Realm.cpp33
-rw-r--r--src/server/shared/Realm/RealmList.cpp32
-rw-r--r--src/server/shared/Realm/RealmList.h2
-rw-r--r--src/server/worldserver/Main.cpp5
13 files changed, 386 insertions, 93 deletions
diff --git a/src/common/Asio/AsioHacksFwd.h b/src/common/Asio/AsioHacksFwd.h
index 6030436d39d..a8f04b16d81 100644
--- a/src/common/Asio/AsioHacksFwd.h
+++ b/src/common/Asio/AsioHacksFwd.h
@@ -38,6 +38,11 @@ namespace boost
namespace ip
{
class address;
+ class address_v4;
+ class address_v6;
+
+ class network_v4;
+ class network_v6;
class tcp;
diff --git a/src/common/Asio/IpAddress.h b/src/common/Asio/IpAddress.h
index 30500d662c6..22af8bbfd41 100644
--- a/src/common/Asio/IpAddress.h
+++ b/src/common/Asio/IpAddress.h
@@ -27,6 +27,7 @@ namespace Trinity
{
using boost::asio::ip::make_address;
using boost::asio::ip::make_address_v4;
+ using boost::asio::ip::make_address_v6;
inline uint32 address_to_uint(boost::asio::ip::address_v4 const& address) { return address.to_uint(); }
}
}
diff --git a/src/common/Asio/IpNetwork.cpp b/src/common/Asio/IpNetwork.cpp
new file mode 100644
index 00000000000..5e5dcb9ac22
--- /dev/null
+++ b/src/common/Asio/IpNetwork.cpp
@@ -0,0 +1,284 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "IpNetwork.h"
+#include "IpAddress.h"
+#include <boost/asio/ip/network_v4.hpp>
+#include <boost/asio/ip/network_v6.hpp>
+
+namespace
+{
+std::vector<boost::asio::ip::network_v4> LocalV4Networks;
+std::vector<boost::asio::ip::network_v6> LocalV6Networks;
+}
+
+namespace Trinity::Net
+{
+bool IsInLocalNetwork(boost::asio::ip::address const& clientAddress)
+{
+ if (clientAddress.is_v4())
+ {
+ return std::any_of(LocalV4Networks.begin(), LocalV4Networks.end(), [clientAddressV4 = clientAddress.to_v4()](boost::asio::ip::network_v4 const& network)
+ {
+ return IsInNetwork(network, clientAddressV4);
+ });
+ }
+
+ if (clientAddress.is_v6())
+ {
+ return std::any_of(LocalV6Networks.begin(), LocalV6Networks.end(), [clientAddressV6 = clientAddress.to_v6()](boost::asio::ip::network_v6 const& network)
+ {
+ return IsInNetwork(network, clientAddressV6);
+ });
+ }
+
+ return false;
+};
+
+bool IsInNetwork(boost::asio::ip::network_v4 const& network, boost::asio::ip::address_v4 const& clientAddress)
+{
+ if (clientAddress == network.address())
+ return true;
+
+ boost::asio::ip::network_v4 endpointAsNetwork = boost::asio::ip::make_network_v4(clientAddress, 32);
+ return endpointAsNetwork.is_subnet_of(network);
+}
+
+bool IsInNetwork(boost::asio::ip::network_v6 const& network, boost::asio::ip::address_v6 const& clientAddress)
+{
+ if (clientAddress == network.address())
+ return true;
+
+ boost::asio::ip::network_v6 endpointAsNetwork = boost::asio::ip::make_network_v6(clientAddress, 128);
+ return endpointAsNetwork.is_subnet_of(network);
+}
+
+Optional<std::size_t> SelectAddressForClient(boost::asio::ip::address const& clientAddress, std::span<boost::asio::ip::address> const& addresses)
+{
+ Optional<std::size_t> localIpv6Index;
+ Optional<std::size_t> externalIpv6Index;
+ Optional<std::size_t> loopbackIpv6Index;
+ Optional<std::size_t> localIpv4Index;
+ Optional<std::size_t> externalIpv4Index;
+ Optional<std::size_t> loopbackIpv4Index;
+
+ for (std::size_t i = 0; i < addresses.size(); ++i)
+ {
+ boost::asio::ip::address const& address = addresses[i];
+
+ if (IsInLocalNetwork(address))
+ {
+ if (address.is_v6() && !localIpv6Index)
+ localIpv6Index = i;
+
+ if (address.is_v4() && !localIpv4Index)
+ localIpv4Index = i;
+ }
+ else
+ {
+ if (address.is_v6() && !externalIpv6Index)
+ externalIpv6Index = i;
+
+ if (address.is_v4() && !externalIpv4Index)
+ externalIpv4Index = i;
+ }
+
+ if (address.is_loopback())
+ {
+ if (address.is_v6() && !loopbackIpv6Index)
+ loopbackIpv6Index = i;
+
+ if (address.is_v4() && !loopbackIpv4Index)
+ loopbackIpv4Index = i;
+ }
+ }
+
+ if (IsInLocalNetwork(clientAddress) || clientAddress.is_loopback())
+ {
+ // client is in the same network as this process, prefer local addresses
+
+ // first, try finding a local ipv6 address
+ if (clientAddress.is_v6() && localIpv6Index)
+ {
+ // we have a usable ipv6 local address
+ return localIpv6Index;
+ }
+
+ // we dont have a local v6, return local v4
+ if (localIpv4Index)
+ return localIpv4Index;
+ }
+
+ if (clientAddress.is_loopback())
+ {
+ // fallback, search for a loopback address in configuration
+ if (clientAddress.is_v6() && loopbackIpv6Index)
+ return loopbackIpv6Index;
+
+ if (loopbackIpv4Index)
+ return loopbackIpv4Index;
+ }
+
+ // client is NOT in the same network as this process
+ if (clientAddress.is_v6() && externalIpv6Index)
+ return externalIpv6Index;
+
+ return externalIpv4Index;
+}
+}
+
+#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
+
+#include <boost/dll/shared_library.hpp>
+#include <iphlpapi.h>
+
+void Trinity::Net::ScanLocalNetworks()
+{
+ LocalV4Networks.clear();
+ LocalV6Networks.clear();
+
+ boost::system::error_code dllError;
+ boost::dll::shared_library iphlp("Iphlpapi.dll", dllError, boost::dll::load_mode::search_system_folders);
+ if (dllError || !iphlp.is_loaded())
+ return;
+
+ auto getAdaptersAddresses = iphlp.get<decltype(GetAdaptersAddresses)>("GetAdaptersAddresses");
+ if (!getAdaptersAddresses)
+ return;
+
+ ULONG queryFlags = GAA_FLAG_SKIP_UNICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_FRIENDLY_NAME;
+ ULONG bufferSize = 0;
+
+ if (getAdaptersAddresses(AF_UNSPEC, queryFlags, nullptr, nullptr, &bufferSize) != ERROR_BUFFER_OVERFLOW)
+ return;
+
+ std::unique_ptr<std::byte[]> addressesBuffer = std::make_unique<std::byte[]>(bufferSize);
+ if (getAdaptersAddresses(AF_UNSPEC, queryFlags, nullptr, reinterpret_cast<IP_ADAPTER_ADDRESSES*>(addressesBuffer.get()), &bufferSize) != ERROR_SUCCESS)
+ return;
+
+ for (IP_ADAPTER_ADDRESSES* itr = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(addressesBuffer.get()); itr; itr = itr->Next)
+ {
+ if (itr->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
+ continue;
+
+ if (itr->OperStatus != IfOperStatusUp)
+ continue;
+
+ for (IP_ADAPTER_PREFIX_XP* prefix = itr->FirstPrefix; prefix; prefix = prefix->Next)
+ {
+ switch (prefix->Address.lpSockaddr->sa_family)
+ {
+ case AF_INET:
+ {
+ SOCKADDR_IN* ipv4raw = reinterpret_cast<SOCKADDR_IN*>(prefix->Address.lpSockaddr);
+ boost::asio::ip::address_v4::bytes_type addressBytes;
+ std::memcpy(addressBytes.data(), &ipv4raw->sin_addr.s_addr, addressBytes.size());
+ boost::asio::ip::address_v4 address = make_address_v4(addressBytes);
+ if (address.is_unspecified() || address.is_multicast() || address == boost::asio::ip::address_v4::broadcast())
+ continue;
+
+ LocalV4Networks.push_back(boost::asio::ip::make_network_v4(address, prefix->PrefixLength));
+ break;
+ }
+ case AF_INET6:
+ {
+ SOCKADDR_IN6* ipv6raw = reinterpret_cast<SOCKADDR_IN6*>(prefix->Address.lpSockaddr);
+ boost::asio::ip::address_v6::bytes_type addressBytes;
+ std::memcpy(addressBytes.data(), ipv6raw->sin6_addr.s6_addr, addressBytes.size());
+ boost::asio::ip::address_v6 address = make_address_v6(addressBytes, ipv6raw->sin6_scope_id);
+ if (address.is_unspecified() || address.is_multicast())
+ continue;
+
+ LocalV6Networks.push_back(boost::asio::ip::make_network_v6(address, prefix->PrefixLength));
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+}
+
+#else
+
+#include <numeric>
+#include <ifaddrs.h>
+
+void Trinity::Net::ScanLocalNetworks()
+{
+ LocalV4Networks.clear();
+ LocalV6Networks.clear();
+
+ ifaddrs* addressesLinkedList = nullptr;
+ if (getifaddrs(&addressesLinkedList) == -1)
+ return;
+
+ for (ifaddrs* itr = addressesLinkedList; itr; itr = itr->ifa_next)
+ {
+ if (!itr->ifa_addr)
+ continue;
+
+ switch (itr->ifa_addr->sa_family)
+ {
+ case AF_INET:
+ {
+ sockaddr_in* ipv4raw = reinterpret_cast<sockaddr_in*>(itr->ifa_addr);
+ boost::asio::ip::address_v4::bytes_type addressBytes;
+ std::memcpy(addressBytes.data(), &ipv4raw->sin_addr.s_addr, addressBytes.size());
+ boost::asio::ip::address_v4 address = make_address_v4(addressBytes);
+ if (address.is_unspecified() || address.is_loopback() || address.is_multicast() || address == boost::asio::ip::address_v4::broadcast())
+ continue;
+
+ if (sockaddr_in* netmask4raw = reinterpret_cast<sockaddr_in*>(itr->ifa_netmask))
+ {
+ boost::asio::ip::address_v4::bytes_type netmaskBytes;
+ std::memcpy(netmaskBytes.data(), &netmask4raw->sin_addr.s_addr, netmaskBytes.size());
+ boost::asio::ip::address_v4 netmask = make_address_v4(netmaskBytes);
+ LocalV4Networks.push_back(boost::asio::ip::make_network_v4(address, netmask));
+ }
+ else
+ LocalV4Networks.push_back(boost::asio::ip::make_network_v4(address, 32));
+ break;
+ }
+ case AF_INET6:
+ {
+ sockaddr_in6* ipv6raw = reinterpret_cast<sockaddr_in6*>(itr->ifa_addr);
+ boost::asio::ip::address_v6::bytes_type addressBytes;
+ std::memcpy(addressBytes.data(), ipv6raw->sin6_addr.s6_addr, addressBytes.size());
+ boost::asio::ip::address_v6 address = make_address_v6(addressBytes, ipv6raw->sin6_scope_id);
+ if (address.is_unspecified() || address.is_loopback() || address.is_multicast())
+ continue;
+
+ if (sockaddr_in6* netmask6raw = reinterpret_cast<sockaddr_in6*>(itr->ifa_netmask))
+ {
+ int32 prefixLength = 0;
+ for (uint8 addressByte : netmask6raw->sin6_addr.s6_addr)
+ prefixLength += std::countl_one(addressByte);
+
+ LocalV6Networks.push_back(boost::asio::ip::make_network_v6(address, prefixLength));
+ }
+ else
+ LocalV6Networks.push_back(boost::asio::ip::make_network_v6(address, 128));
+ break;
+ }
+ }
+ }
+
+ freeifaddrs(addressesLinkedList);
+}
+
+#endif
diff --git a/src/common/Asio/IpNetwork.h b/src/common/Asio/IpNetwork.h
index 294532c5c78..242c344fc15 100644
--- a/src/common/Asio/IpNetwork.h
+++ b/src/common/Asio/IpNetwork.h
@@ -18,40 +18,22 @@
#ifndef IpNetwork_h__
#define IpNetwork_h__
+#include "AsioHacksFwd.h"
#include "Define.h"
-#include "IpAddress.h"
-#include <boost/asio/ip/network_v4.hpp>
-#include <boost/asio/ip/network_v6.hpp>
+#include "Optional.h"
+#include <span>
-namespace Trinity
+namespace Trinity::Net
{
- namespace Net
- {
- inline bool IsInNetwork(boost::asio::ip::address_v4 const& networkAddress, boost::asio::ip::address_v4 const& mask, boost::asio::ip::address_v4 const& clientAddress)
- {
- boost::asio::ip::network_v4 network = boost::asio::ip::make_network_v4(networkAddress, mask);
- boost::asio::ip::address_v4_range hosts = network.hosts();
- return hosts.find(clientAddress) != hosts.end();
- }
-
- inline boost::asio::ip::address_v4 GetDefaultNetmaskV4(boost::asio::ip::address_v4 const& networkAddress)
- {
- if ((address_to_uint(networkAddress) & 0x80000000) == 0)
- return boost::asio::ip::address_v4(0xFF000000);
- if ((address_to_uint(networkAddress) & 0xC0000000) == 0x80000000)
- return boost::asio::ip::address_v4(0xFFFF0000);
- if ((address_to_uint(networkAddress) & 0xE0000000) == 0xC0000000)
- return boost::asio::ip::address_v4(0xFFFFFF00);
- return boost::asio::ip::address_v4(0xFFFFFFFF);
- }
-
- inline bool IsInNetwork(boost::asio::ip::address_v6 const& networkAddress, uint16 prefixLength, boost::asio::ip::address_v6 const& clientAddress)
- {
- boost::asio::ip::network_v6 network = boost::asio::ip::make_network_v6(networkAddress, prefixLength);
- boost::asio::ip::address_v6_range hosts = network.hosts();
- return hosts.find(clientAddress) != hosts.end();
- }
- }
+TC_COMMON_API bool IsInLocalNetwork(boost::asio::ip::address const& clientAddress);
+
+TC_COMMON_API bool IsInNetwork(boost::asio::ip::network_v4 const& network, boost::asio::ip::address_v4 const& clientAddress);
+
+TC_COMMON_API bool IsInNetwork(boost::asio::ip::network_v6 const& network, boost::asio::ip::address_v6 const& clientAddress);
+
+TC_COMMON_API Optional<std::size_t> SelectAddressForClient(boost::asio::ip::address const& clientAddress, std::span<boost::asio::ip::address> const& addresses);
+
+TC_COMMON_API void ScanLocalNetworks();
}
#endif // IpNetwork_h__
diff --git a/src/server/bnetserver/Main.cpp b/src/server/bnetserver/Main.cpp
index a1b93920489..6b2e058262e 100644
--- a/src/server/bnetserver/Main.cpp
+++ b/src/server/bnetserver/Main.cpp
@@ -32,6 +32,7 @@
#include "DeadlineTimer.h"
#include "GitRevision.h"
#include "IPLocation.h"
+#include "IpNetwork.h"
#include "LoginRESTService.h"
#include "MySQLThreading.h"
#include "OpenSSLCrypto.h"
@@ -192,6 +193,8 @@ int main(int argc, char** argv)
std::shared_ptr<Trinity::Asio::IoContext> ioContext = std::make_shared<Trinity::Asio::IoContext>();
+ Trinity::Net::ScanLocalNetworks();
+
// Start the listening port (acceptor) for auth connections
int32 bnport = sConfigMgr->GetIntDefault("BattlenetPort", 1119);
if (bnport < 0 || bnport > 0xFFFF)
diff --git a/src/server/bnetserver/REST/LoginRESTService.cpp b/src/server/bnetserver/REST/LoginRESTService.cpp
index 5267b2bd761..6e260b4df56 100644
--- a/src/server/bnetserver/REST/LoginRESTService.cpp
+++ b/src/server/bnetserver/REST/LoginRESTService.cpp
@@ -90,7 +90,8 @@ bool LoginRESTService::Start(Trinity::Asio::IoContext* ioContext)
return false;
}
- _externalAddress = *externalAddress;
+ _externalEndpoint = *externalAddress;
+ _externalHostname = Trinity::StringFormat("{}:{}", configuredAddress, _port);
configuredAddress = sConfigMgr->GetStringDefault("LoginREST.LocalAddress", "127.0.0.1");
Optional<boost::asio::ip::tcp::endpoint> localAddress = resolver.Resolve(boost::asio::ip::tcp::v4(), configuredAddress, std::to_string(_port));
@@ -100,8 +101,8 @@ bool LoginRESTService::Start(Trinity::Asio::IoContext* ioContext)
return false;
}
- _localAddress = *localAddress;
- _localNetmask = Trinity::Net::GetDefaultNetmaskV4(_localAddress.address().to_v4());
+ _localEndpoint = *localAddress;
+ _localHostname = Trinity::StringFormat("{}:{}", configuredAddress, _port);
// set up form inputs
Battlenet::JSON::Login::FormInput* input;
@@ -135,17 +136,48 @@ void LoginRESTService::Stop()
_thread.join();
}
-boost::asio::ip::tcp::endpoint const& LoginRESTService::GetAddressForClient(boost::asio::ip::address const& address) const
+boost::asio::ip::tcp::endpoint const& LoginRESTService::GetEndpointForClient(boost::asio::ip::address const& address) const
{
+ std::array<boost::asio::ip::address, 2> addresses = std::array{ _externalEndpoint.address(), _localEndpoint.address() };
+ if (auto addressIndex = Trinity::Net::SelectAddressForClient(address, addresses))
+ {
+ switch (*addressIndex)
+ {
+ case 0:
+ return _externalEndpoint;
+ case 1:
+ return _localEndpoint;
+ default:
+ break;
+ }
+ }
+
if (address.is_loopback())
- return _localAddress;
- else if (_localAddress.address().is_loopback())
- return _externalAddress;
+ return _localEndpoint;
+
+ return _externalEndpoint;
+}
- if (Trinity::Net::IsInNetwork(_localAddress.address().to_v4(), _localNetmask, address.to_v4()))
- return _localAddress;
+std::string const& LoginRESTService::GetHostnameForClient(boost::asio::ip::address const& address) const
+{
+ std::array<boost::asio::ip::address, 2> addresses = std::array{ _externalEndpoint.address(), _localEndpoint.address() };
+ if (auto addressIndex = Trinity::Net::SelectAddressForClient(address, addresses))
+ {
+ switch (*addressIndex)
+ {
+ case 0:
+ return _externalHostname;
+ case 1:
+ return _localHostname;
+ default:
+ break;
+ }
+ }
+
+ if (address.is_loopback())
+ return _localHostname;
- return _externalAddress;
+ return _externalHostname;
}
void LoginRESTService::Run()
@@ -298,7 +330,7 @@ int32 LoginRESTService::HandleGetGameAccounts(std::shared_ptr<AsyncRequest> requ
int32 LoginRESTService::HandleGetPortal(std::shared_ptr<AsyncRequest> request)
{
- boost::asio::ip::tcp::endpoint const& endpoint = GetAddressForClient(boost::asio::ip::address_v4(request->GetClient()->ip));
+ boost::asio::ip::tcp::endpoint const& endpoint = GetEndpointForClient(boost::asio::ip::address_v4(request->GetClient()->ip));
std::string response = Trinity::StringFormat("{}:{}", endpoint.address().to_string(), sConfigMgr->GetIntDefault("BattlenetPort", 1119));
soap_response(request->GetClient(), SOAP_FILE);
diff --git a/src/server/bnetserver/REST/LoginRESTService.h b/src/server/bnetserver/REST/LoginRESTService.h
index e4d22dd9661..5c549fbf589 100644
--- a/src/server/bnetserver/REST/LoginRESTService.h
+++ b/src/server/bnetserver/REST/LoginRESTService.h
@@ -46,7 +46,8 @@ public:
bool Start(Trinity::Asio::IoContext* ioContext);
void Stop();
- boost::asio::ip::tcp::endpoint const& GetAddressForClient(boost::asio::ip::address const& address) const;
+ boost::asio::ip::tcp::endpoint const& GetEndpointForClient(boost::asio::ip::address const& address) const;
+ std::string const& GetHostnameForClient(boost::asio::ip::address const& address) const;
private:
void Run();
@@ -101,9 +102,10 @@ private:
Battlenet::JSON::Login::FormInputs _formInputs;
std::string _bindIP;
int32 _port;
- boost::asio::ip::tcp::endpoint _externalAddress;
- boost::asio::ip::tcp::endpoint _localAddress;
- boost::asio::ip::address_v4 _localNetmask;
+ std::string _externalHostname;
+ boost::asio::ip::tcp::endpoint _externalEndpoint;
+ std::string _localHostname;
+ boost::asio::ip::tcp::endpoint _localEndpoint;
uint32 _loginTicketDuration;
HttpMethodHandlerMap _getHandlers;
diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp
index 806b371f79d..f98c429acf8 100644
--- a/src/server/bnetserver/Server/Session.cpp
+++ b/src/server/bnetserver/Server/Session.cpp
@@ -232,11 +232,11 @@ uint32 Battlenet::Session::HandleLogon(authentication::v1::LogonRequest const* l
if (logonRequest->has_cached_web_credentials())
return VerifyWebCredentials(logonRequest->cached_web_credentials(), continuation);
- boost::asio::ip::tcp::endpoint const& endpoint = sLoginService.GetAddressForClient(GetRemoteIpAddress());
+ std::string const& hostname = sLoginService.GetHostnameForClient(GetRemoteIpAddress());
challenge::v1::ChallengeExternalRequest externalChallenge;
externalChallenge.set_payload_type("web_auth_url");
- externalChallenge.set_payload(Trinity::StringFormat("https://{}:{}/bnetserver/login/", endpoint.address().to_string(), endpoint.port()));
+ externalChallenge.set_payload(Trinity::StringFormat("https://{}/bnetserver/login/", hostname));
Service<challenge::v1::ChallengeListener>(this).OnExternalChallenge(&externalChallenge);
return ERROR_OK;
}
diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp
index 21b0b7534f1..0b9fd4e8f89 100644
--- a/src/server/database/Database/Implementation/LoginDatabase.cpp
+++ b/src/server/database/Database/Implementation/LoginDatabase.cpp
@@ -23,7 +23,7 @@ void LoginDatabaseConnection::DoPrepareStatements()
if (!m_reconnecting)
m_stmts.resize(MAX_LOGINDATABASE_STATEMENTS);
- PrepareStatement(LOGIN_SEL_REALMLIST, "SELECT id, name, address, localAddress, localSubnetMask, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild, Region, Battlegroup FROM realmlist WHERE flag <> 3 ORDER BY name", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_SEL_REALMLIST, "SELECT id, name, address, localAddress, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild, Region, Battlegroup FROM realmlist WHERE flag <> 3 ORDER BY name", CONNECTION_SYNCH);
PrepareStatement(LOGIN_DEL_EXPIRED_IP_BANS, "DELETE FROM ip_banned WHERE unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS, "UPDATE account_banned SET active = 0 WHERE active = 1 AND unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_IP_INFO, "SELECT unbandate > UNIX_TIMESTAMP() OR unbandate = bandate AS banned, NULL as country FROM ip_banned WHERE ip = ?", CONNECTION_ASYNC);
diff --git a/src/server/shared/Realm/Realm.cpp b/src/server/shared/Realm/Realm.cpp
index 0648de535a3..87b7114111d 100644
--- a/src/server/shared/Realm/Realm.cpp
+++ b/src/server/shared/Realm/Realm.cpp
@@ -31,31 +31,24 @@ void Realm::SetName(std::string name)
boost::asio::ip::address Realm::GetAddressForClient(boost::asio::ip::address const& clientAddr) const
{
- boost::asio::ip::address realmIp;
-
- // Attempt to send best address for client
- if (clientAddr.is_loopback())
+ std::array<boost::asio::ip::address, 2> addresses = std::array{ *ExternalAddress, * LocalAddress };
+ if (auto addressIndex = Trinity::Net::SelectAddressForClient(clientAddr, addresses))
{
- // Try guessing if realm is also connected locally
- if (LocalAddress->is_loopback() || ExternalAddress->is_loopback())
- realmIp = clientAddr;
- else
+ switch (*addressIndex)
{
- // Assume that user connecting from the machine that bnetserver is located on
- // has all realms available in his local network
- realmIp = *LocalAddress;
+ case 0:
+ return *ExternalAddress;
+ case 1:
+ return *LocalAddress;
+ default:
+ break;
}
}
- else
- {
- if (clientAddr.is_v4() && Trinity::Net::IsInNetwork(LocalAddress->to_v4(), LocalSubnetMask->to_v4(), clientAddr.to_v4()))
- realmIp = *LocalAddress;
- else
- realmIp = *ExternalAddress;
- }
- // Return external IP
- return realmIp;
+ if (clientAddr.is_loopback())
+ return *LocalAddress;
+
+ return *ExternalAddress;
}
uint32 Realm::GetConfigId() const
diff --git a/src/server/shared/Realm/RealmList.cpp b/src/server/shared/Realm/RealmList.cpp
index c43b12ae241..ff152276c12 100644
--- a/src/server/shared/Realm/RealmList.cpp
+++ b/src/server/shared/Realm/RealmList.cpp
@@ -94,7 +94,7 @@ void RealmList::LoadBuildInfo()
}
void RealmList::UpdateRealm(Realm& realm, Battlenet::RealmHandle const& id, uint32 build, std::string const& name,
- boost::asio::ip::address&& address, boost::asio::ip::address&& localAddr, boost::asio::ip::address&& localSubmask,
+ boost::asio::ip::address&& address, boost::asio::ip::address&& localAddr,
uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel,
float population)
{
@@ -111,8 +111,6 @@ void RealmList::UpdateRealm(Realm& realm, Battlenet::RealmHandle const& id, uint
realm.ExternalAddress = std::make_unique<boost::asio::ip::address>(std::move(address));
if (!realm.LocalAddress || *realm.LocalAddress != localAddr)
realm.LocalAddress = std::make_unique<boost::asio::ip::address>(std::move(localAddr));
- if (!realm.LocalSubnetMask || *realm.LocalSubnetMask != localSubmask)
- realm.LocalSubnetMask = std::make_unique<boost::asio::ip::address>(std::move(localSubmask));
realm.Port = port;
}
@@ -145,7 +143,6 @@ void RealmList::UpdateRealms(boost::system::error_code const& error)
std::string name = fields[1].GetString();
std::string externalAddressString = fields[2].GetString();
std::string localAddressString = fields[3].GetString();
- std::string localSubmaskString = fields[4].GetString();
Optional<boost::asio::ip::tcp::endpoint> externalAddress = _resolver->Resolve(boost::asio::ip::tcp::v4(), externalAddressString, "");
if (!externalAddress)
@@ -161,30 +158,23 @@ void RealmList::UpdateRealms(boost::system::error_code const& error)
continue;
}
- Optional<boost::asio::ip::tcp::endpoint> localSubmask = _resolver->Resolve(boost::asio::ip::tcp::v4(), localSubmaskString, "");
- if (!localSubmask)
- {
- TC_LOG_ERROR("realmlist", "Could not resolve localSubnetMask {} for realm \"{}\" id {}", localSubmaskString, name, realmId);
- continue;
- }
-
- uint16 port = fields[5].GetUInt16();
- uint8 icon = fields[6].GetUInt8();
+ uint16 port = fields[4].GetUInt16();
+ uint8 icon = fields[5].GetUInt8();
if (icon == REALM_TYPE_FFA_PVP)
icon = REALM_TYPE_PVP;
if (icon >= MAX_CLIENT_REALM_TYPE)
icon = REALM_TYPE_NORMAL;
- RealmFlags flag = RealmFlags(fields[7].GetUInt8());
- uint8 timezone = fields[8].GetUInt8();
- uint8 allowedSecurityLevel = fields[9].GetUInt8();
- float pop = fields[10].GetFloat();
- uint32 build = fields[11].GetUInt32();
- uint8 region = fields[12].GetUInt8();
- uint8 battlegroup = fields[13].GetUInt8();
+ RealmFlags flag = RealmFlags(fields[6].GetUInt8());
+ uint8 timezone = fields[7].GetUInt8();
+ uint8 allowedSecurityLevel = fields[8].GetUInt8();
+ float pop = fields[9].GetFloat();
+ uint32 build = fields[10].GetUInt32();
+ uint8 region = fields[11].GetUInt8();
+ uint8 battlegroup = fields[12].GetUInt8();
Battlenet::RealmHandle id{ region, battlegroup, realmId };
- UpdateRealm(newRealms[id], id, build, name, externalAddress->address(), localAddress->address(), localSubmask->address(), port, icon,
+ UpdateRealm(newRealms[id], id, build, name, externalAddress->address(), localAddress->address(), port, icon,
flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop);
newSubRegions.insert(Battlenet::RealmHandle{ region, battlegroup, 0 }.GetAddressString());
diff --git a/src/server/shared/Realm/RealmList.h b/src/server/shared/Realm/RealmList.h
index 3d820120c37..3032b9975cb 100644
--- a/src/server/shared/Realm/RealmList.h
+++ b/src/server/shared/Realm/RealmList.h
@@ -98,7 +98,7 @@ private:
void LoadBuildInfo();
void UpdateRealms(boost::system::error_code const& error);
void UpdateRealm(Realm& realm, Battlenet::RealmHandle const& id, uint32 build, std::string const& name,
- boost::asio::ip::address&& address, boost::asio::ip::address&& localAddr, boost::asio::ip::address&& localSubmask,
+ boost::asio::ip::address&& address, boost::asio::ip::address&& localAddr,
uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population);
std::vector<RealmBuildInfo> _builds;
diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp
index d56fa0156da..013b4b0f977 100644
--- a/src/server/worldserver/Main.cpp
+++ b/src/server/worldserver/Main.cpp
@@ -34,10 +34,10 @@
#include "GitRevision.h"
#include "InstanceLockMgr.h"
#include "IoContext.h"
+#include "IpNetwork.h"
#include "MapManager.h"
#include "Metric.h"
#include "MySQLThreading.h"
-#include "ObjectAccessor.h"
#include "OpenSSLCrypto.h"
#include "OutdoorPvP/OutdoorPvPMgr.h"
#include "ProcessPriority.h"
@@ -290,6 +290,8 @@ extern int main(int argc, char** argv)
if (vm.count("update-databases-only"))
return 0;
+ Trinity::Net::ScanLocalNetworks();
+
// Set server offline (not connectable)
LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag | {} WHERE id = '{}'", REALM_FLAG_OFFLINE, realm.Id.Realm);
@@ -619,7 +621,6 @@ bool LoadRealmInfo()
realm.Build = realmListRealm->Build;
realm.ExternalAddress = std::make_unique<boost::asio::ip::address>(*realmListRealm->ExternalAddress);
realm.LocalAddress = std::make_unique<boost::asio::ip::address>(*realmListRealm->LocalAddress);
- realm.LocalSubnetMask = std::make_unique<boost::asio::ip::address>(*realmListRealm->LocalSubnetMask);
realm.Port = realmListRealm->Port;
realm.Name = realmListRealm->Name;
realm.NormalizedName = realmListRealm->NormalizedName;