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

Commit 85e4d93c authored by Nucca Chen's avatar Nucca Chen Committed by Gerrit Code Review
Browse files

Merge "resolv_integration_test: Test RRs in authority section and additional section"

parents 4694edc9 bb90ab3b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -84,7 +84,7 @@ std::vector<char> makeAnswer(const std::vector<char>& query, const char* rdata_s
                .rclass = question.qclass,
                .ttl = ttl,
        };
        test::DNSResponder::fillAnswerRdata(rdata_str, record);
        test::DNSResponder::fillRdata(rdata_str, record);
        header.answers.push_back(std::move(record));
    }

+112 −0
Original line number Diff line number Diff line
@@ -3486,3 +3486,115 @@ TEST_F(ResolverTest, ConnectTlsServerTimeout) {
    EXPECT_GE(3000, std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count());
    EXPECT_LE(1000, std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count());
}

// Parameterized tests.
// TODO: Merge the existing tests as parameterized test if possible.
// TODO: Perhaps move parameterized tests to an independent file.
enum class CallType { GETADDRINFO, GETHOSTBYNAME };
class ResolverParameterizedTest : public ResolverTest,
                                  public testing::WithParamInterface<CallType> {};

INSTANTIATE_TEST_SUITE_P(TestQueryCall, ResolverParameterizedTest,
                         testing::Values(CallType::GETADDRINFO, CallType::GETHOSTBYNAME),
                         [](const testing::TestParamInfo<CallType>& info) {
                             std::string name;
                             switch (info.param) {
                                 case CallType::GETADDRINFO:
                                     name = "GetAddrInfo";
                                     break;
                                 case CallType::GETHOSTBYNAME:
                                     name = "GetHostByName";
                                     break;
                                 default:
                                     name = "InvalidParameter";  // Should not happen.
                             }
                             return name;
                         });

TEST_P(ResolverParameterizedTest, AuthoritySectionAndAdditionalSection) {
    // DNS response may have more information in authority section and additional section.
    // Currently, getanswer() of packages/modules/DnsResolver/getaddrinfo.cpp doesn't parse the
    // content of authority section and additional section. Test these sections if they crash
    // the resolver, just in case. See also RFC 1035 section 4.1.
    const auto& calltype = GetParam();
    test::DNSHeader header(kDefaultDnsHeader);

    // Create a DNS response which has a authoritative nameserver record in authority
    // section and its relevant address record in additional section.
    //
    // Question
    //   hello.example.com.     IN      A
    // Answer
    //   hello.example.com.     IN      A   1.2.3.4
    // Authority:
    //   hello.example.com.     IN      NS  ns1.example.com.
    // Additional:
    //   ns1.example.com.       IN      A   5.6.7.8
    //
    // A response may have only question, answer, and authority section. Current testing response
    // should be able to cover this condition.

    // Question section.
    test::DNSQuestion question{
            .qname = {.name = kHelloExampleCom},
            .qtype = ns_type::ns_t_a,
            .qclass = ns_c_in,
    };
    header.questions.push_back(std::move(question));

    // Answer section.
    test::DNSRecord recordAnswer{
            .name = {.name = kHelloExampleCom},
            .rtype = ns_type::ns_t_a,
            .rclass = ns_c_in,
            .ttl = 0,  // no cache
    };
    EXPECT_TRUE(test::DNSResponder::fillRdata("1.2.3.4", recordAnswer));
    header.answers.push_back(std::move(recordAnswer));

    // Authority section.
    test::DNSRecord recordAuthority{
            .name = {.name = kHelloExampleCom},
            .rtype = ns_type::ns_t_ns,
            .rclass = ns_c_in,
            .ttl = 0,  // no cache
    };
    EXPECT_TRUE(test::DNSResponder::fillRdata("ns1.example.com.", recordAuthority));
    header.authorities.push_back(std::move(recordAuthority));

    // Additional section.
    test::DNSRecord recordAdditional{
            .name = {.name = "ns1.example.com."},
            .rtype = ns_type::ns_t_a,
            .rclass = ns_c_in,
            .ttl = 0,  // no cache
    };
    EXPECT_TRUE(test::DNSResponder::fillRdata("5.6.7.8", recordAdditional));
    header.additionals.push_back(std::move(recordAdditional));

    // Start DNS server.
    test::DNSResponder dns(test::DNSResponder::MappingType::DNS_HEADER);
    dns.addMappingDnsHeader(kHelloExampleCom, ns_type::ns_t_a, header);
    ASSERT_TRUE(dns.startServer());
    ASSERT_TRUE(mDnsClient.SetResolversForNetwork());
    dns.clearQueries();

    // Expect that get the address and the resolver doesn't crash.
    if (calltype == CallType::GETADDRINFO) {
        const addrinfo hints = {.ai_family = AF_INET, .ai_socktype = SOCK_DGRAM};
        ScopedAddrinfo result = safe_getaddrinfo("hello", nullptr, &hints);
        EXPECT_TRUE(result != nullptr);
        EXPECT_EQ(1U, GetNumQueries(dns, kHelloExampleCom));
        EXPECT_EQ("1.2.3.4", ToString(result));
    } else if (calltype == CallType::GETHOSTBYNAME) {
        const hostent* result = gethostbyname("hello");
        EXPECT_EQ(1U, GetNumQueries(dns, kHelloExampleCom));
        ASSERT_FALSE(result == nullptr);
        ASSERT_EQ(4, result->h_length);
        ASSERT_FALSE(result->h_addr_list[0] == nullptr);
        EXPECT_EQ("1.2.3.4", ToString(result));
        EXPECT_TRUE(result->h_addr_list[1] == nullptr);
    } else {
        FAIL() << "Unsupported call type: " << static_cast<uint32_t>(calltype);
    }
}
 No newline at end of file
