blob: a963224c38cf8cb268944aa278089240d0a8462a [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "services/network/mdns_responder.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "base/strings/string_piece.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 "net/base/ip_address.h"
#include "net/base/net_errors.h"
#include "net/dns/dns_query.h"
#include "net/dns/dns_response.h"
#include "net/dns/dns_util.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 {
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::Invoke;
using ::testing::NiceMock;
using ::testing::Return;
using ServiceError = MdnsResponderManager::ServiceError;
const net::IPAddress kPublicAddrs[2] = {net::IPAddress(11, 11, 11, 11),
net::IPAddress(22, 22, 22, 22)};
const net::IPAddress kPublicAddrsIpv6[2] = {
net::IPAddress(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16),
net::IPAddress(16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)};
const base::TimeDelta kDefaultTtl = base::TimeDelta::FromSeconds(120);
const int kNumAnnouncementsPerInterface = 2;
const int kNumMaxRetriesPerResponse = 2;
// Keep in sync with the histogram name in ReportServiceError in
// mdns_responder.cc
const char kServiceErrorHistogram[] =
"NetworkService.MdnsResponder.ServiceError";
// Keep in sync with |kMdnsNameGeneratorServiceInstanceName| in
// mdns_responder.cc.
const char kMdnsNameGeneratorServiceInstanceName[] =
"Generated-Names._mdns_name_generator._udp.local";
std::string CreateMdnsQuery(uint16_t query_id,
const std::string& dotted_name,
uint16_t qtype = net::dns_protocol::kTypeA) {
std::string qname;
net::DNSDomainFromDot(dotted_name, &qname);
net::DnsQuery query(query_id, qname, qtype);
return std::string(query.io_buffer()->data(), query.io_buffer()->size());
}
// 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) {
auto buf = network::mdns_helper::CreateResolutionResponse(ttl, name_addr_map);
DCHECK(buf != nullptr);
return std::string(buf->data(), buf->size());
}
std::string CreateNegativeResponse(
const std::map<std::string, net::IPAddress>& name_addr_map) {
auto buf = network::mdns_helper::CreateNegativeResponse(name_addr_map);
DCHECK(buf != nullptr);
return std::string(buf->data(), buf->size());
}
std::string CreateResponseToMdnsNameGeneratorServiceQuery(
const base::TimeDelta& ttl,
const std::set<std::string>& names) {
auto buf =
network::mdns_helper::CreateResponseToMdnsNameGeneratorServiceQuery(
ttl, names);
DCHECK(buf != nullptr);
return std::string(buf->data(), buf->size());
}
std::string CreateResponseToMdnsNameGeneratorServiceQueryWithCacheFlush(
const std::set<std::string>& names) {
auto buf =
network::mdns_helper::CreateResponseToMdnsNameGeneratorServiceQuery(
kDefaultTtl, names);
// Deserialize to set the cache-flush bit before serializing again.
net::DnsResponse response(buf.get(), buf->size());
bool rv = response.InitParseWithoutQuery(buf->size());
DCHECK(rv);
DCHECK_EQ(response.answer_count(), 1u);
net::DnsResourceRecord txt_record;
rv = response.Parser().ReadRecord(&txt_record);
DCHECK(rv);
DCHECK_EQ(net::dns_protocol::kTypeTXT, txt_record.type);
txt_record.klass |= net::dns_protocol::kFlagCacheFlush;
// Parsed record does not own the RDATA. Copy the owned RDATA before
// constructing a new response.
const std::string owned_rdata(txt_record.rdata);
txt_record.SetOwnedRdata(owned_rdata);
std::vector<net::DnsResourceRecord> answers(1, txt_record);
net::DnsResponse response_cache_flush(0 /* id */, true /* is_authoritative */,
answers, {} /* authority_records */,
{} /* additional_records */,
base::nullopt /* query */);
DCHECK(response_cache_flush.io_buffer() != nullptr);
buf = base::MakeRefCounted<net::IOBufferWithSize>(
response_cache_flush.io_buffer_size());
memcpy(buf->data(), response_cache_flush.io_buffer()->data(),
response_cache_flush.io_buffer_size());
return std::string(buf->data(), buf->size());
}
// A mock mDNS socket factory to create sockets that can fail sending or
// receiving packets.
class MockFailingMdnsSocketFactory : public net::MDnsSocketFactory {
public:
MockFailingMdnsSocketFactory(
scoped_refptr<base::SingleThreadTaskRunner> task_runner)
: task_runner_(std::move(task_runner)) {}
~MockFailingMdnsSocketFactory() override = default;
MOCK_METHOD1(CreateSockets,
void(std::vector<std::unique_ptr<net::DatagramServerSocket>>*));
MOCK_METHOD1(OnSendTo, void(const std::string&));
// Emulates the asynchronous contract of invoking |callback| in the SendTo
// primitive but failed sending;
int FailToSend(const std::string& packet,
const std::string& address,
net::CompletionRepeatingCallback callback) {
OnSendTo(packet);
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
[](net::CompletionRepeatingCallback callback) { callback.Run(-1); },
callback));
return -1;
}
// Emulates IO blocking in sending packets if |BlockSend()| is called, in
// which case the completion callback is not invoked until |ResumeSend()| is
// called.
int MaybeBlockSend(const std::string& packet,
const std::string& address,
net::CompletionRepeatingCallback callback) {
OnSendTo(packet);
if (block_send_) {
blocked_packet_size_ = packet.size();
blocked_send_callback_ = std::move(callback);
} else {
task_runner_->PostTask(
FROM_HERE,
base::BindOnce([](net::CompletionRepeatingCallback callback,
size_t packet_size) { callback.Run(packet_size); },
callback, packet.size()));
}
return -1;
}
void BlockSend() {
DCHECK(!block_send_);
block_send_ = true;
}
void ResumeSend() {
DCHECK(block_send_);
block_send_ = false;
blocked_send_callback_.Run(blocked_packet_size_);
}
// Emulates the asynchronous contract of invoking |callback| in the RecvFrom
// primitive but failed receiving;
int FailToRecv(net::IOBuffer* buffer,
int size,
net::IPEndPoint* address,
net::CompletionRepeatingCallback callback) {
task_runner_->PostTask(FROM_HERE,
base::BindOnce(
[](net::CompletionRepeatingCallback callback) {
callback.Run(net::ERR_FAILED);
},
callback));
return net::ERR_IO_PENDING;
}
private:
bool block_send_ = false;
size_t blocked_packet_size_ = 0;
net::CompletionRepeatingCallback blocked_send_callback_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
};
} // 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) {
const char response_data[]{
0x00, 0x00, // mDNS response ID mus be zero.
0x84, 0x00, // flags, response with authoritative answer
0x00, 0x00, // number of questions
0x00, 0x01, // number of answer rr
0x00, 0x00, // number of name server rr
0x00, 0x01, // number of additional rr
0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c',
'o', 'm',
0x00, // null label
0x00, 0x01, // type A Record
0x80, 0x01, // class IN, cache-flush bit set
0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
0x00, 0x04, // rdlength, 32 bits
0xc0, 0xa8, 0x00, 0x01, // 192.168.0.1
// Additional section
0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c',
'o', 'm',
0x00, // null label
0x00, 0x2f, // type NSEC Record
0x80, 0x01, // class IN, cache-flush bit set
0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
0x00, 0x05, // rdlength, 5 bytes
0xc0, 0x2b, // pointer to the previous "www.example.com"
0x00, 0x01, 0x40, // type bit map of type A: window block 0, bitmap
// length 1, bitmap with bit 1 set
};
std::string expected_response(response_data, sizeof(response_data));
std::string actual_response = CreateResolutionResponse(
kDefaultTtl,
{{"www.example.com", net::IPAddress(0xc0, 0xa8, 0x00, 0x01)}});
EXPECT_EQ(expected_response, actual_response);
}
TEST(CreateMdnsResponseTest, SingleARecordGoodbye) {
const char response_data[]{
0x00, 0x00, // mDNS response ID mus be zero.
0x84, 0x00, // flags, response with authoritative answer
0x00, 0x00, // number of questions
0x00, 0x01, // number of answer rr
0x00, 0x00, // number of name server rr
0x00, 0x00, // number of additional rr
0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a',
'm', 'p', 'l', 'e', 0x03, 'c', 'o', 'm',
0x00, // null label
0x00, 0x01, // type A Record
0x80, 0x01, // class IN, cache-flush bit set
0x00, 0x00, 0x00, 0x00, // zero TTL
0x00, 0x04, // rdlength, 32 bits
0xc0, 0xa8, 0x00, 0x01, // 192.168.0.1
};
std::string expected_response(response_data, sizeof(response_data));
std::string actual_response = CreateResolutionResponse(
base::TimeDelta(),
{{"www.example.com", net::IPAddress(0xc0, 0xa8, 0x00, 0x01)}});
EXPECT_EQ(expected_response, actual_response);
}
TEST(CreateMdnsResponseTest, SingleQuadARecordAnswer) {
const char response_data[] = {
0x00, 0x00, // mDNS response ID mus be zero.
0x84, 0x00, // flags, response with authoritative answer
0x00, 0x00, // number of questions
0x00, 0x01, // number of answer rr
0x00, 0x00, // number of name server rr
0x00, 0x01, // number of additional rr
0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'o', 'r', 'g',
0x00, // null label
0x00, 0x1c, // type AAAA Record
0x80, 0x01, // class IN, cache-flush bit set
0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
0x00, 0x10, // rdlength, 128 bits
0xfd, 0x12, 0x34, 0x56, 0x78, 0x9a, 0x00, 0x01, // fd12:3456:789a:1::1
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
// Additional section
0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'o', 'r', 'g',
0x00, // null label
0x00, 0x2f, // type NSEC Record
0x80, 0x01, // class IN, cache-flush bit set
0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
0x00, 0x08, // rdlength, 8 bytes
0xc0, 0x33, // pointer to the previous "example.org"
0x00, 0x04, 0x00, 0x00, 0x00,
0x08, // type bit map of type AAAA: window block 0, bitmap
// length 4, bitmap with bit 28 set
};
std::string expected_response(response_data, sizeof(response_data));
std::string actual_response = CreateResolutionResponse(
kDefaultTtl,
{{"example.org",
net::IPAddress(0xfd, 0x12, 0x34, 0x56, 0x78, 0x9a, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01)}});
EXPECT_EQ(expected_response, actual_response);
}
TEST(CreateMdnsResponseTest, SingleNsecRecordAnswer) {
const char response_data[] = {
0x00, 0x00, // mDNS response ID mus be zero.
0x84, 0x00, // flags, response with authoritative answer
0x00, 0x00, // number of questions
0x00, 0x01, // number of answer rr
0x00, 0x00, // number of name server rr
0x00, 0x01, // number of additional rr
0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c',
'o', 'm',
0x00, // null label
0x00, 0x2f, // type NSEC Record
0x80, 0x01, // class IN, cache-flush bit set
0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
0x00, 0x05, // rdlength, 5 bytes
0xc0, 0x0c, // pointer to the previous "www.example.com"
0x00, 0x01, 0x40, // type bit map of type A: window block 0, bitmap
// length 1, bitmap with bit 1 set
// Additional section
0x03, 'w', 'w', 'w', 0x07, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0x03, 'c',
'o', 'm',
0x00, // null label
0x00, 0x01, // type A Record
0x80, 0x01, // class IN, cache-flush bit set
0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
0x00, 0x04, // rdlength, 32 bits
0xc0, 0xa8, 0x00, 0x01, // 192.168.0.1
};
std::string expected_response(response_data, sizeof(response_data));
std::string actual_response = CreateNegativeResponse(
{{"www.example.com", net::IPAddress(0xc0, 0xa8, 0x00, 0x01)}});
EXPECT_EQ(expected_response, actual_response);
}
TEST(CreateMdnsResponseTest,
SingleTxtRecordAnswerToMdnsNameGeneratorServiceQuery) {
const char response_data[] = {
0x00, 0x00, // mDNS response ID mus be zero.
0x84, 0x00, // flags, response with authoritative answer
0x00, 0x00, // number of questions
0x00, 0x01, // number of answer rr
0x00, 0x00, // number of name server rr
0x00, 0x00, // number of additional rr
0x0f, 'G', 'e', 'n', 'e', 'r', 'a', 't', 'e', 'd', '-', 'N',
'a', 'm', 'e', 's', 0x14, '_', 'm', 'd', 'n', 's', '_', 'n',
'a', 'm', 'e', '_', 'g', 'e', 'n', 'e', 'r', 'a', 't', 'o',
'r', 0x04, '_', 'u', 'd', 'p', 0x05, 'l', 'o', 'c', 'a', 'l',
0x00, // null label
0x00, 0x10, // type A Record
0x00, 0x01, // class IN, cache-flush bit NOT set
0x00, 0x00, 0x00, 0x78, // TTL, 120 seconds
0x00, 0x2e, // rdlength, 46 bytes for the following kv pairs
0x0d, 'n', 'a', 'm', 'e', '0', '=', '1', '.', 'l', 'o', 'c',
'a', 'l', 0x15, 'n', 'a', 'm', 'e', '1', '=', 'w', 'w', 'w',
'.', 'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm',
0x09, 't', 'x', 't', 'v', 'e', 'r', 's', '=', '1'};
std::string expected_response(response_data, sizeof(response_data));
std::string actual_response = CreateResponseToMdnsNameGeneratorServiceQuery(
kDefaultTtl, {"1.local", "www.example.com"});
EXPECT_EQ(expected_response, actual_response);
}
class SimpleNameGenerator : public MdnsResponderManager::NameGenerator {
public:
std::string CreateName() override {
return std::to_string(next_available_id_++);
}
private:
uint32_t next_available_id_ = 0;
};
// Test suite for the mDNS responder utilities provided by the service.
class MdnsResponderTest : public testing::Test {
public:
MdnsResponderTest()
: failing_socket_factory_(task_environment_.GetMainThreadTaskRunner()) {
feature_list_.InitAndEnableFeature(
features::kMdnsResponderGeneratedNameListing);
Reset();
}
~MdnsResponderTest() {
// Goodbye messages are scheduled when the responder service |host_manager_|
// is destroyed and can be synchronously sent if the rate limiting permits.
// See ResponseScheduler::DispatchPendingPackets().
EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(AnyNumber());
EXPECT_CALL(failing_socket_factory_, OnSendTo(_)).Times(AnyNumber());
}
void Reset(bool use_failing_socket_factory = false) {
client_[0].reset();
client_[1].reset();
if (use_failing_socket_factory)
host_manager_ =
std::make_unique<MdnsResponderManager>(&failing_socket_factory_);
else
host_manager_ = std::make_unique<MdnsResponderManager>(&socket_factory_);
host_manager_->SetNameGeneratorForTesting(
std::make_unique<SimpleNameGenerator>());
host_manager_->SetTickClockForTesting(task_environment_.GetMockTickClock());
CreateMdnsResponders();
}
void CreateMdnsResponders() {
auto request1 = mojo::MakeRequest(&client_[0]);
client_[0].set_connection_error_handler(base::BindOnce(
&MdnsResponderTest::OnMojoConnectionError, base::Unretained(this), 0));
host_manager_->CreateMdnsResponder(std::move(request1));
auto request2 = mojo::MakeRequest(&client_[1]);
client_[1].set_connection_error_handler(base::BindOnce(
&MdnsResponderTest::OnMojoConnectionError, base::Unretained(this), 1));
host_manager_->CreateMdnsResponder(std::move(request2));
}
// The following method is synchronous for testing by waiting on running the
// task runner.
std::string CreateNameForAddress(int client_id, const net::IPAddress& addr) {
client_[client_id]->CreateNameForAddress(
addr, base::BindOnce(&MdnsResponderTest::OnNameCreatedForAddress,
base::Unretained(this), addr));
RunUntilNoTasksRemain();
return last_name_created_;
}
void RemoveNameForAddress(int client_id,
const net::IPAddress& addr,
bool expected_removed,
bool expected_goodbye_sched) {
client_[client_id]->RemoveNameForAddress(
addr, base::BindOnce(&MdnsResponderTest::OnNameRemovedForAddress,
base::Unretained(this), expected_removed,
expected_goodbye_sched));
}
void RemoveNameForAddressAndExpectDone(int client_id,
const net::IPAddress& addr) {
RemoveNameForAddress(client_id, addr, true, true);
}
void CloseConnectionToResponderHost(int client_id) {
client_[client_id].reset();
}
void OnMojoConnectionError(int client_id) { client_[client_id].reset(); }
protected:
void OnNameCreatedForAddress(const net::IPAddress& addr,
const std::string& name,
bool announcement_scheduled) {
last_name_created_ = name;
}
void OnNameRemovedForAddress(bool expected_removed,
bool expected_goodbye_scheduled,
bool actual_removed,
bool actual_goodbye_scheduled) {
EXPECT_EQ(expected_removed, actual_removed);
EXPECT_EQ(expected_goodbye_scheduled, actual_goodbye_scheduled);
}
void RunUntilNoTasksRemain() {
task_environment_.FastForwardUntilNoTasksRemain();
}
void RunFor(base::TimeDelta duration) {
task_environment_.FastForwardBy(duration);
}
base::test::ScopedFeatureList feature_list_;
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
// Overrides the current thread task runner, so we can simulate the passage
// of time and avoid any actual sleeps.
NiceMock<net::MockMDnsSocketFactory> socket_factory_;
NiceMock<MockFailingMdnsSocketFactory> failing_socket_factory_;
mojom::MdnsResponderPtr client_[2];
std::unique_ptr<MdnsResponderManager> host_manager_;
std::string last_name_created_;
};
// Test that a name-to-address map does not change for the same client after
// it is created.
TEST_F(MdnsResponderTest, PersistentNameAddressMapForTheSameClient) {
const auto& addr1 = kPublicAddrs[0];
const auto& addr2 = kPublicAddrs[1];
const auto name1 = CreateNameForAddress(0, addr1);
const auto name2 = CreateNameForAddress(0, addr2);
EXPECT_NE(name1, name2);
EXPECT_EQ(name1, CreateNameForAddress(0, addr1));
}
// Test that a name-to-address map can be removed when reaching zero refcount
// and can be updated afterwards.
TEST_F(MdnsResponderTest, NameAddressMapCanBeRemovedByOwningClient) {
const auto& addr = kPublicAddrs[0];
const auto prev_name = CreateNameForAddress(0, addr);
RemoveNameForAddressAndExpectDone(0, addr);
RunUntilNoTasksRemain();
EXPECT_NE(prev_name, CreateNameForAddress(0, addr));
}
// Test that a name-to-address map is not removed with a positive refcount.
TEST_F(MdnsResponderTest,
NameAddressMapCanOnlyBeRemovedWhenReachingZeroRefcount) {
const auto& addr = kPublicAddrs[0];
const auto prev_name = CreateNameForAddress(0, addr);
EXPECT_EQ(prev_name, CreateNameForAddress(0, addr));
RemoveNameForAddress(0, addr, false /* expected removed */,
false /* expected goodbye scheduled */);
RunUntilNoTasksRemain();
EXPECT_EQ(prev_name, CreateNameForAddress(0, addr));
}
// Test that different clients have isolated space of name-to-address maps.
TEST_F(MdnsResponderTest, ClientsHaveIsolatedNameSpaceForAddresses) {
const net::IPAddress& addr = kPublicAddrs[0];
// The same address is mapped to different names for different clients.
const auto name_client1 = CreateNameForAddress(0, addr);
const auto name_client2 = CreateNameForAddress(1, addr);
EXPECT_NE(name_client1, name_client2);
// Removing a name-address association by client 2 does not change the
// mapping for client 1.
RemoveNameForAddressAndExpectDone(1, addr);
EXPECT_EQ(name_client1, CreateNameForAddress(0, addr));
}
// 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) {
const net::IPAddress& addr = kPublicAddrs[0];
std::string expected_announcement =
CreateResolutionResponse(kDefaultTtl, {{"0.local", addr}});
// MockMdnsSocketFactory binds sockets to two interfaces.
EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement))
.Times(2 * kNumAnnouncementsPerInterface);
EXPECT_EQ("0.local", CreateNameForAddress(0, addr)); // SimpleNameGenerator.
// Sends no announcement for a name that is already mapped to an address.
CreateNameForAddress(0, addr);
RunUntilNoTasksRemain();
}
// Test that the announcements are sent for isolated spaces of name-to-address
// maps owned by different clients.
TEST_F(MdnsResponderTest,
CreatingNamesForSameAddressButTwoClientsSendsDistinctAnnouncements) {
const auto& addr = kPublicAddrs[0];
std::string expected_announcement1 =
CreateResolutionResponse(kDefaultTtl, {{"0.local", addr}});
std::string expected_announcement2 =
CreateResolutionResponse(kDefaultTtl, {{"1.local", addr}});
// MockMdnsSocketFactory binds sockets to two interfaces.
EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement1))
.Times(2 * kNumAnnouncementsPerInterface);
EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement2))
.Times(2 * kNumAnnouncementsPerInterface);
CreateNameForAddress(0, addr);
CreateNameForAddress(1, addr);
RunUntilNoTasksRemain();
}
// 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) {
const auto& addr = kPublicAddrs[0];
std::string expected_announcement =
CreateResolutionResponse(kDefaultTtl, {{"0.local", addr}});
std::string expected_goodbye =
CreateResolutionResponse(base::TimeDelta(), {{"0.local", addr}});
// MockMdnsSocketFactory binds sockets to two interfaces.
EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement))
.Times(2 * kNumAnnouncementsPerInterface);
EXPECT_CALL(socket_factory_, OnSendTo(expected_goodbye)).Times(2);
CreateNameForAddress(0, addr);
RemoveNameForAddressAndExpectDone(0, addr);
// Sends no goodbye message for a name that is already removed.
RemoveNameForAddress(0, addr, false /* expected removed */,
false /* expected goodbye scheduled */);
RunUntilNoTasksRemain();
}
// Test that the responder can reply to an incoming query about a name it
// knows.
TEST_F(MdnsResponderTest, SendResponseToQueryForOwnedName) {
const auto& addr = kPublicAddrs[0];
const auto name = CreateNameForAddress(0, addr);
std::string query1 = CreateMdnsQuery(0, name);
std::string query2 = CreateMdnsQuery(0, "unknown_name");
std::string expected_response =
CreateResolutionResponse(kDefaultTtl, {{name, addr}});
// SimulateReceive only lets the last created socket receive.
EXPECT_CALL(socket_factory_, OnSendTo(expected_response)).Times(1);
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query1.data()), query1.size());
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query2.data()), query2.size());
RunUntilNoTasksRemain();
}
// Test that the responder does not respond to any query about a name that is
// unknown to it.
TEST_F(MdnsResponderTest, SendNoResponseToQueryForRemovedName) {
const auto& addr = kPublicAddrs[0];
const auto name = CreateNameForAddress(0, addr);
RemoveNameForAddressAndExpectDone(0, addr);
RunUntilNoTasksRemain();
std::string query = CreateMdnsQuery(0, {name});
EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(0);
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query.data()), query.size());
RunUntilNoTasksRemain();
}
// Test that the responder sends a negative response to any query that is not
// of type A, AAAA, or ANY.
TEST_F(MdnsResponderTest, SendNegativeResponseToQueryForNonAddressRecord) {
const auto& addr = kPublicAddrs[0];
const auto name = CreateNameForAddress(0, addr);
const std::set<uint16_t> non_address_qtypes = {
net::dns_protocol::kTypeCNAME, net::dns_protocol::kTypeSOA,
net::dns_protocol::kTypePTR, net::dns_protocol::kTypeTXT,
net::dns_protocol::kTypeSRV, net::dns_protocol::kTypeOPT,
net::dns_protocol::kTypeNSEC,
};
std::string expected_negative_response =
CreateNegativeResponse({{name, addr}});
for (auto qtype : non_address_qtypes) {
std::string query = CreateMdnsQuery(0, {name}, qtype);
EXPECT_CALL(socket_factory_, OnSendTo(expected_negative_response)).Times(1);
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query.data()), query.size());
RunUntilNoTasksRemain();
}
}
// Test that the mDNS responder service can respond to an mDNS name generator
// service query with all existing names.
TEST_F(MdnsResponderTest,
SendResponseToMdnsNameGeneratorServiceQueryWithAllExistingNames) {
const auto& addr1 = kPublicAddrs[0];
const auto& addr2 = kPublicAddrs[1];
// Let two names be created by different clients.
const std::string name1 = CreateNameForAddress(0, addr1);
const std::string name2 = CreateNameForAddress(1, addr2);
const std::string query = CreateMdnsQuery(
0, kMdnsNameGeneratorServiceInstanceName, net::dns_protocol::kTypeTXT);
// The response should contain both names.
const std::string expected_response1 =
CreateResponseToMdnsNameGeneratorServiceQuery(kDefaultTtl,
{name1, name2});
EXPECT_CALL(socket_factory_, OnSendTo(expected_response1)).Times(1);
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query.data()), query.size());
RunUntilNoTasksRemain();
// Remove |name2|.
std::string expected_goodbye =
CreateResolutionResponse(base::TimeDelta(), {{name2, addr2}});
// Goodbye on both interfaces.
EXPECT_CALL(socket_factory_, OnSendTo(expected_goodbye)).Times(2);
RemoveNameForAddressAndExpectDone(1 /* client_id */, addr2);
RunUntilNoTasksRemain();
// The response should contain only |name1|.
const std::string expected_response2 =
CreateResponseToMdnsNameGeneratorServiceQuery(kDefaultTtl, {name1});
EXPECT_CALL(socket_factory_, OnSendTo(expected_response2)).Times(1);
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query.data()), query.size());
RunUntilNoTasksRemain();
}
// Test that the responder manager closes the connection after
// an invalid IP address is given to create a name for.
TEST_F(MdnsResponderTest,
HostClosesMojoConnectionWhenCreatingNameForInvalidAddress) {
base::HistogramTester tester;
const net::IPAddress addr;
ASSERT_TRUE(!addr.IsValid());
EXPECT_TRUE(client_[0].is_bound());
// No packet should be sent out from interfaces.
EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(0);
CreateNameForAddress(0, addr);
EXPECT_FALSE(client_[0].is_bound());
tester.ExpectBucketCount(kServiceErrorHistogram,
ServiceError::kInvalidIpToRegisterName, 1);
tester.ExpectTotalCount(kServiceErrorHistogram, 1);
}
// Test that the responder manager closes the connection after observing
// conflicting name resolution in the network.
TEST_F(MdnsResponderTest,
HostClosesMojoConnectionAfterObservingAddressNameConflict) {
const auto& addr1 = kPublicAddrs[0];
const auto& addr2 = kPublicAddrs[1];
const auto name1 = CreateNameForAddress(0, addr1);
const auto name2 = CreateNameForAddress(0, addr2);
std::string query1 = CreateMdnsQuery(0, {name1});
std::string query2 = CreateMdnsQuery(0, {name2});
std::string conflicting_response =
CreateResolutionResponse(kDefaultTtl, {{name1, addr2}});
std::string expected_goodbye = CreateResolutionResponse(
base::TimeDelta(), {{name1, addr1}, {name2, addr2}});
EXPECT_TRUE(client_[0].is_bound());
// MockMdnsSocketFactory binds sockets to two interfaces.
// We should send only two goodbyes before closing the connection and no
// packet should be sent out from interfaces after the connection is closed.
EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(0);
EXPECT_CALL(socket_factory_, OnSendTo(expected_goodbye)).Times(2);
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(conflicting_response.data()),
conflicting_response.size());
RunUntilNoTasksRemain();
// The responder should have observed the conflict and the responder manager
// should have closed the Mojo connection and sent out the goodbye messages
// for owned names.
EXPECT_FALSE(client_[0].is_bound());
// Also, as a result, we should have stopped responding to the following
// queries.
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query1.data()), query1.size());
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query2.data()), query2.size());
RunUntilNoTasksRemain();
}
// 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) {
const auto& addr = kPublicAddrs[0];
const std::string name = CreateNameForAddress(0, addr);
const std::string query = CreateMdnsQuery(
0, kMdnsNameGeneratorServiceInstanceName, net::dns_protocol::kTypeTXT);
// Verify that we can respond to the service query.
const std::string expected_response =
CreateResponseToMdnsNameGeneratorServiceQuery(kDefaultTtl, {name});
EXPECT_CALL(socket_factory_, OnSendTo(expected_response)).Times(1);
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query.data()), query.size());
RunUntilNoTasksRemain();
// Receive a conflicting response.
const std::string conflicting_response =
CreateResponseToMdnsNameGeneratorServiceQueryWithCacheFlush(
{"dummy.local"});
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(conflicting_response.data()),
conflicting_response.size());
RunUntilNoTasksRemain();
// We should have stopped responding to service queries.
EXPECT_CALL(socket_factory_, OnSendTo(expected_response)).Times(0);
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query.data()), query.size());
RunUntilNoTasksRemain();
}
// 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) {
const auto& addr = kPublicAddrs[0];
const std::string name = CreateNameForAddress(0, addr);
// Receive an external response to the same instance name but without the
// cache-flush bit set in the TXT record.
const std::string nonconflict_response =
CreateResponseToMdnsNameGeneratorServiceQuery(kDefaultTtl,
{"dummy.local"});
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(nonconflict_response.data()),
nonconflict_response.size());
RunUntilNoTasksRemain();
const std::string query = CreateMdnsQuery(
0, kMdnsNameGeneratorServiceInstanceName, net::dns_protocol::kTypeTXT);
// We can still respond to the service query.
const std::string expected_response =
CreateResponseToMdnsNameGeneratorServiceQuery(kDefaultTtl, {name});
EXPECT_CALL(socket_factory_, OnSendTo(expected_response)).Times(1);
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query.data()), query.size());
RunUntilNoTasksRemain();
}
// Test that scheduled responses to mDNS name generator service queries can be
// cancelled after observing conflict with external records.
TEST_F(MdnsResponderTest,
CancelResponseToGeneratorServiceQueryAfterObservingTxtNameConflict) {
const auto& addr = kPublicAddrs[0];
const std::string name = CreateNameForAddress(0, addr);
// Receive a series of queries so that we have delayed responses scheduled
// because of rate limiting. We will also receive a conflicting response after
// the first response sent to cancel the subsequent ones.
const std::string query = CreateMdnsQuery(
0, kMdnsNameGeneratorServiceInstanceName, net::dns_protocol::kTypeTXT);
const std::string expected_response =
CreateResponseToMdnsNameGeneratorServiceQuery(kDefaultTtl, {name});
// We should have only the first response sent and the rest cancelled after
// encountering the conflicting.
EXPECT_CALL(socket_factory_, OnSendTo(expected_response)).Times(1);
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query.data()), query.size());
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query.data()), query.size());
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query.data()), query.size());
RunFor(base::TimeDelta::FromMilliseconds(900));
// Receive a conflicting response.
const std::string conflicting_response =
CreateResponseToMdnsNameGeneratorServiceQueryWithCacheFlush(
{"dummy.local"});
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(conflicting_response.data()),
conflicting_response.size());
RunUntilNoTasksRemain();
}
// 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) {
const auto& addr = kPublicAddrs[0];
const std::string name = CreateNameForAddress(0, addr);
const std::string query = CreateMdnsQuery(
0, kMdnsNameGeneratorServiceInstanceName, net::dns_protocol::kTypeTXT);
const std::string expected_response =
CreateResponseToMdnsNameGeneratorServiceQuery(kDefaultTtl, {name});
// Respond to a generator service query once.
EXPECT_CALL(socket_factory_, OnSendTo(expected_response)).Times(1);
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query.data()), query.size());
RunFor(base::TimeDelta::FromMilliseconds(1000));
// Goodbye on both interfaces.
const std::string expected_goodbye =
CreateResponseToMdnsNameGeneratorServiceQuery(base::TimeDelta(), {name});
EXPECT_CALL(socket_factory_, OnSendTo(expected_goodbye)).Times(2);
host_manager_ = nullptr;
RunUntilNoTasksRemain();
}
// 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) {
const auto& addr = kPublicAddrs[0];
const std::string name = CreateNameForAddress(0, addr);
const std::string goodbye =
CreateResponseToMdnsNameGeneratorServiceQuery(base::TimeDelta(), {name});
EXPECT_CALL(socket_factory_, OnSendTo(goodbye)).Times(0);
host_manager_ = nullptr;
RunUntilNoTasksRemain();
}
// 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) {
const auto& addr1 = kPublicAddrs[0];
const auto& addr2 = kPublicAddrs[1];
const auto name1 = CreateNameForAddress(0, addr1);
const auto name2 = CreateNameForAddress(0, addr2);
std::string expected_goodbye = CreateResolutionResponse(
base::TimeDelta(), {{name1, addr1}, {name2, addr2}});
// MockMdnsSocketFactory binds sockets to two interfaces.
EXPECT_CALL(socket_factory_, OnSendTo(expected_goodbye)).Times(2);
CloseConnectionToResponderHost(0);
RunUntilNoTasksRemain();
}
// Test that the host generates a Mojo connection error when no socket handler
// is successfully started.
TEST_F(MdnsResponderTest, ClosesBindingWhenNoSocketHanlderStarted) {
base::HistogramTester tester;
EXPECT_CALL(failing_socket_factory_, CreateSockets(_)).WillOnce(Return());
Reset(true /* use_failing_socket_factory */);
RunUntilNoTasksRemain();
// MdnsResponderTest::OnMojoConnectionError.
EXPECT_FALSE(client_[0].is_bound());
EXPECT_FALSE(client_[1].is_bound());
tester.ExpectBucketCount(kServiceErrorHistogram,
ServiceError::kFailToStartManager, 1);
tester.ExpectBucketCount(kServiceErrorHistogram,
ServiceError::kFailToCreateResponder, 2);
tester.ExpectTotalCount(kServiceErrorHistogram, 3);
}
// Test that an announcement is retried after send failure.
TEST_F(MdnsResponderTest, AnnouncementRetriedAfterSendFailure) {
auto create_send_failing_socket =
[this](std::vector<std::unique_ptr<net::DatagramServerSocket>>* sockets) {
auto socket =
std::make_unique<NiceMock<net::MockMDnsDatagramServerSocket>>(
net::ADDRESS_FAMILY_IPV4);
ON_CALL(*socket, SendToInternal(_, _, _))
.WillByDefault(Invoke(&failing_socket_factory_,
&MockFailingMdnsSocketFactory::FailToSend));
ON_CALL(*socket, RecvFromInternal(_, _, _, _))
.WillByDefault(Return(-1));
sockets->push_back(std::move(socket));
};
EXPECT_CALL(failing_socket_factory_, CreateSockets(_))
.WillOnce(Invoke(create_send_failing_socket));
Reset(true /* use_failing_socket_factory */);
const auto& addr = kPublicAddrs[0];
std::string expected_announcement =
CreateResolutionResponse(kDefaultTtl, {{"0.local", addr}});
// Mocked CreateSockets above only creates one socket.
EXPECT_CALL(failing_socket_factory_, OnSendTo(expected_announcement))
.Times(kNumAnnouncementsPerInterface + kNumMaxRetriesPerResponse);
const auto name = CreateNameForAddress(0, addr);
RunUntilNoTasksRemain();
}
// Test that responses as announcements are sent following the per-response rate
// limit.
TEST_F(MdnsResponderTest, AnnouncementsAreRateLimitedPerResponse) {
const auto& addr1 = kPublicAddrs[0];
const auto& addr2 = kPublicAddrs[1];
std::string expected_announcement1 =
CreateResolutionResponse(kDefaultTtl, {{"0.local", addr1}});
std::string expected_announcement2 =
CreateResolutionResponse(kDefaultTtl, {{"1.local", addr2}});
// First announcement for 0.local.
// MockMdnsSocketFactory binds sockets to two interfaces.
EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement1)).Times(2);
// We need the async call from the client.
client_[0]->CreateNameForAddress(addr1, base::DoNothing());
client_[0]->CreateNameForAddress(addr2, base::DoNothing());
RunFor(base::TimeDelta::FromMilliseconds(900));
// Second announcement for 0.local.
EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement1)).Times(2);
RunFor(base::TimeDelta::FromSeconds(1));
// First announcement for 1.local.
EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement2)).Times(2);
RunFor(base::TimeDelta::FromSeconds(1));
// Second announcement for 1.local.
EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement2)).Times(2);
RunUntilNoTasksRemain();
}
// Test that responses as goodbyes are sent following the per-response rate
// limit.
TEST_F(MdnsResponderTest, GoodbyesAreRateLimitedPerResponse) {
const auto& addr1 = kPublicAddrs[0];
const auto& addr2 = kPublicAddrs[1];
// Note that the wrapper method calls below are sync and announcements are
// sent after they return.
auto name1 = CreateNameForAddress(0, addr1);
auto name2 = CreateNameForAddress(0, addr2);
std::string expected_goodbye1 =
CreateResolutionResponse(base::TimeDelta(), {{name1, addr1}});
std::string expected_goodbye2 =
CreateResolutionResponse(base::TimeDelta(), {{name2, addr2}});
// Goodbye for 0.local.
// MockMdnsSocketFactory binds sockets to two interfaces.
EXPECT_CALL(socket_factory_, OnSendTo(expected_goodbye1)).Times(2);
// Note that the wrapper method calls below are async.
RemoveNameForAddressAndExpectDone(0, addr1);
RemoveNameForAddressAndExpectDone(0, addr2);
RunFor(base::TimeDelta::FromMilliseconds(900));
// Goodbye for 1.local.
EXPECT_CALL(socket_factory_, OnSendTo(expected_goodbye2)).Times(2);
RunUntilNoTasksRemain();
}
// Test that the mixture of announcements and goodbyes are sent following the
// per-response rate limit.
TEST_F(MdnsResponderTest, AnnouncementsAndGoodbyesAreRateLimitedPerResponse) {
const auto& addr1 = kPublicAddrs[0];
const auto& addr2 = kPublicAddrs[1];
std::string expected_announcement1 =
CreateResolutionResponse(kDefaultTtl, {{"0.local", addr1}});
std::string expected_announcement2 =
CreateResolutionResponse(kDefaultTtl, {{"1.local", addr2}});
std::string expected_goodbye1 =
CreateResolutionResponse(base::TimeDelta(), {{"0.local", addr1}});
std::string expected_goodbye2 =
CreateResolutionResponse(base::TimeDelta(), {{"1.local", addr2}});
// First announcement for 0.local.
// MockMdnsSocketFactory binds sockets to two interfaces.
EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement1)).Times(2);
// We need the async call from the client.
client_[0]->CreateNameForAddress(addr1, base::DoNothing());
RemoveNameForAddressAndExpectDone(0, addr1);
client_[0]->CreateNameForAddress(addr2, base::DoNothing());
RemoveNameForAddressAndExpectDone(0, addr2);
RunFor(base::TimeDelta::FromMilliseconds(900));
// Second announcement for 0.local.
EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement1)).Times(2);
RunFor(base::TimeDelta::FromSeconds(1));
// Goodbye for 0.local.
EXPECT_CALL(socket_factory_, OnSendTo(expected_goodbye1)).Times(2);
RunFor(base::TimeDelta::FromSeconds(1));
// First announcement for 1.local.
EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement2)).Times(2);
RunFor(base::TimeDelta::FromSeconds(1));
// Second announcement for 1.local.
EXPECT_CALL(socket_factory_, OnSendTo(expected_announcement2)).Times(2);
RunFor(base::TimeDelta::FromSeconds(1));
// Goodbye for 1.local.
EXPECT_CALL(socket_factory_, OnSendTo(expected_goodbye2)).Times(2);
RunUntilNoTasksRemain();
}
// 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) {
const auto& addr = kPublicAddrs[0];
const std::string name = CreateNameForAddress(0, addr);
// After a name has been created for |addr|, let the responder receive
// queries. Their responses should be scheduled sequentially, each separated
// by at least one second. Note that responses to the mDNS name generator
// service queries have an extra delay of 20-120ms as the service instance
// name is shared among Chrome instances.
const std::string query = CreateMdnsQuery(
0, kMdnsNameGeneratorServiceInstanceName, net::dns_protocol::kTypeTXT);
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query.data()), query.size());
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query.data()), query.size());
const std::string expected_response =
CreateResponseToMdnsNameGeneratorServiceQuery(kDefaultTtl, {"0.local"});
// Response to the first query is sent right after the query is received.
EXPECT_CALL(socket_factory_, OnSendTo(expected_response)).Times(1);
// Response to the second received query will be delayed for another one
// second plus an extra delay of 20-120ms.
RunFor(base::TimeDelta::FromMilliseconds(1015));
EXPECT_CALL(socket_factory_, OnSendTo(expected_response)).Times(1);
RunUntilNoTasksRemain();
}
// Test that responses with resource records for name resolution are sent based
// on a per-record rate limit.
TEST_F(MdnsResponderTest, ResolutionResponsesAreRateLimitedPerRecord) {
const auto& addr1 = kPublicAddrs[0];
const auto& addr2 = kPublicAddrs[1];
auto name1 = CreateNameForAddress(0, addr1);
auto name2 = CreateNameForAddress(0, addr2);
// kPublicAddrs are IPv4.
std::string query1 = CreateMdnsQuery(0, {name1}, net::dns_protocol::kTypeA);
std::string query2 = CreateMdnsQuery(0, {name2}, net::dns_protocol::kTypeA);
std::string expected_response1 =
CreateResolutionResponse(kDefaultTtl, {{name1, addr1}});
std::string expected_response2 =
CreateResolutionResponse(kDefaultTtl, {{name2, addr2}});
// Resolution for name1.
EXPECT_CALL(socket_factory_, OnSendTo(expected_response1)).Times(1);
// Resolution for name2.
EXPECT_CALL(socket_factory_, OnSendTo(expected_response2)).Times(1);
// SimulateReceive only lets the last created socket receive.
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query1.data()), query1.size());
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query2.data()), query2.size());
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query1.data()), query1.size());
RunFor(base::TimeDelta::FromMilliseconds(900));
// Resolution for name1 for the second query about it.
EXPECT_CALL(socket_factory_, OnSendTo(expected_response1)).Times(1);
RunUntilNoTasksRemain();
}
// Test that negative responses to queries for non-existing records are sent
// based on a per-record rate limit.
TEST_F(MdnsResponderTest, NegativeResponsesAreRateLimitedPerRecord) {
const auto& addr1 = kPublicAddrs[0];
const auto& addr2 = kPublicAddrs[1];
auto name1 = CreateNameForAddress(0, addr1);
auto name2 = CreateNameForAddress(0, addr2);
// kPublicAddrs are IPv4 and type AAAA records do not exist.
std::string query1 =
CreateMdnsQuery(0, {name1}, net::dns_protocol::kTypeAAAA);
std::string query2 =
CreateMdnsQuery(0, {name2}, net::dns_protocol::kTypeAAAA);
std::string expected_response1 = CreateNegativeResponse({{name1, addr1}});
std::string expected_response2 = CreateNegativeResponse({{name2, addr2}});
// Negative response for name1.
EXPECT_CALL(socket_factory_, OnSendTo(expected_response1)).Times(1);
// Negative response for name2.
EXPECT_CALL(socket_factory_, OnSendTo(expected_response2)).Times(1);
// SimulateReceive only lets the last created socket receive.
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query1.data()), query1.size());
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query2.data()), query2.size());
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query1.data()), query1.size());
RunFor(base::TimeDelta::FromMilliseconds(900));
// Negative response for name1 for the second query about it.
EXPECT_CALL(socket_factory_, OnSendTo(expected_response1)).Times(1);
RunUntilNoTasksRemain();
}
// Test that the mixture of resolution and negative responses are sent following
// the per-record rate limit.
TEST_F(MdnsResponderTest,
ResolutionAndNegativeResponsesAreRateLimitedPerRecord) {
const auto& addr = kPublicAddrs[0];
auto name = CreateNameForAddress(0, addr);
// kPublicAddrs are IPv4 and type AAAA records do not exist.
std::string query_a = CreateMdnsQuery(0, {name}, net::dns_protocol::kTypeA);
std::string query_aaaa =
CreateMdnsQuery(0, {name}, net::dns_protocol::kTypeAAAA);
std::string expected_resolution =
CreateResolutionResponse(kDefaultTtl, {{name, addr}});
std::string expected_negative_resp = CreateNegativeResponse({{name, addr}});
EXPECT_CALL(socket_factory_, OnSendTo(expected_resolution)).Times(1);
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query_a.data()), query_a.size());
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query_aaaa.data()), query_aaaa.size());
RunFor(base::TimeDelta::FromMilliseconds(900));
EXPECT_CALL(socket_factory_, OnSendTo(expected_negative_resp)).Times(1);
RunUntilNoTasksRemain();
}
// Test that we send responses immediately to probing queries with qtype ANY.
TEST_F(MdnsResponderTest, ResponsesToProbesAreNotRateLimited) {
const auto& addr = kPublicAddrs[0];
auto name = CreateNameForAddress(0, addr);
// Type ANY for probing queries.
//
// TODO(qingsi): Setting the type to kTypeAny is not sufficient to construct a
// proper probe query. We also need to include a record in the Authority
// section. See the comment inside IsProbeQuery in mdns_responder.cc. After we
// support parsing the Authority section of a query in DnsQuery, we should
// create the following probe query by the standard definition.
std::string query = CreateMdnsQuery(0, {name}, net::dns_protocol::kTypeANY);
std::string expected_response =
CreateResolutionResponse(kDefaultTtl, {{name, addr}});
EXPECT_CALL(socket_factory_, OnSendTo(expected_response)).Times(2);
// SimulateReceive only lets the last created socket receive.
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query.data()), query.size());
socket_factory_.SimulateReceive(
reinterpret_cast<const uint8_t*>(query.data()), query.size());
RunFor(base::TimeDelta::FromMilliseconds(500));
}
// Test that different rate limit schemes effectively form different queues of
// responses that do not interfere with each other.
TEST_F(MdnsResponderTest, RateLimitSchemesDoNotInterfere) {
const auto& addr1 = kPublicAddrsIpv6[0];
const auto& addr2 = kPublicAddrsIpv6[1];
// SimpleNameGenerator.
std::string name1 = "0.local";
std::string name2 = "1.local";
std::string query1_a = CreateMdnsQuery(0, {name1}, net::dns_protocol::kTypeA);
std::string query1_aaaa =
CreateMdnsQuery(0, {name1}, net::dns_protocol::kTypeAAAA);
std::string query1_any =
CreateMdnsQuery(0, {name1}, net::dns_protocol::kTypeANY);
std::string query2_a = CreateMdnsQuery(0, {name2}, net::dns_protocol::kTypeA);
std::string query2_aaaa =
CreateMdnsQuery(0, {name2}, net::dns_protocol::kTypeAAAA);
std::string query2_any =
CreateMdnsQuery(0, {name2}, net::dns_protocol::kTypeANY);
std::string expected_resolution1 =
CreateResolutionResponse(kDefaultTtl, {{name1, addr1}});
std::string expected_resolution2 =
CreateResolutionResponse(kDefaultTtl, {{name2, addr2}});
std::string expected_negative_resp1 =
CreateNegativeResponse({{name1, addr1}});
std::string expected_negative_resp2 =
CreateNegativeResponse({{name2, addr2}});
auto do_sequence_after_name_created =
[](net::MockMDnsSocketFactory* socket_factory, const std::string& query_a,
const std::string& query_aaaa, const std::string& query_any,
const std::string& /* name */, bool /* announcement_scheduled */) {
socket_factory->SimulateReceive(
reinterpret_cast<const uint8_t*>(query_a.data()), query_a.size());
socket_factory->SimulateReceive(
reinterpret_cast<const uint8_t*>(query_aaaa.data()),
query_aaaa.size());
socket_factory->SimulateReceive(
reinterpret_cast<const uint8_t*>(query_any.data()),
query_any.size());
};
// 2 first announcements for name1 from 2 interfaces (per-response limit) and
// 1 response to the probing query1_any (no limit).
EXPECT_CALL(socket_factory_, OnSendTo(expected_resolution1)).Times(3);
// 1 negative response to query1_a (per-record limit).
EXPECT_CALL(socket_factory_, OnSendTo(expected_negative_resp1)).Times(1);
// 1 response to the probing query2_any (no limit).
EXPECT_CALL(socket_factory_, OnSendTo(expected_resolution2)).Times(1);
// 1 negative response to query2_a (per-record limit).
EXPECT_CALL(socket_factory_, OnSendTo(expected_negative_resp2)).Times(1);
client_[0]->CreateNameForAddress(
addr1, base::BindOnce(do_sequence_after_name_created, &socket_factory_,
query1_a, query1_aaaa, query1_any));
client_[0]->CreateNameForAddress(
addr2, base::BindOnce(do_sequence_after_name_created, &socket_factory_,
query2_a, query2_aaaa, query2_any));
RunFor(base::TimeDelta::FromMilliseconds(900));
// 2 second announcements for name1 from 2 interfaces, and 1 response to
// query1_aaaa (per-record limit).
EXPECT_CALL(socket_factory_, OnSendTo(expected_resolution1)).Times(3);
// 1 response to query2_aaaa (per-record limit).
EXPECT_CALL(socket_factory_, OnSendTo(expected_resolution2)).Times(1);
RunFor(base::TimeDelta::FromSeconds(1));
// 2 first announcements for name2 from 2 interfaces.
EXPECT_CALL(socket_factory_, OnSendTo(expected_resolution2)).Times(2);
RunFor(base::TimeDelta::FromSeconds(1));
// 2 second announcements for name2 from 2 interfaces.
EXPECT_CALL(socket_factory_, OnSendTo(expected_resolution2)).Times(2);
RunUntilNoTasksRemain();
}
// 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) {
const auto& addr = kPublicAddrs[0];
// Enqueue announcements and delays so that we reach the maximum delay
// allowed of the per-response rate limit. Our current implementation defines
// a 10-second maximum scheduled delay (see kMaxScheduledDelay in
// mdns_responder.cc).
for (int i = 0; i < 5; ++i) {
// Use the async call from the client.
client_[0]->CreateNameForAddress(addr, base::DoNothing());
client_[0]->RemoveNameForAddress(addr, base::DoNothing());
}
client_[0]->CreateNameForAddress(
addr, base::BindOnce([](const std::string&, bool announcement_scheduled) {
EXPECT_FALSE(announcement_scheduled);
}));
RunUntilNoTasksRemain();
}
// Test that all pending sends scheduled are cancelled if the responder manager
// is destroyed.
TEST_F(MdnsResponderTest, ScheduledSendsAreCancelledAfterManagerDestroyed) {
const auto& addr = kPublicAddrs[0];
EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(0);
// Use the async call from the client.
client_[0]->CreateNameForAddress(addr, base::DoNothing());
client_[0]->RemoveNameForAddress(addr, base::DoNothing());
host_manager_.reset();
RunUntilNoTasksRemain();
}
// Test that if all socket handlers fail to read, the manager restarts itself.
TEST_F(MdnsResponderTest, ManagerCanRestartAfterAllSocketHandlersFailToRead) {
base::HistogramTester tester;
auto create_read_failing_socket =
[this](std::vector<std::unique_ptr<net::DatagramServerSocket>>* sockets) {
auto socket =
std::make_unique<NiceMock<net::MockMDnsDatagramServerSocket>>(
net::ADDRESS_FAMILY_IPV4);
ON_CALL(*socket, SendToInternal(_, _, _)).WillByDefault(Return(0));
ON_CALL(*socket, RecvFromInternal(_, _, _, _))
.WillByDefault(Invoke(&failing_socket_factory_,
&MockFailingMdnsSocketFactory::FailToRecv));
sockets->push_back(std::move(socket));
};
EXPECT_CALL(failing_socket_factory_, CreateSockets(_))
.WillOnce(Invoke(create_read_failing_socket));
Reset(true /* use_failing_socket_factory */);
// Called when the manager restarts. The mocked CreateSockets() by default
// returns an empty vector of sockets, thus failing the restart again.
EXPECT_CALL(failing_socket_factory_, CreateSockets(_)).Times(1);
RunUntilNoTasksRemain();
tester.ExpectBucketCount(kServiceErrorHistogram,
ServiceError::kFatalSocketHandlerError, 1);
tester.ExpectBucketCount(kServiceErrorHistogram,
ServiceError::kFailToStartManager, 1);
tester.ExpectTotalCount(kServiceErrorHistogram, 2);
}
// 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) {
auto create_send_blocking_socket =
[this](std::vector<std::unique_ptr<net::DatagramServerSocket>>* sockets) {
auto socket =
std::make_unique<NiceMock<net::MockMDnsDatagramServerSocket>>(
net::ADDRESS_FAMILY_IPV4);
ON_CALL(*socket, SendToInternal(_, _, _))
.WillByDefault(
Invoke(&failing_socket_factory_,
&MockFailingMdnsSocketFactory::MaybeBlockSend));
ON_CALL(*socket, RecvFromInternal(_, _, _, _))
.WillByDefault(Return(-1));
sockets->push_back(std::move(socket));
};
EXPECT_CALL(failing_socket_factory_, CreateSockets(_))
.WillOnce(Invoke(create_send_blocking_socket));
Reset(true /* use_failing_socket_factory */);
const auto& addr1 = kPublicAddrs[0];
std::string expected_announcement1 =
CreateResolutionResponse(kDefaultTtl, {{"0.local", addr1}});
// Mocked CreateSockets above only creates one socket.
// We schedule to send the announcement for |kNumAnnouncementsPerInterface|
// times but the second announcement is blocked by the first one in this case.
EXPECT_CALL(failing_socket_factory_, OnSendTo(expected_announcement1))
.Times(1);
failing_socket_factory_.BlockSend();
const auto name1 = CreateNameForAddress(0, addr1);
RunUntilNoTasksRemain();
const auto& addr2 = kPublicAddrs[1];
std::string expected_announcement2 =
CreateResolutionResponse(kDefaultTtl, {{"1.local", addr2}});
// The announcement for the following name should also be blocked.
const auto name2 = CreateNameForAddress(0, addr2);
EXPECT_CALL(failing_socket_factory_, OnSendTo(expected_announcement2))
.Times(0);
RunUntilNoTasksRemain();
// We later unblock sending packets. Previously scheduled announcements should
// be flushed.
EXPECT_CALL(failing_socket_factory_, OnSendTo(expected_announcement1))
.Times(kNumAnnouncementsPerInterface - 1);
EXPECT_CALL(failing_socket_factory_, OnSendTo(expected_announcement2))
.Times(kNumAnnouncementsPerInterface);
failing_socket_factory_.ResumeSend();
RunUntilNoTasksRemain();
}
} // namespace network