Implement a new IPC setResolverOptions in DnsResolver am: a8b0eec046

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/modules/DnsResolver/+/15482201

Change-Id: I0192dced3f8e31345ee50e31c823af76179b15a1
diff --git a/DnsResolverService.cpp b/DnsResolverService.cpp
index 899f726..7e29a9d 100644
--- a/DnsResolverService.cpp
+++ b/DnsResolverService.cpp
@@ -36,6 +36,7 @@
 #include "ResolverEventReporter.h"
 #include "resolv_cache.h"
 
+using aidl::android::net::ResolverOptionsParcel;
 using aidl::android::net::ResolverParamsParcel;
 using android::base::Join;
 using android::base::StringPrintf;
@@ -307,5 +308,13 @@
     return statusFromErrcode(res);
 }
 
+::ndk::ScopedAStatus DnsResolverService::setResolverOptions(int32_t netId,
+                                                            const ResolverOptionsParcel& options) {
+    // Locking happens in res_cache.cpp functions.
+    ENFORCE_NETWORK_STACK_PERMISSIONS();
+
+    return statusFromErrcode(resolv_set_options(netId, options));
+}
+
 }  // namespace net
 }  // namespace android
diff --git a/DnsResolverService.h b/DnsResolverService.h
index fe39301..8acd231 100644
--- a/DnsResolverService.h
+++ b/DnsResolverService.h
@@ -55,6 +55,8 @@
     ::ndk::ScopedAStatus destroyNetworkCache(int32_t netId) override;
     ::ndk::ScopedAStatus createNetworkCache(int32_t netId) override;
     ::ndk::ScopedAStatus flushNetworkCache(int32_t netId) override;
+    ::ndk::ScopedAStatus setResolverOptions(
+            int32_t netId, const aidl::android::net::ResolverOptionsParcel& options) override;
 
     // DNS64-related commands
     ::ndk::ScopedAStatus startPrefix64Discovery(int32_t netId) override;
diff --git a/res_cache.cpp b/res_cache.cpp
index a2ede89..768dc77 100644
--- a/res_cache.cpp
+++ b/res_cache.cpp
@@ -1004,7 +1004,23 @@
         dns_event_subsampling_map = resolv_get_dns_event_subsampling_map();
     }
     int nameserverCount() { return nameserverSockAddrs.size(); }
+    int setOptions(const ResolverOptionsParcel& resolverOptions) {
+        customizedTable.clear();
+        for (const auto& host : resolverOptions.hosts) {
+            if (!host.hostName.empty() && !host.ipAddr.empty())
+                customizedTable.emplace(host.hostName, host.ipAddr);
+        }
 
+        if (resolverOptions.tcMode < aidl::android::net::IDnsResolver::TC_MODE_DEFAULT ||
+            resolverOptions.tcMode > aidl::android::net::IDnsResolver::TC_MODE_UDP_TCP) {
+            LOG(WARNING) << __func__ << ": netid = " << netid
+                         << ", invalid TC mode: " << resolverOptions.tcMode;
+            return -EINVAL;
+        }
+        tc_mode = resolverOptions.tcMode;
+        enforceDnsUid = resolverOptions.enforceDnsUid;
+        return 0;
+    }
     const unsigned netid;
     std::unique_ptr<Cache> cache;
     std::vector<std::string> nameservers;
@@ -1655,30 +1671,22 @@
         LOG(WARNING) << __func__ << ": netid = " << netid << ", failed to set dns stats";
         return -EINVAL;
     }
-    netconfig->customizedTable.clear();
-
+    netconfig->transportTypes = transportTypes;
     if (optionalResolverOptions.has_value()) {
         const ResolverOptionsParcel& resolverOptions = optionalResolverOptions.value();
-        for (const auto& host : resolverOptions.hosts) {
-            if (!host.hostName.empty() && !host.ipAddr.empty())
-                netconfig->customizedTable.emplace(host.hostName, host.ipAddr);
-        }
-
-        if (resolverOptions.tcMode < aidl::android::net::IDnsResolver::TC_MODE_DEFAULT ||
-            resolverOptions.tcMode > aidl::android::net::IDnsResolver::TC_MODE_UDP_TCP) {
-            LOG(WARNING) << __func__ << ": netid = " << netid
-                         << ", invalid TC mode: " << resolverOptions.tcMode;
-            return -EINVAL;
-        }
-        netconfig->tc_mode = resolverOptions.tcMode;
-        netconfig->enforceDnsUid = resolverOptions.enforceDnsUid;
+        return netconfig->setOptions(resolverOptions);
     }
