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

Commit 532405f6 authored by Mike Yu's avatar Mike Yu
Browse files

onDnsEvent check in resolv_integration_test

Add the onDnsEvent check on some of the existing tests to ensure
EAI_SYSTEM and RCODE_TIMEOUT are reported as expected.

Bug: 159193835
Test: resolv_integration_test
Change-Id: Iaac8c8fbc070411826f5df78d637b5233b3e86c7
parent 26dc2b0a
Loading
Loading
Loading
Loading
+47 −1
Original line number Diff line number Diff line
@@ -16,9 +16,11 @@

#include "dns_metrics_listener.h"

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

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

namespace android {
namespace net {
namespace metrics {
@@ -29,6 +31,18 @@ using std::chrono::milliseconds;
constexpr milliseconds kRetryIntervalMs{20};
constexpr milliseconds kEventTimeoutMs{5000};

bool DnsMetricsListener::DnsEvent::operator==(const DnsMetricsListener::DnsEvent& o) const {
    return std::tie(netId, eventType, returnCode, hostname, ipAddresses, ipAddressesCount) ==
           std::tie(o.netId, o.eventType, o.returnCode, o.hostname, o.ipAddresses,
                    o.ipAddressesCount);
}

std::ostream& operator<<(std::ostream& os, const DnsMetricsListener::DnsEvent& data) {
    return os << fmt::format("[{}, {}, {}, {}, [{}], {}]", data.netId, data.eventType,
                             data.returnCode, data.hostname, fmt::join(data.ipAddresses, ", "),
                             data.ipAddressesCount);
}

::ndk::ScopedAStatus DnsMetricsListener::onNat64PrefixEvent(int32_t netId, bool added,
                                                            const std::string& prefixString,
                                                            int32_t /*prefixLength*/) {
@@ -50,6 +64,19 @@ constexpr milliseconds kEventTimeoutMs{5000};
    return ::ndk::ScopedAStatus::ok();
}

::ndk::ScopedAStatus DnsMetricsListener::onDnsEvent(int32_t netId, int32_t eventType,
                                                    int32_t returnCode, int32_t /*latencyMs*/,
                                                    const std::string& hostname,
                                                    const std::vector<std::string>& ipAddresses,
                                                    int32_t ipAddressesCount, int32_t /*uid*/) {
    std::lock_guard lock(mMutex);
    if (netId == mNetId) {
        mDnsEventRecords.push(
                {netId, eventType, returnCode, hostname, ipAddresses, ipAddressesCount});
    }
    return ::ndk::ScopedAStatus::ok();
}

bool DnsMetricsListener::waitForNat64Prefix(ExpectNat64PrefixStatus status, milliseconds timeout) {
    android::base::Timer t;
    while (t.duration() < timeout) {
@@ -91,6 +118,25 @@ bool DnsMetricsListener::findAndRemoveValidationRecord(const ServerKey& key, con
    return false;
}

std::optional<DnsMetricsListener::DnsEvent> DnsMetricsListener::popDnsEvent() {
    // Wait until the queue is not empty or timeout.
    android::base::Timer t;
    while (t.duration() < milliseconds{1000}) {
        {
            std::lock_guard lock(mMutex);
            if (!mDnsEventRecords.empty()) break;
        }
        std::this_thread::sleep_for(kRetryIntervalMs);
    }

    std::lock_guard lock(mMutex);
    if (mDnsEventRecords.empty()) return std::nullopt;

    auto ret = mDnsEventRecords.front();
    mDnsEventRecords.pop();
    return ret;
}

}  // namespace metrics
}  // namespace net
}  // namespace android
+28 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include <condition_variable>
#include <map>
#include <queue>
#include <utility>

#include <android-base/thread_annotations.h>
@@ -38,6 +39,20 @@ namespace metrics {
// verify the event count, the event change order, and so on.
class DnsMetricsListener : public BaseMetricsListener {
  public:
    struct DnsEvent {
        int32_t netId;
        int32_t eventType;
        int32_t returnCode;
        std::string hostname;
        std::vector<std::string> ipAddresses;
        int32_t ipAddressesCount;

        bool operator==(const DnsEvent& o) const;

        // Informative for debugging.
        friend std::ostream& operator<<(std::ostream& os, const DnsEvent& data);
    };

    DnsMetricsListener() = delete;
    DnsMetricsListener(int32_t netId) : mNetId(netId){};

@@ -50,6 +65,11 @@ class DnsMetricsListener : public BaseMetricsListener {
                                                     const std::string& /*hostname*/,
                                                     bool validated) override;

    ::ndk::ScopedAStatus onDnsEvent(int32_t netId, int32_t eventType, int32_t returnCode,
                                    int32_t /*latencyMs*/, const std::string& hostname,
                                    const std::vector<std::string>& ipAddresses,
                                    int32_t ipAddressesCount, int32_t /*uid*/) override;

    // Wait for expected NAT64 prefix status until timeout.
    bool waitForNat64Prefix(ExpectNat64PrefixStatus status, std::chrono::milliseconds timeout)
            EXCLUDES(mMutex);
@@ -70,10 +90,15 @@ class DnsMetricsListener : public BaseMetricsListener {
        return mValidationRecords.find({mNetId, serverAddr}) != mValidationRecords.end();
    }

    std::optional<DnsEvent> popDnsEvent() EXCLUDES(mMutex);

    void reset() EXCLUDES(mMutex) {
        std::lock_guard lock(mMutex);
        mUnexpectedNat64PrefixUpdates = 0;
        mValidationRecords.clear();

        std::queue<DnsEvent> emptyQueue;
        std::swap(mDnsEventRecords, emptyQueue);
    }

  private:
@@ -99,6 +124,9 @@ class DnsMetricsListener : public BaseMetricsListener {
    // Used to store the data from onPrivateDnsValidationEvent.
    std::map<ServerKey, bool> mValidationRecords GUARDED_BY(mMutex);

    // Used to store the data from onDnsEvent.
    std::queue<DnsEvent> mDnsEventRecords GUARDED_BY(mMutex);

    mutable std::mutex mMutex;
    std::condition_variable mCv;
};
+34 −0
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@
#include "ResolverStats.h"
#include "netid_client.h"  // NETID_UNSET
#include "params.h"        // MAXNS
#include "stats.h"         // RCODE_TIMEOUT
#include "test_utils.h"
#include "tests/dns_metrics_listener/dns_metrics_listener.h"
#include "tests/dns_responder/dns_responder.h"
@@ -84,6 +85,7 @@ using namespace std::chrono_literals;
using aidl::android::net::IDnsResolver;
using aidl::android::net::INetd;
using aidl::android::net::ResolverParamsParcel;
using aidl::android::net::metrics::INetdEventListener;
using android::base::ParseInt;
using android::base::StringPrintf;
using android::base::unique_fd;
@@ -230,6 +232,16 @@ class ResolverTest : public ::testing::Test {
        return sDnsMetricsListener->findValidationRecord(serverAddr);
    }

    void ExpectDnsEvent(int32_t eventType, int32_t returnCode, const std::string& hostname,
                        const std::vector<std::string>& ipAddresses) {
        const DnsMetricsListener::DnsEvent expect = {
                TEST_NETID, eventType,   returnCode,
                hostname,   ipAddresses, static_cast<int32_t>(ipAddresses.size())};
        const auto dnsEvent = sDnsMetricsListener->popDnsEvent();
        ASSERT_TRUE(dnsEvent.has_value());
        EXPECT_EQ(dnsEvent.value(), expect);
    }

    bool expectStatsFromGetResolverInfo(const std::vector<NameserverStats>& nameserversStats) {
        std::vector<std::string> res_servers;
        std::vector<std::string> res_domains;
@@ -953,6 +965,7 @@ TEST_F(ResolverTest, GetAddrInfoV6_nonresponsive) {
    EXPECT_TRUE(result != nullptr);
    EXPECT_EQ(1U, GetNumQueries(dns0, host_name1));
    EXPECT_EQ(1U, GetNumQueries(dns1, host_name1));
    ExpectDnsEvent(INetdEventListener::EVENT_GETADDRINFO, 0, host_name1, {"2001:db8::6"});

    // Now make dns1 also ignore 100% requests... The resolve should alternate
    // queries between the nameservers and fail
@@ -962,6 +975,7 @@ TEST_F(ResolverTest, GetAddrInfoV6_nonresponsive) {
    EXPECT_EQ(nullptr, result2);
    EXPECT_EQ(1U, GetNumQueries(dns0, host_name2));
    EXPECT_EQ(1U, GetNumQueries(dns1, host_name2));
    ExpectDnsEvent(INetdEventListener::EVENT_GETADDRINFO, RCODE_TIMEOUT, host_name2, {});
}

TEST_F(ResolverTest, GetAddrInfoV6_concurrent) {
@@ -2170,6 +2184,12 @@ TEST_F(ResolverTest, Async_EmptyAnswer) {
    res = getAsyncResponse(fd1, &rcode, buf, MAXPACKET);
    EXPECT_GT(res, 0);
    EXPECT_EQ("::1.2.3.4", toString(buf, res, AF_INET6));

    // Trailing dot is removed. Is it intended?
    ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, 0, "howdy.example.com", {"::1.2.3.4"});
    ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, RCODE_TIMEOUT, "howdy.example.com", {});
    ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, RCODE_TIMEOUT, "howdy.example.com", {});
    ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, 0, "howdy.example.com", {"1.2.3.4"});
}

TEST_F(ResolverTest, Async_MalformedQuery) {
@@ -2452,6 +2472,8 @@ TEST_F(ResolverTest, Async_NoRetryFlag) {
    // expect no response
    expectAnswersNotValid(fd1, -ETIMEDOUT);
    expectAnswersNotValid(fd2, -ETIMEDOUT);
    ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, RCODE_TIMEOUT, "howdy.example.com", {});
    ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, RCODE_TIMEOUT, "howdy.example.com", {});

    // No retry case, expect total 2 queries. The server is selected randomly.
    EXPECT_EQ(2U, GetNumQueries(dns0, host_name) + GetNumQueries(dns1, host_name));
@@ -2468,6 +2490,8 @@ TEST_F(ResolverTest, Async_NoRetryFlag) {
    // expect no response
    expectAnswersNotValid(fd1, -ETIMEDOUT);
    expectAnswersNotValid(fd2, -ETIMEDOUT);
    ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, RCODE_TIMEOUT, "howdy.example.com", {});
    ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, RCODE_TIMEOUT, "howdy.example.com", {});

