chromium/services/network/mdns_responder_unittest.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "services/network/mdns_responder.h"

#include <cstdint>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>

#include "base/check_op.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/scoped_refptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "mojo/public/cpp/bindings/connector.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/base/ip_address.h"
#include "net/base/net_errors.h"
#include "net/dns/dns_names_util.h"
#include "net/dns/dns_query.h"
#include "net/dns/dns_response.h"
#include "net/dns/mock_mdns_socket_factory.h"
#include "net/dns/public/dns_protocol.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/mojom/mdns_responder.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace network {
namespace {

_;
AnyNumber;
AtLeast;
Invoke;
NiceMock;
Return;
ServiceError;

const net::IPAddress kPublicAddrs[2] =;
const net::IPAddress kPublicAddrsIpv6[2] =;

const base::TimeDelta kDefaultTtl =;

const int kNumAnnouncementsPerInterface =;
const int kNumMaxRetriesPerResponse =;

// Keep in sync with |kMdnsNameGeneratorServiceInstanceName| in
// mdns_responder.cc.
const char kMdnsNameGeneratorServiceInstanceName[] =;

std::string CreateMdnsQuery(uint16_t query_id,
                            const std::string& dotted_name,
                            uint16_t qtype = net::dns_protocol::kTypeA) {}

// Creates an mDNS response as announcement, resolution for queries or goodbye.
std::string CreateResolutionResponse(
    const base::TimeDelta& ttl,
    const std::map<std::string, net::IPAddress>& name_addr_map) {}

std::string CreateNegativeResponse(
    const std::map<std::string, net::IPAddress>& name_addr_map) {}

std::string CreateResponseToMdnsNameGeneratorServiceQuery(
    const base::TimeDelta& ttl,
    const std::set<std::string>& names) {}

std::string CreateResponseToMdnsNameGeneratorServiceQueryWithCacheFlush(
    const std::set<std::string>& names) {}

// A mock mDNS socket factory to create sockets that can fail sending or
// receiving packets.
class MockFailingMdnsSocketFactory : public net::MDnsSocketFactory {};

}  // namespace

// Tests of the response creation helpers. For positive responses, we have the
// address records in the Answer section and, if TTL is nonzero, the
// corresponding NSEC records in the Additional section. For negative responses,
// the NSEC records are placed in the Answer section with the address records in
// the Answer section.
TEST(CreateMdnsResponseTest, SingleARecordAnswer) {}

TEST(CreateMdnsResponseTest, SingleARecordGoodbye) {}

TEST(CreateMdnsResponseTest, SingleQuadARecordAnswer) {}

TEST(CreateMdnsResponseTest, SingleNsecRecordAnswer) {}

TEST(CreateMdnsResponseTest,
     SingleTxtRecordAnswerToMdnsNameGeneratorServiceQuery) {}

class SimpleNameGenerator : public MdnsResponderManager::NameGenerator {};

// Test suite for the mDNS responder utilities provided by the service.
class MdnsResponderTest : public testing::Test {};

// Test that a name-to-address map does not change for the same client after
// it is created.
TEST_F(MdnsResponderTest, PersistentNameAddressMapForTheSameClient) {}

// Test that a name-to-address map can be removed when reaching zero refcount
// and can be updated afterwards.
TEST_F(MdnsResponderTest, NameAddressMapCanBeRemovedByOwningClient) {}

// Test that a name-to-address map is not removed with a positive refcount.
TEST_F(MdnsResponderTest,
       NameAddressMapCanOnlyBeRemovedWhenReachingZeroRefcount) {}

// Test that different clients have isolated space of name-to-address maps.
TEST_F(MdnsResponderTest, ClientsHaveIsolatedNameSpaceForAddresses) {}

// Test that the mDNS responder sends an mDNS response to announce the
// ownership of an address and its newly mapped name, but not for a previously
// announced name-to-address map.
TEST_F(MdnsResponderTest,
       CreatingNameForAddressOnlySendsAnnouncementForNewName) {}

// Test that the announcements are sent for isolated spaces of name-to-address
// maps owned by different clients.
TEST_F(MdnsResponderTest,
       CreatingNamesForSameAddressButTwoClientsSendsDistinctAnnouncements) {}

// Test that the goodbye message with zero TTL for a name is sent only
// when we remove a name in an existing name-to-address map.
TEST_F(MdnsResponderTest,
       RemovingNameForAddressOnlySendsResponseWithZeroTtlForExistingName) {}

// Test that the responder can reply to an incoming query about a name it
// knows.
TEST_F(MdnsResponderTest, SendResponseToQueryForOwnedName) {}

// Test that the responder does not respond to any query about a name that is
// unknown to it.
TEST_F(MdnsResponderTest, SendNoResponseToQueryForRemovedName) {}

// Test that the responder sends a negative response to any query that is not
// of type A, AAAA, or ANY.
TEST_F(MdnsResponderTest, SendNegativeResponseToQueryForNonAddressRecord) {}

