Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1942b662 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 8603585 from fb515a5f to mainline-tethering-release

Change-Id: I49801d65104f1d086d3de3b03200f2e8eec12c39
parents 45378a27 fb515a5f
Loading
Loading
Loading
Loading
+34 −29
Original line number Diff line number Diff line
@@ -67,8 +67,7 @@ std::list<DnsTlsServer> DnsTlsDispatcher::getOrderedAndUsableServerList(

        for (const auto& tlsServer : tlsServers) {
            const Key key = std::make_pair(mark, tlsServer);
            if (const Transport* xport = getTransport(key); xport != nullptr) {
                // DoT revalidation specific feature.
            if (Transport* xport = getTransport(key); xport != nullptr) {
                if (!xport->usable()) {
                    // Don't use this xport. It will be removed after timeout
                    // (IDLE_TIMEOUT minutes).
@@ -112,7 +111,13 @@ DnsTlsTransport::Response DnsTlsDispatcher::query(const std::list<DnsTlsServer>&
    const std::list<DnsTlsServer> servers(
            getOrderedAndUsableServerList(tlsServers, statp->netid, statp->mark));

    if (servers.empty()) LOG(WARNING) << "No usable DnsTlsServers";
    if (servers.empty()) {
        LOG(WARNING) << "No usable DnsTlsServers";

        // Call cleanup so the expired Transports can be removed as expected.
        std::lock_guard guard(sLock);
        cleanup(std::chrono::steady_clock::now());
    }

    DnsTlsTransport::Response code = DnsTlsTransport::Response::internal_error;
    int serverCount = 0;
@@ -209,9 +214,14 @@ DnsTlsTransport::Response DnsTlsDispatcher::query(const DnsTlsServer& server, un
        std::lock_guard guard(sLock);
        --xport->useCount;
        xport->lastUsed = now;
        if (code == DnsTlsTransport::Response::network_error) {
            xport->continuousfailureCount++;
        } else {
            xport->continuousfailureCount = 0;
        }

        // DoT revalidation specific feature.
        if (xport->checkRevalidationNecessary(code)) {
        if (xport->checkRevalidationNecessary()) {
            // Even if the revalidation passes, it doesn't guarantee that DoT queries
            // to the xport can stop failing because revalidation creates a new connection
            // to probe while the xport still uses an existing connection. So far, there isn't
@@ -308,12 +318,11 @@ DnsTlsDispatcher::Transport* DnsTlsDispatcher::addTransport(const DnsTlsServer&
    int queryTimeout = instance->getFlag("dot_query_timeout_ms", Transport::kDotQueryTimeoutMs);

    // Check and adjust the parameters if they are improperly set.
    bool revalidationEnabled = false;
    const bool isForOpportunisticMode = server.name.empty();
    if (triggerThr > 0 && unusableThr > 0 && isForOpportunisticMode) {
        revalidationEnabled = true;
    } else {
    if (triggerThr <= 0 || !isForOpportunisticMode) {
        triggerThr = -1;
    }
    if (unusableThr <= 0 || !isForOpportunisticMode) {
        unusableThr = -1;
    }
    if (queryTimeout < 0) {
@@ -322,9 +331,8 @@ DnsTlsDispatcher::Transport* DnsTlsDispatcher::addTransport(const DnsTlsServer&
        queryTimeout = 1000;
    }

    ret = new Transport(server, mark, netId, mFactory.get(), revalidationEnabled, triggerThr,
                        unusableThr, queryTimeout);
    LOG(DEBUG) << "Transport is initialized with { " << triggerThr << ", " << unusableThr << ", "
    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 << " }";

@@ -338,26 +346,23 @@ DnsTlsDispatcher::Transport* DnsTlsDispatcher::getTransport(const Key& key) {
    return (it == mStore.end() ? nullptr : it->second.get());
}

bool DnsTlsDispatcher::Transport::checkRevalidationNecessary(DnsTlsTransport::Response code) {
    if (!revalidationEnabled) return false;
bool DnsTlsDispatcher::Transport::checkRevalidationNecessary() {
    if (triggerThreshold <= 0) return false;
    if (continuousfailureCount < triggerThreshold) return false;
    if (isRevalidationThresholdReached) return false;

    if (code == DnsTlsTransport::Response::network_error) {
        continuousfailureCount++;
    } else {
        continuousfailureCount = 0;
    }

    // triggerThreshold must be greater than 0 because the value of revalidationEnabled is true.
    if (usable() && continuousfailureCount == triggerThreshold) {
    isRevalidationThresholdReached = true;
    return true;
}
    return false;
}

bool DnsTlsDispatcher::Transport::usable() const {
    if (!revalidationEnabled) return true;
bool DnsTlsDispatcher::Transport::usable() {
    if (unusableThreshold <= 0) return true;

    return continuousfailureCount < unusableThreshold;
    if (continuousfailureCount >= unusableThreshold) {
        // Once reach the threshold, mark this Transport as unusable.
        isXportUnusableThresholdReached = true;
    }
    return !isXportUnusableThresholdReached;
}

}  // end of namespace net
+20 −19
Original line number Diff line number Diff line
@@ -83,11 +83,10 @@ class DnsTlsDispatcher : public PrivateDnsValidationObserver {
    // usage monitoring so we can expire idle sessions from the cache.
    struct Transport {
        Transport(const DnsTlsServer& server, unsigned mark, unsigned netId,
                  IDnsTlsSocketFactory* _Nonnull factory, bool revalidationEnabled, int triggerThr,
                  int unusableThr, int timeout)
                  IDnsTlsSocketFactory* _Nonnull factory, int triggerThr, int unusableThr,
                  int timeout)
            : transport(server, mark, factory),
              mNetId(netId),
              revalidationEnabled(revalidationEnabled),
              triggerThreshold(triggerThr),
              unusableThreshold(unusableThr),
              mTimeout(timeout) {}
@@ -106,9 +105,12 @@ class DnsTlsDispatcher : public PrivateDnsValidationObserver {

        // If DoT revalidation is disabled, it returns true; otherwise, it returns
        // whether or not this Transport is usable.
        bool usable() const REQUIRES(sLock);
        bool usable() REQUIRES(sLock);

        bool checkRevalidationNecessary(DnsTlsTransport::Response code) REQUIRES(sLock);
        // Used to track if this Transport is usable.
        int continuousfailureCount GUARDED_BY(sLock) = 0;

        bool checkRevalidationNecessary() REQUIRES(sLock);

        std::chrono::milliseconds timeout() const { return mTimeout; }

@@ -117,25 +119,24 @@ class DnsTlsDispatcher : public PrivateDnsValidationObserver {
        static constexpr int kDotQueryTimeoutMs = -1;

      private:
        // Used to track if this Transport is usable.
        int continuousfailureCount GUARDED_BY(sLock) = 0;
        // The flag to record whether or not dot_revalidation_threshold is ever reached.
        bool isRevalidationThresholdReached GUARDED_BY(sLock) = false;

        // Used to indicate whether DoT revalidation is enabled for this Transport.
        // The value is set to true only if:
        //    1. both triggerThreshold and unusableThreshold are  positive values.
        //    2. private DNS mode is opportunistic.
        const bool revalidationEnabled;
        // The flag to record whether or not dot_xport_unusable_threshold is ever reached.
        bool isXportUnusableThresholdReached GUARDED_BY(sLock) = false;

        // The number of continuous failures to trigger a validation. It takes effect when DoT
        // revalidation is on. If the value is not a positive value, DoT revalidation is disabled.
        // Note that it must be at least 10, or it breaks ConnectTlsServerTimeout_ConcurrentQueries
        // test.
        // If the number of continuous query timeouts reaches the threshold, mark the
        // server as unvalidated and trigger a validation.
        // If the value is not a positive value or private DNS mode is strict mode, no threshold is
        // set. Note that it must be at least 10, or it breaks
        // ConnectTlsServerTimeout_ConcurrentQueries test.
        const int triggerThreshold;

        // The threshold to determine if this Transport is considered unusable.
        // If continuousfailureCount reaches this value, this Transport is no longer used. It
        // takes effect when DoT revalidation is on. If the value is not a positive value, DoT
        // revalidation is disabled.
        // If the number of continuous query timeouts reaches the threshold, mark this
        // Transport as unusable. An unusable Transport won't be used anymore.
        // If the value is not a positive value or private DNS mode is strict mode, no threshold is
        // set.
        const int unusableThreshold;

        // The time to await a future (the result of a DNS request) from the DnsTlsTransport
+107 −3
Original line number Diff line number Diff line
@@ -2907,6 +2907,11 @@ TEST_F(ResolverTest, BrokenEdns) {
        const std::string testHostName = config.asHostName();
        SCOPED_TRACE(testHostName);

        // Don't skip unusable DoT servers and disable revalidation for this test.
        ScopedSystemProperties sp1(kDotXportUnusableThresholdFlag, "-1");
        ScopedSystemProperties sp2(kDotRevalidationThresholdFlag, "-1");
        resetNetwork();

        const char* host_name = testHostName.c_str();
        dns.addMapping(host_name, ns_type::ns_t_a, ADDR4);
        dns.setEdns(config.edns);
@@ -4572,6 +4577,10 @@ TEST_F(ResolverTest, ConnectTlsServerTimeout) {

        ScopedSystemProperties sp3(kDotAsyncHandshakeFlag, config.asyncHandshake ? "1" : "0");
        ScopedSystemProperties sp4(kDotMaxretriesFlag, std::to_string(config.maxRetries));

        // Don't skip unusable DoT servers and disable revalidation for this test.
        ScopedSystemProperties sp5(kDotXportUnusableThresholdFlag, "-1");
        ScopedSystemProperties sp6(kDotRevalidationThresholdFlag, "-1");
        resetNetwork();

        // Set up resolver to opportunistic mode.
@@ -4662,6 +4671,10 @@ TEST_F(ResolverTest, ConnectTlsServerTimeout_ConcurrentQueries) {
                                   std::to_string(config.dotConnectTimeoutMs));
        ScopedSystemProperties sp3(kDotAsyncHandshakeFlag, config.asyncHandshake ? "1" : "0");
        ScopedSystemProperties sp4(kDotMaxretriesFlag, std::to_string(config.maxRetries));

        // Don't skip unusable DoT servers and disable revalidation for this test.
        ScopedSystemProperties sp5(kDotXportUnusableThresholdFlag, "-1");
        ScopedSystemProperties sp6(kDotRevalidationThresholdFlag, "-1");
        resetNetwork();

        for (const auto& dnsMode : {"OPPORTUNISTIC", "STRICT"}) {
@@ -4744,6 +4757,10 @@ TEST_F(ResolverTest, QueryTlsServerTimeout) {
            ASSERT_TRUE(tls.startServer());

            ScopedSystemProperties sp(kDotQueryTimeoutMsFlag, std::to_string(queryTimeoutMs));

            // Don't skip unusable DoT servers and disable revalidation for this test.
            ScopedSystemProperties sp2(kDotXportUnusableThresholdFlag, "-1");
            ScopedSystemProperties sp3(kDotRevalidationThresholdFlag, "-1");
            resetNetwork();

            auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
@@ -4787,8 +4804,86 @@ TEST_F(ResolverTest, QueryTlsServerTimeout) {
            // Also check how much time the resolver processed the query.
            timeTakenMs = s.timeTakenUs() / 1000;
            EXPECT_LE(timeTakenMs, 500);
            EXPECT_EQ(2, tls.queries());
            EXPECT_TRUE(tls.waitForQueries(2));
        }
    }
}

// Tests that the DnsResolver can skip using unusable DoT servers if dot_xport_unusable_threshold
// flag is set. In this test, we make test DoT servers unresponsive during connection handshake,
// so the DnsResolver will skip using a DoT server if the number of timed out queries reaches
// the threshold.
TEST_F(ResolverTest, SkipUnusableTlsServer) {
    constexpr int DOT_CONNECT_TIMEOUT_MS = 1000;

    static const struct TestConfig {
        int dotXportUnusableThreshold;
        int queries;
        int expectedQueriesSentToDot1;
        int expectedQueriesSentToDot2;
    } testConfigs[] = {
            // clang-format off
            // expectedQueriesSentToDot2 is 0 because dot_quick_fallback flag is set.
            {-1,  3, 3, 0},
            { 1,  3, 1, 1},
            { 3, 10, 3, 3},
            // clang-format on
    };

    for (const auto& config : testConfigs) {
        SCOPED_TRACE(fmt::format("testConfig: [{}, {}, {}, {}]", config.dotXportUnusableThreshold,
                                 config.queries, config.expectedQueriesSentToDot1,
                                 config.expectedQueriesSentToDot2));

        const std::string addr1 = getUniqueIPv4Address();
        const std::string addr2 = getUniqueIPv4Address();
        test::DNSResponder dns1(addr1);
        test::DNSResponder dns2(addr2);
        test::DnsTlsFrontend dot1(addr1, "853", addr1, "53");
        test::DnsTlsFrontend dot2(addr2, "853", addr2, "53");
        dns1.addMapping(kHelloExampleCom, ns_type::ns_t_aaaa, kHelloExampleComAddrV6);
        dns2.addMapping(kHelloExampleCom, ns_type::ns_t_aaaa, kHelloExampleComAddrV6);
        ASSERT_TRUE(dns1.startServer());
        ASSERT_TRUE(dns2.startServer());
        ASSERT_TRUE(dot1.startServer());
        ASSERT_TRUE(dot2.startServer());

        ScopedSystemProperties sp1(kDotConnectTimeoutMsFlag,
                                   std::to_string(DOT_CONNECT_TIMEOUT_MS));
        ScopedSystemProperties sp2(kDotXportUnusableThresholdFlag,
                                   std::to_string(config.dotXportUnusableThreshold));
        ScopedSystemProperties sp3(kDotQuickFallbackFlag, "1");
        ScopedSystemProperties sp4(kDotRevalidationThresholdFlag, "-1");
        resetNetwork();

        // Private DNS opportunistic mode.
        auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
        parcel.servers = {addr1, addr2};
        parcel.tlsServers = {addr1, addr2};
        ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));

        EXPECT_TRUE(WaitForPrivateDnsValidation(dot1.listen_address(), true));
        EXPECT_TRUE(WaitForPrivateDnsValidation(dot2.listen_address(), true));
        EXPECT_TRUE(dot1.waitForQueries(1));
        EXPECT_TRUE(dot2.waitForQueries(1));
        dot1.clearQueries();
        dot2.clearQueries();
        dot1.clearConnectionsCount();
        dot2.clearConnectionsCount();

        // Set the DoT servers as unresponsive to connection handshake.
        dot1.setHangOnHandshakeForTesting(true);
        dot2.setHangOnHandshakeForTesting(true);

        // Send sequential queries
        for (int i = 0; i < config.queries; i++) {
            int fd = resNetworkQuery(TEST_NETID, kHelloExampleCom, ns_c_in, ns_t_aaaa,
                                     ANDROID_RESOLV_NO_CACHE_LOOKUP);
            expectAnswersValid(fd, AF_INET6, kHelloExampleComAddrV6);
        }

        EXPECT_EQ(dot1.acceptConnectionsCount(), config.expectedQueriesSentToDot1);
        EXPECT_EQ(dot2.acceptConnectionsCount(), config.expectedQueriesSentToDot2);
    }
}

@@ -4814,7 +4909,7 @@ TEST_F(ResolverTest, TlsServerRevalidation) {
    } testConfigs[] = {
            // clang-format off
            {"OPPORTUNISTIC", -1,  5, false, false},
            {"OPPORTUNISTIC", -1, 10, false, false},
            {"OPPORTUNISTIC", -1, 10, false,  true},
            {"OPPORTUNISTIC",  5,  5,  true, false},
            {"OPPORTUNISTIC",  5, 10,  true,  true},
            {"STRICT",        -1,  5, false, false},
@@ -5061,6 +5156,15 @@ TEST_F(ResolverTest, DotQuickFallback) {
                                   std::to_string(DOT_CONNECT_TIMEOUT_MS));
        ScopedSystemProperties sp2(kDotQuickFallbackFlag,
                                   std::to_string(config.dotQuickFallbackFlag));

        // Disable revalidation because we are reusing the same IP address of DoT servers.
        ScopedSystemProperties sp3(kDotRevalidationThresholdFlag, "-1");

        // TODO: Remove the flags and fix the test.
        ScopedSystemProperties sp4(kDotAsyncHandshakeFlag, "0");
        ScopedSystemProperties sp5(kDotMaxretriesFlag, "3");
        resetNetwork();

        resetNetwork();

        auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
@@ -5087,7 +5191,7 @@ TEST_F(ResolverTest, DotQuickFallback) {

        EXPECT_EQ(dot1.acceptConnectionsCount(), 1);
        EXPECT_EQ(dot2.acceptConnectionsCount(), canQuickFallback ? 0 : 1);
        EXPECT_EQ(dot2.queries(), canQuickFallback ? 0 : 1);
        EXPECT_TRUE(dot2.waitForQueries(canQuickFallback ? 0 : 1));

        dot1.setHangOnHandshakeForTesting(false);
    }
+17 −0
Original line number Diff line number Diff line
@@ -60,6 +60,8 @@ const std::string kDohProbeTimeoutFlag("persist.device_config.netd_native.doh_pr
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");
const std::string kDotAsyncHandshakeFlag("persist.device_config.netd_native.dot_async_handshake");
const std::string kDotMaxretriesFlag("persist.device_config.netd_native.dot_maxtries");

constexpr int MAXPACKET = (8 * 1024);

@@ -403,6 +405,11 @@ INSTANTIATE_TEST_SUITE_P(PrivateDns, TransportParameterizedTest,
                         });

TEST_P(TransportParameterizedTest, GetAddrInfo) {
    // TODO: Remove the flags and fix the test.
    ScopedSystemProperties sp1(kDotAsyncHandshakeFlag, "0");
    ScopedSystemProperties sp2(kDotMaxretriesFlag, "3");
    resetNetwork();

    const auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
    ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));

@@ -445,6 +452,11 @@ TEST_P(TransportParameterizedTest, GetAddrInfo) {
}

TEST_P(TransportParameterizedTest, MdnsGetAddrInfo_fallback) {
    // TODO: Remove the flags and fix the test.
    ScopedSystemProperties sp1(kDotAsyncHandshakeFlag, "0");
    ScopedSystemProperties sp2(kDotMaxretriesFlag, "3");
    resetNetwork();

    constexpr char host_name[] = "hello.local.";
    test::DNSResponder mdnsv4("127.0.0.3", test::kDefaultMdnsListenService,
                              static_cast<ns_rcode>(-1));
@@ -570,6 +582,11 @@ TEST_F(PrivateDnsDohTest, ValidationFail) {
//   - Fallback to UDP if DoH query times out
//   - Fallback to DoT if DoH validation is in progress or has failed.
TEST_F(PrivateDnsDohTest, QueryFailover) {
    // TODO: Remove the flags and fix the test.
    ScopedSystemProperties sp1(kDotAsyncHandshakeFlag, "0");
    ScopedSystemProperties sp2(kDotMaxretriesFlag, "3");
    resetNetwork();

    const auto parcel = DnsResponderClient::GetDefaultResolverParamsParcel();
    ASSERT_TRUE(mDnsClient.SetResolversFromParcel(parcel));
    EXPECT_TRUE(WaitForDohValidation(test::kDefaultListenAddr, true));