mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 1689987 - P3: Add some ODoH specific skip reasons r=necko-reviewers,valentin
Differential Revision: https://phabricator.services.mozilla.com/D104831
This commit is contained in:
parent
782c896152
commit
9795f890cc
@ -363,6 +363,7 @@ nsresult DNSPacket::EncodeRequest(nsCString& aBody, const nsACString& aHost,
|
||||
}
|
||||
if (labelLength > 63) {
|
||||
// too long label!
|
||||
SetDNSPacketStatus(DNSPacketStatus::EncodeError);
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
if (labelLength > 0) {
|
||||
@ -416,6 +417,7 @@ nsresult DNSPacket::EncodeRequest(nsCString& aBody, const nsACString& aHost,
|
||||
|
||||
// ADDRESS, minimum number of octets == nothing because zero bits
|
||||
}
|
||||
SetDNSPacketStatus(DNSPacketStatus::Success);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -982,8 +984,12 @@ nsresult DNSPacket::Decode(
|
||||
DOHresp& aResp, TypeRecordResultType& aTypeResult,
|
||||
nsClassHashtable<nsCStringHashKey, DOHresp>& aAdditionalRecords,
|
||||
uint32_t& aTTL) {
|
||||
return DecodeInternal(aHost, aType, aCname, aAllowRFC1918, aResp, aTypeResult,
|
||||
aAdditionalRecords, aTTL, mResponse, mBodySize);
|
||||
nsresult rv =
|
||||
DecodeInternal(aHost, aType, aCname, aAllowRFC1918, aResp, aTypeResult,
|
||||
aAdditionalRecords, aTTL, mResponse, mBodySize);
|
||||
SetDNSPacketStatus(NS_SUCCEEDED(rv) ? DNSPacketStatus::Success
|
||||
: DNSPacketStatus::DecodeError);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static SECItem* CreateRawConfig(const ObliviousDoHConfig& aConfig) {
|
||||
@ -1155,10 +1161,17 @@ nsresult ODoHDNSPacket::EncodeRequest(nsCString& aBody, const nsACString& aHost,
|
||||
nsAutoCString queryBody;
|
||||
nsresult rv = DNSPacket::EncodeRequest(queryBody, aHost, aType, aDisableECS);
|
||||
if (NS_FAILED(rv)) {
|
||||
SetDNSPacketStatus(DNSPacketStatus::EncodeError);
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!gODoHService->ODoHConfigs() || gODoHService->ODoHConfigs()->IsEmpty()) {
|
||||
if (!gODoHService->ODoHConfigs()) {
|
||||
SetDNSPacketStatus(DNSPacketStatus::KeyNotAvailable);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (gODoHService->ODoHConfigs()->IsEmpty()) {
|
||||
SetDNSPacketStatus(DNSPacketStatus::KeyNotUsable);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
@ -1168,6 +1181,7 @@ nsresult ODoHDNSPacket::EncodeRequest(nsCString& aBody, const nsACString& aHost,
|
||||
ObliviousDoHMessage message;
|
||||
// The spec didn't recommand padding length for encryption, let's use 0 here.
|
||||
if (!EncryptDNSQuery(queryBody, 0, config, message)) {
|
||||
SetDNSPacketStatus(DNSPacketStatus::EncryptError);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
@ -1185,6 +1199,7 @@ nsresult ODoHDNSPacket::EncodeRequest(nsCString& aBody, const nsACString& aHost,
|
||||
reinterpret_cast<const char*>(message.mEncryptedMessage.Elements()),
|
||||
messageLen);
|
||||
|
||||
SetDNSPacketStatus(DNSPacketStatus::Success);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1291,6 +1306,7 @@ nsresult ODoHDNSPacket::Decode(
|
||||
// records, but we only need to decrypt the response once.
|
||||
if (!mDecryptedResponseRange) {
|
||||
if (!DecryptDNSResponse()) {
|
||||
SetDNSPacketStatus(DNSPacketStatus::DecryptError);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
@ -1299,6 +1315,7 @@ nsresult ODoHDNSPacket::Decode(
|
||||
index += 2;
|
||||
|
||||
if (mBodySize < (index + responseLength)) {
|
||||
SetDNSPacketStatus(DNSPacketStatus::DecryptError);
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
@ -1311,16 +1328,20 @@ nsresult ODoHDNSPacket::Decode(
|
||||
|
||||
if (static_cast<unsigned int>(4 + responseLength + paddingLen) !=
|
||||
mBodySize) {
|
||||
SetDNSPacketStatus(DNSPacketStatus::DecryptError);
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
mDecryptedResponseRange.emplace(range);
|
||||
}
|
||||
|
||||
return DecodeInternal(aHost, aType, aCname, aAllowRFC1918, aResp, aTypeResult,
|
||||
aAdditionalRecords, aTTL,
|
||||
&mResponse[mDecryptedResponseRange->mStart],
|
||||
mDecryptedResponseRange->mLength);
|
||||
nsresult rv = DecodeInternal(aHost, aType, aCname, aAllowRFC1918, aResp,
|
||||
aTypeResult, aAdditionalRecords, aTTL,
|
||||
&mResponse[mDecryptedResponseRange->mStart],
|
||||
mDecryptedResponseRange->mLength);
|
||||
SetDNSPacketStatus(NS_SUCCEEDED(rv) ? DNSPacketStatus::Success
|
||||
: DNSPacketStatus::DecodeError);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static bool CreateObliviousDoHMessage(const unsigned char* aData,
|
||||
|
@ -33,6 +33,17 @@ enum TrrType {
|
||||
TRRTYPE_HTTPSSVC = nsIDNSService::RESOLVE_TYPE_HTTPSSVC, // 65
|
||||
};
|
||||
|
||||
enum class DNSPacketStatus : uint8_t {
|
||||
Unknown = 0,
|
||||
Success,
|
||||
KeyNotAvailable,
|
||||
KeyNotUsable,
|
||||
EncodeError,
|
||||
EncryptError,
|
||||
DecodeError,
|
||||
DecryptError,
|
||||
};
|
||||
|
||||
class DNSPacket {
|
||||
public:
|
||||
DNSPacket() = default;
|
||||
@ -57,6 +68,8 @@ class DNSPacket {
|
||||
nsClassHashtable<nsCStringHashKey, DOHresp>& aAdditionalRecords,
|
||||
uint32_t& aTTL);
|
||||
|
||||
DNSPacketStatus PacketStatus() const { return mStatus; }
|
||||
|
||||
protected:
|
||||
// Never accept larger DOH responses than this as that would indicate
|
||||
// something is wrong. Typical ones are much smaller.
|
||||
@ -74,9 +87,17 @@ class DNSPacket {
|
||||
nsClassHashtable<nsCStringHashKey, DOHresp>& aAdditionalRecords,
|
||||
uint32_t& aTTL, const unsigned char* aBuffer, uint32_t aLen);
|
||||
|
||||
void SetDNSPacketStatus(DNSPacketStatus aStatus) {
|
||||
if (mStatus == DNSPacketStatus::Unknown ||
|
||||
mStatus == DNSPacketStatus::Success) {
|
||||
mStatus = aStatus;
|
||||
}
|
||||
}
|
||||
|
||||
// The response buffer.
|
||||
unsigned char mResponse[MAX_SIZE]{};
|
||||
unsigned int mBodySize = 0;
|
||||
DNSPacketStatus mStatus = DNSPacketStatus::Unknown;
|
||||
};
|
||||
|
||||
class ODoHDNSPacket final : public DNSPacket {
|
||||
|
@ -34,6 +34,7 @@ ODoH::Run() {
|
||||
if (NS_SUCCEEDED(gODoHService->UpdateODoHConfig())) {
|
||||
gODoHService->AppendPendingODoHRequest(this);
|
||||
} else {
|
||||
RecordReason(nsHostRecord::ODOH_UPDATE_KEY_FAILED);
|
||||
FailData(NS_ERROR_FAILURE);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -65,5 +66,45 @@ nsresult ODoH::CreateQueryURI(nsIURI** aOutURI) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void ODoH::HandleTimeout() {
|
||||
// If this request is still in the pending queue, it means we can't get the
|
||||
// ODoHConfigs within the timeout.
|
||||
if (gODoHService->RemovePendingODoHRequest(this)) {
|
||||
RecordReason(nsHostRecord::ODOH_KEY_NOT_AVAILABLE);
|
||||
}
|
||||
|
||||
TRR::HandleTimeout();
|
||||
}
|
||||
|
||||
void ODoH::HandleEncodeError(nsresult aStatusCode) {
|
||||
MOZ_ASSERT(NS_FAILED(aStatusCode));
|
||||
|
||||
DNSPacketStatus status = mPacket->PacketStatus();
|
||||
MOZ_ASSERT(status != DNSPacketStatus::Success);
|
||||
|
||||
if (status == DNSPacketStatus::KeyNotAvailable) {
|
||||
RecordReason(nsHostRecord::ODOH_KEY_NOT_AVAILABLE);
|
||||
} else if (status == DNSPacketStatus::KeyNotUsable) {
|
||||
RecordReason(nsHostRecord::ODOH_KEY_NOT_USABLE);
|
||||
} else if (status == DNSPacketStatus::EncryptError) {
|
||||
RecordReason(nsHostRecord::ODOH_ENCRYPTION_FAILED);
|
||||
} else {
|
||||
MOZ_ASSERT_UNREACHABLE("Unexpected status code.");
|
||||
}
|
||||
}
|
||||
|
||||
void ODoH::HandleDecodeError(nsresult aStatusCode) {
|
||||
MOZ_ASSERT(NS_FAILED(aStatusCode));
|
||||
|
||||
DNSPacketStatus status = mPacket->PacketStatus();
|
||||
MOZ_ASSERT(status != DNSPacketStatus::Success);
|
||||
|
||||
if (status == DNSPacketStatus::DecryptError) {
|
||||
RecordReason(nsHostRecord::ODOH_DECRYPTION_FAILED);
|
||||
}
|
||||
|
||||
TRR::HandleDecodeError(aStatusCode);
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
@ -17,6 +17,10 @@ class ODoH final : public TRR {
|
||||
explicit ODoH(AHostResolver* aResolver, nsHostRecord* aRec,
|
||||
enum TrrType aType)
|
||||
: TRR(aResolver, aRec, aType) {}
|
||||
// when following CNAMEs
|
||||
explicit ODoH(AHostResolver* aResolver, nsHostRecord* aRec, nsCString& aHost,
|
||||
enum TrrType& aType, unsigned int aLoopCount, bool aPB)
|
||||
: TRR(aResolver, aRec, aHost, aType, aLoopCount, aPB) {}
|
||||
NS_IMETHOD Run() override;
|
||||
// ODoH should not support push.
|
||||
NS_IMETHOD GetInterface(const nsIID&, void**) override {
|
||||
@ -43,6 +47,9 @@ class ODoH final : public TRR {
|
||||
virtual void ReportStatus(nsresult aStatusCode) override {
|
||||
// TODO: record status in ODoHService.
|
||||
}
|
||||
virtual void HandleTimeout() override;
|
||||
virtual void HandleEncodeError(nsresult aStatusCode) override;
|
||||
virtual void HandleDecodeError(nsresult aStatusCode) override;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
@ -238,6 +238,7 @@ ODoHService::OnLookupComplete(nsICancelable* aRequest, nsIDNSRecord* aRec,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mODoHConfigs.reset();
|
||||
mODoHConfigs.emplace(std::move(configs));
|
||||
|
||||
if (!mPendingRequests.IsEmpty()) {
|
||||
@ -267,5 +268,13 @@ void ODoHService::AppendPendingODoHRequest(ODoH* aRequest) {
|
||||
mPendingRequests.AppendElement(aRequest);
|
||||
}
|
||||
|
||||
bool ODoHService::RemovePendingODoHRequest(ODoH* aRequest) {
|
||||
MOZ_ASSERT_IF(XRE_IsParentProcess() && gTRRService,
|
||||
NS_IsMainThread() || gTRRService->IsOnTRRThread());
|
||||
MOZ_ASSERT_IF(XRE_IsSocketProcess(), NS_IsMainThread());
|
||||
|
||||
return mPendingRequests.RemoveElement(aRequest);
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
@ -33,6 +33,7 @@ class ODoHService : public nsIDNSListener,
|
||||
|
||||
const Maybe<nsTArray<ObliviousDoHConfig>>& ODoHConfigs();
|
||||
void AppendPendingODoHRequest(ODoH* aRequest);
|
||||
bool RemovePendingODoHRequest(ODoH* aRequest);
|
||||
void GetRequestURI(nsACString& aResult);
|
||||
// Send a DNS query to reterive the ODoHConfig.
|
||||
nsresult UpdateODoHConfig();
|
||||
|
@ -50,12 +50,16 @@ extern mozilla::LazyLogModule gHostResolverLog;
|
||||
NS_IMPL_ISUPPORTS(TRR, nsIHttpPushListener, nsIInterfaceRequestor,
|
||||
nsIStreamListener, nsIRunnable)
|
||||
|
||||
void TRR::HandleTimeout() {
|
||||
mTimeout = nullptr;
|
||||
RecordReason(nsHostRecord::TRR_TIMEOUT);
|
||||
Cancel(NS_ERROR_NET_TIMEOUT_EXTERNAL);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TRR::Notify(nsITimer* aTimer) {
|
||||
if (aTimer == mTimeout) {
|
||||
mTimeout = nullptr;
|
||||
RecordReason(nsHostRecord::TRR_TIMEOUT);
|
||||
Cancel(NS_ERROR_NET_TIMEOUT_EXTERNAL);
|
||||
HandleTimeout();
|
||||
} else {
|
||||
MOZ_CRASH("Unknown timer");
|
||||
}
|
||||
@ -216,7 +220,10 @@ nsresult TRR::SendHTTPRequest() {
|
||||
bool disableECS = StaticPrefs::network_trr_disable_ECS();
|
||||
nsresult rv =
|
||||
GetOrCreateDNSPacket()->EncodeRequest(body, mHost, mType, disableECS);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
HandleEncodeError(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool useGet = StaticPrefs::network_trr_useGET();
|
||||
nsCOMPtr<nsIURI> dnsURI;
|
||||
@ -750,6 +757,18 @@ nsresult TRR::FailData(nsresult error) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void TRR::HandleDecodeError(nsresult aStatusCode) {
|
||||
auto rcode = mPacket->GetRCode();
|
||||
if (rcode.isOk() && rcode.unwrap() != 0) {
|
||||
RecordReason(nsHostRecord::TRR_RCODE_FAIL);
|
||||
} else if (aStatusCode == NS_ERROR_UNKNOWN_HOST ||
|
||||
aStatusCode == NS_ERROR_DEFINITIVE_UNKNOWN_HOST) {
|
||||
RecordReason(nsHostRecord::TRR_NO_ANSWERS);
|
||||
} else {
|
||||
RecordReason(nsHostRecord::TRR_DECODE_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult TRR::FollowCname(nsIChannel* aChannel) {
|
||||
nsresult rv = NS_OK;
|
||||
nsAutoCString cname;
|
||||
@ -768,17 +787,8 @@ nsresult TRR::FollowCname(nsIChannel* aChannel) {
|
||||
cname, mType, mCname, StaticPrefs::network_trr_allow_rfc1918(), mDNS,
|
||||
mResult, additionalRecords, mTTL);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("TRR::On200Response DohDecode %x\n", (int)rv));
|
||||
|
||||
auto rcode = mPacket->GetRCode();
|
||||
if (rcode.isOk() && rcode.unwrap() != 0) {
|
||||
RecordReason(nsHostRecord::TRR_RCODE_FAIL);
|
||||
} else if (rv == NS_ERROR_UNKNOWN_HOST ||
|
||||
rv == NS_ERROR_DEFINITIVE_UNKNOWN_HOST) {
|
||||
RecordReason(nsHostRecord::TRR_NO_ANSWERS);
|
||||
} else {
|
||||
RecordReason(nsHostRecord::TRR_DECODE_FAILED);
|
||||
}
|
||||
LOG(("TRR::FollowCname DohDecode %x\n", (int)rv));
|
||||
HandleDecodeError(rv);
|
||||
}
|
||||
}
|
||||
|
||||
@ -797,7 +807,9 @@ nsresult TRR::FollowCname(nsIChannel* aChannel) {
|
||||
LOG(("TRR::On200Response CNAME %s => %s (%u)\n", mHost.get(), mCname.get(),
|
||||
mCnameLoop));
|
||||
RefPtr<TRR> trr =
|
||||
new TRR(mHostResolver, mRec, mCname, mType, mCnameLoop, mPB);
|
||||
ResolverType() == DNSResolverType::ODoH
|
||||
? new ODoH(mHostResolver, mRec, mCname, mType, mCnameLoop, mPB)
|
||||
: new TRR(mHostResolver, mRec, mCname, mType, mCnameLoop, mPB);
|
||||
if (!gTRRService) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -812,15 +824,7 @@ nsresult TRR::On200Response(nsIChannel* aChannel) {
|
||||
mResult, additionalRecords, mTTL);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("TRR::On200Response DohDecode %x\n", (int)rv));
|
||||
auto rcode = mPacket->GetRCode();
|
||||
if (rcode.isOk() && rcode.unwrap() != 0) {
|
||||
RecordReason(nsHostRecord::TRR_RCODE_FAIL);
|
||||
} else if (rv == NS_ERROR_UNKNOWN_HOST ||
|
||||
rv == NS_ERROR_DEFINITIVE_UNKNOWN_HOST) {
|
||||
RecordReason(nsHostRecord::TRR_NO_ANSWERS);
|
||||
} else {
|
||||
RecordReason(nsHostRecord::TRR_DECODE_FAILED);
|
||||
}
|
||||
HandleDecodeError(rv);
|
||||
return rv;
|
||||
}
|
||||
SaveAdditionalRecords(additionalRecords);
|
||||
|
@ -114,6 +114,9 @@ class TRR : public Runnable,
|
||||
virtual bool MaybeBlockRequest();
|
||||
virtual void RecordProcessingTime(nsIChannel* aChannel);
|
||||
virtual void ReportStatus(nsresult aStatusCode);
|
||||
virtual void HandleTimeout();
|
||||
virtual void HandleEncodeError(nsresult aStatusCode) {}
|
||||
virtual void HandleDecodeError(nsresult aStatusCode);
|
||||
nsresult SendHTTPRequest();
|
||||
nsresult ReturnData(nsIChannel* aChannel);
|
||||
|
||||
|
@ -119,8 +119,13 @@ class nsHostRecord : public mozilla::LinkedListElement<RefPtr<nsHostRecord>>,
|
||||
TRR_SERVER_RESPONSE_ERR = 27, // Server responded with non-200 code
|
||||
TRR_RCODE_FAIL = 28, // DNS response contains a non-NOERROR rcode
|
||||
TRR_NO_CONNECTIVITY = 29, // Not confirmed because of no connectivity
|
||||
TRR_NXDOMAIN = 30, // DNS response contains NXDOMAIN rcode (0x03)
|
||||
TRR_REQ_CANCELLED = 31, // The request has been cancelled
|
||||
TRR_NXDOMAIN = 30, // DNS response contains NXDOMAIN rcode (0x03)
|
||||
TRR_REQ_CANCELLED = 31, // The request has been cancelled
|
||||
ODOH_KEY_NOT_USABLE = 32, // We don't have a valid ODoHConfig to use.
|
||||
ODOH_UPDATE_KEY_FAILED = 33, // Failed to update the ODoHConfigs.
|
||||
ODOH_KEY_NOT_AVAILABLE = 34, // ODoH requests timeout because of no key.
|
||||
ODOH_ENCRYPTION_FAILED = 35, // Failed to encrypt DNS packets.
|
||||
ODOH_DECRYPTION_FAILED = 36, // Failed to decrypt DNS packets.
|
||||
};
|
||||
|
||||
// Records the first reason that caused TRR to be skipped or to fail.
|
||||
|
Loading…
Reference in New Issue
Block a user