3131
3232namespace {
3333
34+ // ! Return CNetAddr for the specified OS-level network address.
35+ // ! If a length is not given, it is taken to be sizeof(struct sockaddr_*) for the family.
36+ std::optional<CNetAddr> FromSockAddr (const struct sockaddr * addr, std::optional<socklen_t > sa_len_opt)
37+ {
38+ socklen_t sa_len = 0 ;
39+ if (sa_len_opt.has_value ()) {
40+ sa_len = *sa_len_opt;
41+ } else {
42+ // If sockaddr length was not specified, determine it from the family.
43+ switch (addr->sa_family ) {
44+ case AF_INET: sa_len = sizeof (struct sockaddr_in ); break ;
45+ case AF_INET6: sa_len = sizeof (struct sockaddr_in6 ); break ;
46+ default :
47+ return std::nullopt ;
48+ }
49+ }
50+ // Fill in a CService from the sockaddr, then drop the port part.
51+ CService service;
52+ if (service.SetSockAddr (addr, sa_len)) {
53+ return (CNetAddr)service;
54+ }
55+ return std::nullopt ;
56+ }
57+
3458// Linux and FreeBSD 14.0+. For FreeBSD 13.2 the code can be compiled but
3559// running it requires loading a special kernel module, otherwise socket(AF_NETLINK,...)
3660// will fail, so we skip that.
@@ -167,16 +191,6 @@ std::optional<CNetAddr> QueryDefaultGatewayImpl(sa_family_t family)
167191#define ROUNDUP32 (a ) \
168192 ((a) > 0 ? (1 + (((a) - 1 ) | (sizeof (uint32_t ) - 1 ))) : sizeof (uint32_t ))
169193
170- std::optional<CNetAddr> FromSockAddr (const struct sockaddr * addr)
171- {
172- // Fill in a CService from the sockaddr, then drop the port part.
173- CService service;
174- if (service.SetSockAddr (addr, addr->sa_len )) {
175- return (CNetAddr)service;
176- }
177- return std::nullopt ;
178- }
179-
180194// ! MacOS: Get default gateway from route table. See route(4) for the format.
181195std::optional<CNetAddr> QueryDefaultGatewayImpl (sa_family_t family)
182196{
@@ -210,9 +224,9 @@ std::optional<CNetAddr> QueryDefaultGatewayImpl(sa_family_t family)
210224 const struct sockaddr * sa = (const struct sockaddr *)(buf.data () + sa_pos);
211225 if ((sa_pos + sa->sa_len ) > next_msg_pos) return std::nullopt ;
212226 if (i == RTAX_DST) {
213- dst = FromSockAddr (sa);
227+ dst = FromSockAddr (sa, sa-> sa_len );
214228 } else if (i == RTAX_GATEWAY) {
215- gateway = FromSockAddr (sa);
229+ gateway = FromSockAddr (sa, sa-> sa_len );
216230 }
217231 // Skip sockaddr entries for bit flags we're not interested in,
218232 // move cursor.
@@ -269,9 +283,47 @@ std::vector<CNetAddr> GetLocalAddresses()
269283{
270284 std::vector<CNetAddr> addresses;
271285#ifdef WIN32
272- char pszHostName[256 ] = " " ;
273- if (gethostname (pszHostName, sizeof (pszHostName)) != SOCKET_ERROR) {
274- addresses = LookupHost (pszHostName, 0 , true );
286+ DWORD status = 0 ;
287+ 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.
288+ std::vector<std::byte> out_buf (15000 , {}); // Start with 15KB allocation as recommended in GetAdaptersAddresses documentation.
289+ while (true ) {
290+ ULONG out_buf_len = out_buf.size ();
291+ status = GetAdaptersAddresses (AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME,
292+ nullptr , reinterpret_cast <PIP_ADAPTER_ADDRESSES>(out_buf.data ()), &out_buf_len);
293+ if (status == ERROR_BUFFER_OVERFLOW && out_buf.size () < MAX_ADAPTER_ADDR_SIZE) {
294+ // If status == ERROR_BUFFER_OVERFLOW, out_buf_len will contain the needed size.
295+ // Unfortunately, this cannot be fully relied on, because another process may have added interfaces.
296+ // So to avoid getting stuck due to a race condition, double the buffer size at least
297+ // once before retrying (but only up to the maximum allowed size).
298+ out_buf.resize (std::min (std::max<size_t >(out_buf_len, out_buf.size ()) * 2 , MAX_ADAPTER_ADDR_SIZE));
299+ } else {
300+ break ;
301+ }
302+ }
303+
304+ if (status != NO_ERROR) {
305+ // This includes ERROR_NO_DATA if there are no addresses and thus there's not even one PIP_ADAPTER_ADDRESSES
306+ // record in the returned structure.
307+ LogPrintLevel (BCLog::NET, BCLog::Level::Error, " Could not get local adapter addreses: %s\n " , NetworkErrorString (status));
308+ return addresses;
309+ }
310+
311+ // Iterate over network adapters.
312+ for (PIP_ADAPTER_ADDRESSES cur_adapter = reinterpret_cast <PIP_ADAPTER_ADDRESSES>(out_buf.data ());
313+ cur_adapter != nullptr ; cur_adapter = cur_adapter->Next ) {
314+ if (cur_adapter->OperStatus != IfOperStatusUp) continue ;
315+ if (cur_adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) continue ;
316+
317+ // Iterate over unicast addresses for adapter, the only address type we're interested in.
318+ for (PIP_ADAPTER_UNICAST_ADDRESS cur_address = cur_adapter->FirstUnicastAddress ;
319+ cur_address != nullptr ; cur_address = cur_address->Next ) {
320+ // "The IP address is a cluster address and should not be used by most applications."
321+ if ((cur_address->Flags & IP_ADAPTER_ADDRESS_TRANSIENT) != 0 ) continue ;
322+
323+ if (std::optional<CNetAddr> addr = FromSockAddr (cur_address->Address .lpSockaddr , static_cast <socklen_t >(cur_address->Address .iSockaddrLength ))) {
324+ addresses.push_back (*addr);
325+ }
326+ }
275327 }
276328#elif (HAVE_DECL_GETIFADDRS && HAVE_DECL_FREEIFADDRS)
277329 struct ifaddrs * myaddrs;
@@ -281,12 +333,9 @@ std::vector<CNetAddr> GetLocalAddresses()
281333 if (ifa->ifa_addr == nullptr ) continue ;
282334 if ((ifa->ifa_flags & IFF_UP) == 0 ) continue ;
283335 if ((ifa->ifa_flags & IFF_LOOPBACK) != 0 ) continue ;
284- if (ifa->ifa_addr ->sa_family == AF_INET) {
285- struct sockaddr_in * s4 = (struct sockaddr_in *)(ifa->ifa_addr );
286- addresses.emplace_back (s4->sin_addr );
287- } else if (ifa->ifa_addr ->sa_family == AF_INET6) {
288- struct sockaddr_in6 * s6 = (struct sockaddr_in6 *)(ifa->ifa_addr );
289- addresses.emplace_back (s6->sin6_addr );
336+
337+ if (std::optional<CNetAddr> addr = FromSockAddr (ifa->ifa_addr , std::nullopt )) {
338+ addresses.push_back (*addr);
290339 }
291340 }
292341 freeifaddrs (myaddrs);
0 commit comments