diff --git a/src/enum_net.cpp b/src/enum_net.cpp index fe9d99192..72e7481e9 100644 --- a/src/enum_net.cpp +++ b/src/enum_net.cpp @@ -699,10 +699,30 @@ int _System __libsocket_sysctl(int* mib, u_int namelen, void *oldp, size_t *oldl for (IP_ADAPTER_UNICAST_ADDRESS* unicast = adapter->FirstUnicastAddress; unicast; unicast = unicast->Next) { - if (!valid_addr_family(unicast->Address.lpSockaddr->sa_family)) + auto const family = unicast->Address.lpSockaddr->sa_family; + if (!valid_addr_family(family)) continue; r.preferred = unicast->DadState == IpDadStatePreferred; r.interface_address = sockaddr_to_address(unicast->Address.lpSockaddr); + // OnLinkPrefixLength is only present on Vista and newer + int const max_prefix_len = family == AF_INET ? 32 : 128; + if (unicast->Length >= 64 && unicast->OnLinkPrefixLength <= max_prefix_len) + { + r.netmask = build_netmask(unicast->OnLinkPrefixLength, family); + } + + if (family == AF_INET6 && (unicast->PrefixOrigin == IpPrefixOriginDhcp + || unicast->SuffixOrigin == IpSuffixOriginRandom)) + { + // DHCPv6 does not specify a subnet mask (it should be taken from the RA) + // but apparently MS didn't get the memo and incorrectly reports a + // prefix length of 128 for DHCPv6 assigned addresses + // 128 is also reported for privacy addresses despite claiming to + // have gotten the prifix length from the RA *shrug* + // use a 64 bit prefix in these cases since that is likely to be + // the correct value, or at least less wrong than 128 + r.netmask = build_netmask(64, family); + } ret.push_back(r); } }