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/NetwerkMetrics.h"
9 #include "mozilla/net/DNSPacket.h"
10 #include "nsIDNSService.h"
11 #include "mozilla/StaticPrefs_network.h"
12 #include "mozilla/ThreadLocal.h"
16 #include <arpa/inet.h>
18 namespace mozilla::net
{
20 #define LOG(msg, ...) \
21 MOZ_LOG(gGetAddrInfoLog, LogLevel::Debug, ("[DNS]: " msg, ##__VA_ARGS__))
25 TypeRecordResultType
* mResult
;
30 // Callback for DNSServiceQueryRecord
31 void QueryCallback(DNSServiceRef aSDRef
, DNSServiceFlags aFlags
,
32 uint32_t aInterfaceIndex
, DNSServiceErrorType aErrorCode
,
33 const char* aFullname
, uint16_t aRRType
, uint16_t aRRClass
,
34 uint16_t aRDLen
, const void* aRdata
, uint32_t aTtl
,
36 struct DNSContext
* context
= (struct DNSContext
*)aContext
;
38 LOG("DNS response name: %s type: %u rdlen %u class %u ttl %u", aFullname
,
39 aRRType
, aRDLen
, aRRClass
, aTtl
);
41 if (aErrorCode
!= kDNSServiceErr_NoError
) {
42 LOG("Error resolving record: %d\n", aErrorCode
);
43 context
->mRv
= NS_ERROR_UNKNOWN_HOST
;
47 if (NS_FAILED(context
->mRv
)) {
48 LOG("Parsing already failed for a previous record");
52 // Process the rdata for HTTPS records (type 65)
53 if (aRRType
!= TRRTYPE_HTTPSSVC
|| aRDLen
== 0) {
54 context
->mRv
= NS_ERROR_UNKNOWN_HOST
;
58 nsDependentCString
fullname(aFullname
);
59 if (fullname
.Length() && fullname
.Last() == '.') {
60 // The fullname argument is always FQDN
61 fullname
.Rebind(aFullname
, fullname
.Length() - 1);
65 nsresult rv
= DNSPacket::ParseHTTPS(
66 aRDLen
, parsed
, 0, (const unsigned char*)aRdata
, aRDLen
, fullname
);
68 LOG("ParseHTTPS failed\n");
73 if (parsed
.mSvcDomainName
.IsEmpty() && parsed
.mSvcFieldPriority
== 0) {
74 // For AliasMode SVCB RRs, a TargetName of "." indicates that the
75 // service is not available or does not exist.
79 if (parsed
.mSvcFieldPriority
== 0) {
80 // Alias form SvcDomainName must not have the "." value (empty)
81 if (parsed
.mSvcDomainName
.IsEmpty()) {
82 context
->mRv
= NS_ERROR_UNEXPECTED
;
85 LOG("alias mode %s -> %s", context
->mHost
.get(),
86 parsed
.mSvcDomainName
.get());
87 context
->mHost
= parsed
.mSvcDomainName
;
88 ToLowerCase(context
->mHost
);
92 if (!context
->mResult
->is
<TypeRecordHTTPSSVC
>()) {
93 *context
->mResult
= mozilla::AsVariant(CopyableTArray
<SVCB
>());
95 auto& results
= context
->mResult
->as
<TypeRecordHTTPSSVC
>();
96 results
.AppendElement(parsed
);
97 *context
->mTTL
= std::min
<uint32_t>(*context
->mTTL
, aTtl
);
100 nsresult
ResolveHTTPSRecordImpl(const nsACString
& aHost
,
101 nsIDNSService::DNSFlags aFlags
,
102 TypeRecordResultType
& aResult
, uint32_t& aTTL
) {
103 nsAutoCString
host(aHost
);
106 if (xpc::IsInAutomation() &&
107 !StaticPrefs::network_dns_native_https_query_in_automation()) {
108 return NS_ERROR_UNKNOWN_HOST
;
111 LOG("resolving %s\n", host
.get());
112 TimeStamp startTime
= TimeStamp::Now();
114 struct DNSContext context
{
121 DNSServiceErrorType err
;
123 err
= DNSServiceQueryRecord(&sdRef
,
126 host
.get(), TRRTYPE_HTTPSSVC
, kDNSServiceClass_IN
,
127 QueryCallback
, &context
);
129 if (err
!= kDNSServiceErr_NoError
) {
130 LOG("DNSServiceQueryRecord failed: %d\n", err
);
131 return NS_ERROR_UNKNOWN_HOST
;
134 int fd
= DNSServiceRefSockFD(sdRef
);
137 FD_SET(fd
, &readfds
);
139 int result
= select(fd
+ 1, &readfds
, NULL
, NULL
, NULL
);
140 if (result
> 0 && FD_ISSET(fd
, &readfds
)) {
141 // Process the result
142 DNSServiceProcessResult(sdRef
);
143 } else if (result
< 0) {
144 LOG("select() failed");
148 DNSServiceRefDeallocate(sdRef
);
149 mozilla::glean::networking::dns_native_https_call_time
.AccumulateRawDuration(
150 TimeStamp::Now() - startTime
);
152 LOG("resolving %s done %x ttl=%u", host
.get(), context
.mRv
, aTTL
);
153 if (NS_FAILED(context
.mRv
)) {
156 if (aResult
.is
<Nothing
>()) {
157 // The call succeeded, but no HTTPS records were found.
158 return NS_ERROR_UNKNOWN_HOST
;
160 if (aTTL
== UINT32_MAX
) {
161 aTTL
= 60; // Defaults to 60 seconds
166 void DNSThreadShutdown() {}
168 } // namespace mozilla::net