Bug 1460537 - Connectivity Service - Add DNSv4 and DNSv6 checks r=dragana

Differential Revision: https://phabricator.services.mozilla.com/D7844

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Valentin Gosu 2018-10-29 11:22:40 +00:00
Родитель ec3d261a04
Коммит 3753105b42
11 изменённых файлов: 324 добавлений и 0 удалений

Просмотреть файл

@ -5433,6 +5433,10 @@ pref("network.captive-portal-service.maxInterval", 1500000); // 25 minutes
pref("network.captive-portal-service.backoffFactor", "5.0");
pref("network.captive-portal-service.enabled", false);
pref("network.connectivity-service.enabled", true);
pref("network.connectivity-service.DNSv4.domain", "mozilla.org");
pref("network.connectivity-service.DNSv6.domain", "mozilla.org");
// DNS Trusted Recursive Resolver
// 0 - default off, 1 - race, 2 TRR first, 3 TRR only, 4 shadow, 5 off by choice
pref("network.trr.mode", 0);

Просмотреть файл

@ -0,0 +1,157 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "NetworkConnectivityService.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "xpcpublic.h"
namespace mozilla {
namespace net {
NS_IMPL_ISUPPORTS(NetworkConnectivityService, nsINetworkConnectivityService, nsIObserver, nsIDNSListener)
static StaticRefPtr<NetworkConnectivityService> gConnService;
// static
already_AddRefed<NetworkConnectivityService>
NetworkConnectivityService::GetSingleton()
{
if (gConnService) {
return do_AddRef(gConnService);
}
RefPtr<NetworkConnectivityService> service = new NetworkConnectivityService();
service->Init();
gConnService = service.forget();
ClearOnShutdown(&gConnService);
return do_AddRef(gConnService);
}
nsresult
NetworkConnectivityService::Init()
{
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
observerService->AddObserver(this, "network:captive-portal-connectivity", false);
// We need to schedule this for a bit later, to avoid a recursive service
// initialization.
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
NewRunnableMethod("NetworkConnectivityService::PerformChecks",
this,
&NetworkConnectivityService::PerformChecks)));
return NS_OK;
}
NS_IMETHODIMP
NetworkConnectivityService::GetDNSv4(int32_t *aState)
{
NS_ENSURE_ARG(aState);
*aState = mDNSv4;
return NS_OK;
}
NS_IMETHODIMP
NetworkConnectivityService::GetDNSv6(int32_t *aState)
{
NS_ENSURE_ARG(aState);
*aState = mDNSv6;
return NS_OK;
}
void
NetworkConnectivityService::PerformChecks()
{
RecheckDNS();
}
NS_IMETHODIMP
NetworkConnectivityService::OnLookupComplete(nsICancelable *aRequest,
nsIDNSRecord *aRecord,
nsresult aStatus)
{
int32_t state = aRecord ? nsINetworkConnectivityService::OK
: nsINetworkConnectivityService::NOT_AVAILABLE;
if (aRequest == mDNSv4Request) {
mDNSv4 = state;
mDNSv4Request = nullptr;
} else if (aRequest == mDNSv6Request) {
mDNSv6 = state;
mDNSv6Request = nullptr;
}
return NS_OK;
}
NS_IMETHODIMP
NetworkConnectivityService::OnLookupByTypeComplete(nsICancelable *aRequest,
nsIDNSByTypeRecord *aRes,
nsresult aStatus)
{
return NS_OK;
}
NS_IMETHODIMP
NetworkConnectivityService::RecheckDNS()
{
bool enabled = Preferences::GetBool("network.connectivity-service.enabled", false);
if (!enabled) {
return NS_OK;
}
nsresult rv;
nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
OriginAttributes attrs;
nsAutoCString host;
Preferences::GetCString("network.connectivity-service.DNSv4.domain", host);
rv = dns->AsyncResolveNative(host, nsIDNSService::RESOLVE_DISABLE_IPV6,
this, NS_GetCurrentThread(),
attrs, getter_AddRefs(mDNSv4Request));
NS_ENSURE_SUCCESS(rv, rv);
Preferences::GetCString("network.connectivity-service.DNSv6.domain", host);
rv = dns->AsyncResolveNative(host, nsIDNSService::RESOLVE_DISABLE_IPV4,
this, NS_GetCurrentThread(),
attrs, getter_AddRefs(mDNSv6Request));
return rv;
}
NS_IMETHODIMP
NetworkConnectivityService::Observe(nsISupports *aSubject,
const char * aTopic,
const char16_t * aData)
{
if (!strcmp(aTopic, "network:captive-portal-connectivity")) {
// Captive portal is cleared, so we redo the checks.
mDNSv4 = nsINetworkConnectivityService::UNKNOWN;
mDNSv6 = nsINetworkConnectivityService::UNKNOWN;
PerformChecks();
} else if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
if (mDNSv4Request) {
mDNSv4Request->Cancel(NS_ERROR_ABORT);
mDNSv4Request = nullptr;
}
if (mDNSv6Request) {
mDNSv6Request->Cancel(NS_ERROR_ABORT);
mDNSv6Request = nullptr;
}
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
observerService->RemoveObserver(this, "network:captive-portal-connectivity");
}
return NS_OK;
}
} // namespace net
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,47 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef NetworkConnectivityService_h_
#define NetworkConnectivityService_h_
#include "nsINetworkConnectivityService.h"
namespace mozilla {
namespace net {
class NetworkConnectivityService
: public nsINetworkConnectivityService
, public nsIObserver
, public nsIDNSListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSINETWORKCONNECTIVITYSERVICE
NS_DECL_NSIOBSERVER
NS_DECL_NSIDNSLISTENER
nsresult Init();
static already_AddRefed<NetworkConnectivityService> GetSingleton();
private:
NetworkConnectivityService() = default;
virtual ~NetworkConnectivityService() = default;
// Calls all the check methods
void PerformChecks();
// Will be set to OK if the DNS request returned in IP of this type,
// NOT_AVAILABLE if that type of resolution is not available
// UNKNOWN if the check wasn't performed
int32_t mDNSv4 = nsINetworkConnectivityService::UNKNOWN;
int32_t mDNSv6 = nsINetworkConnectivityService::UNKNOWN;
nsCOMPtr<nsICancelable> mDNSv4Request;
nsCOMPtr<nsICancelable> mDNSv6Request;
};
} // namespace net
} // namespace mozilla
#endif // NetworkConnectivityService_h_

