Introduction
Recently, I came across the need of detecting if my connection was behind a Captive Portal (Wi-Fi hot spot) (read this) or not. I looked on the internet and found interesting articles on how Mozilla approaches this issue; as well as Safari and other possible alternatives. But in the end, and that would be the approach explained in this article, I opted for the use of the Windows Network List Manager API Reference and looked at the NLM_INTERNET_CONNECTIVITY
flags here.
Background
MSDN exposes a handy API to query for Network Connectivity properties. Through the NLM_INTERNET_CONNECTIVITY
, a set of additional properties are exposed for IPV4 and IPV6 network protocols; such as NLM_INTERNET_CONNECTIVITY_WEBHIJACK
, which is the property we want to find to identify if our network connection is behind a Captive Portal.
Using the Code
The overall strategy here is to use the Network List Manager to enumerate the connections that are connected. And then, through the INetwork
interface query for IPropertyBag
looking for the NLM_INTERNET_CONNECTIVITY
flag desired. As the MSDN documentation proposed: “These connectivity flags can be retrieved by querying for the NA_InternetConnectivityV4
or NA_InternetConnectivityV6
properties using the IPropertyBag
interface for an INetwork
or INetworkConnection
interface.” I first tried INetworkConnection
interface to query for the IPropertyBag
but it kept failing when retrieving the flags. So I switched to INetwork
interface (rest of the code remains the same) and it just worked. I didn’t mind investigating why INetworkConnection
failed. However, I thought I should point this out if you run into something similar.
Finally, we look at network connectivity flags checking for the NLM_INTERNET_CONNECTIVITY_WEBHIJACK
flag to be set. If this is set for NLM_CONNECTIVITY_IPV6_INTERNET
or NLM_CONNECTIVITY_IPV4_INTERNET
, we are under a Captive Portal connection for IPV6 or IPV4 respectively.
Here is the chunk of code that would perform the logic above explained and set boolean variable if a captive portal was detected:
bool fCaptivePortalDetected = false;
if (SUCCEEDED(CoInitializeEx(NULL, COINIT_MULTITHREADED)))
{
INetworkListManager* pNetworkListManager;
if (SUCCEEDED(CoCreateInstance(CLSID_NetworkListManager, NULL,
CLSCTX_ALL, IID_INetworkListManager,
(LPVOID*)&pNetworkListManager)))
{
IEnumNetworks* pEnum;
if (SUCCEEDED(pNetworkListManager->GetNetworks
(NLM_ENUM_NETWORK_CONNECTED, &pEnum)) && pEnum != NULL)
{
INetwork *pINetwork;
HRESULT hr = pEnum->Next(1, &pINetwork, nullptr);
while (hr == S_OK)
{
if (pINetwork != NULL)
{
IPropertyBag *pNetworkPropertyBag;
HRESULT hrQueryInterface = pINetwork->QueryInterface
(IID_IPropertyBag, (LPVOID*)&pNetworkPropertyBag);
if (SUCCEEDED(hrQueryInterface 1) && pNetworkPropertyBag != nullptr)
{
NLM_CONNECTIVITY networkConnectivity;
VARIANT variantConnectivity;
if (SUCCEEDED(pINetwork->GetConnectivity(&networkConnectivity)))
{
if ((networkConnectivity &
NLM_CONNECTIVITY_IPV4_INTERNET) ==
NLM_CONNECTIVITY_IPV4_INTERNET)
{
VariantInit(&variantConnectivity);
if (SUCCEEDED(pNetworkPropertyBag->Read
(NA_InternetConnectivityV4,
&variantConnectivity, nullptr))
&& (V_UINT(&variantConnectivity) &
NLM_INTERNET_CONNECTIVITY_WEBHIJACK) ==
NLM_INTERNET_CONNECTIVITY_WEBHIJACK)
{
fCaptivePortalDetected = true;
}
auto t = V_UINT(&variantConnectivity);
VariantClear(&variantConnectivity);
}
if (!fCaptivePortalDetected && (networkConnectivity
& NLM_CONNECTIVITY_IPV6_INTERNET) ==
NLM_CONNECTIVITY_IPV6_INTERNET)
{
VariantInit(&variantConnectivity);
if (SUCCEEDED(pNetworkPropertyBag->Read
(NA_InternetConnectivityV6,
&variantConnectivity, nullptr)) &&
(V_UINT(&variantConnectivity) &
NLM_INTERNET_CONNECTIVITY_WEBHIJACK) ==
NLM_INTERNET_CONNECTIVITY_WEBHIJACK)
{
fCaptivePortalDetected = true;
}
VariantClear(&variantConnectivity);
}
}
}
pINetwork->Release();
}
if (fCaptivePortalDetected)
break;
hr = hr = pEnum->Next(1, &pINetwork, nullptr);
}
}
}
}
CoUninitialize();
References and Important Links
I would like to say that since this article uses Windows functions, MSDN library is your best friend and the first source of information you should check. But also, these are the two main articles that helped me in understanding the APIs:
History
- 27th March, 2016: Initial version