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

Commit 65fa5047 authored by Ken Chen's avatar Ken Chen Committed by Automerger Merge Worker
Browse files

Merge "Add .local resolution fallback mechanism" am: 166df377 am: 5cfbd508 am: 66f84889

Original change: https://android-review.googlesource.com/c/platform/packages/modules/DnsResolver/+/2006935

Change-Id: I3b736a41e6865308f7ba6e04833cbed736a4cb37
parents b97215ce 66f84889
Loading
Loading
Loading
Loading
+7 −9
Original line number Diff line number Diff line
@@ -483,11 +483,8 @@ int res_nsend(ResState* statp, span<const uint8_t> msg, span<uint8_t> ans, int*
        mDnsQueryEvent->set_linux_errno(static_cast<LinuxErrno>(terrno));
        resolv_stats_add(statp->netid, receivedMdnsAddr, mDnsQueryEvent);

        if (resplen <= 0) {
            _resolv_cache_query_failed(statp->netid, msg, flags);
            return -terrno;
        }
        LOG(DEBUG) << __func__ << ": got answer:";
        if (resplen > 0) {
            LOG(DEBUG) << __func__ << ": got answer from mDNS:";
            res_pquery(ans.first(resplen));

            if (cache_status == RESOLV_CACHE_NOTFOUND) {
@@ -495,6 +492,7 @@ int res_nsend(ResState* statp, span<const uint8_t> msg, span<uint8_t> ans, int*
            }
            return resplen;
        }
    }

    if (statp->nameserverCount() == 0) {
        // We have no nameservers configured and it's not a MDNS resolution, so there's no
+59 −0
Original line number Diff line number Diff line
@@ -6519,6 +6519,65 @@ TEST_F(ResolverTest, MdnsGetAddrInfo_cnamesIllegalRdata) {
    EXPECT_TRUE(result == nullptr);
}

// Test if .local resolution will try unicast when multicast is failed.
TEST_F(ResolverTest, MdnsGetAddrInfo_fallback) {
    constexpr char v6addr[] = "::1.2.3.4";
    constexpr char v4addr[] = "1.2.3.4";
    constexpr char host_name[] = "hello.local.";
    test::DNSResponder mdnsv4("127.0.0.3", test::kDefaultMdnsListenService,
                              static_cast<ns_rcode>(-1));
    test::DNSResponder mdnsv6("::1", test::kDefaultMdnsListenService, static_cast<ns_rcode>(-1));
    // Set unresponsive on multicast.
    mdnsv4.setResponseProbability(0.0);
    mdnsv6.setResponseProbability(0.0);
    ASSERT_TRUE(mdnsv4.startServer());
    ASSERT_TRUE(mdnsv6.startServer());

    const std::vector<DnsRecord> records = {
            {host_name, ns_type::ns_t_a, v4addr},
            {host_name, ns_type::ns_t_aaaa, v6addr},
    };
    test::DNSResponder dns("127.0.0.3");
    StartDns(dns, records);
    ASSERT_TRUE(mDnsClient.SetResolversForNetwork());

    static const struct TestConfig {
        int ai_family;
        const std::vector<std::string> expected_addr;
    } testConfigs[]{
            {AF_INET, {v4addr}},
            {AF_INET6, {v6addr}},
            {AF_UNSPEC, {v4addr, v6addr}},
    };

    for (const auto& config : testConfigs) {
        SCOPED_TRACE(fmt::format("family: {}", config.ai_family));
        addrinfo hints = {.ai_family = config.ai_family, .ai_socktype = SOCK_DGRAM};
        ScopedAddrinfo result = safe_getaddrinfo("hello.local", nullptr, &hints);
        EXPECT_TRUE(result != nullptr);
        if (config.ai_family == AF_INET) {
            EXPECT_EQ(1U, GetNumQueries(mdnsv4, host_name));
            EXPECT_EQ(0U, GetNumQueries(mdnsv6, host_name));
            EXPECT_EQ(1U, GetNumQueries(dns, host_name));
        } else if (config.ai_family == AF_INET6) {
            EXPECT_EQ(0U, GetNumQueries(mdnsv4, host_name));
            EXPECT_EQ(1U, GetNumQueries(mdnsv6, host_name));
            EXPECT_EQ(1U, GetNumQueries(dns, host_name));
        } else {
            EXPECT_EQ(1U, GetNumQueries(mdnsv4, host_name));
            EXPECT_EQ(1U, GetNumQueries(mdnsv6, host_name));
            EXPECT_EQ(2U, GetNumQueries(dns, host_name));
        }
        std::string result_str = ToString(result);
        EXPECT_THAT(ToStrings(result), testing::UnorderedElementsAreArray(config.expected_addr));

        mdnsv4.clearQueries();
        mdnsv6.clearQueries();
        dns.clearQueries();
        ASSERT_TRUE(mDnsClient.resolvService()->flushNetworkCache(TEST_NETID).isOk());
    }
}

// ResolverMultinetworkTest is used to verify multinetwork functionality. Here's how it works:
// The resolver sends queries to address A, and then there will be a TunForwarder helping forward
// the packets to address B, which is the address on which the testing server is listening. The
+77 −2
Original line number Diff line number Diff line
@@ -307,9 +307,9 @@ class BasePrivateDnsTest : public BaseTest {
        BaseTest::TearDown();
    }

    void sendQueryAndCheckResult() {
    void sendQueryAndCheckResult(const char* host_name = kQueryHostname) {
        const addrinfo hints = {.ai_socktype = SOCK_DGRAM};
        ScopedAddrinfo result = safe_getaddrinfo(kQueryHostname, nullptr, &hints);
        ScopedAddrinfo result = safe_getaddrinfo(host_name, nullptr, &hints);
        EXPECT_THAT(ToStrings(result),
                    testing::ElementsAreArray({kQueryAnswerAAAA, kQueryAnswerA}));
    };
@@ -380,6 +380,12 @@ class TransportParameterizedTest : public BasePrivateDnsTest,
            ASSERT_TRUE(doh_backend.startServer());
            ASSERT_TRUE(doh.startServer());
        }
        SetMdnsRoute();
    }

    void TearDown() override {
        RemoveMdnsRoute();
        BasePrivateDnsTest::TearDown();
    }

    bool testParamHasDot() { return GetParam() & kDotBit; }
@@ -437,6 +443,75 @@ TEST_P(TransportParameterizedTest, GetAddrInfo) {
    }
}

