66#include < iterator>
77#include < limits>
88#include < bitset>
9+ #include < unordered_map>
910#if BOOST_OS_LINUX
1011#include < system_error> // For std::error_code.
1112#include < cstring> // For calls in GetIpAddressAndNetmask
3334
3435namespace core_lib
3536{
37+ namespace net_utils
38+ {
3639
3740#if defined(IS_CPP17)
3841ip_octets_t OctetsFromIpAddress (std::string_view ipAddress)
@@ -210,6 +213,22 @@ int32_t SubnetMaskToCidrPrefix(std::string const& subnetMask)
210213 return static_cast <int32_t >(maskBits.count ());
211214}
212215
216+ uint32_t PrefixToMaskNetworkOrder (uint8_t prefixLength)
217+ {
218+ if (prefixLength == 0 )
219+ {
220+ return 0 ;
221+ }
222+
223+ if (prefixLength >= 32 )
224+ {
225+ return 0xFFFFFFFFu ;
226+ }
227+
228+ return htonl (0xFFFFFFFFu << (32 - prefixLength));
229+ }
230+
231+
213232#if defined(IS_CPP17)
214233std::string MakeCidrAddress (std::string_view address, std::string_view subnetMask)
215234#else
@@ -277,8 +296,8 @@ bool IsAddressAndNetmaskOnSameSubnetAsAdapter(std::string const& ipAddress,
277296 try
278297 {
279298 auto tempNetMask = netmask.empty () ? adapterNetmask : netmask;
280- auto broadcastAddress1 = core_lib:: BuildBroadcastAddress (ipAddress, tempNetMask);
281- auto broadcastAddress2 = core_lib:: BuildBroadcastAddress (adapterAddress, adapterNetmask);
299+ auto broadcastAddress1 = BuildBroadcastAddress (ipAddress, tempNetMask);
300+ auto broadcastAddress2 = BuildBroadcastAddress (adapterAddress, adapterNetmask);
282301
283302 return broadcastAddress1 == broadcastAddress2;
284303 }
@@ -290,9 +309,9 @@ bool IsAddressAndNetmaskOnSameSubnetAsAdapter(std::string const& ipAddress,
290309}
291310
292311#if defined(IS_CPP17)
293- std::pair<std::string, std::string> GetIpAddressAndNetmask (std::string_view adapterName);
312+ std::pair<std::string, std::string> GetIpAddressAndNetmask (std::string_view adapterName)
294313#else
295- std::pair<std::string, std::string> GetIpAddressAndNetmask (std::string const & adapterName);
314+ std::pair<std::string, std::string> GetIpAddressAndNetmask (std::string const & adapterName)
296315#endif
297316#if BOOST_OS_LINUX
298317{
@@ -417,4 +436,254 @@ std::pair<std::string, std::string> GetIpAddressAndNetmask(std::string const& ad
417436}
418437#endif
419438
439+ bool IsBadIPv4HostOrder (uint32_t hostIp)
440+ {
441+ if (hostIp == 0 )
442+ return true ;
443+
444+ if ((hostIp & 0xFF000000u ) == 0x7F000000u )
445+ {
446+ return true ;
447+ }
448+
449+ if ((hostIp & 0xFFFF0000u ) == 0xA9FE0000u )
450+ {
451+ return true ;
452+ }
453+
454+ return false ;
455+ }
456+
457+ std::string IPv4ToString (const in_addr& address)
458+ {
459+ char buffer[INET_ADDRSTRLEN]{};
460+
461+ if (!inet_ntop (AF_INET, &address, buffer, sizeof (buffer)))
462+ {
463+ return {};
464+ }
465+
466+ return buffer;
467+ }
468+
469+ #if BOOST_OS_LINUX
470+ bool IsInterfaceUp (const ifaddrs* iface)
471+ {
472+ return iface && (iface->ifa_flags & IFF_UP);
473+ }
474+
475+ bool SupportsBroadcast (const ifaddrs* iface)
476+ {
477+ return iface && (iface->ifa_flags & IFF_BROADCAST);
478+ }
479+
480+ bool SupportsMulticast (const ifaddrs* iface)
481+ {
482+ return iface && (iface->ifa_flags & IFF_MULTICAST);
483+ }
484+
485+ std::vector<IPv4Adapter> GetIPv4Adapters (eInterfaceFilter filter = eInterfaceFilter::All)
486+ {
487+ std::vector<IPv4Adapter> adapters;
488+ std::unordered_map<std::string, size_t > adapterIndex;
489+
490+ ifaddrs* interfaceList = nullptr ;
491+
492+ if (getifaddrs (&interfaceList) != 0 || !interfaceList)
493+ {
494+ return adapters;
495+ }
496+
497+ for (auto * iface = interfaceList; iface; iface = iface->ifa_next )
498+ {
499+ if (!iface->ifa_name )
500+ {
501+ continue ;
502+ }
503+
504+ if (!iface->ifa_addr || !iface->ifa_netmask )
505+ {
506+ continue ;
507+ }
508+
509+ if (iface->ifa_addr ->sa_family != AF_INET)
510+ {
511+ continue ;
512+ }
513+
514+ if (filter == eInterfaceFilter::RealOnly && !IsInterfaceUp (iface))
515+ {
516+ continue ;
517+ }
518+
519+ auto * address = reinterpret_cast <sockaddr_in*>(iface->ifa_addr );
520+ auto * mask = reinterpret_cast <sockaddr_in*>(iface->ifa_netmask );
521+
522+ uint32_t hostIp = ntohl (address->sin_addr .s_addr );
523+
524+ if (filter == eInterfaceFilter::RealOnly && IsBadIPv4HostOrder (hostIp))
525+ {
526+ continue ;
527+ }
528+
529+ std::string ipString = IPv4ToString (address->sin_addr );
530+ std::string maskString = IPv4ToString (mask->sin_addr );
531+
532+ if (ipString.empty () || maskString.empty ())
533+ {
534+ continue ;
535+ }
536+
537+ std::string adapterName = iface->ifa_name ;
538+ size_t index;
539+
540+ auto it = adapterIndex.find (adapterName);
541+
542+ if (it == adapterIndex.end ())
543+ {
544+ index = adapters.size ();
545+ adapterIndex.emplace (adapterName, index);
546+
547+ IPv4Adapter record;
548+ record.name = adapterName;
549+ record.supportsBroadcast = SupportsBroadcast (iface);
550+ record.supportsMulticast = SupportsMulticast (iface);
551+
552+ adapters.push_back (std::move (record));
553+ }
554+ else
555+ {
556+ index = it->second ;
557+
558+ adapters[index].supportsBroadcast =
559+ adapters[index].supportsBroadcast || SupportsBroadcast (iface);
560+
561+ adapters[index].supportsMulticast =
562+ adapters[index].supportsMulticast || SupportsMulticast (iface);
563+ }
564+
565+ adapters[index].addresses .push_back ({ipString, maskString});
566+ }
567+
568+ freeifaddrs (interfaceList);
569+
570+ adapters.erase (
571+ std::remove_if (
572+ adapters.begin (),
573+ adapters.end (),
574+ [](const IPv4Adapter& adapter)
575+ {
576+ return adapter.addresses .empty ();
577+ }),
578+ adapters.end ());
579+
580+ return adapters;
581+ }
582+ #else
583+ bool IsAdapterUp (const IP_ADAPTER_ADDRESSES* adapter)
584+ {
585+ return adapter && adapter->OperStatus == IfOperStatusUp;
586+ }
587+
588+ inline bool SupportsMulticast (const IP_ADAPTER_ADDRESSES* adapter)
589+ {
590+ return adapter && ((adapter->Flags & IP_ADAPTER_NO_MULTICAST) == 0 );
591+ }
592+
593+ std::vector<IPv4Adapter> GetIPv4Adapters (eInterfaceFilter filter)
594+ {
595+ std::vector<IPv4Adapter> adapters;
596+
597+ ULONG bufferSize = 0 ;
598+
599+ GetAdaptersAddresses (AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr , nullptr , &bufferSize);
600+
601+ if (bufferSize == 0 )
602+ {
603+ return adapters;
604+ }
605+
606+ std::vector<unsigned char > buffer (bufferSize);
607+
608+ auto * adapterList = reinterpret_cast <IP_ADAPTER_ADDRESSES*>(buffer.data ());
609+
610+ if (GetAdaptersAddresses (AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr , adapterList, &bufferSize) != NO_ERROR)
611+ {
612+ return adapters;
613+ }
614+
615+ for (auto * adapter = adapterList; adapter; adapter = adapter->Next )
616+ {
617+ if ((filter == eInterfaceFilter::RealOnly) && !IsAdapterUp (adapter))
618+ {
619+ continue ;
620+ }
621+
622+ IPv4Adapter record;
623+
624+ record.name = string_utils::WStringToString (adapter->FriendlyName );
625+
626+ if (record.name .empty ())
627+ {
628+ continue ;
629+ }
630+
631+ record.supportsMulticast = SupportsMulticast (adapter);
632+
633+ for (auto * address = adapter->FirstUnicastAddress ; address; address = address->Next )
634+ {
635+ auto * socketAddress = address->Address .lpSockaddr ;
636+
637+ if (!socketAddress || (socketAddress->sa_family != AF_INET))
638+ {
639+ continue ;
640+ }
641+
642+ auto * ipv4 = reinterpret_cast <sockaddr_in*>(socketAddress);
643+
644+ uint32_t hostIp = ntohl (ipv4->sin_addr .s_addr );
645+
646+ if ((filter == eInterfaceFilter::RealOnly) && IsBadIPv4HostOrder (hostIp))
647+ {
648+ continue ;
649+ }
650+
651+ std::string ipString = IPv4ToString (ipv4->sin_addr );
652+
653+ if (ipString.empty ())
654+ {
655+ continue ;
656+ }
657+
658+ uint32_t maskNetwork = PrefixToMaskNetworkOrder (address->OnLinkPrefixLength );
659+
660+ in_addr maskAddr{};
661+ maskAddr.s_addr = maskNetwork;
662+
663+ std::string maskString = IPv4ToString (maskAddr);
664+
665+ if (maskString.empty ())
666+ {
667+ continue ;
668+ }
669+
670+ record.addresses .push_back ({ipString, maskString});
671+ }
672+
673+ if (record.addresses .empty ())
674+ {
675+ continue ;
676+ }
677+
678+ // Broadcast policy — matches your KM loopback usage
679+ record.supportsBroadcast = true ;
680+
681+ adapters.emplace_back (std::move (record));
682+ }
683+
684+ return adapters;
685+ }
686+ #endif // #if BOOST_OS_LINUX
687+
688+ } // namespace net_utils
420689} // namespace core_lib
0 commit comments