Bug 1869043 allow a device to be specified with MediaTrackGraph::NotifyWhenDeviceStar...
[gecko.git] / netwerk / dns / PlatformDNSWin.cpp
blob94dfb83594c5763ecda91b07b0197709b99f07e3
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/net/DNSPacket.h"
9 #include "nsIDNSService.h"
10 #include "mozilla/Maybe.h"
11 #include "mozilla/ScopeExit.h"
13 #ifdef DNSQUERY_AVAILABLE
14 // There is a bug in windns.h where the type of parameter ppQueryResultsSet for
15 // DnsQuery_A is dependent on UNICODE being set. It should *always* be
16 // PDNS_RECORDA, but if UNICODE is set it is PDNS_RECORDW. To get around this
17 // we make sure that UNICODE is unset.
18 # undef UNICODE
19 # include <ws2tcpip.h>
20 # undef GetAddrInfo
21 # include <windns.h>
22 #endif // DNSQUERY_AVAILABLE
24 namespace mozilla::net {
26 #define LOG(msg, ...) \
27 MOZ_LOG(gGetAddrInfoLog, LogLevel::Debug, ("[DNS]: " msg, ##__VA_ARGS__))
29 nsresult ResolveHTTPSRecordImpl(const nsACString& aHost, uint16_t aFlags,
30 TypeRecordResultType& aResult, uint32_t& aTTL) {
31 nsAutoCString host(aHost);
32 PDNS_RECORD result = nullptr;
33 nsAutoCString cname;
34 aTTL = UINT32_MAX;
36 DNS_STATUS status =
37 DnsQuery_A(host.get(), nsIDNSService::RESOLVE_TYPE_HTTPSSVC,
38 DNS_QUERY_STANDARD, nullptr, &result, nullptr);
39 if (status != ERROR_SUCCESS) {
40 LOG("DnsQuery_A failed with error: %ld\n", status);
41 return NS_ERROR_UNKNOWN_HOST;
44 // This will free the record if we exit early from this function.
45 auto freeDnsRecord =
46 MakeScopeExit([&]() { DnsRecordListFree(result, DnsFreeRecordList); });
48 auto CheckRecords = [&aResult, &cname, &aTTL](
49 PDNS_RECORD result,
50 const nsCString& aHost) -> nsresult {
51 PDNS_RECORD current = result;
53 for (current = result; current; current = current->pNext) {
54 if (strcmp(current->pName, aHost.get()) != 0) {
55 continue;
57 if (current->wType == nsIDNSService::RESOLVE_TYPE_HTTPSSVC) {
58 const unsigned char* ptr = (const unsigned char*)&(current->Data);
59 struct SVCB parsed;
60 nsresult rv = DNSPacket::ParseHTTPS(current->wDataLength, parsed, 0,
61 ptr, current->wDataLength, aHost);
62 if (NS_FAILED(rv)) {
63 return rv;
66 if (parsed.mSvcDomainName.IsEmpty() && parsed.mSvcFieldPriority == 0) {
67 // For AliasMode SVCB RRs, a TargetName of "." indicates that the
68 // service is not available or does not exist.
69 continue;
72 if (parsed.mSvcFieldPriority == 0) {
73 // Alias form SvcDomainName must not have the "." value (empty)
74 if (parsed.mSvcDomainName.IsEmpty()) {
75 return NS_ERROR_UNEXPECTED;
77 cname = parsed.mSvcDomainName;
78 ToLowerCase(cname);
79 break;
82 if (!aResult.is<TypeRecordHTTPSSVC>()) {
83 aResult = mozilla::AsVariant(CopyableTArray<SVCB>());
85 auto& results = aResult.as<TypeRecordHTTPSSVC>();
86 results.AppendElement(parsed);
87 aTTL = std::min<uint32_t>(aTTL, current->dwTtl);
88 } else if (current->wType == DNS_TYPE_CNAME) {
89 cname = current->Data.Cname.pNameHost;
90 ToLowerCase(cname);
91 aTTL = std::min<uint32_t>(aTTL, current->dwTtl);
92 break;
95 return NS_OK;
98 int32_t loopCount = 64;
99 while (loopCount > 0 && aResult.is<Nothing>()) {
100 loopCount--;
102 nsresult rv = CheckRecords(result, host);
103 if (NS_FAILED(rv)) {
104 return rv;
107 if (aResult.is<Nothing>() && !cname.IsEmpty()) {
108 host = cname;
109 cname.Truncate();
110 continue;
113 if (aResult.is<Nothing>()) {
114 return NS_ERROR_UNKNOWN_HOST;
118 // CNAME loop
119 if (loopCount == 0) {
120 return NS_ERROR_UNKNOWN_HOST;
123 if (aResult.is<Nothing>()) {
124 // The call succeeded, but no HTTPS records were found.
125 return NS_ERROR_UNKNOWN_HOST;
128 if (aTTL == UINT32_MAX) {
129 aTTL = 60; // Defaults to 60 seconds
131 return NS_OK;
134 } // namespace mozilla::net