aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-12-15 09:35:39 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-12-15 09:35:39 +0000
commitbefe95e2b78d326d270d3ad7825beda6a1f47d08 (patch)
tree888eee2a961d218d5bc787ea4077697fc8ab300b
parent8be05f6c1eb5c6ddfa50ebde58ec8036f3e74ffe (diff)
parent9c4b2dccac4247418f70e07e37aa02054bded1e9 (diff)
downloadDnsResolver-befe95e2b78d326d270d3ad7825beda6a1f47d08.tar.gz
Snap for 11224086 from 9c4b2dccac4247418f70e07e37aa02054bded1e9 to mainline-tzdata5-release
Change-Id: I4bf41d0cdaa55ab2317dfdf424907a16495a23fa
-rw-r--r--Android.bp91
-rw-r--r--Dns64Configuration.cpp17
-rw-r--r--Dns64Configuration.h4
-rw-r--r--DnsProxyListener.cpp212
-rw-r--r--DnsResolver.cpp1
-rw-r--r--DnsResolver.h2
-rw-r--r--DnsResolverService.cpp14
-rw-r--r--DnsTlsDispatcher.cpp6
-rw-r--r--DnsTlsServer.cpp5
-rw-r--r--DnsTlsServer.h1
-rw-r--r--DnsTlsSocket.cpp12
-rw-r--r--DnsTlsTransport.cpp2
-rw-r--r--Experiments.h3
-rw-r--r--OWNERS3
-rw-r--r--OperationLimiter.h9
-rw-r--r--PrivateDnsConfiguration.cpp8
-rw-r--r--ResolverController.cpp26
-rw-r--r--ResolverController.h6
-rw-r--r--aidl_api/dnsresolver_aidl_interface/12/.hash1
-rw-r--r--aidl_api/dnsresolver_aidl_interface/12/android/net/IDnsResolver.aidl69
-rw-r--r--aidl_api/dnsresolver_aidl_interface/12/android/net/ResolverHostsParcel.aidl24
-rw-r--r--aidl_api/dnsresolver_aidl_interface/12/android/net/ResolverOptionsParcel.aidl25
-rw-r--r--aidl_api/dnsresolver_aidl_interface/12/android/net/ResolverParamsParcel.aidl39
-rw-r--r--aidl_api/dnsresolver_aidl_interface/12/android/net/resolv/aidl/DnsHealthEventParcel.aidl26
-rw-r--r--aidl_api/dnsresolver_aidl_interface/12/android/net/resolv/aidl/IDnsResolverUnsolicitedEventListener.aidl33
-rw-r--r--aidl_api/dnsresolver_aidl_interface/12/android/net/resolv/aidl/Nat64PrefixEventParcel.aidl27
-rw-r--r--aidl_api/dnsresolver_aidl_interface/12/android/net/resolv/aidl/PrivateDnsValidationEventParcel.aidl28
-rw-r--r--aidl_api/dnsresolver_aidl_interface/13/.hash1
-rw-r--r--aidl_api/dnsresolver_aidl_interface/13/android/net/IDnsResolver.aidl69
-rw-r--r--aidl_api/dnsresolver_aidl_interface/13/android/net/ResolverHostsParcel.aidl25
-rw-r--r--aidl_api/dnsresolver_aidl_interface/13/android/net/ResolverOptionsParcel.aidl26
-rw-r--r--aidl_api/dnsresolver_aidl_interface/13/android/net/ResolverParamsParcel.aidl41
-rw-r--r--aidl_api/dnsresolver_aidl_interface/13/android/net/resolv/aidl/DnsHealthEventParcel.aidl26
-rw-r--r--aidl_api/dnsresolver_aidl_interface/13/android/net/resolv/aidl/DohParamsParcel.aidl27
-rw-r--r--aidl_api/dnsresolver_aidl_interface/13/android/net/resolv/aidl/IDnsResolverUnsolicitedEventListener.aidl33
-rw-r--r--aidl_api/dnsresolver_aidl_interface/13/android/net/resolv/aidl/Nat64PrefixEventParcel.aidl27
-rw-r--r--aidl_api/dnsresolver_aidl_interface/13/android/net/resolv/aidl/PrivateDnsValidationEventParcel.aidl28
-rw-r--r--aidl_api/dnsresolver_aidl_interface/current/android/net/IDnsResolver.aidl2
-rw-r--r--aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverHostsParcel.aidl1
-rw-r--r--aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverOptionsParcel.aidl1
-rw-r--r--aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverParamsParcel.aidl3
-rw-r--r--aidl_api/dnsresolver_aidl_interface/current/android/net/resolv/aidl/DohParamsParcel.aidl27
-rw-r--r--binder/android/net/ResolverHostsParcel.aidl1
-rw-r--r--binder/android/net/ResolverOptionsParcel.aidl1
-rw-r--r--binder/android/net/ResolverParamsParcel.aidl13
-rw-r--r--binder/android/net/resolv/aidl/DohParamsParcel.aidl50
-rw-r--r--doh/boot_time.rs16
-rw-r--r--doh/connection/mod.rs2
-rw-r--r--doh/ffi.rs54
-rw-r--r--doh/tests/doh_frontend/src/dns_https_frontend.rs3
-rw-r--r--doh/tests/doh_frontend/src/ffi.rs28
-rw-r--r--getaddrinfo.cpp9
-rw-r--r--res_cache.cpp31
-rw-r--r--res_debug.cpp2
-rw-r--r--res_mkquery.cpp2
-rw-r--r--res_query.cpp2
-rw-r--r--res_send.cpp21
-rw-r--r--resolv_cache.h8
-rw-r--r--sethostent.cpp6
-rw-r--r--stats.proto3
-rw-r--r--tests/Android.bp24
-rw-r--r--tests/dns_metrics_listener/dns_metrics_listener.cpp67
-rw-r--r--tests/dns_metrics_listener/dns_metrics_listener.h9
-rw-r--r--tests/dns_responder/dns_responder.cpp3
-rw-r--r--tests/dns_responder/dns_responder_client_ndk.cpp18
-rw-r--r--tests/dns_responder/dns_responder_client_ndk.h14
-rw-r--r--tests/dnsresolver_binder_test.cpp119
-rw-r--r--tests/doh_ffi_test.cpp2
-rw-r--r--tests/resolv_cache_unit_test.cpp74
-rw-r--r--tests/resolv_integration_test.cpp260
-rw-r--r--tests/resolv_private_dns_test.cpp324
-rw-r--r--tests/resolv_stats_test_utils.cpp3
-rw-r--r--tests/resolv_stats_test_utils.h4
-rw-r--r--tests/resolv_stats_test_utils_test.cpp4
-rw-r--r--tests/resolv_test_utils.cpp4
-rw-r--r--tests/resolv_test_utils.h53
-rw-r--r--tests/resolv_unit_test.cpp4
-rw-r--r--tests/unsolicited_listener/unsolicited_event_listener.cpp64
-rw-r--r--util.h5
79 files changed, 1694 insertions, 644 deletions
diff --git a/Android.bp b/Android.bp
index ef988163..4047527d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -53,7 +53,7 @@ cc_library_headers {
],
}
-dnsresolver_aidl_interface_lateststable_version = "V11"
+dnsresolver_aidl_interface_lateststable_version = "V13"
cc_library_static {
name: "dnsresolver_aidl_interface-lateststable-ndk",
@@ -96,22 +96,67 @@ aidl_interface {
min_sdk_version: "30",
},
},
- versions: [
- "1",
- "2",
- "3",
- "4",
- "5",
- "6",
- "7",
- "8",
- "9",
- "10",
- "11",
- ],
+
dumpapi: {
no_license: true,
},
+ versions_with_info: [
+ {
+ version: "1",
+ imports: ["netd_event_listener_interface-V1"],
+ },
+ {
+ version: "2",
+ imports: ["netd_event_listener_interface-V1"],
+ },
+ {
+ version: "3",
+ imports: ["netd_event_listener_interface-V1"],
+ },
+ {
+ version: "4",
+ imports: ["netd_event_listener_interface-V1"],
+ },
+ {
+ version: "5",
+ imports: ["netd_event_listener_interface-V1"],
+ },
+ {
+ version: "6",
+ imports: ["netd_event_listener_interface-V1"],
+ },
+ {
+ version: "7",
+ imports: ["netd_event_listener_interface-V1"],
+ },
+ {
+ version: "8",
+ imports: ["netd_event_listener_interface-V1"],
+ },
+ {
+ version: "9",
+ imports: ["netd_event_listener_interface-V1"],
+ },
+ {
+ version: "10",
+ imports: ["netd_event_listener_interface-V1"],
+ },
+ {
+ version: "11",
+ imports: ["netd_event_listener_interface-V1"],
+ },
+ {
+ version: "12",
+ imports: ["netd_event_listener_interface-V1"],
+ },
+ {
+ version: "13",
+ imports: ["netd_event_listener_interface-V1"],
+ },
+
+ ],
+ frozen: true,
+
}
cc_defaults {
@@ -154,7 +199,7 @@ cc_defaults {
// after the build process.
host_required: [
"net-tests-utils-host-common",
- ]
+ ],
}
cc_defaults {
@@ -176,7 +221,7 @@ cc_defaults {
// after the build process.
host_required: [
"net-tests-utils-host-common",
- ]
+ ],
}
cc_library {
@@ -229,8 +274,8 @@ cc_library {
"libmodules-utils-build",
"libprotobuf-cpp-lite",
"libstatslog_resolv",
- "libstatspush_compat",
"libsysutils",
+ "libutils",
"netd_event_listener_interface-lateststable-ndk",
"server_configurable_flags",
"stats_proto",
@@ -251,6 +296,9 @@ cc_library {
"libssl",
"libstatssocket",
],
+ runtime_libs: [
+ "libcom.android.tethering.dns_helper",
+ ],
header_libs: [
"libnetdbinder_utils_headers",
],
@@ -292,7 +340,7 @@ genrule {
name: "statslog_resolv.h",
tools: ["stats-log-api-gen"],
cmd: "$(location stats-log-api-gen) --header $(genDir)/statslog_resolv.h --module resolv" +
- " --namespace android,net,stats --minApiLevel 29",
+ " --namespace android,net,stats --minApiLevel 30",
out: [
"statslog_resolv.h",
],
@@ -302,7 +350,7 @@ genrule {
name: "statslog_resolv.cpp",
tools: ["stats-log-api-gen"],
cmd: "$(location stats-log-api-gen) --cpp $(genDir)/statslog_resolv.cpp --module resolv" +
- " --namespace android,net,stats --importHeader statslog_resolv.h --minApiLevel 29",
+ " --namespace android,net,stats --importHeader statslog_resolv.h --minApiLevel 30",
out: [
"statslog_resolv.cpp",
],
@@ -316,10 +364,9 @@ cc_library_static {
export_generated_headers: ["statslog_resolv.h"],
static_libs: [
"libcutils",
- "libstatspush_compat",
],
- header_libs: [
- "libgtest_prod_headers", // Used by libstatspush_compat
+ shared_libs: [
+ "libstatssocket",
],
apex_available: ["com.android.resolv"],
min_sdk_version: "30",
diff --git a/Dns64Configuration.cpp b/Dns64Configuration.cpp
index a1fe8717..fc1428db 100644
--- a/Dns64Configuration.cpp
+++ b/Dns64Configuration.cpp
@@ -24,6 +24,7 @@
#include <netdutils/DumpWriter.h>
#include <netdutils/InternetAddresses.h>
#include <netdutils/ThreadUtil.h>
+#include <utils/StrongPointer.h>
#include <thread>
#include <utility>
@@ -36,6 +37,7 @@
namespace android {
+using android::sp;
using netdutils::DumpWriter;
using netdutils::IPAddress;
using netdutils::IPPrefix;
@@ -61,8 +63,9 @@ void Dns64Configuration::startPrefixDiscovery(unsigned netId) {
// Emplace a copy of |cfg| in the map.
mDns64Configs.emplace(std::make_pair(netId, cfg));
+ const sp<Dns64Configuration> thiz = sp<Dns64Configuration>::fromExisting(this);
// Note that capturing |cfg| in this lambda creates a copy.
- std::thread discovery_thread([this, cfg, netId] {
+ std::thread discovery_thread([thiz, cfg, netId] {
setThreadName(fmt::format("Nat64Pfx_{}", netId));
// Make a mutable copy rather than mark the whole lambda mutable.
@@ -75,28 +78,28 @@ void Dns64Configuration::startPrefixDiscovery(unsigned netId) {
.build();
while (true) {
- if (!this->shouldContinueDiscovery(evalCfg)) break;
+ if (!thiz->shouldContinueDiscovery(evalCfg)) break;
android_net_context netcontext{};
- mGetNetworkContextCallback(evalCfg.netId, 0, &netcontext);
+ thiz->mGetNetworkContextCallback(evalCfg.netId, 0, &netcontext);
// Prefix discovery must bypass private DNS because in strict mode
// the server generally won't know the NAT64 prefix.
netcontext.flags |= NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS;
if (doRfc7050PrefixDiscovery(netcontext, &evalCfg)) {
- this->recordDns64Config(evalCfg);
+ thiz->recordDns64Config(evalCfg);
break;
}
- if (!this->shouldContinueDiscovery(evalCfg)) break;
+ if (!thiz->shouldContinueDiscovery(evalCfg)) break;
if (!backoff.hasNextTimeout()) break;
{
- std::unique_lock<std::mutex> cvGuard(mMutex);
+ std::unique_lock<std::mutex> cvGuard(thiz->mMutex);
// TODO: Consider some chrono math, combined with wait_until()
// perhaps, to prevent early re-resolves from the removal of
// other netids with IPv6-only nameservers.
- mCv.wait_for(cvGuard, backoff.getNextTimeout());
+ thiz->mCv.wait_for(cvGuard, backoff.getNextTimeout());
}
}
});
diff --git a/Dns64Configuration.h b/Dns64Configuration.h
index 387de785..4170e32d 100644
--- a/Dns64Configuration.h
+++ b/Dns64Configuration.h
@@ -20,12 +20,14 @@
#include <netinet/in.h>
#include <condition_variable>
#include <cstdlib>
+#include <functional>
#include <mutex>
#include <unordered_map>
#include <android-base/thread_annotations.h>
#include <netdutils/DumpWriter.h>
#include <netdutils/InternetAddresses.h>
+#include <utils/RefBase.h>
struct android_net_context;
@@ -47,7 +49,7 @@ namespace net {
* Thread-safety: All public methods in this class MUST be thread-safe.
* (In other words: this class handles all its locking privately.)
*/
-class Dns64Configuration {
+class Dns64Configuration : virtual public RefBase {
public:
// Simple data struct for passing back packet NAT64 prefix event information to the
// Dns64PrefixCallback callback.
diff --git a/DnsProxyListener.cpp b/DnsProxyListener.cpp
index 0de74939..e70ddb40 100644
--- a/DnsProxyListener.cpp
+++ b/DnsProxyListener.cpp
@@ -18,6 +18,7 @@
#include <arpa/inet.h>
#include <dirent.h>
+#include <dlfcn.h>
#include <linux/if.h>
#include <math.h>
#include <net/if.h>
@@ -70,20 +71,19 @@ using std::span;
namespace android {
+using netdutils::MAX_QUERIES_IN_TOTAL;
+using netdutils::MAX_QUERIES_PER_UID;
using netdutils::ResponseCode;
using netdutils::Stopwatch;
namespace net {
namespace {
-// Limits the number of outstanding DNS queries by client UID.
-constexpr int MAX_QUERIES_PER_UID = 256;
-
android::netdutils::OperationLimiter<uid_t> queryLimiter(MAX_QUERIES_PER_UID);
bool startQueryLimiter(uid_t uid) {
- const int globalLimit =
- android::net::Experiments::getInstance()->getFlag("max_queries_global", INT_MAX);
+ const int globalLimit = android::net::Experiments::getInstance()->getFlag("max_queries_global",
+ MAX_QUERIES_IN_TOTAL);
return queryLimiter.start(uid, globalLimit);
}
@@ -322,10 +322,12 @@ void maybeLogQuery(int eventType, const android_net_context& netContext,
void reportDnsEvent(int eventType, const android_net_context& netContext, int latencyUs,
int returnCode, NetworkDnsEventReported& event, const std::string& query_name,
- const std::vector<std::string>& ip_addrs = {}, int total_ip_addr_count = 0) {
- uint32_t rate =
- (query_name.ends_with(".local") && is_mdns_supported_network(netContext.dns_netid) &&
- android::net::Experiments::getInstance()->getFlag("mdns_resolution", 1))
+ bool skipStats, const std::vector<std::string>& ip_addrs = {},
+ int total_ip_addr_count = 0) {
+ int32_t rate =
+ skipStats ? 0
+ : (query_name.ends_with(".local") && is_mdns_supported_network(netContext.dns_netid) &&
+ android::net::Experiments::getInstance()->getFlag("mdns_resolution", 1))
? getDnsEventSubsamplingRate(netContext.dns_netid, returnCode, true)
: getDnsEventSubsamplingRate(netContext.dns_netid, returnCode, false);
@@ -334,11 +336,12 @@ void reportDnsEvent(int eventType, const android_net_context& netContext, int la
stats::BytesField dnsQueryBytesField{dnsQueryStats.c_str(), dnsQueryStats.size()};
event.set_return_code(static_cast<ReturnCode>(returnCode));
event.set_network_type(resolv_get_network_types_for_net(netContext.dns_netid));
- android::net::stats::stats_write(android::net::stats::NETWORK_DNS_EVENT_REPORTED,
- event.event_type(), event.return_code(),
- event.latency_micros(), event.hints_ai_flags(),
- event.res_nsend_flags(), event.network_type(),
- event.private_dns_modes(), dnsQueryBytesField, rate);
+ event.set_uid(netContext.uid);
+ android::net::stats::stats_write(
+ android::net::stats::NETWORK_DNS_EVENT_REPORTED, event.event_type(),
+ event.return_code(), event.latency_micros(), event.hints_ai_flags(),
+ event.res_nsend_flags(), event.network_type(), event.private_dns_modes(),
+ dnsQueryBytesField, rate, event.uid());
}
maybeLogQuery(eventType, netContext, event, query_name, ip_addrs);
@@ -662,6 +665,59 @@ std::string makeThreadName(unsigned netId, uint32_t uid) {
return fmt::format("Dns_{}_{}", netId, multiuser_get_app_id(uid));
}
+typedef int (*InitFn)();
+typedef int (*IsUidBlockedFn)(uid_t, bool);
+
+IsUidBlockedFn ADnsHelper_isUidNetworkingBlocked;
+
+IsUidBlockedFn resolveIsUidNetworkingBlockedFn() {
+ // Related BPF maps were mainlined from T.
+ if (!isAtLeastT()) return nullptr;
+
+ // TODO: Check whether it is safe to shared link the .so without using dlopen when the carrier
+ // APEX module (tethering) is fully released.
+ void* handle = dlopen("libcom.android.tethering.dns_helper.so", RTLD_NOW | RTLD_LOCAL);
+ if (!handle) {
+ LOG(WARNING) << __func__ << ": " << dlerror();
+ return nullptr;
+ }
+
+ InitFn ADnsHelper_init = reinterpret_cast<InitFn>(dlsym(handle, "ADnsHelper_init"));
+ if (!ADnsHelper_init) {
+ LOG(ERROR) << __func__ << ": " << dlerror();
+ abort();
+ }
+ const int ret = (*ADnsHelper_init)();
+ if (ret) {
+ LOG(ERROR) << __func__ << ": ADnsHelper_init failed " << strerror(-ret);
+ abort();
+ }
+
+ IsUidBlockedFn f =
+ reinterpret_cast<IsUidBlockedFn>(dlsym(handle, "ADnsHelper_isUidNetworkingBlocked"));
+ if (!f) {
+ LOG(ERROR) << __func__ << ": " << dlerror();
+ abort();
+ }
+ return f;
+}
+
+bool isUidNetworkingBlocked(uid_t uid, unsigned netId) {
+ if (!ADnsHelper_isUidNetworkingBlocked) return false;
+
+ // The enforceDnsUid is an OEM feature that sets DNS packet with AID_DNS instead of the
+ // application's UID. Its DNS packets are not subject to certain network restriction features.
+ if (resolv_is_enforceDnsUid_enabled_network(netId)) return false;
+
+ // Feature flag that can disable the feature.
+ if (!android::net::Experiments::getInstance()->getFlag("fail_fast_on_uid_network_blocking",
+ 1)) {
+ return false;
+ }
+
+ return (*ADnsHelper_isUidNetworkingBlocked)(uid, resolv_is_metered_network(netId)) == 1;
+}
+
} // namespace
DnsProxyListener::DnsProxyListener() : FrameworkListener(SOCKET_NAME) {
@@ -679,6 +735,8 @@ DnsProxyListener::DnsProxyListener() : FrameworkListener(SOCKET_NAME) {
mGetDnsNetIdCommand = std::make_unique<GetDnsNetIdCommand>();
registerCmd(mGetDnsNetIdCommand.get());
+
+ ADnsHelper_isUidNetworkingBlocked = resolveIsUidNetworkingBlockedFn();
}
void DnsProxyListener::Handler::spawn() {
@@ -819,21 +877,14 @@ void DnsProxyListener::GetAddrInfoHandler::doDns64Synthesis(int32_t* rv, addrinf
if (ipv6WantedButNoData) {
// If caller wants IPv6 answers but no data, try to query IPv4 answers for synthesis
- const uid_t uid = mClient->getUid();
- if (startQueryLimiter(uid)) {
- const char* host = mHost.starts_with('^') ? nullptr : mHost.c_str();
- const char* service = mService.starts_with('^') ? nullptr : mService.c_str();
- mHints->ai_family = AF_INET;
- // Don't need to do freeaddrinfo(res) before starting new DNS lookup because previous
- // DNS lookup is failed with error EAI_NODATA.
- *rv = resolv_getaddrinfo(host, service, mHints.get(), &mNetContext, res, event);
- endQueryLimiter(uid);
- if (*rv) {
- *rv = EAI_NODATA; // return original error code
- return;
- }
- } else {
- LOG(ERROR) << __func__ << ": from UID " << uid << ", max concurrent queries reached";
+ const char* host = mHost.starts_with('^') ? nullptr : mHost.c_str();
+ const char* service = mService.starts_with('^') ? nullptr : mService.c_str();
+ mHints->ai_family = AF_INET;
+ // Don't need to do freeaddrinfo(res) before starting new DNS lookup because previous
+ // DNS lookup is failed with error EAI_NODATA.
+ *rv = resolv_getaddrinfo(host, service, mHints.get(), &mNetContext, res, event);
+ if (*rv) {
+ *rv = EAI_NODATA; // return original error code
return;
}
}
@@ -861,11 +912,16 @@ void DnsProxyListener::GetAddrInfoHandler::run() {
int32_t rv = 0;
NetworkDnsEventReported event;
initDnsEvent(&event, mNetContext);
- if (startQueryLimiter(uid)) {
+ const bool isUidBlocked = isUidNetworkingBlocked(mNetContext.uid, mNetContext.dns_netid);
+ if (isUidBlocked) {
+ LOG(INFO) << "GetAddrInfoHandler::run: network access blocked";
+ rv = EAI_FAIL;
+ } else if (startQueryLimiter(uid)) {
const char* host = mHost.starts_with('^') ? nullptr : mHost.c_str();
const char* service = mService.starts_with('^') ? nullptr : mService.c_str();
if (evaluate_domain_name(mNetContext, host)) {
rv = resolv_getaddrinfo(host, service, mHints.get(), &mNetContext, &result, &event);
+ doDns64Synthesis(&rv, &result, &event);
} else {
rv = EAI_SYSTEM;
}
@@ -878,7 +934,6 @@ void DnsProxyListener::GetAddrInfoHandler::run() {
<< ", max concurrent queries reached";
}
- doDns64Synthesis(&rv, &result, &event);
const int32_t latencyUs = saturate_cast<int32_t>(s.timeTakenUs());
event.set_latency_micros(latencyUs);
event.set_event_type(EVENT_GETADDRINFO);
@@ -906,7 +961,7 @@ void DnsProxyListener::GetAddrInfoHandler::run() {
std::vector<std::string> ip_addrs;
const int total_ip_addr_count = extractGetAddrInfoAnswers(result, &ip_addrs);
reportDnsEvent(INetdEventListener::EVENT_GETADDRINFO, mNetContext, latencyUs, rv, event, mHost,
- ip_addrs, total_ip_addr_count);
+ isUidBlocked, ip_addrs, total_ip_addr_count);
freeaddrinfo(result);
}
@@ -1056,8 +1111,8 @@ void DnsProxyListener::ResNSendHandler::run() {
uint16_t original_query_id = 0;
// TODO: Handle the case which is msg contains more than one query
- if (!parseQuery({msg.data(), msgLen}, &original_query_id, &rr_type, &rr_name) ||
- !setQueryId({msg.data(), msgLen}, arc4random_uniform(65536))) {
+ if (!parseQuery(std::span(msg.data(), msgLen), &original_query_id, &rr_type, &rr_name) ||
+ !setQueryId(std::span(msg.data(), msgLen), arc4random_uniform(65536))) {
// If the query couldn't be parsed, block the request.
LOG(WARNING) << "ResNSendHandler::run: resnsend: from UID " << uid << ", invalid query";
sendBE32(mClient, -EINVAL);
@@ -1070,11 +1125,16 @@ void DnsProxyListener::ResNSendHandler::run() {
int ansLen = -1;
NetworkDnsEventReported event;
initDnsEvent(&event, mNetContext);
- if (startQueryLimiter(uid)) {
+ const bool isUidBlocked = isUidNetworkingBlocked(mNetContext.uid, mNetContext.dns_netid);
+ if (isUidBlocked) {
+ LOG(INFO) << "ResNSendHandler::run: network access blocked";
+ ansLen = -ECONNREFUSED;
+ } else if (startQueryLimiter(uid)) {
if (evaluate_domain_name(mNetContext, rr_name.c_str())) {
- ansLen = resolv_res_nsend(&mNetContext, {msg.data(), msgLen}, ansBuf, &rcode,
+ ansLen = resolv_res_nsend(&mNetContext, std::span(msg.data(), msgLen), ansBuf, &rcode,
static_cast<ResNsendFlags>(mFlags), &event);
} else {
+ // TODO(b/307048182): It should return -errno.
ansLen = -EAI_SYSTEM;
}
endQueryLimiter(uid);
@@ -1097,7 +1157,7 @@ void DnsProxyListener::ResNSendHandler::run() {
}
if (rr_type == ns_t_a || rr_type == ns_t_aaaa) {
reportDnsEvent(INetdEventListener::EVENT_RES_NSEND, mNetContext, latencyUs,
- resNSendToAiError(ansLen, rcode), event, rr_name);
+ resNSendToAiError(ansLen, rcode), event, rr_name, isUidBlocked);
}
return;
}
@@ -1110,7 +1170,7 @@ void DnsProxyListener::ResNSendHandler::run() {
}
// Restore query id
- if (!setQueryId({ansBuf.data(), ansLen}, original_query_id)) {
+ if (!setQueryId(std::span(ansBuf.data(), ansLen), original_query_id)) {
LOG(WARNING) << "ResNSendHandler::run: resnsend: failed to restore query id";
return;
}
@@ -1125,10 +1185,10 @@ void DnsProxyListener::ResNSendHandler::run() {
if (rr_type == ns_t_a || rr_type == ns_t_aaaa) {
std::vector<std::string> ip_addrs;
const int total_ip_addr_count =
- extractResNsendAnswers({ansBuf.data(), ansLen}, rr_type, &ip_addrs);
+ extractResNsendAnswers(std::span(ansBuf.data(), ansLen), rr_type, &ip_addrs);
reportDnsEvent(INetdEventListener::EVENT_RES_NSEND, mNetContext, latencyUs,
- resNSendToAiError(ansLen, rcode), event, rr_name, ip_addrs,
- total_ip_addr_count);
+ resNSendToAiError(ansLen, rcode), event, rr_name, /*skipStats=*/false,
+ ip_addrs, total_ip_addr_count);
}
}
@@ -1245,17 +1305,10 @@ void DnsProxyListener::GetHostByNameHandler::doDns64Synthesis(int32_t* rv, hoste
}
// If caller wants IPv6 answers but no data, try to query IPv4 answers for synthesis
- const uid_t uid = mClient->getUid();
- if (startQueryLimiter(uid)) {
- const char* name = mName.starts_with('^') ? nullptr : mName.c_str();
- *rv = resolv_gethostbyname(name, AF_INET, hbuf, buf, buflen, &mNetContext, hpp, event);
- endQueryLimiter(uid);
- if (*rv) {
- *rv = EAI_NODATA; // return original error code
- return;
- }
- } else {
- LOG(ERROR) << __func__ << ": from UID " << uid << ", max concurrent queries reached";
+ const char* name = mName.starts_with('^') ? nullptr : mName.c_str();
+ *rv = resolv_gethostbyname(name, AF_INET, hbuf, buf, buflen, &mNetContext, hpp, event);
+ if (*rv) {
+ *rv = EAI_NODATA; // return original error code
return;
}
@@ -1277,11 +1330,16 @@ void DnsProxyListener::GetHostByNameHandler::run() {
int32_t rv = 0;
NetworkDnsEventReported event;
initDnsEvent(&event, mNetContext);
- if (startQueryLimiter(uid)) {
+ const bool isUidBlocked = isUidNetworkingBlocked(mNetContext.uid, mNetContext.dns_netid);
+ if (isUidBlocked) {
+ LOG(INFO) << "GetHostByNameHandler::run: network access blocked";
+ rv = EAI_FAIL;
+ } else if (startQueryLimiter(uid)) {
const char* name = mName.starts_with('^') ? nullptr : mName.c_str();
if (evaluate_domain_name(mNetContext, name)) {
rv = resolv_gethostbyname(name, mAf, &hbuf, tmpbuf, sizeof tmpbuf, &mNetContext, &hp,
&event);
+ doDns64Synthesis(&rv, &hbuf, tmpbuf, sizeof tmpbuf, &hp, &event);
} else {
rv = EAI_SYSTEM;
}
@@ -1292,7 +1350,6 @@ void DnsProxyListener::GetHostByNameHandler::run() {
<< ", max concurrent queries reached";
}
- doDns64Synthesis(&rv, &hbuf, tmpbuf, sizeof tmpbuf, &hp, &event);
const int32_t latencyUs = saturate_cast<int32_t>(s.timeTakenUs());
event.set_latency_micros(latencyUs);
event.set_event_type(EVENT_GETHOSTBYNAME);
@@ -1318,7 +1375,7 @@ void DnsProxyListener::GetHostByNameHandler::run() {
std::vector<std::string> ip_addrs;
const int total_ip_addr_count = extractGetHostByNameAnswers(hp, &ip_addrs);
reportDnsEvent(INetdEventListener::EVENT_GETHOSTBYNAME, mNetContext, latencyUs, rv, event,
- mName, ip_addrs, total_ip_addr_count);
+ mName, isUidBlocked, ip_addrs, total_ip_addr_count);
}
std::string DnsProxyListener::GetHostByNameHandler::threadName() {
@@ -1407,27 +1464,21 @@ void DnsProxyListener::GetHostByAddrHandler::doDns64ReverseLookup(hostent* hbuf,
return;
}
- const uid_t uid = mClient->getUid();
- if (startQueryLimiter(uid)) {
- // Remove NAT64 prefix and do reverse DNS query
- struct in_addr v4addr = {.s_addr = v6addr.s6_addr32[3]};
- resolv_gethostbyaddr(&v4addr, sizeof(v4addr), AF_INET, hbuf, buf, buflen, &mNetContext, hpp,
- event);
- endQueryLimiter(uid);
- if (*hpp && (*hpp)->h_addr_list[0]) {
- // Replace IPv4 address with original queried IPv6 address in place. The space has
- // reserved by dns_gethtbyaddr() and netbsd_gethostent_r() in
- // system/netd/resolv/gethnamaddr.cpp.
- // Note that resolv_gethostbyaddr() returns only one entry in result.
- char* addr = (*hpp)->h_addr_list[0];
- memcpy(addr, &v6addr, sizeof(v6addr));
- (*hpp)->h_addrtype = AF_INET6;
- (*hpp)->h_length = sizeof(struct in6_addr);
- } else {
- LOG(ERROR) << __func__ << ": hpp or (*hpp)->h_addr_list[0] is null";
- }
+ // Remove NAT64 prefix and do reverse DNS query
+ struct in_addr v4addr = {.s_addr = v6addr.s6_addr32[3]};
+ resolv_gethostbyaddr(&v4addr, sizeof(v4addr), AF_INET, hbuf, buf, buflen, &mNetContext, hpp,
+ event);
+ if (*hpp && (*hpp)->h_addr_list[0]) {
+ // Replace IPv4 address with original queried IPv6 address in place. The space has
+ // reserved by dns_gethtbyaddr() and netbsd_gethostent_r() in
+ // system/netd/resolv/gethnamaddr.cpp.
+ // Note that resolv_gethostbyaddr() returns only one entry in result.
+ char* addr = (*hpp)->h_addr_list[0];
+ memcpy(addr, &v6addr, sizeof(v6addr));
+ (*hpp)->h_addrtype = AF_INET6;
+ (*hpp)->h_length = sizeof(struct in6_addr);
} else {
- LOG(ERROR) << __func__ << ": from UID " << uid << ", max concurrent queries reached";
+ LOG(ERROR) << __func__ << ": hpp or (*hpp)->h_addr_list[0] is null";
}
}
@@ -1442,7 +1493,12 @@ void DnsProxyListener::GetHostByAddrHandler::run() {
int32_t rv = 0;
NetworkDnsEventReported event;
initDnsEvent(&event, mNetContext);
- if (startQueryLimiter(uid)) {
+
+ const bool isUidBlocked = isUidNetworkingBlocked(mNetContext.uid, mNetContext.dns_netid);
+ if (isUidBlocked) {
+ LOG(INFO) << "GetHostByAddrHandler::run: network access blocked";
+ rv = EAI_FAIL;
+ } else if (startQueryLimiter(uid)) {
// From Android U, evaluate_domain_name() is not only for OEM customization, but also tells
// DNS resolver whether the UID can send DNS on the specified network. The function needs
// to be called even when there is no domain name to evaluate (GetHostByAddr). This is
@@ -1454,6 +1510,7 @@ void DnsProxyListener::GetHostByAddrHandler::run() {
} else {
rv = resolv_gethostbyaddr(&mAddress, mAddressLen, mAddressFamily, &hbuf, tmpbuf,
sizeof tmpbuf, &mNetContext, &hp, &event);
+ doDns64ReverseLookup(&hbuf, tmpbuf, sizeof tmpbuf, &hp, &event);
}
endQueryLimiter(uid);
} else {
@@ -1462,7 +1519,6 @@ void DnsProxyListener::GetHostByAddrHandler::run() {
<< ", max concurrent queries reached";
}
- doDns64ReverseLookup(&hbuf, tmpbuf, sizeof tmpbuf, &hp, &event);
const int32_t latencyUs = saturate_cast<int32_t>(s.timeTakenUs());
event.set_latency_micros(latencyUs);
event.set_event_type(EVENT_GETHOSTBYADDR);
@@ -1485,7 +1541,7 @@ void DnsProxyListener::GetHostByAddrHandler::run() {
}
reportDnsEvent(INetdEventListener::EVENT_GETHOSTBYADDR, mNetContext, latencyUs, rv, event,
- (hp && hp->h_name) ? hp->h_name : "null", {}, 0);
+ (hp && hp->h_name) ? hp->h_name : "null", isUidBlocked, {}, 0);
}
std::string DnsProxyListener::GetHostByAddrHandler::threadName() {
diff --git a/DnsResolver.cpp b/DnsResolver.cpp
index 5abfaea6..372252d6 100644
--- a/DnsResolver.cpp
+++ b/DnsResolver.cpp
@@ -68,7 +68,6 @@ bool verifyCallbacks() {
DnsResolver* gDnsResolv = nullptr;
ResolverNetdCallbacks gResNetdCallbacks;
-netdutils::Log gDnsResolverLog("dnsResolver");
uint64_t gApiLevel = 0;
DnsResolver* DnsResolver::getInstance() {
diff --git a/DnsResolver.h b/DnsResolver.h
index 9c2f3d8c..a3819f15 100644
--- a/DnsResolver.h
+++ b/DnsResolver.h
@@ -21,7 +21,6 @@
#include "DnsQueryLog.h"
#include "ResolverController.h"
#include "netd_resolv/resolv.h"
-#include "netdutils/Log.h"
namespace android {
namespace net {
@@ -48,7 +47,6 @@ class DnsResolver {
extern DnsResolver* gDnsResolv;
extern ResolverNetdCallbacks gResNetdCallbacks;
-extern netdutils::Log gDnsResolverLog;
extern uint64_t gApiLevel;
} // namespace net
diff --git a/DnsResolverService.cpp b/DnsResolverService.cpp
index ee129514..2d7a0e5f 100644
--- a/DnsResolverService.cpp
+++ b/DnsResolverService.cpp
@@ -90,8 +90,6 @@ binder_status_t DnsResolverService::start() {
ABinderProcess_startThreadPool();
- // TODO: register log callback if binder NDK backend support it. b/126501406
-
return STATUS_OK;
}
@@ -199,19 +197,7 @@ binder_status_t DnsResolverService::dump(int fd, const char** args, uint32_t num
return ::ndk::ScopedAStatus(AStatus_fromExceptionCodeWithMessage(EX_SECURITY, err.c_str()));
}
- // TODO: Remove this log after AIDL gen_log supporting more types, b/129732660
- auto entry =
- gDnsResolverLog.newEntry()
- .prettyFunction(__PRETTY_FUNCTION__)
- .args(resolverParams.netId, resolverParams.servers, resolverParams.domains,
- resolverParams.sampleValiditySeconds, resolverParams.successThreshold,
- resolverParams.minSamples, resolverParams.maxSamples,
- resolverParams.baseTimeoutMsec, resolverParams.retryCount,
- resolverParams.tlsName, resolverParams.tlsServers);
-
int res = gDnsResolv->resolverCtrl.setResolverConfiguration(resolverParams);
- gResNetdCallbacks.log(entry.returns(res).withAutomaticDuration().toString().c_str());
-
return statusFromErrcode(res);
}
diff --git a/DnsTlsDispatcher.cpp b/DnsTlsDispatcher.cpp
index 452d28b8..6e0ced2a 100644
--- a/DnsTlsDispatcher.cpp
+++ b/DnsTlsDispatcher.cpp
@@ -71,7 +71,7 @@ std::list<DnsTlsServer> DnsTlsDispatcher::getOrderedAndUsableServerList(
if (!xport->usable()) {
// Don't use this xport. It will be removed after timeout
// (IDLE_TIMEOUT minutes).
- LOG(DEBUG) << "Skip using DoT server " << tlsServer.toIpString() << " on "
+ LOG(DEBUG) << "Skip using DoT server " << tlsServer.toString() << " on "
<< netId;
continue;
}
@@ -231,7 +231,7 @@ DnsTlsTransport::Response DnsTlsDispatcher::query(const DnsTlsServer& server, un
// a new xport will be created.
const auto result = PrivateDnsConfiguration::getInstance().requestDotValidation(
netId, PrivateDnsConfiguration::ServerIdentity{server}, mark);
- LOG(WARNING) << "Requested validation for " << server.toIpString() << " with mark 0x"
+ LOG(WARNING) << "Requested validation for " << server.toString() << " with mark 0x"
<< std::hex << mark << ", "
<< (result.ok() ? "succeeded" : "failed: " + result.error().message());
}
@@ -327,7 +327,7 @@ DnsTlsDispatcher::Transport* DnsTlsDispatcher::addTransport(const DnsTlsServer&
ret = new Transport(server, mark, netId, mFactory.get(), triggerThr, unusableThr, queryTimeout);
LOG(INFO) << "Transport is initialized with { " << triggerThr << ", " << unusableThr << ", "
<< queryTimeout << "ms }"
- << " for server { " << server.toIpString() << "/" << server.name << " }";
+ << " for server " << server.toString();
mStore[key].reset(ret);
diff --git a/DnsTlsServer.cpp b/DnsTlsServer.cpp
index 89ea8417..76825317 100644
--- a/DnsTlsServer.cpp
+++ b/DnsTlsServer.cpp
@@ -18,6 +18,7 @@
#include <algorithm>
+#include <android-base/format.h>
#include <netdutils/InternetAddresses.h>
namespace {
@@ -130,5 +131,9 @@ std::string DnsTlsServer::toIpString() const {
return netdutils::IPSockAddr::toIPSockAddr(ss).ip().toString();
}
+std::string DnsTlsServer::toString() const {
+ return fmt::format("{{{}/{}}}", toIpString(), name);
+}
+
} // namespace net
} // namespace android
diff --git a/DnsTlsServer.h b/DnsTlsServer.h
index ef364942..9d2ac5e6 100644
--- a/DnsTlsServer.h
+++ b/DnsTlsServer.h
@@ -63,6 +63,7 @@ struct DnsTlsServer {
bool wasExplicitlyConfigured() const;
std::string toIpString() const;
+ std::string toString() const;
std::string provider() const { return name; }
netdutils::IPSockAddr addr() const { return netdutils::IPSockAddr::toIPSockAddr(ss); }
diff --git a/DnsTlsSocket.cpp b/DnsTlsSocket.cpp
index 9789aa5b..2d1eeb85 100644
--- a/DnsTlsSocket.cpp
+++ b/DnsTlsSocket.cpp
@@ -70,7 +70,7 @@ int waitForWriting(int fd, int timeoutMs = -1) {
Status DnsTlsSocket::tcpConnect() {
if (mServer.protocol != IPPROTO_TCP) return Status(EPROTONOSUPPORT);
- LOG(DEBUG) << mMark << " connecting TCP socket";
+ LOG(INFO) << fmt::format("Connecting to {} with mark 0x{:x}", mServer.toString(), mMark);
mSslFd.reset(socket(mServer.ss.ss_family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
if (mSslFd.get() == -1) {
@@ -270,7 +270,7 @@ bssl::UniquePtr<SSL> DnsTlsSocket::sslConnect(int fd) {
for (;;) {
LOG(DEBUG) << " Calling SSL_connect with mark 0x" << std::hex << mMark;
int ret = SSL_connect(ssl.get());
- LOG(DEBUG) << " SSL_connect returned " << ret << " with mark 0x" << std::hex << mMark;
+ LOG(INFO) << " SSL_connect returned " << ret << " with mark 0x" << std::hex << mMark;
if (ret == 1) break; // SSL handshake complete;
const int ssl_err = SSL_get_error(ssl.get(), ret);
@@ -315,7 +315,7 @@ bssl::UniquePtr<SSL> DnsTlsSocket::sslConnectV2(int fd) {
for (;;) {
LOG(DEBUG) << " Calling SSL_connect with mark 0x" << std::hex << mMark;
int ret = SSL_connect(ssl.get());
- LOG(DEBUG) << " SSL_connect returned " << ret << " with mark 0x" << std::hex << mMark;
+ LOG(INFO) << " SSL_connect returned " << ret << " with mark 0x" << std::hex << mMark;
if (ret == 1) break; // SSL handshake complete;
enum { SSLFD = 0, EVENTFD = 1 };
@@ -445,7 +445,7 @@ void DnsTlsSocket::loop() {
break;
}
if (s < 0) {
- PLOG(DEBUG) << "Poll failed";
+ PLOG(WARNING) << "Poll failed";
break;
}
if (fds[SSLFD].revents & (POLLIN | POLLERR | POLLHUP)) {
@@ -457,7 +457,7 @@ void DnsTlsSocket::loop() {
// refactoring it to not get blocked in any case.
do {
if (!readResponse()) {
- LOG(DEBUG) << "SSL remote close or read error.";
+ LOG(INFO) << "SSL remote close or read error.";
readFailed = true;
}
} while (SSL_pending(mSsl.get()) > 0 && !readFailed);
@@ -496,7 +496,7 @@ void DnsTlsSocket::loop() {
q.pop_front();
}
}
- LOG(DEBUG) << "Disconnecting";
+ LOG(INFO) << fmt::format("Disconnecting {}, mark 0x{:x}", mServer.toString(), mMark);
sslDisconnect();
LOG(DEBUG) << "Calling onClosed";
mObserver->onClosed();
diff --git a/DnsTlsTransport.cpp b/DnsTlsTransport.cpp
index 172a1e36..de40aac1 100644
--- a/DnsTlsTransport.cpp
+++ b/DnsTlsTransport.cpp
@@ -113,7 +113,7 @@ base::Result<void> sendUdpQuery(netdutils::IPAddress ip, uint32_t mark,
return ErrnoErrorf("connect failed");
}
- if (send(fd, query.data(), query.size(), 0) != query.size()) {
+ if (send(fd, query.data(), query.size(), 0) != static_cast<ptrdiff_t>(query.size())) {
return ErrnoErrorf("send failed");
}
diff --git a/Experiments.h b/Experiments.h
index a9845629..db58630c 100644
--- a/Experiments.h
+++ b/Experiments.h
@@ -17,6 +17,7 @@
#pragma once
#include <climits>
+#include <functional>
#include <map>
#include <mutex>
#include <string>
@@ -61,6 +62,7 @@ class Experiments {
"dot_validation_latency_factor",
"dot_validation_latency_offset_ms",
"dot_xport_unusable_threshold",
+ "fail_fast_on_uid_network_blocking",
"keep_listening_udp",
"max_cache_entries",
"max_queries_global",
@@ -68,7 +70,6 @@ class Experiments {
"parallel_lookup_sleep_time",
"retransmission_time_interval",
"retry_count",
- "skip_4a_query_on_v6_linklocal_addr",
"sort_nameservers",
};
// This value is used in updateInternal as the default value if any flags can't be found.
diff --git a/OWNERS b/OWNERS
index 62c5737a..b0e134e2 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,2 +1,3 @@
+# Bug component: 31808
set noparent
-file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking
+file:platform/packages/modules/Connectivity:main:/OWNERS_core_networking
diff --git a/OperationLimiter.h b/OperationLimiter.h
index 24f4dc3c..335ec5a3 100644
--- a/OperationLimiter.h
+++ b/OperationLimiter.h
@@ -28,6 +28,11 @@
namespace android {
namespace netdutils {
+// Limits the number of outstanding DNS queries by client UID.
+constexpr int MAX_QUERIES_PER_UID = 256;
+// Limits the total number of outstanding DNS queries.
+constexpr int MAX_QUERIES_IN_TOTAL = 2500;
+
// Tracks the number of operations in progress on behalf of a particular key or
// ID, rejecting further attempts to start new operations after a configurable
// limit has been reached.
@@ -56,11 +61,11 @@ class OperationLimiter {
//
// Note: each successful start(key) must be matched by exactly one call to
// finish(key).
- bool start(KeyType key, int globalLimit = INT_MAX) EXCLUDES(mMutex) {
+ bool start(KeyType key, int globalLimit = MAX_QUERIES_IN_TOTAL) EXCLUDES(mMutex) {
std::lock_guard lock(mMutex);
if (globalLimit < mLimitPerKey) {
LOG(ERROR) << "Misconfiguration on max_queries_global " << globalLimit;
- globalLimit = INT_MAX;
+ globalLimit = MAX_QUERIES_IN_TOTAL;
}
if (mGlobalCounter >= globalLimit) {
// Oh, no!
diff --git a/PrivateDnsConfiguration.cpp b/PrivateDnsConfiguration.cpp
index 013cd1a5..cb1a8987 100644
--- a/PrivateDnsConfiguration.cpp
+++ b/PrivateDnsConfiguration.cpp
@@ -365,11 +365,11 @@ void PrivateDnsConfiguration::startDotValidation(const ServerIdentity& identity,
while (true) {
// ::validate() is a blocking call that performs network operations.
// It can take milliseconds to minutes, up to the SYN retry limit.
- LOG(WARNING) << "Validating DnsTlsServer " << server.toIpString() << " with mark 0x"
+ LOG(WARNING) << "Validating DnsTlsServer " << server.toString() << " with mark 0x"
<< std::hex << server.validationMark();
const bool success = DnsTlsTransport::validate(server, server.validationMark());
LOG(WARNING) << "validateDnsTlsServer returned " << success << " for "
- << server.toIpString();
+ << server.toString();
const bool needs_reeval =
this->recordDotValidation(identity, netId, success, isRevalidation);
@@ -534,8 +534,8 @@ base::Result<DnsTlsServer*> PrivateDnsConfiguration::getDotServerLocked(
auto iter = netPair->second.find(identity);
if (iter == netPair->second.end()) {
- return Errorf("Failed to get private DNS: server {{{}/{}}} not found", identity.sockaddr,
- identity.provider);
+ return Errorf("Failed to get private DNS: server {{{}/{}}} not found",
+ identity.sockaddr.toString(), identity.provider);
}
return &iter->second;
diff --git a/ResolverController.cpp b/ResolverController.cpp
index 7fe01d48..757e3f74 100644
--- a/ResolverController.cpp
+++ b/ResolverController.cpp
@@ -37,9 +37,11 @@
#include "stats.h"
#include "util.h"
+using aidl::android::net::IDnsResolver;
using aidl::android::net::ResolverParamsParcel;
using aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener;
using aidl::android::net::resolv::aidl::Nat64PrefixEventParcel;
+using android::net::ResolverStats;
namespace android {
@@ -79,8 +81,6 @@ void sendNat64PrefixEvent(const Dns64Configuration::Nat64PrefixInfo& args) {
int getDnsInfo(unsigned netId, std::vector<std::string>* servers, std::vector<std::string>* domains,
res_params* params, std::vector<android::net::ResolverStats>* stats,
int* wait_for_pending_req_timeout_count) {
- using aidl::android::net::IDnsResolver;
- using android::net::ResolverStats;
static_assert(ResolverStats::STATS_SUCCESSES == IDnsResolver::RESOLVER_STATS_SUCCESSES &&
ResolverStats::STATS_ERRORS == IDnsResolver::RESOLVER_STATS_ERRORS &&
ResolverStats::STATS_TIMEOUTS == IDnsResolver::RESOLVER_STATS_TIMEOUTS &&
@@ -155,11 +155,11 @@ int getDnsInfo(unsigned netId, std::vector<std::string>* servers, std::vector<st
} // namespace
ResolverController::ResolverController()
- : mDns64Configuration(
+ : mDns64Configuration(android::sp<Dns64Configuration>::make(
[](uint32_t netId, uint32_t uid, android_net_context* netcontext) {
gResNetdCallbacks.get_network_context(netId, uid, netcontext);
},
- std::bind(sendNat64PrefixEvent, std::placeholders::_1)) {}
+ std::bind(sendNat64PrefixEvent, std::placeholders::_1))) {}
void ResolverController::destroyNetworkCache(unsigned netId) {
LOG(VERBOSE) << __func__ << ": netId = " << netId;
@@ -173,7 +173,7 @@ void ResolverController::destroyNetworkCache(unsigned netId) {
event.network_type(), event.private_dns_modes(), bytesField);
resolv_delete_cache_for_net(netId);
- mDns64Configuration.stopPrefixDiscovery(netId);
+ mDns64Configuration->stopPrefixDiscovery(netId);
privateDnsConfiguration.clear(netId);
// Don't get this instance in PrivateDnsConfiguration. It's probe to deadlock.
@@ -192,8 +192,6 @@ int ResolverController::flushNetworkCache(unsigned netId) {
}
int ResolverController::setResolverConfiguration(const ResolverParamsParcel& resolverParams) {
- using aidl::android::net::IDnsResolver;
-
if (!has_named_cache(resolverParams.netId)) {
return -ENOENT;
}
@@ -239,7 +237,8 @@ int ResolverController::setResolverConfiguration(const ResolverParamsParcel& res
return resolv_set_nameservers(resolverParams.netId, resolverParams.servers,
resolverParams.domains, res_params,
- resolverParams.resolverOptions, resolverParams.transportTypes);
+ resolverParams.resolverOptions, resolverParams.transportTypes,
+ resolverParams.meteredNetwork);
}
int ResolverController::getResolverInfo(int32_t netId, std::vector<std::string>* servers,
@@ -247,8 +246,6 @@ int ResolverController::getResolverInfo(int32_t netId, std::vector<std::string>*
std::vector<std::string>* tlsServers,
std::vector<int32_t>* params, std::vector<int32_t>* stats,
int* wait_for_pending_req_timeout_count) {
- using aidl::android::net::IDnsResolver;
- using android::net::ResolverStats;
res_params res_params;
std::vector<ResolverStats> res_stats;
int ret = getDnsInfo(netId, servers, domains, &res_params, &res_stats,
@@ -276,16 +273,16 @@ int ResolverController::getResolverInfo(int32_t netId, std::vector<std::string>*
}
void ResolverController::startPrefix64Discovery(int32_t netId) {
- mDns64Configuration.startPrefixDiscovery(netId);
+ mDns64Configuration->startPrefixDiscovery(netId);
}
void ResolverController::stopPrefix64Discovery(int32_t netId) {
- return mDns64Configuration.stopPrefixDiscovery(netId);
+ return mDns64Configuration->stopPrefixDiscovery(netId);
}
// TODO: use StatusOr<T> to wrap the result.
int ResolverController::getPrefix64(unsigned netId, netdutils::IPPrefix* prefix) {
- netdutils::IPPrefix p = mDns64Configuration.getPrefix64(netId);
+ netdutils::IPPrefix p = mDns64Configuration->getPrefix64(netId);
if (p.family() != AF_INET6 || p.length() == 0) {
return -ENOENT;
}
@@ -295,7 +292,6 @@ int ResolverController::getPrefix64(unsigned netId, netdutils::IPPrefix* prefix)
void ResolverController::dump(DumpWriter& dw, unsigned netId) {
// No lock needed since Bionic's resolver locks all accessed data structures internally.
- using android::net::ResolverStats;
std::vector<std::string> servers;
std::vector<std::string> domains;
res_params params = {};
@@ -352,7 +348,7 @@ void ResolverController::dump(DumpWriter& dw, unsigned netId) {
params.max_samples, params.base_timeout_msec, params.retry_count);
}
- mDns64Configuration.dump(dw, netId);
+ mDns64Configuration->dump(dw, netId);
const auto privateDnsStatus = PrivateDnsConfiguration::getInstance().getStatus(netId);
dw.println("Private DNS mode: %s", getPrivateDnsModeString(privateDnsStatus.mode));
if (privateDnsStatus.dotServersMap.size() == 0) {
diff --git a/ResolverController.h b/ResolverController.h
index 0af830ee..b74cff92 100644
--- a/ResolverController.h
+++ b/ResolverController.h
@@ -55,10 +55,10 @@ class ResolverController {
// Set or clear a NAT64 prefix discovered by other sources (e.g., RA).
int setPrefix64(unsigned netId, const netdutils::IPPrefix& prefix) {
- return mDns64Configuration.setPrefix64(netId, prefix);
+ return mDns64Configuration->setPrefix64(netId, prefix);
}
- int clearPrefix64(unsigned netId) { return mDns64Configuration.clearPrefix64(netId); }
+ int clearPrefix64(unsigned netId) { return mDns64Configuration->clearPrefix64(netId); }
// Return the current NAT64 prefix network, regardless of how it was discovered.
int getPrefix64(unsigned netId, netdutils::IPPrefix* prefix);
@@ -66,7 +66,7 @@ class ResolverController {
void dump(netdutils::DumpWriter& dw, unsigned netId);
private:
- Dns64Configuration mDns64Configuration;
+ android::sp<Dns64Configuration> mDns64Configuration;
};
} // namespace net
} // namespace android
diff --git a/aidl_api/dnsresolver_aidl_interface/12/.hash b/aidl_api/dnsresolver_aidl_interface/12/.hash
new file mode 100644
index 00000000..788aef87
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/12/.hash
@@ -0,0 +1 @@
+a65a6755e2e5f5c160e7be2be814019e2d5491b1
diff --git a/aidl_api/dnsresolver_aidl_interface/12/android/net/IDnsResolver.aidl b/aidl_api/dnsresolver_aidl_interface/12/android/net/IDnsResolver.aidl
new file mode 100644
index 00000000..6b539c47
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/12/android/net/IDnsResolver.aidl
@@ -0,0 +1,69 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+interface IDnsResolver {
+ boolean isAlive();
+ void registerEventListener(android.net.metrics.INetdEventListener listener);
+ void setResolverConfiguration(in android.net.ResolverParamsParcel resolverParams);
+ void getResolverInfo(int netId, out @utf8InCpp String[] servers, out @utf8InCpp String[] domains, out @utf8InCpp String[] tlsServers, out int[] params, out int[] stats, out int[] wait_for_pending_req_timeout_count);
+ void startPrefix64Discovery(int netId);
+ void stopPrefix64Discovery(int netId);
+ @utf8InCpp String getPrefix64(int netId);
+ void createNetworkCache(int netId);
+ void destroyNetworkCache(int netId);
+ void setLogSeverity(int logSeverity);
+ void flushNetworkCache(int netId);
+ void setPrefix64(int netId, @utf8InCpp String prefix);
+ void registerUnsolicitedEventListener(android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener listener);
+ void setResolverOptions(int netId, in android.net.ResolverOptionsParcel optionParams);
+ const int RESOLVER_PARAMS_SAMPLE_VALIDITY = 0;
+ const int RESOLVER_PARAMS_SUCCESS_THRESHOLD = 1;
+ const int RESOLVER_PARAMS_MIN_SAMPLES = 2;
+ const int RESOLVER_PARAMS_MAX_SAMPLES = 3;
+ const int RESOLVER_PARAMS_BASE_TIMEOUT_MSEC = 4;
+ const int RESOLVER_PARAMS_RETRY_COUNT = 5;
+ const int RESOLVER_PARAMS_COUNT = 6;
+ const int RESOLVER_STATS_SUCCESSES = 0;
+ const int RESOLVER_STATS_ERRORS = 1;
+ const int RESOLVER_STATS_TIMEOUTS = 2;
+ const int RESOLVER_STATS_INTERNAL_ERRORS = 3;
+ const int RESOLVER_STATS_RTT_AVG = 4;
+ const int RESOLVER_STATS_LAST_SAMPLE_TIME = 5;
+ const int RESOLVER_STATS_USABLE = 6;
+ const int RESOLVER_STATS_COUNT = 7;
+ const int DNS_RESOLVER_LOG_VERBOSE = 0;
+ const int DNS_RESOLVER_LOG_DEBUG = 1;
+ const int DNS_RESOLVER_LOG_INFO = 2;
+ const int DNS_RESOLVER_LOG_WARNING = 3;
+ const int DNS_RESOLVER_LOG_ERROR = 4;
+ const int TC_MODE_DEFAULT = 0;
+ const int TC_MODE_UDP_TCP = 1;
+ const int TRANSPORT_UNKNOWN = (-1) /* -1 */;
+ const int TRANSPORT_CELLULAR = 0;
+ const int TRANSPORT_WIFI = 1;
+ const int TRANSPORT_BLUETOOTH = 2;
+ const int TRANSPORT_ETHERNET = 3;
+ const int TRANSPORT_VPN = 4;
+ const int TRANSPORT_WIFI_AWARE = 5;
+ const int TRANSPORT_LOWPAN = 6;
+ const int TRANSPORT_TEST = 7;
+ const int TRANSPORT_USB = 8;
+ const int TRANSPORT_THREAD = 9;
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/12/android/net/ResolverHostsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/12/android/net/ResolverHostsParcel.aidl
new file mode 100644
index 00000000..c24eb619
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/12/android/net/ResolverHostsParcel.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable ResolverHostsParcel {
+ @utf8InCpp String ipAddr;
+ @utf8InCpp String hostName = "";
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/12/android/net/ResolverOptionsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/12/android/net/ResolverOptionsParcel.aidl
new file mode 100644
index 00000000..e806d040
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/12/android/net/ResolverOptionsParcel.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable ResolverOptionsParcel {
+ android.net.ResolverHostsParcel[] hosts = {};
+ int tcMode = 0;
+ boolean enforceDnsUid = false;
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/12/android/net/ResolverParamsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/12/android/net/ResolverParamsParcel.aidl
new file mode 100644
index 00000000..8a7bf997
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/12/android/net/ResolverParamsParcel.aidl
@@ -0,0 +1,39 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+parcelable ResolverParamsParcel {
+ int netId;
+ int sampleValiditySeconds;
+ int successThreshold;
+ int minSamples;
+ int maxSamples;
+ int baseTimeoutMsec;
+ int retryCount;
+ @utf8InCpp String[] servers;
+ @utf8InCpp String[] domains;
+ @utf8InCpp String tlsName;
+ @utf8InCpp String[] tlsServers;
+ @utf8InCpp String[] tlsFingerprints = {};
+ @utf8InCpp String caCertificate = "";
+ int tlsConnectTimeoutMs = 0;
+ @nullable android.net.ResolverOptionsParcel resolverOptions;
+ int[] transportTypes = {};
+ boolean meteredNetwork = false;
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/12/android/net/resolv/aidl/DnsHealthEventParcel.aidl b/aidl_api/dnsresolver_aidl_interface/12/android/net/resolv/aidl/DnsHealthEventParcel.aidl
new file mode 100644
index 00000000..d32be919
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/12/android/net/resolv/aidl/DnsHealthEventParcel.aidl
@@ -0,0 +1,26 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.resolv.aidl;
+/* @hide */
+@JavaDerive(toString=true)
+parcelable DnsHealthEventParcel {
+ int netId;
+ int healthResult;
+ int[] successRttMicros;
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/12/android/net/resolv/aidl/IDnsResolverUnsolicitedEventListener.aidl b/aidl_api/dnsresolver_aidl_interface/12/android/net/resolv/aidl/IDnsResolverUnsolicitedEventListener.aidl
new file mode 100644
index 00000000..32963dfd
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/12/android/net/resolv/aidl/IDnsResolverUnsolicitedEventListener.aidl
@@ -0,0 +1,33 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.resolv.aidl;
+/* @hide */
+interface IDnsResolverUnsolicitedEventListener {
+ oneway void onDnsHealthEvent(in android.net.resolv.aidl.DnsHealthEventParcel dnsHealthEvent);
+ oneway void onNat64PrefixEvent(in android.net.resolv.aidl.Nat64PrefixEventParcel nat64PrefixEvent);
+ oneway void onPrivateDnsValidationEvent(in android.net.resolv.aidl.PrivateDnsValidationEventParcel privateDnsValidationEvent);
+ const int DNS_HEALTH_RESULT_OK = 0;
+ const int DNS_HEALTH_RESULT_TIMEOUT = 255;
+ const int PREFIX_OPERATION_ADDED = 1;
+ const int PREFIX_OPERATION_REMOVED = 2;
+ const int VALIDATION_RESULT_SUCCESS = 1;
+ const int VALIDATION_RESULT_FAILURE = 2;
+ const int PROTOCOL_DOT = 1;
+ const int PROTOCOL_DOH = 2;
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/12/android/net/resolv/aidl/Nat64PrefixEventParcel.aidl b/aidl_api/dnsresolver_aidl_interface/12/android/net/resolv/aidl/Nat64PrefixEventParcel.aidl
new file mode 100644
index 00000000..2daccb0e
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/12/android/net/resolv/aidl/Nat64PrefixEventParcel.aidl
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.resolv.aidl;
+/* @hide */
+@JavaDerive(toString=true)
+parcelable Nat64PrefixEventParcel {
+ int netId;
+ int prefixOperation;
+ @utf8InCpp String prefixAddress;
+ int prefixLength;
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/12/android/net/resolv/aidl/PrivateDnsValidationEventParcel.aidl b/aidl_api/dnsresolver_aidl_interface/12/android/net/resolv/aidl/PrivateDnsValidationEventParcel.aidl
new file mode 100644
index 00000000..f3bfbc76
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/12/android/net/resolv/aidl/PrivateDnsValidationEventParcel.aidl
@@ -0,0 +1,28 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.resolv.aidl;
+/* @hide */
+@JavaDerive(toString=true)
+parcelable PrivateDnsValidationEventParcel {
+ int netId;
+ @utf8InCpp String ipAddress;
+ @utf8InCpp String hostname;
+ int validation;
+ int protocol;
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/13/.hash b/aidl_api/dnsresolver_aidl_interface/13/.hash
new file mode 100644
index 00000000..6b78f7b1
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/13/.hash
@@ -0,0 +1 @@
+a1e64ca6e3e9aafead71a3415d939207725d39d5
diff --git a/aidl_api/dnsresolver_aidl_interface/13/android/net/IDnsResolver.aidl b/aidl_api/dnsresolver_aidl_interface/13/android/net/IDnsResolver.aidl
new file mode 100644
index 00000000..6b539c47
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/13/android/net/IDnsResolver.aidl
@@ -0,0 +1,69 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+interface IDnsResolver {
+ boolean isAlive();
+ void registerEventListener(android.net.metrics.INetdEventListener listener);
+ void setResolverConfiguration(in android.net.ResolverParamsParcel resolverParams);
+ void getResolverInfo(int netId, out @utf8InCpp String[] servers, out @utf8InCpp String[] domains, out @utf8InCpp String[] tlsServers, out int[] params, out int[] stats, out int[] wait_for_pending_req_timeout_count);
+ void startPrefix64Discovery(int netId);
+ void stopPrefix64Discovery(int netId);
+ @utf8InCpp String getPrefix64(int netId);
+ void createNetworkCache(int netId);
+ void destroyNetworkCache(int netId);
+ void setLogSeverity(int logSeverity);
+ void flushNetworkCache(int netId);
+ void setPrefix64(int netId, @utf8InCpp String prefix);
+ void registerUnsolicitedEventListener(android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener listener);
+ void setResolverOptions(int netId, in android.net.ResolverOptionsParcel optionParams);
+ const int RESOLVER_PARAMS_SAMPLE_VALIDITY = 0;
+ const int RESOLVER_PARAMS_SUCCESS_THRESHOLD = 1;
+ const int RESOLVER_PARAMS_MIN_SAMPLES = 2;
+ const int RESOLVER_PARAMS_MAX_SAMPLES = 3;
+ const int RESOLVER_PARAMS_BASE_TIMEOUT_MSEC = 4;
+ const int RESOLVER_PARAMS_RETRY_COUNT = 5;
+ const int RESOLVER_PARAMS_COUNT = 6;
+ const int RESOLVER_STATS_SUCCESSES = 0;
+ const int RESOLVER_STATS_ERRORS = 1;
+ const int RESOLVER_STATS_TIMEOUTS = 2;
+ const int RESOLVER_STATS_INTERNAL_ERRORS = 3;
+ const int RESOLVER_STATS_RTT_AVG = 4;
+ const int RESOLVER_STATS_LAST_SAMPLE_TIME = 5;
+ const int RESOLVER_STATS_USABLE = 6;
+ const int RESOLVER_STATS_COUNT = 7;
+ const int DNS_RESOLVER_LOG_VERBOSE = 0;
+ const int DNS_RESOLVER_LOG_DEBUG = 1;
+ const int DNS_RESOLVER_LOG_INFO = 2;
+ const int DNS_RESOLVER_LOG_WARNING = 3;
+ const int DNS_RESOLVER_LOG_ERROR = 4;
+ const int TC_MODE_DEFAULT = 0;
+ const int TC_MODE_UDP_TCP = 1;
+ const int TRANSPORT_UNKNOWN = (-1) /* -1 */;
+ const int TRANSPORT_CELLULAR = 0;
+ const int TRANSPORT_WIFI = 1;
+ const int TRANSPORT_BLUETOOTH = 2;
+ const int TRANSPORT_ETHERNET = 3;
+ const int TRANSPORT_VPN = 4;
+ const int TRANSPORT_WIFI_AWARE = 5;
+ const int TRANSPORT_LOWPAN = 6;
+ const int TRANSPORT_TEST = 7;
+ const int TRANSPORT_USB = 8;
+ const int TRANSPORT_THREAD = 9;
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/13/android/net/ResolverHostsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/13/android/net/ResolverHostsParcel.aidl
new file mode 100644
index 00000000..2a1c748f
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/13/android/net/ResolverHostsParcel.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+@JavaDerive(equals=true)
+parcelable ResolverHostsParcel {
+ @utf8InCpp String ipAddr;
+ @utf8InCpp String hostName = "";
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/13/android/net/ResolverOptionsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/13/android/net/ResolverOptionsParcel.aidl
new file mode 100644
index 00000000..b07263f8
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/13/android/net/ResolverOptionsParcel.aidl
@@ -0,0 +1,26 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+@JavaDerive(equals=true, toString=true)
+parcelable ResolverOptionsParcel {
+ android.net.ResolverHostsParcel[] hosts = {};
+ int tcMode = 0;
+ boolean enforceDnsUid = false;
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/13/android/net/ResolverParamsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/13/android/net/ResolverParamsParcel.aidl
new file mode 100644
index 00000000..2dd93dd5
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/13/android/net/ResolverParamsParcel.aidl
@@ -0,0 +1,41 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net;
+/* @hide */
+@JavaDerive(equals=true, toString=true)
+parcelable ResolverParamsParcel {
+ int netId;
+ int sampleValiditySeconds;
+ int successThreshold;
+ int minSamples;
+ int maxSamples;
+ int baseTimeoutMsec;
+ int retryCount;
+ @utf8InCpp String[] servers;
+ @utf8InCpp String[] domains;
+ @utf8InCpp String tlsName;
+ @utf8InCpp String[] tlsServers;
+ @utf8InCpp String[] tlsFingerprints = {};
+ @utf8InCpp String caCertificate = "";
+ int tlsConnectTimeoutMs = 0;
+ @nullable android.net.ResolverOptionsParcel resolverOptions;
+ int[] transportTypes = {};
+ boolean meteredNetwork = false;
+ @nullable android.net.resolv.aidl.DohParamsParcel dohParams;
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/13/android/net/resolv/aidl/DnsHealthEventParcel.aidl b/aidl_api/dnsresolver_aidl_interface/13/android/net/resolv/aidl/DnsHealthEventParcel.aidl
new file mode 100644
index 00000000..d32be919
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/13/android/net/resolv/aidl/DnsHealthEventParcel.aidl
@@ -0,0 +1,26 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.resolv.aidl;
+/* @hide */
+@JavaDerive(toString=true)
+parcelable DnsHealthEventParcel {
+ int netId;
+ int healthResult;
+ int[] successRttMicros;
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/13/android/net/resolv/aidl/DohParamsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/13/android/net/resolv/aidl/DohParamsParcel.aidl
new file mode 100644
index 00000000..ba1ea747
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/13/android/net/resolv/aidl/DohParamsParcel.aidl
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.resolv.aidl;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
+parcelable DohParamsParcel {
+ String name = "";
+ String[] ips = {};
+ String dohpath = "";
+ int port = (-1) /* -1 */;
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/13/android/net/resolv/aidl/IDnsResolverUnsolicitedEventListener.aidl b/aidl_api/dnsresolver_aidl_interface/13/android/net/resolv/aidl/IDnsResolverUnsolicitedEventListener.aidl
new file mode 100644
index 00000000..32963dfd
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/13/android/net/resolv/aidl/IDnsResolverUnsolicitedEventListener.aidl
@@ -0,0 +1,33 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.resolv.aidl;
+/* @hide */
+interface IDnsResolverUnsolicitedEventListener {
+ oneway void onDnsHealthEvent(in android.net.resolv.aidl.DnsHealthEventParcel dnsHealthEvent);
+ oneway void onNat64PrefixEvent(in android.net.resolv.aidl.Nat64PrefixEventParcel nat64PrefixEvent);
+ oneway void onPrivateDnsValidationEvent(in android.net.resolv.aidl.PrivateDnsValidationEventParcel privateDnsValidationEvent);
+ const int DNS_HEALTH_RESULT_OK = 0;
+ const int DNS_HEALTH_RESULT_TIMEOUT = 255;
+ const int PREFIX_OPERATION_ADDED = 1;
+ const int PREFIX_OPERATION_REMOVED = 2;
+ const int VALIDATION_RESULT_SUCCESS = 1;
+ const int VALIDATION_RESULT_FAILURE = 2;
+ const int PROTOCOL_DOT = 1;
+ const int PROTOCOL_DOH = 2;
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/13/android/net/resolv/aidl/Nat64PrefixEventParcel.aidl b/aidl_api/dnsresolver_aidl_interface/13/android/net/resolv/aidl/Nat64PrefixEventParcel.aidl
new file mode 100644
index 00000000..2daccb0e
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/13/android/net/resolv/aidl/Nat64PrefixEventParcel.aidl
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.resolv.aidl;
+/* @hide */
+@JavaDerive(toString=true)
+parcelable Nat64PrefixEventParcel {
+ int netId;
+ int prefixOperation;
+ @utf8InCpp String prefixAddress;
+ int prefixLength;
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/13/android/net/resolv/aidl/PrivateDnsValidationEventParcel.aidl b/aidl_api/dnsresolver_aidl_interface/13/android/net/resolv/aidl/PrivateDnsValidationEventParcel.aidl
new file mode 100644
index 00000000..f3bfbc76
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/13/android/net/resolv/aidl/PrivateDnsValidationEventParcel.aidl
@@ -0,0 +1,28 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.resolv.aidl;
+/* @hide */
+@JavaDerive(toString=true)
+parcelable PrivateDnsValidationEventParcel {
+ int netId;
+ @utf8InCpp String ipAddress;
+ @utf8InCpp String hostname;
+ int validation;
+ int protocol;
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/current/android/net/IDnsResolver.aidl b/aidl_api/dnsresolver_aidl_interface/current/android/net/IDnsResolver.aidl
index 19313e40..6b539c47 100644
--- a/aidl_api/dnsresolver_aidl_interface/current/android/net/IDnsResolver.aidl
+++ b/aidl_api/dnsresolver_aidl_interface/current/android/net/IDnsResolver.aidl
@@ -55,7 +55,7 @@ interface IDnsResolver {
const int DNS_RESOLVER_LOG_ERROR = 4;
const int TC_MODE_DEFAULT = 0;
const int TC_MODE_UDP_TCP = 1;
- const int TRANSPORT_UNKNOWN = -1;
+ const int TRANSPORT_UNKNOWN = (-1) /* -1 */;
const int TRANSPORT_CELLULAR = 0;
const int TRANSPORT_WIFI = 1;
const int TRANSPORT_BLUETOOTH = 2;
diff --git a/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverHostsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverHostsParcel.aidl
index c24eb619..2a1c748f 100644
--- a/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverHostsParcel.aidl
+++ b/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverHostsParcel.aidl
@@ -18,6 +18,7 @@
package android.net;
/* @hide */
+@JavaDerive(equals=true)
parcelable ResolverHostsParcel {
@utf8InCpp String ipAddr;
@utf8InCpp String hostName = "";
diff --git a/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverOptionsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverOptionsParcel.aidl
index e806d040..b07263f8 100644
--- a/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverOptionsParcel.aidl
+++ b/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverOptionsParcel.aidl
@@ -18,6 +18,7 @@
package android.net;
/* @hide */
+@JavaDerive(equals=true, toString=true)
parcelable ResolverOptionsParcel {
android.net.ResolverHostsParcel[] hosts = {};
int tcMode = 0;
diff --git a/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverParamsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverParamsParcel.aidl
index 8d0bf75e..2dd93dd5 100644
--- a/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverParamsParcel.aidl
+++ b/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverParamsParcel.aidl
@@ -18,6 +18,7 @@
package android.net;
/* @hide */
+@JavaDerive(equals=true, toString=true)
parcelable ResolverParamsParcel {
int netId;
int sampleValiditySeconds;
@@ -35,4 +36,6 @@ parcelable ResolverParamsParcel {
int tlsConnectTimeoutMs = 0;
@nullable android.net.ResolverOptionsParcel resolverOptions;
int[] transportTypes = {};
+ boolean meteredNetwork = false;
+ @nullable android.net.resolv.aidl.DohParamsParcel dohParams;
}
diff --git a/aidl_api/dnsresolver_aidl_interface/current/android/net/resolv/aidl/DohParamsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/current/android/net/resolv/aidl/DohParamsParcel.aidl
new file mode 100644
index 00000000..ba1ea747
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/current/android/net/resolv/aidl/DohParamsParcel.aidl
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.net.resolv.aidl;
+/* @hide */
+@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
+parcelable DohParamsParcel {
+ String name = "";
+ String[] ips = {};
+ String dohpath = "";
+ int port = (-1) /* -1 */;
+}
diff --git a/binder/android/net/ResolverHostsParcel.aidl b/binder/android/net/ResolverHostsParcel.aidl
index 6b372b18..054fca79 100644
--- a/binder/android/net/ResolverHostsParcel.aidl
+++ b/binder/android/net/ResolverHostsParcel.aidl
@@ -23,6 +23,7 @@ package android.net;
*
* {@hide}
*/
+@JavaDerive(equals=true)
parcelable ResolverHostsParcel {
/**
* The IPv4 or IPv6 address corresponding to |hostName| field.
diff --git a/binder/android/net/ResolverOptionsParcel.aidl b/binder/android/net/ResolverOptionsParcel.aidl
index bca9fb65..dd64cf8c 100644
--- a/binder/android/net/ResolverOptionsParcel.aidl
+++ b/binder/android/net/ResolverOptionsParcel.aidl
@@ -23,6 +23,7 @@ import android.net.ResolverHostsParcel;
*
* {@hide}
*/
+@JavaDerive(equals=true, toString=true)
parcelable ResolverOptionsParcel {
/**
* An IP/hostname mapping table for DNS local lookup customization.
diff --git a/binder/android/net/ResolverParamsParcel.aidl b/binder/android/net/ResolverParamsParcel.aidl
index 5511f281..1aee26bd 100644
--- a/binder/android/net/ResolverParamsParcel.aidl
+++ b/binder/android/net/ResolverParamsParcel.aidl
@@ -17,12 +17,14 @@
package android.net;
import android.net.ResolverOptionsParcel;
+import android.net.resolv.aidl.DohParamsParcel;
/**
* Configuration for a resolver parameters.
*
* {@hide}
*/
+@JavaDerive(equals=true, toString=true)
parcelable ResolverParamsParcel {
/**
* The network ID of the network for which information should be configured.
@@ -113,4 +115,15 @@ parcelable ResolverParamsParcel {
* reasonable network type by DnsResolver, it would be considered as unknown.
*/
int[] transportTypes = {};
+
+ /**
+ * Whether the network is metered or not.
+ */
+ boolean meteredNetwork = false;
+
+ /**
+ * Information about DNS-over-HTTPS servers to use
+ */
+ @nullable
+ DohParamsParcel dohParams;
}
diff --git a/binder/android/net/resolv/aidl/DohParamsParcel.aidl b/binder/android/net/resolv/aidl/DohParamsParcel.aidl
new file mode 100644
index 00000000..d9c05db1
--- /dev/null
+++ b/binder/android/net/resolv/aidl/DohParamsParcel.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.resolv.aidl;
+
+/**
+ * DNS-over-HTTPS configuration parameters. Represents a single DoH server.
+ *
+ * Note that although this parcelable is for DNS-over-HTTPS configuration parameters, there is
+ * no field in this parcelable to specify an exact HTTPS protocol (h2 or h3) because DnsResolver
+ * only supports DNS-over-HTTPS/3. The configuration parameters are for h3.
+ *
+ * {@hide}
+ */
+@JavaDerive(equals=true, toString=true) @JavaOnlyImmutable
+parcelable DohParamsParcel {
+ /**
+ * The server hostname.
+ */
+ String name = "";
+
+ /**
+ * The server IP addresses. They are not sorted.
+ */
+ String[] ips = {};
+
+ /**
+ * A part of the URI template used to construct the URL for DNS resolution.
+ * It's derived only from DNS SVCB SvcParamKey "dohpath".
+ */
+ String dohpath = "";
+
+ /**
+ * The port used to reach the servers.
+ */
+ int port = -1;
+}
diff --git a/doh/boot_time.rs b/doh/boot_time.rs
index 453235ba..666a44de 100644
--- a/doh/boot_time.rs
+++ b/doh/boot_time.rs
@@ -57,8 +57,7 @@ impl BootTime {
/// Gets a `BootTime` representing the current moment in time.
pub fn now() -> BootTime {
let mut t = libc::timespec { tv_sec: 0, tv_nsec: 0 };
- // # Safety
- // clock_gettime's only action will be to possibly write to the pointer provided,
+ // SAFETY: clock_gettime's only action will be to possibly write to the pointer provided,
// and no borrows exist from that object other than the &mut used to construct the pointer
// itself.
if unsafe { libc::clock_gettime(libc::CLOCK_BOOTTIME, &mut t as *mut libc::timespec) } != 0
@@ -93,9 +92,8 @@ struct TimerFd(RawFd);
impl Drop for TimerFd {
fn drop(&mut self) {
- // # Safety
- // The fd is owned by the TimerFd struct, and no memory access occurs as a result of this
- // call.
+ // SAFETY: The fd is owned by the TimerFd struct, and no memory access occurs as a result of
+ // this call.
unsafe {
libc::close(self.0);
}
@@ -110,9 +108,8 @@ impl AsRawFd for TimerFd {
impl TimerFd {
fn create() -> io::Result<Self> {
- // # Unsafe
- // This libc call will either give us back a file descriptor or fail, it does not act on
- // memory or resources.
+ // SAFETY: This libc call will either give us back a file descriptor or fail, it does not
+ // act on memory or resources.
let raw = unsafe {
libc::timerfd_create(libc::CLOCK_BOOTTIME, libc::TFD_NONBLOCK | libc::TFD_CLOEXEC)
};
@@ -131,8 +128,7 @@ impl TimerFd {
tv_nsec: duration.subsec_nanos().try_into().unwrap(),
},
};
- // # Unsafe
- // We own `timer` and there are no borrows to it other than the pointer we pass to
+ // SAFETY: We own `timer` and there are no borrows to it other than the pointer we pass to
// timerfd_settime. timerfd_settime is explicitly documented to handle a null output
// parameter for its fourth argument by not filling out the output. The fd passed in at
// self.0 is owned by the `TimerFd` struct, so we aren't breaking anyone else's invariants.
diff --git a/doh/connection/mod.rs b/doh/connection/mod.rs
index f0b27d79..5898228c 100644
--- a/doh/connection/mod.rs
+++ b/doh/connection/mod.rs
@@ -61,7 +61,7 @@ fn new_scid() -> [u8; quiche::MAX_CONN_ID_LEN] {
fn mark_socket(socket: &std::net::UdpSocket, socket_mark: u32) -> io::Result<()> {
use std::os::unix::io::AsRawFd;
let fd = socket.as_raw_fd();
- // libc::setsockopt is a wrapper function calling into bionic setsockopt.
+ // SAFETY: libc::setsockopt is a wrapper function calling into bionic setsockopt.
// The only pointer being passed in is &socket_mark, which is valid by virtue of being a
// reference, and the foreign function doesn't take ownership or a reference to that memory
// after completion.
diff --git a/doh/ffi.rs b/doh/ffi.rs
index 2276f654..63b98cc8 100644
--- a/doh/ffi.rs
+++ b/doh/ffi.rs
@@ -35,8 +35,12 @@ use tokio::sync::oneshot;
use tokio::task;
use url::Url;
-pub type ValidationCallback =
- extern "C" fn(net_id: uint32_t, success: bool, ip_addr: *const c_char, host: *const c_char);
+pub type ValidationCallback = unsafe extern "C" fn(
+ net_id: uint32_t,
+ success: bool,
+ ip_addr: *const c_char,
+ host: *const c_char,
+);
pub type TagSocketCallback = extern "C" fn(sock: RawFd);
#[repr(C)]
@@ -61,7 +65,9 @@ fn wrap_validation_callback(validation_fn: ValidationCallback) -> ValidationRepo
}
};
let netd_id = info.net_id;
- task::spawn_blocking(move || {
+ // SAFETY: The string pointers are obtained from `CString`, so they must be valid C
+ // strings.
+ task::spawn_blocking(move || unsafe {
validation_fn(netd_id, success, ip_addr.as_ptr(), domain.as_ptr())
})
.await
@@ -167,12 +173,16 @@ pub extern "C" fn doh_dispatcher_new(
}
/// Deletes a DoH engine created by doh_dispatcher_new().
+///
/// # Safety
+///
/// `doh` must be a non-null pointer previously created by `doh_dispatcher_new()`
/// and not yet deleted by `doh_dispatcher_delete()`.
#[no_mangle]
pub unsafe extern "C" fn doh_dispatcher_delete(doh: *mut DohDispatcher) {
- Box::from_raw(doh).lock().exit_handler()
+ // SAFETY: The caller guarantees that `doh` was created by `doh_dispatcher_new` (which does so
+ // using `Box::into_raw`), and that it hasn't yet been deleted by this function.
+ unsafe { Box::from_raw(doh) }.lock().exit_handler()
}
/// Probes and stores the DoH server with the given configurations.
@@ -194,12 +204,15 @@ pub unsafe extern "C" fn doh_net_new(
network_type: uint32_t,
private_dns_mode: uint32_t,
) -> int32_t {
- let (url, domain, ip_addr, cert_path) = match (
- std::ffi::CStr::from_ptr(url).to_str(),
- std::ffi::CStr::from_ptr(domain).to_str(),
- std::ffi::CStr::from_ptr(ip_addr).to_str(),
- std::ffi::CStr::from_ptr(cert_path).to_str(),
- ) {
+ // SAFETY: The caller guarantees that these are all valid nul-terminated C strings.
+ let (url, domain, ip_addr, cert_path) = match unsafe {
+ (
+ std::ffi::CStr::from_ptr(url).to_str(),
+ std::ffi::CStr::from_ptr(domain).to_str(),
+ std::ffi::CStr::from_ptr(ip_addr).to_str(),
+ std::ffi::CStr::from_ptr(cert_path).to_str(),
+ )
+ } {
(Ok(url), Ok(domain), Ok(ip_addr), Ok(cert_path)) => {
if domain.is_empty() {
(url, None, ip_addr.to_string(), None)
@@ -268,7 +281,9 @@ pub unsafe extern "C" fn doh_query(
response_len: size_t,
timeout_ms: uint64_t,
) -> ssize_t {
- let q = slice::from_raw_parts_mut(dns_query, dns_query_len);
+ // SAFETY: The caller guarantees that `dns_query` is a valid pointer to a buffer of at least
+ // `dns_query_len` items.
+ let q = unsafe { slice::from_raw_parts_mut(dns_query, dns_query_len) };
let (resp_tx, resp_rx) = oneshot::channel();
let t = Duration::from_millis(timeout_ms);
@@ -298,7 +313,10 @@ pub unsafe extern "C" fn doh_query(
if answer.len() > response_len || answer.len() > isize::MAX as usize {
return DOH_RESULT_INTERNAL_ERROR;
}
- let response = slice::from_raw_parts_mut(response, answer.len());
+ // SAFETY: The caller guarantees that response points to a valid buffer at
+ // least `response_len` long, and we just checked that `answer.len()` is no
+ // longer than `response_len`.
+ let response = unsafe { slice::from_raw_parts_mut(response, answer.len()) };
response.copy_from_slice(&answer);
answer.len() as ssize_t
}
@@ -341,25 +359,27 @@ mod tests {
const LOOPBACK_ADDR: &str = "127.0.0.1:443";
const LOCALHOST_URL: &str = "https://mylocal.com/dns-query";
- extern "C" fn success_cb(
+ unsafe extern "C" fn success_cb(
net_id: uint32_t,
success: bool,
ip_addr: *const c_char,
host: *const c_char,
) {
assert!(success);
+ // SAFETY: The caller guarantees that ip_addr and host are valid nul-terminated C strings.
unsafe {
assert_validation_info(net_id, ip_addr, host);
}
}
- extern "C" fn fail_cb(
+ unsafe extern "C" fn fail_cb(
net_id: uint32_t,
success: bool,
ip_addr: *const c_char,
host: *const c_char,
) {
assert!(!success);
+ // SAFETY: The caller guarantees that ip_addr and host are valid nul-terminated C strings.
unsafe {
assert_validation_info(net_id, ip_addr, host);
}
@@ -373,10 +393,12 @@ mod tests {
host: *const c_char,
) {
assert_eq!(net_id, TEST_NET_ID);
- let ip_addr = std::ffi::CStr::from_ptr(ip_addr).to_str().unwrap();
+ // SAFETY: The caller guarantees that `ip_addr` is a valid nul-terminated C string.
+ let ip_addr = unsafe { std::ffi::CStr::from_ptr(ip_addr) }.to_str().unwrap();
let expected_addr: SocketAddr = LOOPBACK_ADDR.parse().unwrap();
assert_eq!(ip_addr, expected_addr.ip().to_string());
- let host = std::ffi::CStr::from_ptr(host).to_str().unwrap();
+ // SAFETY: The caller guarantees that `host` is a valid nul-terminated C string.
+ let host = unsafe { std::ffi::CStr::from_ptr(host) }.to_str().unwrap();
assert_eq!(host, "");
}
diff --git a/doh/tests/doh_frontend/src/dns_https_frontend.rs b/doh/tests/doh_frontend/src/dns_https_frontend.rs
index b7d11b7d..d3c538d4 100644
--- a/doh/tests/doh_frontend/src/dns_https_frontend.rs
+++ b/doh/tests/doh_frontend/src/dns_https_frontend.rs
@@ -477,6 +477,9 @@ fn into_tokio_udp_socket(socket: std::net::UdpSocket) -> Result<UdpSocket> {
fn build_pipe() -> Result<(File, File)> {
let mut fds = [0, 0];
+ // SAFETY: The pointer we pass to `pipe` must be valid because it comes from a reference. The
+ // file descriptors it returns must be valid and open, so they are safe to pass to
+ // `File::from_raw_fd`.
unsafe {
if libc::pipe(fds.as_mut_ptr()) == 0 {
return Ok((File::from_raw_fd(fds[0]), File::from_raw_fd(fds[1])));
diff --git a/doh/tests/doh_frontend/src/ffi.rs b/doh/tests/doh_frontend/src/ffi.rs
index 3235d5da..37a5fba0 100644
--- a/doh/tests/doh_frontend/src/ffi.rs
+++ b/doh/tests/doh_frontend/src/ffi.rs
@@ -38,10 +38,14 @@ pub unsafe extern "C" fn frontend_new(
backend_addr: *const c_char,
backend_port: *const c_char,
) -> *mut DohFrontend {
- let addr = CStr::from_ptr(addr).to_str().unwrap();
- let port = CStr::from_ptr(port).to_str().unwrap();
- let backend_addr = CStr::from_ptr(backend_addr).to_str().unwrap();
- let backend_port = CStr::from_ptr(backend_port).to_str().unwrap();
+ // SAFETY: Our caller promises that addr is a valid C string.
+ let addr = unsafe { CStr::from_ptr(addr) }.to_str().unwrap();
+ // SAFETY: Our caller promises that port is a valid C string.
+ let port = unsafe { CStr::from_ptr(port) }.to_str().unwrap();
+ // SAFETY: Our caller promises that backend_addr is a valid C string.
+ let backend_addr = unsafe { CStr::from_ptr(backend_addr) }.to_str().unwrap();
+ // SAFETY: Our caller promises that backend_port is a valid C string.
+ let backend_port = unsafe { CStr::from_ptr(backend_port) }.to_str().unwrap();
let socket_addr = to_socket_addr(addr, port).or_else(logging_and_return_err);
let backend_socket_addr =
@@ -73,13 +77,19 @@ pub extern "C" fn frontend_stop(doh: &mut DohFrontend) -> bool {
/// If the caller has called `frontend_start` to start `DohFrontend`, it has to call
/// call `frontend_stop` to stop the worker thread before deleting the object.
///
+/// The DohFrontend is not set to null pointer, caller needs to do it on its own.
+///
/// # Safety
///
-/// The DohFrontend is not set to null pointer, caller needs to do it on its own.
+/// `doh` must be a pointer either null or previously returned by `frontend_new`, and not yet passed
+/// to `frontend_delete`.
#[no_mangle]
pub unsafe extern "C" fn frontend_delete(doh: *mut DohFrontend) {
if !doh.is_null() {
- drop(Box::from_raw(doh));
+ // SAFETY: Our caller promised that `doh` was either null or previously returned by
+ // `frontend_new`. We just checked that it's not null, so it must have been returned by
+ // `frontend_new`, which obtained it from `Box::into_raw`.
+ drop(unsafe { Box::from_raw(doh) });
}
}
@@ -96,7 +106,8 @@ pub unsafe extern "C" fn frontend_set_certificate(
if certificate.is_null() {
return false;
}
- let certificate = CStr::from_ptr(certificate).to_str().unwrap();
+ // SAFETY: Our caller promises that certificate is a valid C string.
+ let certificate = unsafe { CStr::from_ptr(certificate) }.to_str().unwrap();
doh.set_certificate(certificate).or_else(logging_and_return_err).is_ok()
}
@@ -113,7 +124,8 @@ pub unsafe extern "C" fn frontend_set_private_key(
if private_key.is_null() {
return false;
}
- let private_key = CStr::from_ptr(private_key).to_str().unwrap();
+ // SAFETY: Our caller promises that private_key is a valid C string.
+ let private_key = unsafe { CStr::from_ptr(private_key) }.to_str().unwrap();
doh.set_private_key(private_key).or_else(logging_and_return_err).is_ok()
}
diff --git a/getaddrinfo.cpp b/getaddrinfo.cpp
index 6bae41d7..8d9ed6d4 100644
--- a/getaddrinfo.cpp
+++ b/getaddrinfo.cpp
@@ -1310,8 +1310,7 @@ static int _find_src_addr(const struct sockaddr* addr, struct sockaddr* src_addr
return -1;
}
- if (Experiments::getInstance()->getFlag("skip_4a_query_on_v6_linklocal_addr", 1) &&
- src_addr->sa_family == AF_INET6) {
+ if (src_addr->sa_family == AF_INET6) {
sockaddr_in6* sin6 = reinterpret_cast<sockaddr_in6*>(src_addr);
if (!allow_v6_linklocal && IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
// There is no point in sending an AAAA query because the device does not have a global
@@ -1637,7 +1636,8 @@ QueryResult doQuery(const char* name, res_target* t, ResState* res,
ResState res_temp = res->clone(&event);
int rcode = NOERROR;
- n = res_nsend(&res_temp, {buf, n}, {t->answer.data(), anslen}, &rcode, 0, sleepTimeMs);
+ n = res_nsend(&res_temp, std::span(buf, n), std::span(t->answer.data(), anslen), &rcode, 0,
+ sleepTimeMs);
if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
if (rcode != RCODE_TIMEOUT) rcode = hp->rcode;
// if the query choked with EDNS0, retry without EDNS0
@@ -1646,7 +1646,8 @@ QueryResult doQuery(const char* name, res_target* t, ResState* res,
(res_temp.flags & RES_F_EDNS0ERR)) {
LOG(INFO) << __func__ << ": retry without EDNS0";
n = res_nmkquery(QUERY, name, cl, type, {}, buf, res_temp.netcontext_flags);
- n = res_nsend(&res_temp, {buf, n}, {t->answer.data(), anslen}, &rcode, 0);
+ n = res_nsend(&res_temp, std::span(buf, n), std::span(t->answer.data(), anslen), &rcode,
+ 0);
}
}
diff --git a/res_cache.cpp b/res_cache.cpp
index bf0abdb9..fbe426c8 100644
--- a/res_cache.cpp
+++ b/res_cache.cpp
@@ -154,7 +154,7 @@ using std::span;
* *****************************************
*/
const int MAX_ENTRIES_DEFAULT = 64 * 2 * 5;
-const int MAX_ENTRIES_LOWER_BOUND = 0;
+const int MAX_ENTRIES_LOWER_BOUND = 1;
const int MAX_ENTRIES_UPPER_BOUND = 100 * 1000;
constexpr int DNSEVENT_SUBSAMPLING_MAP_DEFAULT_KEY = -1;
@@ -1065,6 +1065,7 @@ struct NetConfig {
int tc_mode = aidl::android::net::IDnsResolver::TC_MODE_DEFAULT;
bool enforceDnsUid = false;
std::vector<int32_t> transportTypes;
+ bool metered = false;
};
/* gets cache associated with a network, or NULL if none exists */
@@ -1214,7 +1215,7 @@ static void _cache_remove_oldest(Cache* cache) {
return;
}
LOG(DEBUG) << __func__ << ": Cache full - removing oldest";
- res_pquery({oldest->query, oldest->querylen});
+ res_pquery(std::span(oldest->query, oldest->querylen));
_cache_remove_p(cache, lookup);
}
@@ -1318,13 +1319,13 @@ ResolvCacheStatus resolv_cache_lookup(unsigned netid, span<const uint8_t> query,
/* remove stale entries here */
if (now >= e->expires) {
LOG(DEBUG) << __func__ << ": NOT IN CACHE (STALE ENTRY " << *lookup << "DISCARDED)";
- res_pquery({e->query, e->querylen});
+ res_pquery(std::span(e->query, e->querylen));
_cache_remove_p(cache, lookup);
return RESOLV_CACHE_NOTFOUND;
}
*answerlen = e->answerlen;
- if (e->answerlen > answer.size()) {
+ if (e->answerlen > static_cast<ptrdiff_t>(answer.size())) {
/* NOTE: we return UNSUPPORTED if the answer buffer is too short */
LOG(INFO) << __func__ << ": ANSWER TOO LONG";
return RESOLV_CACHE_UNSUPPORTED;
@@ -1642,7 +1643,7 @@ std::vector<std::string> getCustomizedTableByName(const size_t netid, const char
int resolv_set_nameservers(unsigned netid, const std::vector<std::string>& servers,
const std::vector<std::string>& domains, const res_params& params,
const std::optional<ResolverOptionsParcel> optionalResolverOptions,
- const std::vector<int32_t>& transportTypes) {
+ const std::vector<int32_t>& transportTypes, bool metered) {
std::vector<std::string> nameservers = filter_nameservers(servers);
const int numservers = static_cast<int>(nameservers.size());
@@ -1709,6 +1710,7 @@ int resolv_set_nameservers(unsigned netid, const std::vector<std::string>& serve
return -EINVAL;
}
netconfig->transportTypes = transportTypes;
+ netconfig->metered = metered;
if (optionalResolverOptions.has_value()) {
const ResolverOptionsParcel& resolverOptions = optionalResolverOptions.value();
return netconfig->setOptions(resolverOptions);
@@ -2090,6 +2092,7 @@ void resolv_netconfig_dump(DumpWriter& dw, unsigned netid) {
// TODO: dump info->hosts
dw.println("TC mode: %s", tc_mode_to_str(info->tc_mode));
dw.println("TransportType: %s", transport_type_to_str(info->transportTypes));
+ dw.println("Metered: %s", info->metered ? "true" : "false");
}
}
@@ -2101,4 +2104,20 @@ int resolv_get_max_cache_entries(unsigned netid) {
return -1;
}
return info->cache->get_max_cache_entries();
-} \ No newline at end of file
+}
+
+bool resolv_is_enforceDnsUid_enabled_network(unsigned netid) {
+ std::lock_guard guard(cache_mutex);
+ if (const auto info = find_netconfig_locked(netid); info != nullptr) {
+ return info->enforceDnsUid;
+ }
+ return false;
+}
+
+bool resolv_is_metered_network(unsigned netid) {
+ std::lock_guard guard(cache_mutex);
+ if (const auto info = find_netconfig_locked(netid); info != nullptr) {
+ return info->metered;
+ }
+ return false;
+}
diff --git a/res_debug.cpp b/res_debug.cpp
index 848fed59..55356fea 100644
--- a/res_debug.cpp
+++ b/res_debug.cpp
@@ -166,7 +166,7 @@ static void do_section(ns_msg* handle, ns_sect section) {
rdatalen = ns_rr_rdlen(rr);
format_to(out, "; EDNS: version: {}, udp={}, flags={}\n", (rr.ttl >> 16) & 0xff,
- ns_rr_class(rr), rr.ttl & 0xffff);
+ static_cast<int>(ns_rr_class(rr)), rr.ttl & 0xffff);
const uint8_t* cp = ns_rr_rdata(rr);
while (rdatalen <= ns_rr_rdlen(rr) && rdatalen >= 4) {
int i;
diff --git a/res_mkquery.cpp b/res_mkquery.cpp
index 11fbfdb7..24cee30e 100644
--- a/res_mkquery.cpp
+++ b/res_mkquery.cpp
@@ -166,7 +166,7 @@ int res_nmkquery(int op, // opcode of query
/*
* Initialize answer section
*/
- if (ep - cp < 1 + RRFIXEDSZ + data.size()) return (-1);
+ if (ep - cp < static_cast<ptrdiff_t>(1 + RRFIXEDSZ + data.size())) return (-1);
*cp++ = '\0'; /* no domain name */
*reinterpret_cast<uint16_t*>(cp) = htons(type);
cp += INT16SZ;
diff --git a/res_query.cpp b/res_query.cpp
index 036a6e31..be176b6c 100644
--- a/res_query.cpp
+++ b/res_query.cpp
@@ -126,7 +126,7 @@ again:
*herrno = NO_RECOVERY;
return n;
}
- n = res_nsend(statp, {buf, n}, answer, &rcode, 0);
+ n = res_nsend(statp, std::span(buf, n), answer, &rcode, 0);
if (n < 0) {
// If the query choked with EDNS0, retry without EDNS0 that when the server
// has no response, resovler won't retry and do nothing. Even fallback to UDP,
diff --git a/res_send.cpp b/res_send.cpp
index 38b9c6ac..554ace6f 100644
--- a/res_send.cpp
+++ b/res_send.cpp
@@ -491,7 +491,7 @@ int res_nsend(ResState* statp, span<const uint8_t> msg, span<uint8_t> ans, int*
res_pquery(ans.first(resplen));
if (cache_status == RESOLV_CACHE_NOTFOUND) {
- resolv_cache_add(statp->netid, msg, {ans.data(), resplen});
+ resolv_cache_add(statp->netid, msg, std::span(ans.data(), resplen));
}
return resplen;
}
@@ -667,7 +667,7 @@ int res_nsend(ResState* statp, span<const uint8_t> msg, span<uint8_t> ans, int*
res_pquery(ans.first(resplen));
if (cache_status == RESOLV_CACHE_NOTFOUND) {
- resolv_cache_add(statp->netid, msg, {ans.data(), resplen});
+ resolv_cache_add(statp->netid, msg, std::span(ans.data(), resplen));
}
statp->closeSockets();
return (resplen);
@@ -807,7 +807,7 @@ same_ns:
{.iov_base = const_cast<uint8_t*>(msg.data()),
.iov_len = static_cast<size_t>(msg.size())},
};
- if (writev(statp->tcp_nssock, iov, 2) != (INT16SZ + msg.size())) {
+ if (writev(statp->tcp_nssock, iov, 2) != static_cast<ptrdiff_t>(INT16SZ + msg.size())) {
*terrno = errno;
PLOG(DEBUG) << __func__ << ": write failed: ";
statp->closeSockets();
@@ -1111,7 +1111,8 @@ static int send_dg(ResState* statp, res_params* params, span<const uint8_t> msg,
}
LOG(DEBUG) << __func__ << ": new DG socket";
}
- if (send(statp->udpsocks[*ns], msg.data(), msg.size(), 0) != msg.size()) {
+ if (send(statp->udpsocks[*ns], msg.data(), msg.size(), 0) !=
+ static_cast<ptrdiff_t>(msg.size())) {
*terrno = errno;
PLOG(DEBUG) << __func__ << ": send: ";
statp->closeSockets();
@@ -1155,11 +1156,14 @@ static int send_dg(ResState* statp, res_params* params, span<const uint8_t> msg,
*terrno = EMSGSIZE;
continue;
}
+ if (resplen > static_cast<ptrdiff_t>(ans.size())) {
+ LOG(FATAL) << __func__ << ": invalid resplen (too large): " << resplen;
+ }
int receivedFromNs = *ns;
if (needRetry = ignoreInvalidAnswer(statp, from, msg, ans, &receivedFromNs);
needRetry) {
- res_pquery({ans.data(), (resplen > ans.size()) ? ans.size() : resplen});
+ res_pquery(ans.first(resplen));
continue;
}
@@ -1169,7 +1173,7 @@ static int send_dg(ResState* statp, res_params* params, span<const uint8_t> msg,
// The case has to be captured here, as FORMERR packet do not
// carry query section, hence res_queriesmatch() returns 0.
LOG(DEBUG) << __func__ << ": server rejected query with EDNS0:";
- res_pquery({ans.data(), (resplen > ans.size()) ? ans.size() : resplen});
+ res_pquery(ans.first(resplen));
// record the error
statp->flags |= RES_F_EDNS0ERR;
*terrno = EREMOTEIO;
@@ -1178,7 +1182,7 @@ static int send_dg(ResState* statp, res_params* params, span<const uint8_t> msg,
if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP || anhp->rcode == REFUSED) {
LOG(DEBUG) << __func__ << ": server rejected query:";
- res_pquery({ans.data(), (resplen > ans.size()) ? ans.size() : resplen});
+ res_pquery(ans.first(resplen));
*rcode = anhp->rcode;
continue;
}
@@ -1212,7 +1216,8 @@ static int send_mdns(ResState* statp, span<const uint8_t> msg, span<uint8_t> ans
if (setupUdpSocket(statp, mdnsap, &fd, terrno) <= 0) return 0;
- if (sendto(fd, msg.data(), msg.size(), 0, mdnsap, sockaddrSize(mdnsap)) != msg.size()) {
+ if (sendto(fd, msg.data(), msg.size(), 0, mdnsap, sockaddrSize(mdnsap)) !=
+ static_cast<ptrdiff_t>(msg.size())) {
*terrno = errno;
return 0;
}
diff --git a/resolv_cache.h b/resolv_cache.h
index 07697666..18f5b117 100644
--- a/resolv_cache.h
+++ b/resolv_cache.h
@@ -81,7 +81,7 @@ std::vector<std::string> getCustomizedTableByName(const size_t netid, const char
int resolv_set_nameservers(unsigned netid, const std::vector<std::string>& servers,
const std::vector<std::string>& domains, const res_params& params,
std::optional<aidl::android::net::ResolverOptionsParcel> resolverOptions,
- const std::vector<int32_t>& transportTypes = {});
+ const std::vector<int32_t>& transportTypes = {}, bool metered = false);
// Sets options for a given network.
int resolv_set_options(unsigned netid, const aidl::android::net::ResolverOptionsParcel& options);
@@ -143,3 +143,9 @@ void resolv_netconfig_dump(android::netdutils::DumpWriter& dw, unsigned netid);
// Get the maximum cache size of a network.
// Return positive value on success, -1 on failure.
int resolv_get_max_cache_entries(unsigned netid);
+
+// Return true if the enforceDnsUid is enabled on the network.
+bool resolv_is_enforceDnsUid_enabled_network(unsigned netid);
+
+// Return true if the network is metered.
+bool resolv_is_metered_network(unsigned netid);
diff --git a/sethostent.cpp b/sethostent.cpp
index a9b0de6e..55b8c8bc 100644
--- a/sethostent.cpp
+++ b/sethostent.cpp
@@ -69,6 +69,8 @@ int _hf_gethtbyname2(const char* name, int af, getnamaddr* info) {
char* aliases[MAXALIASES];
char* addr_ptrs[MAXADDRS];
+ // TODO: Wrap the 'hf' into a RAII class or std::shared_ptr and modify the
+ // sethostent_r()/endhostent_r() to get rid of manually endhostent_r(&hf) everywhere.
FILE* hf = NULL;
sethostent_r(&hf);
if (hf == NULL) {
@@ -80,6 +82,7 @@ int _hf_gethtbyname2(const char* name, int af, getnamaddr* info) {
}
if ((ptr = buf = (char*) malloc(len = info->buflen)) == NULL) {
+ endhostent_r(&hf);
return EAI_MEMORY;
}
@@ -103,6 +106,7 @@ int _hf_gethtbyname2(const char* name, int af, getnamaddr* info) {
if (hp->h_name == nullptr) {
free(buf);
+ endhostent_r(&hf);
return EAI_FAIL;
}
const char* h_name = hp->h_name;
@@ -131,6 +135,7 @@ int _hf_gethtbyname2(const char* name, int af, getnamaddr* info) {
if (num >= MAXADDRS) goto nospc;
if (hp->h_addr_list[0] == nullptr) {
free(buf);
+ endhostent_r(&hf);
return EAI_FAIL;
}
const char* addr = hp->h_addr_list[0];
@@ -185,6 +190,7 @@ int _hf_gethtbyname2(const char* name, int af, getnamaddr* info) {
free(buf);
return 0;
nospc:
+ endhostent_r(&hf);
free(buf);
return EAI_MEMORY;
}
diff --git a/stats.proto b/stats.proto
index 4052ec7d..1356b7fc 100644
--- a/stats.proto
+++ b/stats.proto
@@ -412,6 +412,9 @@ message NetworkDnsEventReported {
// The sample rate of DNS stats (to statsd) is 1/sampling_rate_denom.
optional int32 sampling_rate_denom = 9;
+
+ // UID sends the DNS query.
+ optional int32 uid = 10;
}
enum HandshakeResult {
diff --git a/tests/Android.bp b/tests/Android.bp
index 72fb008b..b1266037 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -192,21 +192,24 @@ cc_test {
],
static_libs: [
"dnsresolver_aidl_interface-lateststable-ndk",
+ "libc++fs",
"libconnectivity_native_test_utils",
"libcrypto_static",
+ "libcutils",
+ "libdoh_frontend_ffi",
"libgmock",
+ "libip_checksum",
"libmodules-utils-build",
"libnetd_test_dnsresponder_ndk",
"libnetd_test_metrics_listener",
"libnetd_test_resolv_utils",
"libnetdutils",
+ "libnettestutils",
"libssl",
- "libcutils",
+ "libutils",
"netd_aidl_interface-lateststable-ndk",
"netd_event_listener_interface-lateststable-ndk",
- "libip_checksum",
"resolv_unsolicited_listener",
- "libdoh_frontend_ffi",
],
// This test talks to the DnsResolver module over a binary protocol on a socket, so keep it as
// multilib setting is worth because we might be able to get some coverage for the case where
@@ -271,6 +274,7 @@ cc_test {
"libstatslog_resolv",
"libstatspush_compat",
"libsysutils",
+ "libutils",
"resolv_stats_test_utils",
"server_configurable_flags",
"stats_proto",
@@ -377,6 +381,18 @@ cc_defaults {
"server_configurable_flags",
"stats_proto",
],
+ target: {
+ android: {
+ shared_libs: [
+ "libutils",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libutils",
+ ],
+ },
+ },
fuzz_config: {
cc: [
"cken@google.com",
@@ -421,14 +437,12 @@ cc_fuzz {
shared_libs: [
"libbinder_ndk",
"libbinder",
- "libutils",
],
},
host: {
static_libs: [
"libbinder_ndk",
"libbinder",
- "libutils",
],
},
darwin: {
diff --git a/tests/dns_metrics_listener/dns_metrics_listener.cpp b/tests/dns_metrics_listener/dns_metrics_listener.cpp
index 1715118d..c1d4883d 100644
--- a/tests/dns_metrics_listener/dns_metrics_listener.cpp
+++ b/tests/dns_metrics_listener/dns_metrics_listener.cpp
@@ -18,17 +18,13 @@
#include <thread>
-#include <android-base/chrono_utils.h>
#include <android-base/format.h>
-namespace android {
-namespace net {
-namespace metrics {
+namespace android::net::metrics {
using android::base::ScopedLockAssertion;
using std::chrono::milliseconds;
-constexpr milliseconds kRetryIntervalMs{20};
constexpr milliseconds kEventTimeoutMs{5000};
bool DnsMetricsListener::DnsEvent::operator==(const DnsMetricsListener::DnsEvent& o) const {
@@ -49,6 +45,7 @@ std::ostream& operator<<(std::ostream& os, const DnsMetricsListener::DnsEvent& d
std::lock_guard lock(mMutex);
mUnexpectedNat64PrefixUpdates++;
if (netId == mNetId) mNat64Prefix = added ? prefixString : "";
+ mCv.notify_all();
return ::ndk::ScopedAStatus::ok();
}
@@ -60,7 +57,7 @@ std::ostream& operator<<(std::ostream& os, const DnsMetricsListener::DnsEvent& d
// keep updating the server to have latest validation status.
mValidationRecords.insert_or_assign({netId, ipAddress}, validated);
}
- mCv.notify_one();
+ mCv.notify_all();
return ::ndk::ScopedAStatus::ok();
}
@@ -74,39 +71,32 @@ std::ostream& operator<<(std::ostream& os, const DnsMetricsListener::DnsEvent& d
mDnsEventRecords.push(
{netId, eventType, returnCode, hostname, ipAddresses, ipAddressesCount});
}
+ mCv.notify_all();
return ::ndk::ScopedAStatus::ok();
}
bool DnsMetricsListener::waitForNat64Prefix(ExpectNat64PrefixStatus status, milliseconds timeout) {
- android::base::Timer t;
- while (t.duration() < timeout) {
- {
- std::lock_guard lock(mMutex);
- if ((status == EXPECT_FOUND && !mNat64Prefix.empty()) ||
- (status == EXPECT_NOT_FOUND && mNat64Prefix.empty())) {
- mUnexpectedNat64PrefixUpdates--;
- return true;
- }
- }
- std::this_thread::sleep_for(kRetryIntervalMs);
+ std::unique_lock lock(mMutex);
+ ScopedLockAssertion assume_lock(mMutex);
+
+ if (mCv.wait_for(lock, timeout, [&]() REQUIRES(mMutex) {
+ return (status == EXPECT_FOUND && !mNat64Prefix.empty()) ||
+ (status == EXPECT_NOT_FOUND && mNat64Prefix.empty());
+ })) {
+ mUnexpectedNat64PrefixUpdates--;
+ return true;
}
+
+ // Timeout.
return false;
}
bool DnsMetricsListener::waitForPrivateDnsValidation(const std::string& serverAddr,
const bool validated) {
- const auto now = std::chrono::steady_clock::now();
-
std::unique_lock lock(mMutex);
- ScopedLockAssertion assume_lock(mMutex);
-
- // onPrivateDnsValidationEvent() might already be invoked. Search for the record first.
- do {
- if (findAndRemoveValidationRecord({mNetId, serverAddr}, validated)) return true;
- } while (mCv.wait_until(lock, now + kEventTimeoutMs) != std::cv_status::timeout);
-
- // Timeout.
- return false;
+ return mCv.wait_for(lock, kEventTimeoutMs, [&]() REQUIRES(mMutex) {
+ return findAndRemoveValidationRecord({mNetId, serverAddr}, validated);
+ });
}
bool DnsMetricsListener::findAndRemoveValidationRecord(const ServerKey& key, const bool value) {
@@ -119,24 +109,17 @@ bool DnsMetricsListener::findAndRemoveValidationRecord(const ServerKey& key, con
}
std::optional<DnsMetricsListener::DnsEvent> DnsMetricsListener::popDnsEvent() {
- // Wait until the queue is not empty or timeout.
- android::base::Timer t;
- while (t.duration() < milliseconds{1000}) {
- {
- std::lock_guard lock(mMutex);
- if (!mDnsEventRecords.empty()) break;
- }
- std::this_thread::sleep_for(kRetryIntervalMs);
- }
+ std::unique_lock lock(mMutex);
+ ScopedLockAssertion assume_lock(mMutex);
- std::lock_guard lock(mMutex);
- if (mDnsEventRecords.empty()) return std::nullopt;
+ if (!mCv.wait_for(lock, kEventTimeoutMs,
+ [&]() REQUIRES(mMutex) { return !mDnsEventRecords.empty(); })) {
+ return std::nullopt;
+ }
auto ret = mDnsEventRecords.front();
mDnsEventRecords.pop();
return ret;
}
-} // namespace metrics
-} // namespace net
-} // namespace android
+} // namespace android::net::metrics
diff --git a/tests/dns_metrics_listener/dns_metrics_listener.h b/tests/dns_metrics_listener/dns_metrics_listener.h
index ff714664..e34662b2 100644
--- a/tests/dns_metrics_listener/dns_metrics_listener.h
+++ b/tests/dns_metrics_listener/dns_metrics_listener.h
@@ -30,11 +30,8 @@ enum ExpectNat64PrefixStatus : bool {
EXPECT_NOT_FOUND,
};
-namespace android {
-namespace net {
-namespace metrics {
+namespace android::net::metrics {
-// TODO: Perhaps use condition variable but continually polling.
// TODO: Perhaps create a queue to monitor the event changes. That improves the unit test which can
// verify the event count, the event change order, and so on.
class DnsMetricsListener : public BaseMetricsListener {
@@ -131,6 +128,4 @@ class DnsMetricsListener : public BaseMetricsListener {
std::condition_variable mCv;
};
-} // namespace metrics
-} // namespace net
-} // namespace android
+} // namespace android::net::metrics
diff --git a/tests/dns_responder/dns_responder.cpp b/tests/dns_responder/dns_responder.cpp
index c4551ebf..75a2c599 100644
--- a/tests/dns_responder/dns_responder.cpp
+++ b/tests/dns_responder/dns_responder.cpp
@@ -730,7 +730,8 @@ void DNSResponder::requestHandler() {
bool DNSResponder::handleDNSRequest(const char* buffer, ssize_t len, int protocol, char* response,
size_t* response_len) const {
- LOG(DEBUG) << "request: '" << bytesToHexStr({reinterpret_cast<const uint8_t*>(buffer), len})
+ LOG(DEBUG) << "request: '"
+ << bytesToHexStr(std::span(reinterpret_cast<const uint8_t*>(buffer), len))
<< "', on " << dnsproto2str(protocol);
const char* buffer_end = buffer + len;
DNSHeader header;
diff --git a/tests/dns_responder/dns_responder_client_ndk.cpp b/tests/dns_responder/dns_responder_client_ndk.cpp
index ee360dc2..b69ce183 100644
--- a/tests/dns_responder/dns_responder_client_ndk.cpp
+++ b/tests/dns_responder/dns_responder_client_ndk.cpp
@@ -30,6 +30,7 @@ using aidl::android::net::IDnsResolver;
using aidl::android::net::INetd;
using aidl::android::net::ResolverOptionsParcel;
using aidl::android::net::ResolverParamsParcel;
+using aidl::android::net::resolv::aidl::DohParamsParcel;
using android::base::Error;
using android::base::Result;
using android::net::ResolverStats;
@@ -51,6 +52,7 @@ ResolverParams::Builder::Builder() {
mParcel.tlsServers = {kDefaultServer};
mParcel.caCertificate = kCaCert;
mParcel.resolverOptions = ResolverOptionsParcel{}; // optional, must be explicitly set.
+ mParcel.dohParams = std::nullopt;
}
void DnsResponderClient::SetupMappings(unsigned numHosts, const std::vector<std::string>& domains,
@@ -116,22 +118,6 @@ Result<ResolverInfo> DnsResponderClient::getResolverInfo() {
}
bool DnsResponderClient::SetResolversForNetwork(const std::vector<std::string>& servers,
- const std::vector<std::string>& domains,
- std::vector<int> params) {
- params.resize(IDnsResolver::RESOLVER_PARAMS_COUNT);
- std::array<int, IDnsResolver::RESOLVER_PARAMS_COUNT> arr;
- std::copy_n(params.begin(), arr.size(), arr.begin());
- const auto resolverParams = ResolverParams::Builder()
- .setDomains(domains)
- .setDnsServers(servers)
- .setDotServers({})
- .setParams(arr)
- .build();
- const auto rv = mDnsResolvSrv->setResolverConfiguration(resolverParams);
- return rv.isOk();
-}
-
-bool DnsResponderClient::SetResolversForNetwork(const std::vector<std::string>& servers,
const std::vector<std::string>& domains) {
const auto resolverParams = ResolverParams::Builder()
.setDomains(domains)
diff --git a/tests/dns_responder/dns_responder_client_ndk.h b/tests/dns_responder/dns_responder_client_ndk.h
index 1b4ba35d..0713a7ca 100644
--- a/tests/dns_responder/dns_responder_client_ndk.h
+++ b/tests/dns_responder/dns_responder_client_ndk.h
@@ -91,6 +91,15 @@ class ResolverParams {
mParcel.retryCount = params[IDnsResolver::RESOLVER_PARAMS_RETRY_COUNT];
return *this;
}
+ constexpr Builder& setMetered(const bool metered) {
+ mParcel.meteredNetwork = metered;
+ return *this;
+ }
+ constexpr Builder& setDohParams(
+ const aidl::android::net::resolv::aidl::DohParamsParcel& dohParams) {
+ mParcel.dohParams = dohParams;
+ return *this;
+ }
aidl::android::net::ResolverParamsParcel build() { return mParcel; }
private:
@@ -114,11 +123,6 @@ class DnsResponderClient {
static void SetupMappings(unsigned num_hosts, const std::vector<std::string>& domains,
std::vector<Mapping>* mappings);
- // For dns_benchmark built from tm-mainline-prod.
- // TODO: Remove it when possible.
- bool SetResolversForNetwork(const std::vector<std::string>& servers,
- const std::vector<std::string>& domains, std::vector<int> params);
-
// Sets up DnsResolver with given DNS servers. This is used to set up for private DNS off mode.
bool SetResolversForNetwork(const std::vector<std::string>& servers = {kDefaultServer},
const std::vector<std::string>& domains = {kDefaultSearchDomain});
diff --git a/tests/dnsresolver_binder_test.cpp b/tests/dnsresolver_binder_test.cpp
index dc30f71f..799e16a6 100644
--- a/tests/dnsresolver_binder_test.cpp
+++ b/tests/dnsresolver_binder_test.cpp
@@ -37,6 +37,7 @@
#include <gtest/gtest.h>
#include <netdutils/NetNativeTestBase.h>
#include <netdutils/Stopwatch.h>
+#include <nettestutils/DumpService.h>
#include <util.h>
#include "dns_metrics_listener/base_metrics_listener.h"
@@ -52,7 +53,9 @@ using aidl::android::net::ResolverHostsParcel;
using aidl::android::net::ResolverOptionsParcel;
using aidl::android::net::ResolverParamsParcel;
using aidl::android::net::metrics::INetdEventListener;
+using aidl::android::net::resolv::aidl::DohParamsParcel;
using android::base::ReadFdToString;
+using android::base::StringReplace;
using android::base::unique_fd;
using android::net::ResolverStats;
using android::net::metrics::TestOnDnsEvent;
@@ -63,37 +66,6 @@ using android::netdutils::Stopwatch;
// Sync from TEST_NETID in dns_responder_client.cpp as resolv_integration_test.cpp does.
constexpr int TEST_NETID = 30;
-namespace {
-
-std::vector<std::string> dumpService(ndk::SpAIBinder binder) {
- unique_fd localFd, remoteFd;
- bool success = Pipe(&localFd, &remoteFd);
- EXPECT_TRUE(success) << "Failed to open pipe for dumping: " << strerror(errno);
- if (!success) return {};
-
- // dump() blocks until another thread has consumed all its output.
- std::thread dumpThread = std::thread([binder, remoteFd{std::move(remoteFd)}]() {
- EXPECT_EQ(STATUS_OK, AIBinder_dump(binder.get(), remoteFd, nullptr, 0));
- });
-
- std::string dumpContent;
-
- EXPECT_TRUE(ReadFdToString(localFd.get(), &dumpContent))
- << "Error during dump: " << strerror(errno);
- dumpThread.join();
-
- std::stringstream dumpStream(std::move(dumpContent));
- std::vector<std::string> lines;
- std::string line;
- while (std::getline(dumpStream, line)) {
- lines.push_back(std::move(line));
- }
-
- return lines;
-}
-
-} // namespace
-
class DnsResolverBinderTest : public NetNativeTestBase {
public:
DnsResolverBinderTest() {
@@ -118,7 +90,10 @@ class DnsResolverBinderTest : public NetNativeTestBase {
// This could happen when the test isn't running as root, or if netd isn't running.
assert(nullptr != netdBinder.get());
// Send the service dump request to netd.
- std::vector<std::string> lines = dumpService(netdBinder);
+ std::vector<std::string> lines;
+ const android::status_t ret =
+ dumpService(netdBinder, /*args=*/nullptr, /*num_args=*/0, lines);
+ ASSERT_EQ(android::OK, ret) << "Error dumping service: " << android::statusToString(ret);
// Basic regexp to match dump output lines. Matches the beginning and end of the line, and
// puts the output of the command itself into the first match group.
@@ -142,7 +117,6 @@ class DnsResolverBinderTest : public NetNativeTestBase {
// information. To keep it working on Q/R/..., remove what has been
// added for now. TODO(b/266248339)
std::string output = match[1].str();
- using android::base::StringReplace;
output = StringReplace(output, "(null)", "", /*all=*/true);
output = StringReplace(output, "<unimplemented>", "", /*all=*/true);
output = StringReplace(output, "<interface>", "", /*all=*/true);
@@ -198,45 +172,12 @@ class DnsResolverBinderTest : public NetNativeTestBase {
LogData withoutPacel;
};
- std::string toString(const std::vector<ResolverHostsParcel>& parms) {
- std::string o;
- const size_t size = parms.size();
- for (size_t i = 0; i < size; ++i) {
- o.append(fmt::format("ResolverHostsParcel{{ipAddr: {}, hostName: {}}}", parms[i].ipAddr,
- parms[i].hostName));
- if (i + 1 < size) o.append(", ");
- }
- return o;
- }
-
- std::string toString(const std::optional<ResolverOptionsParcel>& parms) {
- if (!parms.has_value()) return "(null)";
- return fmt::format("ResolverOptionsParcel{{hosts: [{}], tcMode: {}, enforceDnsUid: {}}}",
- toString(parms->hosts), parms->tcMode, parms->enforceDnsUid);
- }
-
- std::string toString(const ResolverParamsParcel& parms) {
- return fmt::format(
- "ResolverParamsParcel{{netId: {}, sampleValiditySeconds: {}, successThreshold: {}, "
- "minSamples: {}, "
- "maxSamples: {}, baseTimeoutMsec: {}, retryCount: {}, "
- "servers: [{}], domains: [{}], "
- "tlsName: {}, tlsServers: [{}], "
- "tlsFingerprints: [{}], "
- "caCertificate: {}, tlsConnectTimeoutMs: {}, "
- "resolverOptions: {}, transportTypes: [{}]}}",
- parms.netId, parms.sampleValiditySeconds, parms.successThreshold, parms.minSamples,
- parms.maxSamples, parms.baseTimeoutMsec, parms.retryCount,
- fmt::join(parms.servers, ", "), fmt::join(parms.domains, ", "), parms.tlsName,
- fmt::join(parms.tlsServers, ", "), fmt::join(parms.tlsFingerprints, ", "),
- android::base::StringReplace(parms.caCertificate, "\n", "\\n", true),
- parms.tlsConnectTimeoutMs, toString(parms.resolverOptions),
- fmt::join(parms.transportTypes, ", "));
- }
-
PossibleLogData toSetResolverConfigurationLogData(const ResolverParamsParcel& parms,
int returnCode = 0) {
- std::string outputWithParcel = "setResolverConfiguration(" + toString(parms) + ")";
+ // Replace "\n" with "\\n" in parms.caCertificate.
+ std::string outputWithParcel =
+ fmt::format("setResolverConfiguration({})",
+ StringReplace(parms.toString(), "\n", "\\n", /*all=*/true));
std::string hintRegexWithParcel = fmt::format("setResolverConfiguration.*{}", parms.netId);
std::string outputWithoutParcel = "setResolverConfiguration()";
@@ -498,6 +439,40 @@ TEST_F(DnsResolverBinderTest, SetResolverConfiguration_TransportTypes_Default) {
EXPECT_THAT(str, HasSubstr("UNKNOWN"));
}
+TEST_F(DnsResolverBinderTest, SetResolverConfiguration_DohParams) {
+ const auto paramsWithoutDohParams = ResolverParams::Builder().build();
+ ::ndk::ScopedAStatus status = mDnsResolver->setResolverConfiguration(paramsWithoutDohParams);
+ EXPECT_TRUE(status.isOk()) << status.getMessage();
+ mExpectedLogDataWithPacel.push_back(toSetResolverConfigurationLogData(paramsWithoutDohParams));
+
+ const DohParamsParcel dohParams = {
+ .name = "doh.google",
+ .ips = {"1.2.3.4", "2001:db8::2"},
+ .dohpath = "/dns-query{?dns}",
+ .port = 443,
+ };
+ const auto paramsWithDohParams = ResolverParams::Builder().setDohParams(dohParams).build();
+ status = mDnsResolver->setResolverConfiguration(paramsWithDohParams);
+ EXPECT_TRUE(status.isOk()) << status.getMessage();
+ mExpectedLogDataWithPacel.push_back(toSetResolverConfigurationLogData(paramsWithDohParams));
+}
+
+class MeteredNetworkParameterizedTest : public DnsResolverBinderTest,
+ public testing::WithParamInterface<bool> {};
+
+INSTANTIATE_TEST_SUITE_P(SetResolverConfigurationTest, MeteredNetworkParameterizedTest,
+ testing::Bool(), [](const testing::TestParamInfo<bool>& info) {
+ return info.param ? "Metered" : "NotMetered";
+ });
+
+TEST_P(MeteredNetworkParameterizedTest, MeteredTest) {
+ const auto resolverParams = ResolverParams::Builder().setMetered(GetParam()).build();
+ ::ndk::ScopedAStatus status = mDnsResolver->setResolverConfiguration(resolverParams);
+ EXPECT_TRUE(status.isOk()) << status.getMessage();
+
+ mExpectedLogDataWithPacel.push_back(toSetResolverConfigurationLogData(resolverParams));
+}
+
TEST_F(DnsResolverBinderTest, GetResolverInfo) {
std::vector<std::string> servers = {"127.0.0.1", "127.0.0.2"};
std::vector<std::string> domains = {"example.com"};
@@ -640,9 +615,9 @@ TEST_F(DnsResolverBinderTest, SetResolverOptions) {
options.enforceDnsUid = true;
EXPECT_TRUE(mDnsResolver->setResolverOptions(TEST_NETID, options).isOk());
mExpectedLogData.push_back(
- {"setResolverOptions(30, " + toString(options) + ")", "setResolverOptions.*30"});
+ {"setResolverOptions(30, " + options.toString() + ")", "setResolverOptions.*30"});
EXPECT_EQ(ENONET, mDnsResolver->setResolverOptions(-1, options).getServiceSpecificError());
- mExpectedLogData.push_back({"setResolverOptions(-1, " + toString(options) +
+ mExpectedLogData.push_back({"setResolverOptions(-1, " + options.toString() +
") -> ServiceSpecificException(64, \"Machine is not on the "
"network\")",
"setResolverOptions.*-1.*64"});
diff --git a/tests/doh_ffi_test.cpp b/tests/doh_ffi_test.cpp
index 0e51402a..6d5b0492 100644
--- a/tests/doh_ffi_test.cpp
+++ b/tests/doh_ffi_test.cpp
@@ -73,7 +73,7 @@ bool haveIpv6() {
class DoHFFITest : public NetNativeTestBase {
public:
- static void SetUpTestSuite() { doh_init_logger(DOH_LOG_LEVEL_DEBUG); }
+ static void SetUpTestSuite() { doh_init_logger(DOH_LOG_LEVEL_TRACE); }
};
TEST_F(DoHFFITest, SmokeTest) {
diff --git a/tests/resolv_cache_unit_test.cpp b/tests/resolv_cache_unit_test.cpp
index 49ccab87..ef9ecb30 100644
--- a/tests/resolv_cache_unit_test.cpp
+++ b/tests/resolv_cache_unit_test.cpp
@@ -50,7 +50,7 @@ constexpr int DNS_PORT = 53;
// Constant values sync'd from res_cache.cpp
constexpr int DNS_HEADER_SIZE = 12;
constexpr int MAX_ENTRIES_DEFAULT = 64 * 2 * 5;
-constexpr int MAX_ENTRIES_LOWER_BOUND = 0;
+constexpr int MAX_ENTRIES_LOWER_BOUND = 1;
constexpr int MAX_ENTRIES_UPPER_BOUND = 100 * 1000;
namespace {
@@ -66,6 +66,7 @@ struct SetupParams {
res_params params;
aidl::android::net::ResolverOptionsParcel resolverOptions;
std::vector<int32_t> transportTypes;
+ bool metered;
};
struct CacheStats {
@@ -206,7 +207,7 @@ class ResolvCacheTest : public NetNativeTestBase {
int cacheSetupResolver(uint32_t netId, const SetupParams& setup) {
return resolv_set_nameservers(netId, setup.servers, setup.domains, setup.params,
- setup.resolverOptions, setup.transportTypes);
+ setup.resolverOptions, setup.transportTypes, setup.metered);
}
void cacheAddStats(uint32_t netId, int revision_id, const IPSockAddr& ipsa,
@@ -630,9 +631,6 @@ class ResolvCacheParameterizedTest : public ResolvCacheTest,
INSTANTIATE_TEST_SUITE_P(MaxCacheEntries, ResolvCacheParameterizedTest,
testing::Values(MAX_ENTRIES_LOWER_BOUND - 1, MAX_ENTRIES_UPPER_BOUND + 1),
[](const testing::TestParamInfo<int>& info) {
- if (info.param < 0) { // '-' is an invalid character in test name
- return "negative_" + std::to_string(abs(info.param));
- }
return std::to_string(info.param);
});
@@ -931,6 +929,72 @@ TEST_F(ResolvCacheTest, GetResolverStats) {
}
}
+TEST_F(ResolvCacheTest, IsEnforceDnsUidEnabled) {
+ const SetupParams unenforcedDnsUidCfg = {
+ .servers = {"127.0.0.1", "::127.0.0.2", "fe80::3"},
+ .domains = {"domain1.com", "domain2.com"},
+ .params = kParams,
+ };
+ // Network #1
+ EXPECT_EQ(0, cacheCreate(TEST_NETID));
+ EXPECT_EQ(0, cacheSetupResolver(TEST_NETID, unenforcedDnsUidCfg));
+ EXPECT_FALSE(resolv_is_enforceDnsUid_enabled_network(TEST_NETID));
+
+ // Network #2
+ EXPECT_EQ(0, cacheCreate(TEST_NETID + 1));
+ EXPECT_EQ(0, cacheSetupResolver(TEST_NETID + 1, unenforcedDnsUidCfg));
+ EXPECT_FALSE(resolv_is_enforceDnsUid_enabled_network(TEST_NETID + 1));
+
+ // Change the enforceDnsUid setting on network #1
+ const SetupParams enforcedDnsUidCfg = {
+ .servers = {"127.0.0.1", "::127.0.0.2", "fe80::3"},
+ .domains = {"domain1.com", "domain2.com"},
+ .params = kParams,
+ .resolverOptions = {.enforceDnsUid = true},
+ };
+ EXPECT_EQ(0, cacheSetupResolver(TEST_NETID, enforcedDnsUidCfg));
+ EXPECT_TRUE(resolv_is_enforceDnsUid_enabled_network(TEST_NETID));
+
+ // Network #2 is unaffected
+ EXPECT_FALSE(resolv_is_enforceDnsUid_enabled_network(TEST_NETID + 1));
+
+ // Returns false on non-existent network
+ EXPECT_FALSE(resolv_is_enforceDnsUid_enabled_network(TEST_NETID + 2));
+}
+
+TEST_F(ResolvCacheTest, IsNetworkMetered) {
+ const SetupParams defaultCfg = {
+ .servers = {"127.0.0.1"},
+ .domains = {"domain1.com"},
+ .params = kParams,
+ };
+ // Network #1
+ EXPECT_EQ(0, cacheCreate(TEST_NETID));
+ EXPECT_EQ(0, cacheSetupResolver(TEST_NETID, defaultCfg));
+ EXPECT_FALSE(resolv_is_metered_network(TEST_NETID));
+
+ // Network #2
+ EXPECT_EQ(0, cacheCreate(TEST_NETID + 1));
+ EXPECT_EQ(0, cacheSetupResolver(TEST_NETID + 1, defaultCfg));
+ EXPECT_FALSE(resolv_is_metered_network(TEST_NETID + 1));
+
+ // Change the metered setting on network #1
+ const SetupParams meteredCfg = {
+ .servers = {"127.0.0.1"},
+ .domains = {"domain1.com"},
+ .params = kParams,
+ .metered = true,
+ };
+ EXPECT_EQ(0, cacheSetupResolver(TEST_NETID, meteredCfg));
+ EXPECT_TRUE(resolv_is_metered_network(TEST_NETID));
+
+ // Network #2 is unaffected
+ EXPECT_FALSE(resolv_is_metered_network(TEST_NETID + 1));
+
+ // Returns false on non-existent network
+ EXPECT_FALSE(resolv_is_metered_network(TEST_NETID + 2));
+}
+
namespace {
constexpr int EAI_OK = 0;
diff --git a/tests/resolv_integration_test.cpp b/tests/resolv_integration_test.cpp
index e4f26fad..ef2bf1e5 100644
--- a/tests/resolv_integration_test.cpp
+++ b/tests/resolv_integration_test.cpp
@@ -48,6 +48,7 @@
#include <algorithm>
#include <chrono>
+#include <functional>
#include <iterator>
#include <numeric>
#include <string_view>
@@ -126,6 +127,8 @@ using android::netdutils::ScopedAddrinfo;
using android::netdutils::Stopwatch;
using android::netdutils::toHex;
+namespace fs = std::filesystem;
+
namespace {
std::pair<ScopedAddrinfo, int> safe_getaddrinfo_time_taken(const char* node, const char* service,
@@ -859,6 +862,7 @@ TEST_F(ResolverTest, GetAddrInfoV4_deferred_resp) {
addrinfo hints = {.ai_family = AF_INET};
const std::array<int, IDnsResolver::RESOLVER_PARAMS_COUNT> params = {300, 25, 8, 8, 5000, 0};
bool t3_task_done = false;
+ bool t2_sv_setup_done = false;
dns1.setDeferredResp(true);
std::thread t1([&, this]() {
@@ -883,6 +887,7 @@ TEST_F(ResolverTest, GetAddrInfoV4_deferred_resp) {
.setDotServers({})
.setParams(params)
.build()));
+ t2_sv_setup_done = true;
ScopedAddrinfo result = safe_getaddrinfo(host_name_deferred, nullptr, &hints);
EXPECT_TRUE(t3_task_done);
EXPECT_EQ(0U, GetNumQueries(dns2, host_name_deferred));
@@ -894,7 +899,7 @@ TEST_F(ResolverTest, GetAddrInfoV4_deferred_resp) {
});
// ensuring t2 and t3 handler functions are processed in order
- usleep(100 * 1000);
+ EXPECT_TRUE(PollForCondition([&]() { return t2_sv_setup_done; }));
std::thread t3([&, this]() {
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(ResolverParams::Builder()
.setDnsServers(servers_for_t3)
@@ -4098,54 +4103,46 @@ TEST_F(ResolverTest, GetHostByName2_Dns64QuerySpecialUseIPv4Addresses) {
TEST_F(ResolverTest, PrefixDiscoveryBypassTls) {
constexpr char listen_addr[] = "::1";
- constexpr char cleartext_port[] = "53";
- constexpr char tls_port[] = "853";
constexpr char dns64_name[] = "ipv4only.arpa.";
const std::vector<std::string> servers = {listen_addr};
test::DNSResponder dns(listen_addr);
StartDns(dns, {{dns64_name, ns_type::ns_t_aaaa, "64:ff9b::192.0.0.170"}});
- test::DnsTlsFrontend tls(listen_addr, tls_port, listen_addr, cleartext_port);
+ test::DnsTlsFrontend tls(listen_addr, "853", listen_addr, "53");
ASSERT_TRUE(tls.startServer());
- // Setup OPPORTUNISTIC mode and wait for the validation complete.
- ASSERT_TRUE(mDnsClient.SetResolversFromParcel(
- ResolverParams::Builder().setDnsServers(servers).setDotServers(servers).build()));
- EXPECT_TRUE(WaitForPrivateDnsValidation(tls.listen_address(), true));
- EXPECT_TRUE(tls.waitForQueries(1));
- tls.clearQueries();
+ for (const std::string_view dnsMode : {"OPPORTUNISTIC", "STRICT"}) {
+ SCOPED_TRACE(fmt::format("testConfig: [{}]", dnsMode));
+ auto builder = ResolverParams::Builder().setDnsServers(servers).setDotServers(servers);
+ if (dnsMode == "STRICT") {
+ builder.setPrivateDnsProvider(kDefaultPrivateDnsHostName);
+ }
+ ASSERT_TRUE(mDnsClient.SetResolversFromParcel(builder.build()));
+ EXPECT_TRUE(WaitForPrivateDnsValidation(tls.listen_address(), true));
+ EXPECT_TRUE(tls.waitForQueries(1));
+ tls.clearQueries();
- // Start NAT64 prefix discovery and wait for it complete.
- EXPECT_TRUE(mDnsClient.resolvService()->startPrefix64Discovery(TEST_NETID).isOk());
- EXPECT_TRUE(WaitForNat64Prefix(EXPECT_FOUND));
+ // Start NAT64 prefix discovery.
+ EXPECT_TRUE(mDnsClient.resolvService()->startPrefix64Discovery(TEST_NETID).isOk());
+ EXPECT_TRUE(WaitForNat64Prefix(EXPECT_FOUND));
- // Verify it bypassed TLS even though there's a TLS server available.
- EXPECT_EQ(0, tls.queries()) << dns.dumpQueries();
- EXPECT_EQ(1U, GetNumQueries(dns, dns64_name)) << dns.dumpQueries();
+ // Verify that the DNS query for the NAT64 prefix bypassed private DNS.
+ EXPECT_EQ(0, tls.queries()) << dns.dumpQueries();
+ EXPECT_EQ(1U, GetNumQueries(dns, dns64_name)) << dns.dumpQueries();
- // Restart the testing network to reset the cache.
- mDnsClient.TearDown();
- mDnsClient.SetUp();
- dns.clearQueries();
+ // Stop the prefix discovery to make DnsResolver send the prefix-removed event
+ // earlier. Without this, DnsResolver still sends the event once the network
+ // is destroyed; however, it will fail the next test if the test unexpectedly
+ // receives the event that it doesn't want.
+ EXPECT_TRUE(mDnsClient.resolvService()->stopPrefix64Discovery(TEST_NETID).isOk());
+ EXPECT_TRUE(WaitForNat64Prefix(EXPECT_NOT_FOUND));
- // Setup STRICT mode and wait for the validation complete.
- ASSERT_TRUE(mDnsClient.SetResolversFromParcel(
- ResolverParams::Builder()
- .setDnsServers(servers)
- .setDotServers(servers)
- .setPrivateDnsProvider(kDefaultPrivateDnsHostName)
- .build()));
- EXPECT_TRUE(WaitForPrivateDnsValidation(tls.listen_address(), true));
- EXPECT_TRUE(tls.waitForQueries(1));
- tls.clearQueries();
-
- // Start NAT64 prefix discovery and wait for it to complete.
- EXPECT_TRUE(mDnsClient.resolvService()->startPrefix64Discovery(TEST_NETID).isOk());
- EXPECT_TRUE(WaitForNat64Prefix(EXPECT_FOUND));
+ dns.clearQueries();
+ EXPECT_TRUE(mDnsClient.resolvService()->flushNetworkCache(TEST_NETID).isOk());
+ }
- // Verify it bypassed TLS despite STRICT mode.
- EXPECT_EQ(0, tls.queries()) << dns.dumpQueries();
- EXPECT_EQ(1U, GetNumQueries(dns, dns64_name)) << dns.dumpQueries();
+ EXPECT_EQ(0, sDnsMetricsListener->getUnexpectedNat64PrefixUpdates());
+ EXPECT_EQ(0, sUnsolicitedEventListener->getUnexpectedNat64PrefixUpdates());
}
TEST_F(ResolverTest, SetAndClearNat64Prefix) {
@@ -4510,9 +4507,9 @@ TEST_F(ResolverTest, GetAddrinfo_BlockDnsQueryWithUidRule) {
const char* hname;
const int expectedErrorCode;
} kTestData[] = {
- {host_name, EAI_NODATA},
+ {host_name, (isAtLeastT() && fs::exists(DNS_HELPER)) ? EAI_FAIL : EAI_NODATA},
// To test the query with search domain.
- {"howdy", EAI_AGAIN},
+ {"howdy", (isAtLeastT() && fs::exists(DNS_HELPER)) ? EAI_FAIL : EAI_AGAIN},
};
INetd* netdService = mDnsClient.netdService();
@@ -4830,77 +4827,76 @@ TEST_F(ResolverTest, ConnectTlsServerTimeout_ConcurrentQueries) {
}
}
+// Tests that the DoT query timeout is configurable via the feature flag "dot_query_timeout_ms".
+// The test DoT server is configured to postpone DNS queries for DOT_SERVER_UNRESPONSIVE_TIME_MS
+// (2s). If the feature flag is set to a positive value smaller than
+// DOT_SERVER_UNRESPONSIVE_TIME_MS, DoT queries should timeout.
TEST_F(ResolverTest, QueryTlsServerTimeout) {
- constexpr uint32_t cacheFlag = ANDROID_RESOLV_NO_CACHE_LOOKUP;
- constexpr int INFINITE_QUERY_TIMEOUT = -1;
- constexpr int DOT_SERVER_UNRESPONSIVE_TIME_MS = 5000;
+ constexpr int DOT_SERVER_UNRESPONSIVE_TIME_MS = 2000;
+ constexpr int TIMING_TOLERANCE_MS = 200;
constexpr char hostname1[] = "query1.example.com.";
- constexpr char hostname2[] = "query2.example.com.";
const std::vector<DnsRecord> records = {
{hostname1, ns_type::ns_t_a, "1.2.3.4"},
- {hostname2, ns_type::ns_t_a, "1.2.3.5"},
};
- for (const int queryTimeoutMs : {INFINITE_QUERY_TIMEOUT, 1000}) {
- for (const std::string_view dnsMode : {"OPPORTUNISTIC", "STRICT"}) {
- SCOPED_TRACE(fmt::format("testConfig: [{}] [{}]", dnsMode, queryTimeoutMs));
-
- const std::string addr = getUniqueIPv4Address();
- test::DNSResponder dns(addr);
- StartDns(dns, records);
- test::DnsTlsFrontend tls(addr, "853", addr, "53");
- ASSERT_TRUE(tls.startServer());
+ static const struct TestConfig {
+ std::string dnsMode;
+ int queryTimeoutMs;
+ int expectResultTimedOut;
+ int expectedTimeTakenMs;
+ } testConfigs[] = {
+ // clang-format off
+ {"OPPORTUNISTIC", -1, false, DOT_SERVER_UNRESPONSIVE_TIME_MS},
+ {"OPPORTUNISTIC", 1000, false, 1000},
+ {"STRICT", -1, false, DOT_SERVER_UNRESPONSIVE_TIME_MS},
+ // `expectResultTimedOut` is true in the following testcase because in strict mode
+ // DnsResolver doesn't try Do53 servers after the DoT query is timed out.
+ {"STRICT", 1000, true, 1000},
+ // clang-format on
+ };
+ for (const auto& config : testConfigs) {
+ SCOPED_TRACE(fmt::format("testConfig: [{}] [{}]", config.dnsMode, config.queryTimeoutMs));
- ScopedSystemProperties sp(kDotQueryTimeoutMsFlag, std::to_string(queryTimeoutMs));
+ const std::string addr = getUniqueIPv4Address();
+ test::DNSResponder dns(addr);
+ StartDns(dns, records);
+ test::DnsTlsFrontend tls(addr, "853", addr, "53");
+ ASSERT_TRUE(tls.startServer());
- // Don't skip unusable DoT servers and disable revalidation for this test.
- ScopedSystemProperties sp2(kDotXportUnusableThresholdFlag, "-1");
- ScopedSystemProperties sp3(kDotRevalidationThresholdFlag, "-1");
- resetNetwork();
+ ScopedSystemProperties sp(kDotQueryTimeoutMsFlag, std::to_string(config.queryTimeoutMs));
- auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
- parcel.servers = {addr};
- parcel.tlsServers = {addr};
- if (dnsMode == "STRICT") parcel.tlsName = kDefaultPrivateDnsHostName;
+ // Don't skip unusable DoT servers and disable revalidation for this test.
+ ScopedSystemProperties sp2(kDotXportUnusableThresholdFlag, "-1");
+ ScopedSystemProperties sp3(kDotRevalidationThresholdFlag, "-1");
+ resetNetwork();
- ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- EXPECT_TRUE(WaitForPrivateDnsValidation(tls.listen_address(), true));
- EXPECT_TRUE(tls.waitForQueries(1));
- tls.clearQueries();
+ auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
+ parcel.servers = {addr};
+ parcel.tlsServers = {addr};
+ if (config.dnsMode == "STRICT") parcel.tlsName = kDefaultPrivateDnsHostName;
- // Set the DoT server to be unresponsive to DNS queries until either it receives
- // 2 queries or 5s later.
- tls.setDelayQueries(2);
- tls.setDelayQueriesTimeout(DOT_SERVER_UNRESPONSIVE_TIME_MS);
+ ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
+ EXPECT_TRUE(WaitForPrivateDnsValidation(tls.listen_address(), true));
+ EXPECT_TRUE(tls.waitForQueries(1));
+ tls.clearQueries();
- // First query.
- Stopwatch s;
- int fd = resNetworkQuery(TEST_NETID, hostname1, ns_c_in, ns_t_a, cacheFlag);
- if (dnsMode == "STRICT" && queryTimeoutMs != INFINITE_QUERY_TIMEOUT) {
- expectAnswersNotValid(fd, -ETIMEDOUT);
- } else {
- expectAnswersValid(fd, AF_INET, "1.2.3.4");
- }
+ // Set the DoT server to be unresponsive to DNS queries for
+ // `DOT_SERVER_UNRESPONSIVE_TIME_MS` ms.
+ tls.setDelayQueries(999);
+ tls.setDelayQueriesTimeout(DOT_SERVER_UNRESPONSIVE_TIME_MS);
- // Besides checking the result of the query, check how much time the
- // resolver processed the query.
- int timeTakenMs = s.getTimeAndResetUs() / 1000;
- const int expectedTimeTakenMs = (queryTimeoutMs == INFINITE_QUERY_TIMEOUT)
- ? DOT_SERVER_UNRESPONSIVE_TIME_MS
- : queryTimeoutMs;
- EXPECT_GE(timeTakenMs, expectedTimeTakenMs);
- EXPECT_LE(timeTakenMs, expectedTimeTakenMs + 1000);
-
- // Second query.
- tls.setDelayQueries(1);
- fd = resNetworkQuery(TEST_NETID, hostname2, ns_c_in, ns_t_a, cacheFlag);
- expectAnswersValid(fd, AF_INET, "1.2.3.5");
-
- // Also check how much time the resolver processed the query.
- timeTakenMs = s.timeTakenUs() / 1000;
- EXPECT_LE(timeTakenMs, 500);
- EXPECT_TRUE(tls.waitForQueries(2));
+ // Send a DNS query, and then check the result and the response time.
+ Stopwatch s;
+ int fd = resNetworkQuery(TEST_NETID, hostname1, ns_c_in, ns_t_a,
+ ANDROID_RESOLV_NO_CACHE_LOOKUP);
+ if (config.expectResultTimedOut) {
+ expectAnswersNotValid(fd, -ETIMEDOUT);
+ } else {
+ expectAnswersValid(fd, AF_INET, "1.2.3.4");
}
+ const int timeTakenMs = s.getTimeAndResetUs() / 1000;
+ EXPECT_NEAR(config.expectedTimeTakenMs, timeTakenMs, TIMING_TOLERANCE_MS);
+ EXPECT_TRUE(tls.waitForQueries(1));
}
}
@@ -5635,12 +5631,11 @@ TEST_F(ResolverTest, RepeatedSetup_NoRedundantPrivateDnsValidation) {
parcel.tlsServers = {addr1, addr2, unusable_addr};
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- // Check the validation results.
+ // Check the validation status before proceed. The validation for `unresponsiveTls`
+ // should be running, and the other two should be finished.
EXPECT_TRUE(WaitForPrivateDnsValidation(workableTls.listen_address(), true));
EXPECT_TRUE(WaitForPrivateDnsValidation(unusable_addr, false));
-
- // The validation is still in progress.
- EXPECT_EQ(unresponsiveTls.acceptConnectionsCount(), 1);
+ EXPECT_TRUE(PollForCondition([&]() { return unresponsiveTls.acceptConnectionsCount() == 1; }));
unresponsiveTls.clearConnectionsCount();
static const struct TestConfig {
@@ -5716,7 +5711,8 @@ TEST_F(ResolverTest, RepeatedSetup_NoRedundantPrivateDnsValidation) {
}
if (validationAttemptToUnresponsiveTls) {
- EXPECT_GT(unresponsiveTls.acceptConnectionsCount(), 0);
+ EXPECT_TRUE(PollForCondition(
+ [&]() { return unresponsiveTls.acceptConnectionsCount() > 0; }));
} else {
EXPECT_EQ(unresponsiveTls.acceptConnectionsCount(), 0);
}
@@ -5785,8 +5781,9 @@ TEST_F(ResolverTest, RepeatedSetup_KeepChangingPrivateDnsServers) {
for (const auto& serverState : {WORKING, UNSUPPORTED, UNRESPONSIVE}) {
int testIndex = 0;
for (const auto& config : testConfigs) {
- SCOPED_TRACE(fmt::format("serverState:{} testIndex:{} testConfig:[{}]", serverState,
- testIndex++, config.asTestName()));
+ SCOPED_TRACE(fmt::format("serverState:{} testIndex:{} testConfig:[{}]",
+ static_cast<int>(serverState), testIndex++,
+ config.asTestName()));
auto& tls = (config.tlsServer == addr1) ? tls1 : tls2;
if (serverState == UNSUPPORTED && tls.running()) ASSERT_TRUE(tls.stopServer());
@@ -7434,7 +7431,7 @@ TEST_F(ResolverMultinetworkTest, GetAddrInfo_AI_ADDRCONFIG) {
ConnectivityType::V4V6,
};
for (const auto& type : allTypes) {
- SCOPED_TRACE(fmt::format("ConnectivityType: {}", type));
+ SCOPED_TRACE(fmt::format("ConnectivityType: {}", static_cast<int>(type)));
// Create a network.
ScopedPhysicalNetwork network = CreateScopedPhysicalNetwork(type);
@@ -7566,7 +7563,7 @@ TEST_F(ResolverMultinetworkTest, DnsWithVpn) {
{ConnectivityType::V4V6, {ipv6_addr, ipv4_addr}},
};
for (const auto& [type, result] : testPairs) {
- SCOPED_TRACE(fmt::format("ConnectivityType: {}", type));
+ SCOPED_TRACE(fmt::format("ConnectivityType: {}", static_cast<int>(type)));
// Create a network.
ScopedPhysicalNetwork underlyingNetwork = CreateScopedPhysicalNetwork(type, "Underlying");
@@ -7686,7 +7683,7 @@ TEST_F(ResolverMultinetworkTest, PerAppDefaultNetwork) {
{ConnectivityType::V4V6, {ipv6_addr, ipv4_addr}},
};
for (const auto& [ipVersion, expectedDnsReply] : testPairs) {
- SCOPED_TRACE(fmt::format("ConnectivityType: {}", ipVersion));
+ SCOPED_TRACE(fmt::format("ConnectivityType: {}", static_cast<int>(ipVersion)));
// Create networks.
ScopedPhysicalNetwork sysDefaultNetwork =
@@ -7816,55 +7813,6 @@ TEST_F(ResolverMultinetworkTest, IPv6LinkLocalWithDefaultRoute) {
EXPECT_EQ(GetNumQueriesForType(*dnsPair->dnsServer, ns_type::ns_t_aaaa, host_name), 1U);
}
-// Test if the "do not send AAAA query when IPv6 address is link-local with a default route" feature
-// can be toggled by flag.
-TEST_F(ResolverMultinetworkTest, IPv6LinkLocalWithDefaultRouteFlag) {
- // Kernel 4.4 does not provide an IPv6 link-local address when an interface is added to a
- // network. Skip it because v6 link-local address is a prerequisite for this test.
- SKIP_IF_KERNEL_VERSION_LOWER_THAN(4, 9, 0);
-
- constexpr char host_name[] = "ohayou.example.com.";
- const struct TestConfig {
- std::string flagValue;
- std::vector<std::string> ips;
- unsigned numOfQuadAQuery;
- } TestConfigs[]{{"0", {"192.0.2.0", "2001:db8:cafe:d00d::31"}, 1U}, {"1", {"192.0.2.0"}, 0U}};
-
- for (const auto& config : TestConfigs) {
- SCOPED_TRACE(fmt::format("flagValue = {}, numOfQuadAQuery = {}", config.flagValue,
- config.numOfQuadAQuery));
-
- ScopedSystemProperties sp1(kSkip4aQueryOnV6LinklocalAddrFlag, config.flagValue);
- ScopedPhysicalNetwork network = CreateScopedPhysicalNetwork(ConnectivityType::V4);
- ASSERT_RESULT_OK(network.init());
-
- // Add IPv6 default route
- ASSERT_TRUE(mDnsClient.netdService()
- ->networkAddRoute(network.netId(), network.ifname(), "::/0", "")
- .isOk());
-
- // Ensuring that routing is applied. This is required for mainline test (b/257404586).
- usleep(1000 * 1000);
-
- const Result<DnsServerPair> dnsPair = network.addIpv4Dns();
- ASSERT_RESULT_OK(dnsPair);
- StartDns(*dnsPair->dnsServer, {{host_name, ns_type::ns_t_a, "192.0.2.0"},
- {host_name, ns_type::ns_t_aaaa, "2001:db8:cafe:d00d::31"}});
-
- ASSERT_TRUE(network.setDnsConfiguration());
- ASSERT_TRUE(network.startTunForwarder());
-
- auto result = android_getaddrinfofornet_wrapper(host_name, network.netId());
- ASSERT_RESULT_OK(result);
- ScopedAddrinfo ai_results(std::move(result.value()));
- std::vector<std::string> result_strs = ToStrings(ai_results);
- EXPECT_THAT(result_strs, testing::UnorderedElementsAreArray(config.ips));
- EXPECT_EQ(GetNumQueriesForType(*dnsPair->dnsServer, ns_type::ns_t_a, host_name), 1U);
- EXPECT_EQ(GetNumQueriesForType(*dnsPair->dnsServer, ns_type::ns_t_aaaa, host_name),
- config.numOfQuadAQuery);
- }
-}
-
// v6 mdns is expected to be sent when the IPv6 address is a link-local with a default route.
TEST_F(ResolverMultinetworkTest, MdnsIPv6LinkLocalWithDefaultRoute) {
// Kernel 4.4 does not provide an IPv6 link-local address when an interface is added to a
@@ -7980,7 +7928,7 @@ TEST_F(ResolverMultinetworkTest, UidAllowedNetworks) {
{ConnectivityType::V4V6, {ipv6_addr, ipv4_addr}},
};
for (const auto& [ipVersion, expectedDnsReply] : testPairs) {
- SCOPED_TRACE(fmt::format("ConnectivityType: {}", ipVersion));
+ SCOPED_TRACE(fmt::format("ConnectivityType: {}", static_cast<int>(ipVersion)));
// Create networks.
ScopedPhysicalNetwork sysDefaultNetwork =
diff --git a/tests/resolv_private_dns_test.cpp b/tests/resolv_private_dns_test.cpp
index 569b74af..c9b8f46c 100644
--- a/tests/resolv_private_dns_test.cpp
+++ b/tests/resolv_private_dns_test.cpp
@@ -29,6 +29,7 @@
#include <netdutils/InternetAddresses.h>
#include <netdutils/NetNativeTestBase.h>
#include <netdutils/Stopwatch.h>
+#include <nettestutils/DumpService.h>
#include "doh_frontend.h"
#include "tests/dns_responder/dns_responder.h"
@@ -52,6 +53,7 @@ using android::netdutils::ScopedAddrinfo;
using android::netdutils::Stopwatch;
using std::chrono::milliseconds;
using std::this_thread::sleep_for;
+using ::testing::AnyOf;
constexpr int MAXPACKET = (8 * 1024);
@@ -60,33 +62,6 @@ constexpr int kDohIdleDefaultTimeoutMs = 55000;
namespace {
-std::vector<std::string> dumpService(ndk::SpAIBinder binder) {
- unique_fd localFd, remoteFd;
- bool success = Pipe(&localFd, &remoteFd);
- EXPECT_TRUE(success) << "Failed to open pipe for dumping: " << strerror(errno);
- if (!success) return {};
-
- // dump() blocks until another thread has consumed all its output.
- std::thread dumpThread = std::thread([binder, remoteFd{std::move(remoteFd)}]() {
- EXPECT_EQ(STATUS_OK, AIBinder_dump(binder.get(), remoteFd, nullptr, 0));
- });
-
- std::string dumpContent;
-
- EXPECT_TRUE(ReadFdToString(localFd.get(), &dumpContent))
- << "Error during dump: " << strerror(errno);
- dumpThread.join();
-
- std::stringstream dumpStream(std::move(dumpContent));
- std::vector<std::string> lines;
- std::string line;
- while (std::getline(dumpStream, line)) {
- lines.push_back(std::move(line));
- }
-
- return lines;
-}
-
int getAsyncResponse(int fd, int* rcode, uint8_t* buf, int bufLen) {
struct pollfd wait_fd[1];
wait_fd[0].fd = fd;
@@ -202,11 +177,27 @@ class BaseTest : public NetNativeTestBase {
IDnsResolverUnsolicitedEventListener::PROTOCOL_DOT);
}
+ bool WaitForDotValidationSuccess(std::string serverAddr) {
+ return WaitForDotValidation(serverAddr, true);
+ }
+
+ bool WaitForDotValidationFailure(std::string serverAddr) {
+ return WaitForDotValidation(serverAddr, false);
+ }
+
bool WaitForDohValidation(std::string serverAddr, bool validated) {
return WaitForPrivateDnsValidation(serverAddr, validated,
IDnsResolverUnsolicitedEventListener::PROTOCOL_DOH);
}
+ bool WaitForDohValidationSuccess(std::string serverAddr) {
+ return WaitForDohValidation(serverAddr, true);
+ }
+
+ bool WaitForDohValidationFailure(std::string serverAddr) {
+ return WaitForDohValidation(serverAddr, false);
+ }
+
bool WaitForPrivateDnsValidation(std::string serverAddr, bool validated, int protocol) {
return sUnsolicitedEventListener->waitForPrivateDnsValidation(
serverAddr,
@@ -224,9 +215,13 @@ class BaseTest : public NetNativeTestBase {
}
bool expectLog(const std::string& ipAddrOrNoData, const std::string& port) {
- ndk::SpAIBinder resolvBinder = ndk::SpAIBinder(AServiceManager_getService("dnsresolver"));
- assert(nullptr != resolvBinder.get());
- std::vector<std::string> lines = dumpService(resolvBinder);
+ std::vector<std::string> lines;
+ const android::status_t ret =
+ dumpService(sResolvBinder, /*args=*/nullptr, /*num_args=*/0, lines);
+ if (ret != android::OK) {
+ ADD_FAILURE() << "Error dumping service: " << android::statusToString(ret);
+ return false;
+ }
const std::string expectedLog =
port.empty() ? ipAddrOrNoData
@@ -328,6 +323,28 @@ class BasePrivateDnsTest : public BaseTest {
EXPECT_EQ(mDnsClient.resolvService()->dump(fd, querylogCmd, std::size(querylogCmd)), 0);
}
+ void expectQueriesAreBlocked() {
+ // getaddrinfo should fail
+ const addrinfo hints = {.ai_socktype = SOCK_DGRAM};
+ EXPECT_FALSE(safe_getaddrinfo(kQueryHostname, nullptr, &hints));
+
+ // gethostbyname should fail
+ EXPECT_FALSE(gethostbyname(kQueryHostname));
+
+ // gethostbyaddr should fail
+ in6_addr v6addr;
+ inet_pton(AF_INET6, "2001:db8::102:304", &v6addr);
+ EXPECT_FALSE(gethostbyaddr(&v6addr, sizeof(v6addr), AF_INET6));
+
+ // resNetworkQuery should fail
+ int fd = resNetworkQuery(TEST_NETID, kQueryHostname, ns_c_in, ns_t_aaaa, 0);
+ EXPECT_TRUE(fd != -1);
+
+ uint8_t buf[MAXPACKET] = {};
+ int rcode;
+ EXPECT_EQ(-ECONNREFUSED, getAsyncResponse(fd, &rcode, buf, MAXPACKET));
+ }
+
static constexpr milliseconds kExpectedDohValidationTimeWhenTimeout{1000};
static constexpr milliseconds kExpectedDohValidationTimeWhenServerUnreachable{1000};
static constexpr char kQueryHostname[] = "TransportParameterizedTest.example.com.";
@@ -399,8 +416,8 @@ TEST_P(TransportParameterizedTest, GetAddrInfo) {
const auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- if (testParamHasDoh()) EXPECT_TRUE(WaitForDohValidation(test::kDefaultListenAddr, true));
- if (testParamHasDot()) EXPECT_TRUE(WaitForDotValidation(test::kDefaultListenAddr, true));
+ if (testParamHasDoh()) EXPECT_TRUE(WaitForDohValidationSuccess(test::kDefaultListenAddr));
+ if (testParamHasDot()) EXPECT_TRUE(WaitForDotValidationSuccess(test::kDefaultListenAddr));
// This waiting time is expected to avoid that the DoH validation event interferes other tests.
if (!testParamHasDoh()) waitForDohValidationFailed();
@@ -467,8 +484,8 @@ TEST_P(TransportParameterizedTest, MdnsGetAddrInfo_fallback) {
auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- if (testParamHasDoh()) EXPECT_TRUE(WaitForDohValidation(test::kDefaultListenAddr, true));
- if (testParamHasDot()) EXPECT_TRUE(WaitForDotValidation(test::kDefaultListenAddr, true));
+ if (testParamHasDoh()) EXPECT_TRUE(WaitForDohValidationSuccess(test::kDefaultListenAddr));
+ if (testParamHasDot()) EXPECT_TRUE(WaitForDotValidationSuccess(test::kDefaultListenAddr));
// This waiting time is expected to avoid that the DoH validation event interferes other tests.
if (!testParamHasDoh()) waitForDohValidationFailed();
@@ -511,6 +528,128 @@ TEST_P(TransportParameterizedTest, MdnsGetAddrInfo_fallback) {
}
}
+TEST_P(TransportParameterizedTest, BlockDnsQuery) {
+ SKIP_IF_BEFORE_T;
+ SKIP_IF_DEPENDENT_LIB_DOES_NOT_EXIST(DNS_HELPER);
+
+ constexpr char ptr_name[] = "v4v6.example.com.";
+ // PTR record for IPv6 address 2001:db8::102:304
+ constexpr char ptr_addr_v6[] =
+ "4.0.3.0.2.0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.";
+ const DnsRecord r = {ptr_addr_v6, ns_type::ns_t_ptr, ptr_name};
+ dns.addMapping(r.host_name, r.type, r.addr);
+ dot_backend.addMapping(r.host_name, r.type, r.addr);
+ doh_backend.addMapping(r.host_name, r.type, r.addr);
+
+ auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
+ ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
+
+ if (testParamHasDoh()) EXPECT_TRUE(WaitForDohValidationSuccess(test::kDefaultListenAddr));
+ if (testParamHasDot()) EXPECT_TRUE(WaitForDotValidationSuccess(test::kDefaultListenAddr));
+
+ // This waiting time is expected to avoid that the DoH validation event interferes other tests.
+ if (!testParamHasDoh()) waitForDohValidationFailed();
+
+ // Have the test independent of the number of sent queries in private DNS validation, because
+ // the DnsResolver can send either 1 or 2 queries in DoT validation.
+ if (testParamHasDoh()) {
+ doh.clearQueries();
+ }
+ if (testParamHasDot()) {
+ EXPECT_TRUE(dot.waitForQueries(1));
+ dot.clearQueries();
+ }
+ dns.clearQueries();
+
+ for (const bool testDataSaver : {false, true}) {
+ SCOPED_TRACE(fmt::format("test {}", testDataSaver ? "data saver" : "UID firewall rules"));
+ if (testDataSaver) {
+ // Data Saver applies on metered networks only.
+ parcel.meteredNetwork = true;
+ ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
+
+ // Block network access by enabling data saver.
+ ScopedSetDataSaverByBPF scopedSetDataSaverByBPF(true);
+ ScopedChangeUID scopedChangeUID(TEST_UID);
+
+ // DataSaver information is only meaningful after V.
+ // TODO: Add 'else' to check that DNS queries are not blocked before V.
+ if (android::modules::sdklevel::IsAtLeastV()) {
+ expectQueriesAreBlocked();
+ }
+ } else {
+ // Block network access by setting UID firewall rules.
+ ScopeBlockedUIDRule scopeBlockUidRule(mDnsClient.netdService(), TEST_UID);
+ expectQueriesAreBlocked();
+ }
+ expectQueries(0 /* dns */, 0 /* dot */, 0 /* doh */);
+ }
+}
+
+// Verify whether the DNS fail-fast feature can be turned off by flag.
+TEST_P(TransportParameterizedTest, BlockDnsQuery_FlaggedOff) {
+ SKIP_IF_BEFORE_T;
+ SKIP_IF_DEPENDENT_LIB_DOES_NOT_EXIST(DNS_HELPER);
+
+ constexpr char ptr_name[] = "v4v6.example.com.";
+ // PTR record for IPv6 address 2001:db8::102:304
+ constexpr char ptr_addr_v6[] =
+ "4.0.3.0.2.0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.";
+ const DnsRecord r = {ptr_addr_v6, ns_type::ns_t_ptr, ptr_name};
+ dns.addMapping(r.host_name, r.type, r.addr);
+ dot_backend.addMapping(r.host_name, r.type, r.addr);
+ doh_backend.addMapping(r.host_name, r.type, r.addr);
+
+ ScopedSystemProperties sp1(kFailFastOnUidNetworkBlockingFlag, "0");
+ resetNetwork();
+
+ auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
+ ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
+
+ if (testParamHasDoh()) EXPECT_TRUE(WaitForDohValidationSuccess(test::kDefaultListenAddr));
+ if (testParamHasDot()) EXPECT_TRUE(WaitForDotValidationSuccess(test::kDefaultListenAddr));
+
+ // This waiting time is expected to avoid that the DoH validation event interferes other tests.
+ if (!testParamHasDoh()) waitForDohValidationFailed();
+
+ // Have the test independent of the number of sent queries in private DNS validation, because
+ // the DnsResolver can send either 1 or 2 queries in DoT validation.
+ if (testParamHasDoh()) {
+ doh.clearQueries();
+ }
+ if (testParamHasDot()) {
+ EXPECT_TRUE(dot.waitForQueries(1));
+ dot.clearQueries();
+ }
+ dns.clearQueries();
+
+ for (const bool testDataSaver : {false, true}) {
+ SCOPED_TRACE(fmt::format("test {}", testDataSaver ? "data saver" : "UID firewall rules"));
+ if (testDataSaver) {
+ // Data Saver applies on metered networks only.
+ parcel.meteredNetwork = true;
+ ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
+
+ // Block network access by enabling data saver.
+ ScopedSetDataSaverByBPF scopedSetDataSaverByBPF(true);
+ ScopedChangeUID scopedChangeUID(TEST_UID);
+ EXPECT_NO_FAILURE(sendQueryAndCheckResult());
+ } else {
+ // Block network access by setting UID firewall rules.
+ ScopeBlockedUIDRule scopeBlockUidRule(mDnsClient.netdService(), TEST_UID);
+ EXPECT_NO_FAILURE(sendQueryAndCheckResult());
+ }
+
+ if (testParamHasDoh()) {
+ EXPECT_NO_FAILURE(expectQueries(0 /* dns */, 0 /* dot */, 2 /* doh */));
+ dot.clearQueries();
+ } else {
+ EXPECT_NO_FAILURE(expectQueries(0 /* dns */, 2 /* dot */, 0 /* doh */));
+ doh.clearQueries();
+ }
+ }
+}
+
class PrivateDnsDohTest : public BasePrivateDnsTest {
protected:
void SetUp() override {
@@ -542,8 +681,8 @@ TEST_F(PrivateDnsDohTest, ValidationFail) {
Stopwatch s;
const auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- EXPECT_TRUE(WaitForDohValidation(test::kDefaultListenAddr, false));
- EXPECT_TRUE(WaitForDotValidation(test::kDefaultListenAddr, false));
+ EXPECT_TRUE(WaitForDohValidationFailure(test::kDefaultListenAddr));
+ EXPECT_TRUE(WaitForDotValidationFailure(test::kDefaultListenAddr));
EXPECT_LT(s.getTimeAndResetUs(),
microseconds(kExpectedDohValidationTimeWhenServerUnreachable + TIMING_TOLERANCE)
.count());
@@ -555,8 +694,8 @@ TEST_F(PrivateDnsDohTest, ValidationFail) {
s.getTimeAndResetUs();
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- EXPECT_TRUE(WaitForDohValidation(test::kDefaultListenAddr, false));
- EXPECT_TRUE(WaitForDotValidation(test::kDefaultListenAddr, false));
+ EXPECT_TRUE(WaitForDohValidationFailure(test::kDefaultListenAddr));
+ EXPECT_TRUE(WaitForDotValidationFailure(test::kDefaultListenAddr));
EXPECT_LT(s.getTimeAndResetUs(),
microseconds(kExpectedDohValidationTimeWhenTimeout + TIMING_TOLERANCE).count());
@@ -575,8 +714,8 @@ TEST_F(PrivateDnsDohTest, QueryFailover) {
const auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- EXPECT_TRUE(WaitForDohValidation(test::kDefaultListenAddr, true));
- EXPECT_TRUE(WaitForDotValidation(test::kDefaultListenAddr, true));
+ EXPECT_TRUE(WaitForDohValidationSuccess(test::kDefaultListenAddr));
+ EXPECT_TRUE(WaitForDotValidationSuccess(test::kDefaultListenAddr));
EXPECT_TRUE(dot.waitForQueries(1));
dot.clearQueries();
dns.clearQueries();
@@ -593,7 +732,7 @@ TEST_F(PrivateDnsDohTest, QueryFailover) {
resetNetwork();
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- EXPECT_TRUE(WaitForDotValidation(test::kDefaultListenAddr, true));
+ EXPECT_TRUE(WaitForDotValidationSuccess(test::kDefaultListenAddr));
EXPECT_TRUE(dot.waitForQueries(1));
dot.clearQueries();
dns.clearQueries();
@@ -640,7 +779,7 @@ TEST_F(PrivateDnsDohTest, PreferIpv6) {
// Currently, DnsResolver sorts the server list and did DoH validation only
// for the first server.
- EXPECT_TRUE(WaitForDohValidation(listen_ipv6_addr, true));
+ EXPECT_TRUE(WaitForDohValidationSuccess(listen_ipv6_addr));
doh.clearQueries();
doh_ipv6.clearQueries();
@@ -671,7 +810,7 @@ TEST_F(PrivateDnsDohTest, ChangeAndClearPrivateDnsServer) {
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
// Use v4 DoH server first.
- EXPECT_TRUE(WaitForDohValidation(test::kDefaultListenAddr, true));
+ EXPECT_TRUE(WaitForDohValidationSuccess(test::kDefaultListenAddr));
doh.clearQueries();
EXPECT_NO_FAILURE(sendQueryAndCheckResult());
EXPECT_NO_FAILURE(expectQueries(0 /* dns */, 0 /* dot */, 2 /* doh */));
@@ -680,7 +819,7 @@ TEST_F(PrivateDnsDohTest, ChangeAndClearPrivateDnsServer) {
parcel.servers = {listen_ipv6_addr};
parcel.tlsServers = {listen_ipv6_addr};
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- EXPECT_TRUE(WaitForDohValidation(listen_ipv6_addr, true));
+ EXPECT_TRUE(WaitForDohValidationSuccess(listen_ipv6_addr));
doh.clearQueries();
doh_ipv6.clearQueries();
flushCache();
@@ -729,7 +868,7 @@ TEST_F(PrivateDnsDohTest, ChangePrivateDnsServerAndVerifyOutput) {
// Start the v4 DoH server.
auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- EXPECT_TRUE(WaitForDohValidation(test::kDefaultListenAddr, true));
+ EXPECT_TRUE(WaitForDohValidationSuccess(test::kDefaultListenAddr));
EXPECT_TRUE(expectLog(ipv4DohServerAddr, kDohPortString));
// Change to an invalid DoH server.
@@ -742,7 +881,7 @@ TEST_F(PrivateDnsDohTest, ChangePrivateDnsServerAndVerifyOutput) {
parcel.servers = {ipv6DohServerAddr};
parcel.tlsServers = {ipv6DohServerAddr};
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- EXPECT_TRUE(WaitForDohValidation(ipv6DohServerAddr, true));
+ EXPECT_TRUE(WaitForDohValidationSuccess(ipv6DohServerAddr));
EXPECT_TRUE(expectLog(ipv6DohServerAddr, kDohPortString));
EXPECT_FALSE(expectLog(ipv4DohServerAddr, kDohPortString));
@@ -762,8 +901,8 @@ TEST_F(PrivateDnsDohTest, TemporaryConnectionStalled) {
const auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- EXPECT_TRUE(WaitForDohValidation(test::kDefaultListenAddr, true));
- EXPECT_TRUE(WaitForDotValidation(test::kDefaultListenAddr, true));
+ EXPECT_TRUE(WaitForDohValidationSuccess(test::kDefaultListenAddr));
+ EXPECT_TRUE(WaitForDotValidationSuccess(test::kDefaultListenAddr));
EXPECT_TRUE(dot.waitForQueries(1));
dot.clearQueries();
doh.clearQueries();
@@ -788,9 +927,19 @@ TEST_F(PrivateDnsDohTest, TemporaryConnectionStalled) {
TEST_F(PrivateDnsDohTest, ExcessDnsRequests) {
const int total_queries = 70;
- // The number is from MAX_BUFFERED_COMMANDS + 2 (one that will be queued in
- // connection mpsc channel; the other one that will get blocked at dispatcher sending channel).
- const int timeout_queries = 52;
+ // In most cases, the number of timed-out DoH queries is MAX_BUFFERED_COMMANDS + 2 (one that
+ // will be queued in connection's mpsc::channel; the other one that will get blocked at
+ // dispatcher's mpsc::channel), as shown below:
+ //
+ // dispatcher's mpsc::channel -----> network's mpsc:channel -----> connection's mpsc::channel
+ // (expect 1 query queued here) (size: MAX_BUFFERED_COMMANDS) (expect 1 query queued here)
+ //
+ // However, it's still possible that the (MAX_BUFFERED_COMMANDS + 2)th query is sent to the DoH
+ // engine before the DoH engine moves a query to connection's mpsc::channel. In that case,
+ // the (MAX_BUFFERED_COMMANDS + 2)th query will be fallback'ed to DoT immediately rather than
+ // be waiting until DoH timeout, which result in only (MAX_BUFFERED_COMMANDS + 1) timed-out
+ // DoH queries.
+ const int doh_timeout_queries = 52;
// If early data flag is enabled, DnsResolver doesn't wait for the connection established.
// It will send DNS queries along with 0-RTT rather than queue them in connection mpsc channel.
@@ -805,15 +954,15 @@ TEST_F(PrivateDnsDohTest, ExcessDnsRequests) {
auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- EXPECT_TRUE(WaitForDohValidation(test::kDefaultListenAddr, true));
- EXPECT_TRUE(WaitForDotValidation(test::kDefaultListenAddr, true));
+ EXPECT_TRUE(WaitForDohValidationSuccess(test::kDefaultListenAddr));
+ EXPECT_TRUE(WaitForDotValidationSuccess(test::kDefaultListenAddr));
EXPECT_TRUE(dot.waitForQueries(1));
dot.clearQueries();
doh.clearQueries();
dns.clearQueries();
// Set the DoT server not to close the connection until it receives enough queries or timeout.
- dot.setDelayQueries(total_queries - timeout_queries);
+ dot.setDelayQueries(total_queries - doh_timeout_queries);
dot.setDelayQueriesTimeout(200);
// Set the server blocking, wait for the connection closed, and send some DNS requests.
@@ -831,8 +980,10 @@ TEST_F(PrivateDnsDohTest, ExcessDnsRequests) {
// There are some queries that fall back to DoT rather than UDP since the DoH client rejects
// any new DNS requests when the capacity is full.
- EXPECT_NO_FAILURE(expectQueries(timeout_queries /* dns */,
- total_queries - timeout_queries /* dot */, 0 /* doh */));
+ EXPECT_THAT(dns.queries().size(), AnyOf(doh_timeout_queries, doh_timeout_queries - 1));
+ EXPECT_THAT(dot.queries(), AnyOf(total_queries - doh_timeout_queries,
+ total_queries - doh_timeout_queries + 1));
+ EXPECT_EQ(doh.queries(), 0);
// Set up another network and send a DNS query. Expect that this network is unaffected.
constexpr int TEST_NETID_2 = 31;
@@ -899,8 +1050,8 @@ TEST_F(PrivateDnsDohTest, RunOutOfDataLimit) {
const auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- EXPECT_TRUE(WaitForDohValidation(test::kDefaultListenAddr, true));
- EXPECT_TRUE(WaitForDotValidation(test::kDefaultListenAddr, true));
+ EXPECT_TRUE(WaitForDohValidationSuccess(test::kDefaultListenAddr));
+ EXPECT_TRUE(WaitForDotValidationSuccess(test::kDefaultListenAddr));
EXPECT_TRUE(dot.waitForQueries(1));
dot.clearQueries();
doh.clearQueries();
@@ -948,8 +1099,8 @@ TEST_F(PrivateDnsDohTest, RunOutOfStreams) {
const auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- EXPECT_TRUE(WaitForDohValidation(test::kDefaultListenAddr, true));
- EXPECT_TRUE(WaitForDotValidation(test::kDefaultListenAddr, true));
+ EXPECT_TRUE(WaitForDohValidationSuccess(test::kDefaultListenAddr));
+ EXPECT_TRUE(WaitForDotValidationSuccess(test::kDefaultListenAddr));
EXPECT_TRUE(dot.waitForQueries(1));
dot.clearQueries();
doh.clearQueries();
@@ -986,8 +1137,8 @@ TEST_F(PrivateDnsDohTest, ReconnectAfterIdleTimeout) {
const auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- EXPECT_TRUE(WaitForDohValidation(test::kDefaultListenAddr, true));
- EXPECT_TRUE(WaitForDotValidation(test::kDefaultListenAddr, true));
+ EXPECT_TRUE(WaitForDohValidationSuccess(test::kDefaultListenAddr));
+ EXPECT_TRUE(WaitForDotValidationSuccess(test::kDefaultListenAddr));
EXPECT_TRUE(dot.waitForQueries(1));
dot.clearQueries();
doh.clearQueries();
@@ -1027,8 +1178,8 @@ TEST_F(PrivateDnsDohTest, ConnectionIdleTimer) {
const auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- EXPECT_TRUE(WaitForDohValidation(test::kDefaultListenAddr, true));
- EXPECT_TRUE(WaitForDotValidation(test::kDefaultListenAddr, true));
+ EXPECT_TRUE(WaitForDohValidationSuccess(test::kDefaultListenAddr));
+ EXPECT_TRUE(WaitForDotValidationSuccess(test::kDefaultListenAddr));
EXPECT_TRUE(dot.waitForQueries(1));
dot.clearQueries();
doh.clearQueries();
@@ -1061,8 +1212,8 @@ TEST_F(PrivateDnsDohTest, SessionResumption) {
const auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- EXPECT_TRUE(WaitForDohValidation(test::kDefaultListenAddr, true));
- EXPECT_TRUE(WaitForDotValidation(test::kDefaultListenAddr, true));
+ EXPECT_TRUE(WaitForDohValidationSuccess(test::kDefaultListenAddr));
+ EXPECT_TRUE(WaitForDotValidationSuccess(test::kDefaultListenAddr));
EXPECT_TRUE(dot.waitForQueries(1));
dot.clearQueries();
doh.clearQueries();
@@ -1100,8 +1251,8 @@ TEST_F(PrivateDnsDohTest, TestEarlyDataFlag) {
const auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- EXPECT_TRUE(WaitForDohValidation(test::kDefaultListenAddr, true));
- EXPECT_TRUE(WaitForDotValidation(test::kDefaultListenAddr, true));
+ EXPECT_TRUE(WaitForDohValidationSuccess(test::kDefaultListenAddr));
+ EXPECT_TRUE(WaitForDotValidationSuccess(test::kDefaultListenAddr));
EXPECT_TRUE(dot.waitForQueries(1));
dot.clearQueries();
doh.clearQueries();
@@ -1122,8 +1273,8 @@ TEST_F(PrivateDnsDohTest, TestEarlyDataFlag) {
TEST_F(PrivateDnsDohTest, RemoteConnectionClosed) {
const auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- EXPECT_TRUE(WaitForDohValidation(test::kDefaultListenAddr, true));
- EXPECT_TRUE(WaitForDotValidation(test::kDefaultListenAddr, true));
+ EXPECT_TRUE(WaitForDohValidationSuccess(test::kDefaultListenAddr));
+ EXPECT_TRUE(WaitForDotValidationSuccess(test::kDefaultListenAddr));
EXPECT_TRUE(dot.waitForQueries(1));
dot.clearQueries();
doh.clearQueries();
@@ -1149,8 +1300,8 @@ TEST_F(PrivateDnsDohTest, RemoteConnectionClosed) {
TEST_F(PrivateDnsDohTest, ReceiveResetStream) {
const auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
- EXPECT_TRUE(WaitForDohValidation(test::kDefaultListenAddr, true));
- EXPECT_TRUE(WaitForDotValidation(test::kDefaultListenAddr, true));
+ EXPECT_TRUE(WaitForDohValidationSuccess(test::kDefaultListenAddr));
+ EXPECT_TRUE(WaitForDotValidationSuccess(test::kDefaultListenAddr));
EXPECT_TRUE(dot.waitForQueries(1));
dot.clearQueries();
doh.clearQueries();
@@ -1175,3 +1326,32 @@ TEST_F(PrivateDnsDohTest, ReceiveResetStream) {
expectAnswersValid(fd, AF_INET6, kQueryAnswerAAAA);
EXPECT_NO_FAILURE(expectQueries(0 /* dns */, 1 /* dot */, 2 /* doh */));
}
+
+// Tests that, given an IP address with an allowed DoH provider name, PrivateDnsConfiguration
+// attempts to probe the server for DoH.
+TEST_F(PrivateDnsDohTest, UseDohAsLongAsHostnameMatch) {
+ // "example.com" is an allowed DoH provider name defined in
+ // PrivateDnsConfiguration::mAvailableDoHProviders.
+ constexpr char allowedDohName[] = "example.com";
+ constexpr char someOtherIp[] = "127.99.99.99";
+
+ // The test currently doesn't support testing DoH in private DNS strict mode, so DnsResolver
+ // can't connect to the testing DoH servers. We use onPrivateDnsValidationEvent() to check
+ // whether DoT/DoH probes are performed.
+ // Without an allowed private DNS provider hostname, expect PrivateDnsConfiguration to probe
+ // the server for DoT only.
+ ASSERT_TRUE(mDnsClient.SetResolversFromParcel(
+ ResolverParams::Builder().setDotServers({someOtherIp}).build()));
+ EXPECT_TRUE(WaitForDotValidationFailure(someOtherIp));
+ EXPECT_FALSE(hasUncaughtPrivateDnsValidation(someOtherIp));
+
+ // With an allowed private DNS provider hostname, expect PrivateDnsConfiguration to probe the
+ // server for both DoT and DoH.
+ ASSERT_TRUE(mDnsClient.SetResolversFromParcel(ResolverParams::Builder()
+ .setDotServers({someOtherIp})
+ .setPrivateDnsProvider(allowedDohName)
+ .build()));
+ EXPECT_TRUE(WaitForDotValidationFailure(someOtherIp));
+ EXPECT_TRUE(WaitForDohValidationFailure(someOtherIp));
+ EXPECT_FALSE(hasUncaughtPrivateDnsValidation(someOtherIp));
+}
diff --git a/tests/resolv_stats_test_utils.cpp b/tests/resolv_stats_test_utils.cpp
index 492080b8..1704922c 100644
--- a/tests/resolv_stats_test_utils.cpp
+++ b/tests/resolv_stats_test_utils.cpp
@@ -107,6 +107,8 @@ NetworkDnsEventReported fromNetworkDnsEventReportedStr(const std::string& str) {
event.set_private_dns_modes(static_cast<PrivateDnsModes>(value));
} else if (protoField[1] == "sampling_rate_denom" && ParseInt(protoField[2], &value)) {
event.set_sampling_rate_denom(value);
+ } else if (protoField[1] == "uid" && ParseInt(protoField[2], &value)) {
+ event.set_uid(value);
}
}
// Parsing each field of the proto DnsQueryEvent
@@ -169,6 +171,7 @@ void PrintTo(const NetworkDnsEventReported& event, std::ostream* os) {
*os << " network_type: " << event.network_type() << "\n";
*os << " private_dns_modes: " << event.private_dns_modes() << "\n";
*os << " dns_query_event_size: " << event.dns_query_events().dns_query_event_size() << "\n";
+ *os << " uid: " << event.uid() << "\n";
*os << "}";
}
diff --git a/tests/resolv_stats_test_utils.h b/tests/resolv_stats_test_utils.h
index 90fe511a..24e46858 100644
--- a/tests/resolv_stats_test_utils.h
+++ b/tests/resolv_stats_test_utils.h
@@ -120,7 +120,9 @@ MATCHER_P(NetworkDnsEventEq, other, "") {
*/
::testing::Property("dns_query_events",
&android::net::NetworkDnsEventReported::dns_query_events,
- DnsQueryEventsEq(other.dns_query_events()))),
+ DnsQueryEventsEq(other.dns_query_events())),
+ ::testing::Property("uid", &android::net::NetworkDnsEventReported::uid,
+ ::testing::Eq(other.uid()))),
arg, result_listener);
}
diff --git a/tests/resolv_stats_test_utils_test.cpp b/tests/resolv_stats_test_utils_test.cpp
index 3b30e086..af67796c 100644
--- a/tests/resolv_stats_test_utils_test.cpp
+++ b/tests/resolv_stats_test_utils_test.cpp
@@ -58,7 +58,8 @@ TEST_F(ResolvStatsUtilsTest, NetworkDnsEventEq) {
latency_micros: 0,
}
]
- }
+ },
+ uid: 1000,
})Event";
// TODO: Add integration test to verify Level 1 fields of NetworkDnsEventReported.
@@ -83,6 +84,7 @@ TEST_F(ResolvStatsUtilsTest, NetworkDnsEventEq) {
dnsQueryEvent2->set_dns_server_index(1);
dnsQueryEvent2->set_connected(0);
dnsQueryEvent2->set_latency_micros(5);
+ event1.set_uid(1000);
EXPECT_THAT(event1, NetworkDnsEventEq(fromNetworkDnsEventReportedStr(event2)));
}
diff --git a/tests/resolv_test_utils.cpp b/tests/resolv_test_utils.cpp
index 17c6c1db..4b09b213 100644
--- a/tests/resolv_test_utils.cpp
+++ b/tests/resolv_test_utils.cpp
@@ -229,3 +229,7 @@ void RemoveMdnsRoute() {
};
EXPECT_EQ(0, ForkAndRun(args_v6));
}
+
+bool is64bitAbi() {
+ return android::base::GetProperty("ro.product.cpu.abi", "").find("64") != std::string::npos;
+}
diff --git a/tests/resolv_test_utils.h b/tests/resolv_test_utils.h
index 1febb520..e3f744ce 100644
--- a/tests/resolv_test_utils.h
+++ b/tests/resolv_test_utils.h
@@ -20,6 +20,8 @@
#include <arpa/nameser.h>
#include <netdb.h>
+#include <filesystem>
+#include <functional>
#include <string>
#include <vector>
@@ -31,6 +33,7 @@
#include <netdutils/InternetAddresses.h>
#include "dns_responder/dns_responder.h"
+#include "util.h"
class ScopeBlockedUIDRule {
using INetd = aidl::android::net::INetd;
@@ -79,6 +82,33 @@ class ScopeBlockedUIDRule {
const uid_t mSavedUid;
};
+// Supported from T+ only.
+class ScopedSetDataSaverByBPF {
+ public:
+ ScopedSetDataSaverByBPF(bool wanted) {
+ if (android::modules::sdklevel::IsAtLeastT()) {
+ mFw = Firewall::getInstance();
+ // Backup current setting.
+ const Result<bool> current = mFw->getDataSaverSetting();
+ EXPECT_RESULT_OK(current);
+ if (wanted != current.value()) {
+ mSavedDataSaverSetting = current;
+ EXPECT_RESULT_OK(mFw->setDataSaver(wanted));
+ }
+ }
+ };
+ ~ScopedSetDataSaverByBPF() {
+ // Restore the setting.
+ if (mSavedDataSaverSetting.has_value()) {
+ EXPECT_RESULT_OK(mFw->setDataSaver(mSavedDataSaverSetting.value()));
+ }
+ }
+
+ private:
+ Firewall* mFw;
+ Result<bool> mSavedDataSaverSetting;
+};
+
class ScopedChangeUID {
public:
ScopedChangeUID(uid_t testUid) : mTestUid(testUid), mSavedUid(getuid()) {
@@ -154,12 +184,12 @@ const std::string kDotXportUnusableThresholdFlag(kFlagPrefix + "dot_xport_unusab
const std::string kDotValidationLatencyFactorFlag(kFlagPrefix + "dot_validation_latency_factor");
const std::string kDotValidationLatencyOffsetMsFlag(kFlagPrefix +
"dot_validation_latency_offset_ms");
+const std::string kFailFastOnUidNetworkBlockingFlag(kFlagPrefix +
+ "fail_fast_on_uid_network_blocking");
const std::string kKeepListeningUdpFlag(kFlagPrefix + "keep_listening_udp");
const std::string kParallelLookupSleepTimeFlag(kFlagPrefix + "parallel_lookup_sleep_time");
const std::string kRetransIntervalFlag(kFlagPrefix + "retransmission_time_interval");
const std::string kRetryCountFlag(kFlagPrefix + "retry_count");
-const std::string kSkip4aQueryOnV6LinklocalAddrFlag(kFlagPrefix +
- "skip_4a_query_on_v6_linklocal_addr");
const std::string kSortNameserversFlag(kFlagPrefix + "sort_nameservers");
const std::string kPersistNetPrefix("persist.net.");
@@ -401,3 +431,22 @@ android::netdutils::ScopedAddrinfo safe_getaddrinfo(const char* node, const char
void SetMdnsRoute();
void RemoveMdnsRoute();
+
+#define SKIP_IF_BEFORE_T \
+ do { \
+ if (!isAtLeastT()) { \
+ GTEST_SKIP() << "Skipping test because SDK version is less than T."; \
+ } \
+ } while (0)
+
+bool is64bitAbi();
+
+static const std::string DNS_HELPER =
+ is64bitAbi() ? "/apex/com.android.tethering/lib64/libcom.android.tethering.dns_helper.so"
+ : "/apex/com.android.tethering/lib/libcom.android.tethering.dns_helper.so";
+
+#define SKIP_IF_DEPENDENT_LIB_DOES_NOT_EXIST(libPath) \
+ do { \
+ if (!std::filesystem::exists(libPath)) \
+ GTEST_SKIP() << "Required " << (libPath) << " not found."; \
+ } while (0)
diff --git a/tests/resolv_unit_test.cpp b/tests/resolv_unit_test.cpp
index d7471b0b..af4cbf4e 100644
--- a/tests/resolv_unit_test.cpp
+++ b/tests/resolv_unit_test.cpp
@@ -638,7 +638,7 @@ TEST_F(ResolvGetAddrInfoTest, ServerResponseError) {
};
for (const auto& config : testConfigs) {
- SCOPED_TRACE(fmt::format("rcode: {}", config.rcode));
+ SCOPED_TRACE(fmt::format("rcode: {}", static_cast<int>(config.rcode)));
test::DNSResponder dns(config.rcode);
dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4");
@@ -1538,7 +1538,7 @@ TEST_F(GetHostByNameForNetContextTest, ServerResponseError) {
};
for (const auto& config : testConfigs) {
- SCOPED_TRACE(fmt::format("rcode: {}", config.rcode));
+ SCOPED_TRACE(fmt::format("rcode: {}", static_cast<int>(config.rcode)));
test::DNSResponder dns(config.rcode);
dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4");
diff --git a/tests/unsolicited_listener/unsolicited_event_listener.cpp b/tests/unsolicited_listener/unsolicited_event_listener.cpp
index 20edae13..b337496f 100644
--- a/tests/unsolicited_listener/unsolicited_event_listener.cpp
+++ b/tests/unsolicited_listener/unsolicited_event_listener.cpp
@@ -33,11 +33,11 @@ using android::base::ScopedLockAssertion;
using std::chrono::milliseconds;
constexpr milliseconds kEventTimeoutMs{5000};
-constexpr milliseconds kRetryIntervalMs{20};
::ndk::ScopedAStatus UnsolicitedEventListener::onDnsHealthEvent(const DnsHealthEventParcel& event) {
std::lock_guard lock(mMutex);
if (event.netId == mNetId) mDnsHealthResultRecords.push(event.healthResult);
+ mCv.notify_all();
return ::ndk::ScopedAStatus::ok();
}
@@ -51,6 +51,7 @@ constexpr milliseconds kRetryIntervalMs{20};
? event.prefixAddress
: "";
}
+ mCv.notify_all();
return ::ndk::ScopedAStatus::ok();
}
@@ -62,24 +63,16 @@ constexpr milliseconds kRetryIntervalMs{20};
mValidationRecords.insert_or_assign({event.netId, event.ipAddress, event.protocol},
event.validation);
}
- mCv.notify_one();
+ mCv.notify_all();
return ::ndk::ScopedAStatus::ok();
}
bool UnsolicitedEventListener::waitForPrivateDnsValidation(const std::string& serverAddr,
int validation, int protocol) {
- const auto now = std::chrono::steady_clock::now();
-
std::unique_lock lock(mMutex);
- ScopedLockAssertion assume_lock(mMutex);
-
- // onPrivateDnsValidationEvent() might already be invoked. Search for the record first.
- do {
- if (findAndRemoveValidationRecord({mNetId, serverAddr, protocol}, validation)) return true;
- } while (mCv.wait_until(lock, now + kEventTimeoutMs) != std::cv_status::timeout);
-
- // Timeout.
- return false;
+ return mCv.wait_for(lock, kEventTimeoutMs, [&]() REQUIRES(mMutex) {
+ return findAndRemoveValidationRecord({mNetId, serverAddr, protocol}, validation);
+ });
}
bool UnsolicitedEventListener::findAndRemoveValidationRecord(const ServerKey& key, int value) {
@@ -92,36 +85,33 @@ bool UnsolicitedEventListener::findAndRemoveValidationRecord(const ServerKey& ke
}
bool UnsolicitedEventListener::waitForNat64Prefix(int operation, const milliseconds& timeout) {
- android::base::Timer t;
- while (t.duration() < timeout) {
- {
- std::lock_guard lock(mMutex);
- if ((operation == IDnsResolverUnsolicitedEventListener::PREFIX_OPERATION_ADDED &&
- !mNat64PrefixAddress.empty()) ||
- (operation == IDnsResolverUnsolicitedEventListener::PREFIX_OPERATION_REMOVED &&
- mNat64PrefixAddress.empty())) {
- mUnexpectedNat64PrefixUpdates--;
- return true;
- }
- }
- std::this_thread::sleep_for(kRetryIntervalMs);
+ const auto now = std::chrono::steady_clock::now();
+
+ std::unique_lock lock(mMutex);
+ ScopedLockAssertion assume_lock(mMutex);
+
+ if (mCv.wait_for(lock, timeout, [&]() REQUIRES(mMutex) {
+ return (operation == IDnsResolverUnsolicitedEventListener::PREFIX_OPERATION_ADDED &&
+ !mNat64PrefixAddress.empty()) ||
+ (operation == IDnsResolverUnsolicitedEventListener::PREFIX_OPERATION_REMOVED &&
+ mNat64PrefixAddress.empty());
+ })) {
+ mUnexpectedNat64PrefixUpdates--;
+ return true;
}
+
+ // Timeout.
return false;
}
Result<int> UnsolicitedEventListener::popDnsHealthResult() {
- // Wait until the queue is not empty or timeout.
- android::base::Timer t;
- while (t.duration() < milliseconds{1000}) {
- {
- std::lock_guard lock(mMutex);
- if (!mDnsHealthResultRecords.empty()) break;
- }
- std::this_thread::sleep_for(kRetryIntervalMs);
- }
+ std::unique_lock lock(mMutex);
+ ScopedLockAssertion assume_lock(mMutex);
- std::lock_guard lock(mMutex);
- if (mDnsHealthResultRecords.empty()) return Error() << "Dns health result record is empty";
+ if (!mCv.wait_for(lock, kEventTimeoutMs,
+ [&]() REQUIRES(mMutex) { return !mDnsHealthResultRecords.empty(); })) {
+ return Error() << "Dns health result record is empty";
+ }
auto ret = mDnsHealthResultRecords.front();
mDnsHealthResultRecords.pop();
diff --git a/util.h b/util.h
index fd9e2d40..8c03b470 100644
--- a/util.h
+++ b/util.h
@@ -62,6 +62,11 @@ inline bool isDebuggable() {
return android::base::GetBoolProperty("ro.debuggable", false);
}
+inline bool isAtLeastT() {
+ const static bool isAtLeastT = android::modules::sdklevel::IsAtLeastT();
+ return isAtLeastT;
+}
+
inline bool isAtLeastU() {
const static bool isAtLeastU = android::modules::sdklevel::IsAtLeastU();
return isAtLeastU;