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/Atomics.h"
13 #include "mozilla/StaticPrefs_network.h"
18 #include <netinet/in.h>
22 #include <android/multinetwork.h>
24 namespace mozilla::net
{
26 // The first call to ResolveHTTPSRecordImpl will load the library
27 // and function pointers.
28 static Atomic
<bool> sLibLoading
{false};
30 // https://developer.android.com/ndk/reference/group/networking#android_res_nquery
31 // The function android_res_nquery is defined in <android/multinetwork.h>
32 typedef int (*android_res_nquery_ptr
)(net_handle_t network
, const char* dname
,
33 int ns_class
, int ns_type
,
35 static Atomic
<android_res_nquery_ptr
> sAndroidResNQuery
;
37 #define LOG(msg, ...) \
38 MOZ_LOG(gGetAddrInfoLog, LogLevel::Debug, ("[DNS]: " msg, ##__VA_ARGS__))
40 nsresult
ResolveHTTPSRecordImpl(const nsACString
& aHost
, uint16_t aFlags
,
41 TypeRecordResultType
& aResult
, uint32_t& aTTL
) {
43 nsAutoCString
host(aHost
);
47 if (xpc::IsInAutomation() &&
48 !StaticPrefs::network_dns_native_https_query_in_automation()) {
49 return NS_ERROR_UNKNOWN_HOST
;
52 if (!sLibLoading
.exchange(true)) {
53 // We're the first call here, load the library and symbols.
54 void* handle
= dlopen("libandroid.so", RTLD_LAZY
| RTLD_LOCAL
);
56 LOG("Error loading libandroid_net %s", dlerror());
57 return NS_ERROR_UNKNOWN_HOST
;
60 auto x
= dlsym(handle
, "android_res_nquery");
62 LOG("No android_res_nquery symbol");
65 sAndroidResNQuery
= (android_res_nquery_ptr
)x
;
68 if (!sAndroidResNQuery
) {
69 LOG("nquery not loaded");
70 // The library hasn't been loaded yet.
71 return NS_ERROR_UNKNOWN_HOST
;
74 LOG("resolving %s\n", host
.get());
75 TimeStamp startTime
= TimeStamp::Now();
77 rv
= packet
.FillBuffer(
78 [&](unsigned char response
[DNSPacket::MAX_SIZE
]) -> int {
80 auto closeSocket
= MakeScopeExit([&] {
86 if (aFlags
& nsIDNSService::RESOLVE_BYPASS_CACHE
) {
87 flags
= ANDROID_RESOLV_NO_CACHE_LOOKUP
;
89 fd
= sAndroidResNQuery(0, host
.get(), ns_c_in
,
90 nsIDNSService::RESOLVE_TYPE_HTTPSSVC
, flags
);
93 LOG("DNS query failed");
99 fds
.events
= POLLIN
; // Wait for read events
101 // Wait for an event on the file descriptor
102 int ret
= poll(&fds
, 1,
103 StaticPrefs::network_dns_native_https_timeout_android());
105 LOG("poll failed %d", ret
);
109 ssize_t len
= recv(fd
, response
, DNSPacket::MAX_SIZE
- 1, 0);
111 LOG("size too small %zd", len
);
112 return len
< 0 ? len
: -1;
115 // The first 8 bytes are UDP header.
116 // XXX: we should consider avoiding this move somehow.
117 for (int i
= 0; i
< len
- 8; i
++) {
118 response
[i
] = response
[i
+ 8];
123 mozilla::glean::networking::dns_native_https_call_time
.AccumulateRawDuration(
124 TimeStamp::Now() - startTime
);
129 packet
.SetNativePacket(true);
131 int32_t loopCount
= 64;
132 while (loopCount
> 0 && aResult
.is
<Nothing
>()) {
135 nsClassHashtable
<nsCStringHashKey
, DOHresp
> additionalRecords
;
136 rv
= packet
.Decode(host
, TRRTYPE_HTTPSSVC
, cname
, true, resp
, aResult
,
137 additionalRecords
, aTTL
);
139 LOG("Decode failed %x", static_cast<uint32_t>(rv
));
142 if (!cname
.IsEmpty() && aResult
.is
<Nothing
>()) {
149 if (aResult
.is
<Nothing
>()) {
150 LOG("Result is nothing");
151 // The call succeeded, but no HTTPS records were found.
152 return NS_ERROR_UNKNOWN_HOST
;
158 void DNSThreadShutdown() {}
160 } // namespace mozilla::net