diff options
-rw-r--r-- | Experiments.h | 1 | ||||
-rw-r--r-- | PrivateDnsConfiguration.cpp | 5 | ||||
-rw-r--r-- | doh.h | 1 | ||||
-rw-r--r-- | doh/ffi.rs | 3 | ||||
-rw-r--r-- | doh/network/driver.rs | 3 | ||||
-rw-r--r-- | doh/network/mod.rs | 1 | ||||
-rw-r--r-- | tests/doh_ffi_test.cpp | 1 | ||||
-rw-r--r-- | tests/resolv_private_dns_test.cpp | 65 |
8 files changed, 66 insertions, 14 deletions
diff --git a/Experiments.h b/Experiments.h index d03759e1..ea267e82 100644 --- a/Experiments.h +++ b/Experiments.h @@ -65,6 +65,7 @@ class Experiments { "doh_query_timeout_ms", "doh_probe_timeout_ms", "doh_idle_timeout_ms", + "doh_session_resumption", "mdns_resolution", }; // This value is used in updateInternal as the default value if any flags can't be found. diff --git a/PrivateDnsConfiguration.cpp b/PrivateDnsConfiguration.cpp index 0fef5fe7..dd0be8f4 100644 --- a/PrivateDnsConfiguration.cpp +++ b/PrivateDnsConfiguration.cpp @@ -505,9 +505,12 @@ int PrivateDnsConfiguration::setDoh(int32_t netId, uint32_t mark, getTimeoutFromFlag("doh_probe_timeout_ms", kDohProbeDefaultTimeoutMs), .idle_timeout_ms = getTimeoutFromFlag("doh_idle_timeout_ms", kDohIdleDefaultTimeoutMs), + .use_session_resumption = + Experiments::getInstance()->getFlag("doh_session_resumption", 0) == 1, }; LOG(DEBUG) << __func__ << ": probe_timeout_ms=" << flags.probe_timeout_ms - << ", idle_timeout_ms=" << flags.idle_timeout_ms; + << ", idle_timeout_ms=" << flags.idle_timeout_ms + << ", use_session_resumption=" << flags.use_session_resumption; return doh_net_new(mDohDispatcher, netId, dohId.httpsTemplate.c_str(), dohId.host.c_str(), dohId.ipAddr.c_str(), mark, caCert.c_str(), &flags); @@ -53,6 +53,7 @@ struct DohDispatcher; struct FeatureFlags { uint64_t probe_timeout_ms; uint64_t idle_timeout_ms; + bool use_session_resumption; }; using ValidationCallback = void (*)(uint32_t net_id, bool success, const char* ip_addr, @@ -42,6 +42,7 @@ pub type TagSocketCallback = extern "C" fn(sock: RawFd); pub struct FeatureFlags { probe_timeout_ms: uint64_t, idle_timeout_ms: uint64_t, + use_session_resumption: bool, } fn wrap_validation_callback(validation_fn: ValidationCallback) -> ValidationReporter { @@ -231,6 +232,7 @@ pub unsafe extern "C" fn doh_net_new( sk_mark, cert_path, idle_timeout_ms: flags.idle_timeout_ms, + use_session_resumption: flags.use_session_resumption, }, timeout: Duration::from_millis(flags.probe_timeout_ms), }; @@ -381,6 +383,7 @@ mod tests { sk_mark: 0, cert_path: None, idle_timeout_ms: 0, + use_session_resumption: true, }; wrap_validation_callback(success_cb)(&info, true).await; diff --git a/doh/network/driver.rs b/doh/network/driver.rs index 67c32ae7..375ac2c1 100644 --- a/doh/network/driver.rs +++ b/doh/network/driver.rs @@ -185,7 +185,8 @@ impl Driver { } if !self.connection.wait_for_live().await { - let session = self.connection.session(); + let session = + if self.info.use_session_resumption { self.connection.session() } else { None }; // Try reconnecting self.connection = build_connection(&self.info, &self.tag_socket, &mut self.config, session).await?; diff --git a/doh/network/mod.rs b/doh/network/mod.rs index 21e47ec3..19be8643 100644 --- a/doh/network/mod.rs +++ b/doh/network/mod.rs @@ -48,6 +48,7 @@ pub struct ServerInfo { pub sk_mark: u32, pub cert_path: Option<String>, pub idle_timeout_ms: u64, + pub use_session_resumption: bool, } #[derive(Debug)] diff --git a/tests/doh_ffi_test.cpp b/tests/doh_ffi_test.cpp index 954e1ced..d858a760 100644 --- a/tests/doh_ffi_test.cpp +++ b/tests/doh_ffi_test.cpp @@ -56,6 +56,7 @@ TEST(DoHFFITest, SmokeTest) { const FeatureFlags flags = { .probe_timeout_ms = TIMEOUT_MS, .idle_timeout_ms = TIMEOUT_MS, + .use_session_resumption = true, }; // TODO: Use a local server instead of dns.google. diff --git a/tests/resolv_private_dns_test.cpp b/tests/resolv_private_dns_test.cpp index 931d60cb..1791bb64 100644 --- a/tests/resolv_private_dns_test.cpp +++ b/tests/resolv_private_dns_test.cpp @@ -51,11 +51,14 @@ using android::netdutils::IPSockAddr; using android::netdutils::ScopedAddrinfo; using android::netdutils::Stopwatch; using std::chrono::milliseconds; +using std::this_thread::sleep_for; const std::string kDohFlag("persist.device_config.netd_native.doh"); const std::string kDohQueryTimeoutFlag("persist.device_config.netd_native.doh_query_timeout_ms"); const std::string kDohProbeTimeoutFlag("persist.device_config.netd_native.doh_probe_timeout_ms"); const std::string kDohIdleTimeoutFlag("persist.device_config.netd_native.doh_idle_timeout_ms"); +const std::string kDohSessionResumptionFlag( + "persist.device_config.netd_native.doh_session_resumption"); constexpr int MAXPACKET = (8 * 1024); @@ -217,7 +220,7 @@ class BaseTest : public ::testing::Test { } bool hasUncaughtPrivateDnsValidation(const std::string& serverAddr) { - std::this_thread::sleep_for(std::chrono::milliseconds(200)); + sleep_for(milliseconds(200)); return sUnsolicitedEventListener->findValidationRecord( serverAddr, IDnsResolverUnsolicitedEventListener::PROTOCOL_DOT) || sUnsolicitedEventListener->findValidationRecord( @@ -690,7 +693,7 @@ TEST_F(PrivateDnsDohTest, TemporaryConnectionStalled) { Stopwatch s; int fd = resNetworkQuery(TEST_NETID, kQueryHostname, ns_c_in, ns_t_a, ANDROID_RESOLV_NO_CACHE_LOOKUP); - std::this_thread::sleep_for(std::chrono::milliseconds(connectionStalledTimeMs)); + sleep_for(milliseconds(connectionStalledTimeMs)); EXPECT_TRUE(doh.block_sending(false)); expectAnswersValid(fd, AF_INET, kQueryAnswerA); @@ -714,7 +717,7 @@ TEST_F(PrivateDnsDohTest, ExcessDnsRequests) { EXPECT_TRUE(doh.setMaxIdleTimeout(initial_max_idle_timeout_ms)); // Sleep a while to avoid binding socket failed. // TODO: Make DohFrontend retry binding sockets. - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + sleep_for(milliseconds(100)); ASSERT_TRUE(doh.startServer()); auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel(); @@ -767,7 +770,7 @@ TEST_F(PrivateDnsDohTest, ExcessDnsRequests) { // Sleep a while to wait for DoH and DoT validation. // TODO: Extend WaitForDohValidation() to support passing a netId. - std::this_thread::sleep_for(std::chrono::milliseconds(200)); + sleep_for(milliseconds(200)); EXPECT_TRUE(dot_ipv6.waitForQueries(1)); int fd = resNetworkQuery(TEST_NETID_2, kQueryHostname, ns_c_in, ns_t_aaaa, @@ -793,7 +796,7 @@ TEST_F(PrivateDnsDohTest, RunOutOfDataLimit) { EXPECT_TRUE(doh.setMaxBufferSize(initial_max_data)); // Sleep a while to avoid binding socket failed. // TODO: Make DohFrontend retry binding sockets. - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + sleep_for(milliseconds(100)); ASSERT_TRUE(doh.startServer()); const auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel(); @@ -815,7 +818,7 @@ TEST_F(PrivateDnsDohTest, RunOutOfDataLimit) { expectAnswersValid(fd, AF_INET, kQueryAnswerA); }); } - std::this_thread::sleep_for(std::chrono::milliseconds(500)); + sleep_for(milliseconds(500)); EXPECT_TRUE(doh.block_sending(false)); // In current implementation, the fifth DoH query will get blocked and result in timeout. @@ -844,7 +847,7 @@ TEST_F(PrivateDnsDohTest, RunOutOfStreams) { ASSERT_TRUE(doh.stopServer()); EXPECT_TRUE(doh.setMaxStreamsBidi(initial_max_streams_bidi)); // Sleep a while to avoid binding socket failed. - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + sleep_for(milliseconds(100)); ASSERT_TRUE(doh.startServer()); const auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel(); @@ -866,7 +869,7 @@ TEST_F(PrivateDnsDohTest, RunOutOfStreams) { expectAnswersValid(fd, AF_INET, kQueryAnswerA); }); } - std::this_thread::sleep_for(std::chrono::milliseconds(500)); + sleep_for(milliseconds(500)); EXPECT_TRUE(doh.block_sending(false)); for (std::thread& thread : threads) { @@ -884,7 +887,7 @@ TEST_F(PrivateDnsDohTest, ReconnectAfterIdleTimeout) { ASSERT_TRUE(doh.stopServer()); EXPECT_TRUE(doh.setMaxIdleTimeout(initial_max_idle_timeout_ms)); // Sleep a while to avoid binding socket failed. - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + sleep_for(milliseconds(100)); ASSERT_TRUE(doh.startServer()); const auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel(); @@ -898,7 +901,7 @@ TEST_F(PrivateDnsDohTest, ReconnectAfterIdleTimeout) { for (int i = 0; i < 5; i++) { SCOPED_TRACE(fmt::format("Round: {}", i)); - std::this_thread::sleep_for(std::chrono::milliseconds(initial_max_idle_timeout_ms + 500)); + sleep_for(milliseconds(initial_max_idle_timeout_ms + 500)); // As the connection is closed, the DnsResolver will reconnect to the DoH server // for this DNS request. @@ -909,7 +912,6 @@ TEST_F(PrivateDnsDohTest, ReconnectAfterIdleTimeout) { EXPECT_NO_FAILURE(expectQueries(0 /* dns */, 0 /* dot */, 5 /* doh */)); EXPECT_EQ(doh.connections(), 6); - EXPECT_EQ(doh.resumedConnections(), 5); } // Tests that the experiment flag doh_idle_timeout_ms is effective. @@ -945,9 +947,48 @@ TEST_F(PrivateDnsDohTest, ConnectionIdleTimer) { EXPECT_EQ(doh.connections(), 1); // Expect that the DoH connection gets disconnected while sleeping. - std::this_thread::sleep_for(std::chrono::milliseconds(connection_idle_timeout + tolerance_ms)); + sleep_for(milliseconds(connection_idle_timeout + tolerance_ms)); EXPECT_NO_FAILURE(sendQueryAndCheckResult()); EXPECT_NO_FAILURE(expectQueries(0 /* dns */, 0 /* dot */, 4 /* doh */)); EXPECT_EQ(doh.connections(), 2); } + +// Tests that the flag "doh_session_resumption" works as expected. +TEST_F(PrivateDnsDohTest, SessionResumption) { + const int initial_max_idle_timeout_ms = 1000; + for (const auto& flag : {"0", "1"}) { + auto sp = make_unique<ScopedSystemProperties>(kDohSessionResumptionFlag, flag); + resetNetwork(); + + ASSERT_TRUE(doh.stopServer()); + EXPECT_TRUE(doh.setMaxIdleTimeout(initial_max_idle_timeout_ms)); + // Sleep a while to avoid binding socket failed. + sleep_for(milliseconds(100)); + ASSERT_TRUE(doh.startServer()); + + const auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel(); + ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel)); + EXPECT_TRUE(WaitForDohValidation(test::kDefaultListenAddr, true)); + EXPECT_TRUE(WaitForDotValidation(test::kDefaultListenAddr, true)); + EXPECT_TRUE(dot.waitForQueries(1)); + dot.clearQueries(); + doh.clearQueries(); + dns.clearQueries(); + + for (int i = 0; i < 2; i++) { + SCOPED_TRACE(fmt::format("Round: {}", i)); + sleep_for(milliseconds(initial_max_idle_timeout_ms + 500)); + + // As the connection is closed, the DnsResolver will reconnect to the DoH server + // for this DNS request. + int fd = resNetworkQuery(TEST_NETID, kQueryHostname, ns_c_in, ns_t_a, + ANDROID_RESOLV_NO_CACHE_LOOKUP); + expectAnswersValid(fd, AF_INET, kQueryAnswerA); + } + + EXPECT_NO_FAILURE(expectQueries(0 /* dns */, 0 /* dot */, 2 /* doh */)); + EXPECT_EQ(doh.connections(), 3); + EXPECT_EQ(doh.resumedConnections(), (flag == "1" ? 2 : 0)); + } +} |