1 /*
2  *  Copyright 2018 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #ifndef P2P_BASE_MDNS_MESSAGE_H_
12 #define P2P_BASE_MDNS_MESSAGE_H_
13 
14 // This file contains classes to read and write mDNSs message defined in RFC
15 // 6762 and RFC 1025 (DNS messages). Note that it is recommended by RFC 6762 to
16 // use the name compression scheme defined in RFC 1035 whenever possible. We
17 // currently only implement the capability of reading compressed names in mDNS
18 // messages in MdnsMessage::Read(); however, the MdnsMessage::Write() does not
19 // support name compression yet.
20 //
21 // Fuzzer tests (test/fuzzers/mdns_parser_fuzzer.cc) MUST always be performed
22 // after changes made to this file.
23 
24 #include <stdint.h>
25 
26 #include <string>
27 #include <vector>
28 
29 #include "rtc_base/byte_buffer.h"
30 #include "rtc_base/ip_address.h"
31 #include "rtc_base/message_buffer_reader.h"
32 
33 namespace webrtc {
34 
35 // We use "section entry" to denote either a question or a resource record.
36 //
37 // RFC 1035 Section 3.2.2.
38 enum class SectionEntryType {
39   kA,
40   kAAAA,
41   // Only the above types are processed in the current implementation.
42   kUnsupported,
43 };
44 
45 // RFC 1035 Section 3.2.4.
46 enum class SectionEntryClass {
47   kIN,
48   kUnsupported,
49 };
50 
51 // RFC 1035, Section 4.1.1.
52 class MdnsHeader final {
53  public:
54   bool Read(MessageBufferReader* buf);
55   void Write(rtc::ByteBufferWriter* buf) const;
56 
57   void SetQueryOrResponse(bool is_query);
58   bool IsQuery() const;
59   void SetAuthoritative(bool is_authoritative);
60   bool IsAuthoritative() const;
61 
62   uint16_t id = 0;
63   uint16_t flags = 0;
64   // Number of entries in the question section.
65   uint16_t qdcount = 0;
66   // Number of resource records in the answer section.
67   uint16_t ancount = 0;
68   // Number of name server resource records in the authority records section.
69   uint16_t nscount = 0;
70   // Number of resource records in the additional records section.
71   uint16_t arcount = 0;
72 };
73 
74 // Entries in each section after the header share a common structure. Note that
75 // this is not a concept defined in RFC 1035.
76 class MdnsSectionEntry {
77  public:
78   MdnsSectionEntry();
79   MdnsSectionEntry(const MdnsSectionEntry& other);
80   virtual ~MdnsSectionEntry();
81   virtual bool Read(MessageBufferReader* buf) = 0;
82   virtual bool Write(rtc::ByteBufferWriter* buf) const = 0;
83 
SetName(const std::string & name)84   void SetName(const std::string& name) { name_ = name; }
85   // Returns the fully qualified domain name in the section entry, i.e., QNAME
86   // in a question or NAME in a resource record.
GetName()87   std::string GetName() const { return name_; }
88 
89   void SetType(SectionEntryType type);
90   SectionEntryType GetType() const;
91   void SetClass(SectionEntryClass cls);
92   SectionEntryClass GetClass() const;
93 
94  protected:
95   std::string name_;  // Fully qualified domain name.
96   uint16_t type_ = 0;
97   uint16_t class_ = 0;
98 };
99 
100 // RFC 1035, Section 4.1.2.
101 class MdnsQuestion final : public MdnsSectionEntry {
102  public:
103   MdnsQuestion();
104   MdnsQuestion(const MdnsQuestion& other);
105   ~MdnsQuestion() override;
106 
107   bool Read(MessageBufferReader* buf) override;
108   bool Write(rtc::ByteBufferWriter* buf) const override;
109 
110   void SetUnicastResponse(bool should_unicast);
111   bool ShouldUnicastResponse() const;
112 };
113 
114 // RFC 1035, Section 4.1.3.
115 class MdnsResourceRecord final : public MdnsSectionEntry {
116  public:
117   MdnsResourceRecord();
118   MdnsResourceRecord(const MdnsResourceRecord& other);
119   ~MdnsResourceRecord() override;
120 
121   bool Read(MessageBufferReader* buf) override;
122   bool Write(rtc::ByteBufferWriter* buf) const override;
123 
SetTtlSeconds(uint32_t ttl_seconds)124   void SetTtlSeconds(uint32_t ttl_seconds) { ttl_seconds_ = ttl_seconds; }
GetTtlSeconds()125   uint32_t GetTtlSeconds() const { return ttl_seconds_; }
126   // Returns true if |address| is in the address family AF_INET or AF_INET6 and
127   // |address| has a valid IPv4 or IPv6 address; false otherwise.
128   bool SetIPAddressInRecordData(const rtc::IPAddress& address);
129   // Returns true if the record is of type A or AAAA and the record has a valid
130   // IPv4 or IPv6 address; false otherwise. Stores the valid IP in |address|.
131   bool GetIPAddressFromRecordData(rtc::IPAddress* address) const;
132 
133  private:
134   // The list of methods reading and writing rdata can grow as we support more
135   // types of rdata.
136   bool ReadARData(MessageBufferReader* buf);
137   void WriteARData(rtc::ByteBufferWriter* buf) const;
138 
139   bool ReadQuadARData(MessageBufferReader* buf);
140   void WriteQuadARData(rtc::ByteBufferWriter* buf) const;
141 
142   uint32_t ttl_seconds_ = 0;
143   uint16_t rdlength_ = 0;
144   std::string rdata_;
145 };
146 
147 class MdnsMessage final {
148  public:
149   // RFC 1035, Section 4.1.
150   enum class Section { kQuestion, kAnswer, kAuthority, kAdditional };
151 
152   MdnsMessage();
153   ~MdnsMessage();
154   // Reads the mDNS message in |buf| and populates the corresponding fields in
155   // MdnsMessage.
156   bool Read(MessageBufferReader* buf);
157   // Write an mDNS message to |buf| based on the fields in MdnsMessage.
158   //
159   // TODO(qingsi): Implement name compression when writing mDNS messages.
160   bool Write(rtc::ByteBufferWriter* buf) const;
161 
SetId(uint16_t id)162   void SetId(uint16_t id) { header_.id = id; }
GetId()163   uint16_t GetId() const { return header_.id; }
164 
SetQueryOrResponse(bool is_query)165   void SetQueryOrResponse(bool is_query) {
166     header_.SetQueryOrResponse(is_query);
167   }
IsQuery()168   bool IsQuery() const { return header_.IsQuery(); }
169 
SetAuthoritative(bool is_authoritative)170   void SetAuthoritative(bool is_authoritative) {
171     header_.SetAuthoritative(is_authoritative);
172   }
IsAuthoritative()173   bool IsAuthoritative() const { return header_.IsAuthoritative(); }
174 
175   // Returns true if the message is a query and the unicast response is
176   // preferred. False otherwise.
177   bool ShouldUnicastResponse() const;
178 
179   void AddQuestion(const MdnsQuestion& question);
180   // TODO(qingsi): Implement AddXRecord for name server and additional records.
181   void AddAnswerRecord(const MdnsResourceRecord& answer);
182 
question_section()183   const std::vector<MdnsQuestion>& question_section() const {
184     return question_section_;
185   }
answer_section()186   const std::vector<MdnsResourceRecord>& answer_section() const {
187     return answer_section_;
188   }
authority_section()189   const std::vector<MdnsResourceRecord>& authority_section() const {
190     return authority_section_;
191   }
additional_section()192   const std::vector<MdnsResourceRecord>& additional_section() const {
193     return additional_section_;
194   }
195 
196  private:
197   MdnsHeader header_;
198   std::vector<MdnsQuestion> question_section_;
199   std::vector<MdnsResourceRecord> answer_section_;
200   std::vector<MdnsResourceRecord> authority_section_;
201   std::vector<MdnsResourceRecord> additional_section_;
202 };
203 
204 }  // namespace webrtc
205 
206 #endif  // P2P_BASE_MDNS_MESSAGE_H_
207