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/Atomics.h"
12 #include "mozilla/StaticPrefs_network.h"
17 #include <netinet/in.h>
21 #include <android/multinetwork.h>
23 namespace mozilla::net
{
25 // The first call to ResolveHTTPSRecordImpl will load the library
26 // and function pointers.
27 static Atomic
<bool> sLibLoading
{false};
29 // https://developer.android.com/ndk/reference/group/networking#android_res_nquery
30 // The function android_res_nquery is defined in <android/multinetwork.h>
31 typedef int (*android_res_nquery_ptr
)(net_handle_t network
, const char* dname
,
32 int ns_class
, int ns_type
,
34 static Atomic
<android_res_nquery_ptr
> sAndroidResNQuery
;
36 #define LOG(msg, ...) \
37 MOZ_LOG(gGetAddrInfoLog, LogLevel::Debug, ("[DNS]: " msg, ##__VA_ARGS__))
39 nsresult
ResolveHTTPSRecordImpl(const nsACString
& aHost
, uint16_t aFlags
,
40 TypeRecordResultType
& aResult
, uint32_t& aTTL
) {
42 nsAutoCString
host(aHost
);
46 if (xpc::IsInAutomation() &&
47 !StaticPrefs::network_dns_native_https_query_in_automation()) {
48 return NS_ERROR_UNKNOWN_HOST
;
51 if (!sLibLoading
.exchange(true)) {
52 // We're the first call here, load the library and symbols.
53 void* handle
= dlopen("libandroid.so", RTLD_LAZY
| RTLD_LOCAL
);
55 LOG("Error loading libandroid_net %s", dlerror());
56 return NS_ERROR_UNKNOWN_HOST
;
59 auto x
= dlsym(handle
, "android_res_nquery");
61 LOG("No android_res_nquery symbol");
64 sAndroidResNQuery
= (android_res_nquery_ptr
)x
;
67 if (!sAndroidResNQuery
) {
68 LOG("nquery not loaded");
69 // The library hasn't been loaded yet.
70 return NS_ERROR_UNKNOWN_HOST
;
73 LOG("resolving %s\n", host
.get());
75 rv
= packet
.FillBuffer(
76 [&](unsigned char response
[DNSPacket::MAX_SIZE
]) -> int {
78 auto closeSocket
= MakeScopeExit([&] {
84 if (aFlags
& nsIDNSService::RESOLVE_BYPASS_CACHE
) {
85 flags
= ANDROID_RESOLV_NO_CACHE_LOOKUP
;
87 fd
= sAndroidResNQuery(0, host
.get(), ns_c_in
,
88 nsIDNSService::RESOLVE_TYPE_HTTPSSVC
, flags
);
91 LOG("DNS query failed");
97 fds
.events
= POLLIN
; // Wait for read events
99 // Wait for an event on the file descriptor
100 int ret
= poll(&fds
, 1,
101 StaticPrefs::network_dns_native_https_timeout_android());
103 LOG("poll failed %d", ret
);
107 ssize_t len
= recv(fd
, response
, DNSPacket::MAX_SIZE
- 1, 0);
109 LOG("size too small %zd", len
);
110 return len
< 0 ? len
: -1;
113 // The first 8 bytes are UDP header.
114 // XXX: we should consider avoiding this move somehow.
115 for (int i
= 0; i
< len
- 8; i
++) {
116 response
[i
] = response
[i
+ 8];
125 packet
.SetNativePacket(true);
127 int32_t loopCount
= 64;
128 while (loopCount
> 0 && aResult
.is
<Nothing
>()) {
131 nsClassHashtable
<nsCStringHashKey
, DOHresp
> additionalRecords
;
132 rv
= packet
.Decode(host
, TRRTYPE_HTTPSSVC
, cname
, true, resp
, aResult
,
133 additionalRecords
, aTTL
);
135 LOG("Decode failed %x", static_cast<uint32_t>(rv
));
138 if (!cname
.IsEmpty() && aResult
.is
<Nothing
>()) {
145 if (aResult
.is
<Nothing
>()) {
146 LOG("Result is nothing");
147 // The call succeeded, but no HTTPS records were found.
148 return NS_ERROR_UNKNOWN_HOST
;
154 void DNSThreadShutdown() {}
156 } // namespace mozilla::net