mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
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:
parent
c24ed5f87b
commit
f000a5b4b0
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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"));
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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() {}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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__();
|
||||
|
||||
|
@ -23,6 +23,7 @@ struct DNSRecord
|
||||
union DNSRequestResponse
|
||||
{
|
||||
DNSRecord;
|
||||
nsCString[]; // The result of a by-type query
|
||||
nsresult; // if error
|
||||
};
|
||||
|
||||
|
@ -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()));
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -12,6 +12,7 @@ DIRS += [
|
||||
]
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIDNSByTypeRecord.idl',
|
||||
'nsIDNSListener.idl',
|
||||
'nsIDNSRecord.idl',
|
||||
'nsIDNSService.idl',
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
22
netwerk/dns/nsIDNSByTypeRecord.idl
Normal file
22
netwerk/dns/nsIDNSByTypeRecord.idl
Normal 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();
|
||||
};
|
@ -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);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
|
@ -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); }
|
||||
|
||||
|
@ -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
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
105
netwerk/test/unit/test_esni_dns_fetch.js
Normal file
105
netwerk/test/unit/test_esni_dns_fetch.js
Normal 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;
|
||||
}
|
||||
};
|
||||
|
@ -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"
|
||||
|
@ -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.)
|
||||
|
@ -183,6 +183,7 @@ private:
|
||||
nsresult ActivateSSL();
|
||||
|
||||
nsCString mNegotiatedNPN;
|
||||
nsCString mEsniTxt;
|
||||
bool mNPNCompleted;
|
||||
bool mEarlyDataAccepted;
|
||||
bool mDenyClientCert;
|
||||
|
@ -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');
|
||||
|
@ -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"],
|
||||
|
Loading…
Reference in New Issue
Block a user