Просмотреть файл

@ -4,6 +4,7 @@
#include "RedirectChannelRegistrar.h"
#include "mozilla/StaticPtr.h"
#include "nsThreadUtils.h"
namespace mozilla {
namespace net {

Просмотреть файл

@ -63,6 +63,7 @@ XPIDL_SOURCES += [
'nsINestedURI.idl',
'nsINetAddr.idl',
'nsINetUtil.idl',
'nsINetworkConnectivityService.idl',
'nsINetworkInfoService.idl',
'nsINetworkInterceptController.idl',
'nsINetworkLinkService.idl',
@ -173,6 +174,7 @@ EXPORTS.mozilla.net += [
'DashboardTypes.h',
'IOActivityMonitor.h',
'MemoryDownloader.h',
'NetworkConnectivityService.h',
'PartiallySeekableInputStream.h',
'Predictor.h',
'RedirectChannelRegistrar.h',
@ -194,6 +196,7 @@ UNIFIED_SOURCES += [
'LoadContextInfo.cpp',
'LoadInfo.cpp',
'MemoryDownloader.cpp',
'NetworkConnectivityService.cpp',
'nsAsyncRedirectVerifyHelper.cpp',
'nsAsyncStreamCopier.cpp',
'nsAuthInformationHolder.cpp',

Просмотреть файл

@ -0,0 +1,27 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
[scriptable, builtinclass, uuid(2693457e-3ba5-4455-991f-5350946adb12)]
interface nsINetworkConnectivityService : nsISupports
{
/**
* Each tested feature may be in one of 3 states:
* UNKNOWN, if a check hasn't been performed.
* OK, if the feature was successfully tested
* NOT_AVAILABLE, if the feature is blocked by the network.
* Note that the endpoints are guaranteed to support the features.
*/
const long UNKNOWN = 0;
const long OK = 1;
const long NOT_AVAILABLE = 2;
/* If DNS v4/v6 queries actually work on the current network */
readonly attribute long DNSv4;
readonly attribute long DNSv6;
/* Starts the DNS request to check for DNS v4/v6 availability */
void recheckDNS();
};

Просмотреть файл

@ -53,6 +53,7 @@
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ServiceWorkerDescriptor.h"
#include "mozilla/net/CaptivePortalService.h"
#include "mozilla/net/NetworkConnectivityService.h"
#include "mozilla/Unused.h"
#include "ReferrerPolicy.h"
#include "nsContentSecurityManager.h"
@ -262,6 +263,10 @@ nsIOService::Init()
SetOffline(false);
RefPtr<NetworkConnectivityService> ncs =
NetworkConnectivityService::GetSingleton();
ncs->Init();
return NS_OK;
}

Просмотреть файл

@ -452,6 +452,16 @@
{ 0x92, 0x05, 0xc3, 0x09, 0xce, 0xb2, 0xd6, 0x41 } \
}
#define NS_NETWORKCONNECTIVITYSERVICE_CONTRACTID \
"@mozilla.org/network/network-connectivity-service;1"
#define NS_NETWORKCONNECTIVITYSERVICE_CID \
{ /* 2693457e-3ba5-4455-991f-5350946adb12 */ \
0x2693457e, \
0x3ba5, \
0x4455, \
{ 0x99, 0x1f, 0x53, 0x50, 0x94, 0x6a, 0xdb, 0x12 } \
}
/******************************************************************************
* netwerk/cache/ classes
*/

Просмотреть файл

@ -141,6 +141,14 @@ namespace net {
} // namespace net
} // namespace mozilla
#include "mozilla/net/NetworkConnectivityService.h"
namespace mozilla {
namespace net {
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsINetworkConnectivityService,
NetworkConnectivityService::GetSingleton)
} // namespace net
} // namespace mozilla
///////////////////////////////////////////////////////////////////////////////
extern nsresult
@ -722,6 +730,7 @@ NS_DEFINE_NAMED_CID(NS_CACHE_STORAGE_SERVICE_CID);
NS_DEFINE_NAMED_CID(NS_NSILOADCONTEXTINFOFACTORY_CID);
NS_DEFINE_NAMED_CID(NS_NETWORKPREDICTOR_CID);
NS_DEFINE_NAMED_CID(NS_CAPTIVEPORTAL_CID);
NS_DEFINE_NAMED_CID(NS_NETWORKCONNECTIVITYSERVICE_CID);
#ifdef BUILD_NETWORK_INFO_SERVICE
NS_DEFINE_NAMED_CID(NETWORKINFOSERVICE_CID);
#endif // BUILD_NETWORK_INFO_SERVICE
@ -830,6 +839,7 @@ static const mozilla::Module::CIDEntry kNeckoCIDs[] = {
{ &kNS_NSILOADCONTEXTINFOFACTORY_CID, false, nullptr, LoadContextInfoFactoryConstructor },
{ &kNS_NETWORKPREDICTOR_CID, false, nullptr, mozilla::net::Predictor::Create },
{ &kNS_CAPTIVEPORTAL_CID, false, nullptr, mozilla::net::nsICaptivePortalServiceConstructor },
{ &kNS_NETWORKCONNECTIVITYSERVICE_CID, false, nullptr, mozilla::net::nsINetworkConnectivityServiceConstructor },
#ifdef BUILD_NETWORK_INFO_SERVICE
{ &kNETWORKINFOSERVICE_CID, false, nullptr, nsNetworkInfoServiceConstructor },
#endif
@ -938,6 +948,7 @@ static const mozilla::Module::ContractIDEntry kNeckoContracts[] = {
{ NS_NSILOADCONTEXTINFOFACTORY_CONTRACTID, &kNS_NSILOADCONTEXTINFOFACTORY_CID },
{ NS_NETWORKPREDICTOR_CONTRACTID, &kNS_NETWORKPREDICTOR_CID },
{ NS_CAPTIVEPORTAL_CONTRACTID, &kNS_CAPTIVEPORTAL_CID },
{ NS_NETWORKCONNECTIVITYSERVICE_CONTRACTID, &kNS_NETWORKCONNECTIVITYSERVICE_CID },
#ifdef BUILD_NETWORK_INFO_SERVICE
{ NETWORKINFOSERVICE_CONTRACT_ID, &kNETWORKINFOSERVICE_CID },
#endif

Просмотреть файл

@ -0,0 +1,57 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
"use strict";
ChromeUtils.import("resource://testing-common/httpd.js");
ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
registerCleanupFunction(() => {
Services.prefs.clearUserPref("network.connectivity-service.DNSv4.domain");
Services.prefs.clearUserPref("network.connectivity-service.DNSv6.domain");
});
const DEFAULT_WAIT_TIME = 200; // ms
const kDNSv6Domain = (mozinfo.os == "linux")
? "ip6-localhost"
: "localhost";
add_task(async function testDNS() {
let ncs = Cc["@mozilla.org/network/network-connectivity-service;1"]
.getService(Ci.nsINetworkConnectivityService);
// Set the endpoints, trigger a DNS recheck, and wait for it to complete.
Services.prefs.setCharPref("network.connectivity-service.DNSv4.domain", "example.org");
Services.prefs.setCharPref("network.connectivity-service.DNSv6.domain", kDNSv6Domain);
ncs.recheckDNS();
await new Promise(resolve => do_timeout(DEFAULT_WAIT_TIME, resolve));
equal(ncs.DNSv4, Ci.nsINetworkConnectivityService.OK, "Check DNSv4 support (expect OK)");
equal(ncs.DNSv6, Ci.nsINetworkConnectivityService.OK, "Check DNSv6 support (expect OK)");
// Set the endpoints to non-exitant domains, trigger a DNS recheck, and wait for it to complete.
Services.prefs.setCharPref("network.connectivity-service.DNSv4.domain", "does-not-exist.example");
Services.prefs.setCharPref("network.connectivity-service.DNSv6.domain", "does-not-exist.example");
ncs.recheckDNS();
await new Promise(resolve => do_timeout(DEFAULT_WAIT_TIME, resolve));
equal(ncs.DNSv4, Ci.nsINetworkConnectivityService.NOT_AVAILABLE, "Check DNSv4 support (expect N/A)");
equal(ncs.DNSv6, Ci.nsINetworkConnectivityService.NOT_AVAILABLE, "Check DNSv6 support (expect N/A)");
// Set the endpoints back to the proper domains, and simulate a captive portal
// event.
Services.prefs.setCharPref("network.connectivity-service.DNSv4.domain", "example.org");
Services.prefs.setCharPref("network.connectivity-service.DNSv6.domain", kDNSv6Domain);
Services.obs.notifyObservers(null, "network:captive-portal-connectivity", null);
// This will cause the state to go to UNKNOWN for a bit, until the check is completed.
equal(ncs.DNSv4, Ci.nsINetworkConnectivityService.UNKNOWN, "Check DNSv4 support (expect UNKNOWN)");
equal(ncs.DNSv6, Ci.nsINetworkConnectivityService.UNKNOWN, "Check DNSv6 support (expect UNKNOWN)");
await new Promise(resolve => do_timeout(DEFAULT_WAIT_TIME, resolve));
equal(ncs.DNSv4, Ci.nsINetworkConnectivityService.OK, "Check DNSv4 support (expect OK)");
equal(ncs.DNSv6, Ci.nsINetworkConnectivityService.OK, "Check DNSv6 support (expect OK)");
});

Просмотреть файл

@ -422,3 +422,5 @@ run-sequentially = node server exceptions dont replay well
[test_esni_dns_fetch.js]
# http2-using tests require node available
skip-if = os == "android"
[test_network_connectivity_service.js]
skip-if = os == "android" # DNSv6 issues on android