Bug 1565008 - TRR: Check for Proxy on Windows to use platform DNS r=mayhemer

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Valentin Gosu 2019-11-24 14:54:02 +00:00
parent 8d9b3dc595
commit 0e928af6c3
10 changed files with 99 additions and 28 deletions

View File

@ -6855,6 +6855,12 @@
value: false
mirror: always
# This pref controls if TRR will still be enabled when a proxy is detected
- name: network.trr.enable_when_proxy_detected
type: RelaxedAtomicBool
value: false
mirror: always
# Allow the network changed event to get sent when a network topology or setup
# change is noticed while running.
- name: network.notify.changed
@ -6878,6 +6884,13 @@
value: true
mirror: always
# Whether to check the registry for proxies on network changes that indicate
# that TRR should not be used.
- name: network.notify.checkForProxies
type: RelaxedAtomicBool
value: true
mirror: always
#---------------------------------------------------------------------------
# Prefs starting with "nglayout."
#---------------------------------------------------------------------------

View File

@ -57,10 +57,15 @@ interface nsINetworkLinkService : nsISupports
*/
readonly attribute Array<ACString> dnsSuffixList;
const unsigned long NONE_DETECTED = 0;
const unsigned long VPN_DETECTED = 1 << 0;
const unsigned long PROXY_DETECTED = 1 << 1;
/**
* Whether a VPN was detected on at least one active network interface.
* A bitfield that encodes the platform attributes we detected which
* indicate that we should only use DNS, not TRR.
*/
readonly attribute boolean vpnDetected;
readonly attribute unsigned long platformDNSIndications;
};
%{C++

View File

@ -49,7 +49,7 @@ TRRService::TRRService()
mUseGET(false),
mDisableECS(true),
mDisableAfterFails(5),
mVPNDetected(false),
mPlatformDisabledTRR(false),
mClearTRRBLStorage(false),
mConfirmationState(CONFIRM_INIT),
mRetryConfirmInterval(1000),
@ -456,13 +456,12 @@ TRRService::Observe(nsISupports* aSubject, const char* aTopic,
LOG(("TRRService link-event"));
nsCOMPtr<nsINetworkLinkService> link = do_QueryInterface(aSubject);
RebuildSuffixList(link);
CheckVPNStatus(link);
CheckPlatformDNSStatus(link);
}
return NS_OK;
}
void TRRService::RebuildSuffixList(nsINetworkLinkService* aLinkService) {
mDNSSuffixDomains.Clear();
// The network link service notification normally passes itself as the
// subject, but some unit tests will sometimes pass a null subject.
if (!aLinkService) {
@ -471,21 +470,28 @@ void TRRService::RebuildSuffixList(nsINetworkLinkService* aLinkService) {
nsTArray<nsCString> suffixList;
aLinkService->GetDnsSuffixList(suffixList);
MutexAutoLock lock(mLock);
mDNSSuffixDomains.Clear();
for (const auto& item : suffixList) {
LOG(("TRRService adding %s to suffix list", item.get()));
mDNSSuffixDomains.PutEntry(item);
}
}
void TRRService::CheckVPNStatus(nsINetworkLinkService* aLinkService) {
void TRRService::CheckPlatformDNSStatus(nsINetworkLinkService* aLinkService) {
if (!aLinkService) {
return;
}
bool vpnDetected = false;
aLinkService->GetVpnDetected(&vpnDetected);
mVPNDetected = vpnDetected;
LOG(("TRRService vpnDetected=%d", vpnDetected));
uint32_t platformIndications = nsINetworkLinkService::NONE_DETECTED;
aLinkService->GetPlatformDNSIndications(&platformIndications);
LOG(("TRRService platformIndications=%u", platformIndications));
mPlatformDisabledTRR =
(!StaticPrefs::network_trr_enable_when_vpn_detected() &&
(platformIndications & nsINetworkLinkService::VPN_DETECTED)) ||
(!StaticPrefs::network_trr_enable_when_proxy_detected() &&
(platformIndications & nsINetworkLinkService::PROXY_DETECTED));
}
void TRRService::MaybeConfirm() {
@ -648,14 +654,16 @@ bool TRRService::IsExcludedFromTRR(const nsACString& aHost) {
}
bool TRRService::IsExcludedFromTRR_unlocked(const nsACString& aHost) {
if (mVPNDetected && !StaticPrefs::network_trr_enable_when_vpn_detected()) {
LOG(("%s is excluded from TRR because of VPN", aHost.BeginReading()));
return true;
}
if (!NS_IsMainThread()) {
mLock.AssertCurrentThreadOwns();
}
if (mPlatformDisabledTRR) {
LOG(("%s is excluded from TRR because of platform indications",
aHost.BeginReading()));
return true;
}
int32_t dot = 0;
// iteratively check the sub-domain of |aHost|
while (dot < static_cast<int32_t>(aHost.Length())) {

View File

@ -78,7 +78,7 @@ class TRRService : public nsIObserver,
bool IsExcludedFromTRR_unlocked(const nsACString& aHost);
void RebuildSuffixList(nsINetworkLinkService* aLinkService);
void CheckVPNStatus(nsINetworkLinkService* aLinkService);
void CheckPlatformDNSStatus(nsINetworkLinkService* aLinkService);
bool mInitialized;
Atomic<uint32_t, Relaxed> mMode;
@ -105,7 +105,7 @@ class TRRService : public nsIObserver,
Atomic<bool, Relaxed> mDisableECS; // disable EDNS Client Subnet in requests
Atomic<uint32_t, Relaxed>
mDisableAfterFails; // this many fails in a row means failed TRR service
Atomic<bool, Relaxed> mVPNDetected;
Atomic<bool, Relaxed> mPlatformDisabledTRR;
// TRR Blacklist storage
// mTRRBLStorage is only modified on the main thread, but we query whether it

View File

@ -153,7 +153,8 @@ nsAndroidNetworkLinkService::GetDnsSuffixList(
}
NS_IMETHODIMP
nsAndroidNetworkLinkService::GetVpnDetected(bool* aHasVPN) {
nsAndroidNetworkLinkService::GetPlatformDNSIndications(
uint32_t* aPlatformDNSIndications) {
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@ -69,7 +69,8 @@ nsNetworkLinkService::GetDnsSuffixList(nsTArray<nsCString>& aDnsSuffixList) {
}
NS_IMETHODIMP
nsNetworkLinkService::GetVpnDetected(bool* aHasVPN) {
nsNetworkLinkService::GetPlatformDNSIndications(
uint32_t* aPlatformDNSIndications) {
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@ -119,7 +119,9 @@ nsNetworkLinkService::GetNetworkID(nsACString& aNetworkID) {
}
NS_IMETHODIMP
nsNetworkLinkService::GetVpnDetected(bool* aHasVPN) { return NS_ERROR_NOT_IMPLEMENTED; }
nsNetworkLinkService::GetPlatformDNSIndications(uint32_t* aPlatformDNSIndications) {
return NS_ERROR_NOT_IMPLEMENTED;
}
// Note that this function is copied from xpcom/io/nsLocalFileUnix.cpp.
static nsresult CFStringReftoUTF8(CFStringRef aInStrRef, nsACString& aOutStr) {

View File

@ -66,7 +66,7 @@ nsNotifyAddrListener::nsNotifyAddrListener()
mMutex("nsNotifyAddrListener::mMutex"),
mCheckEvent(nullptr),
mShutdown(false),
mFoundVPN(false),
mPlatformDNSIndications(NONE_DETECTED),
mIPInterfaceChecksum(0),
mCoalescingActive(false) {}
@ -116,8 +116,9 @@ nsNotifyAddrListener::GetDnsSuffixList(nsTArray<nsCString>& aDnsSuffixList) {
}
NS_IMETHODIMP
nsNotifyAddrListener::GetVpnDetected(bool* aHasVPN) {
*aHasVPN = mFoundVPN;
nsNotifyAddrListener::GetPlatformDNSIndications(
uint32_t* aPlatformDNSIndications) {
*aPlatformDNSIndications = mPlatformDNSIndications;
return NS_OK;
}
@ -445,7 +446,7 @@ nsNotifyAddrListener::CheckAdaptersAddresses(void) {
ULONG sumAll = 0;
nsTArray<nsCString> dnsSuffixList;
mFoundVPN = false;
uint32_t platformDNSIndications = NONE_DETECTED;
if (ret == ERROR_SUCCESS) {
bool linkUp = false;
ULONG sum = 0;
@ -460,7 +461,7 @@ nsNotifyAddrListener::CheckAdaptersAddresses(void) {
if (adapter->IfType == IF_TYPE_PPP) {
LOG(("VPN connection found"));
mFoundVPN = true;
platformDNSIndications |= VPN_DETECTED;
}
sum <<= 2;
@ -539,9 +540,47 @@ nsNotifyAddrListener::CheckAdaptersAddresses(void) {
};
checkRegistry();
}
if (StaticPrefs::network_notify_checkForProxies()) {
auto registryChildCount = [](const nsAString& aRegPath) -> uint32_t {
nsresult rv;
nsCOMPtr<nsIWindowsRegKey> regKey =
do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
if (NS_FAILED(rv)) {
LOG((" creating nsIWindowsRegKey failed\n"));
return 0;
}
rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, aRegPath,
nsIWindowsRegKey::ACCESS_READ);
if (NS_FAILED(rv)) {
LOG((" opening registry key failed\n"));
return 0;
}
uint32_t count = 0;
rv = regKey->GetChildCount(&count);
if (NS_FAILED(rv)) {
return 0;
}
return count;
};
if (registryChildCount(
NS_LITERAL_STRING("SYSTEM\\CurrentControlSet\\Services\\Dnscache\\"
"Parameters\\DnsConnections")) > 0 ||
registryChildCount(
NS_LITERAL_STRING("SYSTEM\\CurrentControlSet\\Services\\Dnscache\\"
"Parameters\\DnsConnectionsProxies")) > 0) {
platformDNSIndications |= PROXY_DETECTED;
}
}
{
MutexAutoLock lock(mMutex);
mDnsSuffixList.SwapElements(dnsSuffixList);
mPlatformDNSIndications = platformDNSIndications;
}
calculateNetworkId();

View File

@ -72,8 +72,9 @@ class nsNotifyAddrListener : public nsINetworkLinkService,
// set true when mCheckEvent means shutdown
bool mShutdown;
// If a VPN was detected on at least one active network interface.
mozilla::Atomic<bool, mozilla::MemoryOrdering::Relaxed> mFoundVPN;
// Contains a set of flags that codify the reasons for which
// the platform indicates DNS should be used instead of TRR.
mozilla::Atomic<uint32_t, mozilla::Relaxed> mPlatformDNSIndications;
// This is a checksum of various meta data for all network interfaces
// considered UP at last check.

View File

@ -1149,7 +1149,7 @@ add_task(async function test_vpnDetection() {
await new DNSListener("push.example.org", "2018::2018");
let networkLinkService = {
vpnDetected: true,
platformDNSIndications: Ci.nsINetworkLinkService.VPN_DETECTED,
QueryInterface: ChromeUtils.generateQI([Ci.nsINetworkLinkService]),
};
@ -1175,7 +1175,8 @@ add_task(async function test_vpnDetection() {
Services.prefs.clearUserPref("network.trr.bootstrapAddress");
// Attempt to clean up, just in case
networkLinkService.vpnDetected = false;
networkLinkService.platformDNSIndications =
Ci.nsINetworkLinkService.NONE_DETECTED;
Services.obs.notifyObservers(
networkLinkService,
"network:link-status-changed",