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

Commit 0664f698 authored by paulhu's avatar paulhu
Browse files

[DRUEL03] Implement unsolicited private DNS validation event

Implement unsolicited private DNS validation event that will
report to the listener when process a private DNS validation
and get result.

Bug: 173485754
Test: atest resolv_integration_test resolv_unit_test\
      resolv_stress_test resolv_stats_test_utils_test
Change-Id: I2b90f4e5ad298e06efbb07c8bcc56808df46fdd0
parent 779f160d
Loading
Loading
Loading
Loading
+33 −13
Original line number Original line Diff line number Diff line
@@ -30,6 +30,8 @@
#include "netdutils/BackoffSequence.h"
#include "netdutils/BackoffSequence.h"
#include "util.h"
#include "util.h"


using aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener;
using aidl::android::net::resolv::aidl::PrivateDnsValidationEventParcel;
using android::base::StringPrintf;
using android::base::StringPrintf;
using android::netdutils::setThreadName;
using android::netdutils::setThreadName;
using std::chrono::milliseconds;
using std::chrono::milliseconds;
@@ -222,6 +224,35 @@ void PrivateDnsConfiguration::startValidation(const DnsTlsServer& server, unsign
    validate_thread.detach();
    validate_thread.detach();
}
}


void PrivateDnsConfiguration::sendPrivateDnsValidationEvent(const DnsTlsServer& server,
                                                            unsigned netId, bool success) {
    LOG(DEBUG) << "Sending validation " << (success ? "success" : "failure") << " event on netId "
               << netId << " for " << server.toIpString() << " with hostname {" << server.name
               << "}";
    // Send a validation event to NetdEventListenerService.
    const auto& listeners = ResolverEventReporter::getInstance().getListeners();
    if (listeners.empty()) {
        LOG(ERROR)
                << "Validation event not sent since no INetdEventListener receiver is available.";
    }
    for (const auto& it : listeners) {
        it->onPrivateDnsValidationEvent(netId, server.toIpString(), server.name, success);
    }

    // Send a validation event to unsolicited event listeners.
    const auto& unsolEventListeners = ResolverEventReporter::getInstance().getUnsolEventListeners();
    const PrivateDnsValidationEventParcel validationEvent = {
            .netId = static_cast<int32_t>(netId),
            .ipAddress = server.toIpString(),
            .hostname = server.name,
            .validation = success ? IDnsResolverUnsolicitedEventListener::VALIDATION_RESULT_SUCCESS
                                  : IDnsResolverUnsolicitedEventListener::VALIDATION_RESULT_FAILURE,
    };
    for (const auto& it : unsolEventListeners) {
        it->onPrivateDnsValidationEvent(validationEvent);
    }
}

