Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / netwerk / dns / PlatformDNSMac.cpp
blob65628d6143f57815fad500349c5f8a00a9300b49
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"
14 #include <dns_sd.h>
15 #include <unistd.h>
16 #include <arpa/inet.h>
18 namespace mozilla::net {
20 #define LOG(msg, ...) \
21 MOZ_LOG(gGetAddrInfoLog, LogLevel::Debug, ("[DNS]: " msg, ##__VA_ARGS__))
23 struct DNSContext {
24 nsresult mRv = NS_OK;
25 TypeRecordResultType* mResult;
26 nsCString mHost;
27 uint32_t* mTTL;
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,
35 void* aContext) {
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;
44 return;
47 if (NS_FAILED(context->mRv)) {
48 LOG("Parsing already failed for a previous record");
49 return;
52 // Process the rdata for HTTPS records (type 65)
53 if (aRRType != TRRTYPE_HTTPSSVC || aRDLen == 0) {
54 context->mRv = NS_ERROR_UNKNOWN_HOST;
55 return;
58 nsDependentCString fullname(aFullname);
59 if (fullname.Length() && fullname.Last() == '.') {
60 // The fullname argument is always FQDN
61 fullname.Rebind(aFullname, fullname.Length() - 1);
64 struct SVCB parsed;
65 nsresult rv = DNSPacket::ParseHTTPS(
66 aRDLen, parsed, 0, (const unsigned char*)aRdata, aRDLen, fullname);
67 if (NS_FAILED(rv)) {
68 LOG("ParseHTTPS failed\n");
69 context->mRv = rv;
70 return;
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.
76 return;
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;
83 return;
85 LOG("alias mode %s -> %s", context->mHost.get(),
86 parsed.mSvcDomainName.get());
87 context->mHost = parsed.mSvcDomainName;
88 ToLowerCase(context->mHost);
89 return;
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);
104 nsAutoCString cname;
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{
115 .mResult = &aResult,
116 .mHost = host,
117 .mTTL = &aTTL,
120 DNSServiceRef sdRef;
121 DNSServiceErrorType err;
123 err = DNSServiceQueryRecord(&sdRef,
124 0, // No flags
125 0, // All interfaces
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);
135 fd_set readfds;
136 FD_ZERO(&readfds);
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");
147 // Cleanup
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)) {
154 return 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
163 return NS_OK;
166 void DNSThreadShutdown() {}
168 } // namespace mozilla::net