Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/dns/./../../../netwerk/dns/TRR.cpp
Warning:line 265, column 5
Value stored to 'rv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_netwerk_dns0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/dns -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/dns -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/netwerk/dns -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/dns -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/toolkit/components/telemetry -I /root/firefox-clang/xpcom/base -I /root/firefox-clang/netwerk/base -I /root/firefox-clang/netwerk/ipc -I /root/firefox-clang/netwerk/protocol/http -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ Unified_cpp_netwerk_dns0.cpp
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#include "TRR.h"
6
7#include "DNS.h"
8#include "DNSUtils.h"
9#include "ObliviousHttpChannel.h"
10#include "TRRLoadInfo.h"
11#include "TRRService.h"
12#include "TRRServiceChannel.h"
13#include "mozilla/Base64.h"
14#include "mozilla/Logging.h"
15#include "mozilla/Maybe.h"
16#include "mozilla/Preferences.h"
17#include "mozilla/StaticPrefs_network.h"
18#include "mozilla/TimeStamp.h"
19#include "mozilla/Tokenizer.h"
20#include "mozilla/UniquePtr.h"
21#include "mozilla/glean/NetwerkDnsMetrics.h"
22#include "nsCharSeparatedTokenizer.h"
23#include "nsContentUtils.h"
24#include "nsHostResolver.h"
25#include "nsHttpChannel.h"
26#include "nsHttpHandler.h"
27#include "nsIHttpChannel.h"
28#include "nsIHttpChannelInternal.h"
29#include "nsIIOService.h"
30#include "nsIInputStream.h"
31#include "nsIOService.h"
32#include "nsIObliviousHttp.h"
33#include "nsISupports.h"
34#include "nsISupportsUtils.h"
35#include "nsITimedChannel.h"
36#include "nsIURIMutator.h"
37#include "nsIUploadChannel2.h"
38#include "nsNetUtil.h"
39#include "nsQueryObject.h"
40#include "nsStringStream.h"
41#include "nsThreadUtils.h"
42#include "nsURLHelper.h"
43// Put DNSLogging.h at the end to avoid LOG being overwritten by other headers.
44#include "DNSLogging.h"
45#include "mozilla/glean/NetwerkMetrics.h"
46
47namespace mozilla {
48namespace net {
49
50NS_IMPL_ISUPPORTS_INHERITED(TRR, Runnable, nsIStreamListener, nsITimerCallback,nsresult TRR::QueryInterface(const nsIID& aIID, void** aInstancePtr
) { do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "./../../../netwerk/dns/TRR.cpp", 51); MOZ_PretendNoReturn(
); } } while (0); nsresult rv = NS_ERROR_FAILURE; static_assert
(3 > 0, "Need more arguments to NS_INTERFACE_TABLE_INHERITED"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<TRR, nsIStreamListener>, int32_t( reinterpret_cast
<char*>(static_cast<nsIStreamListener*>((TRR*)0x1000
)) - reinterpret_cast<char*>((TRR*)0x1000))}, {&mozilla
::detail::kImplementedIID<TRR, nsITimerCallback>, int32_t
( reinterpret_cast<char*>(static_cast<nsITimerCallback
*>((TRR*)0x1000)) - reinterpret_cast<char*>((TRR*)0x1000
))}, {&mozilla::detail::kImplementedIID<TRR, nsIRunnablePriority
>, int32_t( reinterpret_cast<char*>(static_cast<nsIRunnablePriority
*>((TRR*)0x1000)) - reinterpret_cast<char*>((TRR*)0x1000
))}, { nullptr, 0 } } ; static_assert(std::size(table) > 1
, "need at least 1 interface"); rv = NS_TableDrivenQI(static_cast
<void*>(this), aIID, aInstancePtr, table); if (((bool)(
__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) return rv; return
Runnable::QueryInterface(aIID, aInstancePtr); } MozExternalRefCountType
TRR::AddRef(void) { static_assert(!std::is_destructible_v<
TRR>, "Reference-counted class " "TRR" " should not have a public destructor. "
"Make this class's destructor non-public"); nsrefcnt r = Runnable
::AddRef(); if constexpr (::mozilla::detail::ShouldLogInheritedRefcnt
<TRR>) { NS_LogAddRef((this), (r), ("TRR"), (uint32_t)(
sizeof(*this))); } return r; } MozExternalRefCountType TRR::Release
(void) { nsrefcnt r = Runnable::Release(); if constexpr (::mozilla
::detail::ShouldLogInheritedRefcnt<TRR>) { NS_LogRelease
((this), (r), ("TRR")); } return r; }
51 nsIRunnablePriority)nsresult TRR::QueryInterface(const nsIID& aIID, void** aInstancePtr
) { do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "./../../../netwerk/dns/TRR.cpp", 51); MOZ_PretendNoReturn(
); } } while (0); nsresult rv = NS_ERROR_FAILURE; static_assert
(3 > 0, "Need more arguments to NS_INTERFACE_TABLE_INHERITED"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<TRR, nsIStreamListener>, int32_t( reinterpret_cast
<char*>(static_cast<nsIStreamListener*>((TRR*)0x1000
)) - reinterpret_cast<char*>((TRR*)0x1000))}, {&mozilla
::detail::kImplementedIID<TRR, nsITimerCallback>, int32_t
( reinterpret_cast<char*>(static_cast<nsITimerCallback
*>((TRR*)0x1000)) - reinterpret_cast<char*>((TRR*)0x1000
))}, {&mozilla::detail::kImplementedIID<TRR, nsIRunnablePriority
>, int32_t( reinterpret_cast<char*>(static_cast<nsIRunnablePriority
*>((TRR*)0x1000)) - reinterpret_cast<char*>((TRR*)0x1000
))}, { nullptr, 0 } } ; static_assert(std::size(table) > 1
, "need at least 1 interface"); rv = NS_TableDrivenQI(static_cast
<void*>(this), aIID, aInstancePtr, table); if (((bool)(
__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) return rv; return
Runnable::QueryInterface(aIID, aInstancePtr); } MozExternalRefCountType
TRR::AddRef(void) { static_assert(!std::is_destructible_v<
TRR>, "Reference-counted class " "TRR" " should not have a public destructor. "
"Make this class's destructor non-public"); nsrefcnt r = Runnable
::AddRef(); if constexpr (::mozilla::detail::ShouldLogInheritedRefcnt
<TRR>) { NS_LogAddRef((this), (r), ("TRR"), (uint32_t)(
sizeof(*this))); } return r; } MozExternalRefCountType TRR::Release
(void) { nsrefcnt r = Runnable::Release(); if constexpr (::mozilla
::detail::ShouldLogInheritedRefcnt<TRR>) { NS_LogRelease
((this), (r), ("TRR")); } return r; }
52
53NS_IMETHODIMPnsresult
54TRR::GetPriority(uint32_t* aPriority) {
55 if (StaticPrefs::network_trr_high_priority_events()) {
56 *aPriority = nsIRunnablePriority::PRIORITY_MEDIUMHIGH;
57 } else {
58 *aPriority = nsIRunnablePriority::PRIORITY_NORMAL;
59 }
60 return NS_OK;
61}
62
63// when firing off a normal A or AAAA query
64TRR::TRR(AHostResolver* aResolver, nsHostRecord* aRec, enum TrrType aType)
65 : mozilla::Runnable("TRR"),
66 mRec(aRec),
67 mHostResolver(aResolver),
68 mType(aType),
69 mOriginSuffix(aRec->originSuffix) {
70 mHost = aRec->host;
71 mPB = aRec->pb;
72 MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess() || XRE_IsSocketProcess())>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(XRE_IsParentProcess() || XRE_IsSocketProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess() || XRE_IsSocketProcess()"
" (" "TRR must be in parent or socket process" ")", "./../../../netwerk/dns/TRR.cpp"
, 73); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess() || XRE_IsSocketProcess()"
") (" "TRR must be in parent or socket process" ")"); do { MOZ_CrashSequence
(__null, 73); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
73 "TRR must be in parent or socket process")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess() || XRE_IsSocketProcess())>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(XRE_IsParentProcess() || XRE_IsSocketProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess() || XRE_IsSocketProcess()"
" (" "TRR must be in parent or socket process" ")", "./../../../netwerk/dns/TRR.cpp"
, 73); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess() || XRE_IsSocketProcess()"
") (" "TRR must be in parent or socket process" ")"); do { MOZ_CrashSequence
(__null, 73); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
74}
75
76// when following CNAMEs
77TRR::TRR(AHostResolver* aResolver, nsHostRecord* aRec, nsCString& aHost,
78 enum TrrType& aType, unsigned int aLoopCount, bool aPB)
79 : mozilla::Runnable("TRR"),
80 mHost(aHost),
81 mRec(aRec),
82 mHostResolver(aResolver),
83 mType(aType),
84 mPB(aPB),
85 mCnameLoop(aLoopCount),
86 mOriginSuffix(aRec ? aRec->originSuffix : ""_ns) {
87 MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess() || XRE_IsSocketProcess())>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(XRE_IsParentProcess() || XRE_IsSocketProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess() || XRE_IsSocketProcess()"
" (" "TRR must be in parent or socket process" ")", "./../../../netwerk/dns/TRR.cpp"
, 88); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess() || XRE_IsSocketProcess()"
") (" "TRR must be in parent or socket process" ")"); do { MOZ_CrashSequence
(__null, 88); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
88 "TRR must be in parent or socket process")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess() || XRE_IsSocketProcess())>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(XRE_IsParentProcess() || XRE_IsSocketProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess() || XRE_IsSocketProcess()"
" (" "TRR must be in parent or socket process" ")", "./../../../netwerk/dns/TRR.cpp"
, 88); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess() || XRE_IsSocketProcess()"
") (" "TRR must be in parent or socket process" ")"); do { MOZ_CrashSequence
(__null, 88); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
89}
90
91// to verify a domain
92TRR::TRR(AHostResolver* aResolver, nsACString& aHost, enum TrrType aType,
93 const nsACString& aOriginSuffix, bool aPB, bool aUseFreshConnection)
94 : mozilla::Runnable("TRR"),
95 mHost(aHost),
96 mRec(nullptr),
97 mHostResolver(aResolver),
98 mType(aType),
99 mPB(aPB),
100 mOriginSuffix(aOriginSuffix),
101 mUseFreshConnection(aUseFreshConnection) {
102 MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess() || XRE_IsSocketProcess(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess() || XRE_IsSocketProcess())>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(XRE_IsParentProcess() || XRE_IsSocketProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess() || XRE_IsSocketProcess()"
" (" "TRR must be in parent or socket process" ")", "./../../../netwerk/dns/TRR.cpp"
, 103); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess() || XRE_IsSocketProcess()"
") (" "TRR must be in parent or socket process" ")"); do { MOZ_CrashSequence
(__null, 103); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
103 "TRR must be in parent or socket process")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess() || XRE_IsSocketProcess())>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(XRE_IsParentProcess() || XRE_IsSocketProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess() || XRE_IsSocketProcess()"
" (" "TRR must be in parent or socket process" ")", "./../../../netwerk/dns/TRR.cpp"
, 103); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess() || XRE_IsSocketProcess()"
") (" "TRR must be in parent or socket process" ")"); do { MOZ_CrashSequence
(__null, 103); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
104}
105
106void TRR::HandleTimeout() {
107 mTimeout = nullptr;
108 RecordReason(TRRSkippedReason::TRR_TIMEOUT);
109 Cancel(NS_ERROR_NET_TIMEOUT_EXTERNAL);
110}
111
112NS_IMETHODIMPnsresult
113TRR::Notify(nsITimer* aTimer) {
114 if (aTimer == mTimeout) {
115 HandleTimeout();
116 } else {
117 MOZ_CRASH("Unknown timer")do { do { } while (false); MOZ_ReportCrash("" "Unknown timer"
, "./../../../netwerk/dns/TRR.cpp", 117); AnnotateMozCrashReason
("MOZ_CRASH(" "Unknown timer" ")"); do { MOZ_CrashSequence(__null
, 117); __attribute__((nomerge)) ::abort(); } while (false); }
while (false)
;
118 }
119
120 return NS_OK;
121}
122
123NS_IMETHODIMPnsresult
124TRR::Run() {
125 MOZ_ASSERT_IF(XRE_IsParentProcess() && TRRService::Get(),do { if (XRE_IsParentProcess() && TRRService::Get()) {
do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread() || TRRService::Get()->IsOnTRRThread
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(NS_IsMainThread() || TRRService::Get()->IsOnTRRThread
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("NS_IsMainThread() || TRRService::Get()->IsOnTRRThread()"
, "./../../../netwerk/dns/TRR.cpp", 126); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread() || TRRService::Get()->IsOnTRRThread()"
")"); do { MOZ_CrashSequence(__null, 126); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
126 NS_IsMainThread() || TRRService::Get()->IsOnTRRThread())do { if (XRE_IsParentProcess() && TRRService::Get()) {
do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread() || TRRService::Get()->IsOnTRRThread
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(NS_IsMainThread() || TRRService::Get()->IsOnTRRThread
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("NS_IsMainThread() || TRRService::Get()->IsOnTRRThread()"
, "./../../../netwerk/dns/TRR.cpp", 126); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread() || TRRService::Get()->IsOnTRRThread()"
")"); do { MOZ_CrashSequence(__null, 126); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
127 MOZ_ASSERT_IF(XRE_IsSocketProcess(), NS_IsMainThread())do { if (XRE_IsSocketProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(NS_IsMainThread(
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("NS_IsMainThread()", "./../../../netwerk/dns/TRR.cpp", 127);
AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"
); do { MOZ_CrashSequence(__null, 127); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
128
129 if ((TRRService::Get() == nullptr) || NS_FAILED(SendHTTPRequest())((bool)(__builtin_expect(!!(NS_FAILED_impl(SendHTTPRequest())
), 0)))
) {
130 RecordReason(TRRSkippedReason::TRR_SEND_FAILED);
131 FailData(NS_ERROR_FAILURE);
132 // The dtor will now be run
133 }
134 return NS_OK;
135}
136
137DNSPacket* TRR::GetOrCreateDNSPacket() {
138 if (!mPacket) {
139 mPacket = MakeUnique<DNSPacket>();
140 }
141
142 return mPacket.get();
143}
144
145nsresult TRR::CreateQueryURI(nsIURI** aOutURI) {
146 nsAutoCString uri;
147 nsCOMPtr<nsIURI> dnsURI;
148 if (UseDefaultServer()) {
149 TRRService::Get()->GetURI(uri);
150 } else {
151 uri = mRec->mTrrServer;
152 }
153
154 nsresult rv = NS_NewURI(getter_AddRefs(dnsURI), uri);
155 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
156 RecordReason(TRRSkippedReason::TRR_BAD_URL);
157 return rv;
158 }
159
160 dnsURI.forget(aOutURI);
161 return NS_OK;
162}
163
164bool TRR::MaybeBlockRequest() {
165 if (((mType == TRRTYPE_A) || (mType == TRRTYPE_AAAA)) &&
166 mRec->mEffectiveTRRMode != nsIRequest::TRR_ONLY_MODE) {
167 // let NS resolves skip the blocklist check
168 // we also don't check the blocklist for TRR only requests
169 MOZ_ASSERT(mRec)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRec)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(mRec))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("mRec", "./../../../netwerk/dns/TRR.cpp"
, 169); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRec" ")"); do
{ MOZ_CrashSequence(__null, 169); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
170
171 // If TRRService isn't enabled anymore for the req, don't do TRR.
172 if (!TRRService::Get()->Enabled(mRec->mEffectiveTRRMode)) {
173 RecordReason(TRRSkippedReason::TRR_MODE_NOT_ENABLED);
174 return true;
175 }
176
177 if (!StaticPrefs::network_trr_strict_native_fallback() &&
178 UseDefaultServer() &&
179 TRRService::Get()->IsTemporarilyBlocked(mHost, mOriginSuffix, mPB,
180 true)) {
181 if (mType == TRRTYPE_A) {
182 // count only blocklist for A records to avoid double counts
183 glean::dns::trr_blacklisted.Get(TRRService::ProviderKey(), "true"_ns)
184 .Add();
185 }
186
187 RecordReason(TRRSkippedReason::TRR_HOST_BLOCKED_TEMPORARY);
188 // not really an error but no TRR is issued
189 return true;
190 }
191
192 if (TRRService::Get()->IsExcludedFromTRR(mHost, mRec->mEffectiveTRRMode)) {
193 RecordReason(TRRSkippedReason::TRR_EXCLUDED);
194 return true;
195 }
196
197 if (UseDefaultServer() && (mType == TRRTYPE_A)) {
198 glean::dns::trr_blacklisted.Get(TRRService::ProviderKey(), "false"_ns)
199 .Add();
200 }
201 }
202
203 return false;
204}
205
206nsresult TRR::SendHTTPRequest() {
207 // This is essentially the "run" method - created from nsHostResolver
208 if (mCancelled) {
209 return NS_ERROR_FAILURE;
210 }
211
212 if ((mType != TRRTYPE_A) && (mType != TRRTYPE_AAAA) &&
213 (mType != TRRTYPE_NS) && (mType != TRRTYPE_TXT) &&
214 (mType != TRRTYPE_HTTPSSVC)) {
215 // limit the calling interface because nsHostResolver has explicit slots for
216 // these types
217 return NS_ERROR_FAILURE;
218 }
219
220 if (MaybeBlockRequest()) {
221 return NS_ERROR_UNKNOWN_HOST;
222 }
223
224 LOG(("TRR::SendHTTPRequest resolve %s type %u\n", mHost.get(), mType))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR::SendHTTPRequest resolve %s type %u\n", mHost.get(), mType
); } } while (0)
;
225
226 nsAutoCString body;
227 bool disableECS = StaticPrefs::network_trr_disable_ECS();
228 nsresult rv =
229 GetOrCreateDNSPacket()->EncodeRequest(body, mHost, mType, disableECS);
230 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
231 HandleEncodeError(rv);
232 return rv;
233 }
234
235 bool useGet = StaticPrefs::network_trr_useGET();
236 nsCOMPtr<nsIURI> dnsURI;
237 rv = CreateQueryURI(getter_AddRefs(dnsURI));
238 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
239 LOG(("TRR:SendHTTPRequest: NewURI failed!\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR:SendHTTPRequest: NewURI failed!\n"); } } while (0)
;
240 return rv;
241 }
242
243 if (useGet) {
244 /* For GET requests, the outgoing packet needs to be Base64url-encoded and
245 then appended to the end of the URI. */
246 nsAutoCString encoded;
247 rv = Base64URLEncode(body.Length(),
248 reinterpret_cast<const unsigned char*>(body.get()),
249 Base64URLEncodePaddingPolicy::Omit, encoded);
250 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/dns/TRR.cpp"
, 250); return rv; } } while (false)
;
251
252 nsAutoCString query;
253 rv = dnsURI->GetQuery(query);
254 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
255 return rv;
256 }
257
258 if (query.IsEmpty()) {
259 query.Assign("?dns="_ns);
260 } else {
261 query.Append("&dns="_ns);
262 }
263 query.Append(encoded);
264
265 rv = NS_MutateURI(dnsURI).SetQuery(query).Finalize(dnsURI);
Value stored to 'rv' is never read
266 LOG(("TRR::SendHTTPRequest GET dns=%s\n", body.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR::SendHTTPRequest GET dns=%s\n", body.get()); } } while
(0)
;
267 }
268
269 nsCOMPtr<nsIChannel> channel;
270 bool useOHTTP = StaticPrefs::network_trr_use_ohttp();
271 if (useOHTTP) {
272 nsCOMPtr<nsIObliviousHttpService> ohttpService(
273 do_GetService("@mozilla.org/network/oblivious-http-service;1"));
274 if (!ohttpService) {
275 return NS_ERROR_FAILURE;
276 }
277 nsCOMPtr<nsIURI> relayURI;
278 nsTArray<uint8_t> encodedConfig;
279 rv = ohttpService->GetTRRSettings(getter_AddRefs(relayURI), encodedConfig);
280 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
281 return rv;
282 }
283 if (!relayURI) {
284 return NS_ERROR_FAILURE;
285 }
286 rv = ohttpService->NewChannel(relayURI, dnsURI, encodedConfig,
287 getter_AddRefs(channel));
288 } else {
289 rv = DNSUtils::CreateChannelHelper(dnsURI, getter_AddRefs(channel));
290 }
291 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !channel) {
292 LOG(("TRR:SendHTTPRequest: NewChannel failed!\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR:SendHTTPRequest: NewChannel failed!\n"); } } while (0)
;
293 return rv;
294 }
295
296 auto loadFlags = nsIRequest::LOAD_ANONYMOUS | nsIRequest::INHIBIT_CACHING |
297 nsIRequest::LOAD_BYPASS_CACHE |
298 nsIChannel::LOAD_BYPASS_URL_CLASSIFIER;
299 if (mUseFreshConnection) {
300 // Causes TRRServiceChannel to tell the connection manager
301 // to clear out any connection with the current conn info.
302 loadFlags |= nsIRequest::LOAD_FRESH_CONNECTION;
303 }
304 channel->SetLoadFlags(loadFlags);
305 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/dns/TRR.cpp"
, 305); return rv; } } while (false)
;
306
307 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
308 if (!httpChannel) {
309 return NS_ERROR_UNEXPECTED;
310 }
311
312 // This connection should not use TRR
313 rv = httpChannel->SetTRRMode(nsIRequest::TRR_DISABLED_MODE);
314 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/dns/TRR.cpp"
, 314); return rv; } } while (false)
;
315
316 nsCString contentType(ContentType());
317 rv = httpChannel->SetRequestHeader("Accept"_ns, contentType, false);
318 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/dns/TRR.cpp"
, 318); return rv; } } while (false)
;
319
320 nsAutoCString cred;
321 if (UseDefaultServer()) {
322 TRRService::Get()->GetCredentials(cred);
323 }
324 if (!cred.IsEmpty()) {
325 rv = httpChannel->SetRequestHeader("Authorization"_ns, cred, false);
326 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/dns/TRR.cpp"
, 326); return rv; } } while (false)
;
327 }
328
329 nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(channel);
330 if (!internalChannel) {
331 return NS_ERROR_UNEXPECTED;
332 }
333
334 // setting a small stream window means the h2 stack won't pipeline a window
335 // update with each HEADERS or reply to a DATA with a WINDOW UPDATE
336 rv = internalChannel->SetInitialRwin(127 * 1024);
337 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/dns/TRR.cpp"
, 337); return rv; } } while (false)
;
338 rv = internalChannel->SetIsTRRServiceChannel(true);
339 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/dns/TRR.cpp"
, 339); return rv; } } while (false)
;
340
341 // When using OHTTP, the we can't use cached connection info, since we
342 // need to connect to the relay, not the TRR server.
343 if (UseDefaultServer() && !useOHTTP &&
344 StaticPrefs::network_trr_async_connInfo()) {
345 RefPtr<nsHttpConnectionInfo> trrConnInfo =
346 TRRService::Get()->TRRConnectionInfo();
347 if (trrConnInfo) {
348 nsAutoCString host;
349 dnsURI->GetHost(host);
350 if (host.Equals(trrConnInfo->GetOrigin())) {
351 internalChannel->SetConnectionInfo(trrConnInfo);
352 LOG(("TRR::SendHTTPRequest use conn info:%s\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR::SendHTTPRequest use conn info:%s\n", trrConnInfo->
HashKey().get()); } } while (0)
353 trrConnInfo->HashKey().get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR::SendHTTPRequest use conn info:%s\n", trrConnInfo->
HashKey().get()); } } while (0)
;
354 } else {
355 // The connection info is inconsistent. Avoid using it and generate a
356 // new one.
357 TRRService::Get()->SetDefaultTRRConnectionInfo(nullptr);
358 TRRService::Get()->InitTRRConnectionInfo(true);
359 }
360 } else {
361 TRRService::Get()->InitTRRConnectionInfo();
362 }
363 }
364
365 if (useGet) {
366 rv = httpChannel->SetRequestMethod("GET"_ns);
367 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/dns/TRR.cpp"
, 367); return rv; } } while (false)
;
368 } else {
369 nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(httpChannel);
370 if (!uploadChannel) {
371 return NS_ERROR_UNEXPECTED;
372 }
373 uint32_t streamLength = body.Length();
374 nsCOMPtr<nsIInputStream> uploadStream;
375 rv =
376 NS_NewCStringInputStream(getter_AddRefs(uploadStream), std::move(body));
377 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/dns/TRR.cpp"
, 377); return rv; } } while (false)
;
378
379 rv = uploadChannel->ExplicitSetUploadStream(uploadStream, contentType,
380 streamLength, "POST"_ns);
381 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/dns/TRR.cpp"
, 381); return rv; } } while (false)
;
382 }
383
384 rv = SetupTRRServiceChannelInternal(httpChannel, useGet, contentType);
385 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
386 return rv;
387 }
388
389 rv = httpChannel->AsyncOpen(this);
390 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
391 return rv;
392 }
393
394 // If the asyncOpen succeeded we can say that we actually attempted to
395 // use the TRR connection.
396 if (mRec) {
397 mRec->mResolverType = ResolverType();
398 }
399
400 NS_NewTimerWithCallback(
401 getter_AddRefs(mTimeout), this,
402 mTimeoutMs ? mTimeoutMs : TRRService::Get()->GetRequestTimeout(),
403 nsITimer::TYPE_ONE_SHOT);
404
405 mChannel = std::move(channel);
406 return NS_OK;
407}
408
409// static
410nsresult TRR::SetupTRRServiceChannelInternal(nsIHttpChannel* aChannel,
411 bool aUseGet,
412 const nsACString& aContentType) {
413 nsCOMPtr<nsIHttpChannel> httpChannel = aChannel;
414 MOZ_ASSERT(httpChannel)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(httpChannel)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(httpChannel))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("httpChannel", "./../../../netwerk/dns/TRR.cpp"
, 414); AnnotateMozCrashReason("MOZ_ASSERT" "(" "httpChannel"
")"); do { MOZ_CrashSequence(__null, 414); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
415
416 nsresult rv = NS_OK;
417 if (!aUseGet) {
418 rv =
419 httpChannel->SetRequestHeader("Cache-Control"_ns, "no-store"_ns, false);
420 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/dns/TRR.cpp"
, 420); return rv; } } while (false)
;
421 }
422
423 // Sanitize the request by removing the Accept-Language header so we minimize
424 // the amount of fingerprintable information we send to the server.
425 if (!StaticPrefs::network_trr_send_accept_language_headers()) {
426 rv = httpChannel->SetRequestHeader("Accept-Language"_ns, ""_ns, false);
427 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/dns/TRR.cpp"
, 427); return rv; } } while (false)
;
428 }
429
430 // Sanitize the request by removing the User-Agent
431 if (!StaticPrefs::network_trr_send_user_agent_headers()) {
432 rv = httpChannel->SetRequestHeader("User-Agent"_ns, ""_ns, false);
433 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/dns/TRR.cpp"
, 433); return rv; } } while (false)
;
434 }
435
436 if (StaticPrefs::network_trr_send_empty_accept_encoding_headers()) {
437 rv = httpChannel->SetEmptyRequestHeader("Accept-Encoding"_ns);
438 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../netwerk/dns/TRR.cpp"
, 438); return rv; } } while (false)
;
439 }
440
441 // set the *default* response content type
442 if (NS_FAILED(httpChannel->SetContentType(aContentType))((bool)(__builtin_expect(!!(NS_FAILED_impl(httpChannel->SetContentType
(aContentType))), 0)))
) {
443 LOG(("TRR::SetupTRRServiceChannelInternal: couldn't set content-type!\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR::SetupTRRServiceChannelInternal: couldn't set content-type!\n"
); } } while (0)
;
444 }
445
446 return NS_OK;
447}
448
449NS_IMETHODIMPnsresult
450TRR::OnStartRequest(nsIRequest* aRequest) {
451 LOG(("TRR::OnStartRequest %p %s %d\n", this, mHost.get(), mType))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR::OnStartRequest %p %s %d\n", this, mHost.get(), mType)
; } } while (0)
;
452
453 nsresult status = NS_OK;
454 aRequest->GetStatus(&status);
455
456 if (NS_FAILED(status)((bool)(__builtin_expect(!!(NS_FAILED_impl(status)), 0)))) {
457 if (gIOService->InSleepMode()) {
458 RecordReason(TRRSkippedReason::TRR_SYSTEM_SLEEP_MODE);
459 } else if (NS_IsOffline()) {
460 RecordReason(TRRSkippedReason::TRR_BROWSER_IS_OFFLINE);
461 }
462
463 switch (status) {
464 case NS_ERROR_UNKNOWN_HOST:
465 RecordReason(TRRSkippedReason::TRR_CHANNEL_DNS_FAIL);
466 break;
467 case NS_ERROR_OFFLINE:
468 RecordReason(TRRSkippedReason::TRR_BROWSER_IS_OFFLINE);
469 break;
470 case NS_ERROR_NET_RESET:
471 RecordReason(TRRSkippedReason::TRR_NET_RESET);
472 break;
473 case NS_ERROR_NET_TIMEOUT:
474 case NS_ERROR_NET_TIMEOUT_EXTERNAL:
475 RecordReason(TRRSkippedReason::TRR_NET_TIMEOUT);
476 break;
477 case NS_ERROR_PROXY_CONNECTION_REFUSED:
478 RecordReason(TRRSkippedReason::TRR_NET_REFUSED);
479 break;
480 case NS_ERROR_NET_INTERRUPT:
481 RecordReason(TRRSkippedReason::TRR_NET_INTERRUPT);
482 break;
483 case NS_ERROR_NET_INADEQUATE_SECURITY:
484 RecordReason(TRRSkippedReason::TRR_NET_INADEQ_SEQURITY);
485 break;
486 default:
487 RecordReason(TRRSkippedReason::TRR_UNKNOWN_CHANNEL_FAILURE);
488 }
489 }
490
491 return NS_OK;
492}
493
494void TRR::SaveAdditionalRecords(
495 const nsClassHashtable<nsCStringHashKey, DOHresp>& aRecords) {
496 if (!mRec) {
497 return;
498 }
499 nsresult rv;
500 for (const auto& recordEntry : aRecords) {
501 if (!recordEntry.GetData() || recordEntry.GetData()->mAddresses.IsEmpty()) {
502 // no point in adding empty records.
503 continue;
504 }
505 // If IPv6 is disabled don't add anything else than IPv4.
506 if (StaticPrefs::network_dns_disableIPv6() &&
507 std::find_if(recordEntry.GetData()->mAddresses.begin(),
508 recordEntry.GetData()->mAddresses.end(),
509 [](const NetAddr& addr) { return !addr.IsIPAddrV4(); }) !=
510 recordEntry.GetData()->mAddresses.end()) {
511 continue;
512 }
513 RefPtr<nsHostRecord> hostRecord;
514 rv = mHostResolver->GetHostRecord(
515 recordEntry.GetKey(), EmptyCString(),
516 nsIDNSService::RESOLVE_TYPE_DEFAULT, mRec->flags, AF_UNSPEC0, mRec->pb,
517 mRec->originSuffix, getter_AddRefs(hostRecord));
518 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
519 LOG(("Failed to get host record for additional record %s",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "Failed to get host record for additional record %s", TPromiseFlatString
<char>(recordEntry.GetKey()).get()); } } while (0)
520 PromiseFlatCString(recordEntry.GetKey()).get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "Failed to get host record for additional record %s", TPromiseFlatString
<char>(recordEntry.GetKey()).get()); } } while (0)
;
521 continue;
522 }
523 RefPtr<AddrInfo> ai(
524 new AddrInfo(recordEntry.GetKey(), ResolverType(), TRRTYPE_A,
525 std::move(recordEntry.GetData()->mAddresses),
526 recordEntry.GetData()->mTtl));
527 mHostResolver->MaybeRenewHostRecord(hostRecord);
528
529 // Since we're not actually calling NameLookup for this record, we need
530 // to set these fields to avoid assertions in CompleteLookup.
531 // This is quite hacky, and should be fixed.
532 hostRecord->Reset();
533 hostRecord->mResolving++;
534 hostRecord->mEffectiveTRRMode =
535 static_cast<nsIRequest::TRRMode>(mRec->mEffectiveTRRMode);
536 LOG(("Completing lookup for additional: %s",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "Completing lookup for additional: %s", TPromiseFlatString<
char>(recordEntry.GetKey()).get()); } } while (0)
537 PromiseFlatCString(recordEntry.GetKey()).get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "Completing lookup for additional: %s", TPromiseFlatString<
char>(recordEntry.GetKey()).get()); } } while (0)
;
538 (void)mHostResolver->CompleteLookup(hostRecord, NS_OK, ai, mPB,
539 mOriginSuffix, TRRSkippedReason::TRR_OK,
540 this);
541 }
542}
543
544void TRR::StoreIPHintAsDNSRecord(const struct SVCB& aSVCBRecord) {
545 LOG(("TRR::StoreIPHintAsDNSRecord [%p] [%s]", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR::StoreIPHintAsDNSRecord [%p] [%s]", this, aSVCBRecord.
mSvcDomainName.get()); } } while (0)
546 aSVCBRecord.mSvcDomainName.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR::StoreIPHintAsDNSRecord [%p] [%s]", this, aSVCBRecord.
mSvcDomainName.get()); } } while (0)
;
547 CopyableTArray<NetAddr> addresses;
548 aSVCBRecord.GetIPHints(addresses);
549
550 if (StaticPrefs::network_dns_disableIPv6()) {
551 addresses.RemoveElementsBy(
552 [](const NetAddr& addr) { return !addr.IsIPAddrV4(); });
553 }
554
555 if (addresses.IsEmpty()) {
556 return;
557 }
558
559 RefPtr<nsHostRecord> hostRecord;
560 nsresult rv = mHostResolver->GetHostRecord(
561 aSVCBRecord.mSvcDomainName, EmptyCString(),
562 nsIDNSService::RESOLVE_TYPE_DEFAULT,
563 mRec->flags | nsIDNSService::RESOLVE_IP_HINT, AF_UNSPEC0, mRec->pb,
564 mRec->originSuffix, getter_AddRefs(hostRecord));
565 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
566 LOG(("Failed to get host record"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "Failed to get host record"); } } while (0)
;
567 return;
568 }
569
570 mHostResolver->MaybeRenewHostRecord(hostRecord);
571
572 RefPtr<AddrInfo> ai(new AddrInfo(aSVCBRecord.mSvcDomainName, ResolverType(),
573 TRRTYPE_A, std::move(addresses), mTTL));
574
575 // Since we're not actually calling NameLookup for this record, we need
576 // to set these fields to avoid assertions in CompleteLookup.
577 // This is quite hacky, and should be fixed.
578 hostRecord->mResolving++;
579 hostRecord->mEffectiveTRRMode =
580 static_cast<nsIRequest::TRRMode>(mRec->mEffectiveTRRMode);
581 (void)mHostResolver->CompleteLookup(hostRecord, NS_OK, ai, mPB, mOriginSuffix,
582 TRRSkippedReason::TRR_OK, this);
583}
584
585nsresult TRR::ReturnData(nsIChannel* aChannel) {
586 Maybe<TimeDuration> trrFetchDuration;
587 Maybe<TimeDuration> trrFetchDurationNetworkOnly;
588 // Set timings.
589 nsCOMPtr<nsITimedChannel> timedChan = do_QueryInterface(aChannel);
590 if (timedChan) {
591 TimeStamp asyncOpen, start, end;
592 if (NS_SUCCEEDED(timedChan->GetAsyncOpen(&asyncOpen))((bool)(__builtin_expect(!!(!NS_FAILED_impl(timedChan->GetAsyncOpen
(&asyncOpen))), 1)))
&&
593 !asyncOpen.IsNull()) {
594 trrFetchDuration = Some(TimeStamp::Now() - asyncOpen);
595 }
596 if (NS_SUCCEEDED(timedChan->GetRequestStart(&start))((bool)(__builtin_expect(!!(!NS_FAILED_impl(timedChan->GetRequestStart
(&start))), 1)))
&&
597 NS_SUCCEEDED(timedChan->GetResponseEnd(&end))((bool)(__builtin_expect(!!(!NS_FAILED_impl(timedChan->GetResponseEnd
(&end))), 1)))
&& !start.IsNull() &&
598 !end.IsNull()) {
599 trrFetchDurationNetworkOnly = Some(end - start);
600 }
601 }
602
603 if (mType != TRRTYPE_TXT && mType != TRRTYPE_HTTPSSVC) {
604 // create and populate an AddrInfo instance to pass on
605 RefPtr<AddrInfo> ai(new AddrInfo(mHost, ResolverType(), mType,
606 nsTArray<NetAddr>(), mDNS.mTtl));
607 auto builder = ai->Build();
608 builder.SetAddresses(std::move(mDNS.mAddresses));
609 builder.SetCanonicalHostname(mCname);
610 if (trrFetchDuration) {
611 builder.SetTrrFetchDuration((*trrFetchDuration).ToMilliseconds());
612 }
613 if (trrFetchDurationNetworkOnly) {
614 builder.SetTrrFetchDurationNetworkOnly(
615 (*trrFetchDurationNetworkOnly).ToMilliseconds());
616 }
617 ai = builder.Finish();
618
619 if (!mHostResolver) {
620 return NS_ERROR_FAILURE;
621 }
622 RecordReason(TRRSkippedReason::TRR_OK);
623 (void)mHostResolver->CompleteLookup(mRec, NS_OK, ai, mPB, mOriginSuffix,
624 mTRRSkippedReason, this);
625 mHostResolver = nullptr;
626 mRec = nullptr;
627 } else {
628 RecordReason(TRRSkippedReason::TRR_OK);
629 (void)mHostResolver->CompleteLookupByType(mRec, NS_OK, mResult,
630 mTRRSkippedReason, mTTL, mPB);
631 }
632
633 return NS_OK;
634}
635
636nsresult TRR::FailData(nsresult error) {
637 if (!mHostResolver) {
638 return NS_ERROR_FAILURE;
639 }
640
641 // If we didn't record a reason until now, record a default one.
642 RecordReason(TRRSkippedReason::TRR_FAILED);
643
644 if (mType == TRRTYPE_TXT || mType == TRRTYPE_HTTPSSVC) {
645 TypeRecordResultType empty(Nothing{});
646 (void)mHostResolver->CompleteLookupByType(mRec, error, empty,
647 mTRRSkippedReason, 0, mPB);
648 } else {
649 // create and populate an TRR AddrInfo instance to pass on to signal that
650 // this comes from TRR
651 nsTArray<NetAddr> noAddresses;
652 RefPtr<AddrInfo> ai =
653 new AddrInfo(mHost, ResolverType(), mType, std::move(noAddresses));
654
655 (void)mHostResolver->CompleteLookup(mRec, error, ai, mPB, mOriginSuffix,
656 mTRRSkippedReason, this);
657 }
658
659 mHostResolver = nullptr;
660 mRec = nullptr;
661 return NS_OK;
662}
663
664void TRR::HandleDecodeError(nsresult aStatusCode) {
665 auto rcode = mPacket->GetRCode();
666 if (rcode.isOk() && rcode.unwrap() != 0) {
667 if (rcode.unwrap() == 0x03) {
668 RecordReason(TRRSkippedReason::TRR_NXDOMAIN);
669 } else {
670 RecordReason(TRRSkippedReason::TRR_RCODE_FAIL);
671 }
672 } else if (aStatusCode == NS_ERROR_UNKNOWN_HOST ||
673 aStatusCode == NS_ERROR_DEFINITIVE_UNKNOWN_HOST) {
674 RecordReason(TRRSkippedReason::TRR_NO_ANSWERS);
675 } else {
676 RecordReason(TRRSkippedReason::TRR_DECODE_FAILED);
677 }
678}
679
680bool TRR::HasUsableResponse() {
681 if (mType == TRRTYPE_A || mType == TRRTYPE_AAAA) {
682 return !mDNS.mAddresses.IsEmpty();
683 }
684 if (mType == TRRTYPE_TXT) {
685 return mResult.is<TypeRecordTxt>();
686 }
687 if (mType == TRRTYPE_HTTPSSVC) {
688 return mResult.is<TypeRecordHTTPSSVC>();
689 }
690 return false;
691}
692
693nsresult TRR::FollowCname(nsIChannel* aChannel) {
694 nsresult rv = NS_OK;
695 nsAutoCString cname;
696 // True when at least one link of the chain we are following is an HTTPS
697 // AliasMode TargetName rather than a plain CNAME. Only then does RFC 9460
698 // require us to chase the target ourselves.
699 bool aliasFollow =
700 mHTTPSAliasFollow || GetOrCreateDNSPacket()->CnameIsHTTPSAlias();
701 while (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && mDNS.mAddresses.IsEmpty() && !mCname.IsEmpty() &&
702 mCnameLoop > 0) {
703 mCnameLoop--;
704 LOG(("TRR::On200Response CNAME %s => %s (%u)\n", mHost.get(), mCname.get(),do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR::On200Response CNAME %s => %s (%u)\n", mHost.get(),
mCname.get(), mCnameLoop); } } while (0)
705 mCnameLoop))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR::On200Response CNAME %s => %s (%u)\n", mHost.get(),
mCname.get(), mCnameLoop); } } while (0)
;
706 cname = mCname;
707 mCname.Truncate();
708
709 LOG(("TRR: check for CNAME record for %s within previous response\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR: check for CNAME record for %s within previous response\n"
, cname.get()); } } while (0)
710 cname.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR: check for CNAME record for %s within previous response\n"
, cname.get()); } } while (0)
;
711 nsClassHashtable<nsCStringHashKey, DOHresp> additionalRecords;
712 rv = GetOrCreateDNSPacket()->Decode(
713 cname, mType, mCname, StaticPrefs::network_trr_allow_rfc1918(), mDNS,
714 mResult, additionalRecords, mTTL);
715 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
716 LOG(("TRR::FollowCname DohDecode %x\n", (int)rv))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR::FollowCname DohDecode %x\n", (int)rv); } } while (0)
;
717 HandleDecodeError(rv);
718 }
719 aliasFollow = aliasFollow || (!mCname.IsEmpty() &&
720 GetOrCreateDNSPacket()->CnameIsHTTPSAlias());
721 }
722
723 // restore mCname as DohDecode() change it
724 mCname = std::move(cname);
725 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && HasUsableResponse()) {
726 ReturnData(aChannel);
727 return NS_OK;
728 }
729
730 bool ra = mPacket && mPacket->RecursionAvailable().unwrapOr(false);
731 LOG(("ra = %d", ra))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "ra = %d", ra); } } while (0)
;
732 if (rv == NS_ERROR_UNKNOWN_HOST && ra && !aliasFollow) {
733 // If recursion is available, but no addresses have been returned,
734 // we can just return a failure here.
735 // This optimization is only valid for CNAME chains: a recursive
736 // resolver that follows a CNAME already inlines the target's addresses.
737 // It does not hold for HTTPS AliasMode, since recursive resolvers do not
738 // chase the SVCB/HTTPS alias, so we must query the TargetName ourselves.
739 LOG(("TRR::FollowCname not sending another request as RA flag is set."))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR::FollowCname not sending another request as RA flag is set."
); } } while (0)
;
740 FailData(NS_ERROR_UNKNOWN_HOST);
741 return NS_OK;
742 }
743
744 if (!mCnameLoop) {
745 LOG(("TRR::On200Response CNAME loop, eject!\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR::On200Response CNAME loop, eject!\n"); } } while (0)
;
746 return NS_ERROR_REDIRECT_LOOP;
747 }
748
749 LOG(("TRR::On200Response CNAME %s => %s (%u)\n", mHost.get(), mCname.get(),do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR::On200Response CNAME %s => %s (%u)\n", mHost.get(),
mCname.get(), mCnameLoop); } } while (0)
750 mCnameLoop))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR::On200Response CNAME %s => %s (%u)\n", mHost.get(),
mCname.get(), mCnameLoop); } } while (0)
;
751 RefPtr<TRR> trr =
752 new TRR(mHostResolver, mRec, mCname, mType, mCnameLoop, mPB);
753 trr->SetPurpose(mPurpose);
754 // Recursive resolvers do not chase HTTPS AliasMode targets, so following the
755 // TargetName is an HTTPS alias follow. Remember this so that a target with no
756 // HTTPS record still yields an AliasMode record instead of failing. A plain
757 // CNAME is not an alias follow: a target without an HTTPS record simply has
758 // no HTTPS RR.
759 trr->mHTTPSAliasFollow = aliasFollow;
760 if (!TRRService::Get()) {
761 return NS_ERROR_FAILURE;
762 }
763 return TRRService::Get()->DispatchTRRRequest(trr);
764}
765
766nsresult TRR::On200Response(nsIChannel* aChannel) {
767 // decode body and create an AddrInfo struct for the response
768 nsClassHashtable<nsCStringHashKey, DOHresp> additionalRecords;
769 if (RefPtr<TypeHostRecord> typeRec = do_QueryObject(mRec)) {
770 MutexAutoLock lock(typeRec->mResultsLock);
771 if (typeRec->mOriginHost) {
772 GetOrCreateDNSPacket()->SetOriginHost(typeRec->mOriginHost);
773 }
774 }
775 nsresult rv = GetOrCreateDNSPacket()->Decode(
776 mHost, mType, mCname, StaticPrefs::network_trr_allow_rfc1918(), mDNS,
777 mResult, additionalRecords, mTTL);
778 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
779 // We followed an HTTPS AliasMode record to this TargetName. If the target
780 // resolved successfully (NOERROR) but simply has no HTTPS record of its
781 // own, RFC 9460 still requires connecting to the TargetName, so synthesize
782 // an AliasMode record carrying it. The connection layer then routes to the
783 // target and Happy Eyeballs issues A/AAAA/HTTPS queries for it. A SERVFAIL
784 // or NXDOMAIN is a genuine failure and is left to propagate.
785 if (mType == TRRTYPE_HTTPSSVC && mHTTPSAliasFollow &&
786 rv == NS_ERROR_UNKNOWN_HOST) {
787 auto rcode = mPacket->GetRCode();
788 if (rcode.isOk() && rcode.unwrap() == 0) {
789 LOG(("TRR::On200Response synthesizing AliasMode record for %s\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR::On200Response synthesizing AliasMode record for %s\n"
, mHost.get()); } } while (0)
790 mHost.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR::On200Response synthesizing AliasMode record for %s\n"
, mHost.get()); } } while (0)
;
791 SVCB alias;
792 alias.mSvcFieldPriority = 0;
793 alias.mSvcDomainName = mHost;
794 CopyableTArray<SVCB> records;
795 records.AppendElement(std::move(alias));
796 mResult = AsVariant(std::move(records));
797 if (mTTL == UINT32_MAX(4294967295U)) {
798 mTTL = 60;
799 }
800 ReturnData(aChannel);
801 return NS_OK;
802 }
803 }
804 LOG(("TRR::On200Response DohDecode %x\n", (int)rv))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR::On200Response DohDecode %x\n", (int)rv); } } while (0
)
;
805 HandleDecodeError(rv);
806 return rv;
807 }
808 if (StaticPrefs::network_trr_add_additional_records()) {
809 SaveAdditionalRecords(additionalRecords);
810 }
811
812 if (mResult.is<TypeRecordHTTPSSVC>()) {
813 auto& results = mResult.as<TypeRecordHTTPSSVC>();
814 for (const auto& rec : results) {
815 StoreIPHintAsDNSRecord(rec);
816 }
817 }
818
819 if (!mDNS.mAddresses.IsEmpty() || mType == TRRTYPE_TXT || mCname.IsEmpty()) {
820 // pass back the response data
821 ReturnData(aChannel);
822 return NS_OK;
823 }
824
825 LOG(("TRR::On200Response trying CNAME %s", mCname.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR::On200Response trying CNAME %s", mCname.get()); } } while
(0)
;
826 return FollowCname(aChannel);
827}
828
829void TRR::RecordProcessingTime(nsIChannel* aChannel) {
830 // This method records the time it took from the last received byte of the
831 // DoH response until we've notified the consumer with a host record.
832 nsCOMPtr<nsITimedChannel> timedChan = do_QueryInterface(aChannel);
833 if (!timedChan) {
834 return;
835 }
836 TimeStamp end;
837 if (NS_FAILED(timedChan->GetResponseEnd(&end))((bool)(__builtin_expect(!!(NS_FAILED_impl(timedChan->GetResponseEnd
(&end))), 0)))
) {
838 return;
839 }
840
841 if (end.IsNull()) {
842 return;
843 }
844
845 glean::dns::trr_processing_time.AccumulateRawDuration(TimeStamp::Now() - end);
846
847 LOG(("Processing DoH response took %f ms",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "Processing DoH response took %f ms", (TimeStamp::Now() - end
).ToMilliseconds()); } } while (0)
848 (TimeStamp::Now() - end).ToMilliseconds()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "Processing DoH response took %f ms", (TimeStamp::Now() - end
).ToMilliseconds()); } } while (0)
;
849}
850
851void TRR::ReportStatus(nsresult aStatusCode) {
852 // If the TRR was cancelled by nsHostResolver, then we don't need to report
853 // it as failed; otherwise it can cause the confirmation to fail.
854 if (UseDefaultServer() && aStatusCode != NS_ERROR_ABORT) {
855 // Bad content is still considered "okay" if the HTTP response is okay
856 TRRService::Get()->RecordTRRStatus(this);
857 }
858}
859
860static void RecordHttpVersion(nsIHttpChannel* aHttpChannel) {
861 nsCOMPtr<nsIHttpChannelInternal> internalChannel =
862 do_QueryInterface(aHttpChannel);
863 if (!internalChannel) {
864 LOG(("RecordHttpVersion: Failed to QI nsIHttpChannelInternal"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "RecordHttpVersion: Failed to QI nsIHttpChannelInternal"); }
} while (0)
;
865 return;
866 }
867
868 uint32_t major, minor;
869 if (NS_FAILED(internalChannel->GetResponseVersion(&major, &minor))((bool)(__builtin_expect(!!(NS_FAILED_impl(internalChannel->
GetResponseVersion(&major, &minor))), 0)))
) {
870 LOG(("RecordHttpVersion: Failed to get protocol version"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "RecordHttpVersion: Failed to get protocol version"); } } while
(0)
;
871 return;
872 }
873
874 if (major == 2) {
875 glean::dns::trr_http_version.Get(TRRService::ProviderKey(), "h_2"_ns).Add();
876 } else if (major == 3) {
877 glean::dns::trr_http_version.Get(TRRService::ProviderKey(), "h_3"_ns).Add();
878 } else {
879 glean::dns::trr_http_version.Get(TRRService::ProviderKey(), "h_1"_ns).Add();
880 }
881
882 LOG(("RecordHttpVersion: Provider responded using HTTP version: %d", major))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "RecordHttpVersion: Provider responded using HTTP version: %d"
, major); } } while (0)
;
883}
884
885NS_IMETHODIMPnsresult
886TRR::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) {
887 // The dtor will be run after the function returns
888 LOG(("TRR:OnStopRequest %p %s %d failed=%d code=%X\n", this, mHost.get(),do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR:OnStopRequest %p %s %d failed=%d code=%X\n", this, mHost
.get(), mType, mFailed, (unsigned int)aStatusCode); } } while
(0)
889 mType, mFailed, (unsigned int)aStatusCode))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR:OnStopRequest %p %s %d failed=%d code=%X\n", this, mHost
.get(), mType, mFailed, (unsigned int)aStatusCode); } } while
(0)
;
890 nsCOMPtr<nsIChannel> channel;
891 channel.swap(mChannel);
892
893 mChannelStatus = aStatusCode;
894 if (NS_SUCCEEDED(aStatusCode)((bool)(__builtin_expect(!!(!NS_FAILED_impl(aStatusCode)), 1)
))
) {
895 nsCString label = "regular"_ns;
896 if (mPB) {
897 label = "private"_ns;
898 }
899 mozilla::glean::networking::trr_request_count.Get(label).Add(1);
900 }
901
902 {
903 // Cancel the timer since we don't need it anymore.
904 nsCOMPtr<nsITimer> timer;
905 mTimeout.swap(timer);
906 if (timer) {
907 timer->Cancel();
908 }
909 }
910
911 auto scopeExit = MakeScopeExit([&] { ReportStatus(aStatusCode); });
912
913 nsresult rv = NS_OK;
914 // if status was "fine", parse the response and pass on the answer
915 if (!mFailed && NS_SUCCEEDED(aStatusCode)((bool)(__builtin_expect(!!(!NS_FAILED_impl(aStatusCode)), 1)
))
) {
916 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aRequest);
917 if (!httpChannel) {
918 return NS_ERROR_UNEXPECTED;
919 }
920 nsAutoCString contentType;
921 httpChannel->GetContentType(contentType);
922 if (contentType.Length() &&
923 !contentType.LowerCaseEqualsASCII(ContentType())) {
924 LOG(("TRR:OnStopRequest %p %s %d wrong content type %s\n", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR:OnStopRequest %p %s %d wrong content type %s\n", this,
mHost.get(), mType, contentType.get()); } } while (0)
925 mHost.get(), mType, contentType.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR:OnStopRequest %p %s %d wrong content type %s\n", this,
mHost.get(), mType, contentType.get()); } } while (0)
;
926 FailData(NS_ERROR_UNEXPECTED);
927 return NS_OK;
928 }
929
930 uint32_t httpStatus;
931 rv = httpChannel->GetResponseStatus(&httpStatus);
932 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && httpStatus == 200) {
933 rv = On200Response(channel);
934 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && UseDefaultServer()) {
935 RecordReason(TRRSkippedReason::TRR_OK);
936 RecordProcessingTime(channel);
937 RecordHttpVersion(httpChannel);
938 return rv;
939 }
940 } else {
941 RecordReason(TRRSkippedReason::TRR_SERVER_RESPONSE_ERR);
942 LOG(("TRR:OnStopRequest:%d %p rv %x httpStatus %d\n", __LINE__, this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR:OnStopRequest:%d %p rv %x httpStatus %d\n", 942, this,
(int)rv, httpStatus); } } while (0)
943 (int)rv, httpStatus))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR:OnStopRequest:%d %p rv %x httpStatus %d\n", 942, this,
(int)rv, httpStatus); } } while (0)
;
944 }
945 }
946
947 LOG(("TRR:OnStopRequest %p status %x mFailed %d\n", this, (int)aStatusCode,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR:OnStopRequest %p status %x mFailed %d\n", this, (int)aStatusCode
, mFailed); } } while (0)
948 mFailed))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR:OnStopRequest %p status %x mFailed %d\n", this, (int)aStatusCode
, mFailed); } } while (0)
;
949 FailData(NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) ? NS_ERROR_UNKNOWN_HOST : rv);
950 return NS_OK;
951}
952
953NS_IMETHODIMPnsresult
954TRR::OnDataAvailable(nsIRequest* aRequest, nsIInputStream* aInputStream,
955 uint64_t aOffset, const uint32_t aCount) {
956 LOG(("TRR:OnDataAvailable %p %s %d failed=%d aCount=%u\n", this, mHost.get(),do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR:OnDataAvailable %p %s %d failed=%d aCount=%u\n", this,
mHost.get(), mType, mFailed, (unsigned int)aCount); } } while
(0)
957 mType, mFailed, (unsigned int)aCount))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR:OnDataAvailable %p %s %d failed=%d aCount=%u\n", this,
mHost.get(), mType, mFailed, (unsigned int)aCount); } } while
(0)
;
958 // receive DNS response into the local buffer
959 if (mFailed) {
960 return NS_ERROR_FAILURE;
961 }
962
963 nsresult rv = GetOrCreateDNSPacket()->OnDataAvailable(aRequest, aInputStream,
964 aOffset, aCount);
965 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
966 LOG(("TRR::OnDataAvailable:%d fail\n", __LINE__))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR::OnDataAvailable:%d fail\n", 966); } } while (0)
;
967 mFailed = true;
968 return rv;
969 }
970 return NS_OK;
971}
972
973void TRR::Cancel(nsresult aStatus) {
974 bool isTRRServiceChannel = false;
975 nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(
976 do_QueryInterface(mChannel));
977 if (httpChannelInternal) {
978 nsresult rv =
979 httpChannelInternal->GetIsTRRServiceChannel(&isTRRServiceChannel);
980 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
981 isTRRServiceChannel = false;
982 }
983 }
984 // nsHttpChannel can be only canceled on the main thread.
985 RefPtr<nsHttpChannel> httpChannel = do_QueryObject(mChannel);
986 if (isTRRServiceChannel && !XRE_IsSocketProcess() && !httpChannel) {
987 if (TRRService::Get()) {
988 nsCOMPtr<nsIThread> thread = TRRService::Get()->TRRThread();
989 if (thread && !thread->IsOnCurrentThread()) {
990 thread->Dispatch(NS_NewRunnableFunction(
991 "TRR::Cancel",
992 [self = RefPtr(this), aStatus]() { self->Cancel(aStatus); }));
993 return;
994 }
995 }
996 } else {
997 if (!NS_IsMainThread()) {
998 NS_DispatchToMainThread(NS_NewRunnableFunction(
999 "TRR::Cancel",
1000 [self = RefPtr(this), aStatus]() { self->Cancel(aStatus); }));
1001 return;
1002 }
1003 }
1004
1005 if (mCancelled) {
1006 return;
1007 }
1008 mCancelled = true;
1009
1010 if (mChannel) {
1011 RecordReason(TRRSkippedReason::TRR_REQ_CANCELLED);
1012 LOG(("TRR: %p canceling Channel %p %s %d status=%" PRIx32 "\n", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR: %p canceling Channel %p %s %d status=%" "x" "\n", this
, mChannel.get(), mHost.get(), mType, static_cast<uint32_t
>(aStatus)); } } while (0)
1013 mChannel.get(), mHost.get(), mType, static_cast<uint32_t>(aStatus)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHostResolverLog; if ((__builtin_expect(!!(mozilla::detail::
log_test(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Debug
, "TRR: %p canceling Channel %p %s %d status=%" "x" "\n", this
, mChannel.get(), mHost.get(), mType, static_cast<uint32_t
>(aStatus)); } } while (0)
;
1014 mChannel->Cancel(aStatus);
1015 }
1016}
1017
1018bool TRR::UseDefaultServer() { return !mRec || mRec->mTrrServer.IsEmpty(); }
1019
1020} // namespace net
1021} // namespace mozilla