bool PrivateDnsConfiguration::recordPrivateDnsValidation(const DnsTlsServer& server, unsigned netId,
bool PrivateDnsConfiguration::recordPrivateDnsValidation(const DnsTlsServer& server, unsigned netId,
                                                         bool success) {
                                                         bool success) {
    constexpr bool NEEDS_REEVALUATION = true;
    constexpr bool NEEDS_REEVALUATION = true;
@@ -268,19 +299,8 @@ bool PrivateDnsConfiguration::recordPrivateDnsValidation(const DnsTlsServer& ser
        reevaluationStatus = DONT_REEVALUATE;
        reevaluationStatus = DONT_REEVALUATE;
    }
    }


    // Send a validation event to NetdEventListenerService.
    // Send private dns validation result to listeners.
    const auto& listeners = ResolverEventReporter::getInstance().getListeners();
    sendPrivateDnsValidationEvent(server, netId, success);
    if (listeners.size() != 0) {
        for (const auto& it : listeners) {
            it->onPrivateDnsValidationEvent(netId, server.toIpString(), server.name, success);
        }
        LOG(DEBUG) << "Sent validation " << (success ? "success" : "failure") << " event on netId "
                   << netId << " for " << server.toIpString() << " with hostname {" << server.name
                   << "}";
    } else {
        LOG(ERROR)
                << "Validation event not sent since no INetdEventListener receiver is available.";
    }


    if (success) {
    if (success) {
        updateServerState(identity, Validation::success, netId);
        updateServerState(identity, Validation::success, netId);
+3 −0
Original line number Original line Diff line number Diff line
@@ -103,6 +103,9 @@ class PrivateDnsConfiguration {
    bool recordPrivateDnsValidation(const DnsTlsServer& server, unsigned netId, bool success)
    bool recordPrivateDnsValidation(const DnsTlsServer& server, unsigned netId, bool success)
            EXCLUDES(mPrivateDnsLock);
            EXCLUDES(mPrivateDnsLock);


    void sendPrivateDnsValidationEvent(const DnsTlsServer& server, unsigned netId, bool success)
            REQUIRES(mPrivateDnsLock);

    // Decide if a validation for |server| is needed. Note that servers that have failed
    // Decide if a validation for |server| is needed. Note that servers that have failed
    // multiple validation attempts but for which there is still a validating
    // multiple validation attempts but for which there is still a validating
    // thread running are marked as being Validation::in_process.
    // thread running are marked as being Validation::in_process.
+5 −5
Original line number Original line Diff line number Diff line
@@ -56,6 +56,7 @@ using android::base::StringPrintf;
using android::base::unique_fd;
using android::base::unique_fd;
using android::net::ResolverStats;
using android::net::ResolverStats;
using android::net::metrics::TestOnDnsEvent;
using android::net::metrics::TestOnDnsEvent;
using android::net::resolv::aidl::UnsolicitedEventListener;
using android::netdutils::Stopwatch;
using android::netdutils::Stopwatch;


// TODO: make this dynamic and stop depending on implementation details.
// TODO: make this dynamic and stop depending on implementation details.
@@ -302,17 +303,16 @@ TEST_F(DnsResolverBinderTest, RegisterUnsolicitedEventListener_NullListener) {
}
}


TEST_F(DnsResolverBinderTest, RegisterUnsolicitedEventListener_DuplicateSubscription) {
TEST_F(DnsResolverBinderTest, RegisterUnsolicitedEventListener_DuplicateSubscription) {
    class FakeListener : public android::net::resolv::aidl::UnsolicitedEventListener {};

    // Expect to subscribe successfully.
    // Expect to subscribe successfully.
    std::shared_ptr<FakeListener> fakeListener = ndk::SharedRefBase::make<FakeListener>();
    std::shared_ptr<UnsolicitedEventListener> listener =
    ::ndk::ScopedAStatus status = mDnsResolver->registerUnsolicitedEventListener(fakeListener);
            ndk::SharedRefBase::make<UnsolicitedEventListener>(TEST_NETID);
    ::ndk::ScopedAStatus status = mDnsResolver->registerUnsolicitedEventListener(listener);
    ASSERT_TRUE(status.isOk()) << status.getMessage();
    ASSERT_TRUE(status.isOk()) << status.getMessage();
    mExpectedLogData.push_back(
    mExpectedLogData.push_back(
            {"registerUnsolicitedEventListener()", "registerUnsolicitedEventListener.*"});
            {"registerUnsolicitedEventListener()", "registerUnsolicitedEventListener.*"});


    // Expect to subscribe failed with registered listener instance.
    // Expect to subscribe failed with registered listener instance.
    status = mDnsResolver->registerUnsolicitedEventListener(fakeListener);
    status = mDnsResolver->registerUnsolicitedEventListener(listener);
    ASSERT_FALSE(status.isOk());
    ASSERT_FALSE(status.isOk());
    ASSERT_EQ(EEXIST, status.getServiceSpecificError());
    ASSERT_EQ(EEXIST, status.getServiceSpecificError());
    mExpectedLogData.push_back(
    mExpectedLogData.push_back(
+21 −2
Original line number Original line Diff line number Diff line
@@ -72,6 +72,7 @@
#include "tests/dns_responder/dns_tls_frontend.h"
#include "tests/dns_responder/dns_tls_frontend.h"
#include "tests/resolv_test_utils.h"
#include "tests/resolv_test_utils.h"
#include "tests/tun_forwarder.h"
#include "tests/tun_forwarder.h"
#include "tests/unsolicited_listener/unsolicited_event_listener.h"


// Valid VPN netId range is 100 ~ 65535
// Valid VPN netId range is 100 ~ 65535
constexpr int TEST_VPN_NETID = 65502;
constexpr int TEST_VPN_NETID = 65502;
@@ -95,6 +96,8 @@ using aidl::android::net::IDnsResolver;
using aidl::android::net::INetd;
using aidl::android::net::INetd;
using aidl::android::net::ResolverParamsParcel;
using aidl::android::net::ResolverParamsParcel;
using aidl::android::net::metrics::INetdEventListener;
using aidl::android::net::metrics::INetdEventListener;
using aidl::android::net::resolv::aidl::IDnsResolverUnsolicitedEventListener;
using aidl::android::net::resolv::aidl::PrivateDnsValidationEventParcel;
using android::base::Error;
using android::base::Error;
using android::base::ParseInt;
using android::base::ParseInt;
using android::base::Result;
using android::base::Result;
@@ -103,6 +106,7 @@ using android::base::unique_fd;
using android::net::ResolverStats;
using android::net::ResolverStats;
using android::net::TunForwarder;
using android::net::TunForwarder;
using android::net::metrics::DnsMetricsListener;
using android::net::metrics::DnsMetricsListener;
using android::net::resolv::aidl::UnsolicitedEventListener;
using android::netdutils::enableSockopt;
using android::netdutils::enableSockopt;
using android::netdutils::makeSlice;
using android::netdutils::makeSlice;
using android::netdutils::ResponseCode;
using android::netdutils::ResponseCode;
@@ -205,6 +209,12 @@ class ResolverTest : public ::testing::Test {
                TEST_NETID /*monitor specific network*/);
                TEST_NETID /*monitor specific network*/);
        ASSERT_TRUE(resolvService->registerEventListener(sDnsMetricsListener).isOk());
        ASSERT_TRUE(resolvService->registerEventListener(sDnsMetricsListener).isOk());


        // Subscribe the unsolicited event listener for verifying unsolicited event contents.
        sUnsolicitedEventListener = ndk::SharedRefBase::make<UnsolicitedEventListener>(
                TEST_NETID /*monitor specific network*/);
        ASSERT_TRUE(
                resolvService->registerUnsolicitedEventListener(sUnsolicitedEventListener).isOk());

        // Start the binder thread pool for listening DNS metrics events and receiving death
        // Start the binder thread pool for listening DNS metrics events and receiving death
        // recipient.
        // recipient.
        ABinderProcess_startThreadPool();
        ABinderProcess_startThreadPool();
@@ -215,6 +225,7 @@ class ResolverTest : public ::testing::Test {
    void SetUp() {
    void SetUp() {
        mDnsClient.SetUp();
        mDnsClient.SetUp();
        sDnsMetricsListener->reset();
        sDnsMetricsListener->reset();
        sUnsolicitedEventListener->reset();
    }
    }


    void TearDown() {
    void TearDown() {
@@ -252,11 +263,16 @@ class ResolverTest : public ::testing::Test {
    }
    }


    bool WaitForPrivateDnsValidation(std::string serverAddr, bool validated) {
    bool WaitForPrivateDnsValidation(std::string serverAddr, bool validated) {
        return sDnsMetricsListener->waitForPrivateDnsValidation(serverAddr, validated);
        return sDnsMetricsListener->waitForPrivateDnsValidation(serverAddr, validated) &&
               sUnsolicitedEventListener->waitForPrivateDnsValidation(
                       serverAddr,
                       validated ? IDnsResolverUnsolicitedEventListener::VALIDATION_RESULT_SUCCESS
                                 : IDnsResolverUnsolicitedEventListener::VALIDATION_RESULT_FAILURE);
    }
    }


    bool hasUncaughtPrivateDnsValidation(const std::string& serverAddr) {
    bool hasUncaughtPrivateDnsValidation(const std::string& serverAddr) {
        return sDnsMetricsListener->findValidationRecord(serverAddr);
        return sDnsMetricsListener->findValidationRecord(serverAddr) &&
               sUnsolicitedEventListener->findValidationRecord(serverAddr);
    }
    }


    void ExpectDnsEvent(int32_t eventType, int32_t returnCode, const std::string& hostname,
    void ExpectDnsEvent(int32_t eventType, int32_t returnCode, const std::string& hostname,
@@ -368,6 +384,9 @@ class ResolverTest : public ::testing::Test {
    static std::shared_ptr<DnsMetricsListener>
    static std::shared_ptr<DnsMetricsListener>
            sDnsMetricsListener;  // Initialized in SetUpTestSuite.
            sDnsMetricsListener;  // Initialized in SetUpTestSuite.


    inline static std::shared_ptr<UnsolicitedEventListener>
            sUnsolicitedEventListener;  // Initialized in SetUpTestSuite.

    // Use a shared static death recipient to monitor the service death. The static death
    // Use a shared static death recipient to monitor the service death. The static death
    // recipient could monitor the death not only during the test but also between tests.
    // recipient could monitor the death not only during the test but also between tests.
    static AIBinder_DeathRecipient* sResolvDeathRecipient;  // Initialized in SetUpTestSuite.
    static AIBinder_DeathRecipient* sResolvDeathRecipient;  // Initialized in SetUpTestSuite.
+46 −5
Original line number Original line Diff line number Diff line
@@ -16,24 +16,65 @@


#include "unsolicited_event_listener.h"
#include "unsolicited_event_listener.h"


#include <thread>

#include <android-base/chrono_utils.h>
#include <android-base/format.h>

namespace android::net::resolv::aidl {
namespace android::net::resolv::aidl {


using ::aidl::android::net::resolv::aidl::PrivateDnsValidationEventParcel;
using android::base::ScopedLockAssertion;
using std::chrono::milliseconds;

constexpr milliseconds kEventTimeoutMs{5000};

::ndk::ScopedAStatus UnsolicitedEventListener::onDnsHealthEvent(
::ndk::ScopedAStatus UnsolicitedEventListener::onDnsHealthEvent(
        const ::aidl::android::net::resolv::aidl::DnsHealthEventParcel&) {
        const ::aidl::android::net::resolv::aidl::DnsHealthEventParcel&) {
    // default no-op
    // default no-op
    return ::ndk::ScopedAStatus::ok();
    return ::ndk::ScopedAStatus::ok();
};
}


::ndk::ScopedAStatus UnsolicitedEventListener::onNat64PrefixEvent(
::ndk::ScopedAStatus UnsolicitedEventListener::onNat64PrefixEvent(
        const ::aidl::android::net::resolv::aidl::Nat64PrefixEventParcel&) {
        const ::aidl::android::net::resolv::aidl::Nat64PrefixEventParcel&) {
    // default no-op
    // default no-op
    return ::ndk::ScopedAStatus::ok();
    return ::ndk::ScopedAStatus::ok();
};
}


::ndk::ScopedAStatus UnsolicitedEventListener::onPrivateDnsValidationEvent(
::ndk::ScopedAStatus UnsolicitedEventListener::onPrivateDnsValidationEvent(
        const ::aidl::android::net::resolv::aidl::PrivateDnsValidationEventParcel&) {
        const PrivateDnsValidationEventParcel& event) {
    // default no-op
    {
        std::lock_guard lock(mMutex);
        // keep updating the server to have latest validation status.
        mValidationRecords.insert_or_assign({event.netId, event.ipAddress}, event.validation);
    }
    mCv.notify_one();
    return ::ndk::ScopedAStatus::ok();
    return ::ndk::ScopedAStatus::ok();
};
}

bool UnsolicitedEventListener::waitForPrivateDnsValidation(const std::string& serverAddr,
                                                           int validation) {
    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}, validation)) return true;
    } while (mCv.wait_until(lock, now + kEventTimeoutMs) != std::cv_status::timeout);

    // Timeout.
    return false;
}

bool UnsolicitedEventListener::findAndRemoveValidationRecord(const ServerKey& key, int value) {
    auto it = mValidationRecords.find(key);
    if (it != mValidationRecords.end() && it->second == value) {
        mValidationRecords.erase(it);
        return true;
    }
    return false;
}


}  // namespace android::net::resolv::aidl
}  // namespace android::net::resolv::aidl
Loading