blob: 7aa1b21039a530f11f8c8f8551c9b50cad3ddc52 [file] [log] [blame]
/*
* Copyright 2018 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef P2P_BASE_MDNS_MESSAGE_H_
#define P2P_BASE_MDNS_MESSAGE_H_
// This file contains classes to read and write mDNSs message defined in RFC
// 6762 and RFC 1025 (DNS messages). Note that it is recommended by RFC 6762 to
// use the name compression scheme defined in RFC 1035 whenever possible. We
// currently only implement the capability of reading compressed names in mDNS
// messages in MdnsMessage::Read(); however, the MdnsMessage::Write() does not
// support name compression yet.
//
// Fuzzer tests (test/fuzzers/mdns_parser_fuzzer.cc) MUST always be performed
// after changes made to this file.
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "rtc_base/bytebuffer.h"
#include "rtc_base/ipaddress.h"
#include "rtc_base/message_buffer_reader.h"
namespace webrtc {
// We use "section entry" to denote either a question or a resource record.
//
// RFC 1035 Section 3.2.2.
enum class SectionEntryType {
kA,
kAAAA,
// Only the above types are processed in the current implementation.
kUnsupported,
};
// RFC 1035 Section 3.2.4.
enum class SectionEntryClass {
kIN,
kUnsupported,
};
// RFC 1035, Section 4.1.1.
class MdnsHeader final {
public:
bool Read(MessageBufferReader* buf);
void Write(rtc::ByteBufferWriter* buf) const;
void SetQueryOrResponse(bool is_query);
bool IsQuery() const;
void SetAuthoritative(bool is_authoritative);
bool IsAuthoritative() const;
uint16_t id = 0;
uint16_t flags = 0;
// Number of entries in the question section.
uint16_t qdcount = 0;
// Number of resource records in the answer section.
uint16_t ancount = 0;
// Number of name server resource records in the authority records section.
uint16_t nscount = 0;
// Number of resource records in the additional records section.
uint16_t arcount = 0;
};
// Entries in each section after the header share a common structure. Note that
// this is not a concept defined in RFC 1035.
class MdnsSectionEntry {
public:
MdnsSectionEntry();
MdnsSectionEntry(const MdnsSectionEntry& other);
virtual ~MdnsSectionEntry();
virtual bool Read(MessageBufferReader* buf) = 0;
virtual bool Write(rtc::ByteBufferWriter* buf) const = 0;
void SetName(const std::string& name) { name_ = name; }
// Returns the fully qualified domain name in the section entry, i.e., QNAME
// in a question or NAME in a resource record.
std::string GetName() const { return name_; }
void SetType(SectionEntryType type);
SectionEntryType GetType() const;
void SetClass(SectionEntryClass cls);
SectionEntryClass GetClass() const;
protected:
std::string name_; // Fully qualified domain name.
uint16_t type_ = 0;
uint16_t class_ = 0;
};
// RFC 1035, Section 4.1.2.
class MdnsQuestion final : public MdnsSectionEntry {
public:
MdnsQuestion();
MdnsQuestion(const MdnsQuestion& other);
~MdnsQuestion() override;
bool Read(MessageBufferReader* buf) override;
bool Write(rtc::ByteBufferWriter* buf) const override;
void SetUnicastResponse(bool should_unicast);
bool ShouldUnicastResponse() const;
};
// RFC 1035, Section 4.1.3.
class MdnsResourceRecord final : public MdnsSectionEntry {
public:
MdnsResourceRecord();
MdnsResourceRecord(const MdnsResourceRecord& other);
~MdnsResourceRecord() override;
bool Read(MessageBufferReader* buf) override;
bool Write(rtc::ByteBufferWriter* buf) const override;
void SetTtlSeconds(uint32_t ttl_seconds) { ttl_seconds_ = ttl_seconds; }
uint32_t GetTtlSeconds() const { return ttl_seconds_; }
// Returns true if |address| is in the address family AF_INET or AF_INET6 and
// |address| has a valid IPv4 or IPv6 address; false otherwise.
bool SetIPAddressInRecordData(const rtc::IPAddress& address);
// Returns true if the record is of type A or AAAA and the record has a valid
// IPv4 or IPv6 address; false otherwise. Stores the valid IP in |address|.
bool GetIPAddressFromRecordData(rtc::IPAddress* address) const;
private:
// The list of methods reading and writing rdata can grow as we support more
// types of rdata.
bool ReadARData(MessageBufferReader* buf);
void WriteARData(rtc::ByteBufferWriter* buf) const;
bool ReadQuadARData(MessageBufferReader* buf);
void WriteQuadARData(rtc::ByteBufferWriter* buf) const;
uint32_t ttl_seconds_ = 0;
uint16_t rdlength_ = 0;
std::string rdata_;
};
class MdnsMessage final {
public:
// RFC 1035, Section 4.1.
enum class Section { kQuestion, kAnswer, kAuthority, kAdditional };
MdnsMessage();
~MdnsMessage();
// Reads the mDNS message in |buf| and populates the corresponding fields in
// MdnsMessage.
bool Read(MessageBufferReader* buf);
// Write an mDNS message to |buf| based on the fields in MdnsMessage.
//
// TODO(qingsi): Implement name compression when writing mDNS messages.
bool Write(rtc::ByteBufferWriter* buf) const;
void SetId(uint16_t id) { header_.id = id; }
uint16_t GetId() const { return header_.id; }
void SetQueryOrResponse(bool is_query) {
header_.SetQueryOrResponse(is_query);
}
bool IsQuery() const { return header_.IsQuery(); }
void SetAuthoritative(bool is_authoritative) {
header_.SetAuthoritative(is_authoritative);
}
bool IsAuthoritative() const { return header_.IsAuthoritative(); }
// Returns true if the message is a query and the unicast response is
// preferred. False otherwise.
bool ShouldUnicastResponse() const;
void AddQuestion(const MdnsQuestion& question);
// TODO(qingsi): Implement AddXRecord for name server and additional records.
void AddAnswerRecord(const MdnsResourceRecord& answer);
const std::vector<MdnsQuestion>& question_section() const {
return question_section_;
}
const std::vector<MdnsResourceRecord>& answer_section() const {
return answer_section_;
}
const std::vector<MdnsResourceRecord>& authority_section() const {
return authority_section_;
}
const std::vector<MdnsResourceRecord>& additional_section() const {
return additional_section_;
}
private:
MdnsHeader header_;
std::vector<MdnsQuestion> question_section_;
std::vector<MdnsResourceRecord> answer_section_;
std::vector<MdnsResourceRecord> authority_section_;
std::vector<MdnsResourceRecord> additional_section_;
};
} // namespace webrtc
#endif // P2P_BASE_MDNS_MESSAGE_H_