Snap for 6617762 from c35b4541c3c7e7e7bd339a036ebe1ad9e94a10eb to rvc-release
Change-Id: I30b245ca8956fc9930dffd089ab91456a9763c16
diff --git a/Android.bp b/Android.bp
index 559b62d..f84f7ab 100644
--- a/Android.bp
+++ b/Android.bp
@@ -49,6 +49,7 @@
"3",
"4",
"5",
+ "6",
],
}
diff --git a/aidl_api/dnsresolver_aidl_interface/6/.hash b/aidl_api/dnsresolver_aidl_interface/6/.hash
new file mode 100644
index 0000000..77b34a4
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/6/.hash
@@ -0,0 +1 @@
+5bc773534ffa9d7614ccd27d5de6daefdeeee2b8
diff --git a/aidl_api/dnsresolver_aidl_interface/6/android/net/IDnsResolver.aidl b/aidl_api/dnsresolver_aidl_interface/6/android/net/IDnsResolver.aidl
new file mode 100644
index 0000000..863927b
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/6/android/net/IDnsResolver.aidl
@@ -0,0 +1,64 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files 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);
+ 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;
+ 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;
+}
diff --git a/aidl_api/dnsresolver_aidl_interface/6/android/net/ResolverHostsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/6/android/net/ResolverHostsParcel.aidl
new file mode 100644
index 0000000..3ab0533
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/6/android/net/ResolverHostsParcel.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files 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/6/android/net/ResolverOptionsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/6/android/net/ResolverOptionsParcel.aidl
new file mode 100644
index 0000000..d55ae46
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/6/android/net/ResolverOptionsParcel.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files 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/6/android/net/ResolverParamsParcel.aidl b/aidl_api/dnsresolver_aidl_interface/6/android/net/ResolverParamsParcel.aidl
new file mode 100644
index 0000000..5dae1ca
--- /dev/null
+++ b/aidl_api/dnsresolver_aidl_interface/6/android/net/ResolverParamsParcel.aidl
@@ -0,0 +1,37 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files 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;
+ android.net.ResolverOptionsParcel resolverOptions;
+ int[] transportTypes = {};
+}
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 a13216a..d55ae46 100644
--- a/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverOptionsParcel.aidl
+++ b/aidl_api/dnsresolver_aidl_interface/current/android/net/ResolverOptionsParcel.aidl
@@ -20,4 +20,5 @@
parcelable ResolverOptionsParcel {
android.net.ResolverHostsParcel[] hosts = {};
int tcMode = 0;
+ boolean enforceDnsUid = false;
}
diff --git a/binder/android/net/ResolverOptionsParcel.aidl b/binder/android/net/ResolverOptionsParcel.aidl
index 8e435de..bca9fb6 100644
--- a/binder/android/net/ResolverOptionsParcel.aidl
+++ b/binder/android/net/ResolverOptionsParcel.aidl
@@ -43,4 +43,18 @@
* Other values are invalid.
*/
int tcMode = 0;
+
+ /**
+ * The default behavior is that plaintext DNS queries are sent by the application's UID using
+ * fchown(). DoT are sent with an UID of AID_DNS. This option control the plaintext uid of DNS
+ * query.
+ * Setting this option to true decreases battery life because it results in the device sending
+ * UDP DNS queries even if the app that made the DNS lookup does not have network access.
+ * Anecdotal data from the field suggests that about 15% of DNS lookups are in this category.
+ * This option also results in data usage for UDP DNS queries being attributed to the OS instead
+ * of to the requesting app.
+ * false: set application uid on DNS sockets (default)
+ * true: set AID_DNS on DNS sockets
+ */
+ boolean enforceDnsUid = false;
}
diff --git a/res_cache.cpp b/res_cache.cpp
index 07985d1..560de93 100644
--- a/res_cache.cpp
+++ b/res_cache.cpp
@@ -1003,6 +1003,7 @@
// If resolverParams.hosts is empty, the existing customized table will be erased.
HostMapping customizedTable = {};
int tc_mode = aidl::android::net::IDnsResolver::TC_MODE_DEFAULT;
+ bool enforceDnsUid = false;
std::vector<int32_t> transportTypes;
};
@@ -1645,6 +1646,7 @@
return -EINVAL;
}
netconfig->tc_mode = resolverOptions.tcMode;
+ netconfig->enforceDnsUid = resolverOptions.enforceDnsUid;
netconfig->transportTypes = transportTypes;
@@ -1683,6 +1685,7 @@
statp->nsaddrs = info->nameserverSockAddrs;
statp->search_domains = info->search_domains;
statp->tc_mode = info->tc_mode;
+ statp->enforce_dns_uid = info->enforceDnsUid;
}
/* Resolver reachability statistics. */
diff --git a/res_send.cpp b/res_send.cpp
index 6646310..2db8220 100644
--- a/res_send.cpp
+++ b/res_send.cpp
@@ -707,7 +707,8 @@
return -1;
}
}
- resolv_tag_socket(statp->tcp_nssock, statp->uid, statp->pid);
+ const uid_t uid = statp->enforce_dns_uid ? AID_DNS : statp->uid;
+ resolv_tag_socket(statp->tcp_nssock, uid, statp->pid);
if (statp->_mark != MARK_UNSET) {
if (setsockopt(statp->tcp_nssock, SOL_SOCKET, SO_MARK, &statp->_mark,
sizeof(statp->_mark)) < 0) {
@@ -1018,7 +1019,8 @@
}
}
- resolv_tag_socket(statp->nssocks[*ns], statp->uid, statp->pid);
+ const uid_t uid = statp->enforce_dns_uid ? AID_DNS : statp->uid;
+ resolv_tag_socket(statp->nssocks[*ns], uid, statp->pid);
if (statp->_mark != MARK_UNSET) {
if (setsockopt(statp->nssocks[*ns], SOL_SOCKET, SO_MARK, &(statp->_mark),
sizeof(statp->_mark)) < 0) {
diff --git a/resolv_cache.h b/resolv_cache.h
index 49c7f56..d8a3afc 100644
--- a/resolv_cache.h
+++ b/resolv_cache.h
@@ -84,7 +84,8 @@
const std::vector<std::string>& domains, const res_params& params,
const aidl::android::net::ResolverOptionsParcel& resolverOptions =
{{} /* hosts */,
- aidl::android::net::IDnsResolver::TC_MODE_DEFAULT},
+ aidl::android::net::IDnsResolver::TC_MODE_DEFAULT,
+ false /* enforceDnsUid */},
const std::vector<int32_t>& transportTypes = {});
// Creates the cache associated with the given network.
diff --git a/resolv_cache_unit_test.cpp b/resolv_cache_unit_test.cpp
index 7b022bb..d604b2d 100644
--- a/resolv_cache_unit_test.cpp
+++ b/resolv_cache_unit_test.cpp
@@ -104,9 +104,20 @@
return std::time(nullptr);
}
-// Comparison for res_stats. Simply check the count in the cache test.
+// Comparison for res_sample.
+bool operator==(const res_sample& a, const res_sample& b) {
+ return std::tie(a.at, a.rtt, a.rcode) == std::tie(b.at, b.rtt, b.rcode);
+}
+
+// Comparison for res_stats.
bool operator==(const res_stats& a, const res_stats& b) {
- return std::tie(a.sample_count, a.sample_next) == std::tie(b.sample_count, b.sample_next);
+ if (std::tie(a.sample_count, a.sample_next) != std::tie(b.sample_count, b.sample_next)) {
+ return false;
+ }
+ for (int i = 0; i < a.sample_count; i++) {
+ if (a.samples[i] != b.samples[i]) return false;
+ }
+ return true;
}
// Comparison for res_params.
@@ -837,6 +848,65 @@
EXPECT_STREQ(answer, domain_name);
}
+TEST_F(ResolvCacheTest, GetResolverStats) {
+ const res_sample sample1 = {.at = time(nullptr), .rtt = 100, .rcode = ns_r_noerror};
+ const res_sample sample2 = {.at = time(nullptr), .rtt = 200, .rcode = ns_r_noerror};
+ const res_sample sample3 = {.at = time(nullptr), .rtt = 300, .rcode = ns_r_noerror};
+ const res_stats expectedStats[MAXNS] = {
+ {{sample1}, 1 /*sample_count*/, 1 /*sample_next*/},
+ {{sample2}, 1, 1},
+ {{sample3}, 1, 1},
+ };
+ std::vector<IPSockAddr> nameserverSockAddrs = {
+ IPSockAddr::toIPSockAddr("127.0.0.1", DNS_PORT),
+ IPSockAddr::toIPSockAddr("::127.0.0.2", DNS_PORT),
+ IPSockAddr::toIPSockAddr("fe80::3", DNS_PORT),
+ };
+ const SetupParams setup = {
+ .servers = {"127.0.0.1", "::127.0.0.2", "fe80::3"},
+ .domains = {"domain1.com", "domain2.com"},
+ .params = kParams,
+ };
+ EXPECT_EQ(0, cacheCreate(TEST_NETID));
+ EXPECT_EQ(0, cacheSetupResolver(TEST_NETID, setup));
+ int revision_id = 1;
+ cacheAddStats(TEST_NETID, revision_id, nameserverSockAddrs[0], sample1,
+ setup.params.max_samples);
+ cacheAddStats(TEST_NETID, revision_id, nameserverSockAddrs[1], sample2,
+ setup.params.max_samples);
+ cacheAddStats(TEST_NETID, revision_id, nameserverSockAddrs[2], sample3,
+ setup.params.max_samples);
+
+ res_stats cacheStats[MAXNS]{};
+ res_params params;
+ EXPECT_EQ(resolv_cache_get_resolver_stats(TEST_NETID, ¶ms, cacheStats, nameserverSockAddrs),
+ revision_id);
+ EXPECT_TRUE(params == kParams);
+ for (size_t i = 0; i < MAXNS; i++) {
+ EXPECT_TRUE(cacheStats[i] == expectedStats[i]);
+ }
+
+ // pass another list of IPSockAddr
+ const res_stats expectedStats2[MAXNS] = {
+ {{sample3, sample2}, 2, 2},
+ {{sample2}, 1, 1},
+ {{sample1}, 1, 1},
+ };
+ nameserverSockAddrs = {
+ IPSockAddr::toIPSockAddr("fe80::3", DNS_PORT),
+ IPSockAddr::toIPSockAddr("::127.0.0.2", DNS_PORT),
+ IPSockAddr::toIPSockAddr("127.0.0.1", DNS_PORT),
+ };
+ cacheAddStats(TEST_NETID, revision_id, nameserverSockAddrs[0], sample2,
+ setup.params.max_samples);
+ EXPECT_EQ(resolv_cache_get_resolver_stats(TEST_NETID, ¶ms, cacheStats, nameserverSockAddrs),
+ revision_id);
+ EXPECT_TRUE(params == kParams);
+ for (size_t i = 0; i < MAXNS; i++) {
+ EXPECT_TRUE(cacheStats[i] == expectedStats2[i]);
+ }
+}
+
namespace {
constexpr int EAI_OK = 0;
@@ -907,8 +977,6 @@
}
// TODO: Tests for NetConfig, including:
-// - res_params
-// -- resolv_cache_get_resolver_stats()
// - res_stats
// -- _resolv_cache_add_resolver_stats_sample()
// -- android_net_res_stats_get_info_for_net()
diff --git a/resolv_private.h b/resolv_private.h
index 61d87f2..f1b667e 100644
--- a/resolv_private.h
+++ b/resolv_private.h
@@ -112,6 +112,7 @@
android::net::NetworkDnsEventReported* event;
uint32_t netcontext_flags;
int tc_mode = 0;
+ bool enforce_dns_uid = false;
// clang-format on
};
diff --git a/tests/resolv_integration_test.cpp b/tests/resolv_integration_test.cpp
index 236b031..95b5a5c 100644
--- a/tests/resolv_integration_test.cpp
+++ b/tests/resolv_integration_test.cpp
@@ -4018,6 +4018,71 @@
EXPECT_EQ(-ECONNREFUSED, res);
}
+TEST_F(ResolverTest, EnforceDnsUid) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ constexpr char listen_addr1[] = "127.0.0.4";
+ constexpr char listen_addr2[] = "::1";
+ constexpr char host_name[] = "howdy.example.com.";
+ const std::vector<DnsRecord> records = {
+ {host_name, ns_type::ns_t_a, "1.2.3.4"},
+ {host_name, ns_type::ns_t_aaaa, "::1.2.3.4"},
+ };
+ INetd* netdService = mDnsClient.netdService();
+
+ test::DNSResponder dns1(listen_addr1);
+ test::DNSResponder dns2(listen_addr2);
+ StartDns(dns1, records);
+ StartDns(dns2, records);
+
+ // switch uid of DNS queries from applications to AID_DNS
+ ResolverParamsParcel parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
+ parcel.servers = {listen_addr1, listen_addr2};
+ ASSERT_TRUE(mDnsClient.resolvService()->setResolverConfiguration(parcel).isOk());
+
+ uint8_t buf[MAXPACKET] = {};
+ int rcode;
+ {
+ ScopeBlockedUIDRule scopeBlockUidRule(netdService, TEST_UID);
+ // Dns Queries should be blocked
+ int fd1 = resNetworkQuery(TEST_NETID, host_name, ns_c_in, ns_t_a, 0);
+ int fd2 = resNetworkQuery(TEST_NETID, host_name, ns_c_in, ns_t_aaaa, 0);
+ EXPECT_TRUE(fd1 != -1);
+ EXPECT_TRUE(fd2 != -1);
+
+ int res = getAsyncResponse(fd2, &rcode, buf, MAXPACKET);
+ EXPECT_EQ(-ECONNREFUSED, res);
+
+ memset(buf, 0, MAXPACKET);
+ res = getAsyncResponse(fd1, &rcode, buf, MAXPACKET);
+ EXPECT_EQ(-ECONNREFUSED, res);
+ }
+
+ parcel.resolverOptions.enforceDnsUid = true;
+ ASSERT_TRUE(mDnsClient.resolvService()->setResolverConfiguration(parcel).isOk());
+ {
+ ScopeBlockedUIDRule scopeBlockUidRule(netdService, TEST_UID);
+ // Dns Queries should NOT be blocked
+ int fd1 = resNetworkQuery(TEST_NETID, host_name, ns_c_in, ns_t_a, 0);
+ int fd2 = resNetworkQuery(TEST_NETID, host_name, ns_c_in, ns_t_aaaa, 0);
+ EXPECT_TRUE(fd1 != -1);
+ EXPECT_TRUE(fd2 != -1);
+
+ int res = getAsyncResponse(fd2, &rcode, buf, MAXPACKET);
+ EXPECT_EQ("::1.2.3.4", toString(buf, res, AF_INET6));
+
+ memset(buf, 0, MAXPACKET);
+ res = getAsyncResponse(fd1, &rcode, buf, MAXPACKET);
+ EXPECT_EQ("1.2.3.4", toString(buf, res, AF_INET));
+
+ // @TODO: So far we know that uid of DNS queries are no more set to DNS requester. But we
+ // don't check if they are actually being set to AID_DNS, because system uids are always
+ // allowed in bpf_owner_match(). Audit by firewallSetUidRule(AID_DNS) + sending queries is
+ // infeasible. Fix it if the behavior of bpf_owner_match() is changed in the future, or if
+ // we have better idea to deal with this.
+ }
+}
+
namespace {
const std::string kDotConnectTimeoutMsFlag(