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:
Daniel Stenberg 2018-02-01 10:20:49 +01:00
Родитель 0912c2657b
Коммит e5d3226694
34 изменённых файлов: 3400 добавлений и 219 удалений

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

@ -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,

1047
netwerk/dns/TRR.cpp Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

170
netwerk/dns/TRR.h Normal file
Просмотреть файл

@ -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

510
netwerk/dns/TRRService.cpp Normal file
Просмотреть файл

@ -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

88
netwerk/dns/TRRService.h Normal file
Просмотреть файл

@ -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"],