// Test that the mDNS responder service can respond to an mDNS name generator
// service query with all existing names.
TEST_F(MdnsResponderTest,
       SendResponseToMdnsNameGeneratorServiceQueryWithAllExistingNames) {}

// Test that the responder manager closes the connection after
// an invalid IP address is given to create a name for.
TEST_F(MdnsResponderTest,
       HostClosesMojoConnectionWhenCreatingNameForInvalidAddress) {}

// Test that the responder manager closes the connection after observing
// conflicting name resolution in the network.
TEST_F(MdnsResponderTest,
       HostClosesMojoConnectionAfterObservingAddressNameConflict) {}

// Test that we stop sending response to the mDNS name generator service queries
// when there is an external response carrying a TXT record with the same
// service instance name and the cache-flush bit set.
TEST_F(MdnsResponderTest,
       StopRespondingToGeneratorServiceQueryAfterObservingTxtNameConflict) {}

// Test that an external response with the same service instance name but
// without the cache-flush bit set is not considered a conflict.
TEST_F(MdnsResponderTest,
       NoConflictResolutionIfCacheFlushBitSetInExternalResponse) {}

// Test that scheduled responses to mDNS name generator service queries can be
// cancelled after observing conflict with external records.
TEST_F(MdnsResponderTest,
       CancelResponseToGeneratorServiceQueryAfterObservingTxtNameConflict) {}

// Test that if we ever send any response to mDNS name generator service
// queries, a goodbye packet is sent when the responder manager is destroyed.
TEST_F(MdnsResponderTest,
       SendGoodbyeForMdnsNameGeneratorServiceAfterManagerDestroyed) {}

// Test that we do not send any goodbye packet to flush TXT records of
// owned names when the responder manager is destroyed, if we have not sent any
// response to mDNS name generator service queries.
TEST_F(MdnsResponderTest,
       NoGoodbyeForMdnsNameGeneratorServiceIfNoPreviousServiceResponseSent) {}

// Test that the responder host clears all name-address maps in one goodbye
// message with zero TTL for a client after the Mojo connection between them is
// lost.
TEST_F(MdnsResponderTest, ResponderHostDoesCleanUpAfterMojoConnectionError) {}

// Test that the host generates a Mojo connection error when no socket handler
// is successfully started, and subsequent retry attempts are throttled.
TEST_F(MdnsResponderTest, ClosesBindingWhenNoSocketHanlderStarted) {}

// Test that an announcement is retried after send failure.
TEST_F(MdnsResponderTest, AnnouncementRetriedAfterSendFailure) {}

// Test that responses as announcements are sent following the per-response rate
// limit.
TEST_F(MdnsResponderTest, AnnouncementsAreRateLimitedPerResponse) {}

// Test that responses as goodbyes are sent following the per-response rate
// limit.
TEST_F(MdnsResponderTest, GoodbyesAreRateLimitedPerResponse) {}

// Test that the mixture of announcements and goodbyes are sent following the
// per-response rate limit.
TEST_F(MdnsResponderTest, AnnouncementsAndGoodbyesAreRateLimitedPerResponse) {}

// Test that responses to the name generator service queries are sent following
// the per-record rate limit, so that each message is separated by at least one
// second.
TEST_F(MdnsResponderTest,
       MdnsNameGeneratorServiceResponsesAreRateLimitedPerRecord) {}

// Test that responses with resource records for name resolution are sent based
// on a per-record rate limit.
TEST_F(MdnsResponderTest, ResolutionResponsesAreRateLimitedPerRecord) {}

// Test that negative responses to queries for non-existing records are sent
// based on a per-record rate limit.
TEST_F(MdnsResponderTest, NegativeResponsesAreRateLimitedPerRecord) {}

// Test that the mixture of resolution and negative responses are sent following
// the per-record rate limit.
TEST_F(MdnsResponderTest,
       ResolutionAndNegativeResponsesAreRateLimitedPerRecord) {}

// Test that we send responses immediately to probing queries with qtype ANY.
TEST_F(MdnsResponderTest, ResponsesToProbesAreNotRateLimited) {}

// Test that different rate limit schemes effectively form different queues of
// responses that do not interfere with each other.
TEST_F(MdnsResponderTest, RateLimitSchemesDoNotInterfere) {}

// Test that the responder does not send an announcement if the current
// scheduled delay exceeds the maximum delay allowed, and the client side gets
// notified of the result.
TEST_F(MdnsResponderTest, LongDelayedAnnouncementIsNotScheduled) {}

// Test that all pending sends scheduled are cancelled if the responder manager
// is destroyed.
TEST_F(MdnsResponderTest, ScheduledSendsAreCancelledAfterManagerDestroyed) {}

// Test that if all socket handlers fail to read, the manager restarts itself.
TEST_F(MdnsResponderTest, ManagerCanRestartAfterAllSocketHandlersFailToRead) {}

// Test that sending packets on an interface can be blocked by an incomplete
// send on the same interface. Blocked packets are later flushed when sending is
// unblocked.
TEST_F(MdnsResponderTest, IncompleteSendBlocksFollowingSends) {}

}  // namespace network