forked from mirrors/gecko-dev
Bug 1852900 - Use android_res_nquery from libandroid.so to resolve HTTPS records on Android (API level >= 29) r=necko-reviewers,jesup
Depends on D194515 Differential Revision: https://phabricator.services.mozilla.com/D196068
This commit is contained in:
parent
30640603d5
commit
eb73825495
5 changed files with 168 additions and 3 deletions
|
|
@ -11912,6 +11912,13 @@
|
|||
value: false
|
||||
mirror: always
|
||||
|
||||
# When resolving a native HTTPS query with native APIs
|
||||
# the Android implementation has a max timeout
|
||||
- name: network.dns.native_https_timeout_android
|
||||
type: RelaxedAtomicInt32
|
||||
value: 20000
|
||||
mirror: always
|
||||
|
||||
# When this pref is true, we copy the host name to a fresh string before
|
||||
# calling into getaddrinfo.
|
||||
- name: network.dns.copy_string_before_call
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ nsresult DNSPacket::FillBuffer(
|
|||
std::function<int(unsigned char response[MAX_SIZE])>&& aPredicate) {
|
||||
int response_length = aPredicate(mResponse);
|
||||
if (response_length < 0) {
|
||||
LOG(("FillBuffer response len < 0"));
|
||||
mBodySize = 0;
|
||||
mStatus = NS_ERROR_UNEXPECTED;
|
||||
return mStatus;
|
||||
|
|
|
|||
149
netwerk/dns/PlatformDNSAndroid.cpp
Normal file
149
netwerk/dns/PlatformDNSAndroid.cpp
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=4 sw=2 sts=2 et cin: */
|
||||
/* 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 "GetAddrInfo.h"
|
||||
#include "mozilla/net/DNSPacket.h"
|
||||
#include "nsIDNSService.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/StaticPrefs_network.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
#include <resolv.h>
|
||||
#include <poll.h>
|
||||
#include <dlfcn.h>
|
||||
#include <android/multinetwork.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;
|
||||
|
||||
#define LOG(msg, ...) \
|
||||
MOZ_LOG(gGetAddrInfoLog, LogLevel::Debug, ("[DNS]: " msg, ##__VA_ARGS__))
|
||||
|
||||
nsresult ResolveHTTPSRecordImpl(const nsACString& aHost, uint16_t aFlags,
|
||||
TypeRecordResultType& aResult, uint32_t& aTTL) {
|
||||
DNSPacket packet;
|
||||
nsAutoCString host(aHost);
|
||||
nsAutoCString cname;
|
||||
nsresult rv;
|
||||
|
||||
if (!sLibLoading.exchange(true)) {
|
||||
// We're the first call here, load the library and symbols.
|
||||
void* handle = dlopen("libandroid.so", RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!handle) {
|
||||
LOG("Error loading libandroid_net %s", dlerror());
|
||||
return NS_ERROR_UNKNOWN_HOST;
|
||||
}
|
||||
|
||||
auto x = dlsym(handle, "android_res_nquery");
|
||||
if (!x) {
|
||||
LOG("No android_res_nquery symbol");
|
||||
}
|
||||
|
||||
sAndroidResNQuery = (android_res_nquery_ptr)x;
|
||||
}
|
||||
|
||||
if (!sAndroidResNQuery) {
|
||||
LOG("nquery not loaded");
|
||||
// The library hasn't been loaded yet.
|
||||
return NS_ERROR_UNKNOWN_HOST;
|
||||
}
|
||||
|
||||
LOG("resolving %s\n", host.get());
|
||||
// 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;
|
||||
}
|
||||
|
||||
ssize_t len = recv(fd, response, DNSPacket::MAX_SIZE - 1, 0);
|
||||
if (len <= 8) {
|
||||
LOG("size too small %zd", len);
|
||||
return len < 0 ? len : -1;
|
||||
}
|
||||
|
||||
// The first 8 bytes are UDP header.
|
||||
// XXX: we should consider avoiding this move somehow.
|
||||
for (int i = 0; i < len - 8; i++) {
|
||||
response[i] = response[i + 8];
|
||||
}
|
||||
|
||||
return len - 8;
|
||||
});
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG("failed rv");
|
||||
return rv;
|
||||
}
|
||||
packet.SetNativePacket(true);
|
||||
|
||||
int32_t loopCount = 64;
|
||||
while (loopCount > 0 && aResult.is<Nothing>()) {
|
||||
loopCount--;
|
||||
DOHresp resp;
|
||||
nsClassHashtable<nsCStringHashKey, DOHresp> additionalRecords;
|
||||
rv = packet.Decode(host, TRRTYPE_HTTPSSVC, cname, true, resp, aResult,
|
||||
additionalRecords, aTTL);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG("Decode failed %x", static_cast<uint32_t>(rv));
|
||||
return rv;
|
||||
}
|
||||
if (!cname.IsEmpty() && aResult.is<Nothing>()) {
|
||||
host = cname;
|
||||
cname.Truncate();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (aResult.is<Nothing>()) {
|
||||
LOG("Result is nothing");
|
||||
// The call succeeded, but no HTTPS records were found.
|
||||
return NS_ERROR_UNKNOWN_HOST;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace mozilla::net
|
||||
|
|
@ -64,6 +64,8 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows":
|
|||
elif CONFIG["OS_TARGET"] == "Linux" or CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa":
|
||||
SOURCES += ["PlatformDNSUnix.cpp"]
|
||||
OS_LIBS += ["resolv"]
|
||||
elif CONFIG["MOZ_WIDGET_TOOLKIT"] == "android":
|
||||
SOURCES += ["PlatformDNSAndroid.cpp"]
|
||||
else:
|
||||
DEFINES["MOZ_NO_HTTPS_IMPL"] = 1
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,10 @@
|
|||
# include "mozilla/WindowsVersion.h"
|
||||
#endif // XP_WIN
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
# include "mozilla/jni/Utils.h"
|
||||
#endif
|
||||
|
||||
#define IS_ADDR_TYPE(_type) ((_type) == nsIDNSService::RESOLVE_TYPE_DEFAULT)
|
||||
#define IS_OTHER_TYPE(_type) ((_type) != nsIDNSService::RESOLVE_TYPE_DEFAULT)
|
||||
|
||||
|
|
@ -232,11 +236,13 @@ nsresult nsHostResolver::Init() MOZ_NO_THREAD_SAFETY_ANALYSIS {
|
|||
// It returns a success code, but no records. We only allow
|
||||
// native HTTPS records on Win 11 for now.
|
||||
sNativeHTTPSSupported = mozilla::IsWin11OrLater();
|
||||
#elif defined(XP_LINUX) && !defined(ANDROID)
|
||||
sNativeHTTPSSupported = true;
|
||||
#elif defined(XP_MACOSX)
|
||||
#elif defined(MOZ_WIDGET_ANDROID)
|
||||
// android_res_nquery only got added in API level 29
|
||||
sNativeHTTPSSupported = jni::GetAPIVersion() >= 29;
|
||||
#elif defined(XP_LINUX) || defined(XP_MACOSX)
|
||||
sNativeHTTPSSupported = true;
|
||||
#endif
|
||||
LOG(("Native HTTPS records supported=%d", bool(sNativeHTTPSSupported)));
|
||||
|
||||
nsCOMPtr<nsIThreadPool> threadPool = new nsThreadPool();
|
||||
MOZ_ALWAYS_SUCCEEDS(threadPool->SetThreadLimit(MaxResolverThreads()));
|
||||
|
|
|
|||
Loading…
Reference in a new issue