blob: f6dec20a956d53020748dfc9cb2b489fd4098207 [file] [log] [blame]
Qingsi Wang558b93b2018-08-30 17:38:441/*
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 <map>
25#include <memory>
26#include <set>
27#include <string>
28#include <vector>
29
30#include "rtc_base/bytebuffer.h"
31#include "rtc_base/ipaddress.h"
32#include "rtc_base/message_buffer_reader.h"
33
34namespace webrtc {
35
36// We use "section entry" to denote either a question or a resource record.
37//
38// RFC 1035 Section 3.2.2.
39enum class SectionEntryType {
40 kA,
41 kAAAA,
42 // Only the above types are processed in the current implementation.
43 kUnsupported,
44};
45
46// RFC 1035 Section 3.2.4.
47enum class SectionEntryClass {
48 kIN,
49 kUnsupported,
50};
51
52// RFC 1035, Section 4.1.1.
53class MDnsHeader final {
54 public:
55 bool Read(MessageBufferReader* buf);
56 void Write(rtc::ByteBufferWriter* buf) const;
57
58 void SetQueryOrResponse(bool is_query);
59 bool IsQuery() const;
60 void SetAuthoritative(bool is_authoritative);
61 bool IsAuthoritative() const;
62
63 uint16_t id = 0;
64 uint16_t flags = 0;
65 // Number of entries in the question section.
66 uint16_t qdcount = 0;
67 // Number of resource records in the answer section.
68 uint16_t ancount = 0;
69 // Number of name server resource records in the authority records section.
70 uint16_t nscount = 0;
71 // Number of resource records in the additional records section.
72 uint16_t arcount = 0;
73};
74
75// Entries in each section after the header share a common structure. Note that
76// this is not a concept defined in RFC 1035.
77class MDnsSectionEntry {
78 public:
79 MDnsSectionEntry();
80 MDnsSectionEntry(const MDnsSectionEntry& other);
81 virtual ~MDnsSectionEntry();
82 virtual bool Read(MessageBufferReader* buf) = 0;
83 virtual bool Write(rtc::ByteBufferWriter* buf) const = 0;
84
85 void SetName(const std::string& name) { name_ = name; }
86 // Returns the fully qualified domain name in the section entry, i.e., QNAME
87 // in a question or NAME in a resource record.
88 std::string GetName() const { return name_; }
89
90 void SetType(SectionEntryType type);
91 SectionEntryType GetType() const;
92 void SetClass(SectionEntryClass cls);
93 SectionEntryClass GetClass() const;
94
95 protected:
96 std::string name_; // Fully qualified domain name.
97 uint16_t type_ = 0;
98 uint16_t class_ = 0;
99};
100
101// RFC 1035, Section 4.1.2.
102class MDnsQuestion final : public MDnsSectionEntry {
103 public:
104 MDnsQuestion();
105 MDnsQuestion(const MDnsQuestion& other);
106 ~MDnsQuestion() override;
107
108 bool Read(MessageBufferReader* buf) override;
109 bool Write(rtc::ByteBufferWriter* buf) const override;
110
111 void SetUnicastResponse(bool should_unicast);
112 bool ShouldUnicastResponse() const;
113};
114
115// RFC 1035, Section 4.1.3.
116class MDnsResourceRecord final : public MDnsSectionEntry {
117 public:
118 MDnsResourceRecord();
119 MDnsResourceRecord(const MDnsResourceRecord& other);
120 ~MDnsResourceRecord() override;
121
122 bool Read(MessageBufferReader* buf) override;
123 bool Write(rtc::ByteBufferWriter* buf) const override;
124
125 void SetTtlSeconds(uint32_t ttl_seconds) { ttl_seconds_ = ttl_seconds; }
126 uint32_t GetTtlSeconds() const { return ttl_seconds_; }
127 // Returns true if |address| is in the address family AF_INET or AF_INET6 and
128 // |address| has a valid IPv4 or IPv6 address; false otherwise.
129 bool SetIPAddressInRecordData(const rtc::IPAddress& address);
130 // Returns true if the record is of type A or AAAA and the record has a valid
131 // IPv4 or IPv6 address; false otherwise. Stores the valid IP in |address|.
132 bool GetIPAddressFromRecordData(rtc::IPAddress* address) const;
133
134 private:
135 // The list of methods reading and writing rdata can grow as we support more
136 // types of rdata.
137 bool ReadARData(MessageBufferReader* buf);
138 void WriteARData(rtc::ByteBufferWriter* buf) const;
139
140 bool ReadQuadARData(MessageBufferReader* buf);
141 void WriteQuadARData(rtc::ByteBufferWriter* buf) const;
142
143 uint32_t ttl_seconds_ = 0;
144 uint16_t rdlength_ = 0;
145 std::string rdata_;
146};
147
148class MDnsMessage final {
149 public:
150 // RFC 1035, Section 4.1.
151 enum class Section { kQuestion, kAnswer, kAuthority, kAdditional };
152
153 MDnsMessage();
154 ~MDnsMessage();
155 // Reads the mDNS message in |buf| and populates the corresponding fields in
156 // MDnsMessage.
157 bool Read(MessageBufferReader* buf);
158 // Write an mDNS message to |buf| based on the fields in MDnsMessage.
159 //
160 // TODO(qingsi): Implement name compression when writing mDNS messages.
161 bool Write(rtc::ByteBufferWriter* buf) const;
162
163 void SetId(uint16_t id) { header_.id = id; }
164 uint16_t GetId() const { return header_.id; }
165
166 void SetQueryOrResponse(bool is_query) {
167 header_.SetQueryOrResponse(is_query);
168 }
169 bool IsQuery() const { return header_.IsQuery(); }
170
171 void SetAuthoritative(bool is_authoritative) {
172 header_.SetAuthoritative(is_authoritative);
173 }
174 bool IsAuthoritative() const { return header_.IsAuthoritative(); }
175
176 // Returns true if the message is a query and the unicast response is
177 // preferred. False otherwise.
178 bool ShouldUnicastResponse() const;
179
180 void AddQuestion(const MDnsQuestion& question);
181 // TODO(qingsi): Implement AddXRecord for name server and additional records.
182 void AddAnswerRecord(const MDnsResourceRecord& answer);
183
184 const std::vector<MDnsQuestion>& question_section() const {
185 return question_section_;
186 }
187 const std::vector<MDnsResourceRecord>& answer_section() const {
188 return answer_section_;
189 }
190 const std::vector<MDnsResourceRecord>& authority_section() const {
191 return authority_section_;
192 }
193 const std::vector<MDnsResourceRecord>& additional_section() const {
194 return additional_section_;
195 }
196
197 private:
198 MDnsHeader header_;
199 std::vector<MDnsQuestion> question_section_;
200 std::vector<MDnsResourceRecord> answer_section_;
201 std::vector<MDnsResourceRecord> authority_section_;
202 std::vector<MDnsResourceRecord> additional_section_;
203};
204
205} // namespace webrtc
206
207#endif // P2P_BASE_MDNS_MESSAGE_H_