How can I ask the networking stack whether the system has obtained network connectivity?

Raymond Chen

Raymond

Recall a while back we had a customer who had assumed that the Get­Ip­Addr­Table function returned the IP addresses sorted by scope rather than by IP address. Digging into the customer’s actual problem revealed that what they really wanted to know was when the system had obtained network connectivity.

Their original plan was to poll on Get­Ip­Addr­Table expecting their public IP address to show up first, but we learned that that technique was flawed. So what can they do? They wondered if maybe there was a specific service whose startup demonstrated that the system had an IP address.

Network connectivity is more fickle than just checking for a service. It can come and go dynamically. You wander in and out of range of a Wi-Fi base station. You plug in or remove the USB networking adapter. The cleaning crew temporarily—or perhaps permanently—unplugs the Ethernet cable because it prevents them from vacuuming the floor.

The networking folks had a few suggestions. One was to use INetwork­List­Manager::get_Is­Connected, which tells you if the system has any network connectivity at all. This will tell you whether the system is connected to the local network, if that’s what you care about.

If you are looking for internet connectivity, then you can use INetwork­List­Manager::get_Is­Connected­To­Internet.

The methods on INetwork­List­Manager aggregates network connectivity across multiple interfaces, saving you the trouble of having to deal with the messy details of the networking stack.

If you prefer to get your hands dirty, you can use the Notify­Unicast­Ip­Address­Change function which lets you register a callback that will be invoked whenever a change occurs to the IP address of the system (optionally filtered to only IPv4 or IPv6).

This function is a little tricky because your callback doesn’t actually get the address information. Instead, it contains only enough information for you to call Get­Unicast­Ip­Address­Entry to obtain more information about the new address. In particular, you want to see if the IP address meets your criteria (routability being one thing you probably want) and that the Duplicate Address Detection (DAD) state is Preferred, indicating that this is the preferred IP address.

Another high-level interface is the network connection profile in the Windows Runtime.

using Windows.Networking.Connectivity;

var level = NetworkConnectivityLevel.None;
var profile = NetworkInformation.GetInternetConnectionProfile();
if (profile != null) {
  level = profile.GetNetworkConnectivityLevel();
}

The Get­Internet­Connection­Profile method gives you a Connection­Profile object which describes the system’s internet connection. This also tries to distinguish between normal internet connectivity and being trapped in a captive portal. You can subscribe to the Network­Status­Changed event to be notified when the connectivity level changes. (The Windows Runtime class also gives you other information, such as whether you are on a metered network.)

You can see from the extra features in the Windows Runtime class that it is more focused on app scenarios (particularly mobile networking) than on understanding the low-level details of the networking stack. This particular customer was writing software that ran in a server room, so they didn’t need to worry about things like metered networks or captive portals.

Or at least I hope they didn’t!

19 comments

Comments are closed. Login to edit/delete your existing comments

  • Avatar
    Joshua Hudson

    Back in the pre-IPv6 days I would connect a UDP socket to 1.0.0.0 and ask what IP address was on. 1.0.0.0 was reserved-unsssignable then.

    I suspect a similar technique works today, but multiple IPv4 and v6 addresses have to be tried. It’s longer code but it’s portable.

  • Avatar
    ChDF T

    I would like to add, that while the presented APIs try their best to guess the devices/users connectivity, they still just guess: The user might be connected to some badly configured VPN or the network administrator might have setup an aggressive packet filter at the edge.
    This means that your application still has to be able to deal with connectivity issues, even when the presented APIs say “connection seems fine”. Additionally these APIs might get tripped up by some unusual configuration and report “no internet connection” even though your application would be able to communicate with whatever it wants to communicate with.

    So please use the presented APIs (and whatever smart smart hacks you come up with) to show the user more helpful error messages, but don’t disable features that require a connection to a specific server without actually checking whether the specific server can be reached.

    • Avatar
      Alex Martin

      Yes. I’ve noticed a trend recently of programs refusing to work because the system says “Internet disconnected” even though the connection is actually fine, and the system’s connection checking function is just malfunctioning. Frequently I can ping DNS servers and get to things through a Web browser, but some applications will just refuse to work until Windows realizes that the network is working.

      • Avatar
        Alex Martin

        It comes down to a principle that has been a theme on this blog in the past sometimes: Checking to see if something is going to succeed usually doesn’t work. Just try to do it and deal with the failure if it fails.

      • Avatar
        Mike Swaim

        I’ve noticed the same thing. Skype and (most) command line tools think that I’m connected. The Network connection icon, our VPN software and most browsers think that I’m not. Doing a release and renew will sometimes convince Windows that I have a connection. Other times, after a while it heals itself. It’s frustrating.

        • Simon Geard
          Simon Geard

          Also useful is that http://example.org/ works over HTTP — not HTTPS — which makes it a bit more resilient to captive portals… HTTPS sites will (quite reasonably) give certificate errors in that situation, but being inherently insecure and unconcerned about MitM attacks, an HTTP site will happily redirect to the portal.

          This used to be extremely useful on my old phone. The current one deals with portals automatically as part of establishing the connection, but the old one wasn’t so clever and required a manual sign-in… something that became increasingly difficult as more and more sites started enforcing HTTPS. Solution… keeping http://example.org/ open in a tab, and refreshing after connecting to WiFi.

  • Avatar
    Fleet Command

    I must say, Mr. Chen, your 2020 blog posts are as valuable as gold.

    I think I’ll have to go find that article that says how to use Windows Runtime API in .NET apps, although WebClient has so far done a good job of telling me when there is network connectivity. In PowerShell, I even have more options.

  • Avatar
    Almighty Toomre

    My very first public presentation at Microsoft was on this very topic (and it’s still relevant!): Offline Network Detection in Microsoft Silverlight 3. The TL/DR: just like ChDF T says, just try to connect, and then handle the failure.

    These days, with so many VPNs and so much security software in use, it’s even harder to tell if you are truly online. You might be connected to a corporate network that lets you see some, but not all, of the internet; you might have internet for some protocols (HTTP) but not others (IPsec); you might have some DNS queries filtered and not others. And, of course, some countries have filters to prevent certain sites from being accessed.

    • Raymond Chen
      Raymond ChenMicrosoft employee

      This question is not coming from an application author. It’s coming from a service provider. They want to know when to open a port and start listening for inbound requests. Doing so on a system with no network connectivity will succeed, but nobody will connect.

      • Avatar
        cheong00

        In that case the most reliable way to detect is to implement something like the Certbot of “Let’s Encrypt” – try to connect to external web service (possibly hosted by themselves) that will try to connect back when received request on start. If they receive incoming request, the service is online.

        Note: If you register your e-cert with Certbot and configured automatic renewal, when your cert is due to renew, the bot will contact the server where it’ll try to connect your port 80 in attempt to retrieve a predefined answer file to prove your server is still at that domain, and proceed to renew if success.

      • Avatar
        Neil Rashbrook

        I don’t quite see why you have to wait for network connectivity before you start listening. Why wouldn’t people be able to connect once network connectivity has been established?

  • Travis Hayes
    Travis Hayes
    One was to use INetwork­List­Manager::get_Is­Connected, which tells you if the system has any network connectivity at all.

    But therein lies the rub (and the heart of the question…); what does “any network connectivity at all” mean? Network card is present and connected to a switch/router/basestation? Has a layer 2 link? Has an IP address? Has a valid gateway? Sees any Ethernet frames at all? Valid DNS server? Can ping microsoft.com?