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

Commit 166df377 authored by Ken Chen's avatar Ken Chen Committed by Gerrit Code Review
Browse files

Merge "Add .local resolution fallback mechanism"

parents 8bc0e5c6 a11d8675
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));