dns_query.cc 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "net/dns/dns_query.h"
  5. #include <utility>
  6. #include "base/big_endian.h"
  7. #include "base/logging.h"
  8. #include "base/memory/ptr_util.h"
  9. #include "base/numerics/safe_conversions.h"
  10. #include "base/sys_byteorder.h"
  11. #include "net/base/io_buffer.h"
  12. #include "net/dns/dns_util.h"
  13. #include "net/dns/opt_record_rdata.h"
  14. #include "net/dns/public/dns_protocol.h"
  15. #include "net/dns/record_rdata.h"
  16. #include "third_party/abseil-cpp/absl/types/optional.h"
  17. namespace net {
  18. namespace {
  19. const size_t kHeaderSize = sizeof(dns_protocol::Header);
  20. // Size of the fixed part of an OPT RR:
  21. // https://tools.ietf.org/html/rfc6891#section-6.1.2
  22. static const size_t kOptRRFixedSize = 11;
  23. // https://tools.ietf.org/html/rfc6891#section-6.2.5
  24. // TODO(robpercival): Determine a good value for this programmatically.
  25. const uint16_t kMaxUdpPayloadSize = 4096;
  26. size_t QuestionSize(size_t qname_size) {
  27. // QNAME + QTYPE + QCLASS
  28. return qname_size + sizeof(uint16_t) + sizeof(uint16_t);
  29. }
  30. // Buffer size of Opt record for |rdata| (does not include Opt record or RData
  31. // added for padding).
  32. size_t OptRecordSize(const OptRecordRdata* rdata) {
  33. return rdata == nullptr ? 0 : kOptRRFixedSize + rdata->buf().size();
  34. }
  35. // Padding size includes Opt header for the padding. Does not include OptRecord
  36. // header (kOptRRFixedSize) even when added just for padding.
  37. size_t DeterminePaddingSize(size_t unpadded_size,
  38. DnsQuery::PaddingStrategy padding_strategy) {
  39. switch (padding_strategy) {
  40. case DnsQuery::PaddingStrategy::NONE:
  41. return 0;
  42. case DnsQuery::PaddingStrategy::BLOCK_LENGTH_128:
  43. size_t padding_size = OptRecordRdata::Opt::kHeaderSize;
  44. size_t remainder = (padding_size + unpadded_size) % 128;
  45. padding_size += (128 - remainder) % 128;
  46. DCHECK_EQ((unpadded_size + padding_size) % 128, 0u);
  47. return padding_size;
  48. }
  49. }
  50. std::unique_ptr<OptRecordRdata> AddPaddingIfNecessary(
  51. const OptRecordRdata* opt_rdata,
  52. DnsQuery::PaddingStrategy padding_strategy,
  53. size_t no_opt_buffer_size) {
  54. // If no input OPT record rdata and no padding, no OPT record rdata needed.
  55. if (!opt_rdata && padding_strategy == DnsQuery::PaddingStrategy::NONE)
  56. return nullptr;
  57. std::unique_ptr<OptRecordRdata> merged_opt_rdata;
  58. if (opt_rdata) {
  59. merged_opt_rdata = OptRecordRdata::Create(
  60. base::StringPiece(opt_rdata->buf().data(), opt_rdata->buf().size()));
  61. } else {
  62. merged_opt_rdata = std::make_unique<OptRecordRdata>();
  63. }
  64. DCHECK(merged_opt_rdata);
  65. size_t unpadded_size =
  66. no_opt_buffer_size + OptRecordSize(merged_opt_rdata.get());
  67. size_t padding_size = DeterminePaddingSize(unpadded_size, padding_strategy);
  68. if (padding_size > 0) {
  69. // |opt_rdata| must not already contain padding if DnsQuery is to add
  70. // padding.
  71. DCHECK(!merged_opt_rdata->ContainsOptCode(dns_protocol::kEdnsPadding));
  72. // OPT header is the minimum amount of padding.
  73. DCHECK(padding_size >= OptRecordRdata::Opt::kHeaderSize);
  74. merged_opt_rdata->AddOpt(std::make_unique<OptRecordRdata::PaddingOpt>(
  75. padding_size - OptRecordRdata::Opt::kHeaderSize));
  76. }
  77. return merged_opt_rdata;
  78. }
  79. } // namespace
  80. // DNS query consists of a 12-byte header followed by a question section.
  81. // For details, see RFC 1035 section 4.1.1. This header template sets RD
  82. // bit, which directs the name server to pursue query recursively, and sets
  83. // the QDCOUNT to 1, meaning the question section has a single entry.
  84. DnsQuery::DnsQuery(uint16_t id,
  85. const base::StringPiece& qname,
  86. uint16_t qtype,
  87. const OptRecordRdata* opt_rdata,
  88. PaddingStrategy padding_strategy)
  89. : qname_size_(qname.size()) {
  90. #if DCHECK_IS_ON()
  91. absl::optional<std::string> dotted_name = DnsDomainToString(qname);
  92. DCHECK(dotted_name && !dotted_name.value().empty());
  93. #endif // DCHECK_IS_ON()
  94. size_t buffer_size = kHeaderSize + QuestionSize(qname_size_);
  95. std::unique_ptr<OptRecordRdata> merged_opt_rdata =
  96. AddPaddingIfNecessary(opt_rdata, padding_strategy, buffer_size);
  97. if (merged_opt_rdata)
  98. buffer_size += OptRecordSize(merged_opt_rdata.get());
  99. io_buffer_ = base::MakeRefCounted<IOBufferWithSize>(buffer_size);
  100. header_ = reinterpret_cast<dns_protocol::Header*>(io_buffer_->data());
  101. *header_ = {};
  102. header_->id = base::HostToNet16(id);
  103. header_->flags = base::HostToNet16(dns_protocol::kFlagRD);
  104. header_->qdcount = base::HostToNet16(1);
  105. // Write question section after the header.
  106. base::BigEndianWriter writer(io_buffer_->data() + kHeaderSize,
  107. io_buffer_->size() - kHeaderSize);
  108. writer.WriteBytes(qname.data(), qname.size());
  109. writer.WriteU16(qtype);
  110. writer.WriteU16(dns_protocol::kClassIN);
  111. if (merged_opt_rdata) {
  112. DCHECK_NE(merged_opt_rdata->OptCount(), 0u);
  113. header_->arcount = base::HostToNet16(1);
  114. // Write OPT pseudo-resource record.
  115. writer.WriteU8(0); // empty domain name (root domain)
  116. writer.WriteU16(OptRecordRdata::kType); // type
  117. writer.WriteU16(kMaxUdpPayloadSize); // class
  118. // ttl (next 3 fields)
  119. writer.WriteU8(0); // rcode does not apply to requests
  120. writer.WriteU8(0); // version
  121. // TODO(robpercival): Set "DNSSEC OK" flag if/when DNSSEC is supported:
  122. // https://tools.ietf.org/html/rfc3225#section-3
  123. writer.WriteU16(0); // flags
  124. // rdata
  125. writer.WriteU16(merged_opt_rdata->buf().size()); // rdata length
  126. writer.WriteBytes(merged_opt_rdata->buf().data(),
  127. merged_opt_rdata->buf().size());
  128. }
  129. }
  130. DnsQuery::DnsQuery(scoped_refptr<IOBufferWithSize> buffer)
  131. : io_buffer_(std::move(buffer)) {}
  132. DnsQuery::DnsQuery(const DnsQuery& query) {
  133. CopyFrom(query);
  134. }
  135. DnsQuery& DnsQuery::operator=(const DnsQuery& query) {
  136. CopyFrom(query);
  137. return *this;
  138. }
  139. DnsQuery::~DnsQuery() = default;
  140. std::unique_ptr<DnsQuery> DnsQuery::CloneWithNewId(uint16_t id) const {
  141. return base::WrapUnique(new DnsQuery(*this, id));
  142. }
  143. bool DnsQuery::Parse(size_t valid_bytes) {
  144. if (io_buffer_ == nullptr || io_buffer_->data() == nullptr) {
  145. return false;
  146. }
  147. CHECK(valid_bytes <= base::checked_cast<size_t>(io_buffer_->size()));
  148. // We should only parse the query once if the query is constructed from a raw
  149. // buffer. If we have constructed the query from data or the query is already
  150. // parsed after constructed from a raw buffer, |header_| is not null.
  151. DCHECK(header_ == nullptr);
  152. base::BigEndianReader reader(
  153. reinterpret_cast<const uint8_t*>(io_buffer_->data()), valid_bytes);
  154. dns_protocol::Header header;
  155. if (!ReadHeader(&reader, &header)) {
  156. return false;
  157. }
  158. if (header.flags & dns_protocol::kFlagResponse) {
  159. return false;
  160. }
  161. if (header.qdcount != 1) {
  162. VLOG(1) << "Not supporting parsing a DNS query with multiple (or zero) "
  163. "questions.";
  164. return false;
  165. }
  166. std::string qname;
  167. if (!ReadName(&reader, &qname)) {
  168. return false;
  169. }
  170. uint16_t qtype;
  171. uint16_t qclass;
  172. if (!reader.ReadU16(&qtype) || !reader.ReadU16(&qclass) ||
  173. qclass != dns_protocol::kClassIN) {
  174. return false;
  175. }
  176. // |io_buffer_| now contains the raw packet of a valid DNS query, we just
  177. // need to properly initialize |qname_size_| and |header_|.
  178. qname_size_ = qname.size();
  179. header_ = reinterpret_cast<dns_protocol::Header*>(io_buffer_->data());
  180. return true;
  181. }
  182. uint16_t DnsQuery::id() const {
  183. return base::NetToHost16(header_->id);
  184. }
  185. base::StringPiece DnsQuery::qname() const {
  186. return base::StringPiece(io_buffer_->data() + kHeaderSize, qname_size_);
  187. }
  188. uint16_t DnsQuery::qtype() const {
  189. uint16_t type;
  190. base::ReadBigEndian(reinterpret_cast<const uint8_t*>(
  191. io_buffer_->data() + kHeaderSize + qname_size_),
  192. &type);
  193. return type;
  194. }
  195. base::StringPiece DnsQuery::question() const {
  196. return base::StringPiece(io_buffer_->data() + kHeaderSize,
  197. QuestionSize(qname_size_));
  198. }
  199. size_t DnsQuery::question_size() const {
  200. return QuestionSize(qname_size_);
  201. }
  202. void DnsQuery::set_flags(uint16_t flags) {
  203. header_->flags = flags;
  204. }
  205. DnsQuery::DnsQuery(const DnsQuery& orig, uint16_t id) {
  206. CopyFrom(orig);
  207. header_->id = base::HostToNet16(id);
  208. }
  209. void DnsQuery::CopyFrom(const DnsQuery& orig) {
  210. qname_size_ = orig.qname_size_;
  211. io_buffer_ = base::MakeRefCounted<IOBufferWithSize>(orig.io_buffer()->size());
  212. memcpy(io_buffer_.get()->data(), orig.io_buffer()->data(),
  213. io_buffer_.get()->size());
  214. header_ = reinterpret_cast<dns_protocol::Header*>(io_buffer_->data());
  215. }
  216. bool DnsQuery::ReadHeader(base::BigEndianReader* reader,
  217. dns_protocol::Header* header) {
  218. return (
  219. reader->ReadU16(&header->id) && reader->ReadU16(&header->flags) &&
  220. reader->ReadU16(&header->qdcount) && reader->ReadU16(&header->ancount) &&
  221. reader->ReadU16(&header->nscount) && reader->ReadU16(&header->arcount));
  222. }
  223. bool DnsQuery::ReadName(base::BigEndianReader* reader, std::string* out) {
  224. DCHECK(out != nullptr);
  225. out->clear();
  226. out->reserve(dns_protocol::kMaxNameLength + 1);
  227. uint8_t label_length;
  228. if (!reader->ReadU8(&label_length)) {
  229. return false;
  230. }
  231. while (label_length) {
  232. if (out->size() + 1 + label_length > dns_protocol::kMaxNameLength) {
  233. return false;
  234. }
  235. out->append(reinterpret_cast<char*>(&label_length), 1);
  236. base::StringPiece label;
  237. if (!reader->ReadPiece(&label, label_length)) {
  238. return false;
  239. }
  240. out->append(label.data(), label.size());
  241. if (!reader->ReadU8(&label_length)) {
  242. return false;
  243. }
  244. }
  245. DCHECK_LE(out->size(), static_cast<size_t>(dns_protocol::kMaxNameLength));
  246. out->append(1, '\0');
  247. return true;
  248. }
  249. } // namespace net