Bug 1684040 - P1: Introduce new ODoH class for sending ODoH queries r=necko-reviewers,valentin

Differential Revision: https://phabricator.services.mozilla.com/D101682
This commit is contained in:
Kershaw Chang 2021-01-26 14:19:09 +00:00
Родитель f5a8824095
Коммит 19e0167786
22 изменённых файлов: 661 добавлений и 83 удалений

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

@ -8765,6 +8765,30 @@
value: true
mirror: always
# Whether to enable odoh.
- name: network.trr.odoh.enabled
type: RelaxedAtomicBool
value: false
mirror: always
# The uri of Oblivious Proxy.
- name: network.trr.odoh.proxy_uri
type: String
value: ""
mirror: never
# The host name of Oblivious Target.
- name: network.trr.odoh.target_host
type: String
value: ""
mirror: never
# The uri path of the odoh uri.
- name: network.trr.odoh.target_path
type: String
value: ""
mirror: never
# Allow the network changed event to get sent when a network topology or setup
# change is noticed while running.
- name: network.notify.changed

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

@ -151,6 +151,20 @@ union NetAddr {
bool ToStringBuffer(char* buf, uint32_t bufSize) const;
};
struct ObliviousDoHConfigContents {
uint16_t mKemId;
uint16_t mKdfId;
uint16_t mAeadId;
nsTArray<uint8_t> mPublicKey;
};
struct ObliviousDoHConfig {
uint16_t mVersion;
uint16_t mLength;
ObliviousDoHConfigContents mContents;
nsTArray<uint8_t> mConfigId;
};
class AddrInfo {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AddrInfo)

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

