| 318 | } |
| 319 | |
| 320 | std::vector<CNetAddr> GetLocalAddresses() |
| 321 | { |
| 322 | std::vector<CNetAddr> addresses; |
| 323 | #ifdef WIN32 |
| 324 | DWORD status = 0; |
| 325 | constexpr size_t MAX_ADAPTER_ADDR_SIZE = 4 * 1000 * 1000; // Absolute maximum size of adapter addresses structure we're willing to handle, as a precaution. |
| 326 | std::vector<std::byte> out_buf(15000, {}); // Start with 15KB allocation as recommended in GetAdaptersAddresses documentation. |
| 327 | while (true) { |
| 328 | ULONG out_buf_len = out_buf.size(); |
| 329 | status = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, |
| 330 | nullptr, reinterpret_cast<PIP_ADAPTER_ADDRESSES>(out_buf.data()), &out_buf_len); |
| 331 | if (status == ERROR_BUFFER_OVERFLOW && out_buf.size() < MAX_ADAPTER_ADDR_SIZE) { |
| 332 | // If status == ERROR_BUFFER_OVERFLOW, out_buf_len will contain the needed size. |
| 333 | // Unfortunately, this cannot be fully relied on, because another process may have added interfaces. |
| 334 | // So to avoid getting stuck due to a race condition, double the buffer size at least |
| 335 | // once before retrying (but only up to the maximum allowed size). |
| 336 | out_buf.resize(std::min(std::max<size_t>(out_buf_len, out_buf.size()) * 2, MAX_ADAPTER_ADDR_SIZE)); |
| 337 | } else { |
| 338 | break; |
| 339 | } |
| 340 | } |
| 341 | |
| 342 | if (status != NO_ERROR) { |
| 343 | // This includes ERROR_NO_DATA if there are no addresses and thus there's not even one PIP_ADAPTER_ADDRESSES |
| 344 | // record in the returned structure. |
| 345 | LogError("Could not get local adapter addresses: %s\n", NetworkErrorString(status)); |
| 346 | return addresses; |
| 347 | } |
| 348 | |
| 349 | // Iterate over network adapters. |
| 350 | for (PIP_ADAPTER_ADDRESSES cur_adapter = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(out_buf.data()); |
| 351 | cur_adapter != nullptr; cur_adapter = cur_adapter->Next) { |
| 352 | if (cur_adapter->OperStatus != IfOperStatusUp) continue; |
| 353 | if (cur_adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) continue; |
| 354 | |
| 355 | // Iterate over unicast addresses for adapter, the only address type we're interested in. |
| 356 | for (PIP_ADAPTER_UNICAST_ADDRESS cur_address = cur_adapter->FirstUnicastAddress; |
| 357 | cur_address != nullptr; cur_address = cur_address->Next) { |
| 358 | // "The IP address is a cluster address and should not be used by most applications." |
| 359 | if ((cur_address->Flags & IP_ADAPTER_ADDRESS_TRANSIENT) != 0) continue; |
| 360 | |
| 361 | if (std::optional<CNetAddr> addr = FromSockAddr(cur_address->Address.lpSockaddr, static_cast<socklen_t>(cur_address->Address.iSockaddrLength))) { |
| 362 | addresses.push_back(*addr); |
| 363 | } |
| 364 | } |
| 365 | } |
| 366 | #elif defined(HAVE_IFADDRS) |
| 367 | struct ifaddrs* myaddrs; |
| 368 | if (getifaddrs(&myaddrs) == 0) { |
| 369 | for (struct ifaddrs* ifa = myaddrs; ifa != nullptr; ifa = ifa->ifa_next) |
| 370 | { |
| 371 | if (ifa->ifa_addr == nullptr) continue; |
| 372 | if ((ifa->ifa_flags & IFF_UP) == 0) continue; |
| 373 | if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) continue; |
| 374 | |
| 375 | if (std::optional<CNetAddr> addr = FromSockAddr(ifa->ifa_addr, std::nullopt)) { |
| 376 | addresses.push_back(*addr); |
| 377 | } |
no test coverage detected