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 /src/server/shared | |
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
Diffstat (limited to 'src/server/shared')
-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 |
4 files changed, 53 insertions, 30 deletions
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; |