1 // Copyright 2019 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef DISCOVERY_MDNS_MDNS_RECORDS_H_ 6 #define DISCOVERY_MDNS_MDNS_RECORDS_H_ 7 8 #include <algorithm> 9 #include <chrono> 10 #include <functional> 11 #include <initializer_list> 12 #include <string> 13 #include <utility> 14 #include <vector> 15 16 #include "absl/strings/ascii.h" 17 #include "absl/strings/string_view.h" 18 #include "absl/types/variant.h" 19 #include "discovery/mdns/public/mdns_constants.h" 20 #include "platform/base/error.h" 21 #include "platform/base/interface_info.h" 22 #include "platform/base/ip_address.h" 23 #include "util/osp_logging.h" 24 25 namespace openscreen { 26 namespace discovery { 27 28 bool IsValidDomainLabel(absl::string_view label); 29 30 // Represents domain name as a collection of labels, ensures label length and 31 // domain name length requirements are met. 32 class DomainName { 33 public: 34 DomainName(); 35 36 template <typename IteratorType> TryCreate(IteratorType first,IteratorType last)37 static ErrorOr<DomainName> TryCreate(IteratorType first, IteratorType last) { 38 std::vector<std::string> labels; 39 size_t max_wire_size = 1; 40 labels.reserve(std::distance(first, last)); 41 for (IteratorType entry = first; entry != last; ++entry) { 42 if (!IsValidDomainLabel(*entry)) { 43 return Error::Code::kParameterInvalid; 44 } 45 labels.emplace_back(*entry); 46 // Include the length byte in the size calculation. 47 max_wire_size += entry->size() + 1; 48 } 49 50 if (max_wire_size > kMaxDomainNameLength) { 51 return Error::Code::kIndexOutOfBounds; 52 } else { 53 return DomainName(std::move(labels), max_wire_size); 54 } 55 } 56 57 template <typename IteratorType> DomainName(IteratorType first,IteratorType last)58 DomainName(IteratorType first, IteratorType last) { 59 ErrorOr<DomainName> domain = TryCreate(first, last); 60 *this = std::move(domain.value()); 61 } 62 explicit DomainName(std::vector<std::string> labels); 63 explicit DomainName(const std::vector<absl::string_view>& labels); 64 explicit DomainName(std::initializer_list<absl::string_view> labels); 65 DomainName(const DomainName& other); 66 DomainName(DomainName&& other) noexcept; 67 68 DomainName& operator=(const DomainName& rhs); 69 DomainName& operator=(DomainName&& rhs); 70 bool operator<(const DomainName& rhs) const; 71 bool operator<=(const DomainName& rhs) const; 72 bool operator>(const DomainName& rhs) const; 73 bool operator>=(const DomainName& rhs) const; 74 bool operator==(const DomainName& rhs) const; 75 bool operator!=(const DomainName& rhs) const; 76 77 std::string ToString() const; 78 79 // Returns the maximum space that the domain name could take up in its 80 // on-the-wire format. This is an upper bound based on the length of the 81 // labels that make up the domain name. It's possible that with domain name 82 // compression the actual space taken in on-the-wire format is smaller. 83 size_t MaxWireSize() const; empty()84 bool empty() const { return labels_.empty(); } IsRoot()85 bool IsRoot() const { return labels_.empty(); } labels()86 const std::vector<std::string>& labels() const { return labels_; } 87 88 template <typename H> AbslHashValue(H h,const DomainName & domain_name)89 friend H AbslHashValue(H h, const DomainName& domain_name) { 90 std::vector<std::string> labels_clone = domain_name.labels_; 91 for (auto& label : labels_clone) { 92 absl::AsciiStrToLower(&label); 93 } 94 return H::combine(std::move(h), std::move(labels_clone)); 95 } 96 97 private: 98 DomainName(std::vector<std::string> labels, size_t max_wire_size); 99 100 // max_wire_size_ starts at 1 for the terminating character length. 101 size_t max_wire_size_ = 1; 102 std::vector<std::string> labels_; 103 }; 104 105 // Parsed representation of the extra data in a record. Does not include 106 // standard DNS record data such as TTL, Name, Type, and Class. We use it to 107 // distinguish a raw record type that we do not know the identity of. 108 class RawRecordRdata { 109 public: 110 static ErrorOr<RawRecordRdata> TryCreate(std::vector<uint8_t> rdata); 111 112 RawRecordRdata(); 113 explicit RawRecordRdata(std::vector<uint8_t> rdata); 114 RawRecordRdata(const uint8_t* begin, size_t size); 115 RawRecordRdata(const RawRecordRdata& other); 116 RawRecordRdata(RawRecordRdata&& other) noexcept; 117 118 RawRecordRdata& operator=(const RawRecordRdata& rhs); 119 RawRecordRdata& operator=(RawRecordRdata&& rhs); 120 bool operator==(const RawRecordRdata& rhs) const; 121 bool operator!=(const RawRecordRdata& rhs) const; 122 123 size_t MaxWireSize() const; size()124 uint16_t size() const { return rdata_.size(); } data()125 const uint8_t* data() const { return rdata_.data(); } 126 127 template <typename H> AbslHashValue(H h,const RawRecordRdata & rdata)128 friend H AbslHashValue(H h, const RawRecordRdata& rdata) { 129 return H::combine(std::move(h), rdata.rdata_); 130 } 131 132 private: 133 std::vector<uint8_t> rdata_; 134 }; 135 136 // SRV record format (http://www.ietf.org/rfc/rfc2782.txt): 137 // 2 bytes network-order unsigned priority 138 // 2 bytes network-order unsigned weight 139 // 2 bytes network-order unsigned port 140 // target: domain name (on-the-wire representation) 141 class SrvRecordRdata { 142 public: 143 SrvRecordRdata(); 144 SrvRecordRdata(uint16_t priority, 145 uint16_t weight, 146 uint16_t port, 147 DomainName target); 148 SrvRecordRdata(const SrvRecordRdata& other); 149 SrvRecordRdata(SrvRecordRdata&& other) noexcept; 150 151 SrvRecordRdata& operator=(const SrvRecordRdata& rhs); 152 SrvRecordRdata& operator=(SrvRecordRdata&& rhs); 153 bool operator==(const SrvRecordRdata& rhs) const; 154 bool operator!=(const SrvRecordRdata& rhs) const; 155 156 size_t MaxWireSize() const; priority()157 uint16_t priority() const { return priority_; } weight()158 uint16_t weight() const { return weight_; } port()159 uint16_t port() const { return port_; } target()160 const DomainName& target() const { return target_; } 161 162 template <typename H> AbslHashValue(H h,const SrvRecordRdata & rdata)163 friend H AbslHashValue(H h, const SrvRecordRdata& rdata) { 164 return H::combine(std::move(h), rdata.priority_, rdata.weight_, rdata.port_, 165 rdata.target_); 166 } 167 168 private: 169 uint16_t priority_ = 0; 170 uint16_t weight_ = 0; 171 uint16_t port_ = 0; 172 DomainName target_; 173 }; 174 175 // A Record format (http://www.ietf.org/rfc/rfc1035.txt): 176 // 4 bytes for IP address. 177 class ARecordRdata { 178 public: 179 ARecordRdata(); 180 explicit ARecordRdata(IPAddress ipv4_address, 181 NetworkInterfaceIndex interface_index = 0); 182 ARecordRdata(const ARecordRdata& other); 183 ARecordRdata(ARecordRdata&& other) noexcept; 184 185 ARecordRdata& operator=(const ARecordRdata& rhs); 186 ARecordRdata& operator=(ARecordRdata&& rhs); 187 bool operator==(const ARecordRdata& rhs) const; 188 bool operator!=(const ARecordRdata& rhs) const; 189 190 size_t MaxWireSize() const; ipv4_address()191 const IPAddress& ipv4_address() const { return ipv4_address_; } interface_index()192 NetworkInterfaceIndex interface_index() const { return interface_index_; } 193 194 template <typename H> AbslHashValue(H h,const ARecordRdata & rdata)195 friend H AbslHashValue(H h, const ARecordRdata& rdata) { 196 const auto& bytes = rdata.ipv4_address_.bytes(); 197 return H::combine_contiguous(std::move(h), bytes, 4); 198 } 199 200 private: 201 IPAddress ipv4_address_{0, 0, 0, 0}; 202 NetworkInterfaceIndex interface_index_; 203 }; 204 205 // AAAA Record format (http://www.ietf.org/rfc/rfc1035.txt): 206 // 16 bytes for IP address. 207 class AAAARecordRdata { 208 public: 209 AAAARecordRdata(); 210 explicit AAAARecordRdata(IPAddress ipv6_address, 211 NetworkInterfaceIndex interface_index = 0); 212 AAAARecordRdata(const AAAARecordRdata& other); 213 AAAARecordRdata(AAAARecordRdata&& other) noexcept; 214 215 AAAARecordRdata& operator=(const AAAARecordRdata& rhs); 216 AAAARecordRdata& operator=(AAAARecordRdata&& rhs); 217 bool operator==(const AAAARecordRdata& rhs) const; 218 bool operator!=(const AAAARecordRdata& rhs) const; 219 220 size_t MaxWireSize() const; ipv6_address()221 const IPAddress& ipv6_address() const { return ipv6_address_; } interface_index()222 NetworkInterfaceIndex interface_index() const { return interface_index_; } 223 224 template <typename H> AbslHashValue(H h,const AAAARecordRdata & rdata)225 friend H AbslHashValue(H h, const AAAARecordRdata& rdata) { 226 const auto& bytes = rdata.ipv6_address_.bytes(); 227 return H::combine_contiguous(std::move(h), bytes, 16); 228 } 229 230 private: 231 IPAddress ipv6_address_{0x0000, 0x0000, 0x0000, 0x0000, 232 0x0000, 0x0000, 0x0000, 0x0000}; 233 NetworkInterfaceIndex interface_index_; 234 }; 235 236 // PTR record format (http://www.ietf.org/rfc/rfc1035.txt): 237 // domain: On the wire representation of domain name. 238 class PtrRecordRdata { 239 public: 240 PtrRecordRdata(); 241 explicit PtrRecordRdata(DomainName ptr_domain); 242 PtrRecordRdata(const PtrRecordRdata& other); 243 PtrRecordRdata(PtrRecordRdata&& other) noexcept; 244 245 PtrRecordRdata& operator=(const PtrRecordRdata& rhs); 246 PtrRecordRdata& operator=(PtrRecordRdata&& rhs); 247 bool operator==(const PtrRecordRdata& rhs) const; 248 bool operator!=(const PtrRecordRdata& rhs) const; 249 250 size_t MaxWireSize() const; ptr_domain()251 const DomainName& ptr_domain() const { return ptr_domain_; } 252 253 template <typename H> AbslHashValue(H h,const PtrRecordRdata & rdata)254 friend H AbslHashValue(H h, const PtrRecordRdata& rdata) { 255 return H::combine(std::move(h), rdata.ptr_domain_); 256 } 257 258 private: 259 DomainName ptr_domain_; 260 }; 261 262 // TXT record format (http://www.ietf.org/rfc/rfc1035.txt). 263 // texts: One or more <entries>. 264 // An <entry> is a length octet followed by as many data octets. 265 // 266 // DNS-SD interprets <entries> as a list of boolean keys and key=value 267 // attributes. See https://tools.ietf.org/html/rfc6763#section-6 for details. 268 class TxtRecordRdata { 269 public: 270 using Entry = std::vector<uint8_t>; 271 272 static ErrorOr<TxtRecordRdata> TryCreate(std::vector<Entry> texts); 273 274 TxtRecordRdata(); 275 explicit TxtRecordRdata(std::vector<Entry> texts); 276 TxtRecordRdata(const TxtRecordRdata& other); 277 TxtRecordRdata(TxtRecordRdata&& other) noexcept; 278 279 TxtRecordRdata& operator=(const TxtRecordRdata& rhs); 280 TxtRecordRdata& operator=(TxtRecordRdata&& rhs); 281 bool operator==(const TxtRecordRdata& rhs) const; 282 bool operator!=(const TxtRecordRdata& rhs) const; 283 284 size_t MaxWireSize() const; 285 // NOTE: TXT entries are not guaranteed to be character data. texts()286 const std::vector<std::string>& texts() const { return texts_; } 287 288 template <typename H> AbslHashValue(H h,const TxtRecordRdata & rdata)289 friend H AbslHashValue(H h, const TxtRecordRdata& rdata) { 290 return H::combine(std::move(h), rdata.texts_); 291 } 292 293 private: 294 TxtRecordRdata(std::vector<std::string> texts, size_t max_wire_size); 295 296 // max_wire_size_ is at least 3, uint16_t record length and at the 297 // minimum a NULL byte character string is present. 298 size_t max_wire_size_ = 3; 299 // NOTE: For compatibility with DNS-SD usage, std::string is used for internal 300 // storage. 301 std::vector<std::string> texts_; 302 }; 303 304 // NSEC record format (https://tools.ietf.org/html/rfc4034#section-4). 305 // In mDNS, this record type is used for representing negative responses to 306 // queries. 307 // 308 // next_domain_name: The next domain to process. In mDNS, this value is expected 309 // to match the record-level domain name in a negative response. 310 // 311 // An example of how the |types_| vector is serialized is as follows: 312 // When encoding the following DNS types: 313 // - A (value 1) 314 // - MX (value 15) 315 // - RRSIG (value 46) 316 // - NSEC (value 47) 317 // - TYPE1234 (value 1234) 318 // The result would be: 319 // 0x00 0x06 0x40 0x01 0x00 0x00 0x00 0x03 320 // 0x04 0x1b 0x00 0x00 0x00 0x00 0x00 0x00 321 // 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 322 // 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 323 // 0x00 0x00 0x00 0x00 0x20 324 class NsecRecordRdata { 325 public: 326 NsecRecordRdata(); 327 328 // Constructor that takes an arbitrary number of DnsType parameters. 329 // NOTE: If `types...` provide a valid set of parameters for an 330 // std::vector<DnsType> ctor call, this will compile. Do not use this ctor 331 // except to provide multiple DnsType parameters. 332 template <typename... Types> NsecRecordRdata(DomainName next_domain_name,Types...types)333 NsecRecordRdata(DomainName next_domain_name, Types... types) 334 : NsecRecordRdata(std::move(next_domain_name), 335 std::vector<DnsType>{types...}) {} 336 NsecRecordRdata(DomainName next_domain_name, std::vector<DnsType> types); 337 NsecRecordRdata(const NsecRecordRdata& other); 338 NsecRecordRdata(NsecRecordRdata&& other) noexcept; 339 340 NsecRecordRdata& operator=(const NsecRecordRdata& rhs); 341 NsecRecordRdata& operator=(NsecRecordRdata&& rhs); 342 bool operator==(const NsecRecordRdata& rhs) const; 343 bool operator!=(const NsecRecordRdata& rhs) const; 344 345 size_t MaxWireSize() const; 346 next_domain_name()347 const DomainName& next_domain_name() const { return next_domain_name_; } types()348 const std::vector<DnsType>& types() const { return types_; } encoded_types()349 const std::vector<uint8_t>& encoded_types() const { return encoded_types_; } 350 351 template <typename H> AbslHashValue(H h,const NsecRecordRdata & rdata)352 friend H AbslHashValue(H h, const NsecRecordRdata& rdata) { 353 return H::combine(std::move(h), rdata.types_, rdata.next_domain_name_); 354 } 355 356 private: 357 std::vector<uint8_t> encoded_types_; 358 std::vector<DnsType> types_; 359 DomainName next_domain_name_; 360 }; 361 362 // The OPT pseudo-record / meta-record as defined by RFC6891. 363 class OptRecordRdata { 364 public: 365 // A single option as defined in RFC6891 section 6.1.2. 366 struct Option { 367 size_t MaxWireSize() const; 368 369 bool operator>(const Option& rhs) const; 370 bool operator<(const Option& rhs) const; 371 bool operator>=(const Option& rhs) const; 372 bool operator<=(const Option& rhs) const; 373 bool operator==(const Option& rhs) const; 374 bool operator!=(const Option& rhs) const; 375 376 template <typename H> AbslHashValueOption377 friend H AbslHashValue(H h, const Option& option) { 378 return H::combine(std::move(h), option.code, option.length, option.data); 379 } 380 381 // Code assigned by the Expert Review process as defined by the DNSEXT 382 // working group and the IESG, as specified in RFC6891 section 9.1. For 383 // specific assignments, see: 384 // https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml 385 uint16_t code; 386 387 // Size (in octets) of |data|. 388 uint16_t length; 389 390 // Bit Field with meaning varying based on |code|. 391 std::vector<uint8_t> data; 392 }; 393 394 OptRecordRdata(); 395 396 // Constructor that takes zero or more Option parameters. 397 template <typename... Types> OptRecordRdata(Types...types)398 explicit OptRecordRdata(Types... types) 399 : OptRecordRdata(std::vector<Option>{std::move(types)...}) {} 400 explicit OptRecordRdata(std::vector<Option> options); 401 OptRecordRdata(const OptRecordRdata& other); 402 OptRecordRdata(OptRecordRdata&& other) noexcept; 403 404 OptRecordRdata& operator=(const OptRecordRdata& rhs); 405 OptRecordRdata& operator=(OptRecordRdata&& rhs); 406 407 // NOTE: Only the options field is technically considered part of the rdata, 408 // so only this field is considered for equality comparison. The other fields 409 // are included here solely because their meaning differs for OPT pseudo- 410 // records and normal record types. 411 bool operator==(const OptRecordRdata& rhs) const; 412 bool operator!=(const OptRecordRdata& rhs) const; 413 MaxWireSize()414 size_t MaxWireSize() const { return max_wire_size_; } 415 416 // Set of options stored in this OPT record. options()417 const std::vector<Option>& options() { return options_; } 418 419 template <typename H> AbslHashValue(H h,const OptRecordRdata & rdata)420 friend H AbslHashValue(H h, const OptRecordRdata& rdata) { 421 return H::combine(std::move(h), rdata.options_); 422 } 423 424 private: 425 // NOTE: The elements of |options_| are stored is sorted order to simplify the 426 // comparison operators of OptRecordRdata. 427 std::vector<Option> options_; 428 429 size_t max_wire_size_ = 0; 430 }; 431 432 using Rdata = absl::variant<RawRecordRdata, 433 SrvRecordRdata, 434 ARecordRdata, 435 AAAARecordRdata, 436 PtrRecordRdata, 437 TxtRecordRdata, 438 NsecRecordRdata, 439 OptRecordRdata>; 440 441 // Resource record top level format (http://www.ietf.org/rfc/rfc1035.txt): 442 // name: the name of the node to which this resource record pertains. 443 // type: 2 bytes network-order RR TYPE code. 444 // class: 2 bytes network-order RR CLASS code. 445 // ttl: 4 bytes network-order cache time interval. 446 // rdata: RDATA describing the resource. The format of this information varies 447 // according to the TYPE and CLASS of the resource record. 448 class MdnsRecord { 449 public: 450 using ConstRef = std::reference_wrapper<const MdnsRecord>; 451 452 static ErrorOr<MdnsRecord> TryCreate(DomainName name, 453 DnsType dns_type, 454 DnsClass dns_class, 455 RecordType record_type, 456 std::chrono::seconds ttl, 457 Rdata rdata); 458 459 MdnsRecord(); 460 MdnsRecord(DomainName name, 461 DnsType dns_type, 462 DnsClass dns_class, 463 RecordType record_type, 464 std::chrono::seconds ttl, 465 Rdata rdata); 466 MdnsRecord(const MdnsRecord& other); 467 MdnsRecord(MdnsRecord&& other) noexcept; 468 469 MdnsRecord& operator=(const MdnsRecord& rhs); 470 MdnsRecord& operator=(MdnsRecord&& rhs); 471 bool operator==(const MdnsRecord& other) const; 472 bool operator!=(const MdnsRecord& other) const; 473 bool operator<(const MdnsRecord& other) const; 474 bool operator>(const MdnsRecord& other) const; 475 bool operator<=(const MdnsRecord& other) const; 476 bool operator>=(const MdnsRecord& other) const; 477 478 // While not being "equivalent", a record could be said to be an update of 479 // a different record if it is the same, excepting TTL. 480 bool IsReannouncementOf(const MdnsRecord& other) const; 481 size_t MaxWireSize() const; name()482 const DomainName& name() const { return name_; } dns_type()483 DnsType dns_type() const { return dns_type_; } dns_class()484 DnsClass dns_class() const { return dns_class_; } record_type()485 RecordType record_type() const { return record_type_; } ttl()486 std::chrono::seconds ttl() const { return ttl_; } rdata()487 const Rdata& rdata() const { return rdata_; } 488 489 template <typename H> AbslHashValue(H h,const MdnsRecord & record)490 friend H AbslHashValue(H h, const MdnsRecord& record) { 491 return H::combine(std::move(h), record.name_, record.dns_type_, 492 record.dns_class_, record.record_type_, 493 record.ttl_.count(), record.rdata_); 494 } 495 496 std::string ToString() const; 497 498 private: 499 static bool IsValidConfig(const DomainName& name, 500 DnsType dns_type, 501 std::chrono::seconds ttl, 502 const Rdata& rdata); 503 504 DomainName name_; 505 DnsType dns_type_ = static_cast<DnsType>(0); 506 DnsClass dns_class_ = static_cast<DnsClass>(0); 507 RecordType record_type_ = RecordType::kShared; 508 std::chrono::seconds ttl_{kDefaultRecordTTLSeconds}; 509 // Default-constructed Rdata contains default-constructed RawRecordRdata 510 // as it is the first alternative type and it is default-constructible. 511 Rdata rdata_; 512 }; 513 514 // Creates an A or AAAA record as appropriate for the provided parameters. 515 MdnsRecord CreateAddressRecord(DomainName name, const IPAddress& address); 516 517 // Question top level format (http://www.ietf.org/rfc/rfc1035.txt): 518 // name: a domain name which identifies the target resource set. 519 // type: 2 bytes network-order RR TYPE code. 520 // class: 2 bytes network-order RR CLASS code. 521 class MdnsQuestion { 522 public: 523 static ErrorOr<MdnsQuestion> TryCreate(DomainName name, 524 DnsType dns_type, 525 DnsClass dns_class, 526 ResponseType response_type); 527 528 MdnsQuestion() = default; 529 MdnsQuestion(DomainName name, 530 DnsType dns_type, 531 DnsClass dns_class, 532 ResponseType response_type); 533 534 bool operator==(const MdnsQuestion& other) const; 535 bool operator!=(const MdnsQuestion& other) const; 536 537 size_t MaxWireSize() const; name()538 const DomainName& name() const { return name_; } dns_type()539 DnsType dns_type() const { return dns_type_; } dns_class()540 DnsClass dns_class() const { return dns_class_; } response_type()541 ResponseType response_type() const { return response_type_; } 542 543 template <typename H> AbslHashValue(H h,const MdnsQuestion & record)544 friend H AbslHashValue(H h, const MdnsQuestion& record) { 545 return H::combine(std::move(h), record.name_, record.dns_type_, 546 record.dns_class_, record.response_type_); 547 } 548 549 private: 550 void CopyFrom(const MdnsQuestion& other); 551 552 DomainName name_; 553 DnsType dns_type_ = static_cast<DnsType>(0); 554 DnsClass dns_class_ = static_cast<DnsClass>(0); 555 ResponseType response_type_ = ResponseType::kMulticast; 556 }; 557 558 // Message top level format (http://www.ietf.org/rfc/rfc1035.txt): 559 // id: 2 bytes network-order identifier assigned by the program that generates 560 // any kind of query. This identifier is copied to the corresponding reply and 561 // can be used by the requester to match up replies to outstanding queries. 562 // flags: 2 bytes network-order flags bitfield. 563 // questions: questions in the message. 564 // answers: resource records that answer the questions. 565 // authority_records: resource records that point toward authoritative name. 566 // servers additional_records: additional resource records that relate to the 567 // query. 568 class MdnsMessage { 569 public: 570 static ErrorOr<MdnsMessage> TryCreate( 571 uint16_t id, 572 MessageType type, 573 std::vector<MdnsQuestion> questions, 574 std::vector<MdnsRecord> answers, 575 std::vector<MdnsRecord> authority_records, 576 std::vector<MdnsRecord> additional_records); 577 578 MdnsMessage() = default; 579 // Constructs a message with ID, flags and empty question, answer, authority 580 // and additional record collections. 581 MdnsMessage(uint16_t id, MessageType type); 582 MdnsMessage(uint16_t id, 583 MessageType type, 584 std::vector<MdnsQuestion> questions, 585 std::vector<MdnsRecord> answers, 586 std::vector<MdnsRecord> authority_records, 587 std::vector<MdnsRecord> additional_records); 588 589 bool operator==(const MdnsMessage& other) const; 590 bool operator!=(const MdnsMessage& other) const; 591 592 void AddQuestion(MdnsQuestion question); 593 void AddAnswer(MdnsRecord record); 594 void AddAuthorityRecord(MdnsRecord record); 595 void AddAdditionalRecord(MdnsRecord record); 596 597 // Returns false if adding a new record would push the size of this message 598 // beyond kMaxMulticastMessageSize, and true otherwise. 599 bool CanAddRecord(const MdnsRecord& record); 600 601 // Sets the truncated bit (TC), as specified in RFC 1035 Section 4.1.1. set_truncated()602 void set_truncated() { is_truncated_ = true; } 603 604 // Returns true if the provided message is an mDNS probe query as described in 605 // RFC 6762 section 8.1. Specifically, it examines whether any question in 606 // the 'questions' section is a query for which answers are present in the 607 // 'authority records' section of the same message. 608 bool IsProbeQuery() const; 609 610 size_t MaxWireSize() const; id()611 uint16_t id() const { return id_; } type()612 MessageType type() const { return type_; } is_truncated()613 bool is_truncated() const { return is_truncated_; } questions()614 const std::vector<MdnsQuestion>& questions() const { return questions_; } answers()615 const std::vector<MdnsRecord>& answers() const { return answers_; } authority_records()616 const std::vector<MdnsRecord>& authority_records() const { 617 return authority_records_; 618 } additional_records()619 const std::vector<MdnsRecord>& additional_records() const { 620 return additional_records_; 621 } 622 623 template <typename H> AbslHashValue(H h,const MdnsMessage & message)624 friend H AbslHashValue(H h, const MdnsMessage& message) { 625 return H::combine(std::move(h), message.id_, message.type_, 626 message.questions_, message.answers_, 627 message.authority_records_, message.additional_records_); 628 } 629 630 private: 631 // The mDNS header is 12 bytes long 632 size_t max_wire_size_ = sizeof(Header); 633 uint16_t id_ = 0; 634 bool is_truncated_ = false; 635 MessageType type_ = MessageType::Query; 636 std::vector<MdnsQuestion> questions_; 637 std::vector<MdnsRecord> answers_; 638 std::vector<MdnsRecord> authority_records_; 639 std::vector<MdnsRecord> additional_records_; 640 }; 641 642 uint16_t CreateMessageId(); 643 644 // Determines whether a record of the given type can be published. 645 bool CanBePublished(DnsType type); 646 647 // Determines whether a record of the given type can be queried for. 648 bool CanBeQueried(DnsType type); 649 650 // Determines whether a record of the given type received over the network 651 // should be processed. 652 bool CanBeProcessed(DnsType type); 653 654 } // namespace discovery 655 } // namespace openscreen 656 657 #endif // DISCOVERY_MDNS_MDNS_RECORDS_H_ 658