Bug 1890277: part 4) Add CSPParser support for the `trusted-types` directive, guarded...
[gecko.git] / netwerk / dns / PlatformDNSWin.cpp
blob93e936f4dcd66b6e38e4469b03773b868ed3c5f9
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=4 sw=2 sts=2 et cin: */
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"
8 #include "mozilla/glean/GleanMetrics.h"
9 #include "mozilla/net/DNSPacket.h"
10 #include "nsIDNSService.h"
11 #include "mozilla/Maybe.h"
12 #include "mozilla/ScopeExit.h"
13 #include "mozilla/StaticPrefs_network.h"
15 #ifdef DNSQUERY_AVAILABLE
16 // There is a bug in windns.h where the type of parameter ppQueryResultsSet for
17 // DnsQuery_A is dependent on UNICODE being set. It should *always* be
18 // PDNS_RECORDA, but if UNICODE is set it is PDNS_RECORDW. To get around this
19 // we make sure that UNICODE is unset.
20 # undef UNICODE
21 # include <ws2tcpip.h>
22 # undef GetAddrInfo
23 # include <windns.h>
24 #endif // DNSQUERY_AVAILABLE
26 namespace mozilla::net {
28 #define LOG(msg, ...) \
29 MOZ_LOG(gGetAddrInfoLog, LogLevel::Debug, ("[DNS]: " msg, ##__VA_ARGS__))
31 nsresult ResolveHTTPSRecordImpl(const nsACString& aHost, uint16_t aFlags,
32 TypeRecordResultType& aResult, uint32_t& aTTL) {
33 nsAutoCString host(aHost);
34 PDNS_RECORD result = nullptr;
35 nsAutoCString cname;
36 aTTL = UINT32_MAX;
38 if (xpc::IsInAutomation() &&
39 !StaticPrefs::network_dns_native_https_query_in_automation()) {
40 return NS_ERROR_UNKNOWN_HOST;
43 TimeStamp startTime = TimeStamp::Now();
45 DNS_STATUS status =
46 DnsQuery_A(host.get(), nsIDNSService::RESOLVE_TYPE_HTTPSSVC,
47 DNS_QUERY_STANDARD, nullptr, &result, nullptr);
49 mozilla::glean::networking::dns_native_https_call_time.AccumulateRawDuration(
50 TimeStamp::Now() - startTime);
52 if (status != ERROR_SUCCESS) {
53 LOG("DnsQuery_A failed with error: %ld\n", status);
54 return NS_ERROR_UNKNOWN_HOST;
57 // This will free the record if we exit early from this function.
58 auto freeDnsRecord =
59 MakeScopeExit([&]() { DnsRecordListFree(result, DnsFreeRecordList); });
61 auto CheckRecords = [&aResult, &cname, &aTTL](
62 PDNS_RECORD result,
63 const nsCString& aHost) -> nsresult {
64 PDNS_RECORD current = result;
66 for (current = result; current; current = current->pNext) {
67 if (strcmp(current->pName, aHost.get()) != 0) {
68 continue;
70 if (current->wType == nsIDNSService::RESOLVE_TYPE_HTTPSSVC) {
71 const unsigned char* ptr = (const unsigned char*)&(current->Data);
72 struct SVCB parsed;
73 nsresult rv = DNSPacket::ParseHTTPS(current->wDataLength, parsed, 0,
74 ptr, current->wDataLength, aHost);
75 if (NS_FAILED(rv)) {
76 return rv;
79 if (parsed.mSvcDomainName.IsEmpty() && parsed.mSvcFieldPriority == 0) {
80 // For AliasMode SVCB RRs, a TargetName of "." indicates that the
81 // service is not available or does not exist.
82 continue;
85 if (parsed.mSvcFieldPriority == 0) {
86 // Alias form SvcDomainName must not have the "." value (empty)
87 if (parsed.mSvcDomainName.IsEmpty()) {
88 return NS_ERROR_UNEXPECTED;
90 cname = parsed.mSvcDomainName;
91 ToLowerCase(cname);
92 break;
95 if (!aResult.is<TypeRecordHTTPSSVC>()) {
96 aResult = mozilla::AsVariant(CopyableTArray<SVCB>());
98 auto& results = aResult.as<TypeRecordHTTPSSVC>();
99 results.AppendElement(parsed);
100 aTTL = std::min<uint32_t>(aTTL, current->dwTtl);
101 } else if (current->wType == DNS_TYPE_CNAME) {
102 cname = current->Data.Cname.pNameHost;
103 ToLowerCase(cname);
104 aTTL = std::min<uint32_t>(aTTL, current->dwTtl);
105 break;
108 return NS_OK;
111 int32_t loopCount = 64;
112 while (loopCount > 0 && aResult.is<Nothing>()) {
113 loopCount--;
115 nsresult rv = CheckRecords(result, host);
116 if (NS_FAILED(rv)) {
117 return rv;
120 if (aResult.is<Nothing>() && !cname.IsEmpty()) {
121 host = cname;
122 cname.Truncate();
123 continue;
126 if (aResult.is<Nothing>()) {
127 return NS_ERROR_UNKNOWN_HOST;
131 // CNAME loop
132 if (loopCount == 0) {
133 return NS_ERROR_UNKNOWN_HOST;
136 if (aResult.is<Nothing>()) {
137 // The call succeeded, but no HTTPS records were found.
138 return NS_ERROR_UNKNOWN_HOST;
141 if (aTTL == UINT32_MAX) {
142 aTTL = 60; // Defaults to 60 seconds
144 return NS_OK;
147 void DNSThreadShutdown() {}
149 } // namespace mozilla::net