20#include <boost/asio/ip/network_v4.hpp>
21#include <boost/asio/ip/network_v6.hpp>
26std::vector<boost::asio::ip::network_v4> LocalV4Networks;
27std::vector<boost::asio::ip::network_v6> LocalV6Networks;
34 if (clientAddress.is_v4())
36 return std::any_of(LocalV4Networks.begin(), LocalV4Networks.end(), [clientAddressV4 = clientAddress.to_v4()](boost::asio::ip::network_v4
const& network)
38 return IsInNetwork(network, clientAddressV4);
42 if (clientAddress.is_v6())
44 return std::any_of(LocalV6Networks.begin(), LocalV6Networks.end(), [clientAddressV6 = clientAddress.to_v6()](boost::asio::ip::network_v6
const& network)
46 return IsInNetwork(network, clientAddressV6);
53bool IsInNetwork(boost::asio::ip::network_v4
const& network, boost::asio::ip::address_v4
const& clientAddress)
55 if (clientAddress == network.address())
58 boost::asio::ip::network_v4 endpointAsNetwork = boost::asio::ip::make_network_v4(clientAddress, 32);
59 return endpointAsNetwork.is_subnet_of(network);
62bool IsInNetwork(boost::asio::ip::network_v6
const& network, boost::asio::ip::address_v6
const& clientAddress)
64 if (clientAddress == network.address())
67 boost::asio::ip::network_v6 endpointAsNetwork = boost::asio::ip::make_network_v6(clientAddress, 128);
68 return endpointAsNetwork.is_subnet_of(network);
80 for (std::size_t i = 0; i < addresses.size(); ++i)
82 boost::asio::ip::address
const& address = addresses[i];
84 if (address.is_loopback())
86 if (address.is_v6() && !loopbackIpv6Index)
87 loopbackIpv6Index = i;
89 if (address.is_v4() && !loopbackIpv4Index)
90 loopbackIpv4Index = i;
94 if (address.is_v6() && !localIpv6Index)
97 if (address.is_v4() && !localIpv4Index)
102 if (address.is_v6() && !externalIpv6Index)
103 externalIpv6Index = i;
105 if (address.is_v4() && !externalIpv4Index)
106 externalIpv4Index = i;
115 if (clientAddress.is_v6() && localIpv6Index)
118 return localIpv6Index;
123 return localIpv4Index;
126 if (clientAddress.is_loopback())
129 if (clientAddress.is_v6() && loopbackIpv6Index)
130 return loopbackIpv6Index;
132 if (loopbackIpv4Index)
133 return loopbackIpv4Index;
137 if (clientAddress.is_v6() && externalIpv6Index)
138 return externalIpv6Index;
140 return externalIpv4Index;
144#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
146#include <boost/dll/shared_library.hpp>
151 LocalV4Networks.clear();
152 LocalV6Networks.clear();
154 boost::system::error_code dllError;
155 boost::dll::shared_library iphlp(
"Iphlpapi.dll", dllError, boost::dll::load_mode::search_system_folders);
156 if (dllError || !iphlp.is_loaded())
159 auto getAdaptersAddresses = iphlp.get<
decltype(GetAdaptersAddresses)>(
"GetAdaptersAddresses");
160 if (!getAdaptersAddresses)
163 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;
166 if (getAdaptersAddresses(AF_UNSPEC, queryFlags,
nullptr,
nullptr, &
bufferSize) != ERROR_BUFFER_OVERFLOW)
169 std::unique_ptr<std::byte[]> addressesBuffer = std::make_unique<std::byte[]>(
bufferSize);
170 if (getAdaptersAddresses(AF_UNSPEC, queryFlags,
nullptr,
reinterpret_cast<IP_ADAPTER_ADDRESSES*
>(addressesBuffer.get()), &
bufferSize) != ERROR_SUCCESS)
173 for (IP_ADAPTER_ADDRESSES* itr =
reinterpret_cast<IP_ADAPTER_ADDRESSES*
>(addressesBuffer.get()); itr; itr = itr->Next)
175 if (itr->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
178 if (itr->OperStatus != IfOperStatusUp)
181 for (IP_ADAPTER_PREFIX_XP* prefix = itr->FirstPrefix; prefix; prefix = prefix->Next)
183 switch (prefix->Address.lpSockaddr->sa_family)
187 SOCKADDR_IN* ipv4raw =
reinterpret_cast<SOCKADDR_IN*
>(prefix->Address.lpSockaddr);
188 boost::asio::ip::address_v4::bytes_type addressBytes;
189 std::memcpy(addressBytes.data(), &ipv4raw->sin_addr.s_addr, addressBytes.size());
190 boost::asio::ip::address_v4 address = make_address_v4(addressBytes);
191 if (address.is_unspecified() || address.is_multicast() || address == boost::asio::ip::address_v4::broadcast())
194 LocalV4Networks.push_back(boost::asio::ip::make_network_v4(address, prefix->PrefixLength));
199 SOCKADDR_IN6* ipv6raw =
reinterpret_cast<SOCKADDR_IN6*
>(prefix->Address.lpSockaddr);
200 boost::asio::ip::address_v6::bytes_type addressBytes;
201 std::memcpy(addressBytes.data(), ipv6raw->sin6_addr.s6_addr, addressBytes.size());
202 boost::asio::ip::address_v6 address = make_address_v6(addressBytes, ipv6raw->sin6_scope_id);
203 if (address.is_unspecified() || address.is_multicast())
206 LocalV6Networks.push_back(boost::asio::ip::make_network_v6(address, prefix->PrefixLength));
223 LocalV4Networks.clear();
224 LocalV6Networks.clear();
226 ifaddrs* addressesLinkedList =
nullptr;
227 if (getifaddrs(&addressesLinkedList) == -1)
230 for (ifaddrs* itr = addressesLinkedList; itr; itr = itr->ifa_next)
235 switch (itr->ifa_addr->sa_family)
239 sockaddr_in* ipv4raw =
reinterpret_cast<sockaddr_in*
>(itr->ifa_addr);
240 boost::asio::ip::address_v4::bytes_type addressBytes;
241 std::memcpy(addressBytes.data(), &ipv4raw->sin_addr.s_addr, addressBytes.size());
242 boost::asio::ip::address_v4 address = make_address_v4(addressBytes);
243 if (address.is_unspecified() || address.is_loopback() || address.is_multicast() || address == boost::asio::ip::address_v4::broadcast())
246 if (sockaddr_in* netmask4raw =
reinterpret_cast<sockaddr_in*
>(itr->ifa_netmask))
248 boost::asio::ip::address_v4::bytes_type netmaskBytes;
249 std::memcpy(netmaskBytes.data(), &netmask4raw->sin_addr.s_addr, netmaskBytes.size());
250 boost::asio::ip::address_v4 netmask = make_address_v4(netmaskBytes);
251 LocalV4Networks.push_back(boost::asio::ip::make_network_v4(address, netmask));
254 LocalV4Networks.push_back(boost::asio::ip::make_network_v4(address, 32));
259 sockaddr_in6* ipv6raw =
reinterpret_cast<sockaddr_in6*
>(itr->ifa_addr);
260 boost::asio::ip::address_v6::bytes_type addressBytes;
261 std::memcpy(addressBytes.data(), ipv6raw->sin6_addr.s6_addr, addressBytes.size());
262 boost::asio::ip::address_v6 address = make_address_v6(addressBytes, ipv6raw->sin6_scope_id);
263 if (address.is_unspecified() || address.is_loopback() || address.is_multicast())
266 if (sockaddr_in6* netmask6raw =
reinterpret_cast<sockaddr_in6*
>(itr->ifa_netmask))
268 int32 prefixLength = 0;
269 for (
uint8 addressByte : netmask6raw->sin6_addr.s6_addr)
270 prefixLength += std::countl_one(addressByte);
272 LocalV6Networks.push_back(boost::asio::ip::make_network_v6(address, prefixLength));
275 LocalV6Networks.push_back(boost::asio::ip::make_network_v6(address, 128));
281 freeifaddrs(addressesLinkedList);
std::optional< T > Optional
Optional helper class to wrap optional values within.
bool IsInNetwork(boost::asio::ip::network_v4 const &network, boost::asio::ip::address_v4 const &clientAddress)
bool IsInLocalNetwork(boost::asio::ip::address const &clientAddress)
Optional< std::size_t > SelectAddressForClient(boost::asio::ip::address const &clientAddress, std::span< boost::asio::ip::address const > const &addresses)
TC_COMMON_API void ScanLocalNetworks()