[PATCH 0/1] MR10432: netprofm: Check adapter addresses instead of gateway to guess ipv6 internet connectivity.
From: Paul Gofman <pgofman@codeweavers.com> --- dlls/netprofm/list.c | 51 ++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/dlls/netprofm/list.c b/dlls/netprofm/list.c index 2b156fc562c..073ffa3553a 100644 --- a/dlls/netprofm/list.c +++ b/dlls/netprofm/list.c @@ -1806,24 +1806,41 @@ static inline BOOL is_link_local( const SOCKADDR *addr ) return in->sin6_family == AF_INET6 && in->sin6_addr.u.Byte[0] == 0xfe && (in->sin6_addr.u.Byte[1] & 0xc0) == 0x80; } -static BOOL has_address( const IP_ADAPTER_ADDRESSES *aa, USHORT family ) +static void has_ipv6_address( const IP_ADAPTER_ADDRESSES *aa, BOOL *has_link_local, BOOL *has_global ) +{ + const IP_ADAPTER_UNICAST_ADDRESS *addr = aa->FirstUnicastAddress; + const struct in6_addr *sa6; + + *has_link_local = *has_global = FALSE; + for (addr = aa->FirstUnicastAddress; addr; addr = addr->Next) + { + if (addr->Address.lpSockaddr->sa_family != AF_INET6) continue; + sa6 = &((struct sockaddr_in6 *)addr->Address.lpSockaddr)->sin6_addr; + if (IN6_IS_ADDR_LINKLOCAL(sa6) || IN6_IS_ADDR_SITELOCAL(sa6)) + *has_link_local = TRUE; + else if (!IN6_IS_ADDR_UNSPECIFIED(sa6) && !IN6_IS_ADDR_MULTICAST(sa6) && !IN6_IS_ADDR_LOOPBACK(sa6)) + *has_global = TRUE; + } +} + +static BOOL has_ipv4_address( const IP_ADAPTER_ADDRESSES *aa ) { const IP_ADAPTER_UNICAST_ADDRESS *addr = aa->FirstUnicastAddress; while (addr) { - if (addr->Address.lpSockaddr->sa_family == family && !is_link_local( addr->Address.lpSockaddr )) + if (addr->Address.lpSockaddr->sa_family == AF_INET) return TRUE; addr = addr->Next; } return FALSE; } -static BOOL has_gateway_address( const IP_ADAPTER_ADDRESSES *aa, USHORT family ) +static BOOL has_ipv4_gateway_address( const IP_ADAPTER_ADDRESSES *aa ) { const IP_ADAPTER_GATEWAY_ADDRESS *addr = aa->FirstGatewayAddress; while (addr) { - if (addr->Address.lpSockaddr->sa_family == family && !is_link_local( addr->Address.lpSockaddr )) + if (addr->Address.lpSockaddr->sa_family == AF_INET) return TRUE; addr = addr->Next; } @@ -1832,6 +1849,7 @@ static BOOL has_gateway_address( const IP_ADAPTER_ADDRESSES *aa, USHORT family ) static void init_networks( struct list_manager *mgr ) { + BOOL has_link_local, has_global; IP_ADAPTER_ADDRESSES *buf, *aa; GUID id; @@ -1862,26 +1880,27 @@ static void init_networks( struct list_manager *mgr ) goto done; } - if (has_address( aa, AF_INET )) - { - network->connected_v4 = VARIANT_TRUE; - connection->connected_v4 = VARIANT_TRUE; - } - if (has_address( aa, AF_INET6 )) + has_ipv6_address( aa, &has_link_local, &has_global ); + if (has_link_local || has_global) { network->connected_v6 = VARIANT_TRUE; connection->connected_v6 = VARIANT_TRUE; } - if (has_gateway_address( aa, AF_INET )) - { - network->connected_to_internet_v4 = VARIANT_TRUE; - connection->connected_to_internet_v4 = VARIANT_TRUE; - } - if (has_gateway_address( aa, AF_INET6 )) + if (has_global) { network->connected_to_internet_v6 = VARIANT_TRUE; connection->connected_to_internet_v6 = VARIANT_TRUE; } + if (has_ipv4_address( aa )) + { + network->connected_v4 = VARIANT_TRUE; + connection->connected_v4 = VARIANT_TRUE; + } + if (has_ipv4_gateway_address( aa )) + { + network->connected_to_internet_v4 = VARIANT_TRUE; + connection->connected_to_internet_v4 = VARIANT_TRUE; + } network->mgr = &mgr->INetworkListManager_iface; INetworkListManager_AddRef( network->mgr ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10432
Currently gateway address list is used to find non-local ipv6 address to assume ipv6 global connectivity presence. However, those gateway addresses returned by GetAdaptersAddresses() both on Windows and Wine usually have gateway address as link local address Which reflects the actual state of things, inside the local network gateway may be addressed with link local address and I am not sure if that is even possible to address the gateway for packet forwarding using its global ipv6 address. It is route prefix which may be global. Global ipv6 address on local interface, however, can't be assigned arbitrary, that is a part of global routing system and typically assigned by the gateway (which in turn should either have it configured statically or receive the address range from the next router). So if there is no actual ipv6 connectivity the global address is not assigned in the typical configurations. Of course, special configurations are possible when global ipv6 address is configured on host statically, or that it is masqueraded and there is no global address at all, but we are choosing between some heuristics here and the current one just always doesn't report ipv6 internet connectivity for the typical configurations. The exact detection is probably only possible with probing connectivity using some public servers. Windows has netprofm service which reports actual connectivity state apparently based on MS servers availablility. Technically we could implement the same, e. g., somewhere in nsiproxy.sys, but we should not probably use MS or other corporate servers for this purpose, and it is unclear to me what server can we probe for actual detection. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10432#note_133392
participants (2)
-
Paul Gofman -
Paul Gofman (@gofman)