123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- // 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.
- #ifndef SERVICES_NETWORK_MDNS_RESPONDER_H_
- #define SERVICES_NETWORK_MDNS_RESPONDER_H_
- #include <map>
- #include <memory>
- #include <set>
- #include <string>
- #include <vector>
- #include "base/callback.h"
- #include "base/containers/flat_set.h"
- #include "base/containers/unique_ptr_adapters.h"
- #include "base/memory/raw_ptr.h"
- #include "base/memory/weak_ptr.h"
- #include "base/time/default_tick_clock.h"
- #include "base/time/time.h"
- #include "mojo/public/cpp/bindings/pending_receiver.h"
- #include "mojo/public/cpp/bindings/receiver.h"
- #include "net/dns/dns_query.h"
- #include "net/dns/dns_response.h"
- #include "services/network/public/mojom/mdns_responder.mojom.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- namespace net {
- class IOBufferWithSize;
- class IPAddress;
- class MDnsSocketFactory;
- } // namespace net
- namespace network {
- class MdnsResponder;
- namespace mdns_helper {
- // Creates an mDNS response, of which the Answer section contains the address
- // records for |name_addr_map|, and the Additional section contains the
- // corresponding NSEC records that assert the existence of only address
- // records in the Answer section.
- COMPONENT_EXPORT(NETWORK_SERVICE)
- scoped_refptr<net::IOBufferWithSize> CreateResolutionResponse(
- const base::TimeDelta& ttl,
- const std::map<std::string, net::IPAddress>& name_addr_map);
- // Creates an mDNS response, of which the Answer section contains NSEC records
- // that assert the existence of only address records for |name_addr_map|, and
- // the Additional section contains the corresponding address records.
- COMPONENT_EXPORT(NETWORK_SERVICE)
- scoped_refptr<net::IOBufferWithSize> CreateNegativeResponse(
- const std::map<std::string, net::IPAddress>& name_addr_map);
- // Creates an mDNS response to an mDNS name generator service query.
- //
- // An mDNS name generator service query is a query for TXT records associated
- // with the name "Generated-Names._mdns_name_generator._udp.local". It is
- // similar to the service query defined in DNS-SD but is not an implementation
- // of the specification in RFC 6763. The Answer section of the response contains
- // a TXT record for the list of |mdns_names|. The cache-flush bit is set in the
- // TXT record if |cached_flush| is true.
- COMPONENT_EXPORT(NETWORK_SERVICE)
- scoped_refptr<net::IOBufferWithSize>
- CreateResponseToMdnsNameGeneratorServiceQuery(
- const base::TimeDelta& ttl,
- const std::set<std::string>& mdns_names);
- } // namespace mdns_helper
- // Options to configure the transmission of mDNS responses.
- struct COMPONENT_EXPORT(NETWORK_SERVICE) MdnsResponseSendOption
- : public base::RefCounted<MdnsResponseSendOption> {
- public:
- enum class ResponseClass {
- UNSPECIFIED,
- ANNOUNCEMENT,
- PROBE_RESOLUTION,
- REGULAR_RESOLUTION,
- NEGATIVE,
- GOODBYE,
- };
- MdnsResponseSendOption();
- // As a shorthand, an empty set denotes all interfaces.
- std::set<uint16_t> send_socket_handler_ids;
- // Used for rate limiting.
- base::flat_set<std::string> names_for_rate_limit;
- // Used for retry after send failure.
- ResponseClass klass = ResponseClass::UNSPECIFIED;
- // The number of retries done for the same response due to send failure.
- uint8_t num_send_retries_done = 0;
- // Indicates if the response includes a resource record that is a member of a
- // shared resource record set.
- bool shared_result = false;
- // If not nullopt, returns true if the response to send is cancelled.
- absl::optional<base::RepeatingCallback<bool()>> cancelled_callback;
- private:
- friend class base::RefCounted<MdnsResponseSendOption>;
- ~MdnsResponseSendOption();
- };
- // The responder manager creates and manages responder instances spawned for
- // each Mojo binding. It also manages the underlying network IO by delegating
- // the IO task to socket handlers of each interface. When there is a network
- // stack error or a Mojo binding error, the manager also offers the
- // corresponding error handling.
- class COMPONENT_EXPORT(NETWORK_SERVICE) MdnsResponderManager {
- public:
- // Wraps a name generation method that can be configured in tests via
- // SetNameGeneratorForTesting below.
- //
- // The generated name by |CreateName| must be no more than 245 characters.
- class NameGenerator {
- public:
- virtual ~NameGenerator() = default;
- virtual std::string CreateName() = 0;
- };
- // Used in histograms to measure the service health.
- enum class ServiceError {
- // Fail to start the MdnsResponderManager after all socket handlers fail to
- // start on each interface.
- kFailToStartManager = 0,
- // Fail to create a MdnsResponder after all socket handlers fail to start on
- // each interface.
- kFailToCreateResponder = 1,
- // All socket handlers have encountered read errors and failed. Imminent to
- // restart the MdnsResponderManager.
- kFatalSocketHandlerError = 2,
- // An invalid IP address is given to register an mDNS name for.
- kInvalidIpToRegisterName = 3,
- // A record is received from the network such that it resolves a name
- // created
- // by the service to a different address.
- kConflictingNameResolution = 4,
- kMaxValue = kConflictingNameResolution,
- };
- // Delay between throttled attempts to start the `MdnsResponderManager`.
- constexpr static base::TimeDelta kManagerStartThrottleDelay =
- base::Seconds(1);
- MdnsResponderManager();
- explicit MdnsResponderManager(net::MDnsSocketFactory* socket_factory);
- MdnsResponderManager(const MdnsResponderManager&) = delete;
- MdnsResponderManager& operator=(const MdnsResponderManager&) = delete;
- ~MdnsResponderManager();
- // Creates an instance of MdnsResponder for the receiver.
- void CreateMdnsResponder(
- mojo::PendingReceiver<mojom::MdnsResponder> receiver);
- // The methods below are used to bookkeep names owned by responders, and
- // also for the extra uniqueness validation of these names. By default,
- // we use the RandomUuidNameGenerator (see mdns_responder.cc), which
- // probabilistically guarantees the uniqueness of generated names.
- //
- // Adds a name to the set of all existing names generated by all responders
- // (i.e., names owned by an instance of responder). Return true if the name is
- // not in the set before the addition; false otherwise.
- bool AddName(const std::string& name) {
- auto result = names_.insert(name);
- return result.second;
- }
- // Removes a name from the set of all existing names generated by all
- // responders. Return true if the name exists in the set before the removal;
- // false otherwise.
- bool RemoveName(const std::string& name) { return names_.erase(name) == 1; }
- // Sends an mDNS response in the wire format given by |buf|. See
- // MdnsResponseSendOption for configurable options in |option|.
- //
- // Sending responses is rate-limited, and this method returns true if the
- // response is successfully scheduled to send on all successfully bound
- // interfaces specified in |option.send_socket_handler_ids|, and false
- // otherwise.
- bool Send(scoped_refptr<net::IOBufferWithSize> buf,
- scoped_refptr<MdnsResponseSendOption> option);
- // The error handler that is invoked when the Mojo binding of |responder| is
- // closed (e.g. the InterfacePtr on the client side is destroyed) or
- // encounters an error. It removes this responder instance, which further
- // clears the existing name-address associations owned by this responder in
- // the local network.
- void OnMojoConnectionError(MdnsResponder* responder);
- // Called when an external mDNS response is received and it contains address
- // records of names generated by an owned MdnsResponder instance.
- void HandleAddressNameConflictIfAny(
- const std::map<std::string, std::set<net::IPAddress>>&
- external_address_maps);
- // Called when an external mDNS response is received and it contains a TXT
- // record for the mDNS name generator service instance name with the
- // cache-flush bit set.
- void HandleTxtNameConflict();
- NameGenerator* name_generator() const { return name_generator_.get(); }
- // Sets the name generator that is shared by all MdnsResponder instances.
- // Changing the name generator affects all existing responder instances and
- // also the ones spawned in the future.
- //
- // Used for tests only.
- void SetNameGeneratorForTesting(
- std::unique_ptr<NameGenerator> name_generator);
- // Sets the tick clock that is used for rate limiting of mDNS responses, and
- // also resets the internal schedule for rate limiting.
- //
- // Used for tests only.
- void SetTickClockForTesting(const base::TickClock* tick_clock);
- private:
- enum class SocketHandlerStartResult {
- UNSPECIFIED,
- // Handlers started for all interfaces.
- ALL_SUCCESS,
- // Handlers started for a subset of interfaces.
- PARTIAL_SUCCESS,
- // No handler started.
- ALL_FAILURE,
- };
- // Handles the underlying sending and receiving of mDNS messages on each
- // interface available. The implementation mostly resembles
- // net::MdnsConnection::SocketHandler.
- class SocketHandler;
- // Initializes socket handlers and sets `start_result_`. Safe to call multiple
- // times after success or failure (and will noop after success). As a
- // protection against spammy network usage this will also noop if called too
- // soon after the last failure.
- void StartIfNeeded();
- // Dispatches a parsed query from a socket handler to each responder instance.
- void OnMdnsQueryReceived(const net::DnsQuery& query,
- uint16_t recv_socket_handler_id);
- void OnSocketHandlerReadError(uint16_t socket_handler_id, int result);
- bool IsFatalError(int result);
- // Called when an mDNS name service query is received. The manager fills a
- // list of registered names in a TXT record in the response.
- void HandleMdnsNameGeneratorServiceQuery(const net::DnsQuery& query,
- uint16_t recv_socket_handler_id);
- // Sends a zero-TTL mDNS response with a TXT record of mDNS names from the
- // last generator service response sent. No-op if no generator service
- // response sent previously.
- void SendGoodbyePacketForMdnsNameGeneratorServiceIfNecessary();
- std::unique_ptr<net::MDnsSocketFactory> owned_socket_factory_;
- raw_ptr<net::MDnsSocketFactory> socket_factory_;
- // Only the socket handlers that have successfully bound and started are kept.
- std::map<uint16_t, std::unique_ptr<SocketHandler>> socket_handler_by_id_;
- SocketHandlerStartResult start_result_ =
- SocketHandlerStartResult::UNSPECIFIED;
- // Used to bookkeep all names owned by |responders_| for
- // 1. the extra uniqueness validation of names generated by responders;
- // 2. generating responses to the mDNS name generator service queries.
- std::set<std::string> names_;
- std::unique_ptr<NameGenerator> name_generator_;
- // The names used to create the last response to a generator service query.
- std::set<std::string> names_in_last_generator_response_;
- bool should_respond_to_generator_service_query_ = true;
- std::set<std::unique_ptr<MdnsResponder>, base::UniquePtrComparator>
- responders_;
- raw_ptr<const base::TickClock> tick_clock_ =
- base::DefaultTickClock::GetInstance();
- // If not `base::TimeTicks()`, represents the end of the throttling period for
- // calls to `StartIfNeeded()`.
- base::TimeTicks throttled_start_end_;
- base::WeakPtrFactory<MdnsResponderManager> weak_factory_{this};
- };
- // Implementation of the mDNS service that can provide utilities of an mDNS
- // responder.
- class COMPONENT_EXPORT(NETWORK_SERVICE) MdnsResponder
- : public mojom::MdnsResponder {
- public:
- MdnsResponder(mojo::PendingReceiver<mojom::MdnsResponder> receiver,
- MdnsResponderManager* manager);
- MdnsResponder(const MdnsResponder&) = delete;
- MdnsResponder& operator=(const MdnsResponder&) = delete;
- // When destroyed, clears all existing name-address associations owned by this
- // responder in the local network by sending out goodbye packets. See
- // SendGoodbyePacketForNameAddressMap below.
- ~MdnsResponder() override;
- // mojom::MdnsResponder overrides.
- void CreateNameForAddress(
- const net::IPAddress& address,
- mojom::MdnsResponder::CreateNameForAddressCallback callback) override;
- void RemoveNameForAddress(
- const net::IPAddress& address,
- mojom::MdnsResponder::RemoveNameForAddressCallback callback) override;
- // Processes the given query and generates a response if the query contains an
- // mDNS name that this responder has a mapped IP address.
- void OnMdnsQueryReceived(const net::DnsQuery& query,
- uint16_t recv_socket_handler_id);
- bool HasConflictWithExternalResolution(
- const std::string& name,
- const std::set<net::IPAddress>& external_mapped_addreses);
- void SetNameGeneratorForTesting(
- MdnsResponderManager::NameGenerator* name_generator) {
- name_generator_ = name_generator;
- }
- private:
- // Returns true if the response is successfully scheduled to send on all
- // successfully bound interfaces after rate limiting, and false otherwise. See
- // also MdnsResponderManager::Send.
- bool SendMdnsResponse(scoped_refptr<net::IOBufferWithSize> response,
- scoped_refptr<MdnsResponseSendOption> option);
- // RFC 6761, Section 10.1 "Goodbye Packets".
- //
- // The responder should send out an unsolicited mDNS response with an resource
- // record of zero TTL to clear the name-to-address mapping in neighboring
- // hosts, when the mapping is no longer valid.
- //
- // Returns true if the goodbye message is successfully scheduled to send on
- // all interfaces after rate limiting, and false otherwise. See also
- // MdnsResponderManager::Send.
- bool SendGoodbyePacketForNameAddressMap(
- const std::map<std::string, net::IPAddress>& name_addr_map);
- std::map<std::string, net::IPAddress>::iterator FindNameCreatedForAddress(
- const net::IPAddress& address);
- mojo::Receiver<network::mojom::MdnsResponder> receiver_;
- // A back pointer to the responder manager that owns this responder. The
- // responder should be destroyed before |manager_| becomes invalid or a weak
- // reference should be used to access the manager when there is no such
- // guarantee in an operation.
- const raw_ptr<MdnsResponderManager> manager_;
- std::map<std::string, net::IPAddress> name_addr_map_;
- std::map<std::string, uint16_t> name_refcount_map_;
- raw_ptr<MdnsResponderManager::NameGenerator> name_generator_;
- };
- } // namespace network
- #endif // SERVICES_NETWORK_MDNS_RESPONDER_H_
|