-
-    netconfig->transportTypes = transportTypes;
-
     return 0;
 }
 
+int resolv_set_options(unsigned netid, const ResolverOptionsParcel& options) {
+    std::lock_guard guard(cache_mutex);
+    NetConfig* netconfig = find_netconfig_locked(netid);
+
+    if (netconfig == nullptr) return -ENONET;
+    return netconfig->setOptions(options);
+}
+
 static bool resolv_is_nameservers_equal(const std::vector<std::string>& oldServers,
                                         const std::vector<std::string>& newServers) {
     const std::set<std::string> olds(oldServers.begin(), oldServers.end());
diff --git a/resolv_cache.h b/resolv_cache.h
index 7011e5a..970459b 100644
--- a/resolv_cache.h
+++ b/resolv_cache.h
@@ -82,6 +82,9 @@
                            std::optional<aidl::android::net::ResolverOptionsParcel> resolverOptions,
                            const std::vector<int32_t>& transportTypes = {});
 
+// Sets options for a given network.
+int resolv_set_options(unsigned netid, const aidl::android::net::ResolverOptionsParcel& options);
+
 // Creates the cache associated with the given network.
 int resolv_create_cache_for_net(unsigned netid);
 
diff --git a/tests/dnsresolver_binder_test.cpp b/tests/dnsresolver_binder_test.cpp
index 3f478fa..55a67e1 100644
--- a/tests/dnsresolver_binder_test.cpp
+++ b/tests/dnsresolver_binder_test.cpp
@@ -626,3 +626,18 @@
     EXPECT_TRUE(mDnsResolver->setLogSeverity(IDnsResolver::DNS_RESOLVER_LOG_WARNING).isOk());
     mExpectedLogData.push_back({"setLogSeverity(3)", "setLogSeverity.*3"});
 }
+
+TEST_F(DnsResolverBinderTest, SetResolverOptions) {
+    SKIP_IF_REMOTE_VERSION_LESS_THAN(mDnsResolver.get(), 9);
+    ResolverOptionsParcel options;
+    options.tcMode = 1;
+    options.enforceDnsUid = true;
+    EXPECT_TRUE(mDnsResolver->setResolverOptions(TEST_NETID, options).isOk());
+    mExpectedLogData.push_back(
+            {"setResolverOptions(30, " + toString(options) + ")", "setResolverOptions.*30"});
+    EXPECT_EQ(ENONET, mDnsResolver->setResolverOptions(-1, options).getServiceSpecificError());
+    mExpectedLogData.push_back({"setResolverOptions(-1, " + toString(options) +
+                                        ") -> ServiceSpecificException(64, \"Machine is not on the "
+                                        "network\")",
+                                "setResolverOptions.*-1.*64"});
+}
diff --git a/tests/resolv_integration_test.cpp b/tests/resolv_integration_test.cpp
index 6213b6c..b602d85 100644
--- a/tests/resolv_integration_test.cpp
+++ b/tests/resolv_integration_test.cpp
@@ -102,6 +102,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::metrics::INetdEventListener;
 using aidl::android::net::resolv::aidl::DnsHealthEventParcel;
@@ -237,6 +238,8 @@
         mDnsClient.SetUp();
         sDnsMetricsListener->reset();
         sUnsolicitedEventListener->reset();