    // Retry case, expect 4 queries
    EXPECT_EQ(4U, GetNumQueries(dns0, host_name));
@@ -2707,10 +2731,13 @@ TEST_F(ResolverTest, BrokenEdns) {
                ASSERT_FALSE(h_result->h_addr_list[0] == nullptr);
                EXPECT_EQ(ADDR4, ToString(h_result));
                EXPECT_TRUE(h_result->h_addr_list[1] == nullptr);
                ExpectDnsEvent(INetdEventListener::EVENT_GETHOSTBYNAME, 0, host_name, {ADDR4});
            } else {
                EXPECT_EQ(0U, GetNumQueriesForType(dns, ns_type::ns_t_a, host_name));
                ASSERT_TRUE(h_result == nullptr);
                ASSERT_EQ(HOST_NOT_FOUND, h_errno);
                int returnCode = (config.edns == Edns::DROP) ? RCODE_TIMEOUT : EAI_FAIL;
                ExpectDnsEvent(INetdEventListener::EVENT_GETHOSTBYNAME, returnCode, host_name, {});
            }
        } else if (config.method == GETADDRINFO) {
            ScopedAddrinfo ai_result;
@@ -2721,9 +2748,12 @@ TEST_F(ResolverTest, BrokenEdns) {
                EXPECT_EQ(1U, GetNumQueries(dns, host_name));
                const std::string result_str = ToString(ai_result);
                EXPECT_EQ(ADDR4, result_str);
                ExpectDnsEvent(INetdEventListener::EVENT_GETADDRINFO, 0, host_name, {ADDR4});
            } else {
                EXPECT_TRUE(ai_result == nullptr);
                EXPECT_EQ(0U, GetNumQueries(dns, host_name));
                int returnCode = (config.edns == Edns::DROP) ? RCODE_TIMEOUT : EAI_FAIL;
                ExpectDnsEvent(INetdEventListener::EVENT_GETADDRINFO, returnCode, host_name, {});
            }
        } else {
            FAIL() << "Unsupported query method: " << config.method;
@@ -4016,6 +4046,9 @@ TEST_F(ResolverTest, BlockDnsQueryWithUidRule) {
    memset(buf, 0, MAXPACKET);
    res = getAsyncResponse(fd1, &rcode, buf, MAXPACKET);
    EXPECT_EQ(-ECONNREFUSED, res);

    ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, EAI_SYSTEM, "howdy.example.com", {});
    ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, EAI_SYSTEM, "howdy.example.com", {});
}

namespace {
@@ -4932,6 +4965,7 @@ TEST_F(ResolverTest, GetAddrInfoParallelLookupTimeout) {
    EXPECT_NEAR(DNS_TIMEOUT_MS, timeTakenMs, TIMING_TOLERANCE_MS)
            << "took time should approximate equal timeout";
    EXPECT_EQ(2U, GetNumQueries(neverRespondDns, host_name));
    ExpectDnsEvent(INetdEventListener::EVENT_GETADDRINFO, RCODE_TIMEOUT, host_name, {});
}

TEST_F(ResolverTest, GetAddrInfoParallelLookupSleepTime) {