// Copyright 2019 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Collection of constants defined for multicast DNS (RFC 6762) and DNS-Based // Service Discovery (RFC 6763), along with a few constants used specifically // for cast receiver's implementation of the mDNS spec (not 100% conformant). // // Some cast-specific implementation details include the maximum multicast // message size (synced with sender SDK) and usage of site-local MDNS group // in addition to the default link-local MDNS multicast group. #ifndef DISCOVERY_MDNS_PUBLIC_MDNS_CONSTANTS_H_ #define DISCOVERY_MDNS_PUBLIC_MDNS_CONSTANTS_H_ #include <stddef.h> #include <stdint.h> #include <array> #include <chrono> #include "platform/api/time.h" #include "platform/base/ip_address.h" #include "util/osp_logging.h" namespace openscreen::discovery { // ============================================================================ // Networking // ============================================================================ // RFC 6762: https://www.ietf.org/rfc/rfc6762.txt // RFC 2365: https://www.ietf.org/rfc/rfc2365.txt // RFC 5771: https://www.ietf.org/rfc/rfc5771.txt // RFC 7346: https://www.ietf.org/rfc/rfc7346.txt // Default multicast port used by mDNS protocol. On some systems there may be // multiple processes binding to same port, so prefer to allow address re-use. // See RFC 6762, Section 2 constexpr uint16_t kDefaultMulticastPort = …; // IPv4 group address for sending mDNS messages, given as byte array in // network-order. This is a link-local multicast address, so messages will not // be forwarded outside local network. See RFC 6762, section 3. constexpr IPAddress kDefaultMulticastGroupIPv4{ … }; // IPv6 group address for sending mDNS messages. This is a link-local // multicast address, so messages will not be forwarded outside local network. // See RFC 6762, section 3. constexpr IPAddress kDefaultMulticastGroupIPv6{ … }; // The send address for multicast mDNS should be the any address (0.*) on the // default mDNS multicast port. constexpr IPEndpoint kMulticastSendIPv4Endpoint{ … }; constexpr IPEndpoint kMulticastSendIPv6Endpoint{ … }; // IPv4 group address for joining cast-specific site-local mDNS multicast group, // given as byte array in network-order. This is a site-local multicast address, // so messages can extend past the local network to the administrative area // boundary. Local sockets will filter out messages that are not on local- // subnet though, so it will behave the same as link-local. The difference is // that router sometimes treat link-local and site-local differently, which // may cause link-local to have worse reliability than site-local. // See https://tools.ietf.org/html/draft-cai-ssdp-v1-03 // 239.X.X.X is "administratively scoped IPv4 multicast space". See RFC 2365 // and RFC 5771, Section 3. Combined with relative address of 5 for SSDP this // gives 239.255.255.250. See // https://www.iana.org/assignments/multicast-addresses // NOTE: For now the group address is the same group address used for SSDP // discovery, albeit using the MDNS port rather than SSDP port. constexpr IPAddress kDefaultSiteLocalGroupIPv4{ … }; constexpr IPEndpoint kDefaultSiteLocalGroupIPv4Endpoint{ … }; // IPv6 group address for joining cast-specific site-local mDNS multicast group, // give as byte array in network-order. See comments for IPv4 group address for // more details on site-local vs. link-local. // 0xFF05 is site-local. See RFC 7346. // FF0X:0:0:0:0:0:0:C is variable scope multicast addresses for SSDP. See // https://www.iana.org/assignments/ipv6-multicast-addresses constexpr IPAddress kDefaultSiteLocalGroupIPv6{ … }; constexpr IPEndpoint kDefaultSiteLocalGroupIPv6Endpoint{ … }; // Maximum MTU size (1500) minus the UDP header size (8) and IP header size // (20). If any packets are larger than this size, the responder or sender // should break up the message into multiple packets and set the TC // (Truncated) bit to 1. See RFC 6762, section 7.2. // TODO(https://crbug.com/openscreen/47): Figure out the exact size that the // senders are using and sync with them. We want to verify that we are using the // same maximum packet size. The spec also suggests keeping all UDP messsages // below 512 bytes, since that is where some fragmentation may occur. If // possible we should measure the rate of fragmented messages and see if // lowering the max size alleviates it. constexpr size_t kMaxMulticastMessageSize = …; // Specifies whether the site-local group described above should be enabled // by default. When enabled, the responder will be able to receive messages from // that group; when disabled, only the default MDNS multicast group will be // enabled. constexpr bool kDefaultSupportSiteLocalGroup = …; // ============================================================================ // Message Header // ============================================================================ // RFC 1035: https://www.ietf.org/rfc/rfc1035.txt // RFC 2535: https://www.ietf.org/rfc/rfc2535.txt // DNS packet consists of a fixed-size header (12 bytes) followed by // zero or more questions and/or records. // For the meaning of specific fields, please see RFC 1035 and 2535. // // Header format: // 1 1 1 1 1 1 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // | ID | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // |QR| Opcode |AA|TC|RD|RA| Z|AD|CD| RCODE | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // | QDCOUNT | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // | ANCOUNT | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // | NSCOUNT | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // | ARCOUNT | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // On-the-wire header. All uint16_t are in network order. struct Header { … }; static_assert …; enum class MessageType { … }; constexpr uint16_t kFlagResponse = …; constexpr uint16_t kFlagAA = …; constexpr uint16_t kFlagTC = …; constexpr uint16_t kOpcodeMask = …; constexpr uint16_t kRcodeMask = …; constexpr MessageType GetMessageType(uint16_t flags) { … } constexpr bool IsMessageTruncated(uint16_t flags) { … } constexpr uint16_t MakeFlags(MessageType type, bool is_truncated) { … } constexpr bool IsValidFlagsSection(uint16_t flags) { … } // ============================================================================ // Domain Name // ============================================================================ // RFC 1035: https://www.ietf.org/rfc/rfc1035.txt // Maximum number of octets allowed in a single domain name including the // terminating character octet constexpr size_t kMaxDomainNameLength = …; // Maximum number of octets allowed in a single domain name label. constexpr size_t kMaxLabelLength = …; // To allow for message compression, domain names can fall under the following // categories: // - A sequence of labels ending in a zero octet (label of length zero) // - A pointer to prior occurance of name in message // - A sequence of labels ending with a pointer. // // Domain Name Label - DIRECT: // 1 1 1 1 1 1 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // | 0 0| LABEL LENGTH | CHAR 0 | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // / CHAR 1 | CHAR 2 / // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // // Domain Name Label - POINTER: // 1 1 1 1 1 1 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // | 1 1| OFFSET | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ constexpr uint8_t kLabelTermination = …; constexpr uint8_t kLabelTypeMask = …; constexpr uint8_t kLabelDirect = …; constexpr uint8_t kLabelPointer = …; constexpr uint8_t kLabelLengthMask = …; constexpr uint16_t kLabelOffsetMask = …; constexpr bool IsTerminationLabel(uint8_t label) { … } constexpr bool IsDirectLabel(uint8_t label) { … } constexpr bool IsPointerLabel(uint8_t label) { … } constexpr uint8_t GetDirectLabelLength(uint8_t label) { … } constexpr uint16_t GetPointerLabelOffset(uint16_t label) { … } constexpr bool IsValidPointerLabelOffset(size_t offset) { … } constexpr uint16_t MakePointerLabel(uint16_t offset) { … } constexpr uint8_t MakeDirectLabel(uint8_t length) { … } // ============================================================================ // Record Fields // ============================================================================ // RFC 1035: https://www.ietf.org/rfc/rfc1035.txt // RFC 2535: https://www.ietf.org/rfc/rfc2535.txt // Question format: // 1 1 1 1 1 1 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // | | // / QNAME / // / / // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // | QTYPE | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // | QCLASS | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // Answer format: // 1 1 1 1 1 1 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // | | // / / // / NAME / // | | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // | TYPE | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // | CLASS | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // | TTL | // | | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // | RDLENGTH | // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| // / RDATA / // / / // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ // DNS TYPE values. See http://www.iana.org/assignments/dns-parameters for full // list. Only a sub-set is used and listed here. enum class DnsType : uint16_t { … }; // TODO(mfoltz): Move definition so we don't have to inline. inline std::ostream& operator<<(std::ostream& output, DnsType type) { … } constexpr std::array<DnsType, 7> kSupportedDnsTypes = …; enum class DnsClass : uint16_t { … }; // Unique and shared records are described in // https://tools.ietf.org/html/rfc6762#section-2 and // https://tools.ietf.org/html/rfc6762#section-10.2 enum class RecordType { … }; // Unicast and multicast preferred response types are described in // https://tools.ietf.org/html/rfc6762#section-5.4 enum class ResponseType { … }; // These are the default TTL values for supported DNS Record types as specified // by RFC 6762 section 10. constexpr std::chrono::seconds kPtrRecordTtl(120); constexpr std::chrono::seconds kSrvRecordTtl(120); constexpr std::chrono::seconds kARecordTtl(120); constexpr std::chrono::seconds kAAAARecordTtl(120); constexpr std::chrono::seconds kTXTRecordTtl(120); // DNS CLASS masks and values. // In mDNS the most significant bit of the RRCLASS for response records is // designated as the "cache-flush bit", as described in // https://tools.ietf.org/html/rfc6762#section-10.2 // In mDNS the most significant bit of the RRCLASS for query records is // designated as the "unicast-response bit", as described in // https://tools.ietf.org/html/rfc6762#section-5.4 constexpr uint16_t kClassMask = …; constexpr uint16_t kClassMsbMask = …; constexpr uint16_t kClassMsbShift = …; constexpr DnsClass GetDnsClass(uint16_t rrclass) { … } constexpr RecordType GetRecordType(uint16_t rrclass) { … } constexpr ResponseType GetResponseType(uint16_t rrclass) { … } constexpr uint16_t MakeRecordClass(DnsClass dns_class, RecordType record_type) { … } constexpr uint16_t MakeQuestionClass(DnsClass dns_class, ResponseType response_type) { … } // See RFC 6762, section 11: https://tools.ietf.org/html/rfc6762#section-11 // // The IP TTL value for the UDP packets sent to the multicast group is advised // to be 255 in order to be compatible with older DNS queriers. This also keeps // consistent with other mDNS solutions (jMDNS, Avahi, etc.), which use 255 // as the IP TTL as well. // // The default mDNS group address is in a range of link-local addresses, so // messages should not be forwarded by routers even when TTL is greater than 1. constexpr uint32_t kDefaultRecordTTLSeconds = …; // ============================================================================ // RDATA Constants // ============================================================================ // The maximum allowed size for a single entry in a TXT resource record. The // mDNS spec specifies that entries in TXT record should be key/value pair // separated by '=', so the size of the key + value + '=' should not exceed // the maximum allowed size. // See: https://tools.ietf.org/html/rfc6763#section-6.1 constexpr size_t kTXTMaxEntrySize = …; // Placeholder RDATA for "empty" TXT records that contains only a single // zero length byte. This is required since TXT records CANNOT have empty // RDATA sections. // See RFC: https://tools.ietf.org/html/rfc6763#section-6.1 constexpr uint8_t kTXTEmptyRdata = …; // ============================================================================ // Probing Constants // ============================================================================ // RFC 6762 section 8.1 specifies that a probe should wait 250 ms between // subsequent probe queries. constexpr Clock::duration kDelayBetweenProbeQueries = …; // RFC 6762 section 8.1 specifies that the probing phase should send out probe // requests 3 times before treating the probe as completed. constexpr int kProbeIterationCountBeforeSuccess = …; // ============================================================================ // OPT Pseudo-Record Constants // ============================================================================ // For OPT records, the TTL field has been re-purposed as follows: // // +0 (MSB) +1 (LSB) // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ // 0: | EXTENDED-RCODE | VERSION | // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ // 2: | DO| Z | // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ constexpr uint32_t kExtendedRcodeMask = …; constexpr int kExtendedRcodeShift = …; constexpr uint32_t kVersionMask = …; constexpr int kVersionShift = …; constexpr uint32_t kDnssecOkBitMask = …; constexpr uint8_t kVersionBadvers = …; } // namespace openscreen::discovery #endif // DISCOVERY_MDNS_PUBLIC_MDNS_CONSTANTS_H_