chromium/services/network/mdns_responder.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.

#include "services/network/mdns_responder.h"

#include <algorithm>
#include <cmath>
#include <numeric>
#include <optional>
#include <queue>
#include <string>
#include <utility>

#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_macros.h"
#include "base/not_fatal_until.h"
#include "base/numerics/safe_conversions.h"
#include "base/rand_util.h"
#include "base/strings/stringprintf.h"
#include "base/time/default_tick_clock.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/uuid.h"
#include "net/base/address_family.h"
#include "net/base/io_buffer.h"
#include "net/base/ip_address.h"
#include "net/base/net_errors.h"
#include "net/dns/dns_names_util.h"
#include "net/dns/dns_response.h"
#include "net/dns/dns_util.h"
#include "net/dns/mdns_client.h"
#include "net/dns/public/dns_protocol.h"
#include "net/dns/public/util.h"
#include "net/dns/record_parsed.h"
#include "net/dns/record_rdata.h"
#include "net/socket/datagram_server_socket.h"
#include "net/socket/udp_server_socket.h"
#include "services/network/public/cpp/features.h"

// TODO(qingsi): Several features to implement:
//
// 1) Support parsing a query with multiple questions in the wire format to a
// DnsQuery, and bundle answers to questions in a single DnsResponse with proper
// rate limiting.
//
// 2) Support detecting queries for the same record within the minimal interval
// between responses and allow at most one response queued by the scheduler at a
// time for each name.
//
// 3) Support parsing the authority section of a query in the wire format to
// correctly implement the detection of probe queries.
namespace network {

namespace {

MdnsResponderServiceError;

// RFC 6762, Section 6.
//
// The multicast of responses of the same record on an interface must be at
// least one second apart on that particular interface.
const base::TimeDelta kMinIntervalBetweenSameRecord =;

const base::TimeDelta kMinIntervalBetweenMdnsResponses =;

// RFC 6762, Section 10.
const base::TimeDelta kDefaultTtlForRecordWithHostname =;

// RFC 6762, Section 8.3.
const int kMinNumAnnouncementsToSend =;

// Maximum number of retries for the same response due to send failure.
const uint8_t kMaxMdnsResponseRetries =;
// The capacity of the send queue for packets blocked by an incomplete send.
const uint8_t kSendQueueCapacity =;
// Maximum delay allowed for per-response rate-limited responses.
const base::TimeDelta kMaxScheduledDelay =;

// The query name of the mDNS name generator service.
const char kMdnsNameGeneratorServiceInstanceName[] =;

// RFC 6763, the TXT record is recommended to be under 1300 bytes to fit in a
// single 1500-byte Ethernet packet.
//
// Currently we only construct a TXT record in the response to an mDNS name
// generator service query. The record consists of a list of owned names, and
// this list is truncated as necessary to stay within the size limit. See
// |CreateTxtRdataWithNames| below for the detail.
const uint16_t kMaxTxtRecordSizeInBytes =;
// RFC 6763, Section 6.4, the key in a kv pair in a DNS-SD TXT record should be
// no more than 9 characters long.
const int kMaxKeySizeInTxtRecord =;
// The prefix of the key used in the TXT record to list mDNS names.
const char kKeyPrefixInTxtRecord[] =;
// Version tag in the TXT record.
const char kTxtversLine[] =;

// RFC 6762, Section 6, a response that may contain an answer as a member of a
// shared resource record set, should be delayed uniformly and randomly in the
// range of 20-120 ms. This delay is applied in addition to the scheduled delay
// by rate limiting.
constexpr auto kMinRandDelayForSharedResult =;
constexpr auto kMaxRandDelayForSharedResult =;

class RandomUuidNameGenerator
    : public network::MdnsResponderManager::NameGenerator {};

bool QueryTypeAndAddressFamilyAreCompatible(uint16_t qtype,
                                            net::AddressFamily af) {}

// Creates a vector of A or AAAA records, where the name field of each record is
// given by the name in |name_addr_map|, and its mapped address is used to
// construct the RDATA stored in |DnsResourceRecord::owned_rdata|. |ttl|
// specifies the TTL of each record. With the owned RDATA, the returned records
// can be later used to construct a DnsResponse.
std::vector<net::DnsResourceRecord> CreateAddressResourceRecords(
    const std::map<std::string, net::IPAddress>& name_addr_map,
    const base::TimeDelta& ttl) {}

// Creates an NSEC record RDATA in the wire format for the resource record type
// that corresponds to the address family of |addr|. The type bit map in the
// RDATA asserts the existence of only the address record that matches |addr|.
// Per RFC 3845 Section 2.1 and RFC 6762 Section 6, each RDATA has its Next
// Domain Name as a two-octet pointer to the name field of the NSEC resource
// record. |containing_nsec_rr_offset| defines the offset in the message of the
// NSEC resource record that would contain the returned RDATA, and its value is
// used to generate the correct pointer for Next Domain Name.
std::string CreateNsecRdata(const net::IPAddress& addr,
                            uint16_t containing_nsec_rr_offset) {}

// Creates a vector of NSEC records, where the name field of each record is
// given by the name in |name_addr_map|, and its mapped address is used to
// construct the RDATA stored in |DnsResourceRecord::owned_rdata| via
// CreateNsecRdata above. With the owned RDATA, the returned records can be
// later used to construct a DnsResponse.
std::vector<net::DnsResourceRecord> CreateNsecResourceRecords(
    const std::map<std::string, net::IPAddress>& name_addr_map,
    uint16_t first_nsec_rr_offset) {}

// Creates TXT RDATA as a list of key-value pairs subject to a size limit. The
// key is in the format "name0", "name1" and so on, and the value is the name.
std::string CreateTxtRdataWithNames(const std::set<std::string>& names,
                                    uint16_t txt_rdata_size_limit) {}

net::DnsResourceRecord CreateTxtRecordWithNames(
    const base::TimeDelta& ttl,
    const std::string& service_instance_name,
    const std::set<std::string>& names) {}

bool IsProbeQuery(const net::DnsQuery& query) {}

struct PendingPacket {};

}  // namespace


namespace mdns_helper {

scoped_refptr<net::IOBufferWithSize> CreateResolutionResponse(
    const base::TimeDelta& ttl,
    const std::map<std::string, net::IPAddress>& name_addr_map) {}

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

scoped_refptr<net::IOBufferWithSize>
CreateResponseToMdnsNameGeneratorServiceQuery(
    const base::TimeDelta& ttl,
    const std::set<std::string>& mdns_names) {}

}  // namespace mdns_helper

class MdnsResponderManager::SocketHandler {};

// Implements the rate limiting schemes for sending responses as defined by
// RateLimitScheme. Specifically:
//
// 1. Announcements for new names (RFC 6762, Section 8.3) and goodbyes (RFC
// 6762, Section 10.1) are rate limited per response on each interface, so that
// the interval between sending the above responses is no less than one second
// on the given interface.
//
// 2. Responses containing resource records for name resolution, and also
// negative responses to queries for non-existing records of generated names,
// are rate limited per record. The delay of such a response from the last
// per-record rate limited response is computed as the maximum delay of all
// records (names) contained. Per RFC 6762, Section 6, records are sent at a
// maximum rate of one per each second.
//
// 3. Responses to probing queries (RFC 6762, Section 8.1) are not rate
// limited.
//
// Also, if the projected delay of a response exceeds the maximum scheduled
// delay given by kMaxScheduledDelay, the response is NOT scheduled.
class MdnsResponderManager::SocketHandler::ResponseScheduler {};

bool MdnsResponderManager::SocketHandler::Send(
    scoped_refptr<net::IOBufferWithSize> buf,
    scoped_refptr<MdnsResponseSendOption> option) {}

int MdnsResponderManager::SocketHandler::DoSend(PendingPacket pending_packet) {}

void MdnsResponderManager::SocketHandler::SetTickClockForTesting(
    const base::TickClock* tick_clock) {}

bool MdnsResponderManager::SocketHandler::ResponseScheduler::ScheduleNextSend(
    scoped_refptr<net::IOBufferWithSize> buf,
    scoped_refptr<MdnsResponseSendOption> option) {}

std::optional<base::TimeDelta> MdnsResponderManager::SocketHandler::
    ResponseScheduler::ComputeResponseDelayAndUpdateNextAvailableTime(
        RateLimitScheme rate_limit_scheme,
        const MdnsResponseSendOption& option) {}

void MdnsResponderManager::SocketHandler::ResponseScheduler::
    DispatchPendingPackets() {}

MdnsResponseSendOption::MdnsResponseSendOption() = default;
MdnsResponseSendOption::~MdnsResponseSendOption() = default;

// static
constexpr base::TimeDelta MdnsResponderManager::kManagerStartThrottleDelay;

MdnsResponderManager::MdnsResponderManager() :{}

MdnsResponderManager::MdnsResponderManager(
    net::MDnsSocketFactory* socket_factory)
    :{}

MdnsResponderManager::~MdnsResponderManager() {}

void MdnsResponderManager::StartIfNeeded() {}

void MdnsResponderManager::CreateMdnsResponder(
    mojo::PendingReceiver<mojom::MdnsResponder> receiver) {}

bool MdnsResponderManager::Send(scoped_refptr<net::IOBufferWithSize> buf,
                                scoped_refptr<MdnsResponseSendOption> option) {}

void MdnsResponderManager::OnMojoConnectionError(MdnsResponder* responder) {}

void MdnsResponderManager::SetNameGeneratorForTesting(
    std::unique_ptr<MdnsResponderManager::NameGenerator> name_generator) {}

void MdnsResponderManager::SetTickClockForTesting(
    const base::TickClock* tick_clock) {}

void MdnsResponderManager::HandleAddressNameConflictIfAny(
    const std::map<std::string, std::set<net::IPAddress>>& external_maps) {}

void MdnsResponderManager::HandleTxtNameConflict() {}

void MdnsResponderManager::OnMdnsQueryReceived(
    const net::DnsQuery& query,
    uint16_t recv_socket_handler_id) {}

void MdnsResponderManager::OnSocketHandlerReadError(uint16_t socket_handler_id,
                                                    int result) {}

bool MdnsResponderManager::IsFatalError(int result) {}

void MdnsResponderManager::HandleMdnsNameGeneratorServiceQuery(
    const net::DnsQuery& query,
    uint16_t recv_socket_handler_id) {}

// TODO(qingsi): When the list of owned names are updated, if we have ever sent
// a response to the generator service query, we should send a goodbye for the
// stale list of names and an update to advertise the new list. See RFC 6762,
// Section 8.4. Currently we only send the goodbye when the manager is
// destroyed. See the destructor of the manager.
void MdnsResponderManager::
    SendGoodbyePacketForMdnsNameGeneratorServiceIfNecessary() {}

int MdnsResponderManager::SocketHandler::HandlePacket(int result) {}

MdnsResponder::MdnsResponder(
    mojo::PendingReceiver<mojom::MdnsResponder> receiver,
    MdnsResponderManager* manager)
    :{}

MdnsResponder::~MdnsResponder() {}

void MdnsResponder::CreateNameForAddress(
    const net::IPAddress& address,
    mojom::MdnsResponder::CreateNameForAddressCallback callback) {}

void MdnsResponder::RemoveNameForAddress(
    const net::IPAddress& address,
    mojom::MdnsResponder::RemoveNameForAddressCallback callback) {}

void MdnsResponder::OnMdnsQueryReceived(const net::DnsQuery& query,
                                        uint16_t recv_socket_handler_id) {}

bool MdnsResponder::HasConflictWithExternalResolution(
    const std::string& name,
    const std::set<net::IPAddress>& external_mapped_addreses) {}

bool MdnsResponder::SendMdnsResponse(
    scoped_refptr<net::IOBufferWithSize> response,
    scoped_refptr<MdnsResponseSendOption> option) {}

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

std::map<std::string, net::IPAddress>::iterator
MdnsResponder::FindNameCreatedForAddress(const net::IPAddress& address) {}

}  // namespace network