blob: 303c6bb34c96ba0b26e1872375884c3f629903b6 [file] [log] [blame]
Qingsi Wang558b93b2018-08-30 10:38:44 -07001/*
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
Qingsi Wang7852d292018-10-31 11:17:07 -070018// messages in MdnsMessage::Read(); however, the MdnsMessage::Write() does not
Qingsi Wang558b93b2018-08-30 10:38:44 -070019// 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
Yves Gerey3e707812018-11-28 16:47:49 +010024#include <stdint.h>
Qingsi Wang558b93b2018-08-30 10:38:44 -070025#include <string>
26#include <vector>
27
Steve Anton10542f22019-01-11 09:11:00 -080028#include "rtc_base/byte_buffer.h"
29#include "rtc_base/ip_address.h"
Qingsi Wang558b93b2018-08-30 10:38:44 -070030#include "rtc_base/message_buffer_reader.h"
31
32namespace webrtc {
33
34// We use "section entry" to denote either a question or a resource record.
35//
36// RFC 1035 Section 3.2.2.
37enum class SectionEntryType {
38 kA,
39 kAAAA,
40 // Only the above types are processed in the current implementation.
41 kUnsupported,
42};
43
44// RFC 1035 Section 3.2.4.
45enum class SectionEntryClass {
46 kIN,
47 kUnsupported,
48};
49
50// RFC 1035, Section 4.1.1.
Qingsi Wang7852d292018-10-31 11:17:07 -070051class MdnsHeader final {
Qingsi Wang558b93b2018-08-30 10:38:44 -070052 public:
53 bool Read(MessageBufferReader* buf);
54 void Write(rtc::ByteBufferWriter* buf) const;
55
56 void SetQueryOrResponse(bool is_query);
57 bool IsQuery() const;
58 void SetAuthoritative(bool is_authoritative);
59 bool IsAuthoritative() const;
60
61 uint16_t id = 0;
62 uint16_t flags = 0;
63 // Number of entries in the question section.
64 uint16_t qdcount = 0;
65 // Number of resource records in the answer section.
66 uint16_t ancount = 0;
67 // Number of name server resource records in the authority records section.
68 uint16_t nscount = 0;
69 // Number of resource records in the additional records section.
70 uint16_t arcount = 0;
71};
72
73// Entries in each section after the header share a common structure. Note that
74// this is not a concept defined in RFC 1035.
Qingsi Wang7852d292018-10-31 11:17:07 -070075class MdnsSectionEntry {
Qingsi Wang558b93b2018-08-30 10:38:44 -070076 public:
Qingsi Wang7852d292018-10-31 11:17:07 -070077 MdnsSectionEntry();
78 MdnsSectionEntry(const MdnsSectionEntry& other);
79 virtual ~MdnsSectionEntry();
Qingsi Wang558b93b2018-08-30 10:38:44 -070080 virtual bool Read(MessageBufferReader* buf) = 0;
81 virtual bool Write(rtc::ByteBufferWriter* buf) const = 0;
82
83 void SetName(const std::string& name) { name_ = name; }
84 // Returns the fully qualified domain name in the section entry, i.e., QNAME
85 // in a question or NAME in a resource record.
86 std::string GetName() const { return name_; }
87
88 void SetType(SectionEntryType type);
89 SectionEntryType GetType() const;
90 void SetClass(SectionEntryClass cls);
91 SectionEntryClass GetClass() const;
92
93 protected:
94 std::string name_; // Fully qualified domain name.
95 uint16_t type_ = 0;
96 uint16_t class_ = 0;
97};
98
99// RFC 1035, Section 4.1.2.
Qingsi Wang7852d292018-10-31 11:17:07 -0700100class MdnsQuestion final : public MdnsSectionEntry {
Qingsi Wang558b93b2018-08-30 10:38:44 -0700101 public:
Qingsi Wang7852d292018-10-31 11:17:07 -0700102 MdnsQuestion();
103 MdnsQuestion(const MdnsQuestion& other);
104 ~MdnsQuestion() override;
Qingsi Wang558b93b2018-08-30 10:38:44 -0700105
106 bool Read(MessageBufferReader* buf) override;
107 bool Write(rtc::ByteBufferWriter* buf) const override;
108
109 void SetUnicastResponse(bool should_unicast);
110 bool ShouldUnicastResponse() const;
111};
112
113// RFC 1035, Section 4.1.3.
Qingsi Wang7852d292018-10-31 11:17:07 -0700114class MdnsResourceRecord final : public MdnsSectionEntry {
Qingsi Wang558b93b2018-08-30 10:38:44 -0700115 public:
Qingsi Wang7852d292018-10-31 11:17:07 -0700116 MdnsResourceRecord();
117 MdnsResourceRecord(const MdnsResourceRecord& other);
118 ~MdnsResourceRecord() override;
Qingsi Wang558b93b2018-08-30 10:38:44 -0700119
120 bool Read(MessageBufferReader* buf) override;
121 bool Write(rtc::ByteBufferWriter* buf) const override;
122
123 void SetTtlSeconds(uint32_t ttl_seconds) { ttl_seconds_ = ttl_seconds; }
124 uint32_t GetTtlSeconds() const { return ttl_seconds_; }
125 // Returns true if |address| is in the address family AF_INET or AF_INET6 and
126 // |address| has a valid IPv4 or IPv6 address; false otherwise.
127 bool SetIPAddressInRecordData(const rtc::IPAddress& address);
128 // Returns true if the record is of type A or AAAA and the record has a valid
129 // IPv4 or IPv6 address; false otherwise. Stores the valid IP in |address|.
130 bool GetIPAddressFromRecordData(rtc::IPAddress* address) const;
131
132 private:
133 // The list of methods reading and writing rdata can grow as we support more
134 // types of rdata.
135 bool ReadARData(MessageBufferReader* buf);
136 void WriteARData(rtc::ByteBufferWriter* buf) const;
137
138 bool ReadQuadARData(MessageBufferReader* buf);
139 void WriteQuadARData(rtc::ByteBufferWriter* buf) const;
140
141 uint32_t ttl_seconds_ = 0;
142 uint16_t rdlength_ = 0;
143 std::string rdata_;
144};
145
Qingsi Wang7852d292018-10-31 11:17:07 -0700146class MdnsMessage final {
Qingsi Wang558b93b2018-08-30 10:38:44 -0700147 public:
148 // RFC 1035, Section 4.1.
149 enum class Section { kQuestion, kAnswer, kAuthority, kAdditional };
150
Qingsi Wang7852d292018-10-31 11:17:07 -0700151 MdnsMessage();
152 ~MdnsMessage();
Qingsi Wang558b93b2018-08-30 10:38:44 -0700153 // Reads the mDNS message in |buf| and populates the corresponding fields in
Qingsi Wang7852d292018-10-31 11:17:07 -0700154 // MdnsMessage.
Qingsi Wang558b93b2018-08-30 10:38:44 -0700155 bool Read(MessageBufferReader* buf);
Qingsi Wang7852d292018-10-31 11:17:07 -0700156 // Write an mDNS message to |buf| based on the fields in MdnsMessage.
Qingsi Wang558b93b2018-08-30 10:38:44 -0700157 //
158 // TODO(qingsi): Implement name compression when writing mDNS messages.
159 bool Write(rtc::ByteBufferWriter* buf) const;
160
161 void SetId(uint16_t id) { header_.id = id; }
162 uint16_t GetId() const { return header_.id; }
163
164 void SetQueryOrResponse(bool is_query) {
165 header_.SetQueryOrResponse(is_query);
166 }
167 bool IsQuery() const { return header_.IsQuery(); }
168
169 void SetAuthoritative(bool is_authoritative) {
170 header_.SetAuthoritative(is_authoritative);
171 }
172 bool IsAuthoritative() const { return header_.IsAuthoritative(); }
173
174 // Returns true if the message is a query and the unicast response is
175 // preferred. False otherwise.
176 bool ShouldUnicastResponse() const;
177
Qingsi Wang7852d292018-10-31 11:17:07 -0700178 void AddQuestion(const MdnsQuestion& question);
Qingsi Wang558b93b2018-08-30 10:38:44 -0700179 // TODO(qingsi): Implement AddXRecord for name server and additional records.
Qingsi Wang7852d292018-10-31 11:17:07 -0700180 void AddAnswerRecord(const MdnsResourceRecord& answer);
Qingsi Wang558b93b2018-08-30 10:38:44 -0700181
Qingsi Wang7852d292018-10-31 11:17:07 -0700182 const std::vector<MdnsQuestion>& question_section() const {
Qingsi Wang558b93b2018-08-30 10:38:44 -0700183 return question_section_;
184 }
Qingsi Wang7852d292018-10-31 11:17:07 -0700185 const std::vector<MdnsResourceRecord>& answer_section() const {
Qingsi Wang558b93b2018-08-30 10:38:44 -0700186 return answer_section_;
187 }
Qingsi Wang7852d292018-10-31 11:17:07 -0700188 const std::vector<MdnsResourceRecord>& authority_section() const {
Qingsi Wang558b93b2018-08-30 10:38:44 -0700189 return authority_section_;
190 }
Qingsi Wang7852d292018-10-31 11:17:07 -0700191 const std::vector<MdnsResourceRecord>& additional_section() const {
Qingsi Wang558b93b2018-08-30 10:38:44 -0700192 return additional_section_;
193 }
194
195 private:
Qingsi Wang7852d292018-10-31 11:17:07 -0700196 MdnsHeader header_;
197 std::vector<MdnsQuestion> question_section_;
198 std::vector<MdnsResourceRecord> answer_section_;
199 std::vector<MdnsResourceRecord> authority_section_;
200 std::vector<MdnsResourceRecord> additional_section_;
Qingsi Wang558b93b2018-08-30 10:38:44 -0700201};
202
203} // namespace webrtc
204
205#endif // P2P_BASE_MDNS_MESSAGE_H_