TEST_P(TransportParameterizedTest, MdnsGetAddrInfo_fallback) {
    constexpr char host_name[] = "hello.local.";
    test::DNSResponder mdnsv4("127.0.0.3", test::kDefaultMdnsListenService,
                              static_cast<ns_rcode>(-1));
    test::DNSResponder mdnsv6("::1", test::kDefaultMdnsListenService, static_cast<ns_rcode>(-1));
    // Set unresponsive on multicast.
    mdnsv4.setResponseProbability(0.0);
    mdnsv6.setResponseProbability(0.0);
    ASSERT_TRUE(mdnsv4.startServer());
    ASSERT_TRUE(mdnsv6.startServer());

    const std::vector<DnsRecord> records = {
            {host_name, ns_type::ns_t_a, kQueryAnswerA},
            {host_name, ns_type::ns_t_aaaa, kQueryAnswerAAAA},
    };

    for (const auto& r : records) {
        dns.addMapping(r.host_name, r.type, r.addr);
        dot_backend.addMapping(r.host_name, r.type, r.addr);
        doh_backend.addMapping(r.host_name, r.type, r.addr);
    }

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

    if (testParamHasDoh()) EXPECT_TRUE(WaitForDohValidation(test::kDefaultListenAddr, true));
    if (testParamHasDot()) EXPECT_TRUE(WaitForDotValidation(test::kDefaultListenAddr, true));

    // This waiting time is expected to avoid that the DoH validation event interferes other tests.
    if (!testParamHasDoh()) waitForDohValidationFailed();

    // Have the test independent of the number of sent queries in private DNS validation, because
    // the DnsResolver can send either 1 or 2 queries in DoT validation.
    if (testParamHasDoh()) {
        doh.clearQueries();
    }
    if (testParamHasDot()) {
        EXPECT_TRUE(dot.waitForQueries(1));
        dot.clearQueries();
    }
    dns.clearQueries();

    EXPECT_NO_FAILURE(sendQueryAndCheckResult("hello.local"));
    EXPECT_EQ(1U, GetNumQueries(mdnsv4, host_name));
    EXPECT_EQ(1U, GetNumQueries(mdnsv6, host_name));
    if (testParamHasDoh()) {
        EXPECT_NO_FAILURE(expectQueries(0 /* dns */, 0 /* dot */, 2 /* doh */));
    } else {
        EXPECT_NO_FAILURE(expectQueries(0 /* dns */, 2 /* dot */, 0 /* doh */));
    }

    // Stop the private DNS servers. Since we are in opportunistic mode, queries will
    // fall back to the cleartext nameserver.
    flushCache();
    dot.stopServer();
    doh.stopServer();
    mdnsv4.clearQueries();
    mdnsv6.clearQueries();

    EXPECT_NO_FAILURE(sendQueryAndCheckResult("hello.local"));
    EXPECT_EQ(1U, GetNumQueries(mdnsv4, host_name));
    EXPECT_EQ(1U, GetNumQueries(mdnsv6, host_name));
    if (testParamHasDoh()) {
        EXPECT_NO_FAILURE(expectQueries(2 /* dns */, 0 /* dot */, 2 /* doh */));
    } else {
        EXPECT_NO_FAILURE(expectQueries(2 /* dns */, 2 /* dot */, 0 /* doh */));
    }
}

class PrivateDnsDohTest : public BasePrivateDnsTest {
  protected:
    void SetUp() override {
+6 −0
Original line number Diff line number Diff line
@@ -1037,6 +1037,9 @@ TEST_F(ResolvGetAddrInfoTest, MdnsResponderTimeout) {
    ASSERT_TRUE(mdnsv4.startServer());
    ASSERT_TRUE(mdnsv6.startServer());
    ASSERT_EQ(0, SetResolvers());
    test::DNSResponder dns("127.0.0.3", test::kDefaultListenService, static_cast<ns_rcode>(-1));
    dns.setResponseProbability(0.0);
    ASSERT_TRUE(dns.startServer());

    for (const auto& family : {AF_INET, AF_INET6, AF_UNSPEC}) {
        SCOPED_TRACE(fmt::format("family: {}, host_name: {}", family, host_name));
@@ -1825,6 +1828,9 @@ TEST_F(GetHostByNameForNetContextTest, MdnsResponderTimeout) {
    ASSERT_TRUE(mdnsv4.startServer());
    ASSERT_TRUE(mdnsv6.startServer());
    ASSERT_EQ(0, SetResolvers());
    test::DNSResponder dns("127.0.0.3", test::kDefaultListenService, static_cast<ns_rcode>(-1));
    dns.setResponseProbability(0.0);
    ASSERT_TRUE(dns.startServer());

    for (const auto& family : {AF_INET, AF_INET6}) {
        SCOPED_TRACE(fmt::format("family: {}, host_name: {}", family, host_name));