Detect configured protocols
To get information about supported IP versions by the network adapter, we need to go through assigned IP addresses and check their types.
In WinRT there is GetHostNames(), which gets a list of host names associated with the local machine. Then we only need to filter results by the current network adapter id.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
// the order is important, if we want to support bitwise OR: IPv4 | IPv6 equals IPv4and6 enum IpVersion { None, IPv4, IPv6, IPv4and6 } IpVersion GetConfiguredProtocols(ConnectionProfile profile) { var result = IpVersion.None; if (profile != null && profile.NetworkAdapter != null) { var hostnames = NetworkInformation.GetHostNames() .Where(h => h.IPInformation != null && h.IPInformation.NetworkAdapter != null && h.IPInformation.NetworkAdapter.NetworkAdapterId == profile.NetworkAdapter.NetworkAdapterId); foreach (var hostname in hostnames) { if (hostname.Type == HostNameType.Ipv4) { result |= IpVersion.IPv4; } else if (hostname.Type == HostNameType.Ipv6) { result |= IpVersion.IPv6; } } } return result; } // USAGE: GetConfiguredProtocols(NetworkInformation.GetInternetConnectionProfile()); |
What does the ‘internet connection’ mean?
In general it’s an ability to exchange data between devices in network using their IP addresses. However, many applications use domain names to connect to web services, APIs etc. In this case we need to be able to query DNS server to get an IP address. Without a connection with DNS server, you will usually see limited / limited access / no internet connection warning. Therefore in many cases the ability to resolve domain names is essential to assume that there is an internet connection.
Detect which IP version provides an internet connection
Let’s go back to the solution above – it doesn’t detect if there is set and working DNS server. It only returns protocols for which IP address has been set. So actually it doesn’t give you information if your application will be able to connect to for example ‘webapi.domain.com’ using the specific protocol.
What can we do to check internet connectivity for each IP version?
If we want to get a similar status like in the Wi-Fi Status window, we need to try to resolve some domain name. This trick is quite simple. First of all, it verifies connectivity using IP address, because we have to connect to DNS servers. Then if we get in response IPv6 address, it means the DNS server is set and working for that protocol.
Why not a simple PING?
Someone could come up with an idea to just ping IPv4 and IPv6 addresses of DNS servers to verify their connectivity.
However, it’s not possible to ping from WinRT application as it requires a raw socket, which needs administrative privileges and is not supported in WinRT. I’m not even sure if it is possible to get DNS IPs.
Solution
I used google.com to test connectivity as it’s one of the most reliable domains. The code below works only for WinRT applications. In WPF there is System.Net.Dns.Resolve to resolve domain names.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
// the order is important, if we want to support bitwise OR: IPv4 | IPv6 equals IPv4and6 public enum IpVersion { None, IPv4, IPv6, IPv4and6 } public async Task GetCurrentIpVersion() { try { // resolves domain name to IP addresses (may contain several) var endPointPairs = await DatagramSocket.GetEndpointPairsAsync(new HostName("google.com"), "0"); if (endPointPairs == null) { return IpVersion.None; } // detect which IP version is supported var result = IpVersion.None; foreach (var endPoint in endPointPairs) { if (endPoint.RemoteHostName != null) { if (endPoint.RemoteHostName.Type == HostNameType.Ipv4) { result |= IpVersion.IPv4; } else if (endPoint.RemoteHostName.Type == HostNameType.Ipv6) { result |= IpVersion.IPv6; } } } return result; } catch { return IpVersion.None; } } |
Detect network change
The last question is: when should we update IP connectivity? Fortunately there is NetworkStatusChanged event (Windows.Networking.Connectivity.NetworkInformation), which can be used for this purpose.
Although, it may not be enough, because this event is not triggered if you modify DNS server address. In this case, I think the only option would be to update connectivity every few seconds.
Share IPv6 network using OS X El Capitan
If you need to provide IPv6 support, but you don’t have an IPv6 network, then there is a solution for that using MacBook. OS X El Capitan provides a feature to share NAT64/DNS64 network, which translates IPv4 addresses to IPv6, so that you are able to communicate using IPv6.