+        mIsResolverOptionIPCSupported =
+                DnsResponderClient::isRemoteVersionSupported(mDnsClient.resolvService(), 9);
     }
 
     void TearDown() {
@@ -404,6 +407,8 @@
 
     DnsResponderClient mDnsClient;
 
+    bool mIsResolverOptionIPCSupported = false;
+
     // Use a shared static DNS listener for all tests to avoid registering lots of listeners
     // which may be released late until process terminated. Currently, registered DNS listener
     // is removed by binder death notification which is fired when the process hosting an
@@ -1315,8 +1320,18 @@
     test::DNSResponder dns;
     StartDns(dns, {});
     auto resolverParams = DnsResponderClient::GetDefaultResolverParamsParcel();
-    resolverParams.resolverOptions->hosts = invalidCustHosts;
+
+    ResolverOptionsParcel resolverOptions;
+    resolverOptions.hosts = invalidCustHosts;
+    if (!mIsResolverOptionIPCSupported) {
+        resolverParams.resolverOptions = resolverOptions;
+    }
     ASSERT_TRUE(mDnsClient.resolvService()->setResolverConfiguration(resolverParams).isOk());
+    if (mIsResolverOptionIPCSupported) {
+        ASSERT_TRUE(mDnsClient.resolvService()
+                            ->setResolverOptions(resolverParams.netId, resolverOptions)
+                            .isOk());
+    }
     for (const auto& hostname : {hostnameNoip, hostnameInvalidip}) {
         // The query won't get data from customized table because of invalid customized table
         // and DNSResponder also has no records. hostnameNoip has never registered and
@@ -1390,8 +1405,18 @@
         StartDns(dns, config.dnsserverHosts);
 
         auto resolverParams = DnsResponderClient::GetDefaultResolverParamsParcel();
-        resolverParams.resolverOptions->hosts = config.customizedHosts;
+        ResolverOptionsParcel resolverOptions;
+        resolverOptions.hosts = config.customizedHosts;
+        if (!mIsResolverOptionIPCSupported) {
+            resolverParams.resolverOptions = resolverOptions;
+        }
         ASSERT_TRUE(mDnsClient.resolvService()->setResolverConfiguration(resolverParams).isOk());
+
+        if (mIsResolverOptionIPCSupported) {
+            ASSERT_TRUE(mDnsClient.resolvService()
+                                ->setResolverOptions(resolverParams.netId, resolverOptions)
+                                .isOk());
+        }
         const addrinfo hints = {.ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM};
         ScopedAddrinfo result = safe_getaddrinfo(config.name.c_str(), nullptr, &hints);
         if (config.customizedHosts.empty() && config.dnsserverHosts.empty()) {
@@ -1426,16 +1451,34 @@
     StartDns(dns, dnsSvHostV4V6);
     auto resolverParams = DnsResponderClient::GetDefaultResolverParamsParcel();
 
-    resolverParams.resolverOptions->hosts = custHostV4V6;
+    ResolverOptionsParcel resolverOptions;
+    resolverOptions.hosts = custHostV4V6;
+    if (!mIsResolverOptionIPCSupported) {
+        resolverParams.resolverOptions = resolverOptions;
+    }
     ASSERT_TRUE(mDnsClient.resolvService()->setResolverConfiguration(resolverParams).isOk());
+
+    if (mIsResolverOptionIPCSupported) {
+        ASSERT_TRUE(mDnsClient.resolvService()
+                            ->setResolverOptions(resolverParams.netId, resolverOptions)
+                            .isOk());
+    }
+
     const addrinfo hints = {.ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM};
     ScopedAddrinfo result = safe_getaddrinfo(hostnameV4V6, nullptr, &hints);
     ASSERT_TRUE(result != nullptr);
     EXPECT_THAT(ToStrings(result), testing::UnorderedElementsAreArray({custAddrV4, custAddrV6}));
     EXPECT_EQ(0U, GetNumQueries(dns, hostnameV4V6));
 
-    resolverParams.resolverOptions->hosts = {};
-    ASSERT_TRUE(mDnsClient.resolvService()->setResolverConfiguration(resolverParams).isOk());
+    resolverOptions.hosts = {};
+    if (!mIsResolverOptionIPCSupported) {
+        resolverParams.resolverOptions = resolverOptions;
+        ASSERT_TRUE(mDnsClient.resolvService()->setResolverConfiguration(resolverParams).isOk());
+    } else {
+        ASSERT_TRUE(mDnsClient.resolvService()
+                            ->setResolverOptions(resolverParams.netId, resolverOptions)
+                            .isOk());
+    }
     result = safe_getaddrinfo(hostnameV4V6, nullptr, &hints);
     ASSERT_TRUE(result != nullptr);
     EXPECT_THAT(ToStrings(result), testing::UnorderedElementsAreArray({dnsSvAddrV4, dnsSvAddrV6}));
@@ -4365,8 +4408,17 @@
     }
 
     memset(buf, 0, MAXPACKET);
-    parcel.resolverOptions->enforceDnsUid = true;
-    ASSERT_TRUE(mDnsClient.resolvService()->setResolverConfiguration(parcel).isOk());
+    ResolverOptionsParcel resolverOptions;
+    resolverOptions.enforceDnsUid = true;
+    if (!mIsResolverOptionIPCSupported) {
+        parcel.resolverOptions = resolverOptions;
+        ASSERT_TRUE(mDnsClient.resolvService()->setResolverConfiguration(parcel).isOk());
+    } else {
+        ASSERT_TRUE(mDnsClient.resolvService()
+                            ->setResolverOptions(parcel.netId, resolverOptions)
+                            .isOk());
+    }
+
     {
         ScopeBlockedUIDRule scopeBlockUidRule(netdService, TEST_UID);
         // Dns Queries should NOT be blocked
@@ -5042,8 +5094,8 @@
             // clang-format off
             {std::nullopt,                                      true,  0}, /* mode unset */
             {aidl::android::net::IDnsResolver::TC_MODE_DEFAULT, true,  0}, /* default mode */
+            {-666,                                              false, 0}, /* invalid input */
             {aidl::android::net::IDnsResolver::TC_MODE_UDP_TCP, true,  1}, /* alternative mode */
-            {-666,                                              false, 1}, /* invalid input */
             // clang-format on
     };
 
@@ -5052,10 +5104,21 @@
 
         ResolverParamsParcel parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
         parcel.servers = {listen_addr, listen_addr2};
-        if (config.tcMode) {
-            parcel.resolverOptions->tcMode = config.tcMode.value();
+        ResolverOptionsParcel resolverOptions;
+        if (config.tcMode.has_value()) resolverOptions.tcMode = config.tcMode.value();
+        if (!mIsResolverOptionIPCSupported) {
+            parcel.resolverOptions = resolverOptions;
+            ASSERT_EQ(mDnsClient.resolvService()->setResolverConfiguration(parcel).isOk(),
+                      config.ret);
+        } else {
+            ASSERT_TRUE(mDnsClient.resolvService()->setResolverConfiguration(parcel).isOk());
         }
-        ASSERT_EQ(mDnsClient.resolvService()->setResolverConfiguration(parcel).isOk(), config.ret);
+        if (mIsResolverOptionIPCSupported) {
+            ASSERT_EQ(mDnsClient.resolvService()
+                              ->setResolverOptions(parcel.netId, resolverOptions)
+                              .isOk(),
+                      config.ret);
+        }
 
         const addrinfo hints = {.ai_family = AF_INET, .ai_socktype = SOCK_DGRAM};
         ScopedAddrinfo result = safe_getaddrinfo("hello", nullptr, &hints);
@@ -5075,7 +5138,12 @@
         // Clear the stats to make the resolver always choose the same server for the first query.
         parcel.servers.clear();
         parcel.tlsServers.clear();
-        ASSERT_EQ(mDnsClient.resolvService()->setResolverConfiguration(parcel).isOk(), config.ret);
+        if (!mIsResolverOptionIPCSupported) {
+            ASSERT_EQ(mDnsClient.resolvService()->setResolverConfiguration(parcel).isOk(),
+                      config.ret);
+        } else {
+            ASSERT_TRUE(mDnsClient.resolvService()->setResolverConfiguration(parcel).isOk());
+        }
     }
 }