Bug Summary

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