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/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
,
41 nsIDNSService::DNSFlags aFlags
,
42 TypeRecordResultType
& aResult
, uint32_t& aTTL
) {
44 nsAutoCString
host(aHost
);
48 if (xpc::IsInAutomation() &&
49 !StaticPrefs::network_dns_native_https_query_in_automation()) {
50 return NS_ERROR_UNKNOWN_HOST
;
53 if (!sLibLoading
.exchange(true)) {
54 // We're the first call here, load the library and symbols.
55 void* handle
= dlopen("libandroid.so", RTLD_LAZY
| RTLD_LOCAL
);
57 LOG("Error loading libandroid_net %s", dlerror());
58 return NS_ERROR_UNKNOWN_HOST
;
61 auto x
= dlsym(handle
, "android_res_nquery");
63 LOG("No android_res_nquery symbol");
66 sAndroidResNQuery
= (android_res_nquery_ptr
)x
;
69 if (!sAndroidResNQuery
) {
70 LOG("nquery not loaded");
71 // The library hasn't been loaded yet.
72 return NS_ERROR_UNKNOWN_HOST
;
75 LOG("resolving %s\n", host
.get());
76 TimeStamp startTime
= TimeStamp::Now();
78 rv
= packet
.FillBuffer(
79 [&](unsigned char response
[DNSPacket::MAX_SIZE
]) -> int {
81 auto closeSocket
= MakeScopeExit([&] {
87 if (aFlags
& nsIDNSService::RESOLVE_BYPASS_CACHE
) {
88 flags
= ANDROID_RESOLV_NO_CACHE_LOOKUP
;
90 fd
= sAndroidResNQuery(0, host
.get(), ns_c_in
,
91 nsIDNSService::RESOLVE_TYPE_HTTPSSVC
, flags
);
94 LOG("DNS query failed");
100 fds
.events
= POLLIN
; // Wait for read events
102 // Wait for an event on the file descriptor
103 int ret
= poll(&fds
, 1,
104 StaticPrefs::network_dns_native_https_timeout_android());
106 LOG("poll failed %d", ret
);
110 ssize_t len
= recv(fd
, response
, DNSPacket::MAX_SIZE
- 1, 0);
112 LOG("size too small %zd", len
);
113 return len
< 0 ? len
: -1;
116 // The first 8 bytes are UDP header.
117 // XXX: we should consider avoiding this move somehow.
118 for (int i
= 0; i
< len
- 8; i
++) {
119 response
[i
] = response
[i
+ 8];
124 mozilla::glean::networking::dns_native_https_call_time
.AccumulateRawDuration(
125 TimeStamp::Now() - startTime
);
130 packet
.SetNativePacket(true);
132 int32_t loopCount
= 64;
133 while (loopCount
> 0 && aResult
.is
<Nothing
>()) {
136 nsClassHashtable
<nsCStringHashKey
, DOHresp
> additionalRecords
;
137 rv
= packet
.Decode(host
, TRRTYPE_HTTPSSVC
, cname
, true, resp
, aResult
,
138 additionalRecords
, aTTL
);
140 LOG("Decode failed %x", static_cast<uint32_t>(rv
));
143 if (!cname
.IsEmpty() && aResult
.is
<Nothing
>()) {
150 if (aResult
.is
<Nothing
>()) {
151 LOG("Result is nothing");
152 // The call succeeded, but no HTTPS records were found.
153 return NS_ERROR_UNKNOWN_HOST
;
159 void DNSThreadShutdown() {}
161 } // namespace mozilla::net