207 lines
6.6 KiB
C
207 lines
6.6 KiB
C
|
/*
|
||
|
* 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 <stdint.h>
|
||
|
|
||
|
#include <string>
|
||
|
#include <vector>
|
||
|
|
||
|
#include "rtc_base/byte_buffer.h"
|
||
|
#include "rtc_base/ip_address.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_
|