diff options
author | Shauren <shauren.trinity@gmail.com> | 2023-07-15 00:45:16 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2023-07-15 00:45:16 +0200 |
commit | 6be536a73bc8a6e331ce20e7d19e2ea56b99b4d0 (patch) | |
tree | 2ad2ae6d9f4096c97235063eff60e7d69641a2b9 | |
parent | cdfaecda52e165bb04381e1677108ff87b8bdf13 (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.h | 5 | ||||
-rw-r--r-- | src/common/Asio/IpAddress.h | 1 | ||||
-rw-r--r-- | src/common/Asio/IpNetwork.cpp | 284 | ||||
-rw-r--r-- | src/common/Asio/IpNetwork.h | 44 | ||||
-rw-r--r-- | src/server/bnetserver/Main.cpp | 3 | ||||
-rw-r--r-- | src/server/bnetserver/REST/LoginRESTService.cpp | 54 | ||||
-rw-r--r-- | src/server/bnetserver/REST/LoginRESTService.h | 10 | ||||
-rw-r--r-- | src/server/bnetserver/Server/Session.cpp | 4 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/LoginDatabase.cpp | 2 | ||||
-rw-r--r-- | src/server/shared/Realm/Realm.cpp | 33 | ||||
-rw-r--r-- | src/server/shared/Realm/RealmList.cpp | 32 | ||||
-rw-r--r-- | src/server/shared/Realm/RealmList.h | 2 | ||||
-rw-r--r-- | src/server/worldserver/Main.cpp | 5 |
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; |