| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ssl/captive_portal_helper.h" |
| |
| #include <netlistmgr.h> |
| #include <wrl/client.h> |
| |
| #include "base/win/scoped_variant.h" |
| |
| namespace { |
| |
| bool IsNetworkBehindCaptivePortal(INetwork* network) { |
| NLM_CONNECTIVITY connectivity; |
| if (FAILED(network->GetConnectivity(&connectivity))) |
| return false; |
| |
| if (connectivity == NLM_CONNECTIVITY_DISCONNECTED) |
| return false; |
| |
| Microsoft::WRL::ComPtr<IPropertyBag> property_bag; |
| if (FAILED(network->QueryInterface(property_bag.GetAddressOf())) || |
| !property_bag) { |
| return false; |
| } |
| |
| base::win::ScopedVariant connectivity_variant; |
| |
| if ((connectivity & NLM_CONNECTIVITY_IPV4_SUBNET) || |
| (connectivity & NLM_CONNECTIVITY_IPV4_LOCALNETWORK) || |
| (connectivity & NLM_CONNECTIVITY_IPV4_INTERNET)) { |
| // IPV4 connection: |
| if (SUCCEEDED(property_bag->Read(NA_InternetConnectivityV4, |
| connectivity_variant.Receive(), |
| nullptr)) && |
| (V_UINT(connectivity_variant.ptr()) & |
| NLM_INTERNET_CONNECTIVITY_WEBHIJACK) == |
| NLM_INTERNET_CONNECTIVITY_WEBHIJACK) { |
| return true; |
| } |
| } else if ((connectivity & NLM_CONNECTIVITY_IPV6_SUBNET) || |
| (connectivity & NLM_CONNECTIVITY_IPV6_LOCALNETWORK) || |
| (connectivity & NLM_CONNECTIVITY_IPV6_INTERNET)) { |
| // IPV6 connection: |
| if (SUCCEEDED(property_bag->Read(NA_InternetConnectivityV6, |
| connectivity_variant.Receive(), |
| nullptr)) && |
| (V_UINT(connectivity_variant.ptr()) & |
| NLM_INTERNET_CONNECTIVITY_WEBHIJACK) == |
| NLM_INTERNET_CONNECTIVITY_WEBHIJACK) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| } // namespace |
| |
| namespace chrome { |
| |
| bool IsBehindCaptivePortal() { |
| // Assume the device is behind a captive portal if there is at least one |
| // connected network and all connected networks are behind captive portals. |
| Microsoft::WRL::ComPtr<INetworkListManager> network_list_manager; |
| if (FAILED(CoCreateInstance(CLSID_NetworkListManager, nullptr, |
| CLSCTX_INPROC_SERVER, |
| IID_PPV_ARGS(&network_list_manager)))) { |
| return false; |
| } |
| |
| Microsoft::WRL::ComPtr<IEnumNetworks> enum_networks; |
| if (FAILED(network_list_manager->GetNetworks(NLM_ENUM_NETWORK_CONNECTED, |
| enum_networks.GetAddressOf()))) { |
| return false; |
| } |
| |
| if (!enum_networks) |
| return false; |
| |
| bool found = false; |
| while (true) { |
| Microsoft::WRL::ComPtr<INetwork> network; |
| ULONG items_returned = 0; |
| // Note: MSDN documentation at |
| // https://msdn.microsoft.com/en-us/library/windows/desktop/aa370740(v=vs.85).aspx |
| // says items_returned is set to NULL if the first parameter is 1, but this |
| // seems incorrect. In this call, items_returned is 1 until there are no |
| // networks. Then it becomes zero. |
| if (FAILED(enum_networks->Next(1, network.GetAddressOf(), &items_returned))) |
| return false; |
| |
| if (items_returned == 0) |
| break; |
| |
| if (!IsNetworkBehindCaptivePortal(network.Get())) |
| return false; |
| |
| found = true; |
| } |
| return found; |
| } |
| |
| } // namespace chrome |