@ -315,7 +315,6 @@ nsresult DNSPacket::OnDataAvailable(nsIRequest* aRequest,
const uint8_t kDNS_CLASS_IN = 1;
// static
nsresult DNSPacket::EncodeRequest(nsCString& aBody, const nsACString& aHost,
uint16_t aType, bool aDisableECS) {
aBody.Truncate();
@ -971,5 +970,45 @@ nsresult DNSPacket::Decode(
return NS_OK;
}
// static
bool ODoHDNSPacket::ParseODoHConfigs(const nsCString& aRawODoHConfig,
nsTArray<ObliviousDoHConfig>& aOut) {
// struct {
// uint16 kem_id;
// uint16 kdf_id;
// uint16 aead_id;
// opaque public_key<1..2^16-1>;
// } ObliviousDoHConfigContents;
//
// struct {
// uint16 version;
// uint16 length;
// select (ObliviousDoHConfig.version) {
// case 0xff03: ObliviousDoHConfigContents contents;
// }
// } ObliviousDoHConfig;
//
// ObliviousDoHConfig ObliviousDoHConfigs<1..2^16-1>;
// TODO
return false;
}
ODoHDNSPacket::~ODoHDNSPacket() {}
nsresult ODoHDNSPacket::EncodeRequest(nsCString& aBody, const nsACString& aHost,
uint16_t aType, bool aDisableECS) {
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult ODoHDNSPacket::Decode(
nsCString& aHost, enum TrrType aType, nsCString& aCname, bool aAllowRFC1918,
nsHostRecord::TRRSkippedReason& reason, DOHresp& aResp,
TypeRecordResultType& aTypeResult,
nsClassHashtable<nsCStringHashKey, DOHresp>& aAdditionalRecords,
uint32_t& aTTL) {
return NS_ERROR_NOT_IMPLEMENTED;
}
} // namespace net
} // namespace mozilla

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

@ -32,25 +32,28 @@ enum TrrType {
class DNSPacket {
public:
DNSPacket() = default;
virtual ~DNSPacket() = default;
// Called in order to feed data into the buffer.
nsresult OnDataAvailable(nsIRequest* aRequest, nsIInputStream* aInputStream,
uint64_t aOffset, const uint32_t aCount);
// Encodes the name request into a buffer that represents a DNS packet
static nsresult EncodeRequest(nsCString& aBody, const nsACString& aHost,
uint16_t aType, bool aDisableECS);
virtual nsresult EncodeRequest(nsCString& aBody, const nsACString& aHost,
uint16_t aType, bool aDisableECS);
// Decodes the DNS response and extracts the responses, additional records,
// etc. XXX: This should probably be refactored to reduce the number of
// output parameters and have a common format for different record types.
nsresult Decode(
virtual nsresult Decode(
nsCString& aHost, enum TrrType aType, nsCString& aCname,
bool aAllowRFC1918, nsHostRecord::TRRSkippedReason& reason,
DOHresp& aResp, TypeRecordResultType& aTypeResult,
nsClassHashtable<nsCStringHashKey, DOHresp>& aAdditionalRecords,
uint32_t& aTTL);
private:
protected:
// Never accept larger DOH responses than this as that would indicate
// something is wrong. Typical ones are much smaller.
static const unsigned int MAX_SIZE = 3200;
@ -65,6 +68,27 @@ class DNSPacket {
unsigned int mBodySize = 0;
};
class ODoHDNSPacket final : public DNSPacket {
public:
ODoHDNSPacket() {}
virtual ~ODoHDNSPacket();
static bool ParseODoHConfigs(const nsCString& aRawODoHConfig,
nsTArray<ObliviousDoHConfig>& aOut);
virtual nsresult EncodeRequest(nsCString& aBody, const nsACString& aHost,
uint16_t aType, bool aDisableECS) override;
virtual nsresult Decode(
nsCString& aHost, enum TrrType aType, nsCString& aCname,
bool aAllowRFC1918, nsHostRecord::TRRSkippedReason& reason,
DOHresp& aResp, TypeRecordResultType& aTypeResult,
nsClassHashtable<nsCStringHashKey, DOHresp>& aAdditionalRecords,
uint32_t& aTTL) override;
protected:
};
} // namespace net
} // namespace mozilla

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

@ -0,0 +1,69 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ODoH.h"
#include "mozilla/Base64.h"
#include "nsIURIMutator.h"
#include "ODoHService.h"
#include "TRRService.h"
namespace mozilla {
namespace net {
#undef LOG
#undef LOG_ENABLED
extern mozilla::LazyLogModule gHostResolverLog;
#define LOG(args) MOZ_LOG(gHostResolverLog, mozilla::LogLevel::Debug, args)
#define LOG_ENABLED() \
MOZ_LOG_TEST(mozilla::net::gHostResolverLog, mozilla::LogLevel::Debug)
NS_IMETHODIMP
ODoH::Run() {
if (!gODoHService) {
RecordReason(nsHostRecord::TRR_SEND_FAILED);
FailData(NS_ERROR_FAILURE);
return NS_OK;
}
if (!gODoHService->ODoHConfigs()) {
LOG(("ODoH::Run ODoHConfigs is not available\n"));
if (NS_SUCCEEDED(gODoHService->UpdateODoHConfig())) {
gODoHService->AppendPendingODoHRequest(this);
} else {
FailData(NS_ERROR_FAILURE);
return NS_OK;
}
return NS_OK;
}
return TRR::Run();
}
DNSPacket* ODoH::GetOrCreateDNSPacket() {
if (!mPacket) {
mPacket = MakeUnique<ODoHDNSPacket>();
}
return mPacket.get();
}
nsresult ODoH::CreateQueryURI(nsIURI** aOutURI) {
nsAutoCString uri;
nsCOMPtr<nsIURI> dnsURI;
gODoHService->GetRequestURI(uri);
nsresult rv = NS_NewURI(getter_AddRefs(dnsURI), uri);
if (NS_FAILED(rv)) {
return rv;
}
dnsURI.forget(aOutURI);
return NS_OK;
}
} // namespace net
} // namespace mozilla

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

@ -0,0 +1,38 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_net_ODoH_h
#define mozilla_net_ODoH_h
#include "TRR.h"
namespace mozilla {
namespace net {
class ODoH final : public TRR {
public:
explicit ODoH(AHostResolver* aResolver, nsHostRecord* aRec,
enum TrrType aType)
: TRR(aResolver, aRec, aType) {}
NS_IMETHOD Run() override;
// ODoH should not support push.
NS_IMETHOD GetInterface(const nsIID&, void**) override {
return NS_ERROR_NO_INTERFACE;
}
protected:
virtual ~ODoH() = default;
virtual DNSPacket* GetOrCreateDNSPacket() override;
virtual nsresult CreateQueryURI(nsIURI** aOutURI) override;
virtual const char* ContentType() const override {
return "application/oblivious-dns-message";
}
};
} // namespace net
} // namespace mozilla
#endif

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

@ -0,0 +1,255 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ODoHService.h"
#include "mozilla/Preferences.h"
#include "mozilla/StaticPrefs_network.h"
#include "nsIDNSService.h"
#include "nsIDNSByTypeRecord.h"
#include "nsIOService.h"
#include "ODoH.h"
#include "TRRService.h"
#include "nsURLHelper.h"
static const char kODoHProxyURIPref[] = "network.trr.odoh.proxy_uri";
static const char kODoHTargetHostPref[] = "network.trr.odoh.target_host";
static const char kODoHTargetPathPref[] = "network.trr.odoh.target_path";
namespace mozilla {
namespace net {
ODoHService* gODoHService = nullptr;
extern mozilla::LazyLogModule gHostResolverLog;
#define LOG(args) MOZ_LOG(gHostResolverLog, mozilla::LogLevel::Debug, args)
NS_IMPL_ISUPPORTS(ODoHService, nsIDNSListener, nsIObserver,
nsISupportsWeakReference)
ODoHService::ODoHService()
: mLock("net::ODoHService"), mQueryODoHConfigInProgress(false) {
gODoHService = this;
}
ODoHService::~ODoHService() { gODoHService = nullptr; }
bool ODoHService::Init() {
MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
if (!prefBranch) {
return false;
}
prefBranch->AddObserver(kODoHProxyURIPref, this, true);
prefBranch->AddObserver(kODoHTargetHostPref, this, true);
prefBranch->AddObserver(kODoHTargetPathPref, this, true);
ReadPrefs(nullptr);
return true;
}
bool ODoHService::Enabled() const {
return StaticPrefs::network_trr_odoh_enabled();
}
NS_IMETHODIMP
ODoHService::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) {
MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
ReadPrefs(NS_ConvertUTF16toUTF8(aData).get());
}
return NS_OK;
}
nsresult ODoHService::ReadPrefs(const char* aName) {
if (!aName || !strcmp(aName, kODoHProxyURIPref) ||
!strcmp(aName, kODoHTargetHostPref) ||
!strcmp(aName, kODoHTargetPathPref)) {
OnODoHPrefsChange();
}
return NS_OK;
}
void ODoHService::OnODoHPrefsChange() {
nsAutoCString proxyURI;
Preferences::GetCString(kODoHProxyURIPref, proxyURI);
nsAutoCString targetHost;
Preferences::GetCString(kODoHTargetHostPref, targetHost);
nsAutoCString targetPath;
Preferences::GetCString(kODoHTargetPathPref, targetPath);
bool updateODoHConfig = false;
{
MutexAutoLock lock(mLock);
mODoHProxyURI = proxyURI;
// Only update ODoHConfig when the host is really changed.
if (!mODoHTargetHost.Equals(targetHost)) {
updateODoHConfig = true;
}
mODoHTargetHost = targetHost;
mODoHTargetPath = targetPath;
BuildODoHRequestURI();
}
if (updateODoHConfig) {
UpdateODoHConfig();
}
}
void ODoHService::BuildODoHRequestURI() {
mLock.AssertCurrentThreadOwns();
mODoHRequestURI.Truncate();
if (mODoHTargetHost.IsEmpty() || mODoHTargetPath.IsEmpty()) {
return;
}
if (mODoHProxyURI.IsEmpty()) {
mODoHRequestURI.Append(mODoHTargetHost);
mODoHRequestURI.AppendLiteral("/");
mODoHRequestURI.Append(mODoHTargetPath);
} else {
mODoHRequestURI.Append(mODoHProxyURI);
mODoHRequestURI.AppendLiteral("?targethost=");
mODoHRequestURI.Append(mODoHTargetHost);
mODoHRequestURI.AppendLiteral("&targetpath=/");
mODoHRequestURI.Append(mODoHTargetPath);
}
}
void ODoHService::GetRequestURI(nsACString& aResult) {
MutexAutoLock lock(mLock);
aResult = mODoHRequestURI;
}
nsresult ODoHService::UpdateODoHConfig() {
LOG(("ODoHService::UpdateODoHConfig"));
if (mQueryODoHConfigInProgress) {
return NS_OK;
}
nsAutoCString uri;
{
MutexAutoLock lock(mLock);
uri = mODoHProxyURI.IsEmpty() ? mODoHTargetHost : mODoHProxyURI;
}
nsCOMPtr<nsIDNSService> dns(
do_GetService("@mozilla.org/network/dns-service;1"));
if (!dns) {
return NS_ERROR_NOT_AVAILABLE;
}
if (!gTRRService) {
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsIURI> queryURI;
nsresult rv = NS_NewURI(getter_AddRefs(queryURI), uri);
if (NS_FAILED(rv)) {
return rv;
}
nsAutoCString scheme;
queryURI->GetScheme(scheme);
if (!scheme.Equals("https")) {
LOG(("ODoHService::UpdateODoHConfig uri is not https"));
return NS_ERROR_FAILURE;
}
nsAutoCString hostStr;
rv = queryURI->GetAsciiHost(hostStr);
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsICancelable> tmpOutstanding;
nsCOMPtr<nsIEventTarget> target = gTRRService->MainThreadOrTRRThread();
uint32_t flags = nsIDNSService::RESOLVE_DISABLE_ODOH;
rv = dns->AsyncResolveNative(hostStr, nsIDNSService::RESOLVE_TYPE_HTTPSSVC,
flags, nullptr, this, target, OriginAttributes(),
getter_AddRefs(tmpOutstanding));
LOG(("ODoHService::UpdateODoHConfig [host=%s rv=%" PRIx32 "]", hostStr.get(),
static_cast<uint32_t>(rv)));
if (NS_SUCCEEDED(rv)) {
mQueryODoHConfigInProgress = true;
}
return rv;
}
NS_IMETHODIMP
ODoHService::OnLookupComplete(nsICancelable* aRequest, nsIDNSRecord* aRec,
nsresult aStatus) {
MOZ_ASSERT_IF(XRE_IsParentProcess() && gTRRService,
NS_IsMainThread() || gTRRService->IsOnTRRThread());
MOZ_ASSERT_IF(XRE_IsSocketProcess(), NS_IsMainThread());
mQueryODoHConfigInProgress = false;
LOG(("ODoHService::OnLookupComplete [aStatus=%" PRIx32 "]",
static_cast<uint32_t>(aStatus)));
if (NS_FAILED(aStatus)) {
return NS_OK;
}
nsCOMPtr<nsIDNSHTTPSSVCRecord> httpsRecord = do_QueryInterface(aRec);
if (!httpsRecord) {
return NS_OK;
}
nsCString rawODoHConfig;
nsTArray<RefPtr<nsISVCBRecord>> svcbRecords;
httpsRecord->GetRecords(svcbRecords);
for (const auto& record : svcbRecords) {
Unused << record->GetODoHConfig(rawODoHConfig);
if (!rawODoHConfig.IsEmpty()) {
break;
}
}
nsTArray<ObliviousDoHConfig> configs;
if (!ODoHDNSPacket::ParseODoHConfigs(rawODoHConfig, configs)) {
return NS_OK;
}
mODoHConfigs.emplace(std::move(configs));
if (!mPendingRequests.IsEmpty()) {
nsTArray<RefPtr<ODoH>> requests = std::move(mPendingRequests);
nsCOMPtr<nsIEventTarget> target = gTRRService->MainThreadOrTRRThread();
for (auto& query : requests) {
target->Dispatch(query.forget());
}
}
return NS_OK;
}
const Maybe<nsTArray<ObliviousDoHConfig>>& ODoHService::ODoHConfigs() {
MOZ_ASSERT_IF(XRE_IsParentProcess() && gTRRService,
NS_IsMainThread() || gTRRService->IsOnTRRThread());
MOZ_ASSERT_IF(XRE_IsSocketProcess(), NS_IsMainThread());
return mODoHConfigs;
}
void ODoHService::AppendPendingODoHRequest(ODoH* aRequest) {
LOG(("ODoHService::AppendPendingODoHQuery\n"));
MOZ_ASSERT_IF(XRE_IsParentProcess() && gTRRService,
NS_IsMainThread() || gTRRService->IsOnTRRThread());
MOZ_ASSERT_IF(XRE_IsSocketProcess(), NS_IsMainThread());
mPendingRequests.AppendElement(aRequest);
}
} // namespace net
} // namespace mozilla

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

@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef ODoHService_h_
#define ODoHService_h_
#include "DNS.h"
#include "mozilla/Atomics.h"
#include "mozilla/Maybe.h"
#include "nsString.h"
#include "nsIDNSListener.h"
#include "nsIObserver.h"
#include "nsWeakReference.h"
namespace mozilla {
namespace net {
class ODoH;
class ODoHService : public nsIDNSListener,
public nsIObserver,
public nsSupportsWeakReference {
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIDNSLISTENER
NS_DECL_NSIOBSERVER
ODoHService();
bool Init();
bool Enabled() const;
const Maybe<nsTArray<ObliviousDoHConfig>>& ODoHConfigs();
void AppendPendingODoHRequest(ODoH* aRequest);
void GetRequestURI(nsACString& aResult);
nsresult UpdateODoHConfig();
private:
virtual ~ODoHService();
nsresult ReadPrefs(const char* aName);
void OnODoHPrefsChange();
// Send a DNS query to reterive the ODoHConfig.
void BuildODoHRequestURI();
Mutex mLock;
Atomic<bool, Relaxed> mQueryODoHConfigInProgress;
nsCString mODoHProxyURI;
nsCString mODoHTargetHost;
nsCString mODoHTargetPath;
nsCString mODoHRequestURI;
Maybe<nsTArray<ObliviousDoHConfig>> mODoHConfigs;
nsTArray<RefPtr<ODoH>> mPendingRequests;
};
extern ODoHService* gODoHService;
} // namespace net
} // namespace mozilla
#endif

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

@ -134,6 +134,32 @@ nsresult TRR::CreateChannelHelper(nsIURI* aUri, nsIChannel** aResult) {
aResult);
}
DNSPacket* TRR::GetOrCreateDNSPacket() {
if (!mPacket) {
mPacket = MakeUnique<DNSPacket>();
}
return mPacket.get();
}
nsresult TRR::CreateQueryURI(nsIURI** aOutURI) {
nsAutoCString uri;
nsCOMPtr<nsIURI> dnsURI;
if (UseDefaultServer()) {
gTRRService->GetURI(uri);
} else {
uri = mRec->mTrrServer;
}
nsresult rv = NS_NewURI(getter_AddRefs(dnsURI), uri);
if (NS_FAILED(rv)) {
return rv;
}
dnsURI.forget(aOutURI);
return NS_OK;
}
nsresult TRR::SendHTTPRequest() {
// This is essentially the "run" method - created from nsHostResolver
@ -175,39 +201,31 @@ nsresult TRR::SendHTTPRequest() {
}
}
bool useGet = StaticPrefs::network_trr_useGET();
nsAutoCString body;
nsCOMPtr<nsIURI> dnsURI;
bool disableECS = StaticPrefs::network_trr_disable_ECS();
nsresult rv;
LOG(("TRR::SendHTTPRequest resolve %s type %u\n", mHost.get(), mType));
if (useGet) {
nsAutoCString tmp;
rv = DNSPacket::EncodeRequest(tmp, mHost, mType, disableECS);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString body;
bool disableECS = StaticPrefs::network_trr_disable_ECS();
nsresult rv =
GetOrCreateDNSPacket()->EncodeRequest(body, mHost, mType, disableECS);
NS_ENSURE_SUCCESS(rv, rv);
bool useGet = StaticPrefs::network_trr_useGET();
nsCOMPtr<nsIURI> dnsURI;
rv = CreateQueryURI(getter_AddRefs(dnsURI));
if (NS_FAILED(rv)) {
LOG(("TRR:SendHTTPRequest: NewURI failed!\n"));
return rv;
}
if (useGet) {
/* For GET requests, the outgoing packet needs to be Base64url-encoded and
then appended to the end of the URI. */
rv = Base64URLEncode(tmp.Length(),
reinterpret_cast<const unsigned char*>(tmp.get()),
Base64URLEncodePaddingPolicy::Omit, body);
nsAutoCString encoded;
rv = Base64URLEncode(body.Length(),
reinterpret_cast<const unsigned char*>(body.get()),
Base64URLEncodePaddingPolicy::Omit, encoded);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString uri;
if (UseDefaultServer()) {
gTRRService->GetURI(uri);
} else {
uri = mRec->mTrrServer;
}
rv = NS_NewURI(getter_AddRefs(dnsURI), uri);
if (NS_FAILED(rv)) {
LOG(("TRR:SendHTTPRequest: NewURI failed!\n"));
return rv;
}
nsAutoCString query;
rv = dnsURI->GetQuery(query);
if (NS_FAILED(rv)) {
@ -219,25 +237,10 @@ nsresult TRR::SendHTTPRequest() {
} else {
query.Append("&dns="_ns);
}
query.Append(body);
query.Append(encoded);
rv = NS_MutateURI(dnsURI).SetQuery(query).Finalize(dnsURI);
LOG(("TRR::SendHTTPRequest GET dns=%s\n", body.get()));
} else {
rv = DNSPacket::EncodeRequest(body, mHost, mType, disableECS);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString uri;
if (UseDefaultServer()) {
gTRRService->GetURI(uri);
} else {
uri = mRec->mTrrServer;
}
rv = NS_NewURI(getter_AddRefs(dnsURI), uri);
}
if (NS_FAILED(rv)) {
LOG(("TRR:SendHTTPRequest: NewURI failed!\n"));
return rv;
}
nsCOMPtr<nsIChannel> channel;
@ -264,8 +267,8 @@ nsresult TRR::SendHTTPRequest() {
rv = httpChannel->SetTRRMode(nsIRequest::TRR_DISABLED_MODE);
NS_ENSURE_SUCCESS(rv, rv);
rv = httpChannel->SetRequestHeader("Accept"_ns, "application/dns-message"_ns,
false);
nsCString contentType(ContentType());
rv = httpChannel->SetRequestHeader("Accept"_ns, contentType, false);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString cred;
@ -303,13 +306,12 @@ nsresult TRR::SendHTTPRequest() {
NS_NewCStringInputStream(getter_AddRefs(uploadStream), std::move(body));
NS_ENSURE_SUCCESS(rv, rv);
rv = uploadChannel->ExplicitSetUploadStream(uploadStream,
"application/dns-message"_ns,
rv = uploadChannel->ExplicitSetUploadStream(uploadStream, contentType,
streamLength, "POST"_ns, false);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = SetupTRRServiceChannelInternal(httpChannel, useGet);
rv = SetupTRRServiceChannelInternal(httpChannel, useGet, contentType);
if (NS_FAILED(rv)) {
return rv;
}
@ -336,7 +338,8 @@ nsresult TRR::SendHTTPRequest() {
// static
nsresult TRR::SetupTRRServiceChannelInternal(nsIHttpChannel* aChannel,
bool aUseGet) {
bool aUseGet,
const nsACString& aContentType) {
nsCOMPtr<nsIHttpChannel> httpChannel = aChannel;
MOZ_ASSERT(httpChannel);
@ -366,7 +369,7 @@ nsresult TRR::SetupTRRServiceChannelInternal(nsIHttpChannel* aChannel,
}
// set the *default* response content type
if (NS_FAILED(httpChannel->SetContentType("application/dns-message"_ns))) {
if (NS_FAILED(httpChannel->SetContentType(aContentType))) {
LOG(("TRR::SetupTRRServiceChannelInternal: couldn't set content-type!\n"));
}
@ -748,7 +751,7 @@ nsresult TRR::FollowCname(nsIChannel* aChannel) {
LOG(("TRR: check for CNAME record for %s within previous response\n",
cname.get()));
nsClassHashtable<nsCStringHashKey, DOHresp> additionalRecords;
rv = mPacket.Decode(
rv = GetOrCreateDNSPacket()->Decode(
cname, mType, mCname, StaticPrefs::network_trr_allow_rfc1918(),
mTRRSkippedReason, mDNS, mResult, additionalRecords, mTTL);
if (NS_FAILED(rv)) {
@ -781,7 +784,7 @@ nsresult TRR::FollowCname(nsIChannel* aChannel) {
nsresult TRR::On200Response(nsIChannel* aChannel) {
// decode body and create an AddrInfo struct for the response
nsClassHashtable<nsCStringHashKey, DOHresp> additionalRecords;
nsresult rv = mPacket.Decode(
nsresult rv = GetOrCreateDNSPacket()->Decode(
mHost, mType, mCname, StaticPrefs::network_trr_allow_rfc1918(),
mTRRSkippedReason, mDNS, mResult, additionalRecords, mTTL);
@ -864,7 +867,7 @@ TRR::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) {
nsAutoCString contentType;
httpChannel->GetContentType(contentType);
if (contentType.Length() &&
!contentType.LowerCaseEqualsLiteral("application/dns-message")) {
!contentType.LowerCaseEqualsASCII(ContentType())) {
LOG(("TRR:OnStopRequest %p %s %d wrong content type %s\n", this,
mHost.get(), mType, contentType.get()));
FailData(NS_ERROR_UNEXPECTED);
@ -903,8 +906,8 @@ TRR::OnDataAvailable(nsIRequest* aRequest, nsIInputStream* aInputStream,
return NS_ERROR_FAILURE;
}
nsresult rv =
mPacket.OnDataAvailable(aRequest, aInputStream, aOffset, aCount);
nsresult rv = GetOrCreateDNSPacket()->OnDataAvailable(aRequest, aInputStream,
aOffset, aCount);
if (NS_FAILED(rv)) {
LOG(("TRR::OnDataAvailable:%d fail\n", __LINE__));
mFailed = true;

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

@ -101,8 +101,11 @@ class TRR : public Runnable,
RefPtr<nsHostRecord> mRec;
RefPtr<AHostResolver> mHostResolver;
private:
~TRR() = default;
protected:
virtual ~TRR() = default;
virtual DNSPacket* GetOrCreateDNSPacket();
virtual nsresult CreateQueryURI(nsIURI** aOutURI);
virtual const char* ContentType() const { return "application/dns-message"; }
nsresult SendHTTPRequest();
nsresult ReturnData(nsIChannel* aChannel);
@ -126,14 +129,14 @@ class TRR : public Runnable,
nsresult CreateChannelHelper(nsIURI* aUri, nsIChannel** aResult);
friend class TRRServiceChannel;
static nsresult SetupTRRServiceChannelInternal(nsIHttpChannel* aChannel,
bool aUseGet);
static nsresult SetupTRRServiceChannelInternal(
nsIHttpChannel* aChannel, bool aUseGet, const nsACString& aContentType);
void StoreIPHintAsDNSRecord(const struct SVCB& aSVCBRecord);
nsCOMPtr<nsIChannel> mChannel;
enum TrrType mType;
DNSPacket mPacket;
UniquePtr<DNSPacket> mPacket;
bool mFailed = false;
bool mPB;
DOHresp mDNS;

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

@ -4,6 +4,7 @@
#include "TRRQuery.h"
#include "TRR.h"
#include "ODoH.h"
namespace mozilla {
namespace net {
@ -49,7 +50,12 @@ void TRRQuery::Cancel() {
}
}
nsresult TRRQuery::DispatchLookup(TRR* pushedTRR) {
nsresult TRRQuery::DispatchLookup(TRR* pushedTRR, bool aUseODoH) {
if (aUseODoH && pushedTRR) {
MOZ_ASSERT(false, "ODoH should not support push");
return NS_ERROR_UNKNOWN_HOST;
}
mTrrStart = TimeStamp::Now();
RefPtr<AddrHostRecord> addrRec;
@ -91,7 +97,12 @@ nsresult TRRQuery::DispatchLookup(TRR* pushedTRR) {
}
LOG(("TRR Resolve %s type %d\n", addrRec->host.get(), (int)rectype));
RefPtr<TRR> trr;
trr = pushedTRR ? pushedTRR : new TRR(this, mRecord, rectype);
if (aUseODoH) {
trr = new ODoH(this, mRecord, rectype);
} else {
trr = pushedTRR ? pushedTRR : new TRR(this, mRecord, rectype);
}
if (pushedTRR || NS_SUCCEEDED(gTRRService->DispatchTRRRequest(trr))) {
MutexAutoLock trrlock(mTrrLock);
if (rectype == TRRTYPE_A) {
@ -132,8 +143,12 @@ nsresult TRRQuery::DispatchLookup(TRR* pushedTRR) {
LOG(("TRR Resolve %s type %d\n", typeRec->host.get(), (int)rectype));
RefPtr<TRR> trr;
trr = pushedTRR ? pushedTRR : new TRR(this, mRecord, rectype);
RefPtr<TRR> trrRequest = trr;
if (aUseODoH) {
trr = new ODoH(this, mRecord, rectype);
} else {
trr = pushedTRR ? pushedTRR : new TRR(this, mRecord, rectype);
}
if (pushedTRR || NS_SUCCEEDED(gTRRService->DispatchTRRRequest(trr))) {
MutexAutoLock trrlock(mTrrLock);
MOZ_ASSERT(!mTrrByType);

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

@ -19,7 +19,7 @@ class TRRQuery : public AHostResolver {
mRecord(aHostRecord),
mTrrLock("TRRQuery.mTrrLock") {}
nsresult DispatchLookup(TRR* pushedTRR = nullptr);
nsresult DispatchLookup(TRR* pushedTRR = nullptr, bool aUseODoHProxy = false);
void Cancel();

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

@ -32,8 +32,6 @@ static const char kOpenCaptivePortalLoginEvent[] = "captive-portal-login";
static const char kClearPrivateData[] = "clear-private-data";
static const char kPurge[] = "browser:purge-session-history";
static const char kDisableIpv6Pref[] = "network.dns.disableIPv6";
static const char kRolloutURIPref[] = "doh-rollout.uri";
static const char kRolloutModePref[] = "doh-rollout.mode";
#define TRR_PREF_PREFIX "network.trr."
#define TRR_PREF(x) TRR_PREF_PREFIX x
@ -200,6 +198,11 @@ nsresult TRRService::Init() {
}
}
mODoHService = new ODoHService();
if (!mODoHService->Init()) {
return NS_ERROR_FAILURE;
}
LOG(("Initialized TRRService\n"));
return NS_OK;
}
@ -492,20 +495,26 @@ nsresult TRRService::DispatchTRRRequest(TRR* aTrrRequest) {
nsresult TRRService::DispatchTRRRequestInternal(TRR* aTrrRequest,
bool aWithLock) {
NS_ENSURE_ARG_POINTER(aTrrRequest);
if (!StaticPrefs::network_trr_fetch_off_main_thread() ||
XRE_IsSocketProcess()) {
return NS_DispatchToMainThread(aTrrRequest);
}
RefPtr<TRR> trr = aTrrRequest;
nsCOMPtr<nsIThread> thread = aWithLock ? TRRThread() : TRRThread_locked();
nsCOMPtr<nsIThread> thread = MainThreadOrTRRThread(aWithLock);
if (!thread) {
return NS_ERROR_FAILURE;
}
RefPtr<TRR> trr = aTrrRequest;
return thread->Dispatch(trr.forget());
}
already_AddRefed<nsIThread> TRRService::MainThreadOrTRRThread(bool aWithLock) {
if (!StaticPrefs::network_trr_fetch_off_main_thread() ||
XRE_IsSocketProcess()) {
return do_GetMainThread();
}
nsCOMPtr<nsIThread> thread = aWithLock ? TRRThread() : TRRThread_locked();
return thread.forget();
}
already_AddRefed<nsIThread> TRRService::TRRThread() {
MutexAutoLock lock(mLock);
return TRRThread_locked();

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

@ -11,6 +11,7 @@
#include "nsIObserver.h"
#include "nsITimer.h"
#include "nsWeakReference.h"
#include "ODoHService.h"
#include "TRRServiceBase.h"
class nsDNSService;
@ -75,6 +76,7 @@ class TRRService : public TRRServiceBase,
friend class TRRServiceChild;
friend class TRRServiceParent;
friend class ODoHService;
static void AddObserver(nsIObserver* aObserver,
nsIObserverService* aObserverService = nullptr);
static bool CheckCaptivePortalIsPassed();
@ -96,6 +98,7 @@ class TRRService : public TRRServiceBase,
nsresult DispatchTRRRequestInternal(TRR* aTrrRequest, bool aWithLock);
already_AddRefed<nsIThread> TRRThread_locked();
already_AddRefed<nsIThread> MainThreadOrTRRThread(bool aWithLock = true);
// This method will process the URI and try to set mPrivateURI to that value.
// Will return true if performed the change (if the value was different)
@ -142,6 +145,7 @@ class TRRService : public TRRServiceBase,
uint32_t mRetryConfirmInterval; // milliseconds until retry
Atomic<uint32_t, Relaxed> mTRRFailures;
bool mParentalControlEnabled;
RefPtr<ODoHService> mODoHService;
};
extern TRRService* gTRRService;

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

@ -6,7 +6,10 @@
#include "TRRServiceBase.h"
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
#include "nsHostResolver.h"
#include "nsNetUtil.h"
#include "nsIOService.h"
#include "nsIDNSService.h"

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

@ -13,6 +13,9 @@
namespace mozilla {
namespace net {
static const char kRolloutURIPref[] = "doh-rollout.uri";
static const char kRolloutModePref[] = "doh-rollout.mode";
class TRRServiceBase {
public:
TRRServiceBase();

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

@ -9,6 +9,7 @@
#include "mozilla/StaticPtr.h"
#include "nsIDNService.h"
#include "nsIObserverService.h"
#include "nsServiceManagerUtils.h"
#include "TRRService.h"
namespace mozilla {

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

@ -22,9 +22,6 @@
namespace mozilla {
namespace net {
static const char kRolloutURIPref[] = "doh-rollout.uri";
static const char kRolloutModePref[] = "doh-rollout.mode";
static const char* gTRRUriCallbackPrefs[] = {
"network.trr.uri", "network.trr.mode", kRolloutURIPref, kRolloutModePref,
nullptr,

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

@ -71,6 +71,8 @@ UNIFIED_SOURCES += [
"NativeDNSResolverOverrideParent.cpp",
"nsDNSService2.cpp",
"nsIDNService.cpp",
"ODoH.cpp",
"ODoHService.cpp",
"punycode.c",
"TRR.cpp",
"TRRQuery.cpp",

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

@ -37,6 +37,7 @@
#include "TRR.h"
#include "TRRQuery.h"
#include "TRRService.h"
#include "ODoHService.h"
#include "mozilla/Atomics.h"
#include "mozilla/HashFunctions.h"
@ -1383,7 +1384,9 @@ nsresult nsHostResolver::TrrLookup(nsHostRecord* aRec, TRR* pushedTRR) {
MaybeRenewHostRecordLocked(rec);
RefPtr<TRRQuery> query = new TRRQuery(this, rec);
nsresult rv = query->DispatchLookup(pushedTRR);
bool useODoH = gODoHService->Enabled() &&
!((rec->flags & nsIDNSService::RESOLVE_DISABLE_ODOH));
nsresult rv = query->DispatchLookup(pushedTRR, useODoH);
if (NS_FAILED(rv)) {
rec->RecordReason(nsHostRecord::TRR_DID_NOT_MAKE_QUERY);
return rv;

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

@ -330,6 +330,11 @@ interface nsIDNSService : nsISupports
* resolve/asyncResolve.
*/
const unsigned long RESOLVE_IP_HINT = 1 << 14;
/**
* If set, do not use ODoH for resolving the host name.
*/
const unsigned long RESOLVE_DISABLE_ODOH = 1 << 15;
};
%{C++

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

@ -1170,10 +1170,16 @@ nsresult TRRServiceChannel::SetupReplacementChannel(nsIURI* aNewURI,
encodedChannel->SetApplyConversion(LoadApplyConversion());
}
// Apply TRR specific settings.
// Make sure we set content-type on the old channel properly.
MOZ_ASSERT(mContentTypeHint.Equals("application/dns-message") ||
mContentTypeHint.Equals("application/oblivious-dns-message"));
// Apply TRR specific settings. Note that we already know mContentTypeHint is
// "application/dns-message" or "application/oblivious-dns-message" here.
return TRR::SetupTRRServiceChannelInternal(
httpChannel,
mRequestHead.ParsedMethod() == nsHttpRequestHead::kMethod_Get);
mRequestHead.ParsedMethod() == nsHttpRequestHead::kMethod_Get,
mContentTypeHint);
}
NS_IMETHODIMP