зеркало из https://github.com/mozilla/gecko-dev.git
bug 1434852 - introducing TRR (DOH); r=mcmanus,valentin
Provides an optional resolver mechanism for Firefox that allows running together with or instead of the native resolver. TRR offers resolving of host names using a dedicated DNS-over-HTTPS server (HTTPS is required, HTTP/2 is preferable). DNS-over-HTTPS (DOH) allows DNS resolves with enhanced privacy, secure transfers and improved performance. To keep the failure rate at a minimum, the TRR system manages a dynamic persistent blacklist for host names that can't be resolved with DOH but works with the native resolver. Blacklisted entries will not be retried over DOH for a couple of days. "localhost" and names in the ".local" TLD will not be resolved via DOH. TRR is preffed OFF by default and you need to set a URI for an available DOH server to be able to use it. Since the URI for DOH is set with a name itself, it may have to use the native resolver for bootstrapping. (Optionally, the user can set the IP address of the DOH server in a pref to avoid the required initial native resolve.) When TRR starts up, it will first verify that it works by checking a "confirmation" domain name. This confirmation domain is a pref by default set to "example.com". TRR will also by default await the captive-portal detection to raise its green flag before getting activated. All prefs for TRR are under the "network.trr" hierarchy. The DNS-over-HTTPS spec: https://tools.ietf.org/html/draft-ietf-doh-dns-over-https-03 MozReview-Commit-ID: GuuU6vjTjlm --HG-- extra : rebase_source : 53fcca757334090ac05fec540ef29d109d5ceed3
This commit is contained in:
Родитель
0912c2657b
Коммит
e5d3226694
|
@ -2091,6 +2091,10 @@ pref("network.dnsCacheExpiration", 60);
|
|||
// Get TTL; not supported on all platforms; nop on the unsupported ones.
|
||||
pref("network.dns.get-ttl", true);
|
||||
|
||||
// For testing purposes! Makes the native resolver resolve IPv4 "localhost"
|
||||
// instead of the actual given name.
|
||||
pref("network.dns.native-is-localhost", false);
|
||||
|
||||
// The grace period allows the DNS cache to use expired entries, while kicking off
|
||||
// a revalidation in the background.
|
||||
pref("network.dnsCacheExpirationGracePeriod", 60);
|
||||
|
@ -5404,6 +5408,30 @@ pref("network.captive-portal-service.maxInterval", 1500000); // 25 minutes
|
|||
pref("network.captive-portal-service.backoffFactor", "5.0");
|
||||
pref("network.captive-portal-service.enabled", false);
|
||||
|
||||
// DNS Trusted Recursive Resolver
|
||||
// 0 - off, 1 - race, 2 TRR first, 3 TRR only, 4 shadow
|
||||
pref("network.trr.mode", 0);
|
||||
// DNS-over-HTTP service to use, must be HTTPS://
|
||||
pref("network.trr.uri", "");
|
||||
// credentials to pass to DOH end-point
|
||||
pref("network.trr.credentials", "");
|
||||
// Wait for captive portal confirmation before enabling TRR
|
||||
pref("network.trr.wait-for-portal", true);
|
||||
// Allow RFC1918 address in responses?
|
||||
pref("network.trr.allow-rfc1918", false);
|
||||
// Use GET (rather than POST)
|
||||
pref("network.trr.useGET", false);
|
||||
// Before TRR is widely used the NS record for this host is fetched
|
||||
// from the DOH end point to ensure proper configuration
|
||||
pref("network.trr.confirmationNS", "example.com");
|
||||
// hardcode the resolution of the hostname in network.trr.uri instead of
|
||||
// relying on the system resolver to do it for you
|
||||
pref("network.trr.bootstrapAddress", "");
|
||||
// TRR blacklist entry expire time (in seconds). Default is 72 hours.
|
||||
pref("network.trr.blacklist-duration", 259200);
|
||||
// Single TRR request timeout, in milliseconds
|
||||
pref("network.trr.request-timeout", 3000);
|
||||
|
||||
pref("captivedetect.canonicalURL", "http://detectportal.firefox.com/success.txt");
|
||||
pref("captivedetect.canonicalContent", "success\n");
|
||||
pref("captivedetect.maxWaitingTime", 5000);
|
||||
|
|
|
@ -201,7 +201,7 @@ interface nsIChannel : nsIRequest
|
|||
/**************************************************************************
|
||||
* Channel specific load flags:
|
||||
*
|
||||
* Bits 26-31 are reserved for future use by this interface or one of its
|
||||
* Bits 16-31 are reserved for future use by this interface or one of its
|
||||
* derivatives (e.g., see nsICachingChannel).
|
||||
*/
|
||||
|
||||
|
|
|
@ -237,6 +237,13 @@ interface nsISocketTransport : nsITransport
|
|||
*/
|
||||
const unsigned long BE_CONSERVATIVE = (1 << 7);
|
||||
|
||||
/**
|
||||
* If set, do not use TRR for resolving the host name. Intended only for
|
||||
* retries or other scenarios when TRR is deemed likely to have returned a
|
||||
* wrong adddress.
|
||||
*/
|
||||
const unsigned long DISABLE_TRR = (1 << 8);
|
||||
|
||||
/**
|
||||
* An opaque flags for non-standard behavior of the TLS system.
|
||||
* It is unlikely this will need to be set outside of telemetry studies
|
||||
|
|
|
@ -1110,6 +1110,8 @@ nsSocketTransport::ResolveHost()
|
|||
dnsFlags |= nsIDNSService::RESOLVE_DISABLE_IPV6;
|
||||
if (mConnectionFlags & nsSocketTransport::DISABLE_IPV4)
|
||||
dnsFlags |= nsIDNSService::RESOLVE_DISABLE_IPV4;
|
||||
if (mConnectionFlags & nsSocketTransport::DISABLE_TRR)
|
||||
dnsFlags |= nsIDNSService::RESOLVE_DISABLE_TRR;
|
||||
|
||||
NS_ASSERTION(!(dnsFlags & nsIDNSService::RESOLVE_DISABLE_IPV6) ||
|
||||
!(dnsFlags & nsIDNSService::RESOLVE_DISABLE_IPV4),
|
||||
|
@ -1802,6 +1804,17 @@ nsSocketTransport::RecoverFromError()
|
|||
mState = STATE_CLOSED;
|
||||
mConnectionFlags &= ~(DISABLE_IPV6 | DISABLE_IPV4);
|
||||
tryAgain = true;
|
||||
} else if (!(mConnectionFlags & DISABLE_TRR)) {
|
||||
bool trrEnabled;
|
||||
mDNSRecord->IsTRR(&trrEnabled);
|
||||
if (trrEnabled) {
|
||||
// Drop state to closed. This will trigger a new round of
|
||||
// DNS resolving.
|
||||
SOCKET_LOG((" failed to connect with TRR enabled, try w/o\n"));
|
||||
mState = STATE_CLOSED;
|
||||
mConnectionFlags |= DISABLE_TRR;
|
||||
tryAgain = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=4 sw=4 sts=4 et cin: */
|
||||
/* 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/. */
|
||||
|
@ -296,6 +298,7 @@ AddrInfo::AddrInfo(const char *host, const PRAddrInfo *prAddrInfo,
|
|||
: mHostName(nullptr)
|
||||
, mCanonicalName(nullptr)
|
||||
, ttl(NO_TTL_DATA)
|
||||
, mFromTRR(false)
|
||||
{
|
||||
MOZ_ASSERT(prAddrInfo, "Cannot construct AddrInfo with a null prAddrInfo pointer!");
|
||||
const uint32_t nameCollisionAddr = htonl(0x7f003535); // 127.0.53.53
|
||||
|
@ -319,10 +322,40 @@ AddrInfo::AddrInfo(const char *host, const char *cname)
|
|||
: mHostName(nullptr)
|
||||
, mCanonicalName(nullptr)
|
||||
, ttl(NO_TTL_DATA)
|
||||
, mFromTRR(false)
|
||||
{
|
||||
Init(host, cname);
|
||||
}
|
||||
|
||||
AddrInfo::AddrInfo(const char *host, unsigned int aTRR)
|
||||
: mHostName(nullptr)
|
||||
, mCanonicalName(nullptr)
|
||||
, ttl(NO_TTL_DATA)
|
||||
, mFromTRR(aTRR)
|
||||
{
|
||||
Init(host, nullptr);
|
||||
}
|
||||
|
||||
// deep copy constructor
|
||||
AddrInfo::AddrInfo(const AddrInfo *src)
|
||||
{
|
||||
mHostName = nullptr;
|
||||
if (src->mHostName) {
|
||||
mHostName = strdup(src->mHostName);
|
||||
}
|
||||
mCanonicalName = nullptr;
|
||||
if (src->mCanonicalName) {
|
||||
mCanonicalName = strdup(src->mCanonicalName);
|
||||
}
|
||||
ttl = src->ttl;
|
||||
mFromTRR = src->mFromTRR;
|
||||
|
||||
for (auto element = src->mAddresses.getFirst(); element;
|
||||
element = element->getNext()) {
|
||||
AddAddress(new NetAddrElement(*element));
|
||||
}
|
||||
}
|
||||
|
||||
AddrInfo::~AddrInfo()
|
||||
{
|
||||
NetAddrElement *addrElement;
|
||||
|
|
|
@ -135,13 +135,18 @@ class AddrInfo {
|
|||
public:
|
||||
// Creates an AddrInfo object. It calls the AddrInfo(const char*, const char*)
|
||||
// to initialize the host and the cname.
|
||||
AddrInfo(const char *host, const PRAddrInfo *prAddrInfo, bool disableIPv4,
|
||||
bool filterNameCollision, const char *cname);
|
||||
explicit AddrInfo(const char *host, const PRAddrInfo *prAddrInfo, bool disableIPv4,
|
||||
bool filterNameCollision, const char *cname);
|
||||
|
||||
// Creates a basic AddrInfo object (initialize only the host and the cname).
|
||||
AddrInfo(const char *host, const char *cname);
|
||||
explicit AddrInfo(const char *host, const char *cname);
|
||||
|
||||
// Creates a basic AddrInfo object (initialize only the host and TRR status).
|
||||
explicit AddrInfo(const char *host, unsigned int TRRType);
|
||||
~AddrInfo();
|
||||
|
||||
explicit AddrInfo(const AddrInfo *src); // copy
|
||||
|
||||
void AddAddress(NetAddrElement *address);
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
|
@ -152,8 +157,9 @@ public:
|
|||
static const uint32_t NO_TTL_DATA = (uint32_t) -1;
|
||||
|
||||
LinkedList<NetAddrElement> mAddresses;
|
||||
|
||||
unsigned int IsTRR() { return mFromTRR; }
|
||||
private:
|
||||
unsigned int mFromTRR;
|
||||
void Init(const char *host, const char *cname);
|
||||
};
|
||||
|
||||
|
|
|
@ -81,6 +81,13 @@ ChildDNSRecord::GetCanonicalName(nsACString &result)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ChildDNSRecord::IsTRR(bool *retval)
|
||||
{
|
||||
*retval = false;
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ChildDNSRecord::GetNextAddr(uint16_t port, NetAddr *addr)
|
||||
{
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
#if DNSQUERY_AVAILABLE
|
||||
#ifdef DNSQUERY_AVAILABLE
|
||||
// There is a bug in windns.h where the type of parameter ppQueryResultsSet for
|
||||
// DnsQuery_A is dependent on UNICODE being set. It should *always* be
|
||||
// PDNS_RECORDA, but if UNICODE is set it is PDNS_RECORDW. To get around this
|
||||
|
@ -40,7 +40,7 @@ static LazyLogModule gGetAddrInfoLog("GetAddrInfo");
|
|||
#define LOG_WARNING(msg, ...) \
|
||||
MOZ_LOG(gGetAddrInfoLog, LogLevel::Warning, ("[DNS]: " msg, ##__VA_ARGS__))
|
||||
|
||||
#if DNSQUERY_AVAILABLE
|
||||
#ifdef DNSQUERY_AVAILABLE
|
||||
////////////////////////////
|
||||
// WINDOWS IMPLEMENTATION //
|
||||
////////////////////////////
|
||||
|
@ -302,7 +302,7 @@ nsresult
|
|||
GetAddrInfoInit() {
|
||||
LOG("Initializing GetAddrInfo.\n");
|
||||
|
||||
#if DNSQUERY_AVAILABLE
|
||||
#ifdef DNSQUERY_AVAILABLE
|
||||
return _GetAddrInfoInit_Windows();
|
||||
#else
|
||||
return NS_OK;
|
||||
|
@ -313,7 +313,7 @@ nsresult
|
|||
GetAddrInfoShutdown() {
|
||||
LOG("Shutting down GetAddrInfo.\n");
|
||||
|
||||
#if DNSQUERY_AVAILABLE
|
||||
#ifdef DNSQUERY_AVAILABLE
|
||||
return _GetAddrInfoShutdown_Windows();
|
||||
#else
|
||||
return NS_OK;
|
||||
|
@ -328,18 +328,24 @@ GetAddrInfo(const char* aHost, uint16_t aAddressFamily, uint16_t aFlags,
|
|||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
#if DNSQUERY_AVAILABLE
|
||||
#ifdef DNSQUERY_AVAILABLE
|
||||
// The GetTTLData needs the canonical name to function properly
|
||||
if (aGetTtl) {
|
||||
aFlags |= nsHostResolver::RES_CANON_NAME;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (gNativeIsLocalhost) {
|
||||
// pretend we use the given host but use IPv4 localhost instead!
|
||||
aHost = "localhost";
|
||||
aAddressFamily = PR_AF_INET;
|
||||
}
|
||||
|
||||
*aAddrInfo = nullptr;
|
||||
nsresult rv = _GetAddrInfo_Portable(aHost, aAddressFamily, aFlags,
|
||||
aNetworkInterface, aAddrInfo);
|
||||
|
||||
#if DNSQUERY_AVAILABLE
|
||||
#ifdef DNSQUERY_AVAILABLE
|
||||
if (aGetTtl && NS_SUCCEEDED(rv)) {
|
||||
// Figure out the canonical name, or if that fails, just use the host name
|
||||
// we have.
|
||||
|
|
|
@ -12,10 +12,8 @@
|
|||
|
||||
#if defined(XP_WIN)
|
||||
#define DNSQUERY_AVAILABLE 1
|
||||
#define TTL_AVAILABLE 1
|
||||
#else
|
||||
#define DNSQUERY_AVAILABLE 0
|
||||
#define TTL_AVAILABLE 0
|
||||
#undef DNSQUERY_AVAILABLE
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -35,8 +33,8 @@ class AddrInfo;
|
|||
* hostname (PR_AI_NOCANONNAME will be ignored if the TTL is retrieved).
|
||||
* @param aAddrInfo[out] Will point to the results of the host lookup, or be
|
||||
* null if the lookup failed.
|
||||
* @param aGetTtl[in] If true, and TTL_AVAILABLE is truthy, the TTL will be
|
||||
* retrieved if DNS provides the answers..
|
||||
* @param aGetTtl[in] If true, the TTL will be retrieved if DNS provides the
|
||||
* answers..
|
||||
*/
|
||||
nsresult
|
||||
GetAddrInfo(const char* aHost, uint16_t aAddressFamily, uint16_t aFlags,
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,170 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
/* 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 mozilla_net_TRR_h
|
||||
#define mozilla_net_TRR_h
|
||||
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIHttpPushListener.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIStreamListener.h"
|
||||
|
||||
namespace mozilla { namespace net {
|
||||
|
||||
// the values map to RFC1035 type identifiers
|
||||
enum TrrType {
|
||||
TRRTYPE_A = 1,
|
||||
TRRTYPE_NS = 2,
|
||||
TRRTYPE_CNAME = 5,
|
||||
TRRTYPE_AAAA = 28,
|
||||
};
|
||||
|
||||
class DOHaddr : public LinkedListElement<DOHaddr> {
|
||||
public:
|
||||
NetAddr mNet;
|
||||
uint32_t mTtl;
|
||||
};
|
||||
|
||||
class TRRService;
|
||||
extern TRRService *gTRRService;
|
||||
|
||||
class DOHresp {
|
||||
public:
|
||||
~DOHresp() {
|
||||
DOHaddr *el;
|
||||
while ((el = mAddresses.popLast())) {
|
||||
delete el;
|
||||
}
|
||||
}
|
||||
nsresult Add(uint32_t TTL, unsigned char *dns, int index, uint16_t len,
|
||||
bool aLocalAllowed);
|
||||
LinkedList<DOHaddr> mAddresses;
|
||||
};
|
||||
|
||||
class TRR
|
||||
: public Runnable
|
||||
, public nsITimerCallback
|
||||
, public nsIHttpPushListener
|
||||
, public nsIInterfaceRequestor
|
||||
, public nsIStreamListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIHTTPPUSHLISTENER
|
||||
NS_DECL_NSIINTERFACEREQUESTOR
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
|
||||
// Never accept larger DOH responses than this as that would indicate
|
||||
// something is wrong. Typical ones are much smaller.
|
||||
static const unsigned int kMaxSize = 3200;
|
||||
|
||||
// Number of "steps" we follow CNAME chains
|
||||
static const unsigned int kCnameChaseMax = 64;
|
||||
|
||||
// when firing off a normal A or AAAA query
|
||||
explicit TRR(AHostResolver *aResolver,
|
||||
nsHostRecord *aRec,
|
||||
enum TrrType aType)
|
||||
: mozilla::Runnable("TRR")
|
||||
, mRec(aRec)
|
||||
, mHostResolver(aResolver)
|
||||
, mTRRService(gTRRService)
|
||||
, mType(aType)
|
||||
, mBodySize(0)
|
||||
, mFailed(false)
|
||||
, mCnameLoop(kCnameChaseMax)
|
||||
{
|
||||
mHost = aRec->host;
|
||||
mPB = aRec->pb;
|
||||
}
|
||||
|
||||
// when following CNAMEs
|
||||
explicit TRR(AHostResolver *aResolver,
|
||||
nsHostRecord *aRec,
|
||||
nsCString &aHost,
|
||||
enum TrrType & aType,
|
||||
unsigned int aLoopCount,
|
||||
bool aPB)
|
||||
: mozilla::Runnable("TRR")
|
||||
, mHost(aHost)
|
||||
, mRec(aRec)
|
||||
, mHostResolver(aResolver)
|
||||
, mTRRService(gTRRService)
|
||||
, mType(aType)
|
||||
, mBodySize(0)
|
||||
, mFailed(false)
|
||||
, mPB(aPB)
|
||||
, mCnameLoop(aLoopCount)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// used on push
|
||||
explicit TRR(AHostResolver *aResolver, bool aPB)
|
||||
: mozilla::Runnable("TRR")
|
||||
, mHostResolver(aResolver)
|
||||
, mTRRService(gTRRService)
|
||||
, mBodySize(0)
|
||||
, mFailed(false)
|
||||
, mPB(aPB)
|
||||
, mCnameLoop(kCnameChaseMax)
|
||||
{ }
|
||||
|
||||
// to verify a domain
|
||||
explicit TRR(AHostResolver *aResolver,
|
||||
nsACString &aHost,
|
||||
enum TrrType aType,
|
||||
bool aPB)
|
||||
: mozilla::Runnable("TRR")
|
||||
, mHost(aHost)
|
||||
, mHostResolver(aResolver)
|
||||
, mTRRService(gTRRService)
|
||||
, mType(aType)
|
||||
, mBodySize(0)
|
||||
, mFailed(false)
|
||||
, mPB(aPB)
|
||||
, mCnameLoop(kCnameChaseMax)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run() override;
|
||||
void Cancel();
|
||||
enum TrrType Type() { return mType; }
|
||||
nsCString mHost;
|
||||
RefPtr<nsHostRecord> mRec;
|
||||
RefPtr<AHostResolver> mHostResolver;
|
||||
TRRService *mTRRService;
|
||||
|
||||
private:
|
||||
~TRR() { if (mTimeout) { mTimeout->Cancel(); } };
|
||||
nsresult SendHTTPRequest();
|
||||
nsresult DohEncode(nsCString &target);
|
||||
nsresult DohDecode();
|
||||
nsresult ReturnData();
|
||||
nsresult FailData();
|
||||
nsresult DohDecodeQuery(const nsCString &query,
|
||||
nsCString &host, enum TrrType &type);
|
||||
nsresult ReceivePush(nsIHttpChannel *pushed, nsHostRecord *pushedRec);
|
||||
nsresult On200Response();
|
||||
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
enum TrrType mType;
|
||||
TimeStamp mStartTime;
|
||||
unsigned char mResponse[kMaxSize];
|
||||
unsigned int mBodySize;
|
||||
bool mFailed;
|
||||
bool mPB;
|
||||
DOHresp mDNS;
|
||||
nsCOMPtr<nsITimer> mTimeout;
|
||||
nsCString mCname;
|
||||
uint32_t mCnameLoop; // loop detection counter
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // include guard
|
|
@ -0,0 +1,510 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "nsICaptivePortalService.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIURIMutator.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsStandardURL.h"
|
||||
#include "TRR.h"
|
||||
#include "TRRService.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
static const char kOpenCaptivePortalLoginEvent[] = "captive-portal-login";
|
||||
static const char kClearPrivateData[] = "clear-private-data";
|
||||
static const char kPurge[] = "browser:purge-session-history";
|
||||
|
||||
#define TRR_PREF_PREFIX "network.trr."
|
||||
#define TRR_PREF(x) TRR_PREF_PREFIX x
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
#undef LOG
|
||||
extern mozilla::LazyLogModule gHostResolverLog;
|
||||
#define LOG(args) MOZ_LOG(gHostResolverLog, mozilla::LogLevel::Debug, args)
|
||||
|
||||
TRRService *gTRRService = nullptr;
|
||||
|
||||
NS_IMPL_ISUPPORTS(TRRService, nsIObserver, nsISupportsWeakReference)
|
||||
|
||||
TRRService::TRRService()
|
||||
: mInitialized(false)
|
||||
, mMode(0)
|
||||
, mTRRBlacklistExpireTime(72 * 3600)
|
||||
, mTRRTimeout(3000)
|
||||
, mLock("trrservice")
|
||||
, mConfirmationNS(NS_LITERAL_CSTRING("example.com"))
|
||||
, mWaitForCaptive(true)
|
||||
, mRfc1918(false)
|
||||
, mCaptiveIsPassed(false)
|
||||
, mUseGET(false)
|
||||
, mClearTRRBLStorage(false)
|
||||
, mConfirmationState(CONFIRM_INIT)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
|
||||
}
|
||||
|
||||
nsresult
|
||||
TRRService::Init()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
|
||||
if (mInitialized) {
|
||||
return NS_OK;
|
||||
}
|
||||
mInitialized = true;
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
if (observerService) {
|
||||
observerService->AddObserver(this, NS_CAPTIVE_PORTAL_CONNECTIVITY, true);
|
||||
observerService->AddObserver(this, kOpenCaptivePortalLoginEvent, true);
|
||||
observerService->AddObserver(this, kClearPrivateData, true);
|
||||
observerService->AddObserver(this, kPurge, true);
|
||||
}
|
||||
nsCOMPtr<nsIPrefBranch> prefBranch;
|
||||
GetPrefBranch(getter_AddRefs(prefBranch));
|
||||
if (prefBranch) {
|
||||
prefBranch->AddObserver(TRR_PREF_PREFIX, this, true);
|
||||
}
|
||||
|
||||
ReadPrefs(NULL);
|
||||
|
||||
gTRRService = this;
|
||||
|
||||
LOG(("Initialized TRRService\n"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
TRRService::Enabled()
|
||||
{
|
||||
if (mConfirmationState == CONFIRM_INIT && !mWaitForCaptive) {
|
||||
mConfirmationState = CONFIRM_TRYING;
|
||||
}
|
||||
|
||||
if (mConfirmationState == CONFIRM_TRYING) {
|
||||
MaybeConfirm();
|
||||
}
|
||||
|
||||
return (mConfirmationState == CONFIRM_OK);
|
||||
}
|
||||
|
||||
void
|
||||
TRRService::GetPrefBranch(nsIPrefBranch **result)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
|
||||
*result = nullptr;
|
||||
CallGetService(NS_PREFSERVICE_CONTRACTID, result);
|
||||
}
|
||||
|
||||
nsresult
|
||||
TRRService::ReadPrefs(const char *name)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
|
||||
if (!name || !strcmp(name, TRR_PREF("mode"))) {
|
||||
// 0 - off, 1 - parallel, 2 - TRR first, 3 - TRR only, 4 - shadow
|
||||
uint32_t tmp;
|
||||
if (NS_SUCCEEDED(Preferences::GetUint(TRR_PREF("mode"), &tmp))) {
|
||||
mMode = tmp;
|
||||
}
|
||||
}
|
||||
if (!name || !strcmp(name, TRR_PREF("uri"))) {
|
||||
// Base URI, appends "?ct&dns=..."
|
||||
MutexAutoLock lock(mLock);
|
||||
nsAutoCString old(mPrivateURI);
|
||||
Preferences::GetCString(TRR_PREF("uri"), mPrivateURI);
|
||||
nsAutoCString scheme;
|
||||
if (!mPrivateURI.IsEmpty()) {
|
||||
nsCOMPtr<nsIIOService> ios(do_GetIOService());
|
||||
if (ios) {
|
||||
ios->ExtractScheme(mPrivateURI, scheme);
|
||||
}
|
||||
}
|
||||
if (!mPrivateURI.IsEmpty() && !scheme.Equals("https")) {
|
||||
LOG(("TRRService TRR URI %s is not https. Not used.\n",
|
||||
mPrivateURI.get()));
|
||||
mPrivateURI.Truncate();
|
||||
}
|
||||
if (!mPrivateURI.IsEmpty()) {
|
||||
LOG(("TRRService TRR URI %s\n", mPrivateURI.get()));
|
||||
}
|
||||
if (!old.IsEmpty() && !mPrivateURI.Equals(old)) {
|
||||
mClearTRRBLStorage = true;
|
||||
LOG(("TRRService clearing blacklist because of change is uri service\n"));
|
||||
}
|
||||
}
|
||||
if (!name || !strcmp(name, TRR_PREF("credentials"))) {
|
||||
MutexAutoLock lock(mLock);
|
||||
Preferences::GetCString(TRR_PREF("credentials"), mPrivateCred);
|
||||
}
|
||||
if (!name || !strcmp(name, TRR_PREF("confirmationNS"))) {
|
||||
MutexAutoLock lock(mLock);
|
||||
nsAutoCString old(mConfirmationNS);
|
||||
Preferences::GetCString(TRR_PREF("confirmationNS"), mConfirmationNS);
|
||||
if (name && !old.IsEmpty() && !mConfirmationNS.Equals(old) &&
|
||||
(mConfirmationState > CONFIRM_TRYING)) {
|
||||
LOG(("TRR::ReadPrefs: restart confirmationNS state\n"));
|
||||
mConfirmationState = CONFIRM_TRYING;
|
||||
}
|
||||
}
|
||||
if (!name || !strcmp(name, TRR_PREF("bootstrapAddress"))) {
|
||||
MutexAutoLock lock(mLock);
|
||||
Preferences::GetCString(TRR_PREF("bootstrapAddress"), mBootstrapAddr);
|
||||
}
|
||||
if (!name || !strcmp(name, TRR_PREF("wait-for-portal"))) {
|
||||
// Wait for captive portal?
|
||||
bool tmp;
|
||||
if (NS_SUCCEEDED(Preferences::GetBool(TRR_PREF("wait-for-portal"), &tmp))) {
|
||||
mWaitForCaptive = tmp;
|
||||
}
|
||||
}
|
||||
if (!name || !strcmp(name, TRR_PREF("allow-rfc1918"))) {
|
||||
bool tmp;
|
||||
if (NS_SUCCEEDED(Preferences::GetBool(TRR_PREF("allow-rfc1918"), &tmp))) {
|
||||
mRfc1918 = tmp;
|
||||
}
|
||||
}
|
||||
if (!name || !strcmp(name, TRR_PREF("useGET"))) {
|
||||
bool tmp;
|
||||
if (NS_SUCCEEDED(Preferences::GetBool(TRR_PREF("useGET"), &tmp))) {
|
||||
mUseGET = tmp;
|
||||
}
|
||||
}
|
||||
if (!name || !strcmp(name, TRR_PREF("blacklist-duration"))) {
|
||||
// prefs is given in number of seconds
|
||||
uint32_t secs;
|
||||
if (NS_SUCCEEDED(Preferences::GetUint(TRR_PREF("blacklist-duration"), &secs))) {
|
||||
mTRRBlacklistExpireTime = secs;
|
||||
}
|
||||
}
|
||||
if (!name || !strcmp(name, TRR_PREF("request-timeout"))) {
|
||||
// number of milliseconds
|
||||
uint32_t ms;
|
||||
if (NS_SUCCEEDED(Preferences::GetUint(TRR_PREF("request-timeout"), &ms))) {
|
||||
mTRRTimeout = ms;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TRRService::GetURI(nsCString &result)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
result = mPrivateURI;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TRRService::GetCredentials(nsCString &result)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
result = mPrivateCred;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TRRService::Start()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
|
||||
if (!mInitialized) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
TRRService::~TRRService()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
|
||||
LOG(("Exiting TRRService\n"));
|
||||
gTRRService = nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TRRService::Observe(nsISupports *aSubject,
|
||||
const char * aTopic,
|
||||
const char16_t * aData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
|
||||
LOG(("TRR::Observe() topic=%s\n", aTopic));
|
||||
if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
|
||||
ReadPrefs(NS_ConvertUTF16toUTF8(aData).get());
|
||||
|
||||
if ((mConfirmationState == CONFIRM_INIT) &&
|
||||
!mBootstrapAddr.IsEmpty() &&
|
||||
(mMode == MODE_TRRONLY)) {
|
||||
mConfirmationState = CONFIRM_TRYING;
|
||||
MaybeConfirm();
|
||||
}
|
||||
|
||||
} else if (!strcmp(aTopic, kOpenCaptivePortalLoginEvent)) {
|
||||
// We are in a captive portal
|
||||
LOG(("TRRservice in captive portal\n"));
|
||||
mCaptiveIsPassed = false;
|
||||
} else if (!strcmp(aTopic, NS_CAPTIVE_PORTAL_CONNECTIVITY)) {
|
||||
nsAutoCString data = NS_ConvertUTF16toUTF8(aData);
|
||||
LOG(("TRRservice captive portal was %s\n", data.get()));
|
||||
if (!mTRRBLStorage) {
|
||||
mTRRBLStorage = DataStorage::Get(DataStorageClass::TRRBlacklist);
|
||||
if (mTRRBLStorage) {
|
||||
bool storageWillPersist = true;
|
||||
if (NS_FAILED(mTRRBLStorage->Init(storageWillPersist))) {
|
||||
mTRRBLStorage = nullptr;
|
||||
}
|
||||
if (mClearTRRBLStorage) {
|
||||
if (mTRRBLStorage) {
|
||||
mTRRBLStorage->Clear();
|
||||
}
|
||||
mClearTRRBLStorage = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mConfirmationState = CONFIRM_TRYING;
|
||||
MaybeConfirm();
|
||||
mCaptiveIsPassed = true;
|
||||
|
||||
} else if (!strcmp(aTopic, kClearPrivateData) ||
|
||||
!strcmp(aTopic, kPurge)) {
|
||||
// flush the TRR blacklist, both in-memory and on-disk
|
||||
if (mTRRBLStorage) {
|
||||
mTRRBLStorage->Clear();
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
TRRService::MaybeConfirm()
|
||||
{
|
||||
if ((mMode == MODE_NATIVEONLY) || mConfirmer ||
|
||||
mConfirmationState != CONFIRM_TRYING) {
|
||||
return;
|
||||
}
|
||||
nsAutoCString host;
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
host = mConfirmationNS;
|
||||
}
|
||||
if (host.Equals("skip")) {
|
||||
LOG(("TRRService starting confirmation test %s SKIPPED\n",
|
||||
mPrivateURI.get()));
|
||||
mConfirmationState = CONFIRM_OK;
|
||||
} else {
|
||||
LOG(("TRRService starting confirmation test %s %s\n",
|
||||
mPrivateURI.get(), host.get()));
|
||||
mConfirmer = new TRR(this, host, TRRTYPE_NS, false);
|
||||
NS_DispatchToMainThread(mConfirmer);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
TRRService::MaybeBootstrap(const nsACString &aPossible, nsACString &aResult)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
if ((mMode == MODE_NATIVEONLY) || mBootstrapAddr.IsEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> url;
|
||||
nsresult rv = NS_MutateURI(NS_STANDARDURLMUTATOR_CONTRACTID)
|
||||
.Apply<nsIStandardURLMutator>(&nsIStandardURLMutator::Init,
|
||||
nsIStandardURL::URLTYPE_STANDARD, 443,
|
||||
mPrivateURI, nullptr, nullptr,
|
||||
nullptr)
|
||||
.Finalize(url);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("TRRService::MaybeBootstrap failed to create URI!\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoCString host;
|
||||
url->GetHost(host);
|
||||
if (!aPossible.Equals(host)) {
|
||||
return false;
|
||||
}
|
||||
LOG(("TRRService::MaybeBootstrap: use %s instead of %s\n",
|
||||
mBootstrapAddr.get(), host.get()));
|
||||
aResult = mBootstrapAddr;
|
||||
return true;
|
||||
}
|
||||
|
||||
// When running in TRR-only mode, the blacklist is not used and it will also
|
||||
// try resolving the localhost / .local names.
|
||||
bool
|
||||
TRRService::IsTRRBlacklisted(const nsACString &aHost, bool privateBrowsing,
|
||||
bool aParentsToo) // false if domain
|
||||
{
|
||||
if (mClearTRRBLStorage) {
|
||||
if (mTRRBLStorage) {
|
||||
mTRRBLStorage->Clear();
|
||||
}
|
||||
mClearTRRBLStorage = false;
|
||||
}
|
||||
|
||||
if (mMode == MODE_TRRONLY) {
|
||||
return false; // might as well try
|
||||
}
|
||||
|
||||
// hardcode these so as to not worry about expiration
|
||||
if (StringEndsWith(aHost, NS_LITERAL_CSTRING(".local")) ||
|
||||
aHost.Equals(NS_LITERAL_CSTRING("localhost"))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Enabled()) {
|
||||
return true;
|
||||
}
|
||||
if (!mTRRBLStorage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t dot = aHost.FindChar('.');
|
||||
if ((dot == kNotFound) && aParentsToo) {
|
||||
// Only if a full host name. Domains can be dotless to be able to
|
||||
// blacklist entire TLDs
|
||||
return true;
|
||||
} else if(dot != kNotFound) {
|
||||
// there was a dot, check the parent first
|
||||
dot++;
|
||||
nsDependentCSubstring domain = Substring(aHost, dot, aHost.Length() - dot);
|
||||
nsAutoCString check(domain);
|
||||
|
||||
// recursively check the domain part of this name
|
||||
if (IsTRRBlacklisted(check, privateBrowsing, false)) {
|
||||
// the domain name of this name is already TRR blacklisted
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
MutexAutoLock lock(mLock);
|
||||
// use a unified casing for the hashkey
|
||||
nsAutoCString hashkey(aHost);
|
||||
nsCString val(mTRRBLStorage->Get(hashkey, privateBrowsing ?
|
||||
DataStorage_Private : DataStorage_Persistent));
|
||||
|
||||
if (!val.IsEmpty()) {
|
||||
nsresult code;
|
||||
int32_t until = val.ToInteger(&code) + mTRRBlacklistExpireTime;
|
||||
int32_t expire = NowInSeconds();
|
||||
if (NS_SUCCEEDED(code) && (until > expire)) {
|
||||
LOG(("Host [%s] is TRR blacklisted\n", nsCString(aHost).get()));
|
||||
return true;
|
||||
} else {
|
||||
// the blacklisted entry has expired
|
||||
mTRRBLStorage->Remove(hashkey, privateBrowsing ?
|
||||
DataStorage_Private : DataStorage_Persistent);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class ProxyBlacklist : public Runnable
|
||||
{
|
||||
public:
|
||||
ProxyBlacklist(TRRService *service, const nsACString &aHost, bool pb, bool aParentsToo)
|
||||
: mozilla::Runnable("proxyBlackList")
|
||||
, mService(service), mHost(aHost), mPB(pb), mParentsToo(aParentsToo)
|
||||
{ }
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
mService->TRRBlacklist(mHost, mPB, mParentsToo);
|
||||
mService = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<TRRService> mService;
|
||||
nsCString mHost;
|
||||
bool mPB;
|
||||
bool mParentsToo;
|
||||
};
|
||||
|
||||
void
|
||||
TRRService::TRRBlacklist(const nsACString &aHost, bool privateBrowsing, bool aParentsToo)
|
||||
{
|
||||
if (!mTRRBLStorage) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
NS_DispatchToMainThread(new ProxyBlacklist(this, aHost,
|
||||
privateBrowsing, aParentsToo));
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(("TRR blacklist %s\n", nsCString(aHost).get()));
|
||||
nsAutoCString hashkey(aHost);
|
||||
nsAutoCString val;
|
||||
val.AppendInt( NowInSeconds() ); // creation time
|
||||
|
||||
// this overwrites any existing entry
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
mTRRBLStorage->Put(hashkey, val, privateBrowsing ?
|
||||
DataStorage_Private : DataStorage_Persistent);
|
||||
}
|
||||
|
||||
if (aParentsToo) {
|
||||
// when given a full host name, verify its domain as well
|
||||
int32_t dot = aHost.FindChar('.');
|
||||
if (dot != kNotFound) {
|
||||
// this has a domain to be checked
|
||||
dot++;
|
||||
nsDependentCSubstring domain = Substring(aHost, dot, aHost.Length() - dot);
|
||||
nsAutoCString check(domain);
|
||||
if (IsTRRBlacklisted(check, privateBrowsing, false)) {
|
||||
// the domain part is already blacklisted, no need to add this entry
|
||||
return;
|
||||
}
|
||||
// verify 'check' over TRR
|
||||
LOG(("TRR: verify if '%s' resolves as NS\n", check.get()));
|
||||
|
||||
// check if there's an NS entry for this name
|
||||
RefPtr<TRR> trr = new TRR(this, check, TRRTYPE_NS, privateBrowsing);
|
||||
NS_DispatchToMainThread(trr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AHostResolver::LookupStatus
|
||||
TRRService::CompleteLookup(nsHostRecord *rec, nsresult status, AddrInfo *aNewRRSet, bool pb)
|
||||
{
|
||||
// this is an NS check for the TRR blacklist or confirmationNS check
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!rec);
|
||||
|
||||
nsAutoPtr<AddrInfo> newRRSet(aNewRRSet);
|
||||
MOZ_ASSERT(newRRSet && newRRSet->IsTRR() == TRRTYPE_NS);
|
||||
|
||||
MOZ_ASSERT(!mConfirmer || (mConfirmationState == CONFIRM_TRYING));
|
||||
if (mConfirmationState == CONFIRM_TRYING) {
|
||||
MOZ_ASSERT(mConfirmer);
|
||||
mConfirmationState = NS_SUCCEEDED(status) ? CONFIRM_OK : CONFIRM_FAILED;
|
||||
LOG(("TRRService finishing confirmation test %s %d %X\n",
|
||||
mPrivateURI.get(), (int)mConfirmationState, (unsigned int)status));
|
||||
mConfirmer = nullptr;
|
||||
return LOOKUP_OK;
|
||||
}
|
||||
|
||||
// when called without a host record, this is a domain name check response.
|
||||
if (NS_SUCCEEDED(status)) {
|
||||
LOG(("TRR verified %s to be fine!\n", newRRSet->mHostName));
|
||||
} else {
|
||||
LOG(("TRR says %s doesn't resove as NS!\n", newRRSet->mHostName));
|
||||
TRRBlacklist(nsCString(newRRSet->mHostName), pb, false);
|
||||
}
|
||||
return LOOKUP_OK;
|
||||
}
|
||||
|
||||
#undef LOG
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,88 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 TRRService_h_
|
||||
#define TRRService_h_
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/DataStorage.h"
|
||||
#include "nsHostResolver.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
class nsIPrefBranch;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class TRRService
|
||||
: public nsIObserver
|
||||
, public nsSupportsWeakReference
|
||||
, public AHostResolver
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
TRRService();
|
||||
nsresult Init();
|
||||
nsresult Start();
|
||||
bool Enabled();
|
||||
|
||||
uint32_t Mode() { return mMode; }
|
||||
bool AllowRFC1918() { return mRfc1918; }
|
||||
bool UseGET() { return mUseGET; }
|
||||
nsresult GetURI(nsCString &result);
|
||||
nsresult GetCredentials(nsCString &result);
|
||||
uint32_t GetRequestTimeout() { return mTRRTimeout; }
|
||||
|
||||
LookupStatus CompleteLookup(nsHostRecord *, nsresult, mozilla::net::AddrInfo *, bool pb) override;
|
||||
void TRRBlacklist(const nsACString &host, bool privateBrowsing, bool aParentsToo);
|
||||
bool IsTRRBlacklisted(const nsACString &host, bool privateBrowsing, bool fullhost);
|
||||
|
||||
bool MaybeBootstrap(const nsACString &possible, nsACString &result);
|
||||
|
||||
private:
|
||||
virtual ~TRRService();
|
||||
nsresult ReadPrefs(const char *name);
|
||||
void GetPrefBranch(nsIPrefBranch **result);
|
||||
void MaybeConfirm();
|
||||
|
||||
bool mInitialized;
|
||||
Atomic<uint32_t, Relaxed> mMode;
|
||||
Atomic<uint32_t, Relaxed> mTRRBlacklistExpireTime;
|
||||
Atomic<uint32_t, Relaxed> mTRRTimeout;
|
||||
|
||||
Mutex mLock; // protects mPrivate* string
|
||||
nsCString mPrivateURI; // main thread only
|
||||
nsCString mPrivateCred; // main thread only
|
||||
nsCString mConfirmationNS;
|
||||
nsCString mBootstrapAddr;
|
||||
|
||||
Atomic<bool, Relaxed> mWaitForCaptive; // wait for the captive portal to say OK before using TRR
|
||||
Atomic<bool, Relaxed> mRfc1918; // okay with local IP addresses in DOH responses?
|
||||
Atomic<bool, Relaxed> mCaptiveIsPassed; // set when captive portal check is passed
|
||||
Atomic<bool, Relaxed> mUseGET; // do DOH using GET requests (instead of POST)
|
||||
|
||||
// TRR Blacklist storage
|
||||
RefPtr<DataStorage> mTRRBLStorage;
|
||||
Atomic<bool, Relaxed> mClearTRRBLStorage;
|
||||
|
||||
enum ConfirmationState {
|
||||
CONFIRM_INIT = 0,
|
||||
CONFIRM_TRYING = 1,
|
||||
CONFIRM_OK = 2,
|
||||
CONFIRM_FAILED = 3
|
||||
};
|
||||
Atomic<ConfirmationState, Relaxed> mConfirmationState;
|
||||
RefPtr<TRR> mConfirmer;
|
||||
};
|
||||
|
||||
extern TRRService *gTRRService;
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // TRRService_h_
|
|
@ -29,6 +29,7 @@ EXPORTS.mozilla.net += [
|
|||
'DNSRequestChild.h',
|
||||
'DNSRequestParent.h',
|
||||
'PDNSParams.h',
|
||||
'TRRService.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
|
@ -46,6 +47,8 @@ UNIFIED_SOURCES += [
|
|||
'nsDNSService2.cpp',
|
||||
'nsIDNService.cpp',
|
||||
'punycode.c',
|
||||
'TRR.cpp',
|
||||
'TRRService.cpp',
|
||||
]
|
||||
|
||||
IPDL_SOURCES = [
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "nsProxyRelease.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsINetworkLinkService.h"
|
||||
#include "TRRService.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
|
@ -104,6 +105,18 @@ nsDNSRecord::GetCanonicalName(nsACString &result)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDNSRecord::IsTRR(bool *retval)
|
||||
{
|
||||
MutexAutoLock lock(mHostRecord->addr_info_lock);
|
||||
if (mHostRecord->addr_info) {
|
||||
*retval = mHostRecord->addr_info->IsTRR();
|
||||
}
|
||||
else {
|
||||
*retval = false;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
nsDNSRecord::GetNextAddr(uint16_t port, NetAddr *addr)
|
||||
{
|
||||
|
@ -486,6 +499,7 @@ nsDNSService::nsDNSService()
|
|||
, mNotifyResolution(false)
|
||||
, mOfflineLocalhost(false)
|
||||
, mForceResolveOn(false)
|
||||
, mTrrService(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -639,6 +653,11 @@ nsDNSService::Init()
|
|||
|
||||
RegisterWeakMemoryReporter(this);
|
||||
|
||||
mTrrService = new TRRService();
|
||||
if (NS_FAILED(mTrrService->Init())) {
|
||||
mTrrService = nullptr;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -711,6 +730,11 @@ nsDNSService::PreprocessHostname(bool aLocalDomain,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mTrrService &&
|
||||
mTrrService->MaybeBootstrap(aInput, aACE)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mForceResolveOn) {
|
||||
MutexAutoLock lock(mLock);
|
||||
if (!aInput.LowerCaseEqualsASCII("localhost") &&
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "nsHashKeys.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "TRRService.h"
|
||||
|
||||
class nsAuthSSPI;
|
||||
|
||||
|
@ -47,7 +48,6 @@ protected:
|
|||
uint32_t flags,
|
||||
const mozilla::OriginAttributes &aOriginAttributes,
|
||||
nsIDNSRecord **result);
|
||||
|
||||
private:
|
||||
~nsDNSService();
|
||||
|
||||
|
@ -84,6 +84,7 @@ private:
|
|||
bool mOfflineLocalhost;
|
||||
bool mForceResolveOn;
|
||||
nsTHashtable<nsCStringHashKey> mLocalDomains;
|
||||
RefPtr<mozilla::net::TRRService> mTrrService;
|
||||
};
|
||||
|
||||
#endif //nsDNSService2_h__
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -15,19 +15,30 @@
|
|||
#include "nsISupportsImpl.h"
|
||||
#include "nsIDNSListener.h"
|
||||
#include "nsIDNSService.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "GetAddrInfo.h"
|
||||
#include "mozilla/net/DNS.h"
|
||||
#include "mozilla/net/DashboardTypes.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
|
||||
class nsHostResolver;
|
||||
class nsHostRecord;
|
||||
class nsResolveHostCallback;
|
||||
namespace mozilla { namespace net {
|
||||
class TRR;
|
||||
enum ResolverMode {
|
||||
MODE_NATIVEONLY, // TRR OFF
|
||||
MODE_PARALLEL, // race and use the first response
|
||||
MODE_TRRFIRST, // fallback to native on TRR failure
|
||||
MODE_TRRONLY, // don't even fallback
|
||||
MODE_SHADOW // race for stats, but always use native result
|
||||
};
|
||||
} }
|
||||
|
||||
extern mozilla::Atomic<bool, mozilla::Relaxed> gNativeIsLocalhost;
|
||||
|
||||
#define MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY 3
|
||||
#define MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY 5
|
||||
|
@ -41,15 +52,17 @@ struct nsHostKey
|
|||
const nsCString host;
|
||||
uint16_t flags;
|
||||
uint16_t af;
|
||||
bool pb;
|
||||
const nsCString netInterface;
|
||||
const nsCString originSuffix;
|
||||
|
||||
nsHostKey(const nsACString& host, uint16_t flags,
|
||||
uint16_t af, const nsACString& netInterface,
|
||||
uint16_t af, bool pb, const nsACString& netInterface,
|
||||
const nsACString& originSuffix)
|
||||
: host(host)
|
||||
, flags(flags)
|
||||
, af(af)
|
||||
, pb(pb)
|
||||
, netInterface(netInterface)
|
||||
, originSuffix(originSuffix) {
|
||||
}
|
||||
|
@ -114,6 +127,12 @@ public:
|
|||
// but a request to refresh it will be made.
|
||||
mozilla::TimeStamp mGraceStart;
|
||||
|
||||
// When the lookups of this record started and their durations
|
||||
mozilla::TimeStamp mTrrStart;
|
||||
mozilla::TimeStamp mNativeStart;
|
||||
mozilla::TimeDuration mTrrDuration;
|
||||
mozilla::TimeDuration mNativeDuration;
|
||||
|
||||
// Convenience function for setting the timestamps above (mValidStart,
|
||||
// mValidEnd, and mGraceStart). valid and grace are durations in seconds.
|
||||
void SetExpiration(const mozilla::TimeStamp& now, unsigned int valid,
|
||||
|
@ -139,6 +158,11 @@ public:
|
|||
|
||||
bool RemoveOrRefresh(); // Mark records currently being resolved as needed
|
||||
// to resolve again.
|
||||
bool IsTRR() { return mTRRUsed; }
|
||||
void ResolveComplete();
|
||||
void Cancel();
|
||||
|
||||
mozilla::net::ResolverMode mResolverMode;
|
||||
|
||||
private:
|
||||
friend class nsHostResolver;
|
||||
|
@ -146,17 +170,27 @@ private:
|
|||
explicit nsHostRecord(const nsHostKey& key);
|
||||
mozilla::LinkedList<RefPtr<nsResolveHostCallback>> mCallbacks;
|
||||
|
||||
bool resolving; /* true if this record is being resolved, which means
|
||||
* that it is either on the pending queue or owned by
|
||||
* one of the worker threads. */
|
||||
|
||||
bool onQueue; /* true if pending and on the queue (not yet given to getaddrinfo())*/
|
||||
bool usingAnyThread; /* true if off queue and contributing to mActiveAnyThreadCount */
|
||||
bool mDoomed; /* explicitly expired */
|
||||
|
||||
#if TTL_AVAILABLE
|
||||
int mResolving; // counter of outstanding resolving calls
|
||||
bool mNative; // true if this record is being resolved "natively",
|
||||
// which means that it is either on the pending queue
|
||||
// or owned by one of the worker threads. */
|
||||
int mTRRSuccess; // number of successful TRR responses
|
||||
bool mTRRUsed; // TRR was used on this record
|
||||
bool mNativeUsed;
|
||||
int mNativeSuccess; // number of native lookup responses
|
||||
nsAutoPtr<mozilla::net::AddrInfo> mFirstTRR; // partial TRR storage
|
||||
bool onQueue; // true if pending and on the queue (not yet given to getaddrinfo())
|
||||
bool usingAnyThread; // true if off queue and contributing to mActiveAnyThreadCount
|
||||
bool mDoomed; // explicitly expired
|
||||
bool mDidCallbacks;
|
||||
bool mGetTtl;
|
||||
#endif
|
||||
|
||||
enum {
|
||||
INIT, STARTED, OK, FAILED
|
||||
} mTrrAUsed, mTrrAAAAUsed;
|
||||
|
||||
RefPtr<mozilla::net::TRR> mTrrA;
|
||||
RefPtr<mozilla::net::TRR> mTrrAAAA;
|
||||
|
||||
// The number of times ReportUnusable() has been called in the record's
|
||||
// lifetime.
|
||||
|
@ -224,19 +258,43 @@ protected:
|
|||
virtual ~nsResolveHostCallback() = default;
|
||||
};
|
||||
|
||||
class AHostResolver
|
||||
{
|
||||
public:
|
||||
AHostResolver() {}
|
||||
virtual ~AHostResolver() {}
|
||||
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
|
||||
|
||||
enum LookupStatus {
|
||||
LOOKUP_OK,
|
||||
LOOKUP_RESOLVEAGAIN,
|
||||
};
|
||||
|
||||
virtual LookupStatus CompleteLookup(nsHostRecord *, nsresult, mozilla::net::AddrInfo *, bool pb) = 0;
|
||||
virtual nsresult GetHostRecord(const char *host,
|
||||
uint16_t flags, uint16_t af, bool pb,
|
||||
const nsCString &netInterface,
|
||||
const nsCString &originSuffix,
|
||||
nsHostRecord **result)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
virtual nsresult TrrLookup_unlocked(nsHostRecord *, mozilla::net::TRR *pushedTRR = nullptr)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* nsHostResolver - an asynchronous host name resolver.
|
||||
*/
|
||||
class nsHostResolver
|
||||
class nsHostResolver : public nsISupports, public AHostResolver
|
||||
{
|
||||
typedef mozilla::CondVar CondVar;
|
||||
typedef mozilla::Mutex Mutex;
|
||||
|
||||
public:
|
||||
/**
|
||||
* host resolver instances are reference counted.
|
||||
*/
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsHostResolver)
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
/**
|
||||
* creates an addref'd instance of a nsHostResolver object.
|
||||
|
@ -310,7 +368,8 @@ public:
|
|||
//RES_DISABLE_IPV6 = nsIDNSService::RESOLVE_DISABLE_IPV6, // Not used
|
||||
RES_OFFLINE = nsIDNSService::RESOLVE_OFFLINE,
|
||||
//RES_DISABLE_IPv4 = nsIDNSService::RESOLVE_DISABLE_IPV4, // Not Used
|
||||
RES_ALLOW_NAME_COLLISION = nsIDNSService::RESOLVE_ALLOW_NAME_COLLISION
|
||||
RES_ALLOW_NAME_COLLISION = nsIDNSService::RESOLVE_ALLOW_NAME_COLLISION,
|
||||
RES_DISABLE_TRR = nsIDNSService::RESOLVE_DISABLE_TRR
|
||||
};
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
|
@ -320,22 +379,30 @@ public:
|
|||
*/
|
||||
void FlushCache();
|
||||
|
||||
LookupStatus CompleteLookup(nsHostRecord *, nsresult, mozilla::net::AddrInfo *, bool pb) override;
|
||||
nsresult GetHostRecord(const char *host,
|
||||
uint16_t flags, uint16_t af, bool pb,
|
||||
const nsCString &netInterface,
|
||||
const nsCString &originSuffix,
|
||||
nsHostRecord **result) override;
|
||||
nsresult TrrLookup_unlocked(nsHostRecord *, mozilla::net::TRR *pushedTRR = nullptr) override;
|
||||
|
||||
private:
|
||||
explicit nsHostResolver(uint32_t maxCacheEntries,
|
||||
uint32_t defaultCacheEntryLifetime,
|
||||
uint32_t defaultGracePeriod);
|
||||
~nsHostResolver();
|
||||
virtual ~nsHostResolver();
|
||||
|
||||
nsresult Init();
|
||||
nsresult IssueLookup(nsHostRecord *);
|
||||
void AssertOnQ(nsHostRecord *, PRCList *);
|
||||
mozilla::net::ResolverMode Mode();
|
||||
nsresult NativeLookup(nsHostRecord *);
|
||||
nsresult TrrLookup(nsHostRecord *, mozilla::net::TRR *pushedTRR = nullptr);
|
||||
|
||||
// Kick-off a name resolve operation, using native resolver and/or TRR
|
||||
nsresult NameLookup(nsHostRecord *);
|
||||
bool GetHostToLookup(nsHostRecord **m);
|
||||
|
||||
enum LookupStatus {
|
||||
LOOKUP_OK,
|
||||
LOOKUP_RESOLVEAGAIN,
|
||||
};
|
||||
|
||||
LookupStatus CompleteLookup(nsHostRecord *, nsresult, mozilla::net::AddrInfo *);
|
||||
void DeQueue(PRCList &aQ, nsHostRecord **aResult);
|
||||
void ClearPendingQueue(PRCList *aPendingQueue);
|
||||
nsresult ConditionallyCreateThread(nsHostRecord *rec);
|
||||
|
|
|
@ -97,4 +97,9 @@ interface nsIDNSRecord : nsISupports
|
|||
* It may be zero if not applicable.
|
||||
*/
|
||||
void reportUnusable(in uint16_t aPort);
|
||||
|
||||
/**
|
||||
* Record retreived with TRR.
|
||||
*/
|
||||
bool IsTRR();
|
||||
};
|
||||
|
|
|
@ -233,4 +233,10 @@ interface nsIDNSService : nsISupports
|
|||
* If set, allow name collision results (127.0.53.53) which are normally filtered.
|
||||
*/
|
||||
const unsigned long RESOLVE_ALLOW_NAME_COLLISION = (1 << 8);
|
||||
|
||||
/**
|
||||
* If set, do not use TRR for resolving the host name.
|
||||
*/
|
||||
const unsigned long RESOLVE_DISABLE_TRR = (1 << 9);
|
||||
|
||||
};
|
||||
|
|
|
@ -154,7 +154,7 @@ public:
|
|||
|
||||
// below the emergency threshold of local window we ack every received
|
||||
// byte. Above that we coalesce bytes into the MinimumToAck size.
|
||||
const static int32_t kEmergencyWindowThreshold = 256 * 1024;
|
||||
const static int32_t kEmergencyWindowThreshold = 96 * 1024;
|
||||
const static uint32_t kMinimumToAck = 4 * 1024 * 1024;
|
||||
|
||||
// The default rwin is 64KB - 1 unless updated by a settings frame
|
||||
|
|
|
@ -183,6 +183,7 @@ HttpBaseChannel::HttpBaseChannel()
|
|||
, mAllowSpdy(true)
|
||||
, mAllowAltSvc(true)
|
||||
, mBeConservative(false)
|
||||
, mTRR(false)
|
||||
, mResponseTimeoutEnabled(true)
|
||||
, mAllRedirectsSameOrigin(true)
|
||||
, mAllRedirectsPassTimingAllowCheck(true)
|
||||
|
@ -2687,6 +2688,22 @@ HttpBaseChannel::SetBeConservative(bool aBeConservative)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpBaseChannel::GetTrr(bool *aTRR)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aTRR);
|
||||
|
||||
*aTRR = mTRR;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpBaseChannel::SetTrr(bool aTRR)
|
||||
{
|
||||
mTRR = aTRR;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpBaseChannel::GetTlsFlags(uint32_t *aTlsFlags)
|
||||
{
|
||||
|
@ -3612,6 +3629,8 @@ HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI,
|
|||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
rv = httpInternal->SetBeConservative(mBeConservative);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
rv = httpInternal->SetTrr(mTRR);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
rv = httpInternal->SetTlsFlags(mTlsFlags);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
|
||||
|
|
|
@ -236,6 +236,8 @@ public:
|
|||
NS_IMETHOD SetAllowAltSvc(bool aAllowAltSvc) override;
|
||||
NS_IMETHOD GetBeConservative(bool *aBeConservative) override;
|
||||
NS_IMETHOD SetBeConservative(bool aBeConservative) override;
|
||||
NS_IMETHOD GetTrr(bool *aTRR) override;
|
||||
NS_IMETHOD SetTrr(bool aTRR) override;
|
||||
NS_IMETHOD GetTlsFlags(uint32_t *aTlsFlags) override;
|
||||
NS_IMETHOD SetTlsFlags(uint32_t aTlsFlags) override;
|
||||
NS_IMETHOD GetApiRedirectToURI(nsIURI * *aApiRedirectToURI) override;
|
||||
|
@ -574,6 +576,7 @@ protected:
|
|||
uint32_t mAllowSpdy : 1;
|
||||
uint32_t mAllowAltSvc : 1;
|
||||
uint32_t mBeConservative : 1;
|
||||
uint32_t mTRR : 1;
|
||||
uint32_t mResponseTimeoutEnabled : 1;
|
||||
// A flag that should be false only if a cross-domain redirect occurred
|
||||
uint32_t mAllRedirectsSameOrigin : 1;
|
||||
|
|
|
@ -58,7 +58,7 @@ typedef uint8_t nsHttpVersion;
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define NS_HTTP_ALLOW_KEEPALIVE (1<<0)
|
||||
// NS_HTTP_ALLOW_PIPELINING (1<<1) removed
|
||||
#define NS_HTTP_LARGE_KEEPALIVE (1<<1)
|
||||
|
||||
// a transaction with this caps flag will continue to own the connection,
|
||||
// preventing it from being reclaimed, even after the transaction completes.
|
||||
|
|
|
@ -1010,6 +1010,9 @@ nsHttpChannel::SetupTransaction()
|
|||
|
||||
mUsedNetwork = 1;
|
||||
|
||||
if (mTRR) {
|
||||
mCaps |= NS_HTTP_LARGE_KEEPALIVE;
|
||||
}
|
||||
if (!mAllowSpdy) {
|
||||
mCaps |= NS_HTTP_DISALLOW_SPDY;
|
||||
}
|
||||
|
@ -3756,6 +3759,9 @@ nsHttpChannel::OpenCacheEntryInternal(bool isHttps,
|
|||
if (mPostID) {
|
||||
extension.Append(nsPrintfCString("%d", mPostID));
|
||||
}
|
||||
if (mTRR) {
|
||||
extension.Append("TRR");
|
||||
}
|
||||
|
||||
mCacheOpenWithPriority = cacheEntryOpenFlags & nsICacheStorage::OPEN_PRIORITY;
|
||||
mCacheQueueSizeWhenOpen = CacheStorageService::CacheQueueSize(mCacheOpenWithPriority);
|
||||
|
|
|
@ -81,6 +81,7 @@ nsHttpConnection::nsHttpConnection()
|
|||
, mEverUsedSpdy(false)
|
||||
, mLastHttpResponseVersion(NS_HTTP_VERSION_1_1)
|
||||
, mTransactionCaps(0)
|
||||
, mDefaultTimeoutFactor(1)
|
||||
, mResponseTimeoutEnabled(false)
|
||||
, mTCPKeepaliveConfig(kTCPKeepaliveDisabled)
|
||||
, mForceSendPending(false)
|
||||
|
@ -347,7 +348,7 @@ nsHttpConnection::StartSpdy(uint8_t spdyVersion)
|
|||
"rv[0x%" PRIx32 "]", this, static_cast<uint32_t>(rv)));
|
||||
}
|
||||
|
||||
mIdleTimeout = gHttpHandler->SpdyTimeout();
|
||||
mIdleTimeout = gHttpHandler->SpdyTimeout() * mDefaultTimeoutFactor;
|
||||
|
||||
if (!mTLSFilter) {
|
||||
mTransaction = mSpdySession;
|
||||
|
@ -643,6 +644,10 @@ nsHttpConnection::Activate(nsAHttpTransaction *trans, uint32_t caps, int32_t pri
|
|||
mBootstrappedTimings = TimingStruct();
|
||||
}
|
||||
|
||||
if (caps & NS_HTTP_LARGE_KEEPALIVE) {
|
||||
mDefaultTimeoutFactor = 10; // don't ever lower
|
||||
}
|
||||
|
||||
mTransactionCaps = caps;
|
||||
mPriority = pri;
|
||||
if (mTransaction && mUsingSpdyVersion) {
|
||||
|
@ -1043,14 +1048,20 @@ nsHttpConnection::IdleTime()
|
|||
uint32_t
|
||||
nsHttpConnection::TimeToLive()
|
||||
{
|
||||
if (IdleTime() >= mIdleTimeout)
|
||||
LOG(("nsHttpConnection::TTL: %p %s idle %d timeout %d\n",
|
||||
this, mConnInfo->Origin(), IdleTime(), mIdleTimeout));
|
||||
|
||||
if (IdleTime() >= mIdleTimeout) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t timeToLive = PR_IntervalToSeconds(mIdleTimeout - IdleTime());
|
||||
|
||||
// a positive amount of time can be rounded to 0. Because 0 is used
|
||||
// as the expiration signal, round all values from 0 to 1 up to 1.
|
||||
if (!timeToLive)
|
||||
if (!timeToLive) {
|
||||
timeToLive = 1;
|
||||
}
|
||||
return timeToLive;
|
||||
}
|
||||
|
||||
|
@ -1181,7 +1192,7 @@ nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans,
|
|||
if (cp)
|
||||
mIdleTimeout = PR_SecondsToInterval((uint32_t) atoi(cp + 8));
|
||||
else
|
||||
mIdleTimeout = gHttpHandler->IdleTimeout();
|
||||
mIdleTimeout = gHttpHandler->IdleTimeout() * mDefaultTimeoutFactor;
|
||||
|
||||
cp = PL_strcasestr(keepAlive.get(), "max=");
|
||||
if (cp) {
|
||||
|
@ -1192,9 +1203,6 @@ nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction *trans,
|
|||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
mIdleTimeout = gHttpHandler->SpdyTimeout();
|
||||
}
|
||||
|
||||
LOG(("Connection can be reused [this=%p idle-timeout=%usec]\n",
|
||||
this, PR_IntervalToSeconds(mIdleTimeout)));
|
||||
|
|
|
@ -380,6 +380,10 @@ private:
|
|||
// The capabailities associated with the most recent transaction
|
||||
uint32_t mTransactionCaps;
|
||||
|
||||
// If a large keepalive has been requested for any trans,
|
||||
// scale the default by this factor
|
||||
uint32_t mDefaultTimeoutFactor;
|
||||
|
||||
bool mResponseTimeoutEnabled;
|
||||
|
||||
// Flag to indicate connection is in inital keepalive period (fast detect).
|
||||
|
|
|
@ -257,7 +257,7 @@ nsHttpHandler::nsHttpHandler()
|
|||
, mEnableOriginExtension(false)
|
||||
, mSpdySendingChunkSize(ASpdySession::kSendingChunkSize)
|
||||
, mSpdySendBufferSize(ASpdySession::kTCPSendBufferSize)
|
||||
, mSpdyPushAllowance(32768)
|
||||
, mSpdyPushAllowance(131072) // match default pref
|
||||
, mSpdyPullAllowance(ASpdySession::kInitialRwin)
|
||||
, mDefaultSpdyConcurrent(ASpdySession::kDefaultMaxConcurrent)
|
||||
, mSpdyPingThreshold(PR_SecondsToInterval(58))
|
||||
|
|
|
@ -216,6 +216,12 @@ interface nsIHttpChannelInternal : nsISupports
|
|||
*/
|
||||
[must_use] attribute boolean beConservative;
|
||||
|
||||
/**
|
||||
* True if channel is used by the internal trusted recursive resolver
|
||||
* This flag places data for the request in a cache segment specific to TRR
|
||||
*/
|
||||
[noscript, must_use] attribute boolean trr;
|
||||
|
||||
/**
|
||||
* An opaque flags for non-standard behavior of the TLS system.
|
||||
* It is unlikely this will need to be set outside of telemetry studies
|
||||
|
|
|
@ -0,0 +1,448 @@
|
|||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
var prefs;
|
||||
var origin;
|
||||
var h2Port;
|
||||
|
||||
var dns = Cc["@mozilla.org/network/dns-service;1"].getService(Ci.nsIDNSService);
|
||||
var threadManager = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
|
||||
var mainThread = threadManager.currentThread;
|
||||
|
||||
const defaultOriginAttributes = {};
|
||||
|
||||
function run_test() {
|
||||
dump ("start!\n");
|
||||
|
||||
var env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
|
||||
h2Port = env.get("MOZHTTP2_PORT");
|
||||
Assert.notEqual(h2Port, null);
|
||||
Assert.notEqual(h2Port, "");
|
||||
|
||||
// Set to allow the cert presented by our H2 server
|
||||
do_get_profile();
|
||||
prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
|
||||
|
||||
prefs.setBoolPref("network.http.spdy.enabled", true);
|
||||
prefs.setBoolPref("network.http.spdy.enabled.http2", true);
|
||||
// the TRR server is on 127.0.0.1
|
||||
prefs.setCharPref("network.trr.bootstrapAddress", "127.0.0.1");
|
||||
|
||||
// use the h2 server as DOH provider
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns");
|
||||
// make all native resolve calls "secretly" resolve localhost instead
|
||||
prefs.setBoolPref("network.dns.native-is-localhost", true);
|
||||
|
||||
// 0 - off, 1 - race, 2 TRR first, 3 TRR only, 4 shadow
|
||||
prefs.setIntPref("network.trr.mode", 2); // TRR first
|
||||
prefs.setBoolPref("network.trr.wait-for-portal", false);
|
||||
// don't confirm that TRR is working, just go!
|
||||
prefs.setCharPref("network.trr.confirmationNS", "skip");
|
||||
|
||||
// The moz-http2 cert is for foo.example.com and is signed by CA.cert.der
|
||||
// so add that cert to the trust list as a signing cert. // the foo.example.com domain name.
|
||||
let certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
addCertFromFile(certdb, "CA.cert.der", "CTu,u,u");
|
||||
do_test_pending();
|
||||
run_dns_tests();
|
||||
}
|
||||
|
||||
function resetTRRPrefs() {
|
||||
prefs.clearUserPref("network.trr.mode");
|
||||
prefs.clearUserPref("network.trr.uri");
|
||||
prefs.clearUserPref("network.trr.credentials");
|
||||
prefs.clearUserPref("network.trr.wait-for-portal");
|
||||
prefs.clearUserPref("network.trr.allow-rfc1918");
|
||||
prefs.clearUserPref("network.trr.useGET");
|
||||
prefs.clearUserPref("network.trr.confirmationNS");
|
||||
prefs.clearUserPref("network.trr.bootstrapAddress");
|
||||
prefs.clearUserPref("network.trr.blacklist-duration");
|
||||
prefs.clearUserPref("network.trr.request-timeout");
|
||||
}
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
prefs.clearUserPref("network.http.spdy.enabled");
|
||||
prefs.clearUserPref("network.http.spdy.enabled.http2");
|
||||
prefs.clearUserPref("network.dns.localDomains");
|
||||
prefs.clearUserPref("network.dns.native-is-localhost");
|
||||
resetTRRPrefs();
|
||||
});
|
||||
|
||||
function readFile(file) {
|
||||
let fstream = Cc["@mozilla.org/network/file-input-stream;1"]
|
||||
.createInstance(Ci.nsIFileInputStream);
|
||||
fstream.init(file, -1, 0, 0);
|
||||
let data = NetUtil.readInputStreamToString(fstream, fstream.available());
|
||||
fstream.close();
|
||||
return data;
|
||||
}
|
||||
|
||||
function addCertFromFile(certdb, filename, trustString) {
|
||||
let certFile = do_get_file(filename, false);
|
||||
let der = readFile(certFile);
|
||||
certdb.addCert(der, trustString);
|
||||
}
|
||||
|
||||
function testsDone()
|
||||
{
|
||||
do_test_finished();
|
||||
do_test_finished();
|
||||
}
|
||||
|
||||
var test_loops;
|
||||
var test_answer="127.0.0.1";
|
||||
|
||||
// check that we do lookup the name fine
|
||||
var listenerFine = {
|
||||
onLookupComplete: function(inRequest, inRecord, inStatus) {
|
||||
if (inRequest == listen) {
|
||||
Assert.ok(!inStatus);
|
||||
var answer = inRecord.getNextAddrAsString();
|
||||
Assert.equal(answer, test_answer);
|
||||
do_test_finished();
|
||||
run_dns_tests();
|
||||
}
|
||||
},
|
||||
QueryInterface: function(aIID) {
|
||||
if (aIID.equals(Ci.nsIDNSListener) ||
|
||||
aIID.equals(Ci.nsISupports)) {
|
||||
return this;
|
||||
}
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
};
|
||||
|
||||
// check that the name lookup fails
|
||||
var listenerFails = {
|
||||
onLookupComplete: function(inRequest, inRecord, inStatus) {
|
||||
if (inRequest == listen) {
|
||||
Assert.ok(!Components.isSuccessCode(inStatus));
|
||||
do_test_finished();
|
||||
run_dns_tests();
|
||||
}
|
||||
},
|
||||
QueryInterface: function(aIID) {
|
||||
if (aIID.equals(Ci.nsIDNSListener) ||
|
||||
aIID.equals(Ci.nsISupports)) {
|
||||
return this;
|
||||
}
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
};
|
||||
|
||||
// check that we do lookup the name fine
|
||||
var listenerUntilFine = {
|
||||
onLookupComplete: function(inRequest, inRecord, inStatus) {
|
||||
if ((inRequest == listen) && (inRecord != null)) {
|
||||
var answer = inRecord.getNextAddrAsString();
|
||||
if (answer == test_answer) {
|
||||
Assert.equal(answer, test_answer);
|
||||
dump("Got what we were waiting for!\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
// not the one we want, try again
|
||||
dump("Waiting for " + test_answer + " but got " + answer + "\n");
|
||||
--test_loops;
|
||||
Assert.ok(test_loops != 0);
|
||||
current_test--;
|
||||
}
|
||||
do_test_finished();
|
||||
run_dns_tests();
|
||||
},
|
||||
QueryInterface: function(aIID) {
|
||||
if (aIID.equals(Ci.nsIDNSListener) ||
|
||||
aIID.equals(Ci.nsISupports)) {
|
||||
return this;
|
||||
}
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
};
|
||||
|
||||
var listen;
|
||||
|
||||
// verify basic A record
|
||||
function test1()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 2); // TRR-first
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns");
|
||||
test_answer="127.0.0.1";
|
||||
listen = dns.asyncResolve("bar.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// verify basic A record - without bootstrapping
|
||||
function test1b()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns");
|
||||
prefs.clearUserPref("network.trr.bootstrapAddress");
|
||||
prefs.setCharPref("network.dns.localDomains", "foo.example.com");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("bar.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// verify that the name was put in cache - it works with bad DNS URI
|
||||
function test2()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
//prefs.clearUserPref("network.trr.bootstrapAddress");
|
||||
//prefs.setCharPref("network.dns.localDomains", "foo.example.com");
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/404");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("bar.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// verify working credentials in DOH request
|
||||
function test3()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-auth");
|
||||
prefs.setCharPref("network.trr.credentials", "user:password");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("auth.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// verify failing credentials in DOH request
|
||||
function test4()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-auth");
|
||||
prefs.setCharPref("network.trr.credentials", "evil:person");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("wrong.example.com", 0, listenerFails, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// verify DOH push, part A
|
||||
function test5()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-push");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("first.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
function test5b()
|
||||
{
|
||||
// At this point the second host name should've been pushed and we can resolve it using
|
||||
// cache only. Set back the URI to a path that fails.
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/404");
|
||||
dump("test5b - resolve push.example.now please\n");
|
||||
test_answer = "2018::2018";
|
||||
listen = dns.asyncResolve("push.example.com", 0, listenerUntilFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// verify AAAA entry
|
||||
function test6()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-aaaa");
|
||||
test_answer = "2020:2020::2020";
|
||||
listen = dns.asyncResolve("aaaa.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// verify RFC1918 address from the server is rejected
|
||||
function test7()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-rfc1918");
|
||||
listen = dns.asyncResolve("rfc1918.example.com", 0, listenerFails, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// verify RFC1918 address from the server is fine when told so
|
||||
function test8()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-rfc1918");
|
||||
prefs.setBoolPref("network.trr.allow-rfc1918", true);
|
||||
test_answer = "192.168.0.1";
|
||||
listen = dns.asyncResolve("rfc1918.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// use GET
|
||||
function test9()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-get");
|
||||
prefs.clearUserPref("network.trr.allow-rfc1918");
|
||||
prefs.setBoolPref("network.trr.useGET", true);
|
||||
test_answer = "1.2.3.4";
|
||||
listen = dns.asyncResolve("get.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// confirmationNS set without confirmed NS yet
|
||||
// NOTE: this requires test9 to run before, as the http2 server resets state there
|
||||
function test10()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.clearUserPref("network.trr.useGET");
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-confirm");
|
||||
prefs.setCharPref("network.trr.confirmationNS", "confirm.example.com");
|
||||
test_loops = 100; // set for test10b
|
||||
try {
|
||||
listen = dns.asyncResolve("wrong.example.com", 0, listenerFails,
|
||||
mainThread, defaultOriginAttributes);
|
||||
} catch (e) {
|
||||
// NS_ERROR_UNKNOWN_HOST exception is expected
|
||||
do_test_finished();
|
||||
run_dns_tests();
|
||||
}
|
||||
}
|
||||
|
||||
// confirmationNS, retry until the confirmed NS works
|
||||
function test10b()
|
||||
{
|
||||
print("test confirmationNS, retry until the confirmed NS works");
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
// same URI as in test10
|
||||
test_answer = "1::ffff"
|
||||
// this test needs to resolve new names in every attempt since the DNS cache
|
||||
// will keep the negative resolved info
|
||||
try {
|
||||
listen = dns.asyncResolve("10b-" + test_loops + ".example.com", 0, listenerUntilFine,
|
||||
mainThread, defaultOriginAttributes);
|
||||
} catch(e) {
|
||||
// wait a while and try again
|
||||
test_loops--;
|
||||
do_timeout(200, test10b);
|
||||
}
|
||||
}
|
||||
// use a slow server and short timeout!
|
||||
function test11()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.confirmationNS", "skip");
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-750ms");
|
||||
prefs.setIntPref("network.trr.request-timeout", 10);
|
||||
listen = dns.asyncResolve("test11.example.com", 0, listenerFails, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// gets an NS back from DOH
|
||||
function test12()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 2); // TRR-first
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-ns");
|
||||
prefs.clearUserPref("network.trr.request-timeout");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("test12.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-first gets a 404 back from DOH
|
||||
function test13()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 2); // TRR-first
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/404");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("test13.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-shadow gets a 404 back from DOH
|
||||
function test14()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 4); // TRR-shadow
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/404");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("test14.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-shadow and timed out TRR
|
||||
function test15()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 4); // TRR-shadow
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-750ms");
|
||||
prefs.setIntPref("network.trr.request-timeout", 10);
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("test15.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-first and timed out TRR
|
||||
function test16()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 2); // TRR-first
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-750ms");
|
||||
prefs.setIntPref("network.trr.request-timeout", 10);
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("test16.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-only and chase CNAME
|
||||
function test17()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-cname");
|
||||
prefs.clearUserPref("network.trr.request-timeout");
|
||||
test_answer = "99.88.77.66";
|
||||
listen = dns.asyncResolve("cname.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-only and a CNAME loop
|
||||
function test18()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 3); // TRR-only
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-cname-loop");
|
||||
listen = dns.asyncResolve("test18.example.com", 0, listenerFails, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-race and a CNAME loop
|
||||
function test19()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 1); // Race them!
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-cname-loop");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("test19.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-first and a CNAME loop
|
||||
function test20()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 2); // TRR-first
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-cname-loop");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("test20.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
// TRR-shadow and a CNAME loop
|
||||
function test21()
|
||||
{
|
||||
prefs.setIntPref("network.trr.mode", 4); // TRR-first
|
||||
prefs.setCharPref("network.trr.uri", "https://foo.example.com:" + h2Port + "/dns-cname-loop");
|
||||
test_answer = "127.0.0.1";
|
||||
listen = dns.asyncResolve("test21.example.com", 0, listenerFine, mainThread, defaultOriginAttributes);
|
||||
}
|
||||
|
||||
var tests = [ test1,
|
||||
test1b,
|
||||
test2,
|
||||
test3,
|
||||
test4,
|
||||
test5,
|
||||
test5b,
|
||||
test6,
|
||||
test7,
|
||||
test8,
|
||||
test9,
|
||||
test10,
|
||||
test10b,
|
||||
test11,
|
||||
test12,
|
||||
test13,
|
||||
test14,
|
||||
test15,
|
||||
test16,
|
||||
test17,
|
||||
test18,
|
||||
test19,
|
||||
test20,
|
||||
test21,
|
||||
testsDone
|
||||
];
|
||||
|
||||
var current_test = 0;
|
||||
|
||||
function run_dns_tests()
|
||||
{
|
||||
if (current_test < tests.length) {
|
||||
dump("starting test " + current_test + "\n");
|
||||
do_test_pending();
|
||||
tests[current_test++]();
|
||||
}
|
||||
}
|
|
@ -412,3 +412,6 @@ skip-if = os == "android"
|
|||
[test_uri_mutator.js]
|
||||
[test_bug1411316_http1.js]
|
||||
[test_header_Server_Timing.js]
|
||||
[test_trr.js]
|
||||
# http2-using tests require node available
|
||||
skip-if = os == "android"
|
||||
|
|
|
@ -16,3 +16,4 @@
|
|||
DATA_STORAGE(AlternateServices)
|
||||
DATA_STORAGE(SecurityPreloadState)
|
||||
DATA_STORAGE(SiteSecurityServiceState)
|
||||
DATA_STORAGE(TRRBlacklist)
|
||||
|
|
|
@ -194,6 +194,9 @@ var didRst = false;
|
|||
var rstConnection = null;
|
||||
var illegalheader_conn = null;
|
||||
|
||||
var ns_confirm = 0;
|
||||
var cname_confirm = 0;
|
||||
|
||||
function handleRequest(req, res) {
|
||||
// We do this first to ensure nothing goes wonky in our tests that don't want
|
||||
// the headers to have something illegal in them
|
||||
|
@ -526,6 +529,163 @@ function handleRequest(req, res) {
|
|||
res.setHeader('Cache-Control', 'no-cache');
|
||||
res.setHeader('Alt-Svc', 'h2=' + req.headers['x-altsvc']);
|
||||
}
|
||||
// for use with test_trr.js
|
||||
else if (u.pathname === "/dns-cname") {
|
||||
// asking for cname.example.com
|
||||
var content;
|
||||
if(0 == cname_confirm) {
|
||||
// ... this sends a CNAME back to pointing-elsewhere.example.com
|
||||
content = new Buffer("00000100000100010000000005636E616D65076578616D706C6503636F6D0000050001C00C0005000100000037002012706F696E74696E672D656C73657768657265076578616D706C6503636F6D00", "hex");
|
||||
cname_confirm++;
|
||||
}
|
||||
else {
|
||||
// ... this sends an A 99.88.77.66 entry back for pointing-elsewhere.example.com
|
||||
content = new Buffer("00000100000100010000000012706F696E74696E672D656C73657768657265076578616D706C6503636F6D0000010001C00C0001000100000037000463584D42", "hex");
|
||||
}
|
||||
res.setHeader('Content-Type', 'application/dns-udpwireformat');
|
||||
res.setHeader('Content-Length', content.length);
|
||||
res.writeHead(200);
|
||||
res.write(content);
|
||||
res.end("");
|
||||
return;
|
||||
|
||||
}
|
||||
else if (u.pathname === "/dns-cname-loop") {
|
||||
// asking for cname.example.com
|
||||
var content;
|
||||
// ... this always sends a CNAME back to pointing-elsewhere.example.com. Loop time!
|
||||
content = new Buffer("00000100000100010000000005636E616D65076578616D706C6503636F6D0000050001C00C0005000100000037002012706F696E74696E672D656C73657768657265076578616D706C6503636F6D00", "hex");
|
||||
res.setHeader('Content-Type', 'application/dns-udpwireformat');
|
||||
res.setHeader('Content-Length', content.length);
|
||||
res.writeHead(200);
|
||||
res.write(content);
|
||||
res.end("");
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// for use with test_trr.js
|
||||
else if (u.path === "/dns-get?ct&dns=AAAAAAABAAAAAAAAA2dldAdleGFtcGxlA2NvbQAAAQAB") {
|
||||
// the query string asks for an A entry for get.example.com
|
||||
// get.example.com has A entry 1.2.3.4
|
||||
var content= new Buffer("00000100000100010000000003676574076578616D706C6503636F6D0000010001C00C0001000100000037000401020304", "hex");
|
||||
res.setHeader('Content-Type', 'application/dns-udpwireformat');
|
||||
res.setHeader('Content-Length', content.length);
|
||||
res.writeHead(200);
|
||||
res.write(content);
|
||||
res.end("");
|
||||
ns_confirm = 0; // back to first reply for dns-confirm
|
||||
cname_confirm = 0; // back to first reply for dns-cname
|
||||
return;
|
||||
}
|
||||
// for use with test_trr.js
|
||||
else if (u.pathname === "/dns") {
|
||||
// bar.example.com has A entry 127.0.0.1
|
||||
var content= new Buffer("00000100000100010000000003626172076578616D706C6503636F6D0000010001C00C000100010000003700047F000001", "hex");
|
||||
res.setHeader('Content-Type', 'application/dns-udpwireformat');
|
||||
res.setHeader('Content-Length', content.length);
|
||||
res.writeHead(200);
|
||||
res.write(content);
|
||||
res.end("");
|
||||
return;
|
||||
}
|
||||
else if (u.pathname === "/dns-ns") {
|
||||
// confirm.example.com has NS entry ns.example.com
|
||||
var content= new Buffer("00000100000100010000000007636F6E6669726D076578616D706C6503636F6D0000020001C00C00020001000000370012026E73076578616D706C6503636F6D010A00", "hex");
|
||||
res.setHeader('Content-Type', 'application/dns-udpwireformat');
|
||||
res.setHeader('Content-Length', content.length);
|
||||
res.writeHead(200);
|
||||
res.write(content);
|
||||
res.end("");
|
||||
return;
|
||||
}
|
||||
else if (u.pathname === '/dns-750ms') {
|
||||
// it's just meant to be this slow - the test doesn't care about the actual response
|
||||
return;
|
||||
}
|
||||
// for use with test_trr.js
|
||||
else if (u.pathname === "/dns-confirm") {
|
||||
if (0 == ns_confirm) {
|
||||
// confirm.example.com has NS entry ns.example.com
|
||||
var content= new Buffer("00000100000100010000000007636F6E6669726D076578616D706C6503636F6D0000020001C00C00020001000000370012026E73076578616D706C6503636F6D010A00", "hex");
|
||||
ns_confirm++;
|
||||
} else {
|
||||
// next response: wrong.example.com has AAAA entry 1::FFFF
|
||||
var content= new Buffer("0000010000010001000000000577726F6E67076578616D706C6503636F6D00001C0001C00C001C00010000003700100001000000000000000000000000FFFF", "hex");
|
||||
}
|
||||
res.setHeader('Content-Type', 'application/dns-udpwireformat');
|
||||
res.setHeader('Content-Length', content.length);
|
||||
res.writeHead(200);
|
||||
res.write(content);
|
||||
res.end("");
|
||||
return;
|
||||
}
|
||||
// for use with test_trr.js
|
||||
else if (u.pathname === "/dns-aaaa") {
|
||||
// aaaa.example.com has AAAA entry 2020:2020::2020
|
||||
var content= new Buffer("0000010000010001000000000461616161076578616D706C6503636F6D00001C0001C00C001C000100000037001020202020000000000000000000002020", "hex");
|
||||
res.setHeader('Content-Type', 'application/dns-udpwireformat');
|
||||
res.setHeader('Content-Length', content.length);
|
||||
res.writeHead(200);
|
||||
res.write(content);
|
||||
res.end("");
|
||||
return;
|
||||
}
|
||||
else if (u.pathname === "/dns-rfc1918") {
|
||||
// rfc1918.example.com has A entry 192.168.0.1
|
||||
var content= new Buffer("0000010000010001000000000772666331393138076578616D706C6503636F6D0000010001C00C00010001000000370004C0A80001", "hex");
|
||||
res.setHeader('Content-Type', 'application/dns-udpwireformat');
|
||||
res.setHeader('Content-Length', content.length);
|
||||
res.writeHead(200);
|
||||
res.write(content);
|
||||
res.end("");
|
||||
return;
|
||||
}
|
||||
// for use with test_trr.js
|
||||
else if (u.pathname === "/dns-push") {
|
||||
// first.example.com has A entry 127.0.0.1
|
||||
var content= new Buffer("000001000001000100000000056669727374076578616D706C6503636F6D0000010001C00C000100010000003700047F000001", "hex");
|
||||
// push.example.com has AAAA entry 2018::2018
|
||||
var pcontent= new Buffer("0000010000010001000000000470757368076578616D706C6503636F6D00001C0001C00C001C000100000037001020180000000000000000000000002018", "hex");
|
||||
push = res.push({
|
||||
hostname: 'foo.example.com:' + serverPort,
|
||||
port: serverPort,
|
||||
path: '/dns-pushed-response?ct&dns=AAAAAAABAAAAAAAABHB1c2gHZXhhbXBsZQNjb20AABwAAQ',
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'accept' : 'application/dns-udpwireformat'
|
||||
}
|
||||
});
|
||||
push.writeHead(200, {
|
||||
'content-type': 'application/dns-udpwireformat',
|
||||
'pushed' : 'yes',
|
||||
'content-length' : pcontent.length,
|
||||
'X-Connection-Http2': 'yes'
|
||||
});
|
||||
push.end(pcontent);
|
||||
res.setHeader('Content-Type', 'application/dns-udpwireformat');
|
||||
res.setHeader('Content-Length', content.length);
|
||||
res.writeHead(200);
|
||||
res.write(content);
|
||||
res.end("");
|
||||
return;
|
||||
}
|
||||
// for use with test_trr.js
|
||||
else if (u.pathname === "/dns-auth") {
|
||||
if (req.headers['authorization'] != "user:password") {
|
||||
res.writeHead(401);
|
||||
res.end("bad boy!");
|
||||
return;
|
||||
}
|
||||
// bar.example.com has A entry 127.0.0.1
|
||||
var content= new Buffer("00000100000100010000000003626172076578616D706C6503636F6D0000010001C00C000100010000003700047F000001", "hex");
|
||||
res.setHeader('Content-Type', 'application/dns-udpwireformat');
|
||||
res.setHeader('Content-Length', content.length);
|
||||
res.writeHead(200);
|
||||
res.write(content);
|
||||
res.end("");
|
||||
return;
|
||||
}
|
||||
|
||||
else if (u.pathname === "/.well-known/http-opportunistic") {
|
||||
res.setHeader('Cache-Control', 'no-cache');
|
||||
|
|
|
@ -3612,7 +3612,7 @@
|
|||
"description": "I want to be tracked, I do NOT want to be tracked, DNT unset"
|
||||
},
|
||||
"DNS_LOOKUP_METHOD2": {
|
||||
"record_in_processes": ["main", "content"],
|
||||
"record_in_processes": ["main"],
|
||||
"expires_in_version": "never",
|
||||
"kind": "enumerated",
|
||||
"n_values": 16,
|
||||
|
@ -3621,7 +3621,7 @@
|
|||
"description": "DNS Lookup Type (hit, renewal, negative-hit, literal, overflow, network-first, network-shared)"
|
||||
},
|
||||
"DNS_CLEANUP_AGE": {
|
||||
"record_in_processes": ["main", "content"],
|
||||
"record_in_processes": ["main"],
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": 1440,
|
||||
|
@ -3629,17 +3629,75 @@
|
|||
"description": "DNS Cache Entry Age at Removal Time (minutes)"
|
||||
},
|
||||
"DNS_LOOKUP_TIME": {
|
||||
"record_in_processes": ["main", "content"],
|
||||
"record_in_processes": ["main"],
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": 60000,
|
||||
"releaseChannelCollection": "opt-out",
|
||||
"alert_emails": ["necko@mozilla.com", "pmcmanus@mozilla.com"],
|
||||
"n_buckets": 50,
|
||||
"description": "Time for a successful DNS OS resolution (msec)"
|
||||
"description": "Time for a successful DNS resolution (msec)"
|
||||
},
|
||||
"DNS_TRR_LOOKUP_TIME": {
|
||||
"record_in_processes": ["main"],
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": 60000,
|
||||
"releaseChannelCollection": "opt-out",
|
||||
"alert_emails": ["necko@mozilla.com", "dstenberg@mozilla.com"],
|
||||
"bug_numbers": [1434852],
|
||||
"n_buckets": 50,
|
||||
"description": "Time for a completed TRR resolution (msec)"
|
||||
},
|
||||
"DNS_NATIVE_LOOKUP_TIME": {
|
||||
"record_in_processes": ["main"],
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": 60000,
|
||||
"releaseChannelCollection": "opt-out",
|
||||
"alert_emails": ["necko@mozilla.com", "dstenberg@mozilla.com"],
|
||||
"bug_numbers": [1434852],
|
||||
"n_buckets": 50,
|
||||
"description": "Time for a completed native name resolution (msec)"
|
||||
},
|
||||
"DNS_TRR_RACE": {
|
||||
"record_in_processes": ["main"],
|
||||
"alert_emails": ["necko@mozilla.com", "dstenberg@mozilla.com"],
|
||||
"expires_in_version": "never",
|
||||
"kind": "categorical",
|
||||
"labels": ["TRRFasterBy50", "TRRFaster", "NativeFaster", "NativeFasterBy50"],
|
||||
"bug_numbers": [1434852],
|
||||
"description": "DNS: TRR parallel resolve racing results"
|
||||
},
|
||||
"DNS_TRR_BLACKLISTED": {
|
||||
"record_in_processes": ["main"],
|
||||
"expires_in_version": "never",
|
||||
"kind": "boolean",
|
||||
"description": "DNS check for TRR was blocked by blacklist",
|
||||
"bug_numbers": [1434852],
|
||||
"alert_emails": ["necko@mozilla.com", "dstenberg@mozilla.com"]
|
||||
},
|
||||
"DNS_LOOKUP_ALGORITHM": {
|
||||
"record_in_processes": ["main"],
|
||||
"alert_emails": ["necko@mozilla.com", "dstenberg@mozilla.com"],
|
||||
"expires_in_version": "never",
|
||||
"kind": "categorical",
|
||||
"labels": ["nativeOnly", "trrRace", "trrFirst", "trrOnly", "trrShadow"],
|
||||
"bug_numbers": [1434852],
|
||||
"description": "DNS: lookup algorithm"
|
||||
},
|
||||
"DNS_LOOKUP_DISPOSITION": {
|
||||
"record_in_processes": ["main"],
|
||||
"alert_emails": ["necko@mozilla.com", "dstenberg@mozilla.com"],
|
||||
"expires_in_version": "never",
|
||||
"kind": "categorical",
|
||||
"labels": ["trrOK", "trrFail", "trrAOK", "trrAFail",
|
||||
"trrAAAAOK", "trrAAAAFail", "osOK", "osFail"],
|
||||
"bug_numbers": [1434852],
|
||||
"description": "DNS: lookup algorithm"
|
||||
},
|
||||
"DNS_RENEWAL_TIME": {
|
||||
"record_in_processes": ["main", "content"],
|
||||
"record_in_processes": ["main"],
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": 60000,
|
||||
|
@ -3647,7 +3705,7 @@
|
|||
"description": "Time for a renewed DNS OS resolution (msec)"
|
||||
},
|
||||
"DNS_RENEWAL_TIME_FOR_TTL": {
|
||||
"record_in_processes": ["main", "content"],
|
||||
"record_in_processes": ["main"],
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": 60000,
|
||||
|
@ -3655,7 +3713,7 @@
|
|||
"description": "Time for a DNS OS resolution (msec) used to get TTL"
|
||||
},
|
||||
"DNS_FAILED_LOOKUP_TIME": {
|
||||
"record_in_processes": ["main", "content"],
|
||||
"record_in_processes": ["main"],
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": 60000,
|
||||
|
@ -3665,7 +3723,7 @@
|
|||
"description": "Time for an unsuccessful DNS OS resolution (msec)"
|
||||
},
|
||||
"DNS_BLACKLIST_COUNT": {
|
||||
"record_in_processes": ["main", "content"],
|
||||
"record_in_processes": ["main"],
|
||||
"expires_in_version": "never",
|
||||
"releaseChannelCollection": "opt-out",
|
||||
"alert_emails": ["necko@mozilla.com", "pmcmanus@mozilla.com"],
|
||||
|
|
Загрузка…
Ссылка в новой задаче