+1 −1
Original line number Diff line number Diff line
@@ -67,7 +67,7 @@ class TestBase : public ::testing::Test {
                .rclass = rclass,
                .ttl = ttl,
        };
        EXPECT_TRUE(test::DNSResponder::fillAnswerRdata(rdata, record));
        EXPECT_TRUE(test::DNSResponder::fillRdata(rdata, record));
        return record;
    }

+4 −3
Original line number Diff line number Diff line
@@ -742,7 +742,7 @@ bool DNSResponder::addAnswerRecords(const DNSQuestion& question,
                    .rclass = ns_class::ns_c_in,
                    .ttl = kAnswerRecordTtlSec,  // seconds
            };
            if (!fillAnswerRdata(it->second, record)) return false;
            if (!fillRdata(it->second, record)) return false;
            answers->push_back(std::move(record));
            if (rtype != ns_type::ns_t_cname) break;
            rname = it->second;
@@ -758,7 +758,7 @@ bool DNSResponder::addAnswerRecords(const DNSQuestion& question,
    return true;
}

bool DNSResponder::fillAnswerRdata(const std::string& rdatastr, DNSRecord& record) {
bool DNSResponder::fillRdata(const std::string& rdatastr, DNSRecord& record) {
    if (record.rtype == ns_type::ns_t_a) {
        record.rdata.resize(4);
        if (inet_pton(AF_INET, rdatastr.c_str(), record.rdata.data()) != 1) {
@@ -771,7 +771,8 @@ bool DNSResponder::fillAnswerRdata(const std::string& rdatastr, DNSRecord& recor
            LOG(ERROR) << "inet_pton(AF_INET6, " << rdatastr << ") failed";
            return false;
        }
    } else if ((record.rtype == ns_type::ns_t_ptr) || (record.rtype == ns_type::ns_t_cname)) {
    } else if ((record.rtype == ns_type::ns_t_ptr) || (record.rtype == ns_type::ns_t_cname) ||
               (record.rtype == ns_type::ns_t_ns)) {
        constexpr char delimiter = '.';
        std::string name = rdatastr;
        std::vector<char> rdata;
+1 −1
Original line number Diff line number Diff line
@@ -171,7 +171,7 @@ class DNSResponder {
    std::condition_variable& getCv() { return cv; }
    std::mutex& getCvMutex() { return cv_mutex_; }
    void setDeferredResp(bool deferred_resp);
    static bool fillAnswerRdata(const std::string& rdatastr, DNSRecord& record);
    static bool fillRdata(const std::string& rdatastr, DNSRecord& record);

  private:
    // Key used for accessing mappings.