Backed out changeset 1893713e1d17 (bug 1930292) for causing bc failures @ browser_fin...
[gecko.git] / netwerk / dns / GetAddrInfo.cpp
blob715b08b4956276347edfd4e784a678591c784329
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "GetAddrInfo.h"
9 #ifdef DNSQUERY_AVAILABLE
10 // There is a bug in windns.h where the type of parameter ppQueryResultsSet for
11 // DnsQuery_A is dependent on UNICODE being set. It should *always* be
12 // PDNS_RECORDA, but if UNICODE is set it is PDNS_RECORDW. To get around this
13 // we make sure that UNICODE is unset.
14 # undef UNICODE
15 # include <ws2tcpip.h>
16 # undef GetAddrInfo
17 # include <windns.h>
18 #endif // DNSQUERY_AVAILABLE
20 #include "mozilla/ClearOnShutdown.h"
21 #include "mozilla/net/DNS.h"
22 #include "NativeDNSResolverOverrideParent.h"
23 #include "prnetdb.h"
24 #include "nsIOService.h"
25 #include "nsHostResolver.h"
26 #include "nsError.h"
27 #include "mozilla/net/DNS.h"
28 #include <algorithm>
29 #include "prerror.h"
31 #include "mozilla/Logging.h"
32 #include "mozilla/StaticPrefs_network.h"
33 #include "mozilla/net/DNSPacket.h"
34 #include "nsIDNSService.h"
35 #include "nsINetworkLinkService.h"
37 namespace mozilla::net {
39 static StaticRefPtr<NativeDNSResolverOverride> gOverrideService;
41 LazyLogModule gGetAddrInfoLog("GetAddrInfo");
42 #define LOG(msg, ...) \
43 MOZ_LOG(gGetAddrInfoLog, LogLevel::Debug, ("[DNS]: " msg, ##__VA_ARGS__))
44 #define LOG_WARNING(msg, ...) \
45 MOZ_LOG(gGetAddrInfoLog, LogLevel::Warning, ("[DNS]: " msg, ##__VA_ARGS__))
47 #ifdef DNSQUERY_AVAILABLE
49 # define COMPUTER_NAME_BUFFER_SIZE 100
50 static char sDNSComputerName[COMPUTER_NAME_BUFFER_SIZE];
51 static char sNETBIOSComputerName[MAX_COMPUTERNAME_LENGTH + 1];
53 ////////////////////////////
54 // WINDOWS IMPLEMENTATION //
55 ////////////////////////////
57 // Ensure consistency of PR_* and AF_* constants to allow for legacy usage of
58 // PR_* constants with this API.
59 static_assert(PR_AF_INET == AF_INET && PR_AF_INET6 == AF_INET6 &&
60 PR_AF_UNSPEC == AF_UNSPEC,
61 "PR_AF_* must match AF_*");
63 // If successful, returns in aResult a TTL value that is smaller or
64 // equal with the one already there. Gets the TTL value by calling
65 // to DnsQuery_A and iterating through the returned
66 // records to find the one with the smallest TTL value.
67 static MOZ_ALWAYS_INLINE nsresult _CallDnsQuery_A_Windows(
68 const nsACString& aHost, uint16_t aAddressFamily, DWORD aFlags,
69 std::function<void(PDNS_RECORDA)> aCallback) {
70 NS_ConvertASCIItoUTF16 name(aHost);
72 auto callDnsQuery_A = [&](uint16_t reqFamily) {
73 PDNS_RECORDA dnsData = nullptr;
74 DNS_STATUS status = DnsQuery_A(aHost.BeginReading(), reqFamily, aFlags,
75 nullptr, &dnsData, nullptr);
76 if (status == DNS_INFO_NO_RECORDS || status == DNS_ERROR_RCODE_NAME_ERROR ||
77 !dnsData) {
78 LOG("No DNS records found for %s. status=%lX. reqFamily = %X\n",
79 aHost.BeginReading(), status, reqFamily);
80 return NS_ERROR_FAILURE;
81 } else if (status != NOERROR) {
82 LOG_WARNING("DnsQuery_A failed with status %lX.\n", status);
83 return NS_ERROR_UNEXPECTED;
86 for (PDNS_RECORDA curRecord = dnsData; curRecord;
87 curRecord = curRecord->pNext) {
88 // Only records in the answer section are important
89 if (curRecord->Flags.S.Section != DnsSectionAnswer) {
90 continue;
92 if (curRecord->wType != reqFamily) {
93 continue;
96 aCallback(curRecord);
99 DnsFree(dnsData, DNS_FREE_TYPE::DnsFreeRecordList);
100 return NS_OK;
103 if (aAddressFamily == PR_AF_UNSPEC || aAddressFamily == PR_AF_INET) {
104 callDnsQuery_A(DNS_TYPE_A);
107 if (aAddressFamily == PR_AF_UNSPEC || aAddressFamily == PR_AF_INET6) {
108 callDnsQuery_A(DNS_TYPE_AAAA);
110 return NS_OK;
113 bool recordTypeMatchesRequest(uint16_t wType, uint16_t aAddressFamily) {
114 if (aAddressFamily == PR_AF_UNSPEC) {
115 return wType == DNS_TYPE_A || wType == DNS_TYPE_AAAA;
117 if (aAddressFamily == PR_AF_INET) {
118 return wType == DNS_TYPE_A;
120 if (aAddressFamily == PR_AF_INET6) {
121 return wType == DNS_TYPE_AAAA;
123 return false;
126 static MOZ_ALWAYS_INLINE nsresult _GetTTLData_Windows(const nsACString& aHost,
127 uint32_t* aResult,
128 uint16_t aAddressFamily) {
129 MOZ_ASSERT(!aHost.IsEmpty());
130 MOZ_ASSERT(aResult);
131 if (aAddressFamily != PR_AF_UNSPEC && aAddressFamily != PR_AF_INET &&
132 aAddressFamily != PR_AF_INET6) {
133 return NS_ERROR_UNEXPECTED;
136 // In order to avoid using ANY records which are not always implemented as a
137 // "Gimme what you have" request in hostname resolvers, we should send A
138 // and/or AAAA requests, based on the address family requested.
139 const DWORD ttlFlags =
140 (DNS_QUERY_STANDARD | DNS_QUERY_NO_NETBT | DNS_QUERY_NO_HOSTS_FILE |
141 DNS_QUERY_NO_MULTICAST | DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE |
142 DNS_QUERY_DONT_RESET_TTL_VALUES);
143 unsigned int ttl = (unsigned int)-1;
144 _CallDnsQuery_A_Windows(
145 aHost, aAddressFamily, ttlFlags,
146 [&ttl, &aHost, aAddressFamily](PDNS_RECORDA curRecord) {
147 if (recordTypeMatchesRequest(curRecord->wType, aAddressFamily)) {
148 ttl = std::min<unsigned int>(ttl, curRecord->dwTtl);
149 } else {
150 LOG("Received unexpected record type %u in response for %s.\n",
151 curRecord->wType, aHost.BeginReading());
155 if (ttl == (unsigned int)-1) {
156 LOG("No useable TTL found.");
157 return NS_ERROR_FAILURE;
160 *aResult = ttl;
161 return NS_OK;
164 static MOZ_ALWAYS_INLINE nsresult
165 _DNSQuery_A_SingleLabel(const nsACString& aCanonHost, uint16_t aAddressFamily,
166 uint16_t aFlags, AddrInfo** aAddrInfo) {
167 bool setCanonName = aFlags & nsIDNSService::RESOLVE_CANONICAL_NAME;
168 nsAutoCString canonName;
169 const DWORD flags = (DNS_QUERY_STANDARD | DNS_QUERY_NO_MULTICAST |
170 DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE);
171 nsTArray<NetAddr> addresses;
173 _CallDnsQuery_A_Windows(
174 aCanonHost, aAddressFamily, flags, [&](PDNS_RECORDA curRecord) {
175 MOZ_DIAGNOSTIC_ASSERT(curRecord->wType == DNS_TYPE_A ||
176 curRecord->wType == DNS_TYPE_AAAA);
177 if (setCanonName) {
178 canonName.Assign(curRecord->pName);
180 NetAddr addr{};
181 addr.inet.family = AF_INET;
182 addr.inet.ip = curRecord->Data.A.IpAddress;
183 addresses.AppendElement(addr);
186 LOG("Query for: %s has %zu results", aCanonHost.BeginReading(),
187 addresses.Length());
188 if (addresses.IsEmpty()) {
189 return NS_ERROR_UNKNOWN_HOST;
191 RefPtr<AddrInfo> ai(new AddrInfo(
192 aCanonHost, canonName, DNSResolverType::Native, 0, std::move(addresses)));
193 ai.forget(aAddrInfo);
195 return NS_OK;
198 #endif
200 ////////////////////////////////////
201 // PORTABLE RUNTIME IMPLEMENTATION//
202 ////////////////////////////////////
204 static bool SkipIPv6DNSLookup() {
205 #if defined(XP_WIN) || defined(XP_LINUX) || defined(XP_MACOSX)
206 return StaticPrefs::network_dns_skip_ipv6_when_no_addresses() &&
207 !nsINetworkLinkService::HasNonLocalIPv6Address();
208 #else
209 return false;
210 #endif
213 static MOZ_ALWAYS_INLINE nsresult
214 _GetAddrInfo_Portable(const nsACString& aCanonHost, uint16_t aAddressFamily,
215 nsIDNSService::DNSFlags aFlags, AddrInfo** aAddrInfo) {
216 MOZ_ASSERT(!aCanonHost.IsEmpty());
217 MOZ_ASSERT(aAddrInfo);
219 // We accept the same aFlags that nsHostResolver::ResolveHost accepts, but we
220 // need to translate the aFlags into a form that PR_GetAddrInfoByName
221 // accepts.
222 int prFlags = PR_AI_ADDRCONFIG;
223 if (!(aFlags & nsIDNSService::RESOLVE_CANONICAL_NAME)) {
224 prFlags |= PR_AI_NOCANONNAME;
227 // We need to remove IPv4 records manually because PR_GetAddrInfoByName
228 // doesn't support PR_AF_INET6.
229 bool disableIPv4 = aAddressFamily == PR_AF_INET6;
230 if (disableIPv4) {
231 aAddressFamily = PR_AF_UNSPEC;
234 if (SkipIPv6DNSLookup()) {
235 // If the family was AF_UNSPEC initially, make it AF_INET
236 // when there are no IPv6 addresses.
237 // If the DNS request specified IPv6 specifically, let it
238 // go through.
239 if (aAddressFamily == PR_AF_UNSPEC && !disableIPv4) {
240 aAddressFamily = PR_AF_INET;
244 #if defined(DNSQUERY_AVAILABLE)
245 if (StaticPrefs::network_dns_dns_query_single_label() &&
246 !aCanonHost.Contains('.') && aCanonHost != "localhost"_ns) {
247 // For some reason we can't use DnsQuery_A to get the computer's IP.
248 if (!aCanonHost.Equals(nsDependentCString(sDNSComputerName),
249 nsCaseInsensitiveCStringComparator) &&
250 !aCanonHost.Equals(nsDependentCString(sNETBIOSComputerName),
251 nsCaseInsensitiveCStringComparator)) {
252 // This is a single label name resolve without a dot.
253 // We use DNSQuery_A for these.
254 LOG("Resolving %s using DnsQuery_A (computername: %s)\n",
255 aCanonHost.BeginReading(), sDNSComputerName);
256 return _DNSQuery_A_SingleLabel(aCanonHost, aAddressFamily, aFlags,
257 aAddrInfo);
260 #endif
262 LOG("Resolving %s using PR_GetAddrInfoByName", aCanonHost.BeginReading());
263 PRAddrInfo* prai =
264 PR_GetAddrInfoByName(aCanonHost.BeginReading(), aAddressFamily, prFlags);
266 if (!prai) {
267 LOG("PR_GetAddrInfoByName returned null PR_GetError:%d PR_GetOSErrpr:%d",
268 PR_GetError(), PR_GetOSError());
269 return NS_ERROR_UNKNOWN_HOST;
272 nsAutoCString canonName;
273 if (aFlags & nsIDNSService::RESOLVE_CANONICAL_NAME) {
274 canonName.Assign(PR_GetCanonNameFromAddrInfo(prai));
277 bool filterNameCollision =
278 !(aFlags & nsIDNSService::RESOLVE_ALLOW_NAME_COLLISION);
279 RefPtr<AddrInfo> ai(new AddrInfo(aCanonHost, prai, disableIPv4,
280 filterNameCollision, canonName));
281 PR_FreeAddrInfo(prai);
282 if (ai->Addresses().IsEmpty()) {
283 LOG("PR_GetAddrInfoByName returned empty address list");
284 return NS_ERROR_UNKNOWN_HOST;
287 ai.forget(aAddrInfo);
289 LOG("PR_GetAddrInfoByName resolved successfully");
290 return NS_OK;
293 //////////////////////////////////////
294 // COMMON/PLATFORM INDEPENDENT CODE //
295 //////////////////////////////////////
296 nsresult GetAddrInfoInit() {
297 LOG("Initializing GetAddrInfo.\n");
299 #ifdef DNSQUERY_AVAILABLE
300 DWORD namesize = COMPUTER_NAME_BUFFER_SIZE;
301 if (!GetComputerNameExA(ComputerNameDnsHostname, sDNSComputerName,
302 &namesize)) {
303 sDNSComputerName[0] = 0;
305 namesize = MAX_COMPUTERNAME_LENGTH + 1;
306 if (!GetComputerNameExA(ComputerNameNetBIOS, sNETBIOSComputerName,
307 &namesize)) {
308 sNETBIOSComputerName[0] = 0;
310 #endif
311 return NS_OK;
314 nsresult GetAddrInfoShutdown() {
315 LOG("Shutting down GetAddrInfo.\n");
316 return NS_OK;
319 bool FindAddrOverride(const nsACString& aHost, uint16_t aAddressFamily,
320 nsIDNSService::DNSFlags aFlags, AddrInfo** aAddrInfo) {
321 RefPtr<NativeDNSResolverOverride> overrideService = gOverrideService;
322 if (!overrideService) {
323 return false;
325 AutoReadLock lock(overrideService->mLock);
326 auto overrides = overrideService->mOverrides.Lookup(aHost);
327 if (!overrides) {
328 return false;
330 nsCString* cname = nullptr;
331 if (aFlags & nsIDNSService::RESOLVE_CANONICAL_NAME) {
332 cname = overrideService->mCnames.Lookup(aHost).DataPtrOrNull();
335 RefPtr<AddrInfo> ai;
337 nsTArray<NetAddr> addresses;
338 for (const auto& ip : *overrides) {
339 if (aAddressFamily != AF_UNSPEC && ip.raw.family != aAddressFamily) {
340 continue;
342 addresses.AppendElement(ip);
345 if (!cname) {
346 ai = new AddrInfo(aHost, DNSResolverType::Native, 0, std::move(addresses));
347 } else {
348 ai = new AddrInfo(aHost, *cname, DNSResolverType::Native, 0,
349 std::move(addresses));
352 ai.forget(aAddrInfo);
353 return true;
356 nsresult GetAddrInfo(const nsACString& aHost, uint16_t aAddressFamily,
357 nsIDNSService::DNSFlags aFlags, AddrInfo** aAddrInfo,
358 bool aGetTtl) {
359 if (NS_WARN_IF(aHost.IsEmpty()) || NS_WARN_IF(!aAddrInfo)) {
360 return NS_ERROR_NULL_POINTER;
362 *aAddrInfo = nullptr;
364 if (StaticPrefs::network_dns_disabled()) {
365 return NS_ERROR_UNKNOWN_HOST;
368 #ifdef DNSQUERY_AVAILABLE
369 // The GetTTLData needs the canonical name to function properly
370 if (aGetTtl) {
371 aFlags |= nsIDNSService::RESOLVE_CANONICAL_NAME;
373 #endif
375 // If there is an override for this host, then we synthetize a result.
376 if (gOverrideService &&
377 FindAddrOverride(aHost, aAddressFamily, aFlags, aAddrInfo)) {
378 LOG("Returning IP address from NativeDNSResolverOverride");
379 return (*aAddrInfo)->Addresses().Length() ? NS_OK : NS_ERROR_UNKNOWN_HOST;
382 nsAutoCString host;
383 if (StaticPrefs::network_dns_copy_string_before_call()) {
384 host = Substring(aHost.BeginReading(), aHost.Length());
385 MOZ_ASSERT(aHost.BeginReading() != host.BeginReading());
386 } else {
387 host = aHost;
390 if (gNativeIsLocalhost) {
391 // pretend we use the given host but use IPv4 localhost instead!
392 host = "localhost"_ns;
393 aAddressFamily = PR_AF_INET;
396 RefPtr<AddrInfo> info;
397 nsresult rv =
398 _GetAddrInfo_Portable(host, aAddressFamily, aFlags, getter_AddRefs(info));
400 #ifdef DNSQUERY_AVAILABLE
401 if (aGetTtl && NS_SUCCEEDED(rv)) {
402 // Figure out the canonical name, or if that fails, just use the host name
403 // we have.
404 nsAutoCString name;
405 if (info && !info->CanonicalHostname().IsEmpty()) {
406 name = info->CanonicalHostname();
407 } else {
408 name = host;
411 LOG("Getting TTL for %s (cname = %s).", host.get(), name.get());
412 uint32_t ttl = 0;
413 nsresult ttlRv = _GetTTLData_Windows(name, &ttl, aAddressFamily);
414 if (NS_SUCCEEDED(ttlRv)) {
415 auto builder = info->Build();
416 builder.SetTTL(ttl);
417 info = builder.Finish();
418 LOG("Got TTL %u for %s (name = %s).", ttl, host.get(), name.get());
419 } else {
420 LOG_WARNING("Could not get TTL for %s (cname = %s).", host.get(),
421 name.get());
424 #endif
426 info.forget(aAddrInfo);
427 return rv;
430 bool FindHTTPSRecordOverride(const nsACString& aHost,
431 TypeRecordResultType& aResult) {
432 LOG("FindHTTPSRecordOverride aHost=%s", nsCString(aHost).get());
433 RefPtr<NativeDNSResolverOverride> overrideService = gOverrideService;
434 if (!overrideService) {
435 return false;
438 AutoReadLock lock(overrideService->mLock);
439 auto overrides = overrideService->mHTTPSRecordOverrides.Lookup(aHost);
440 if (!overrides) {
441 return false;
444 DNSPacket packet;
445 nsAutoCString host(aHost);
447 LOG("resolving %s\n", host.get());
448 // Perform the query
449 nsresult rv = packet.FillBuffer(
450 [&](unsigned char response[DNSPacket::MAX_SIZE]) -> int {
451 if (overrides->Length() > DNSPacket::MAX_SIZE) {
452 return -1;
454 memcpy(response, overrides->Elements(), overrides->Length());
455 return overrides->Length();
457 if (NS_FAILED(rv)) {
458 return false;
461 uint32_t ttl = 0;
462 rv = ParseHTTPSRecord(host, packet, aResult, ttl);
464 return NS_SUCCEEDED(rv);
467 nsresult ParseHTTPSRecord(nsCString& aHost, DNSPacket& aDNSPacket,
468 TypeRecordResultType& aResult, uint32_t& aTTL) {
469 nsAutoCString cname;
470 nsresult rv;
472 aDNSPacket.SetNativePacket(true);
474 int32_t loopCount = 64;
475 while (loopCount > 0 && aResult.is<Nothing>()) {
476 loopCount--;
477 DOHresp resp;
478 nsClassHashtable<nsCStringHashKey, DOHresp> additionalRecords;
479 rv = aDNSPacket.Decode(aHost, TRRTYPE_HTTPSSVC, cname, true, resp, aResult,
480 additionalRecords, aTTL);
481 if (NS_FAILED(rv)) {
482 LOG("Decode failed %x", static_cast<uint32_t>(rv));
483 return rv;
485 if (!cname.IsEmpty() && aResult.is<Nothing>()) {
486 aHost = cname;
487 cname.Truncate();
488 continue;
492 if (aResult.is<Nothing>()) {
493 LOG("Result is nothing");
494 // The call succeeded, but no HTTPS records were found.
495 return NS_ERROR_UNKNOWN_HOST;
498 return NS_OK;
501 nsresult ResolveHTTPSRecord(const nsACString& aHost,
502 nsIDNSService::DNSFlags aFlags,
503 TypeRecordResultType& aResult, uint32_t& aTTL) {
504 if (gOverrideService) {
505 return FindHTTPSRecordOverride(aHost, aResult) ? NS_OK
506 : NS_ERROR_UNKNOWN_HOST;
509 return ResolveHTTPSRecordImpl(aHost, aFlags, aResult, aTTL);
512 nsresult CreateAndResolveMockHTTPSRecord(const nsACString& aHost,
513 nsIDNSService::DNSFlags aFlags,
514 TypeRecordResultType& aResult,
515 uint32_t& aTTL) {
516 nsCString buffer;
517 buffer += '\0';
518 buffer += '\0'; // 16 bit id
519 buffer += 0x80;
520 buffer += '\0'; // Flags
521 buffer += '\0';
522 buffer += '\0'; // Question count
523 buffer += '\0';
524 buffer += 0x1; // Answer count
525 buffer += '\0';
526 buffer += '\0';
527 buffer += '\0';
528 buffer += '\0';
530 nsresult rv = DNSPacket::EncodeHost(buffer, aHost);
531 if (NS_FAILED(rv)) {
532 return rv;
535 buffer += '\0';
536 buffer += 0x41; // TYPE 65
538 buffer += '\0';
539 buffer += 0x1; // Class
541 buffer += '\0';
542 buffer += '\0';
543 buffer += '\0';
544 buffer += 0xFF; // TTL
545 buffer += '\0';
546 buffer += 0x03; // RDLENGTH
547 buffer += '\0';
548 buffer += 0x01; // SvcPriority
549 buffer += '\0';
551 DNSPacket packet;
552 nsAutoCString host(aHost);
554 LOG("resolving %s\n", host.get());
555 // Perform the query
556 rv = packet.FillBuffer(
557 [&](unsigned char response[DNSPacket::MAX_SIZE]) -> int {
558 if (buffer.Length() > DNSPacket::MAX_SIZE) {
559 return -1;
561 memcpy(response, buffer.BeginReading(), buffer.Length());
562 return buffer.Length();
564 if (NS_FAILED(rv)) {
565 return rv;
568 return ParseHTTPSRecord(host, packet, aResult, aTTL);
571 // static
572 already_AddRefed<nsINativeDNSResolverOverride>
573 NativeDNSResolverOverride::GetSingleton() {
574 if (nsIOService::UseSocketProcess() && XRE_IsParentProcess()) {
575 return NativeDNSResolverOverrideParent::GetSingleton();
578 if (gOverrideService) {
579 return do_AddRef(gOverrideService);
582 gOverrideService = new NativeDNSResolverOverride();
583 ClearOnShutdown(&gOverrideService);
584 return do_AddRef(gOverrideService);
587 NS_IMPL_ISUPPORTS(NativeDNSResolverOverride, nsINativeDNSResolverOverride)
589 NS_IMETHODIMP NativeDNSResolverOverride::AddIPOverride(
590 const nsACString& aHost, const nsACString& aIPLiteral) {
591 NetAddr tempAddr;
593 if (aIPLiteral.Equals("N/A"_ns)) {
594 AutoWriteLock lock(mLock);
595 auto& overrides = mOverrides.LookupOrInsert(aHost);
596 overrides.Clear();
597 return NS_OK;
600 if (NS_FAILED(tempAddr.InitFromString(aIPLiteral))) {
601 return NS_ERROR_UNEXPECTED;
604 AutoWriteLock lock(mLock);
605 auto& overrides = mOverrides.LookupOrInsert(aHost);
606 overrides.AppendElement(tempAddr);
608 return NS_OK;
611 NS_IMETHODIMP NativeDNSResolverOverride::AddHTTPSRecordOverride(
612 const nsACString& aHost, const uint8_t* aData, uint32_t aLength) {
613 AutoWriteLock lock(mLock);
614 nsTArray<uint8_t> data(aData, aLength);
615 mHTTPSRecordOverrides.InsertOrUpdate(aHost, std::move(data));
617 return NS_OK;
620 NS_IMETHODIMP NativeDNSResolverOverride::SetCnameOverride(
621 const nsACString& aHost, const nsACString& aCNAME) {
622 if (aCNAME.IsEmpty()) {
623 return NS_ERROR_UNEXPECTED;
626 AutoWriteLock lock(mLock);
627 mCnames.InsertOrUpdate(aHost, nsCString(aCNAME));
629 return NS_OK;
632 NS_IMETHODIMP NativeDNSResolverOverride::ClearHostOverride(
633 const nsACString& aHost) {
634 AutoWriteLock lock(mLock);
635 mCnames.Remove(aHost);
636 auto overrides = mOverrides.Extract(aHost);
637 if (!overrides) {
638 return NS_OK;
641 overrides->Clear();
642 return NS_OK;
645 NS_IMETHODIMP NativeDNSResolverOverride::ClearOverrides() {
646 AutoWriteLock lock(mLock);
647 mOverrides.Clear();
648 mCnames.Clear();
649 return NS_OK;
652 #ifdef MOZ_NO_HTTPS_IMPL
654 // If there is no platform specific implementation of ResolveHTTPSRecordImpl
655 // we link a dummy implementation here.
656 // Otherwise this is implemented in PlatformDNSWin/Linux/etc
657 nsresult ResolveHTTPSRecordImpl(const nsACString& aHost,
658 nsIDNSService::DNSFlags aFlags,
659 TypeRecordResultType& aResult, uint32_t& aTTL) {
660 return NS_ERROR_NOT_IMPLEMENTED;
663 void DNSThreadShutdown() {}
665 #endif // MOZ_NO_HTTPS_IMPL
667 } // namespace mozilla::net