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.
19 # include <ws2tcpip.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;
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.
46 MakeScopeExit([&]() { DnsRecordListFree(result
, DnsFreeRecordList
); });
48 auto CheckRecords
= [&aResult
, &cname
, &aTTL
](
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) {
57 if (current
->wType
== nsIDNSService::RESOLVE_TYPE_HTTPSSVC
) {
58 const unsigned char* ptr
= (const unsigned char*)&(current
->Data
);
60 nsresult rv
= DNSPacket::ParseHTTPS(current
->wDataLength
, parsed
, 0,
61 ptr
, current
->wDataLength
, aHost
);
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.
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
;
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
;
91 aTTL
= std::min
<uint32_t>(aTTL
, current
->dwTtl
);
98 int32_t loopCount
= 64;
99 while (loopCount
> 0 && aResult
.is
<Nothing
>()) {
102 nsresult rv
= CheckRecords(result
, host
);
107 if (aResult
.is
<Nothing
>() && !cname
.IsEmpty()) {
113 if (aResult
.is
<Nothing
>()) {
114 return NS_ERROR_UNKNOWN_HOST
;
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
134 } // namespace mozilla::net