Bug 1473736 - Implement necko part of ESNI r=mcmanus

Implement necko part of ESNI

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Dragana Damjanovic 2018-09-17 23:08:14 +00:00
parent c24ed5f87b
commit f000a5b4b0
56 changed files with 1748 additions and 307 deletions

View File

@ -908,6 +908,7 @@ void
nsContentSink::PrefetchDNS(const nsAString &aHref)
{
nsAutoString hostname;
bool isHttps = false;
if (StringBeginsWith(aHref, NS_LITERAL_STRING("//"))) {
hostname = Substring(aHref, 2);
@ -927,10 +928,11 @@ nsContentSink::PrefetchDNS(const nsAString &aHref)
uri->GetHost(host);
CopyUTF8toUTF16(host, hostname);
}
uri->SchemeIs("https", &isHttps);
}
if (!hostname.IsEmpty() && nsHTMLDNSPrefetch::IsAllowed(mDocument)) {
nsHTMLDNSPrefetch::PrefetchLow(hostname,
nsHTMLDNSPrefetch::PrefetchLow(hostname, isHttps,
mDocument->NodePrincipal()->OriginAttributesRef());
}
}

View File

@ -43,6 +43,7 @@ static bool sInitialized = false;
static nsIDNSService *sDNSService = nullptr;
static nsHTMLDNSPrefetch::nsDeferrals *sPrefetches = nullptr;
static nsHTMLDNSPrefetch::nsListener *sDNSListener = nullptr;
bool sEsniEnabled;
nsresult
nsHTMLDNSPrefetch::Initialize()
@ -63,10 +64,15 @@ nsHTMLDNSPrefetch::Initialize()
Preferences::AddBoolVarCache(&sDisablePrefetchHTTPSPref,
"network.dns.disablePrefetchFromHTTPS");
Preferences::AddBoolVarCache(&sEsniEnabled,
"network.security.esni.enabled");
// Default is false, so we need an explicit call to prime the cache.
sDisablePrefetchHTTPSPref =
Preferences::GetBool("network.dns.disablePrefetchFromHTTPS", true);
sEsniEnabled = Preferences::GetBool("network.security.esni.enabled", false);
NS_IF_RELEASE(sDNSService);
nsresult rv;
rv = CallGetService(kDNSServiceCID, &sDNSService);
@ -129,7 +135,7 @@ nsHTMLDNSPrefetch::PrefetchHigh(Link *aElement)
}
nsresult
nsHTMLDNSPrefetch::Prefetch(const nsAString &hostname,
nsHTMLDNSPrefetch::Prefetch(const nsAString &hostname, bool isHttps,
const OriginAttributes &aOriginAttributes,
uint16_t flags)
{
@ -140,7 +146,7 @@ nsHTMLDNSPrefetch::Prefetch(const nsAString &hostname,
net_IsValidHostName(NS_ConvertUTF16toUTF8(hostname))) {
// during shutdown gNeckoChild might be null
if (gNeckoChild) {
gNeckoChild->SendHTMLDNSPrefetch(nsString(hostname),
gNeckoChild->SendHTMLDNSPrefetch(nsString(hostname), isHttps,
aOriginAttributes, flags);
}
}
@ -151,31 +157,50 @@ nsHTMLDNSPrefetch::Prefetch(const nsAString &hostname,
return NS_ERROR_NOT_AVAILABLE;
nsCOMPtr<nsICancelable> tmpOutstanding;
return sDNSService->AsyncResolveNative(NS_ConvertUTF16toUTF8(hostname),
flags | nsIDNSService::RESOLVE_SPECULATE,
sDNSListener, nullptr, aOriginAttributes,
getter_AddRefs(tmpOutstanding));
nsresult rv = sDNSService->AsyncResolveNative(NS_ConvertUTF16toUTF8(hostname),
flags | nsIDNSService::RESOLVE_SPECULATE,
sDNSListener, nullptr, aOriginAttributes,
getter_AddRefs(tmpOutstanding));
if (NS_FAILED(rv)) {
return rv;
}
// Fetch ESNI keys if needed.
if (isHttps && sEsniEnabled) {
nsAutoCString esniHost;
esniHost.Append("_esni.");
esniHost.Append(NS_ConvertUTF16toUTF8(hostname));
Unused << sDNSService->AsyncResolveByTypeNative(esniHost,
nsIDNSService::RESOLVE_TYPE_TXT,
flags | nsIDNSService::RESOLVE_SPECULATE,
sDNSListener, nullptr, aOriginAttributes,
getter_AddRefs(tmpOutstanding));
}
return NS_OK;
}
nsresult
nsHTMLDNSPrefetch::PrefetchLow(const nsAString &hostname,
nsHTMLDNSPrefetch::PrefetchLow(const nsAString &hostname, bool isHttps,
const OriginAttributes &aOriginAttributes)
{
return Prefetch(hostname, aOriginAttributes, nsIDNSService::RESOLVE_PRIORITY_LOW);
return Prefetch(hostname, isHttps, aOriginAttributes,
nsIDNSService::RESOLVE_PRIORITY_LOW);
}
nsresult
nsHTMLDNSPrefetch::PrefetchMedium(const nsAString &hostname,
nsHTMLDNSPrefetch::PrefetchMedium(const nsAString &hostname, bool isHttps,
const OriginAttributes &aOriginAttributes)
{
return Prefetch(hostname, aOriginAttributes, nsIDNSService::RESOLVE_PRIORITY_MEDIUM);
return Prefetch(hostname, isHttps, aOriginAttributes,
nsIDNSService::RESOLVE_PRIORITY_MEDIUM);
}
nsresult
nsHTMLDNSPrefetch::PrefetchHigh(const nsAString &hostname,
nsHTMLDNSPrefetch::PrefetchHigh(const nsAString &hostname, bool isHttps,
const OriginAttributes &aOriginAttributes)
{
return Prefetch(hostname, aOriginAttributes, 0);
return Prefetch(hostname, isHttps, aOriginAttributes, 0);
}
nsresult
@ -192,14 +217,20 @@ nsHTMLDNSPrefetch::CancelPrefetch(Link *aElement,
Element* element = aElement->GetElement();
NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
return CancelPrefetch(hostname,
nsAutoString protocol;
aElement->GetProtocol(protocol);
bool isHttps = false;
if (protocol.EqualsLiteral("https:")) {
isHttps = true;
}
return CancelPrefetch(hostname, isHttps,
element->NodePrincipal()
->OriginAttributesRef(),
flags, aReason);
}
nsresult
nsHTMLDNSPrefetch::CancelPrefetch(const nsAString &hostname,
nsHTMLDNSPrefetch::CancelPrefetch(const nsAString &hostname, bool isHttps,
const OriginAttributes &aOriginAttributes,
uint16_t flags,
nsresult aReason)
@ -213,6 +244,7 @@ nsHTMLDNSPrefetch::CancelPrefetch(const nsAString &hostname,
// during shutdown gNeckoChild might be null
if (gNeckoChild) {
gNeckoChild->SendCancelHTMLDNSPrefetch(nsString(hostname),
isHttps,
aOriginAttributes,
flags,
aReason);
@ -225,10 +257,22 @@ nsHTMLDNSPrefetch::CancelPrefetch(const nsAString &hostname,
return NS_ERROR_NOT_AVAILABLE;
// Forward cancellation to DNS service
return sDNSService->CancelAsyncResolveNative(NS_ConvertUTF16toUTF8(hostname),
flags
| nsIDNSService::RESOLVE_SPECULATE,
sDNSListener, aReason, aOriginAttributes);
nsresult rv = sDNSService->CancelAsyncResolveNative(NS_ConvertUTF16toUTF8(hostname),
flags
| nsIDNSService::RESOLVE_SPECULATE,
sDNSListener, aReason, aOriginAttributes);
// Cancel fetching ESNI keys if needed.
if (sEsniEnabled && isHttps) {
nsAutoCString esniHost;
esniHost.Append("_esni.");
esniHost.Append(NS_ConvertUTF16toUTF8(hostname));
sDNSService->CancelAsyncResolveByTypeNative(esniHost,
nsIDNSService::RESOLVE_TYPE_TXT,
flags
| nsIDNSService::RESOLVE_SPECULATE,
sDNSListener, aReason, aOriginAttributes);
}
return rv;
}
nsresult
@ -239,12 +283,12 @@ nsHTMLDNSPrefetch::CancelPrefetchLow(Link *aElement, nsresult aReason)
}
nsresult
nsHTMLDNSPrefetch::CancelPrefetchLow(const nsAString &hostname,
nsHTMLDNSPrefetch::CancelPrefetchLow(const nsAString &hostname, bool isHttps,
const OriginAttributes &aOriginAttributes,
nsresult aReason)
{
return CancelPrefetch(hostname, aOriginAttributes, nsIDNSService::RESOLVE_PRIORITY_LOW,
aReason);
return CancelPrefetch(hostname, isHttps, aOriginAttributes,
nsIDNSService::RESOLVE_PRIORITY_LOW, aReason);
}
void
@ -270,6 +314,14 @@ nsHTMLDNSPrefetch::nsListener::OnLookupComplete(nsICancelable *request,
return NS_OK;
}
NS_IMETHODIMP
nsHTMLDNSPrefetch::nsListener::OnLookupByTypeComplete(nsICancelable *request,
nsIDNSByTypeRecord *res,
nsresult status)
{
return NS_OK;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
nsHTMLDNSPrefetch::nsDeferrals::nsDeferrals()
@ -352,11 +404,14 @@ nsHTMLDNSPrefetch::nsDeferrals::SubmitQueue()
Element* element = link->GetElement();
hostName.Truncate();
bool isHttps = false;
if (hrefURI) {
hrefURI->GetAsciiHost(hostName);
rv = NS_URIChainHasFlags(hrefURI,
nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
&isLocalResource);
hrefURI->SchemeIs("https", &isHttps);
}
if (!hostName.IsEmpty() && NS_SUCCEEDED(rv) && !isLocalResource &&
@ -365,6 +420,7 @@ nsHTMLDNSPrefetch::nsDeferrals::SubmitQueue()
// during shutdown gNeckoChild might be null
if (gNeckoChild) {
gNeckoChild->SendHTMLDNSPrefetch(NS_ConvertUTF8toUTF16(hostName),
isHttps,
element->NodePrincipal()
->OriginAttributesRef(),
mEntries[mTail].mFlags);
@ -379,6 +435,20 @@ nsHTMLDNSPrefetch::nsDeferrals::SubmitQueue()
element->NodePrincipal()
->OriginAttributesRef(),
getter_AddRefs(tmpOutstanding));
// Fetch ESNI keys if needed.
if (NS_SUCCEEDED(rv) && sEsniEnabled && isHttps) {
nsAutoCString esniHost;
esniHost.Append("_esni.");
esniHost.Append(hostName);
sDNSService->AsyncResolveByTypeNative(esniHost,
nsIDNSService::RESOLVE_TYPE_TXT,
mEntries[mTail].mFlags
| nsIDNSService::RESOLVE_SPECULATE,
sDNSListener, nullptr,
element->NodePrincipal()
->OriginAttributesRef(),
getter_AddRefs(tmpOutstanding));
}
// Tell link that deferred prefetch was requested
if (NS_SUCCEEDED(rv))
link->OnDNSPrefetchRequested();

View File

@ -51,13 +51,13 @@ public:
static nsresult PrefetchHigh(mozilla::dom::Link *aElement);
static nsresult PrefetchMedium(mozilla::dom::Link *aElement);
static nsresult PrefetchLow(mozilla::dom::Link *aElement);
static nsresult PrefetchHigh(const nsAString &host,
static nsresult PrefetchHigh(const nsAString &host, bool isHttps,
const mozilla::OriginAttributes &aOriginAttributes);
static nsresult PrefetchMedium(const nsAString &host,
static nsresult PrefetchMedium(const nsAString &host, bool isHttps,
const mozilla::OriginAttributes &aOriginAttributes);
static nsresult PrefetchLow(const nsAString &host,
static nsresult PrefetchLow(const nsAString &host, bool isHttps,
const mozilla::OriginAttributes &aOriginAttributes);
static nsresult CancelPrefetchLow(const nsAString &host,
static nsresult CancelPrefetchLow(const nsAString &host, bool isHttps,
const mozilla::OriginAttributes &aOriginAttributes,
nsresult aReason);
static nsresult CancelPrefetchLow(mozilla::dom::Link *aElement,
@ -66,11 +66,11 @@ public:
static void LinkDestroyed(mozilla::dom::Link* aLink);
private:
static nsresult Prefetch(const nsAString &host,
static nsresult Prefetch(const nsAString &host, bool isHttps,
const mozilla::OriginAttributes &aOriginAttributes,
uint16_t flags);
static nsresult Prefetch(mozilla::dom::Link *aElement, uint16_t flags);
static nsresult CancelPrefetch(const nsAString &hostname,
static nsresult CancelPrefetch(const nsAString &hostname, bool isHttps,
const mozilla::OriginAttributes &aOriginAttributes,
uint16_t flags,
nsresult aReason);

View File

@ -98,6 +98,12 @@ class NrIceResolver
cb_(cb), cb_arg_(cb_arg) {}
NS_IMETHOD OnLookupComplete(nsICancelable *request, nsIDNSRecord *record,
nsresult status) override;
NS_IMETHOD OnLookupByTypeComplete(nsICancelable *request,
nsIDNSByTypeRecord *res,
nsresult status) override
{
return NS_OK;
}
int cancel();
nsCOMPtr<nsICancelable> request_;
NS_DECL_THREADSAFE_ISUPPORTS

View File

@ -1876,6 +1876,11 @@ pref("network.sts.max_time_for_pr_close_during_shutdown", 5000);
// The value is expected in seconds.
pref("network.sts.pollable_event_timeout", 6);
// Enable/disable sni encryption.
// Currently this does not work even if the pref is true, the nss part is
// missing.
pref("network.security.esni.enabled", false);
// 2147483647 == PR_INT32_MAX == ~2 GB
pref("network.websocket.max-message-size", 2147483647);

View File

@ -323,6 +323,14 @@ LookupHelper::OnLookupComplete(nsICancelable *aRequest,
return NS_OK;
}
NS_IMETHODIMP
LookupHelper::OnLookupByTypeComplete(nsICancelable *aRequest,
nsIDNSByTypeRecord *aRes,
nsresult aStatus)
{
return NS_OK;
}
nsresult
LookupHelper::ConstructAnswer(LookupArgument *aArgument)
{

View File

@ -98,6 +98,8 @@ static const uint8_t kRollingLoadOffset = 12;
static const int32_t kMaxPrefetchRollingLoadCount = 20;
static const uint32_t kFlagsMask = ((1 << kRollingLoadOffset) - 1);
static bool sEsniEnabled = false;
// ID Extensions for cache entries
#define PREDICTOR_ORIGIN_EXTENSION "predictor-origin"
@ -147,6 +149,14 @@ Predictor::DNSListener::OnLookupComplete(nsICancelable *request,
return NS_OK;
}
NS_IMETHODIMP
Predictor::DNSListener::OnLookupByTypeComplete(nsICancelable *request,
nsIDNSByTypeRecord *res,
nsresult status)
{
return NS_OK;
}
// Class to proxy important information from the initial predictor call through
// the cache API and back into the internals of the predictor. We can't use the
// predictor itself, as it may have multiple actions in-flight, and each action
@ -454,6 +464,8 @@ Predictor::Init()
mDnsService = do_GetService("@mozilla.org/network/dns-service;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
Preferences::AddBoolVarCache(&sEsniEnabled, "network.security.esni.enabled");
mInitialized = true;
return rv;
@ -1422,6 +1434,22 @@ Predictor::RunPredictions(nsIURI *referrer,
nsIDNSService::RESOLVE_SPECULATE),
mDNSListener, nullptr, originAttributes,
getter_AddRefs(tmpCancelable));
bool isHttps;
uri->SchemeIs("https", &isHttps);
// Fetch esni keys if needed.
if (sEsniEnabled && isHttps) {
nsAutoCString esniHost;
esniHost.Append("_esni.");
esniHost.Append(hostname);
mDnsService->AsyncResolveByTypeNative(esniHost,
nsIDNSService::RESOLVE_TYPE_TXT,
(nsIDNSService::RESOLVE_PRIORITY_MEDIUM |
nsIDNSService::RESOLVE_SPECULATE),
mDNSListener, nullptr, originAttributes,
getter_AddRefs(tmpCancelable));
}
predicted = true;
if (verifier) {
PREDICTOR_LOG((" sending preresolve verification"));

View File

@ -305,6 +305,13 @@ public:
return NS_OK;
}
NS_IMETHOD OnLookupByTypeComplete(nsICancelable *request,
nsIDNSByTypeRecord *res,
nsresult status) override
{
return NS_OK;
}
// nsITimerCallback
NS_IMETHOD Notify(nsITimer *timer) override
{

View File

@ -12,8 +12,10 @@
#include "nsIDNSService.h"
#include "nsICancelable.h"
#include "nsIURI.h"
#include "mozilla/Preferences.h"
static nsIDNSService *sDNSService = nullptr;
static bool sESNIEnabled = false;
nsresult
nsDNSPrefetch::Initialize(nsIDNSService *aDNSService)
@ -21,6 +23,7 @@ nsDNSPrefetch::Initialize(nsIDNSService *aDNSService)
NS_IF_RELEASE(sDNSService);
sDNSService = aDNSService;
NS_IF_ADDREF(sDNSService);
mozilla::Preferences::AddBoolVarCache(&sESNIEnabled, "network.security.esni.enabled");
return NS_OK;
}
@ -38,21 +41,29 @@ nsDNSPrefetch::nsDNSPrefetch(nsIURI *aURI,
: mOriginAttributes(aOriginAttributes)
, mStoreTiming(storeTiming)
, mListener(do_GetWeakReference(aListener))
, mARequestInProgress(false)
, mEsniKeysRequestInProgress(false)
{
aURI->GetAsciiHost(mHostname);
mIsHttps = false;
aURI->SchemeIs("https", &mIsHttps);
}
nsresult
nsDNSPrefetch::Prefetch(uint16_t flags)
{
// This can work properly only if this call is on the main thread.
// Curenlty we use nsDNSPrefetch only in nsHttpChannel which will call
// PrefetchHigh() from the main thread. Let's add assertion to catch
// if things change.
MOZ_ASSERT(NS_IsMainThread(), "Expecting DNS callback on main thread.");
if (mHostname.IsEmpty())
return NS_ERROR_NOT_AVAILABLE;
if (!sDNSService)
return NS_ERROR_NOT_AVAILABLE;
nsCOMPtr<nsICancelable> tmpOutstanding;
if (mStoreTiming)
mStartTimestamp = mozilla::TimeStamp::Now();
// If AsyncResolve fails, for example because prefetching is disabled,
@ -60,10 +71,32 @@ nsDNSPrefetch::Prefetch(uint16_t flags)
// mEndTimestamp will be a null timestamp and callers should check
// TimingsValid() before using the timing.
nsCOMPtr<nsIEventTarget> main = mozilla::GetMainThreadEventTarget();
return sDNSService->AsyncResolveNative(mHostname,
flags | nsIDNSService::RESOLVE_SPECULATE,
this, main, mOriginAttributes,
getter_AddRefs(tmpOutstanding));
nsresult rv = sDNSService->AsyncResolveNative(mHostname,
flags | nsIDNSService::RESOLVE_SPECULATE,
this, main, mOriginAttributes,
getter_AddRefs(mARequest));
if (NS_FAILED(rv)) {
return rv;
}
mARequestInProgress = true;
// Fetch esni keys if needed.
if (sESNIEnabled && mIsHttps) {
nsAutoCString esniHost;
esniHost.Append("_esni.");
esniHost.Append(mHostname);
nsCOMPtr<nsICancelable> tmpOutstanding;
sDNSService->AsyncResolveByTypeNative(esniHost, nsIDNSService::RESOLVE_TYPE_TXT,
flags | nsIDNSService::RESOLVE_SPECULATE,
this, main, mOriginAttributes,
getter_AddRefs(tmpOutstanding));
if (NS_SUCCEEDED(rv)) {
mEsniKeysRequestInProgress = true;
}
}
return NS_OK;
}
nsresult
@ -87,6 +120,17 @@ nsDNSPrefetch::PrefetchHigh(bool refreshDNS)
nsIDNSService::RESOLVE_BYPASS_CACHE : 0);
}
void
nsDNSPrefetch::FinishPrefetch()
{
if (mStoreTiming) {
mEndTimestamp = mozilla::TimeStamp::Now();
}
nsCOMPtr<nsIDNSListener> listener = do_QueryReferent(mListener);
if (listener) {
listener->OnLookupComplete(mARequest, mARecord, mAStatus);
}
}
NS_IMPL_ISUPPORTS(nsDNSPrefetch, nsIDNSListener)
@ -96,13 +140,32 @@ nsDNSPrefetch::OnLookupComplete(nsICancelable *request,
nsresult status)
{
MOZ_ASSERT(NS_IsMainThread(), "Expecting DNS callback on main thread.");
MOZ_ASSERT(mARequest);
MOZ_ASSERT(mARequestInProgress);
mARequestInProgress = false;
// Remember the record, we will need it for calling the listener.
mARecord = rec;
mAStatus = status;
if (!mEsniKeysRequestInProgress) {
FinishPrefetch();
} // otherwise wait for esni keys.
return NS_OK;
}
NS_IMETHODIMP
nsDNSPrefetch::OnLookupByTypeComplete(nsICancelable *request,
nsIDNSByTypeRecord *res,
nsresult status)
{
MOZ_ASSERT(NS_IsMainThread(), "Expecting DNS callback on main thread.");
MOZ_ASSERT(mEsniKeysRequestInProgress);
mEsniKeysRequestInProgress = false;
if (!mARequestInProgress) {
FinishPrefetch();
} // otherwise wait for A/AAAA record.
if (mStoreTiming) {
mEndTimestamp = mozilla::TimeStamp::Now();
}
nsCOMPtr<nsIDNSListener> listener = do_QueryReferent(mListener);
if (listener) {
listener->OnLookupComplete(request, rec, status);
}
return NS_OK;
}

View File

@ -13,6 +13,7 @@
#include "mozilla/BasePrincipal.h"
#include "nsIDNSListener.h"
#include "nsIDNSRecord.h"
class nsIURI;
class nsIDNSService;
@ -44,13 +45,20 @@ public:
private:
nsCString mHostname;
bool mIsHttps;
mozilla::OriginAttributes mOriginAttributes;
bool mStoreTiming;
mozilla::TimeStamp mStartTimestamp;
mozilla::TimeStamp mEndTimestamp;
nsWeakPtr mListener;
bool mARequestInProgress;
bool mEsniKeysRequestInProgress;
nsCOMPtr<nsICancelable> mARequest;
nsCOMPtr<nsIDNSRecord> mARecord;
nsresult mAStatus;
nsresult Prefetch(uint16_t flags);
void FinishPrefetch();
};
#endif

View File

@ -252,6 +252,12 @@ interface nsISocketTransport : nsITransport
*/
const unsigned long RETRY_WITH_DIFFERENT_IP_FAMILY = (1 << 10);
/**
* If we know that a server speaks only tls <1.3 there is no need to try
* to use esni and query dns for esni keys.
*/
const unsigned long DONT_TRY_ESNI = (1 << 11);
/**
* An opaque flags for non-standard behavior of the TLS system.
* It is unlikely this will need to be set outside of telemetry studies
@ -295,4 +301,10 @@ interface nsISocketTransport : nsITransport
* connections any more. Hence, the preference should be reset.
*/
readonly attribute boolean resetIPFamilyPreference;
/**
* This attribute holds information whether esni has been used.
* The value is set after PR_Connect is called.
*/
readonly attribute boolean esniUsed;
};

View File

@ -33,6 +33,7 @@
#include "nsURLHelper.h"
#include "nsIDNSService.h"
#include "nsIDNSRecord.h"
#include "nsIDNSByTypeRecord.h"
#include "nsICancelable.h"
#include "TCPFastOpenLayer.h"
#include <algorithm>
@ -773,6 +774,9 @@ nsSocketTransport::nsSocketTransport()
, mInputClosed(true)
, mOutputClosed(true)
, mResolving(false)
, mDNSARequestFinished(0)
, mEsniQueried(false)
, mEsniUsed(false)
, mNetAddrIsSet(false)
, mSelfAddrIsSet(false)
, mLock("nsSocketTransport.mLock")
@ -1137,8 +1141,45 @@ nsSocketTransport::ResolveHost()
this, mOriginHost.get(), SocketHost().get()));
}
rv = dns->AsyncResolveNative(SocketHost(), dnsFlags,
this, nullptr, mOriginAttributes,
this, mSocketTransportService,
mOriginAttributes,
getter_AddRefs(mDNSRequest));
mEsniQueried = false;
if (mSocketTransportService->IsEsniEnabled() &&
NS_SUCCEEDED(rv) &&
!(mConnectionFlags & (DONT_TRY_ESNI | BE_CONSERVATIVE))) {
bool isSSL = false;
for (unsigned int i = 0; i < mTypeCount; ++i) {
if (!strcmp(mTypes[i], "ssl")) {
isSSL = true;
break;
}
}
if (isSSL) {
SOCKET_LOG((" look for esni txt record"));
nsAutoCString esniHost;
esniHost.Append("_esni.");
// This might end up being the SocketHost
// see https://github.com/ekr/draft-rescorla-tls-esni/issues/61
esniHost.Append(mOriginHost);
rv = dns->AsyncResolveByTypeNative(esniHost,
nsIDNSService::RESOLVE_TYPE_TXT,
dnsFlags,
this,
mSocketTransportService,
mOriginAttributes,
getter_AddRefs(mDNSTxtRequest));
if (NS_FAILED(rv)) {
SOCKET_LOG((" dns request by type failed."));
mDNSTxtRequest = nullptr;
rv = NS_OK;
} else {
mEsniQueried = true;
}
}
}
if (NS_SUCCEEDED(rv)) {
SOCKET_LOG((" advancing to STATE_RESOLVING\n"));
mState = STATE_RESOLVING;
@ -1540,6 +1581,19 @@ nsSocketTransport::InitiateSocket()
}
#endif
if (!mDNSRecordTxt.IsEmpty() && mSecInfo) {
nsCOMPtr<nsISSLSocketControl> secCtrl =
do_QueryInterface(mSecInfo);
if (secCtrl) {
SOCKET_LOG(("nsSocketTransport::InitiateSocket set esni keys."));
rv = secCtrl->SetEsniTxt(mDNSRecordTxt);
if (NS_FAILED(rv)) {
return rv;
}
mEsniUsed = true;
}
}
// We use PRIntervalTime here because we need
// nsIOService::LastOfflineStateChange time and
// nsIOService::LastConectivityChange time to be atomic.
@ -2126,13 +2180,14 @@ nsSocketTransport::OnSocketEvent(uint32_t type, nsresult status, nsISupports *pa
break;
case MSG_DNS_LOOKUP_COMPLETE:
if (mDNSRequest) // only send this if we actually resolved anything
if (mDNSRequest || mDNSTxtRequest) { // only send this if we actually resolved anything
SendStatus(NS_NET_STATUS_RESOLVED_HOST);
}
SOCKET_LOG((" MSG_DNS_LOOKUP_COMPLETE\n"));
mDNSRequest = nullptr;
if (param) {
mDNSRecord = static_cast<nsIDNSRecord *>(param);
mDNSTxtRequest = nullptr;
if (mDNSRecord) {
mDNSRecord->GetNextAddr(SocketPort(), &mNetAddr);
}
// status contains DNS lookup status
@ -2403,6 +2458,11 @@ nsSocketTransport::OnSocketDetached(PRFileDesc *fd)
mDNSRequest = nullptr;
}
if (mDNSTxtRequest) {
mDNSTxtRequest->Cancel(NS_ERROR_ABORT);
mDNSTxtRequest = nullptr;
}
//
// notify input/output streams
//
@ -2960,17 +3020,73 @@ nsSocketTransport::OnLookupComplete(nsICancelable *request,
nsIDNSRecord *rec,
nsresult status)
{
SOCKET_LOG(("nsSocketTransport::OnLookupComplete: this=%p status %" PRIx32
".", this, static_cast<uint32_t>(status)));
if (NS_FAILED(status) && mDNSTxtRequest) {
mDNSTxtRequest->Cancel(NS_ERROR_ABORT);
mDNSTxtRequest = nullptr;
} else {
mDNSRecord = static_cast<nsIDNSRecord *>(rec);
}
// flag host lookup complete for the benefit of the ResolveHost method.
mResolving = false;
if (!mDNSTxtRequest) {
if (mEsniQueried) {
Telemetry::Accumulate(Telemetry::ESNI_KEYS_RECORD_FETCH_DELAYS, 0);
}
mResolving = false;
nsresult rv = PostEvent(MSG_DNS_LOOKUP_COMPLETE, status, nullptr);
nsresult rv = PostEvent(MSG_DNS_LOOKUP_COMPLETE, status, rec);
// if posting a message fails, then we should assume that the socket
// transport has been shutdown. this should never happen! if it does
// it means that the socket transport service was shutdown before the
// DNS service.
if (NS_FAILED(rv)) {
NS_WARNING("unable to post DNS lookup complete message");
}
} else {
mDNSRequest = nullptr;
mDNSARequestFinished = PR_IntervalNow();
}
// if posting a message fails, then we should assume that the socket
// transport has been shutdown. this should never happen! if it does
// it means that the socket transport service was shutdown before the
// DNS service.
if (NS_FAILED(rv))
NS_WARNING("unable to post DNS lookup complete message");
return NS_OK;
}
NS_IMETHODIMP
nsSocketTransport::OnLookupByTypeComplete(nsICancelable *request,
nsIDNSByTypeRecord *txtResponse,
nsresult status)
{
SOCKET_LOG(("nsSocketTransport::OnLookupByTypeComplete: "
"this=%p status %" PRIx32 ".",
this, static_cast<uint32_t>(status)));
MOZ_ASSERT(mDNSTxtRequest == request);
mDNSTxtRequest = nullptr;
if (NS_SUCCEEDED(status)) {
txtResponse->GetRecordsAsOneString(mDNSRecordTxt);
mDNSRecordTxt.Trim(" ");
}
Telemetry::Accumulate(Telemetry::ESNI_KEYS_RECORDS_FOUND,
NS_SUCCEEDED(status));
// flag host lookup complete for the benefit of the ResolveHost method.
if (!mDNSRequest) {
mResolving = false;
MOZ_ASSERT(mDNSARequestFinished);
Telemetry::Accumulate(Telemetry::ESNI_KEYS_RECORD_FETCH_DELAYS,
PR_IntervalToMilliseconds(PR_IntervalNow() - mDNSARequestFinished));
if (status == NS_ERROR_UNKNOWN_HOST) {
status = NS_OK;
}
nsresult rv = PostEvent(MSG_DNS_LOOKUP_COMPLETE, status, nullptr);
// if posting a message fails, then we should assume that the socket
// transport has been shutdown. this should never happen! if it does
// it means that the socket transport service was shutdown before the
// DNS service.
if (NS_FAILED(rv))
NS_WARNING("unable to post DNS lookup complete message");
}
return NS_OK;
}
@ -3598,5 +3714,12 @@ nsSocketTransport::GetResetIPFamilyPreference(bool *aReset)
return NS_OK;
}
NS_IMETHODIMP
nsSocketTransport::GetEsniUsed(bool *aEsniUsed)
{
*aEsniUsed = mEsniUsed;
return NS_OK;
}
} // namespace net
} // namespace mozilla

View File

@ -342,6 +342,12 @@ private:
nsCOMPtr<nsICancelable> mDNSRequest;
nsCOMPtr<nsIDNSRecord> mDNSRecord;
PRIntervalTime mDNSARequestFinished;
nsCOMPtr<nsICancelable> mDNSTxtRequest;
nsCString mDNSRecordTxt;
bool mEsniQueried;
bool mEsniUsed;
// mNetAddr/mSelfAddr is valid from GetPeerAddr()/GetSelfAddr() once we have
// reached STATE_TRANSFERRING. It must not change after that.
void SetSocketName(PRFileDesc *fd);

View File

@ -55,6 +55,8 @@ static Atomic<PRThread*, Relaxed> gSocketThread;
#define TELEMETRY_PREF "toolkit.telemetry.enabled"
#define MAX_TIME_FOR_PR_CLOSE_DURING_SHUTDOWN "network.sts.max_time_for_pr_close_during_shutdown"
#define POLLABLE_EVENT_TIMEOUT "network.sts.pollable_event_timeout"
#define ESNI_ENABLED "network.security.esni.enabled"
#define ESNI_DISABLED_MITM "security.pki.mitm_detected"
#define REPAIR_POLLABLE_EVENT_TIME 10
@ -158,6 +160,9 @@ nsSocketTransportService::nsSocketTransportService()
#if defined(XP_WIN)
, mPolling(false)
#endif
, mEsniEnabled(false)
, mTrustedMitmDetected(false)
, mNotTrustedMitmDetected(false)
{
NS_ASSERTION(NS_IsMainThread(), "wrong thread");
@ -605,6 +610,8 @@ static const char* gCallbackPrefs[] = {
TELEMETRY_PREF,
MAX_TIME_FOR_PR_CLOSE_DURING_SHUTDOWN,
POLLABLE_EVENT_TIMEOUT,
ESNI_ENABLED,
ESNI_DISABLED_MITM,
nullptr,
};
@ -1419,6 +1426,18 @@ nsSocketTransportService::UpdatePrefs()
mPollableEventTimeout = TimeDuration::FromSeconds(pollableEventTimeout);
}
bool esniPref = false;
rv = Preferences::GetBool(ESNI_ENABLED, &esniPref);
if (NS_SUCCEEDED(rv)) {
mEsniEnabled = esniPref;
}
bool esniMitmPref = false;
rv = Preferences::GetBool(ESNI_DISABLED_MITM, &esniMitmPref);
if (NS_SUCCEEDED(rv)) {
mTrustedMitmDetected = esniMitmPref;
}
return NS_OK;
}
@ -1515,6 +1534,7 @@ nsSocketTransportService::Observe(nsISupports *subject,
ShutdownThread();
} else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
mLastNetworkLinkChangeTime = PR_IntervalNow();
mNotTrustedMitmDetected = false;
}
return NS_OK;

View File

@ -120,6 +120,13 @@ public:
!mSleepPhase; }
PRIntervalTime MaxTimeForPrClosePref() {return mMaxTimeForPrClosePref; }
bool IsEsniEnabled() { return mEsniEnabled && !mTrustedMitmDetected &&
!mNotTrustedMitmDetected; }
void SetNotTrustedMitmDetected() {
mNotTrustedMitmDetected = true;
}
protected:
virtual ~nsSocketTransportService();
@ -303,6 +310,10 @@ private:
#endif
void TryRepairPollableEvent();
bool mEsniEnabled;
bool mTrustedMitmDetected;
bool mNotTrustedMitmDetected;
};
extern nsSocketTransportService *gSocketTransportService;

View File

@ -1103,6 +1103,14 @@ PendingSend::OnLookupComplete(nsICancelable *request,
return NS_OK;
}
NS_IMETHODIMP
PendingSend::OnLookupByTypeComplete(nsICancelable *aRequest,
nsIDNSByTypeRecord *aRes,
nsresult aStatus)
{
return NS_OK;
}
class PendingSendStream : public nsIDNSListener
{
public:
@ -1144,6 +1152,14 @@ PendingSendStream::OnLookupComplete(nsICancelable *request,
return NS_OK;
}
NS_IMETHODIMP
PendingSendStream::OnLookupByTypeComplete(nsICancelable *aRequest,
nsIDNSByTypeRecord *aRes,
nsresult aStatus)
{
return NS_OK;
}
class SendRequestRunnable: public Runnable {
public:
SendRequestRunnable(nsUDPSocket* aSocket,

View File

@ -55,12 +55,14 @@ ChildDNSService::ChildDNSService()
void
ChildDNSService::GetDNSRecordHashKey(const nsACString &aHost,
uint16_t aType,
const OriginAttributes &aOriginAttributes,
uint32_t aFlags,
nsIDNSListener* aListener,
nsACString &aHashKey)
{
aHashKey.Assign(aHost);
aHashKey.AppendInt(aType);
nsAutoCString originSuffix;
aOriginAttributes.CreateSuffix(originSuffix);
@ -70,41 +72,14 @@ ChildDNSService::GetDNSRecordHashKey(const nsACString &aHost,
aHashKey.AppendPrintf("%p", aListener);
}
//-----------------------------------------------------------------------------
// ChildDNSService::nsIDNSService
//-----------------------------------------------------------------------------
NS_IMETHODIMP
ChildDNSService::AsyncResolve(const nsACString &hostname,
uint32_t flags,
nsIDNSListener *listener,
nsIEventTarget *target_,
JS::HandleValue aOriginAttributes,
JSContext *aCx,
uint8_t aArgc,
nsICancelable **result)
{
OriginAttributes attrs;
if (aArgc == 1) {
if (!aOriginAttributes.isObject() ||
!attrs.Init(aCx, aOriginAttributes)) {
return NS_ERROR_INVALID_ARG;
}
}
return AsyncResolveNative(hostname, flags,
listener, target_, attrs,
result);
}
NS_IMETHODIMP
ChildDNSService::AsyncResolveNative(const nsACString &hostname,
uint32_t flags,
nsIDNSListener *listener,
nsIEventTarget *target_,
const OriginAttributes &aOriginAttributes,
nsICancelable **result)
nsresult
ChildDNSService::AsyncResolveInternal(const nsACString &hostname,
uint16_t type,
uint32_t flags,
nsIDNSListener *listener,
nsIEventTarget *target_,
const OriginAttributes &aOriginAttributes,
nsICancelable **result)
{
NS_ENSURE_TRUE(gNeckoChild != nullptr, NS_ERROR_FAILURE);
@ -138,6 +113,7 @@ ChildDNSService::AsyncResolveNative(const nsACString &hostname,
RefPtr<DNSRequestChild> childReq =
new DNSRequestChild(hostname,
type,
aOriginAttributes,
flags,
listener, target);
@ -145,7 +121,7 @@ ChildDNSService::AsyncResolveNative(const nsACString &hostname,
{
MutexAutoLock lock(mPendingRequestsLock);
nsCString key;
GetDNSRecordHashKey(hostname, aOriginAttributes, originalFlags,
GetDNSRecordHashKey(hostname, type, aOriginAttributes, originalFlags,
originalListener, key);
nsTArray<RefPtr<DNSRequestChild>> *hashEntry;
if (mPendingRequests.Get(key, &hashEntry)) {
@ -163,6 +139,109 @@ ChildDNSService::AsyncResolveNative(const nsACString &hostname,
return NS_OK;
}
nsresult
ChildDNSService::CancelAsyncResolveInternal(const nsACString &aHostname,
uint16_t aType,
uint32_t aFlags,
nsIDNSListener *aListener,
nsresult aReason,
const OriginAttributes &aOriginAttributes)
{
if (mDisablePrefetch && (aFlags & RESOLVE_SPECULATE)) {
return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
}
MutexAutoLock lock(mPendingRequestsLock);
nsTArray<RefPtr<DNSRequestChild>> *hashEntry;
nsCString key;
GetDNSRecordHashKey(aHostname, aType, aOriginAttributes, aFlags,
aListener, key);
if (mPendingRequests.Get(key, &hashEntry)) {
// We cancel just one.
hashEntry->ElementAt(0)->Cancel(aReason);
}
return NS_OK;
}
//-----------------------------------------------------------------------------
// ChildDNSService::nsIDNSService
//-----------------------------------------------------------------------------
NS_IMETHODIMP
ChildDNSService::AsyncResolve(const nsACString &hostname,
uint32_t flags,
nsIDNSListener *listener,
nsIEventTarget *target_,
JS::HandleValue aOriginAttributes,
JSContext *aCx,
uint8_t aArgc,
nsICancelable **result)
{
OriginAttributes attrs;
if (aArgc == 1) {
if (!aOriginAttributes.isObject() ||
!attrs.Init(aCx, aOriginAttributes)) {
return NS_ERROR_INVALID_ARG;
}
}
return AsyncResolveInternal(hostname, nsIDNSService::RESOLVE_TYPE_DEFAULT,
flags, listener, target_, attrs, result);
}
NS_IMETHODIMP
ChildDNSService::AsyncResolveNative(const nsACString &hostname,
uint32_t flags,
nsIDNSListener *listener,
nsIEventTarget *target_,
const OriginAttributes &aOriginAttributes,
nsICancelable **result)
{
return AsyncResolveInternal(hostname, nsIDNSService::RESOLVE_TYPE_DEFAULT,
flags, listener, target_, aOriginAttributes,
result);
}
NS_IMETHODIMP
ChildDNSService::AsyncResolveByType(const nsACString &hostname,
uint16_t type,
uint32_t flags,
nsIDNSListener *listener,
nsIEventTarget *target_,
JS::HandleValue aOriginAttributes,
JSContext *aCx,
uint8_t aArgc,
nsICancelable **result)
{
OriginAttributes attrs;
if (aArgc == 1) {
if (!aOriginAttributes.isObject() ||
!attrs.Init(aCx, aOriginAttributes)) {
return NS_ERROR_INVALID_ARG;
}
}
return AsyncResolveInternal(hostname, type, flags,
listener, target_, attrs,
result);
}
NS_IMETHODIMP
ChildDNSService::AsyncResolveByTypeNative(const nsACString &hostname,
uint16_t type,
uint32_t flags,
nsIDNSListener *listener,
nsIEventTarget *target_,
const OriginAttributes &aOriginAttributes,
nsICancelable **result)
{
return AsyncResolveInternal(hostname, type, flags, listener, target_,
aOriginAttributes, result);
}
NS_IMETHODIMP
ChildDNSService::CancelAsyncResolve(const nsACString &aHostname,
uint32_t aFlags,
@ -181,8 +260,8 @@ ChildDNSService::CancelAsyncResolve(const nsACString &aHostname,
}
}
return CancelAsyncResolveNative(aHostname, aFlags,
aListener, aReason, attrs);
return CancelAsyncResolveInternal(aHostname, nsIDNSService::RESOLVE_TYPE_DEFAULT,
aFlags, aListener, aReason, attrs);
}
NS_IMETHODIMP
@ -192,21 +271,45 @@ ChildDNSService::CancelAsyncResolveNative(const nsACString &aHostname,
nsresult aReason,
const OriginAttributes &aOriginAttributes)
{
if (mDisablePrefetch && (aFlags & RESOLVE_SPECULATE)) {
return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
return CancelAsyncResolveInternal(aHostname,
nsIDNSService::RESOLVE_TYPE_DEFAULT,
aFlags, aListener, aReason,
aOriginAttributes);
}
NS_IMETHODIMP
ChildDNSService::CancelAsyncResolveByType(const nsACString &aHostname,
uint16_t aType,
uint32_t aFlags,
nsIDNSListener *aListener,
nsresult aReason,
JS::HandleValue aOriginAttributes,
JSContext *aCx,
uint8_t aArgc)
{
OriginAttributes attrs;
if (aArgc == 1) {
if (!aOriginAttributes.isObject() ||
!attrs.Init(aCx, aOriginAttributes)) {
return NS_ERROR_INVALID_ARG;
}
}
MutexAutoLock lock(mPendingRequestsLock);
nsTArray<RefPtr<DNSRequestChild>> *hashEntry;
nsCString key;
GetDNSRecordHashKey(aHostname, aOriginAttributes, aFlags,
aListener, key);
if (mPendingRequests.Get(key, &hashEntry)) {
// We cancel just one.
hashEntry->ElementAt(0)->Cancel(aReason);
}
return CancelAsyncResolveInternal(aHostname, aType, aFlags,
aListener, aReason, attrs);
}
return NS_OK;
NS_IMETHODIMP
ChildDNSService::CancelAsyncResolveByTypeNative(const nsACString &aHostname,
uint16_t aType,
uint32_t aFlags,
nsIDNSListener *aListener,
nsresult aReason,
const OriginAttributes &aOriginAttributes)
{
return CancelAsyncResolveInternal(aHostname, aType, aFlags, aListener,
aReason, aOriginAttributes);
}
NS_IMETHODIMP
@ -265,7 +368,8 @@ ChildDNSService::NotifyRequestDone(DNSRequestChild *aDnsRequest)
MutexAutoLock lock(mPendingRequestsLock);
nsCString key;
GetDNSRecordHashKey(aDnsRequest->mHost, aDnsRequest->mOriginAttributes, originalFlags,
GetDNSRecordHashKey(aDnsRequest->mHost, aDnsRequest->mType,
aDnsRequest->mOriginAttributes, originalFlags,
originalListener, key);
nsTArray<RefPtr<DNSRequestChild>> *hashEntry;

View File

@ -41,10 +41,24 @@ private:
virtual ~ChildDNSService() = default;
void MOZ_ALWAYS_INLINE GetDNSRecordHashKey(const nsACString &aHost,
uint16_t aType,
const OriginAttributes &aOriginAttributes,
uint32_t aFlags,
nsIDNSListener* aListener,
nsACString &aHashKey);
nsresult AsyncResolveInternal(const nsACString &hostname,
uint16_t type,
uint32_t flags,
nsIDNSListener *listener,
nsIEventTarget *target_,
const OriginAttributes &aOriginAttributes,
nsICancelable **result);
nsresult CancelAsyncResolveInternal(const nsACString &aHostname,
uint16_t aType,
uint32_t aFlags,
nsIDNSListener *aListener,
nsresult aReason,
const OriginAttributes &aOriginAttributes);
bool mFirstTime;
bool mDisablePrefetch;

View File

@ -25,6 +25,16 @@ DNSListenerProxy::OnLookupComplete(nsICancelable* aRequest,
return mTargetThread->Dispatch(r, NS_DISPATCH_NORMAL);
}
NS_IMETHODIMP
DNSListenerProxy::OnLookupByTypeComplete(nsICancelable* aRequest,
nsIDNSByTypeRecord *aRes,
nsresult aStatus)
{
RefPtr<OnLookupByTypeCompleteRunnable> r =
new OnLookupByTypeCompleteRunnable(mListener, aRequest, aRes, aStatus);
return mTargetThread->Dispatch(r, NS_DISPATCH_NORMAL);
}
NS_IMETHODIMP
DNSListenerProxy::OnLookupCompleteRunnable::Run()
{
@ -32,6 +42,13 @@ DNSListenerProxy::OnLookupCompleteRunnable::Run()
return NS_OK;
}
NS_IMETHODIMP
DNSListenerProxy::OnLookupByTypeCompleteRunnable::Run()
{
mListener->OnLookupByTypeComplete(mRequest, mResult, mStatus);
return NS_OK;
}
NS_IMETHODIMP
DNSListenerProxy::GetOriginalListener(nsIDNSListener **aOriginalListener)
{

View File

@ -60,6 +60,29 @@ public:
nsresult mStatus;
};
class OnLookupByTypeCompleteRunnable : public Runnable
{
public:
OnLookupByTypeCompleteRunnable(const nsMainThreadPtrHandle<nsIDNSListener> &aListener,
nsICancelable *aRequest,
nsIDNSByTypeRecord *aRes,
nsresult aStatus)
: Runnable("DNSListenerProxy::OnLookupByTypeCompleteRunnable")
, mListener(aListener)
, mRequest(aRequest)
, mResult(aRes)
, mStatus(aStatus)
{ }
NS_DECL_NSIRUNNABLE
private:
nsMainThreadPtrHandle<nsIDNSListener> mListener;
nsCOMPtr<nsICancelable> mRequest;
nsCOMPtr<nsIDNSByTypeRecord> mResult;
nsresult mStatus;
};
private:
~DNSListenerProxy() {}

View File

@ -11,6 +11,7 @@
#include "mozilla/SystemGroup.h"
#include "mozilla/Unused.h"
#include "nsIDNSRecord.h"
#include "nsIDNSByTypeRecord.h"
#include "nsHostResolver.h"
#include "nsTArray.h"
#include "nsNetAddr.h"
@ -160,6 +161,45 @@ ChildDNSRecord::ReportUnusable(uint16_t aPort)
return NS_OK;
}
class ChildDNSByTypeRecord : public nsIDNSByTypeRecord
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIDNSBYTYPERECORD
explicit ChildDNSByTypeRecord(const nsTArray<nsCString> &reply);
private:
virtual ~ChildDNSByTypeRecord() = default;
nsTArray<nsCString> mRecords;
};
NS_IMPL_ISUPPORTS(ChildDNSByTypeRecord, nsIDNSByTypeRecord)
ChildDNSByTypeRecord::ChildDNSByTypeRecord(const nsTArray<nsCString> &reply)
{
mRecords = reply;
}
NS_IMETHODIMP
ChildDNSByTypeRecord::GetRecords(nsTArray<nsCString> &aRecords)
{
aRecords = mRecords;
return NS_OK;
}
NS_IMETHODIMP
ChildDNSByTypeRecord::GetRecordsAsOneString(nsACString &aRecords)
{
// deep copy
for (uint32_t i = 0; i < mRecords.Length(); i++) {
aRecords.Append(mRecords[i]);
}
return NS_OK;
}
//-----------------------------------------------------------------------------
// CancelDNSRequestEvent
//-----------------------------------------------------------------------------
@ -178,6 +218,7 @@ public:
if (mDnsRequest->mIPCOpen) {
// Send request to Parent process.
mDnsRequest->SendCancelDNSRequest(mDnsRequest->mHost,
mDnsRequest->mType,
mDnsRequest->mOriginAttributes,
mDnsRequest->mFlags,
mReasonForCancel);
@ -193,15 +234,17 @@ private:
// DNSRequestChild
//-----------------------------------------------------------------------------
DNSRequestChild::DNSRequestChild(const nsACString& aHost,
DNSRequestChild::DNSRequestChild(const nsACString &aHost,
const uint16_t &aType,
const OriginAttributes& aOriginAttributes,
const uint32_t& aFlags,
const uint32_t &aFlags,
nsIDNSListener *aListener,
nsIEventTarget *target)
: mListener(aListener)
, mTarget(target)
, mResultStatus(NS_OK)
, mHost(aHost)
, mType(aType)
, mOriginAttributes(aOriginAttributes)
, mFlags(aFlags)
, mIPCOpen(false)
@ -248,6 +291,14 @@ DNSRequestChild::CallOnLookupComplete()
mListener->OnLookupComplete(this, mResultRecord, mResultStatus);
}
void
DNSRequestChild::CallOnLookupByTypeComplete()
{
MOZ_ASSERT(mListener);
MOZ_ASSERT(mType != nsIDNSService::RESOLVE_TYPE_DEFAULT);
mListener->OnLookupByTypeComplete(this, mResultByTypeRecords, mResultStatus);
}
mozilla::ipc::IPCResult
DNSRequestChild::RecvLookupCompleted(const DNSRequestResponse& reply)
{
@ -263,6 +314,11 @@ DNSRequestChild::RecvLookupCompleted(const DNSRequestResponse& reply)
mResultStatus = reply.get_nsresult();
break;
}
case DNSRequestResponse::TArrayOfnsCString: {
MOZ_ASSERT(mType != nsIDNSService::RESOLVE_TYPE_DEFAULT);
mResultByTypeRecords = new ChildDNSByTypeRecord(reply.get_ArrayOfnsCString());
break;
}
default:
MOZ_ASSERT_UNREACHABLE("unknown type");
return IPC_FAIL_NO_REASON(this);
@ -278,13 +334,25 @@ DNSRequestChild::RecvLookupCompleted(const DNSRequestResponse& reply)
}
if (targetIsMain) {
CallOnLookupComplete();
if (mType == nsIDNSService::RESOLVE_TYPE_DEFAULT) {
CallOnLookupComplete();
} else {
CallOnLookupByTypeComplete();
}
} else {
nsCOMPtr<nsIRunnable> event =
NewRunnableMethod("net::DNSRequestChild::CallOnLookupComplete",
this,
&DNSRequestChild::CallOnLookupComplete);
mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
if (mType == nsIDNSService::RESOLVE_TYPE_DEFAULT) {
nsCOMPtr<nsIRunnable> event =
NewRunnableMethod("net::DNSRequestChild::CallOnLookupComplete",
this,
&DNSRequestChild::CallOnLookupComplete);
mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
} else {
nsCOMPtr<nsIRunnable> event =
NewRunnableMethod("net::DNSRequestChild::CallOnLookupByTypeComplete",
this,
&DNSRequestChild::CallOnLookupByTypeComplete);
mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
}
}
Unused << Send__delete__(this);

View File

@ -11,6 +11,7 @@
#include "nsICancelable.h"
#include "nsIDNSRecord.h"
#include "nsIDNSListener.h"
#include "nsIDNSByTypeRecord.h"
#include "nsIEventTarget.h"
namespace mozilla {
@ -25,6 +26,7 @@ public:
NS_DECL_NSICANCELABLE
DNSRequestChild(const nsACString& aHost,
const uint16_t& aType,
const OriginAttributes& aOriginAttributes,
const uint32_t& aFlags,
nsIDNSListener *aListener, nsIEventTarget *target);
@ -37,6 +39,7 @@ public:
// Sends IPDL request to parent
void StartRequest();
void CallOnLookupComplete();
void CallOnLookupByTypeComplete();
protected:
friend class CancelDNSRequestEvent;
@ -46,14 +49,21 @@ protected:
virtual mozilla::ipc::IPCResult RecvLookupCompleted(const DNSRequestResponse& reply) override;
virtual void ActorDestroy(ActorDestroyReason why) override;
nsCOMPtr<nsIDNSListener> mListener;
nsCOMPtr<nsIEventTarget> mTarget;
nsCOMPtr<nsIDNSRecord> mResultRecord;
nsresult mResultStatus;
nsCString mHost;
const OriginAttributes mOriginAttributes;
uint16_t mFlags;
bool mIPCOpen;
nsCOMPtr<nsIDNSListener> mListener;
nsCOMPtr<nsIEventTarget> mTarget;
nsCOMPtr<nsIDNSRecord> mResultRecord;
nsCOMPtr<nsIDNSByTypeRecord> mResultByTypeRecords; // the result of a by-type
// query (mType must not be
// equal to
// nsIDNSService::RESOLVE_TYPE_DEFAULT
// (this is reserved for
// the standard A/AAAA query)).
nsresult mResultStatus;
nsCString mHost;
uint16_t mType;
const OriginAttributes mOriginAttributes;
uint16_t mFlags;
bool mIPCOpen;
};
} // namespace net

View File

@ -50,6 +50,7 @@ DNSRequestParent::DoAsyncResolve(const nsACString &hostname,
mozilla::ipc::IPCResult
DNSRequestParent::RecvCancelDNSRequest(const nsCString& hostName,
const uint16_t& type,
const OriginAttributes& originAttributes,
const uint32_t& flags,
const nsresult& reason)
@ -57,9 +58,15 @@ DNSRequestParent::RecvCancelDNSRequest(const nsCString& hostName,
nsresult rv;
nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv)) {
rv = dns->CancelAsyncResolveNative(hostName, flags,
this, reason,
originAttributes);
if (type == nsIDNSService::RESOLVE_TYPE_DEFAULT) {
rv = dns->CancelAsyncResolveNative(hostName, flags,
this, reason,
originAttributes);
} else {
rv = dns->CancelAsyncResolveByTypeNative(hostName, type, flags,
this, reason,
originAttributes);
}
}
return IPC_OK();
}
@ -124,7 +131,26 @@ DNSRequestParent::OnLookupComplete(nsICancelable *request,
return NS_OK;
}
NS_IMETHODIMP
DNSRequestParent::OnLookupByTypeComplete(nsICancelable *aRequest,
nsIDNSByTypeRecord *aRes,
nsresult aStatus)
{
if (mIPCClosed) {
// nothing to do: child probably crashed
return NS_OK;
}
if (NS_SUCCEEDED(aStatus)) {
nsTArray<nsCString> rec;
aRes->GetRecords(rec);
Unused << SendLookupCompleted(DNSRequestResponse(rec));
} else {
Unused << SendLookupCompleted(DNSRequestResponse(aStatus));
}
mIPCClosed = true;
return NS_OK;
}
} // namespace net
} // namespace mozilla

View File

@ -31,6 +31,7 @@ public:
// Pass args here rather than storing them in the parent; they are only
// needed if the request is to be canceled.
mozilla::ipc::IPCResult RecvCancelDNSRequest(const nsCString& hostName,
const uint16_t& type,
const OriginAttributes& originAttributes,
const uint32_t& flags,
const nsresult& reason) override;

View File

@ -25,7 +25,8 @@ parent:
// Pass args here rather than storing them in the parent; they are only
// needed if the request is to be canceled.
async CancelDNSRequest(nsCString hostName, OriginAttributes originAttributes,
async CancelDNSRequest(nsCString hostName, uint16_t type,
OriginAttributes originAttributes,
uint32_t flags, nsresult reason);
async __delete__();

View File

@ -23,6 +23,7 @@ struct DNSRecord
union DNSRequestResponse
{
DNSRecord;
nsCString[]; // The result of a by-type query
nsresult; // if error
};

View File

@ -168,7 +168,8 @@ TRR::SendHTTPRequest()
// This is essentially the "run" method - created from nsHostResolver
MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
if ((mType != TRRTYPE_A) && (mType != TRRTYPE_AAAA) && (mType != TRRTYPE_NS)) {
if ((mType != TRRTYPE_A) && (mType != TRRTYPE_AAAA) && (mType != TRRTYPE_NS) &&
(mType != TRRTYPE_TXT)) {
// limit the calling interface because nsHostResolver has explicit slots for
// these types
return NS_ERROR_FAILURE;
@ -763,6 +764,34 @@ TRR::DohDecode(nsCString &aHost)
LOG(("TRR::DohDecode CNAME - ignoring another entry\n"));
}
break;
case TRRTYPE_TXT:
{
// TXT record RRDATA sections are a series of character-strings
// each character string is a length byte followed by that many data bytes
nsAutoCString txt;
unsigned int txtIndex = index;
uint16_t available = RDLENGTH;
while (available > 0) {
uint8_t characterStringLen = mResponse[txtIndex++];
available--;
if (characterStringLen > available) {
LOG(("TRR::DohDecode MALFORMED TXT RECORD\n"));
break;
}
txt.Append((const char *)(&mResponse[txtIndex]), characterStringLen);
txtIndex += characterStringLen;
available -= characterStringLen;
}
mTxt.AppendElement(txt);
if (mTxtTtl > TTL) {
mTxtTtl = TTL;
}
LOG(("TRR::DohDecode TXT host %s => %s\n",
host.get(), txt.get()));
break;
}
default:
// skip unknown record types
LOG(("TRR unsupported TYPE (%u) RDLENGTH %u\n", TYPE, RDLENGTH));
@ -848,7 +877,8 @@ TRR::DohDecode(nsCString &aHost)
}
if ((mType != TRRTYPE_NS) && mCname.IsEmpty() &&
!mDNS.mAddresses.getFirst()) {
!mDNS.mAddresses.getFirst() &&
mTxt.IsEmpty()) {
// no entries were stored!
LOG(("TRR: No entries were stored!\n"));
return NS_ERROR_FAILURE;
@ -859,29 +889,33 @@ TRR::DohDecode(nsCString &aHost)
nsresult
TRR::ReturnData()
{
// create and populate an AddrInfo instance to pass on
nsAutoPtr<AddrInfo> ai(new AddrInfo(mHost, mType));
DOHaddr *item;
uint32_t ttl = AddrInfo::NO_TTL_DATA;
while ((item = static_cast<DOHaddr*>(mDNS.mAddresses.popFirst()))) {
PRNetAddr prAddr;
NetAddrToPRNetAddr(&item->mNet, &prAddr);
auto *addrElement = new NetAddrElement(&prAddr);
ai->AddAddress(addrElement);
if (item->mTtl < ttl) {
// While the DNS packet might return individual TTLs for each address,
// we can only return one value in the AddrInfo class so pick the
// lowest number.
ttl = item->mTtl;
if (mType != TRRTYPE_TXT) {
// create and populate an AddrInfo instance to pass on
nsAutoPtr<AddrInfo> ai(new AddrInfo(mHost, mType));
DOHaddr *item;
uint32_t ttl = AddrInfo::NO_TTL_DATA;
while ((item = static_cast<DOHaddr*>(mDNS.mAddresses.popFirst()))) {
PRNetAddr prAddr;
NetAddrToPRNetAddr(&item->mNet, &prAddr);
auto *addrElement = new NetAddrElement(&prAddr);
ai->AddAddress(addrElement);
if (item->mTtl < ttl) {
// While the DNS packet might return individual TTLs for each address,
// we can only return one value in the AddrInfo class so pick the
// lowest number.
ttl = item->mTtl;
}
}
ai->ttl = ttl;
if (!mHostResolver) {
return NS_ERROR_FAILURE;
}
(void)mHostResolver->CompleteLookup(mRec, NS_OK, ai.forget(), mPB);
mHostResolver = nullptr;
mRec = nullptr;
} else {
(void)mHostResolver->CompleteLookupByType(mRec, NS_OK, &mTxt, mTxtTtl, mPB);
}
ai->ttl = ttl;
if (!mHostResolver) {
return NS_ERROR_FAILURE;
}
(void)mHostResolver->CompleteLookup(mRec, NS_OK, ai.forget(), mPB);
mHostResolver = nullptr;
mRec = nullptr;
return NS_OK;
}
@ -891,11 +925,18 @@ TRR::FailData(nsresult error)
if (!mHostResolver) {
return NS_ERROR_FAILURE;
}
// create and populate an TRR AddrInfo instance to pass on to signal that
// this comes from TRR
AddrInfo *ai = new AddrInfo(mHost, mType);
(void)mHostResolver->CompleteLookup(mRec, error, ai, mPB);
if (mType == TRRTYPE_TXT) {
(void)mHostResolver->CompleteLookupByType(mRec, error,
nullptr, 0, mPB);
} else {
// create and populate an TRR AddrInfo instance to pass on to signal that
// this comes from TRR
AddrInfo *ai = new AddrInfo(mHost, mType);
(void)mHostResolver->CompleteLookup(mRec, error, ai, mPB);
}
mHostResolver = nullptr;
mRec = nullptr;
return NS_OK;
@ -908,7 +949,8 @@ TRR::On200Response()
nsresult rv = DohDecode(mHost);
if (NS_SUCCEEDED(rv)) {
if (!mDNS.mAddresses.getFirst() && !mCname.IsEmpty()) {
if (!mDNS.mAddresses.getFirst() && !mCname.IsEmpty() &&
mType != TRRTYPE_TXT) {
nsCString cname = mCname;
LOG(("TRR: check for CNAME record for %s within previous response\n",
cname.get()));

View File

@ -20,6 +20,7 @@ enum TrrType {
TRRTYPE_NS = 2,
TRRTYPE_CNAME = 5,
TRRTYPE_AAAA = 28,
TRRTYPE_TXT = 16,
};
class DOHaddr : public LinkedListElement<DOHaddr> {
@ -78,6 +79,7 @@ public:
, mFailed(false)
, mCnameLoop(kCnameChaseMax)
, mAllowRFC1918(false)
, mTxtTtl(UINT32_MAX)
{
mHost = aRec->host;
mPB = aRec->pb;
@ -100,6 +102,7 @@ public:
, mPB(aPB)
, mCnameLoop(aLoopCount)
, mAllowRFC1918(false)
, mTxtTtl(UINT32_MAX)
{
}
@ -114,6 +117,7 @@ public:
, mPB(aPB)
, mCnameLoop(kCnameChaseMax)
, mAllowRFC1918(false)
, mTxtTtl(UINT32_MAX)
{ }
// to verify a domain
@ -130,6 +134,7 @@ public:
, mPB(aPB)
, mCnameLoop(kCnameChaseMax)
, mAllowRFC1918(false)
, mTxtTtl(UINT32_MAX)
{ }
NS_IMETHOD Run() override;
@ -172,6 +177,8 @@ private:
nsCString mCname;
uint32_t mCnameLoop; // loop detection counter
bool mAllowRFC1918;
nsTArray<nsCString> mTxt;
uint32_t mTxtTtl;
};
} // namespace net

View File

@ -639,6 +639,15 @@ TRRService::CompleteLookup(nsHostRecord *rec, nsresult status, AddrInfo *aNewRRS
return LOOKUP_OK;
}
AHostResolver::LookupStatus
TRRService::CompleteLookupByType(nsHostRecord *, nsresult,
const nsTArray<nsCString> *aResult,
uint32_t aTtl,
bool aPb)
{
return LOOKUP_OK;
}
#undef LOG
} // namespace net

View File

@ -44,6 +44,7 @@ public:
uint32_t GetRequestTimeout() { return mTRRTimeout; }
LookupStatus CompleteLookup(nsHostRecord *, nsresult, mozilla::net::AddrInfo *, bool pb) override;
LookupStatus CompleteLookupByType(nsHostRecord *, nsresult, const nsTArray<nsCString> *, uint32_t, bool pb) override;
void TRRBlacklist(const nsACString &host, bool privateBrowsing, bool aParentsToo);
bool IsTRRBlacklisted(const nsACString &host, bool privateBrowsing, bool fullhost);

View File

@ -12,6 +12,7 @@ DIRS += [
]
XPIDL_SOURCES += [
'nsIDNSByTypeRecord.idl',
'nsIDNSListener.idl',
'nsIDNSRecord.idl',
'nsIDNSService.idl',

View File

@ -7,6 +7,7 @@
#include "nsDNSService2.h"
#include "nsIDNSRecord.h"
#include "nsIDNSListener.h"
#include "nsIDNSByTypeRecord.h"
#include "nsICancelable.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch.h"
@ -306,6 +307,44 @@ nsDNSRecord::ReportUnusable(uint16_t aPort)
return NS_OK;
}
class nsDNSByTypeRecord : public nsIDNSByTypeRecord
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIDNSBYTYPERECORD
explicit nsDNSByTypeRecord(nsHostRecord *hostRecord)
: mHostRecord(hostRecord)
{}
private:
virtual ~nsDNSByTypeRecord() = default;
RefPtr<nsHostRecord> mHostRecord;
};
NS_IMPL_ISUPPORTS(nsDNSByTypeRecord, nsIDNSByTypeRecord)
NS_IMETHODIMP
nsDNSByTypeRecord::GetRecords(nsTArray<nsCString> &aRecords)
{
// deep copy
MutexAutoLock lock(mHostRecord->mRequestByTypeResultLock);
aRecords = mHostRecord->mRequestByTypeResult;
return NS_OK;
}
NS_IMETHODIMP
nsDNSByTypeRecord::GetRecordsAsOneString(nsACString &aRecords)
{
// deep copy
MutexAutoLock lock(mHostRecord->mRequestByTypeResultLock);
for (uint32_t i = 0; i < mHostRecord->mRequestByTypeResult.Length(); i++) {
aRecords.Append(mHostRecord->mRequestByTypeResult[i]);
}
return NS_OK;
}
//-----------------------------------------------------------------------------
class nsDNSAsyncRequest final : public nsResolveHostCallback
@ -317,12 +356,14 @@ public:
nsDNSAsyncRequest(nsHostResolver *res,
const nsACString &host,
uint16_t type,
const OriginAttributes &attrs,
nsIDNSListener *listener,
uint16_t flags,
uint16_t af)
: mResolver(res)
, mHost(host)
, mType(type)
, mOriginAttributes(attrs)
, mListener(listener)
, mFlags(flags)
@ -339,6 +380,7 @@ public:
RefPtr<nsHostResolver> mResolver;
nsCString mHost; // hostname we're resolving
uint16_t mType;
const OriginAttributes mOriginAttributes; // The originAttributes for this resolving
nsCOMPtr<nsIDNSListener> mListener;
uint16_t mFlags;
@ -354,16 +396,27 @@ nsDNSAsyncRequest::OnResolveHostComplete(nsHostResolver *resolver,
nsHostRecord *hostRecord,
nsresult status)
{
// need to have an owning ref when we issue the callback to enable
// the caller to be able to addref/release multiple times without
// destroying the record prematurely.
nsCOMPtr<nsIDNSRecord> rec;
if (NS_SUCCEEDED(status)) {
NS_ASSERTION(hostRecord, "no host record");
rec = new nsDNSRecord(hostRecord);
}
if (hostRecord->type != nsDNSService::RESOLVE_TYPE_DEFAULT) {
nsCOMPtr<nsIDNSByTypeRecord> rec;
if (NS_SUCCEEDED(status)) {
MOZ_ASSERT(hostRecord, "no host record");
rec = new nsDNSByTypeRecord(hostRecord);
}
mListener->OnLookupByTypeComplete(this,
rec,
status);
} else {
// need to have an owning ref when we issue the callback to enable
// the caller to be able to addref/release multiple times without
// destroying the record prematurely.
nsCOMPtr<nsIDNSRecord> rec;
if (NS_SUCCEEDED(status)) {
NS_ASSERTION(hostRecord, "no host record");
rec = new nsDNSRecord(hostRecord);
}
mListener->OnLookupComplete(this, rec, status);
mListener->OnLookupComplete(this, rec, status);
}
mListener = nullptr;
}
@ -396,7 +449,7 @@ NS_IMETHODIMP
nsDNSAsyncRequest::Cancel(nsresult reason)
{
NS_ENSURE_ARG(NS_FAILED(reason));
mResolver->DetachCallback(mHost, mOriginAttributes, mFlags, mAF,
mResolver->DetachCallback(mHost, mType, mOriginAttributes, mFlags, mAF,
this, reason);
return NS_OK;
}
@ -799,36 +852,14 @@ nsDNSService::PreprocessHostname(bool aLocalDomain,
return NS_OK;
}
NS_IMETHODIMP
nsDNSService::AsyncResolve(const nsACString &aHostname,
uint32_t flags,
nsIDNSListener *listener,
nsIEventTarget *target_,
JS::HandleValue aOriginAttributes,
JSContext *aCx,
uint8_t aArgc,
nsICancelable **result)
{
OriginAttributes attrs;
if (aArgc == 1) {
if (!aOriginAttributes.isObject() ||
!attrs.Init(aCx, aOriginAttributes)) {
return NS_ERROR_INVALID_ARG;
}
}
return AsyncResolveNative(aHostname, flags, listener,
target_, attrs, result);
}
NS_IMETHODIMP
nsDNSService::AsyncResolveNative(const nsACString &aHostname,
uint32_t flags,
nsIDNSListener *aListener,
nsIEventTarget *target_,
const OriginAttributes &aOriginAttributes,
nsICancelable **result)
nsresult
nsDNSService::AsyncResolveInternal(const nsACString &aHostname,
uint16_t type,
uint32_t flags,
nsIDNSListener *aListener,
nsIEventTarget *target_,
const OriginAttributes &aOriginAttributes,
nsICancelable **result)
{
// grab reference to global host resolver and IDN service. beware
// simultaneous shutdown!!
@ -855,6 +886,10 @@ nsDNSService::AsyncResolveNative(const nsACString &aHostname,
if (!res)
return NS_ERROR_OFFLINE;
if ((type != RESOLVE_TYPE_DEFAULT) && (type != RESOLVE_TYPE_TXT)) {
return NS_ERROR_INVALID_ARG;
}
nsCString hostname;
nsresult rv = PreprocessHostname(localDomain, aHostname, idn, hostname);
if (NS_FAILED(rv)) {
@ -876,47 +911,28 @@ nsDNSService::AsyncResolveNative(const nsACString &aHostname,
listener = new DNSListenerProxy(listener, target);
}
uint16_t af = GetAFForLookup(hostname, flags);
uint16_t af = (type != RESOLVE_TYPE_DEFAULT) ? 0
: GetAFForLookup(hostname, flags);
MOZ_ASSERT(listener);
RefPtr<nsDNSAsyncRequest> req =
new nsDNSAsyncRequest(res, hostname, aOriginAttributes, listener, flags, af);
new nsDNSAsyncRequest(res, hostname, type, aOriginAttributes, listener,
flags, af);
if (!req)
return NS_ERROR_OUT_OF_MEMORY;
rv = res->ResolveHost(req->mHost, req->mOriginAttributes, flags, af, req);
rv = res->ResolveHost(req->mHost, type, req->mOriginAttributes, flags, af, req);
req.forget(result);
return rv;
}
NS_IMETHODIMP
nsDNSService::CancelAsyncResolve(const nsACString &aHostname,
uint32_t aFlags,
nsIDNSListener *aListener,
nsresult aReason,
JS::HandleValue aOriginAttributes,
JSContext *aCx,
uint8_t aArgc)
{
OriginAttributes attrs;
if (aArgc == 1) {
if (!aOriginAttributes.isObject() ||
!attrs.Init(aCx, aOriginAttributes)) {
return NS_ERROR_INVALID_ARG;
}
}
return CancelAsyncResolveNative(aHostname, aFlags,
aListener, aReason, attrs);
}
NS_IMETHODIMP
nsDNSService::CancelAsyncResolveNative(const nsACString &aHostname,
uint32_t aFlags,
nsIDNSListener *aListener,
nsresult aReason,
const OriginAttributes &aOriginAttributes)
nsresult
nsDNSService::CancelAsyncResolveInternal(const nsACString &aHostname,
uint16_t aType,
uint32_t aFlags,
nsIDNSListener *aListener,
nsresult aReason,
const OriginAttributes &aOriginAttributes)
{
// grab reference to global host resolver and IDN service. beware
// simultaneous shutdown!!
@ -942,13 +958,154 @@ nsDNSService::CancelAsyncResolveNative(const nsACString &aHostname,
return rv;
}
uint16_t af = GetAFForLookup(hostname, aFlags);
uint16_t af = (aType != RESOLVE_TYPE_DEFAULT) ? 0
: GetAFForLookup(hostname, aFlags);
res->CancelAsyncRequest(hostname, aOriginAttributes, aFlags, af,
aListener, aReason);
res->CancelAsyncRequest(hostname, aType, aOriginAttributes, aFlags,
af, aListener, aReason);
return NS_OK;
}
NS_IMETHODIMP
nsDNSService::AsyncResolve(const nsACString &aHostname,
uint32_t flags,
nsIDNSListener *listener,
nsIEventTarget *target_,
JS::HandleValue aOriginAttributes,
JSContext *aCx,
uint8_t aArgc,
nsICancelable **result)
{
OriginAttributes attrs;
if (aArgc == 1) {
if (!aOriginAttributes.isObject() ||
!attrs.Init(aCx, aOriginAttributes)) {
return NS_ERROR_INVALID_ARG;
}
}
return AsyncResolveInternal(aHostname, RESOLVE_TYPE_DEFAULT, flags, listener,
target_, attrs, result);
}
NS_IMETHODIMP
nsDNSService::AsyncResolveNative(const nsACString &aHostname,
uint32_t flags,
nsIDNSListener *aListener,
nsIEventTarget *target_,
const OriginAttributes &aOriginAttributes,
nsICancelable **result)
{
return AsyncResolveInternal(aHostname, RESOLVE_TYPE_DEFAULT, flags, aListener, target_,
aOriginAttributes, result);
}
NS_IMETHODIMP
nsDNSService::AsyncResolveByType(const nsACString &aHostname,
uint16_t aType,
uint32_t aFlags,
nsIDNSListener *aListener,
nsIEventTarget *aTarget_,
JS::HandleValue aOriginAttributes,
JSContext *aCx,
uint8_t aArgc,
nsICancelable **aResult)
{
OriginAttributes attrs;
if (aArgc == 1) {
if (!aOriginAttributes.isObject() ||
!attrs.Init(aCx, aOriginAttributes)) {
return NS_ERROR_INVALID_ARG;
}
}
return AsyncResolveInternal(aHostname, aType, aFlags, aListener,
aTarget_, attrs, aResult);
}
NS_IMETHODIMP
nsDNSService::AsyncResolveByTypeNative(const nsACString &aHostname,
uint16_t aType,
uint32_t aFlags,
nsIDNSListener *aListener,
nsIEventTarget *aTarget_,
const OriginAttributes &aOriginAttributes,
nsICancelable **aResult)
{
return AsyncResolveInternal(aHostname, aType, aFlags, aListener, aTarget_,
aOriginAttributes, aResult);
}
NS_IMETHODIMP
nsDNSService::CancelAsyncResolve(const nsACString &aHostname,
uint32_t aFlags,
nsIDNSListener *aListener,
nsresult aReason,
JS::HandleValue aOriginAttributes,
JSContext *aCx,
uint8_t aArgc)
{
OriginAttributes attrs;
if (aArgc == 1) {
if (!aOriginAttributes.isObject() ||
!attrs.Init(aCx, aOriginAttributes)) {
return NS_ERROR_INVALID_ARG;
}
}
return CancelAsyncResolveInternal(aHostname, RESOLVE_TYPE_DEFAULT, aFlags,
aListener, aReason, attrs);
}
NS_IMETHODIMP
nsDNSService::CancelAsyncResolveNative(const nsACString &aHostname,
uint32_t aFlags,
nsIDNSListener *aListener,
nsresult aReason,
const OriginAttributes &aOriginAttributes)
{
return CancelAsyncResolveInternal(aHostname, RESOLVE_TYPE_DEFAULT, aFlags, aListener, aReason,
aOriginAttributes);
}
NS_IMETHODIMP
nsDNSService::CancelAsyncResolveByType(const nsACString &aHostname,
uint16_t aType,
uint32_t aFlags,
nsIDNSListener *aListener,
nsresult aReason,
JS::HandleValue aOriginAttributes,
JSContext *aCx,
uint8_t aArgc)
{
OriginAttributes attrs;
if (aArgc == 1) {
if (!aOriginAttributes.isObject() ||
!attrs.Init(aCx, aOriginAttributes)) {
return NS_ERROR_INVALID_ARG;
}
}
return CancelAsyncResolveInternal(aHostname, aType, aFlags,
aListener, aReason, attrs);
}
NS_IMETHODIMP
nsDNSService::CancelAsyncResolveByTypeNative(const nsACString &aHostname,
uint16_t aType,
uint32_t aFlags,
nsIDNSListener *aListener,
nsresult aReason,
const OriginAttributes &aOriginAttributes)
{
return CancelAsyncResolveInternal(aHostname, aType, aFlags, aListener, aReason,
aOriginAttributes);
}
NS_IMETHODIMP
nsDNSService::Resolve(const nsACString &aHostname,
uint32_t flags,
@ -1044,7 +1201,7 @@ nsDNSService::ResolveInternal(const nsACString &aHostname,
uint16_t af = GetAFForLookup(hostname, flags);
rv = res->ResolveHost(hostname, aOriginAttributes, flags, af, syncReq);
rv = res->ResolveHost(hostname, RESOLVE_TYPE_DEFAULT, aOriginAttributes, flags, af, syncReq);
if (NS_SUCCEEDED(rv)) {
// wait for result
while (!syncReq->mDone) {

View File

@ -61,6 +61,21 @@ private:
nsIIDNService *aIDN,
nsACString &aACE);
nsresult AsyncResolveInternal(const nsACString &aHostname,
uint16_t type,
uint32_t flags,
nsIDNSListener *aListener,
nsIEventTarget *target_,
const mozilla::OriginAttributes &aOriginAttributes,
nsICancelable **result);
nsresult CancelAsyncResolveInternal(const nsACString &aHostname,
uint16_t aType,
uint32_t aFlags,
nsIDNSListener *aListener,
nsresult aReason,
const mozilla::OriginAttributes &aOriginAttributes);
nsresult ResolveInternal(const nsACString &aHostname,
uint32_t flags,
const mozilla::OriginAttributes &aOriginAttributes,

View File

@ -156,9 +156,10 @@ IsLowPriority(uint16_t flags)
#define RES_KEY_FLAGS(_f) ((_f) & (nsHostResolver::RES_CANON_NAME | \
nsHostResolver::RES_DISABLE_TRR))
nsHostKey::nsHostKey(const nsACString& aHost, uint16_t aFlags,
nsHostKey::nsHostKey(const nsACString& aHost, uint16_t aType, uint16_t aFlags,
uint16_t aAf, bool aPb, const nsACString& aOriginsuffix)
: host(aHost)
, type(aType)
, flags(aFlags)
, af(aAf)
, pb(aPb)
@ -174,6 +175,7 @@ bool
nsHostKey::operator==(const nsHostKey& other) const
{
return host == other.host &&
type == other.type &&
RES_KEY_FLAGS (flags) == RES_KEY_FLAGS(other.flags) &&
af == other.af &&
originSuffix == other.originSuffix;
@ -182,7 +184,7 @@ nsHostKey::operator==(const nsHostKey& other) const
PLDHashNumber
nsHostKey::Hash() const
{
return AddToHash(HashString(host.get()), RES_KEY_FLAGS(flags), af,
return AddToHash(HashString(host.get()), type, RES_KEY_FLAGS(flags), af,
HashString(originSuffix.get()));
}
@ -203,6 +205,7 @@ nsHostRecord::nsHostRecord(const nsHostKey& key)
, addr(nullptr)
, negative(false)
, mResolverMode(MODE_NATIVEONLY)
, mRequestByTypeResultLock("nsHostRecord.mRequestByTypeResultLock")
, mFirstTRRresult(NS_OK)
, mResolving(0)
, mTRRSuccess(0)
@ -235,6 +238,10 @@ nsHostRecord::Cancel()
mTrrAAAA->Cancel();
mTrrAAAA = nullptr;
}
if (mTrrTxt) {
mTrrTxt->Cancel();
mTrrTxt = nullptr;
}
}
void
@ -651,7 +658,11 @@ nsHostResolver::ClearPendingQueue(LinkedList<RefPtr<nsHostRecord>>& aPendingQ)
if (!aPendingQ.isEmpty()) {
for (RefPtr<nsHostRecord> rec : aPendingQ) {
rec->Cancel();
CompleteLookup(rec, NS_ERROR_ABORT, nullptr, rec->pb);
if (rec->type == nsIDNSService::RESOLVE_TYPE_DEFAULT) {
CompleteLookup(rec, NS_ERROR_ABORT, nullptr, rec->pb);
} else {
CompleteLookupByType(rec, NS_ERROR_ABORT, nullptr, 0, rec->pb);
}
}
}
}
@ -779,7 +790,8 @@ nsHostResolver::GetHostRecord(const nsACString &host,
nsHostRecord **result)
{
MutexAutoLock lock(mLock);
nsHostKey key(host, flags, af, pb, originSuffix);
nsHostKey key(host, nsIDNSService::RESOLVE_TYPE_DEFAULT, flags, af, pb,
originSuffix);
RefPtr<nsHostRecord>& entry = mRecordDB.GetOrInsert(key);
if (!entry) {
@ -799,6 +811,7 @@ nsHostResolver::GetHostRecord(const nsACString &host,
nsresult
nsHostResolver::ResolveHost(const nsACString &aHost,
uint16_t type,
const OriginAttributes &aOriginAttributes,
uint16_t flags,
uint16_t af,
@ -807,9 +820,10 @@ nsHostResolver::ResolveHost(const nsACString &aHost,
nsAutoCString host(aHost);
NS_ENSURE_TRUE(!host.IsEmpty(), NS_ERROR_UNEXPECTED);
LOG(("Resolving host [%s]%s%s.\n", host.get(),
LOG(("Resolving host [%s]%s%s type %d.\n", host.get(),
flags & RES_BYPASS_CACHE ? " - bypassing cache" : "",
flags & RES_REFRESH_CACHE ? " - refresh cache" : ""));
flags & RES_REFRESH_CACHE ? " - refresh cache" : "",
type));
// ensure that we are working with a valid hostname before proceeding. see
// bug 304904 for details.
@ -842,7 +856,7 @@ nsHostResolver::ResolveHost(const nsACString &aHost,
nsAutoCString originSuffix;
aOriginAttributes.CreateSuffix(originSuffix);
nsHostKey key(host, flags, af,
nsHostKey key(host, type, flags, af,
(aOriginAttributes.mPrivateBrowsingId > 0),
originSuffix);
RefPtr<nsHostRecord>& entry = mRecordDB.GetOrInsert(key);
@ -853,11 +867,13 @@ nsHostResolver::ResolveHost(const nsACString &aHost,
RefPtr<nsHostRecord> rec = entry;
MOZ_ASSERT(rec, "Record should not be null");
if (!(flags & RES_BYPASS_CACHE) &&
rec->HasUsableResult(TimeStamp::NowLoRes(), flags)) {
rec->HasUsableResult(TimeStamp::NowLoRes(), flags)) {
LOG((" Using cached record for host [%s].\n", host.get()));
// put reference to host record on stack...
result = rec;
Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2, METHOD_HIT);
if (type == nsIDNSService::RESOLVE_TYPE_DEFAULT) {
Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2, METHOD_HIT);
}
// For entries that are in the grace period
// or all cached negative entries, use the cache but start a new
@ -866,38 +882,53 @@ nsHostResolver::ResolveHost(const nsACString &aHost,
if (rec->negative) {
LOG((" Negative cache entry for host [%s].\n", host.get()));
Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2,
METHOD_NEGATIVE_HIT);
if (type == nsIDNSService::RESOLVE_TYPE_DEFAULT) {
Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2,
METHOD_NEGATIVE_HIT);
}
status = NS_ERROR_UNKNOWN_HOST;
}
} else if (rec->addr) {
// if the host name is an IP address literal and has been parsed,
// go ahead and use it.
LOG((" Using cached address for IP Literal [%s].\n", host.get()));
Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2,
METHOD_LITERAL);
result = rec;
if (type != nsIDNSService::RESOLVE_TYPE_DEFAULT) {
// do not send a query with type for ip literals.
rv = NS_ERROR_UNKNOWN_HOST;
} else {
// if the host name is an IP address literal and has been
// parsed, go ahead and use it.
LOG((" Using cached address for IP Literal [%s].\n",
host.get()));
Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2,
METHOD_LITERAL);
result = rec;
}
} else if (PR_StringToNetAddr(host.get(), &tempAddr) == PR_SUCCESS) {
// try parsing the host name as an IP address literal to short
// circuit full host resolution. (this is necessary on some
// platforms like Win9x. see bug 219376 for more details.)
LOG((" Host is IP Literal [%s].\n", host.get()));
// ok, just copy the result into the host record, and be done
// with it! ;-)
rec->addr = MakeUnique<NetAddr>();
PRNetAddrToNetAddr(&tempAddr, rec->addr.get());
// put reference to host record on stack...
Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2,
METHOD_LITERAL);
result = rec;
if (type != nsIDNSService::RESOLVE_TYPE_DEFAULT) {
// do not send a query with type for ip literals.
rv = NS_ERROR_UNKNOWN_HOST;
} else {
// ok, just copy the result into the host record, and be
// done with it! ;-)
rec->addr = MakeUnique<NetAddr>();
PRNetAddrToNetAddr(&tempAddr, rec->addr.get());
// put reference to host record on stack...
Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2,
METHOD_LITERAL);
result = rec;
}
} else if (mPendingCount >= MAX_NON_PRIORITY_REQUESTS &&
!IsHighPriority(flags) &&
!rec->mResolving) {
LOG((" Lookup queue full: dropping %s priority request for "
"host [%s].\n",
IsMediumPriority(flags) ? "medium" : "low", host.get()));
Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2,
METHOD_OVERFLOW);
if (type == nsIDNSService::RESOLVE_TYPE_DEFAULT) {
Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2,
METHOD_OVERFLOW);
}
// This is a lower priority request and we are swamped, so refuse it.
rv = NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
} else if (flags & RES_OFFLINE) {
@ -909,8 +940,11 @@ nsHostResolver::ResolveHost(const nsACString &aHost,
if (!(flags & RES_BYPASS_CACHE) &&
((af == PR_AF_INET) || (af == PR_AF_INET6))) {
MOZ_ASSERT(type == nsIDNSService::RESOLVE_TYPE_DEFAULT);
// First, search for an entry with AF_UNSPEC
const nsHostKey unspecKey(host, flags, PR_AF_UNSPEC,
const nsHostKey unspecKey(host,
nsIDNSService::RESOLVE_TYPE_DEFAULT,
flags, PR_AF_UNSPEC,
(aOriginAttributes.mPrivateBrowsingId > 0),
originSuffix);
RefPtr<nsHostRecord> unspecRec = mRecordDB.Get(unspecKey);
@ -995,8 +1029,10 @@ nsHostResolver::ResolveHost(const nsACString &aHost,
rec->mCallbacks.insertBack(callback);
rec->flags = flags;
rv = NameLookup(rec);
Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2,
METHOD_NETWORK_FIRST);
if (type == nsIDNSService::RESOLVE_TYPE_DEFAULT) {
Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2,
METHOD_NETWORK_FIRST);
}
if (NS_FAILED(rv) && callback->isInList()) {
callback->remove();
} else {
@ -1010,7 +1046,9 @@ nsHostResolver::ResolveHost(const nsACString &aHost,
// at once
result = rec;
// make it count as a hit
Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2, METHOD_HIT);
if (type == nsIDNSService::RESOLVE_TYPE_DEFAULT) {
Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2, METHOD_HIT);
}
LOG((" Host [%s] re-using early TRR resolve data\n", host.get()));
} else {
LOG((" Host [%s] is being resolved. Appending callback "
@ -1018,8 +1056,10 @@ nsHostResolver::ResolveHost(const nsACString &aHost,
rec->mCallbacks.insertBack(callback);
if (rec->onQueue) {
Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2,
METHOD_NETWORK_SHARED);
if (type == nsIDNSService::RESOLVE_TYPE_DEFAULT) {
Telemetry::Accumulate(Telemetry::DNS_LOOKUP_METHOD2,
METHOD_NETWORK_SHARED);
}
// Consider the case where we are on a pending queue of
// lower priority than the request is being made at.
@ -1059,6 +1099,7 @@ nsHostResolver::ResolveHost(const nsACString &aHost,
void
nsHostResolver::DetachCallback(const nsACString &host,
uint16_t aType,
const OriginAttributes &aOriginAttributes,
uint16_t flags,
uint16_t af,
@ -1074,7 +1115,7 @@ nsHostResolver::DetachCallback(const nsACString &host,
nsAutoCString originSuffix;
aOriginAttributes.CreateSuffix(originSuffix);
nsHostKey key(host, flags, af,
nsHostKey key(host, aType, flags, af,
(aOriginAttributes.mPrivateBrowsingId > 0),
originSuffix);
RefPtr<nsHostRecord> entry = mRecordDB.Get(key);
@ -1142,7 +1183,7 @@ nsHostResolver::TrrLookup(nsHostRecord *aRec, TRR *pushedTRR)
RefPtr<nsHostRecord> rec(aRec);
mLock.AssertCurrentThreadOwns();
#ifdef DEBUG
{
if (rec->type == nsIDNSService::RESOLVE_TYPE_DEFAULT) {
MutexAutoLock trrlock(rec->mTrrLock);
MOZ_ASSERT(!TRROutstanding());
}
@ -1164,14 +1205,22 @@ nsHostResolver::TrrLookup(nsHostRecord *aRec, TRR *pushedTRR)
}
rec->mTRRSuccess = 0; // bump for each successful TRR response
rec->mTrrAUsed = nsHostRecord::INIT;
rec->mTrrAAAAUsed = nsHostRecord::INIT;
rec->mTrrStart = TimeStamp::Now();
rec->mTRRUsed = true; // this record gets TRR treatment
// If asking for AF_UNSPEC, issue both A and AAAA.
// If asking for AF_INET6 or AF_INET, do only that single type
enum TrrType rectype = (rec->af == AF_INET6)? TRRTYPE_AAAA : TRRTYPE_A;
enum TrrType rectype;
if (rec->type == nsIDNSService::RESOLVE_TYPE_DEFAULT) {
rec->mTrrAUsed = nsHostRecord::INIT;
rec->mTrrAAAAUsed = nsHostRecord::INIT;
// If asking for AF_UNSPEC, issue both A and AAAA.
// If asking for AF_INET6 or AF_INET, do only that single type
rectype = (rec->af == AF_INET6)? TRRTYPE_AAAA : TRRTYPE_A;
} else {
rectype = TRRTYPE_TXT;
}
if (pushedTRR) {
rectype = pushedTRR->Type();
}
@ -1197,6 +1246,9 @@ nsHostResolver::TrrLookup(nsHostRecord *aRec, TRR *pushedTRR)
MOZ_ASSERT(!rec->mTrrAAAA);
rec->mTrrAAAA = trr;
rec->mTrrAAAAUsed = nsHostRecord::STARTED;
} else if (rectype == TRRTYPE_TXT) {
MOZ_ASSERT(!rec->mTrrTxt);
rec->mTrrTxt = trr;
} else {
LOG(("TrrLookup called with bad type set: %d\n", rectype));
MOZ_ASSERT(0);
@ -1231,6 +1283,9 @@ nsresult
nsHostResolver::NativeLookup(nsHostRecord *aRec)
{
mLock.AssertCurrentThreadOwns();
if (aRec->type != nsIDNSService::RESOLVE_TYPE_DEFAULT) {
return NS_ERROR_UNKNOWN_HOST;
}
RefPtr<nsHostRecord> rec(aRec);
rec->mNativeStart = TimeStamp::Now();
@ -1301,8 +1356,11 @@ nsHostResolver::NameLookup(nsHostRecord *rec)
rec->mNativeSuccess = false;
rec->mTRRSuccess = 0;
rec->mDidCallbacks = false;
rec->mTrrAUsed = nsHostRecord::INIT;
rec->mTrrAAAAUsed = nsHostRecord::INIT;
if (rec->type == nsIDNSService::RESOLVE_TYPE_DEFAULT) {
rec->mTrrAUsed = nsHostRecord::INIT;
rec->mTrrAAAAUsed = nsHostRecord::INIT;
}
if (rec->flags & RES_DISABLE_TRR) {
if (mode == MODE_TRRONLY) {
@ -1319,6 +1377,9 @@ nsHostResolver::NameLookup(nsHostRecord *rec)
TRR_DISABLED(mode) ||
(mode == MODE_SHADOW) ||
((mode == MODE_TRRFIRST) && NS_FAILED(rv))) {
if (rec->type != nsIDNSService::RESOLVE_TYPE_DEFAULT) {
return rv;
}
rv = NativeLookup(rec);
}
@ -1523,6 +1584,32 @@ different_rrset(AddrInfo *rrset1, AddrInfo *rrset2)
return false;
}
void
nsHostResolver::AddToEvictionQ(nsHostRecord* rec)
{
MOZ_ASSERT(!rec->isInList());
mEvictionQ.insertBack(rec);
if (mEvictionQSize < mMaxCacheEntries) {
mEvictionQSize++;
} else {
// remove first element on mEvictionQ
RefPtr<nsHostRecord> head = mEvictionQ.popFirst();
mRecordDB.Remove(*static_cast<nsHostKey *>(head.get()));
if (!head->negative) {
// record the age of the entry upon eviction.
TimeDuration age = TimeStamp::NowLoRes() - head->mValidStart;
Telemetry::Accumulate(Telemetry::DNS_CLEANUP_AGE,
static_cast<uint32_t>(age.ToSeconds() / 60));
if (head->CheckExpiration(TimeStamp::Now()) !=
nsHostRecord::EXP_EXPIRED) {
Telemetry::Accumulate(Telemetry::DNS_PREMATURE_EVICTION,
static_cast<uint32_t>(age.ToSeconds() / 60));
}
}
}
}
//
// CompleteLookup() checks if the resolving should be redone and if so it
// returns LOOKUP_RESOLVEAGAIN, but only if 'status' is not NS_ERROR_ABORT.
@ -1729,28 +1816,7 @@ nsHostResolver::CompleteLookup(nsHostRecord* rec, nsresult status, AddrInfo* aNe
if (!rec->mResolving && !mShutdown) {
rec->ResolveComplete();
// add to mEvictionQ
MOZ_ASSERT(!rec->isInList());
mEvictionQ.insertBack(rec);
if (mEvictionQSize < mMaxCacheEntries) {
mEvictionQSize++;
} else {
// remove first element on mEvictionQ
RefPtr<nsHostRecord> head = mEvictionQ.popFirst();
mRecordDB.Remove(*static_cast<nsHostKey *>(head.get()));
if (!head->negative) {
// record the age of the entry upon eviction.
TimeDuration age = TimeStamp::NowLoRes() - head->mValidStart;
Telemetry::Accumulate(Telemetry::DNS_CLEANUP_AGE,
static_cast<uint32_t>(age.ToSeconds() / 60));
if (head->CheckExpiration(TimeStamp::Now()) !=
nsHostRecord::EXP_EXPIRED) {
Telemetry::Accumulate(Telemetry::DNS_PREMATURE_EVICTION,
static_cast<uint32_t>(age.ToSeconds() / 60));
}
}
}
AddToEvictionQ(rec);
}
#ifdef DNSQUERY_AVAILABLE
@ -1777,8 +1843,50 @@ nsHostResolver::CompleteLookup(nsHostRecord* rec, nsresult status, AddrInfo* aNe
return LOOKUP_OK;
}
nsHostResolver::LookupStatus
nsHostResolver::CompleteLookupByType(nsHostRecord* rec, nsresult status,
const nsTArray<nsCString> *aResult,
uint32_t aTtl, bool pb)
{
MutexAutoLock lock(mLock);
MOZ_ASSERT(rec);
MOZ_ASSERT(rec->pb == pb);
MOZ_ASSERT(rec->mResolving);
rec->mResolving--;
MutexAutoLock trrlock(rec->mTrrLock);
rec->mTrrTxt = nullptr;
if (NS_FAILED(status)) {
rec->SetExpiration(TimeStamp::NowLoRes(),
NEGATIVE_RECORD_LIFETIME, 0);
MOZ_ASSERT(!aResult);
status = NS_ERROR_UNKNOWN_HOST;
rec->negative = true;
} else {
MOZ_ASSERT(aResult);
MutexAutoLock byTypeLock(rec->mRequestByTypeResultLock);
rec->mRequestByTypeResult = *aResult;
rec->SetExpiration(TimeStamp::NowLoRes(), aTtl, mDefaultGracePeriod);
rec->negative = false;
}
mozilla::LinkedList<RefPtr<nsResolveHostCallback>> cbs = std::move(rec->mCallbacks);
LOG(("nsHostResolver record %p calling back dns users\n", rec));
for (nsResolveHostCallback* c = cbs.getFirst(); c; c = c->removeAndGetNext()) {
c->OnResolveHostComplete(this, rec, status);
}
AddToEvictionQ(rec);
return LOOKUP_OK;
}
void
nsHostResolver::CancelAsyncRequest(const nsACString &host,
uint16_t aType,
const OriginAttributes &aOriginAttributes,
uint16_t flags,
uint16_t af,
@ -1793,7 +1901,7 @@ nsHostResolver::CancelAsyncRequest(const nsACString &host,
// Lookup the host record associated with host, flags & address family
nsHostKey key(host, flags, af,
nsHostKey key(host, aType, flags, af,
(aOriginAttributes.mPrivateBrowsingId > 0),
originSuffix);
RefPtr<nsHostRecord> rec = mRecordDB.Get(key);

View File

@ -53,11 +53,12 @@ extern mozilla::Atomic<bool, mozilla::Relaxed> gNativeIsLocalhost;
struct nsHostKey
{
const nsCString host;
uint16_t type;
uint16_t flags;
uint16_t af;
bool pb;
const nsCString originSuffix;
explicit nsHostKey(const nsACString& host, uint16_t flags,
explicit nsHostKey(const nsACString& host, uint16_t type, uint16_t flags,
uint16_t af, bool pb, const nsACString& originSuffix);
bool operator==(const nsHostKey& other) const;
size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
@ -161,6 +162,9 @@ public:
mozilla::net::ResolverMode mResolverMode;
nsTArray<nsCString> mRequestByTypeResult;
Mutex mRequestByTypeResultLock;
private:
friend class nsHostResolver;
@ -195,6 +199,7 @@ private:
Mutex mTrrLock; // lock when accessing the mTrrA[AAA] pointers
RefPtr<mozilla::net::TRR> mTrrA;
RefPtr<mozilla::net::TRR> mTrrAAAA;
RefPtr<mozilla::net::TRR> mTrrTxt;
// The number of times ReportUnusable() has been called in the record's
// lifetime.
@ -271,6 +276,9 @@ public:
};
virtual LookupStatus CompleteLookup(nsHostRecord *, nsresult, mozilla::net::AddrInfo *, bool pb) = 0;
virtual LookupStatus CompleteLookupByType(nsHostRecord *, nsresult,
const nsTArray<nsCString> *aResult,
uint32_t aTtl, bool pb) = 0;
virtual nsresult GetHostRecord(const nsACString &host,
uint16_t flags, uint16_t af, bool pb,
const nsCString &originSuffix,
@ -324,6 +332,7 @@ public:
* having the callback implementation return without doing anything).
*/
nsresult ResolveHost(const nsACString &hostname,
uint16_t type,
const mozilla::OriginAttributes &aOriginAttributes,
uint16_t flags,
uint16_t af,
@ -336,6 +345,7 @@ public:
* executes the callback if the callback is still pending with the given status.
*/
void DetachCallback(const nsACString &hostname,
uint16_t type,
const mozilla::OriginAttributes &aOriginAttributes,
uint16_t flags,
uint16_t af,
@ -350,6 +360,7 @@ public:
* host record, it is removed from any request queues it might be on.
*/
void CancelAsyncRequest(const nsACString &host,
uint16_t type,
const mozilla::OriginAttributes &aOriginAttributes,
uint16_t flags,
uint16_t af,
@ -384,6 +395,9 @@ public:
void FlushCache();
LookupStatus CompleteLookup(nsHostRecord *, nsresult, mozilla::net::AddrInfo *, bool pb) override;
LookupStatus CompleteLookupByType(nsHostRecord *, nsresult,
const nsTArray<nsCString> *aResult,
uint32_t aTtl, bool pb) override;
nsresult GetHostRecord(const nsACString &host,
uint16_t flags, uint16_t af, bool pb,
const nsCString &originSuffix,
@ -421,6 +435,8 @@ private:
*/
nsresult ConditionallyRefreshRecord(nsHostRecord *rec, const nsACString &host);
void AddToEvictionQ(nsHostRecord* rec);
void ThreadFunc();
enum {

View File

@ -0,0 +1,22 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
%{ C++
#include "nsTArrayForwardDeclare.h"
%}
[ref] native CStringArrayRef(nsTArray<nsCString>);
[scriptable, uuid(5d13241b-9d46-448a-90d8-77c418491026)]
interface nsIDNSByTypeRecord : nsISupports
{
CStringArrayRef getRecords();
/*
* Return concatenated strings.
*/
ACString getRecordsAsOneString();
};

View File

@ -6,11 +6,12 @@
interface nsICancelable;
interface nsIDNSRecord;
interface nsIDNSByTypeRecord;
/**
* nsIDNSListener
*/
[scriptable, function, uuid(27d49bfe-280c-49e0-bbaa-f6200c232c3d)]
[scriptable, uuid(27d49bfe-280c-49e0-bbaa-f6200c232c3d)]
interface nsIDNSListener : nsISupports
{
/**
@ -27,6 +28,20 @@ interface nsIDNSListener : nsISupports
void onLookupComplete(in nsICancelable aRequest,
in nsIDNSRecord aRecord,
in nsresult aStatus);
/**
* called when an asynchronous dns lookup by type completes.
*
* @param aRequest
* the value returned from asyncResolve.
* @param aRecord
* a string returned by the dns server.
* @param aStatus
* if the lookup failed, this parameter gives the reason.
*/
void onLookupByTypeComplete(in nsICancelable aRequest,
in nsIDNSByTypeRecord aResult,
in nsresult aStatus);
};
/**

View File

@ -66,6 +66,48 @@ interface nsIDNSService : nsISupports
in OriginAttributes aOriginAttributes,
out nsICancelable aResult);
/**
* kicks off an asynchronous host lookup by type, e.g. TXT.
*
* @param aHostName
* the hostname or IP-address-literal to resolve.
* @param aType
* one of RESOLVE_TYPE_*.
* @param aFlags
* a bitwise OR of the RESOLVE_ prefixed constants defined below
* except RESOLVE_CANONICAL_NAME, RESOLVE_DISABLE_IPV6 and
* RESOLVE_DISABLE_IPV4.
* @param aListener
* the listener to be notified when the result is available.
* @param aListenerTarget
* optional parameter (may be null). if non-null, this parameter
* specifies the nsIEventTarget of the thread on which the
* listener's onLookupComplete should be called. however, if this
* parameter is null, then onLookupComplete will be called on an
* unspecified thread (possibly recursively).
* @param aOriginAttributes
* the originAttribute for this resolving, the DNS cache will be
* separated according to this originAttributes.
*
* @return An object that can be used to cancel the host lookup.
*/
[implicit_jscontext, optional_argc]
nsICancelable asyncResolveByType(in AUTF8String aHostName,
in unsigned short aType,
in unsigned long aFlags,
in nsIDNSListener aListener,
in nsIEventTarget aListenerTarget,
in jsval aOriginAttributes);
[notxpcom]
nsresult asyncResolveByTypeNative(in AUTF8String aHostName,
in unsigned short aType,
in unsigned long aFlags,
in nsIDNSListener aListener,
in nsIEventTarget aListenerTarget,
in OriginAttributes aOriginAttributes,
out nsICancelable aResult);
/**
* Attempts to cancel a previously requested async DNS lookup
*
@ -81,8 +123,6 @@ interface nsIDNSService : nsISupports
* @param aOriginAttributes
* the originAttribute for this resolving. This attribute is optional
* to avoid breaking add-ons.
*
* @return An object that can be used to cancel the host lookup.
*/
[implicit_jscontext, optional_argc]
void cancelAsyncResolve(in AUTF8String aHostName,
@ -98,6 +138,43 @@ interface nsIDNSService : nsISupports
in nsresult aReason,
in OriginAttributes aOriginAttributes);
/**
* Attempts to cancel a previously requested async DNS lookup
*
* @param aHostName
* the hostname or IP-address-literal to resolve.
* @param aType
* one of RESOLVE_TYPE_*.
* @param aFlags
* a bitwise OR of the RESOLVE_ prefixed constants defined below
* except RESOLVE_CANONICAL_NAME, RESOLVE_DISABLE_IPV6 and
* RESOLVE_DISABLE_IPV4.
* @param aListener
* the original listener which was to be notified about the host lookup
* result - used to match request information to requestor.
* @param aReason
* nsresult reason for the cancellation
* @param aOriginAttributes
* the originAttribute for this resolving. This attribute is optional
* to avoid breaking add-ons.
*
*/
[implicit_jscontext, optional_argc]
void cancelAsyncResolveByType(in AUTF8String aHostName,
in unsigned short aType,
in unsigned long aFlags,
in nsIDNSListener aListener,
in nsresult aReason,
in jsval aOriginAttributes);
[notxpcom]
nsresult cancelAsyncResolveByTypeNative(in AUTF8String aHostName,
in unsigned short aType,
in unsigned long aFlags,
in nsIDNSListener aListener,
in nsresult aReason,
in OriginAttributes aOriginAttributes);
/**
* called to synchronously resolve a hostname.
*
@ -199,4 +276,12 @@ interface nsIDNSService : nsISupports
* existing cache entry first (if existing) then make a new resolve.
*/
const unsigned long RESOLVE_REFRESH_CACHE = (1 << 10);
/**
* This ure dns request types that are currently supported.
* RESOLVE_TYPE_DEFAULT is standard A/AAAA lookup
* The others (currently only TXT supported) are wireformat types
*/
const unsigned long RESOLVE_TYPE_DEFAULT = 0;
const unsigned long RESOLVE_TYPE_TXT = 16;
};

View File

@ -696,21 +696,23 @@ NeckoParent::RecvSpeculativeConnect(const URIParams& aURI,
}
mozilla::ipc::IPCResult
NeckoParent::RecvHTMLDNSPrefetch(const nsString& hostname,
NeckoParent::RecvHTMLDNSPrefetch(const nsString& hostname, const bool& isHttps,
const OriginAttributes& aOriginAttributes,
const uint16_t& flags)
{
nsHTMLDNSPrefetch::Prefetch(hostname, aOriginAttributes, flags);
nsHTMLDNSPrefetch::Prefetch(hostname, isHttps, aOriginAttributes, flags);
return IPC_OK();
}
mozilla::ipc::IPCResult
NeckoParent::RecvCancelHTMLDNSPrefetch(const nsString& hostname,
const bool& isHttps,
const OriginAttributes& aOriginAttributes,
const uint16_t& flags,
const nsresult& reason)
{
nsHTMLDNSPrefetch::CancelPrefetch(hostname, aOriginAttributes, flags, reason);
nsHTMLDNSPrefetch::CancelPrefetch(hostname, isHttps, aOriginAttributes,
flags, reason);
return IPC_OK();
}

View File

@ -163,9 +163,11 @@ protected:
const Principal& aPrincipal,
const bool& aAnonymous) override;
virtual mozilla::ipc::IPCResult RecvHTMLDNSPrefetch(const nsString& hostname,
const bool& isHttps,
const OriginAttributes& aOriginAttributes,
const uint16_t& flags) override;
virtual mozilla::ipc::IPCResult RecvCancelHTMLDNSPrefetch(const nsString& hostname,
const bool& isHttps,
const OriginAttributes& aOriginAttributes,
const uint16_t& flags,
const nsresult& reason) override;

View File

@ -94,9 +94,10 @@ parent:
async PredReset();
async SpeculativeConnect(URIParams uri, Principal principal, bool anonymous);
async HTMLDNSPrefetch(nsString hostname, OriginAttributes originAttributes,
uint16_t flags);
async CancelHTMLDNSPrefetch(nsString hostname, OriginAttributes originAttributes,
async HTMLDNSPrefetch(nsString hostname, bool isHttps,
OriginAttributes originAttributes, uint16_t flags);
async CancelHTMLDNSPrefetch(nsString hostname, bool isHttps,
OriginAttributes originAttributes,
uint16_t flags, nsresult reason);
/**

View File

@ -1538,6 +1538,13 @@ SocketTransportShim::GetFirstRetryError(nsresult *aFirstRetryError)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
SocketTransportShim::GetEsniUsed(bool *aEsniUsed)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
#define FWD_TS_PTR(fx, ts) NS_IMETHODIMP \
SocketTransportShim::fx(ts *arg) { return mWrapped->fx(arg); }

View File

@ -8781,6 +8781,14 @@ nsHttpChannel::OnLookupComplete(nsICancelable *request,
return NS_OK;
}
NS_IMETHODIMP
nsHttpChannel::OnLookupByTypeComplete(nsICancelable *aRequest,
nsIDNSByTypeRecord *aRes,
nsresult aStatus)
{
return NS_OK;
}
//-----------------------------------------------------------------------------
// nsHttpChannel internal functions
//-----------------------------------------------------------------------------

View File

@ -17,6 +17,11 @@
#define TLS_EARLY_DATA_AVAILABLE_BUT_NOT_USED 1
#define TLS_EARLY_DATA_AVAILABLE_AND_USED 2
#define ESNI_SUCCESSFUL 0
#define ESNI_FAILED 1
#define NO_ESNI_SUCCESSFUL 2
#define NO_ESNI_FAILED 3
#include "ASpdySession.h"
#include "mozilla/ChaosMode.h"
#include "mozilla/Telemetry.h"
@ -34,7 +39,9 @@
#include "nsProxyRelease.h"
#include "nsSocketTransport2.h"
#include "nsStringStream.h"
#include "pkix/pkixnss.h"
#include "sslt.h"
#include "NSSErrorsService.h"
#include "TunnelUtils.h"
#include "TCPFastOpenLayer.h"
@ -412,10 +419,12 @@ nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue,
return true;
}
nsresult rv;
nsresult rv = NS_OK;
nsCOMPtr<nsISupports> securityInfo;
nsCOMPtr<nsISSLSocketControl> ssl;
nsAutoCString negotiatedNPN;
// This is neede for telemetry
bool handshakeSucceeded = false;
GetSecurityInfo(getter_AddRefs(securityInfo));
if (!securityInfo) {
@ -520,15 +529,22 @@ nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue,
this, mConnInfo->HashKey().get(), negotiatedNPN.get(),
mTLSFilter ? " [Double Tunnel]" : ""));
handshakeSucceeded = true;
int16_t tlsVersion;
ssl->GetSSLVersionUsed(&tlsVersion);
mConnInfo->SetLessThanTls13((tlsVersion < nsISSLSocketControl::TLS_VERSION_1_3) &&
(tlsVersion != nsISSLSocketControl::SSL_VERSION_UNKNOWN));
bool earlyDataAccepted = false;
if (mWaitingFor0RTTResponse) {
// Check if early data has been accepted.
rv = ssl->GetEarlyDataAccepted(&earlyDataAccepted);
nsresult rvEarlyData = ssl->GetEarlyDataAccepted(&earlyDataAccepted);
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - early data "
"that was sent during 0RTT %s been accepted [rv=%" PRIx32 "].",
this, earlyDataAccepted ? "has" : "has not", static_cast<uint32_t>(rv)));
if (NS_FAILED(rv) ||
if (NS_FAILED(rvEarlyData) ||
NS_FAILED(mTransaction->Finish0RTT(!earlyDataAccepted, negotiatedNPN != mEarlyNegotiatedALPN))) {
LOG(("nsHttpConection::EnsureNPNComplete [this=%p] closing transaction %p", this, mTransaction.get()));
mTransaction->Close(NS_ERROR_NET_RESET);
@ -536,8 +552,6 @@ nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue,
}
}
int16_t tlsVersion;
ssl->GetSSLVersionUsed(&tlsVersion);
// Send the 0RTT telemetry only for tls1.3
if (tlsVersion > nsISSLSocketControl::TLS_VERSION_1_2) {
Telemetry::Accumulate(Telemetry::TLS_EARLY_DATA_NEGOTIATED,
@ -633,6 +647,19 @@ npnComplete:
// so it can actually do everything it needs to do.
mDid0RTTSpdy = false;
}
if (ssl) {
// Telemetry for tls failure rate with and without esni;
bool esni;
mSocketTransport->GetEsniUsed(&esni);
Telemetry::Accumulate(Telemetry::ESNI_NOESNI_TLS_SUCCESS_RATE,
(esni) ? ((handshakeSucceeded) ? ESNI_SUCCESSFUL : ESNI_FAILED)
: ((handshakeSucceeded) ? NO_ESNI_SUCCESSFUL : NO_ESNI_FAILED));
}
if (rv == psm::GetXPCOMFromNSSError(mozilla::pkix::MOZILLA_PKIX_ERROR_MITM_DETECTED)) {
gSocketTransportService->SetNotTrustedMitmDetected();
}
return true;
}

View File

@ -50,6 +50,7 @@ nsHttpConnectionInfo::nsHttpConnectionInfo(const nsACString &originHost,
const OriginAttributes &originAttributes,
bool endToEndSSL)
: mRoutedPort(443)
, mLessThanTls13(false)
{
Init(originHost, originPort, npnToken, username, proxyInfo, originAttributes, endToEndSSL);
}
@ -62,6 +63,7 @@ nsHttpConnectionInfo::nsHttpConnectionInfo(const nsACString &originHost,
const OriginAttributes &originAttributes,
const nsACString &routedHost,
int32_t routedPort)
: mLessThanTls13(false)
{
mEndToEndSSL = true; // so DefaultPort() works
mRoutedPort = routedPort == -1 ? DefaultPort() : routedPort;

View File

@ -155,6 +155,12 @@ public:
// Returns true when origin/proxy is an RFC1918 literal.
bool HostIsLocalIPLiteral() const;
bool GetLessThanTls13() const { return mLessThanTls13; }
void SetLessThanTls13(bool aLessThanTls13)
{
mLessThanTls13 = aLessThanTls13;
}
private:
void Init(const nsACString &host,
int32_t port,
@ -184,6 +190,10 @@ private:
uint16_t mTrrUsed : 1;
uint16_t mTrrDisabled : 1;
bool mLessThanTls13; // This will be set to true if we negotiate less than
// tls1.3. If the tls version is till not know or it
// is 1.3 or greater the value will be false.
// for RefPtr
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsHttpConnectionInfo, override)
};

View File

@ -4076,6 +4076,10 @@ nsHalfOpenSocket::SetupStreams(nsISocketTransport **transport,
if (ci->GetPrivate())
tmpFlags |= nsISocketTransport::NO_PERMANENT_STORAGE;
if (ci->GetLessThanTls13()) {
tmpFlags |= nsISocketTransport::DONT_TRY_ESNI;
}
if ((mCaps & NS_HTTP_BE_CONSERVATIVE) || ci->GetBeConservative()) {
LOG(("Setting Socket to BE_CONSERVATIVE"));
tmpFlags |= nsISocketTransport::BE_CONSERVATIVE;

View File

@ -3150,6 +3150,14 @@ WebSocketChannel::OnLookupComplete(nsICancelable *aRequest,
return NS_OK;
}
NS_IMETHODIMP
WebSocketChannel::OnLookupByTypeComplete(nsICancelable *aRequest,
nsIDNSByTypeRecord *aRes,
nsresult aStatus)
{
return NS_OK;
}
// nsIProtocolProxyCallback
NS_IMETHODIMP
WebSocketChannel::OnProxyAvailable(nsICancelable *aRequest, nsIChannel *aChannel,

View File

@ -161,5 +161,17 @@ interface nsISSLSocketControl : nsISupports {
* or are using acceptable exceptions will all return false.
*/
[infallible] readonly attribute boolean failedVerification;
/*
* esniTxt is a string that consists of the concatenated _esni. TXT records.
* This is a base64 encoded ESNIKeys structure.
*/
attribute ACString esniTxt;
/**
* If the server certificate is present, serverCertIsBuiltInRoot is true if
* the root certificate for the server certificate is built in.
*/
readonly attribute boolean serverRootCertIsBuiltInRoot;
};

View File

@ -524,6 +524,14 @@ nsSOCKSSocketInfo::OnLookupComplete(nsICancelable *aRequest,
return NS_OK;
}
NS_IMETHODIMP
nsSOCKSSocketInfo::OnLookupByTypeComplete(nsICancelable *aRequest,
nsIDNSByTypeRecord *res,
nsresult aStatus)
{
return NS_OK;
}
PRStatus
nsSOCKSSocketInfo::ConnectToProxy(PRFileDesc *fd)
{

View File

@ -0,0 +1,105 @@
Cu.import("resource://gre/modules/NetUtil.jsm");
var prefs;
var h2Port;
var listen;
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() {
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.security.esni.enabled", true);
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 + "/esni-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();
listen = dns.asyncResolveByType("_esni.example.com", dns.RESOLVE_TYPE_TXT, 0, listenerFine, mainThread, defaultOriginAttributes);
}
registerCleanupFunction(() => {
prefs.clearUserPref("network.security.esni.enabled");
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");
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");
});
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);
}
var test_answer="bXkgdm9pY2UgaXMgbXkgcGFzc3dvcmQ=";
// check that we do lookup by type fine
var listenerFine = {
onLookupByTypeComplete: function(inRequest, inRecord, inStatus) {
if (inRequest == listen) {
Assert.ok(!inStatus);
var answer = inRecord.getRecordsAsOneString();
Assert.equal(answer, test_answer);
do_test_finished();
}
},
QueryInterface: function(aIID) {
if (aIID.equals(Ci.nsIDNSListener) ||
aIID.equals(Ci.nsISupports)) {
return this;
}
throw Cr.NS_ERROR_NO_INTERFACE;
}
};

View File

@ -418,3 +418,7 @@ skip-if = os == "android"
[test_substituting_protocol_handler.js]
[test_captive_portal_service.js]
skip-if = os == "android" # CP service is disabled on Android
run-sequentially = node server exceptions dont replay well
[test_esni_dns_fetch.js]
# http2-using tests require node available
skip-if = os == "android"

View File

@ -1007,6 +1007,62 @@ nsNSSSocketInfo::CloseSocketAndDestroy()
return PR_SUCCESS;
}
NS_IMETHODIMP
nsNSSSocketInfo::GetEsniTxt(nsACString & aEsniTxt)
{
aEsniTxt = mEsniTxt;
return NS_OK;
}
NS_IMETHODIMP
nsNSSSocketInfo::SetEsniTxt(const nsACString & aEsniTxt)
{
mEsniTxt = aEsniTxt;
if (mEsniTxt.Length()) {
fprintf(stderr,"\n\nTODO - SSL_EnableSNI() [%s] (%d bytes)\n",
mEsniTxt.get(), mEsniTxt.Length());
#if 0
if (SECSuccess != SSL_EnableESNI(mFd,
reinterpret_cast<const PRUint8*>(mEsniTxt.get()),
mEsniTxt.Length(), "dummy.invalid")) {
return NS_ERROR_FAILURE;
}
#endif
}
return NS_OK;
}
NS_IMETHODIMP
nsNSSSocketInfo::GetServerRootCertIsBuiltInRoot(bool *aIsBuiltInRoot)
{
*aIsBuiltInRoot = false;
if (!HasServerCert()) {
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsIX509CertList> certList;
nsresult rv = GetSucceededCertChain(getter_AddRefs(certList));
if (NS_SUCCEEDED(rv)) {
if (!certList) {
return NS_ERROR_NOT_AVAILABLE;
}
RefPtr<nsNSSCertList> nssCertList = certList->GetCertList();
nsCOMPtr<nsIX509Cert> cert;
rv = nssCertList->GetRootCertificate(cert);
if (NS_SUCCEEDED(rv)) {
if (!cert) {
return NS_ERROR_NOT_AVAILABLE;
}
rv = cert->GetIsBuiltInRoot(aIsBuiltInRoot);
}
}
return rv;
}
#if defined(DEBUG_SSL_VERBOSE) && defined(DUMP_BUFFER)
// Dumps a (potentially binary) buffer using SSM_DEBUG. (We could have used
// the version in ssltrace.c, but that's specifically tailored to SSLTRACE.)

View File

@ -183,6 +183,7 @@ private:
nsresult ActivateSSL();
nsCString mNegotiatedNPN;
nsCString mEsniTxt;
bool mNPNCompleted;
bool mEarlyDataAccepted;
bool mDenyClientCert;

View File

@ -758,6 +758,32 @@ function handleRequest(req, res) {
return;
}
// for use with test_esni_dns_fetch.js
else if (u.pathname === "/esni-dns") {
content = new Buffer("0000" +
"8180" +
"0001" + // QDCOUNT
"0001" + // ANCOUNT
"00000000" + // NSCOUNT + ARCOUNT
"055F65736E69076578616D706C6503636F6D00" + // esni.example.com
"00100001" + // question type (TXT) + question class (IN)
"C00C" + // name pointer to .example.com
"0010" + // type (TXT)
"0001" + // class
"00000037" + // TTL
"0021" + // RDLENGTH
"2062586B67646D39705932556761584D6762586B676347467A63336476636D513D", // esni keys.
"hex");
res.setHeader('Content-Type', 'application/dns-message');
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');
res.setHeader('Content-Type', 'application/json');

View File

@ -2048,6 +2048,36 @@
"alert_emails": ["necko@mozilla.com", "ddamjanovic@mozilla.com"],
"bug_numbers": [1296288]
},
"ESNI_KEYS_RECORD_FETCH_DELAYS": {
"record_in_processes": ["main"],
"expires_in_version": "70",
"kind": "exponential",
"high": 60000,
"n_buckets": 100,
"description": "Added delays caused the esni keys fetching.(ms)",
"alert_emails": ["necko@mozilla.com", "ddamjanovic@mozilla.com"],
"bug_numbers": [1473736],
"releaseChannelCollection": "opt-out"
},
"ESNI_KEYS_RECORDS_FOUND": {
"record_in_processes": ["main"],
"expires_in_version": "70",
"kind": "boolean",
"description": "ESNI Keys found rate.",
"alert_emails": ["necko@mozilla.com", "ddamjanovic@mozilla.com"],
"bug_numbers": [1473736],
"releaseChannelCollection": "opt-out"
},
"ESNI_NOESNI_TLS_SUCCESS_RATE": {
"record_in_processes": ["main"],
"expires_in_version": "70",
"kind": "categorical",
"labels": ["EsniTLSSucceeded", "EsniTLSFailed", "NoEsniTLSSucceeded", "NoEsniTLSFailed"],
"description": "TLS handshake with and without esni success rate.",
"alert_emails": ["necko@mozilla.com", "ddamjanovic@mozilla.com"],
"bug_numbers": [1473736],
"releaseChannelCollection": "opt-out"
},
"SSL_HANDSHAKE_VERSION": {
"record_in_processes": ["main", "content"],
"alert_emails": ["seceng-telemetry@mozilla.com"],