diff options
author | Shauren <shauren.trinity@gmail.com> | 2024-11-12 13:54:43 +0100 |
---|---|---|
committer | Ovahlord <dreadkiller@gmx.de> | 2024-11-12 20:56:47 +0100 |
commit | 893f2d4cef5b0ee619a04ef6208ef0c1b974c8a3 (patch) | |
tree | a9fb77a877e0319edb96ddd0b72ec72441f8bb46 | |
parent | 1a32ac5ab0cd6887e3904147bda0bc65af6cb992 (diff) |
Core/Networking: Support IPv6
(cherry picked from commit af4dcc93ed04c4f2219c14821b25cb9efeb7e781)
# Conflicts:
# sql/base/auth_database.sql
# sql/updates/auth/cata_classic/2024_11_12_00_auth.sql
-rw-r--r-- | sql/base/auth_database.sql | 7 | ||||
-rw-r--r-- | sql/updates/auth/cata_classic/2024_11_12_00_auth.sql | 5 | ||||
-rw-r--r-- | src/common/Asio/Resolver.h | 17 | ||||
-rw-r--r-- | src/server/bnetserver/REST/LoginRESTService.cpp | 37 | ||||
-rw-r--r-- | src/server/bnetserver/REST/LoginRESTService.h | 3 | ||||
-rw-r--r-- | src/server/bnetserver/bnetserver.conf.dist | 1 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/LoginDatabase.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.cpp | 19 | ||||
-rw-r--r-- | src/server/game/Server/WorldSocket.cpp | 2 | ||||
-rw-r--r-- | src/server/shared/Networking/AsyncAcceptor.h | 6 | ||||
-rw-r--r-- | src/server/shared/Realm/Realm.cpp | 4 | ||||
-rw-r--r-- | src/server/shared/Realm/RealmList.cpp | 71 | ||||
-rw-r--r-- | src/server/shared/Realm/RealmList.h | 2 | ||||
-rw-r--r-- | src/server/worldserver/worldserver.conf.dist | 1 |
14 files changed, 118 insertions, 59 deletions
diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index f4b69295116..85917812ed4 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -2683,6 +2683,8 @@ CREATE TABLE `realmlist` ( `name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '127.0.0.1', `localAddress` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '127.0.0.1', + `address3` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `address4` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, `localSubnetMask` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '255.255.255.0', `port` smallint unsigned NOT NULL DEFAULT '8085', `icon` tinyint unsigned NOT NULL DEFAULT '0', @@ -2705,7 +2707,7 @@ CREATE TABLE `realmlist` ( LOCK TABLES `realmlist` WRITE; /*!40000 ALTER TABLE `realmlist` DISABLE KEYS */; INSERT INTO `realmlist` VALUES -(1,'Trinity','127.0.0.1','127.0.0.1','255.255.255.0',8085,0,0,1,0,0,57359,1,1); +(1,'Trinity','127.0.0.1','127.0.0.1',NULL,NULL,'255.255.255.0',8085,0,0,1,0,0,57359,1,1); /*!40000 ALTER TABLE `realmlist` ENABLE KEYS */; UNLOCK TABLES; @@ -3148,7 +3150,8 @@ INSERT INTO `updates` VALUES ('2024_10_31_00_auth.sql','FCBF83D6981B26DE2807BDF338A3754972535906','RELEASED','2024-10-31 19:29:16',0), ('2024_11_02_00_auth.sql','93A7F7A3C3BA586C139B4060180F7E032C535669','RELEASED','2024-11-02 12:35:24',0), ('2024_11_06_00_auth.sql','0C8D79745E070CEEE55D9546EC78FE89C5CCB040','RELEASED','2024-11-06 17:27:41',0), -('2024_11_11_00_auth.sql','F47CDFB857DB4105306739AF4FBBB3C92CA43363','RELEASED','2024-11-11 13:34:09',0); +('2024_11_11_00_auth.sql','F47CDFB857DB4105306739AF4FBBB3C92CA43363','RELEASED','2024-11-11 13:34:09',0), +('2024_11_12_00_auth.sql','5A236A557291758C0F2C46FDEC02692E7C53F751','RELEASED','2024-11-12 11:42:13',0); /*!40000 ALTER TABLE `updates` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/updates/auth/cata_classic/2024_11_12_00_auth.sql b/sql/updates/auth/cata_classic/2024_11_12_00_auth.sql new file mode 100644 index 00000000000..3eb0af6c898 --- /dev/null +++ b/sql/updates/auth/cata_classic/2024_11_12_00_auth.sql @@ -0,0 +1,5 @@ +ALTER TABLE `realmlist` + MODIFY `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '127.0.0.1' AFTER `name`, + MODIFY `localAddress` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '127.0.0.1' AFTER `address`, + ADD `address3` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL AFTER `localAddress`, + ADD `address4` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL AFTER `address3`; diff --git a/src/common/Asio/Resolver.h b/src/common/Asio/Resolver.h index 01399e435e5..01fd3127abe 100644 --- a/src/common/Asio/Resolver.h +++ b/src/common/Asio/Resolver.h @@ -21,7 +21,8 @@ #include "IoContext.h" #include "Optional.h" #include <boost/asio/ip/tcp.hpp> -#include <string> +#include <string_view> +#include <vector> namespace Trinity { @@ -35,7 +36,7 @@ namespace Trinity public: explicit Resolver(IoContext& ioContext) : _impl(ioContext) { } - Optional<boost::asio::ip::tcp::endpoint> Resolve(boost::asio::ip::tcp const& protocol, std::string const& host, std::string const& service) + Optional<boost::asio::ip::tcp::endpoint> Resolve(boost::asio::ip::tcp const& protocol, std::string_view host, std::string_view service) { boost::system::error_code ec; boost::asio::ip::resolver_base::flags flagsResolver = boost::asio::ip::resolver_base::all_matching; @@ -46,6 +47,18 @@ namespace Trinity return results.begin()->endpoint(); } + std::vector<boost::asio::ip::tcp::endpoint> ResolveAll(std::string_view host, std::string_view service) + { + boost::system::error_code ec; + boost::asio::ip::resolver_base::flags flagsResolver = boost::asio::ip::resolver_base::all_matching; + boost::asio::ip::tcp::resolver::results_type results = _impl.resolve(host, service, flagsResolver, ec); + std::vector<boost::asio::ip::tcp::endpoint> result; + if (!ec) + std::ranges::transform(results, std::back_inserter(result), [](boost::asio::ip::tcp::resolver::results_type::value_type const& entry) { return entry.endpoint(); }); + + return result; + } + private: boost::asio::ip::tcp::resolver _impl; }; diff --git a/src/server/bnetserver/REST/LoginRESTService.cpp b/src/server/bnetserver/REST/LoginRESTService.cpp index c9aabb248a3..b2ce7ddab56 100644 --- a/src/server/bnetserver/REST/LoginRESTService.cpp +++ b/src/server/bnetserver/REST/LoginRESTService.cpp @@ -77,28 +77,26 @@ bool LoginRESTService::StartNetwork(Trinity::Asio::IoContext& ioContext, std::st _bindIP = bindIp; _port = port; + using namespace std::string_literals; + std::array<std::string, 2> configKeys = { { "LoginREST.ExternalAddress"s, "LoginREST.LocalAddress"s } }; + Trinity::Asio::Resolver resolver(ioContext); - _hostnames[0] = sConfigMgr->GetStringDefault("LoginREST.ExternalAddress", "127.0.0.1"); - Optional<boost::asio::ip::tcp::endpoint> externalAddress = resolver.Resolve(boost::asio::ip::tcp::v4(), _hostnames[0], std::to_string(_port)); - if (!externalAddress) + for (std::size_t i = 0; i < _hostnames.size(); ++i) { - TC_LOG_ERROR("server.http.login", "Could not resolve LoginREST.ExternalAddress {}", _hostnames[0]); - return false; - } + _hostnames[i].first = sConfigMgr->GetStringDefault(configKeys[i], "127.0.0.1"); - _addresses[0] = externalAddress->address(); + std::ranges::transform(resolver.ResolveAll(_hostnames[i].first, ""), + std::back_inserter(_hostnames[i].second), + [](boost::asio::ip::tcp::endpoint const& endpoint) { return endpoint.address(); }); - _hostnames[1] = sConfigMgr->GetStringDefault("LoginREST.LocalAddress", "127.0.0.1"); - Optional<boost::asio::ip::tcp::endpoint> localAddress = resolver.Resolve(boost::asio::ip::tcp::v4(), _hostnames[1], std::to_string(_port)); - if (!localAddress) - { - TC_LOG_ERROR("server.http.login", "Could not resolve LoginREST.LocalAddress {}", _hostnames[1]); - return false; + if (_hostnames[i].second.empty()) + { + TC_LOG_ERROR("server.http.login", "Could not resolve {} {}", configKeys[i], _hostnames[i].first); + return false; + } } - _addresses[1] = localAddress->address(); - // set up form inputs JSON::Login::FormInput* input; _formInputs.set_type(JSON::Login::LOGIN_FORM); @@ -129,13 +127,14 @@ bool LoginRESTService::StartNetwork(Trinity::Asio::IoContext& ioContext, std::st std::string const& LoginRESTService::GetHostnameForClient(boost::asio::ip::address const& address) const { - if (auto addressIndex = Trinity::Net::SelectAddressForClient(address, _addresses)) - return _hostnames[*addressIndex]; + for (std::size_t i = 0; i < _hostnames.size(); ++i) + if (Trinity::Net::SelectAddressForClient(address, _hostnames[i].second)) + return _hostnames[i].first; if (address.is_loopback()) - return _hostnames[1]; + return _hostnames[1].first; - return _hostnames[0]; + return _hostnames[0].first; } std::string LoginRESTService::ExtractAuthorization(HttpRequest const& request) diff --git a/src/server/bnetserver/REST/LoginRESTService.h b/src/server/bnetserver/REST/LoginRESTService.h index bcc99808505..079bb6fca9c 100644 --- a/src/server/bnetserver/REST/LoginRESTService.h +++ b/src/server/bnetserver/REST/LoginRESTService.h @@ -83,8 +83,7 @@ private: JSON::Login::FormInputs _formInputs; std::string _bindIP; uint16 _port; - std::array<std::string, 2> _hostnames; - std::array<boost::asio::ip::address, 2> _addresses; + std::array<std::pair<std::string, std::vector<boost::asio::ip::address>>, 2> _hostnames; uint32 _loginTicketDuration; }; } diff --git a/src/server/bnetserver/bnetserver.conf.dist b/src/server/bnetserver/bnetserver.conf.dist index 94fd3964590..1936d57d3fa 100644 --- a/src/server/bnetserver/bnetserver.conf.dist +++ b/src/server/bnetserver/bnetserver.conf.dist @@ -83,6 +83,7 @@ LoginREST.TicketDuration=3600 # # BindIP # Description: Bind auth server to IP/hostname +# Using IPv6 address (such as "::") will enable both IPv4 and IPv6 connections # Default: "0.0.0.0" - (Bind to all IPs on the system) BindIP = "0.0.0.0" diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp index c916a0ac458..ca1930e4b06 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, 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, address3, address4, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild, Region, Battlegroup FROM realmlist WHERE flag <> 3 ORDER BY name", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_REALM_POPULATION, "UPDATE realmlist SET population = ? WHERE id = ?", CONNECTION_ASYNC); 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); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 1d3e5eb4cd7..0794ebf57dc 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -818,8 +818,23 @@ void WorldSession::SendConnectToInstance(WorldPackets::Auth::ConnectToSerial ser } else { - memcpy(connectTo.Payload.Where.Address.V6.data(), instanceAddress.to_v6().to_bytes().data(), 16); - connectTo.Payload.Where.Type = WorldPackets::Auth::ConnectTo::IPv6; + // client always uses v4 address for loopback and v4 mapped addresses + boost::asio::ip::address_v6 v6 = instanceAddress.to_v6(); + if (v6.is_loopback()) + { + memcpy(connectTo.Payload.Where.Address.V4.data(), boost::asio::ip::address_v4::loopback().to_bytes().data(), 4); + connectTo.Payload.Where.Type = WorldPackets::Auth::ConnectTo::IPv4; + } + else if (v6.is_v4_mapped()) + { + memcpy(connectTo.Payload.Where.Address.V4.data(), Trinity::Net::make_address_v4(boost::asio::ip::v4_mapped, v6).to_bytes().data(), 4); + connectTo.Payload.Where.Type = WorldPackets::Auth::ConnectTo::IPv4; + } + else + { + memcpy(connectTo.Payload.Where.Address.V6.data(), v6.to_bytes().data(), 16); + connectTo.Payload.Where.Type = WorldPackets::Auth::ConnectTo::IPv6; + } } connectTo.Con = CONNECTION_TYPE_INSTANCE; diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 2bdde59e956..f12dd005750 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -445,7 +445,7 @@ WorldSocket::ReadDataHandlerResult WorldSocket::ReadDataHandler() return ReadDataHandlerResult::Error; case CMSG_LOG_DISCONNECT: LogOpcodeText(opcode, sessionGuard); - packet.rfinish(); // contains uint32 disconnectReason; + TC_LOG_DEBUG("network", "WorldSocket::ReadDataHandler: client {} sent CMSG_LOG_DISCONNECT reason {}", GetRemoteIpAddress().to_string(), packet.read<uint32>()); break; case CMSG_ENABLE_NAGLE: LogOpcodeText(opcode, sessionGuard); diff --git a/src/server/shared/Networking/AsyncAcceptor.h b/src/server/shared/Networking/AsyncAcceptor.h index 7f1cb34204c..95e25e02166 100644 --- a/src/server/shared/Networking/AsyncAcceptor.h +++ b/src/server/shared/Networking/AsyncAcceptor.h @@ -22,6 +22,7 @@ #include "IpAddress.h" #include "Log.h" #include <boost/asio/ip/tcp.hpp> +#include <boost/asio/ip/v6_only.hpp> #include <atomic> #include <functional> @@ -88,6 +89,11 @@ public: } #endif + // v6_only is enabled on some *BSD distributions by default + // we want to allow both v4 and v6 connections to the same listener + if (_endpoint.protocol() == boost::asio::ip::tcp::v6()) + _acceptor.set_option(boost::asio::ip::v6_only(false)); + _acceptor.bind(_endpoint, errorCode); if (errorCode) { diff --git a/src/server/shared/Realm/Realm.cpp b/src/server/shared/Realm/Realm.cpp index 42ac0c3f64b..c06a53dfe9c 100644 --- a/src/server/shared/Realm/Realm.cpp +++ b/src/server/shared/Realm/Realm.cpp @@ -26,7 +26,7 @@ void Realm::SetName(std::string name) { Name = name; NormalizedName = std::move(name); - NormalizedName.erase(std::remove_if(NormalizedName.begin(), NormalizedName.end(), ::isspace), NormalizedName.end()); + std::erase_if(NormalizedName, [](char c) { return std::isspace(static_cast<unsigned char>(c)); }); } boost::asio::ip::address Realm::GetAddressForClient(boost::asio::ip::address const& clientAddr) const @@ -34,7 +34,7 @@ boost::asio::ip::address Realm::GetAddressForClient(boost::asio::ip::address con if (auto addressIndex = Trinity::Net::SelectAddressForClient(clientAddr, Addresses)) return Addresses[*addressIndex]; - if (clientAddr.is_loopback()) + if (Addresses.size() > 1 && clientAddr.is_loopback()) return Addresses[1]; return Addresses[0]; diff --git a/src/server/shared/Realm/RealmList.cpp b/src/server/shared/Realm/RealmList.cpp index fcee58c47d0..9fe48277353 100644 --- a/src/server/shared/Realm/RealmList.cpp +++ b/src/server/shared/Realm/RealmList.cpp @@ -80,7 +80,7 @@ void RealmList::Close() } 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, + std::vector<boost::asio::ip::address>&& addresses, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, RealmPopulationState population) { @@ -93,9 +93,7 @@ void RealmList::UpdateRealm(Realm& realm, Battlenet::RealmHandle const& id, uint realm.Timezone = timezone; realm.AllowedSecurityLevel = allowedSecurityLevel; realm.PopulationLevel = population; - realm.Addresses.resize(2); - realm.Addresses[0] = std::move(address); - realm.Addresses[1] = std::move(localAddr); + realm.Addresses = std::move(addresses); realm.Port = port; } @@ -121,48 +119,65 @@ void RealmList::UpdateRealms() Field* fields = result->Fetch(); uint32 realmId = fields[0].GetUInt32(); std::string name = fields[1].GetString(); - std::string externalAddressString = fields[2].GetString(); - std::string localAddressString = fields[3].GetString(); + std::vector<boost::asio::ip::address> addresses; - Optional<boost::asio::ip::tcp::endpoint> externalAddress = _resolver->Resolve(boost::asio::ip::tcp::v4(), externalAddressString, ""); - if (!externalAddress) + for (std::size_t i = 0; i < 4; ++i) { - TC_LOG_ERROR("realmlist", "Could not resolve address {} for realm \"{}\" id {}", externalAddressString, name, realmId); - continue; + if (fields[2 + i].IsNull()) + continue; + + for (boost::asio::ip::tcp::endpoint const& endpoint : _resolver->ResolveAll(fields[2 + i].GetStringView(), "")) + { + boost::asio::ip::address address = endpoint.address(); + if (std::ranges::find(addresses, address) != addresses.end()) + continue; + + addresses.push_back(std::move(address)); + } } - Optional<boost::asio::ip::tcp::endpoint> localAddress = _resolver->Resolve(boost::asio::ip::tcp::v4(), localAddressString, ""); - if (!localAddress) + if (addresses.empty()) { - TC_LOG_ERROR("realmlist", "Could not resolve localAddress {} for realm \"{}\" id {}", localAddressString, name, realmId); + TC_LOG_ERROR("realmlist", "Could not resolve any address for realm \"{}\" id {}", name, realmId); continue; } - uint16 port = fields[4].GetUInt16(); - uint8 icon = fields[5].GetUInt8(); + uint16 port = fields[6].GetUInt16(); + uint8 icon = fields[7].GetUInt8(); if (icon == REALM_TYPE_FFA_PVP) icon = REALM_TYPE_PVP; if (icon >= MAX_CLIENT_REALM_TYPE) icon = REALM_TYPE_NORMAL; - RealmFlags flag = ConvertLegacyRealmFlags(Trinity::Legacy::RealmFlags(fields[6].GetUInt8())); - uint8 timezone = fields[7].GetUInt8(); - uint8 allowedSecurityLevel = fields[8].GetUInt8(); - RealmPopulationState pop = ConvertLegacyPopulationState(Trinity::Legacy::RealmFlags(fields[6].GetUInt8()), fields[9].GetFloat()); - uint32 build = fields[10].GetUInt32(); - uint8 region = fields[11].GetUInt8(); - uint8 battlegroup = fields[12].GetUInt8(); + RealmFlags flag = ConvertLegacyRealmFlags(Trinity::Legacy::RealmFlags(fields[8].GetUInt8())); + uint8 timezone = fields[9].GetUInt8(); + uint8 allowedSecurityLevel = fields[10].GetUInt8(); + RealmPopulationState pop = ConvertLegacyPopulationState(Trinity::Legacy::RealmFlags(fields[8].GetUInt8()), fields[11].GetFloat()); + uint32 build = fields[12].GetUInt32(); + uint8 region = fields[13].GetUInt8(); + uint8 battlegroup = fields[14].GetUInt8(); Battlenet::RealmHandle id{ region, battlegroup, realmId }; - UpdateRealm(*newRealms.try_emplace(id, std::make_shared<Realm>()).first->second, id, build, name, externalAddress->address(), localAddress->address(), port, icon, + UpdateRealm(*newRealms.try_emplace(id, std::make_shared<Realm>()).first->second, id, build, name, std::move(addresses), port, icon, flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop); newSubRegions.insert(Battlenet::RealmHandle{ region, battlegroup, 0 }.GetAddressString()); + auto buildAddressesLogText = [&] + { + std::string text; + for (boost::asio::ip::address const& address : newRealms[id]->Addresses) + { + text += address.to_string(); + text += ' '; + } + return text; + }; + if (!existingRealms.erase(id)) - TC_LOG_INFO("realmlist", "Added realm \"{}\" at {}:{}.", name, externalAddressString, port); + TC_LOG_INFO("realmlist", "Added realm \"{}\" at {}(port {}).", name, buildAddressesLogText(), port); else - TC_LOG_DEBUG("realmlist", "Updating realm \"{}\" at {}:{}.", name, externalAddressString, port); + TC_LOG_DEBUG("realmlist", "Updating realm \"{}\" at {}(port {}).", name, buildAddressesLogText(), port); } while (result->NextRow()); } @@ -322,12 +337,14 @@ uint32 RealmList::JoinRealm(uint32 realmAddress, uint32 build, ClientBuild::Vari if (realm->PopulationLevel == RealmPopulationState::Offline || realm->Build != build || accountSecurityLevel < realm->AllowedSecurityLevel) return ERROR_USER_SERVER_NOT_PERMITTED_ON_REALM; + boost::asio::ip::address addressForClient = realm->GetAddressForClient(clientAddress); + JSON::RealmList::RealmListServerIPAddresses serverAddresses; JSON::RealmList::RealmIPAddressFamily* addressFamily = serverAddresses.add_families(); - addressFamily->set_family(1); + addressFamily->set_family(addressForClient.is_v6() ? 2 : 1); JSON::RealmList::IPAddress* address = addressFamily->add_addresses(); - address->set_ip(realm->GetAddressForClient(clientAddress).to_string()); + address->set_ip(addressForClient.to_string()); address->set_port(realm->Port); std::string json = "JSONRealmListServerIPAddresses:" + JSON::Serialize(serverAddresses); diff --git a/src/server/shared/Realm/RealmList.h b/src/server/shared/Realm/RealmList.h index 4ece6124a51..ddb42ae7e1f 100644 --- a/src/server/shared/Realm/RealmList.h +++ b/src/server/shared/Realm/RealmList.h @@ -76,7 +76,7 @@ private: void UpdateRealms(); static void UpdateRealm(Realm& realm, Battlenet::RealmHandle const& id, uint32 build, std::string const& name, - boost::asio::ip::address&& address, boost::asio::ip::address&& localAddr, + std::vector<boost::asio::ip::address>&& addresses, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, RealmPopulationState population); void FillRealmEntry(Realm const& realm, uint32 clientBuild, AccountTypes accountSecurityLevel, JSON::RealmList::RealmEntry* realmEntry) const; diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index c45113097c2..46c3bf6bc7f 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -176,6 +176,7 @@ InstanceServerPort = 8086 # # BindIP # Description: Bind world server to IP/hostname. +# Using IPv6 address (such as "::") will enable both IPv4 and IPv6 connections # Default: "0.0.0.0" - (Bind to all IPs on the system) BindIP = "0.0.0.0" |