Files
sousa-gecko/netwerk/dns/PlatformDNSAndroid.cpp

129 lines
4.2 KiB
C++

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <android/multinetwork.h>
#include <netinet/in.h>
#include <poll.h>
#include <resolv.h>
#include "GetAddrInfo.h"
#include "mozilla/Atomics.h"
#include "mozilla/StaticPrefs_network.h"
#include "mozilla/glean/NetwerkMetrics.h"
#include "mozilla/net/DNSPacket.h"
#include "nsIDNSService.h"
namespace mozilla::net {
// The first call to ResolveHTTPSRecordImpl will load the library
// and function pointers.
static Atomic<bool> sLibLoading{false};
// https://developer.android.com/ndk/reference/group/networking#android_res_nquery
// The function android_res_nquery is defined in <android/multinetwork.h>
typedef int (*android_res_nquery_ptr)(net_handle_t network, const char* dname,
int ns_class, int ns_type,
uint32_t flags);
static Atomic<android_res_nquery_ptr> sAndroidResNQuery;
// https://developer.android.com/ndk/reference/group/networking#android_res_nresult
// The function android_res_nresult is defined in <android/multinetwork.h>
typedef int (*android_res_nresult_ptr)(int fd, int* rcode, uint8_t* answer,
size_t anslen);
static Atomic<android_res_nresult_ptr> sAndroidResNResult;
#define LOG(msg, ...) \
MOZ_LOG(gGetAddrInfoLog, LogLevel::Debug, ("[DNS]: " msg, ##__VA_ARGS__))
nsresult ResolveHTTPSRecordImpl(const nsACString& aHost,
nsIDNSService::DNSFlags aFlags,
TypeRecordResultType& aResult, uint32_t& aTTL,
HTTPSAliasTarget& aAlias) {
DNSPacket packet;
nsAutoCString host(aHost);
nsresult rv;
if (xpc::IsInAutomation() &&
!StaticPrefs::network_dns_native_https_query_in_automation()) {
return NS_ERROR_UNKNOWN_HOST;
}
if (!sLibLoading.exchange(true)) {
// We're the first call here, load the library and symbols.
if (__builtin_available(android 29, *)) {
sAndroidResNQuery = android_res_nquery; // API 29
sAndroidResNResult = android_res_nresult; // API 29
} else {
LOG("No android_res_nquery symbol");
}
}
if (!sAndroidResNQuery || !sAndroidResNResult) {
LOG("nquery not loaded");
// The library hasn't been loaded yet.
return NS_ERROR_UNKNOWN_HOST;
}
LOG("resolving %s\n", host.get());
TimeStamp startTime = TimeStamp::Now();
// Perform the query
rv = packet.FillBuffer(
[&](unsigned char response[DNSPacket::MAX_SIZE]) -> int {
int fd = 0;
auto closeSocket = MakeScopeExit([&] {
if (fd > 0) {
close(fd);
}
});
uint32_t flags = 0;
if (aFlags & nsIDNSService::RESOLVE_BYPASS_CACHE) {
flags = ANDROID_RESOLV_NO_CACHE_LOOKUP;
}
fd = sAndroidResNQuery(0, host.get(), ns_c_in,
nsIDNSService::RESOLVE_TYPE_HTTPSSVC, flags);
if (fd < 0) {
LOG("DNS query failed");
return fd;
}
struct pollfd fds;
fds.fd = fd;
fds.events = POLLIN; // Wait for read events
// Wait for an event on the file descriptor
int ret = poll(&fds, 1,
StaticPrefs::network_dns_native_https_timeout_android());
if (ret <= 0) {
LOG("poll failed %d", ret);
return -1;
}
// android_res_nresult reads the DNS answer and closes the fd, so
// disarm the scope exit to avoid closing it a second time.
int rcode = 0;
int len =
sAndroidResNResult(fd, &rcode, response, DNSPacket::MAX_SIZE - 1);
fd = -1;
if (len < 0) {
LOG("android_res_nresult failed %d", len);
return len;
}
return len;
});
mozilla::glean::networking::dns_native_https_call_time.AccumulateRawDuration(
TimeStamp::Now() - startTime);
if (NS_FAILED(rv)) {
LOG("failed rv");
return rv;
}
return ParseHTTPSRecord(host, packet, aResult, aTTL, aAlias);
}
void DNSThreadShutdown() {}
} // namespace mozilla::net