arc: Move platform2/arc/network/ to platform2/patchpanel
Next step in the arc-networkd -> patchpanel rename, this patch moves the
location of the code.
BUG=b:151879931
TEST=units,flashed image to atlas
TEST=tasts arc.PlayStore, crostini.LaunchTerminal.download
Change-Id: I1b5cf8d670e1631d46f6449b725395157bf88dde
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2115863
Tested-by: Garrick Evans <garrick@chromium.org>
Commit-Queue: Garrick Evans <garrick@chromium.org>
Reviewed-by: Hidehiko Abe <hidehiko@chromium.org>
Reviewed-by: Eric Caruso <ejcaruso@chromium.org>
Reviewed-by: Chirantan Ekbote <chirantan@chromium.org>
Reviewed-by: Hugo Benichi <hugobenichi@google.com>
diff --git a/patchpanel/dns/big_endian.cc b/patchpanel/dns/big_endian.cc
new file mode 100644
index 0000000..88cb363
--- /dev/null
+++ b/patchpanel/dns/big_endian.cc
@@ -0,0 +1,105 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "patchpanel/dns/big_endian.h"
+
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+BigEndianReader::BigEndianReader(const char* buf, size_t len)
+ : ptr_(buf), end_(ptr_ + len) {}
+
+bool BigEndianReader::Skip(size_t len) {
+ if (ptr_ + len > end_)
+ return false;
+ ptr_ += len;
+ return true;
+}
+
+bool BigEndianReader::ReadBytes(void* out, size_t len) {
+ if (ptr_ + len > end_)
+ return false;
+ memcpy(out, ptr_, len);
+ ptr_ += len;
+ return true;
+}
+
+bool BigEndianReader::ReadPiece(base::StringPiece* out, size_t len) {
+ if (ptr_ + len > end_)
+ return false;
+ *out = base::StringPiece(ptr_, len);
+ ptr_ += len;
+ return true;
+}
+
+template <typename T>
+bool BigEndianReader::Read(T* value) {
+ if (ptr_ + sizeof(T) > end_)
+ return false;
+ ReadBigEndian<T>(ptr_, value);
+ ptr_ += sizeof(T);
+ return true;
+}
+
+bool BigEndianReader::ReadU8(uint8_t* value) {
+ return Read(value);
+}
+
+bool BigEndianReader::ReadU16(uint16_t* value) {
+ return Read(value);
+}
+
+bool BigEndianReader::ReadU32(uint32_t* value) {
+ return Read(value);
+}
+
+bool BigEndianReader::ReadU64(uint64_t* value) {
+ return Read(value);
+}
+
+BigEndianWriter::BigEndianWriter(char* buf, size_t len)
+ : ptr_(buf), end_(ptr_ + len) {}
+
+bool BigEndianWriter::Skip(size_t len) {
+ if (ptr_ + len > end_)
+ return false;
+ ptr_ += len;
+ return true;
+}
+
+bool BigEndianWriter::WriteBytes(const void* buf, size_t len) {
+ if (ptr_ + len > end_)
+ return false;
+ memcpy(ptr_, buf, len);
+ ptr_ += len;
+ return true;
+}
+
+template <typename T>
+bool BigEndianWriter::Write(T value) {
+ if (ptr_ + sizeof(T) > end_)
+ return false;
+ WriteBigEndian<T>(ptr_, value);
+ ptr_ += sizeof(T);
+ return true;
+}
+
+bool BigEndianWriter::WriteU8(uint8_t value) {
+ return Write(value);
+}
+
+bool BigEndianWriter::WriteU16(uint16_t value) {
+ return Write(value);
+}
+
+bool BigEndianWriter::WriteU32(uint32_t value) {
+ return Write(value);
+}
+
+bool BigEndianWriter::WriteU64(uint64_t value) {
+ return Write(value);
+}
+
+} // namespace base
diff --git a/patchpanel/dns/big_endian.h b/patchpanel/dns/big_endian.h
new file mode 100644
index 0000000..c9e4f70
--- /dev/null
+++ b/patchpanel/dns/big_endian.h
@@ -0,0 +1,106 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PATCHPANEL_DNS_BIG_ENDIAN_H_
+#define PATCHPANEL_DNS_BIG_ENDIAN_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/base_export.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// Read an integer (signed or unsigned) from |buf| in Big Endian order.
+// Note: this loop is unrolled with -O1 and above.
+// NOTE(szym): glibc dns-canon.c use ntohs(*(uint16_t*)ptr) which is
+// potentially unaligned.
+// This would cause SIGBUS on ARMv5 or earlier and ARMv6-M.
+template <typename T>
+inline void ReadBigEndian(const char buf[], T* out) {
+ *out = buf[0];
+ for (size_t i = 1; i < sizeof(T); ++i) {
+ *out <<= 8;
+ // Must cast to uint8_t to avoid clobbering by sign extension.
+ *out |= static_cast<uint8_t>(buf[i]);
+ }
+}
+
+// Write an integer (signed or unsigned) |val| to |buf| in Big Endian order.
+// Note: this loop is unrolled with -O1 and above.
+template <typename T>
+inline void WriteBigEndian(char buf[], T val) {
+ for (size_t i = 0; i < sizeof(T); ++i) {
+ buf[sizeof(T) - i - 1] = static_cast<char>(val & 0xFF);
+ val >>= 8;
+ }
+}
+
+// Specializations to make clang happy about the (dead code) shifts above.
+template <>
+inline void ReadBigEndian<uint8_t>(const char buf[], uint8_t* out) {
+ *out = buf[0];
+}
+
+template <>
+inline void WriteBigEndian<uint8_t>(char buf[], uint8_t val) {
+ buf[0] = static_cast<char>(val);
+}
+
+// Allows reading integers in network order (big endian) while iterating over
+// an underlying buffer. All the reading functions advance the internal pointer.
+class BASE_EXPORT BigEndianReader {
+ public:
+ BigEndianReader(const char* buf, size_t len);
+
+ const char* ptr() const { return ptr_; }
+ int remaining() const { return end_ - ptr_; }
+
+ bool Skip(size_t len);
+ bool ReadBytes(void* out, size_t len);
+ // Creates a StringPiece in |out| that points to the underlying buffer.
+ bool ReadPiece(base::StringPiece* out, size_t len);
+ bool ReadU8(uint8_t* value);
+ bool ReadU16(uint16_t* value);
+ bool ReadU32(uint32_t* value);
+ bool ReadU64(uint64_t* value);
+
+ private:
+ // Hidden to promote type safety.
+ template <typename T>
+ bool Read(T* v);
+
+ const char* ptr_;
+ const char* end_;
+};
+
+// Allows writing integers in network order (big endian) while iterating over
+// an underlying buffer. All the writing functions advance the internal pointer.
+class BASE_EXPORT BigEndianWriter {
+ public:
+ BigEndianWriter(char* buf, size_t len);
+
+ char* ptr() const { return ptr_; }
+ int remaining() const { return end_ - ptr_; }
+
+ bool Skip(size_t len);
+ bool WriteBytes(const void* buf, size_t len);
+ bool WriteU8(uint8_t value);
+ bool WriteU16(uint16_t value);
+ bool WriteU32(uint32_t value);
+ bool WriteU64(uint64_t value);
+
+ private:
+ // Hidden to promote type safety.
+ template <typename T>
+ bool Write(T v);
+
+ char* ptr_;
+ char* end_;
+};
+
+} // namespace base
+
+#endif // PATCHPANEL_DNS_BIG_ENDIAN_H_
diff --git a/patchpanel/dns/dns_protocol.h b/patchpanel/dns/dns_protocol.h
new file mode 100644
index 0000000..b5e8ff0
--- /dev/null
+++ b/patchpanel/dns/dns_protocol.h
@@ -0,0 +1,149 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PATCHPANEL_DNS_DNS_PROTOCOL_H_
+#define PATCHPANEL_DNS_DNS_PROTOCOL_H_
+
+#include <stdint.h>
+
+#include "patchpanel/dns/net_export.h"
+
+namespace net {
+
+namespace dns_protocol {
+
+static const uint16_t kDefaultPort = 53;
+static const uint16_t kDefaultPortMulticast = 5353;
+
+// DNS packet consists of a header followed by questions and/or answers.
+// For the meaning of specific fields, please see RFC 1035 and 2535
+
+// Header format.
+// 1 1 1 1 1 1
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+// | ID |
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+// |QR| Opcode |AA|TC|RD|RA| Z|AD|CD| RCODE |
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+// | QDCOUNT |
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+// | ANCOUNT |
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+// | NSCOUNT |
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+// | ARCOUNT |
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+// Question format.
+// 1 1 1 1 1 1
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+// | |
+// / QNAME /
+// / /
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+// | QTYPE |
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+// | QCLASS |
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+// Answer format.
+// 1 1 1 1 1 1
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+// | |
+// / /
+// / NAME /
+// | |
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+// | TYPE |
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+// | CLASS |
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+// | TTL |
+// | |
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+// | RDLENGTH |
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+// / RDATA /
+// / /
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+#pragma pack(push)
+#pragma pack(1)
+
+// On-the-wire header. All uint16_t are in network order.
+struct NET_EXPORT Header {
+ uint16_t id;
+ uint16_t flags;
+ uint16_t qdcount;
+ uint16_t ancount;
+ uint16_t nscount;
+ uint16_t arcount;
+};
+
+#pragma pack(pop)
+
+static const uint8_t kLabelMask = 0xc0;
+static const uint8_t kLabelPointer = 0xc0;
+static const uint8_t kLabelDirect = 0x0;
+static const uint16_t kOffsetMask = 0x3fff;
+
+// In MDns the most significant bit of the rrclass is designated as the
+// "cache-flush bit", as described in http://www.rfc-editor.org/rfc/rfc6762.txt
+// section 10.2.
+static const uint16_t kMDnsClassMask = 0x7FFF;
+
+// RFC 1035, section 3.1: To simplify implementations, the total length of
+// a domain name (i.e., label octets and label length octets) is restricted
+// to 255 octets or less.
+static const int kMaxNameLength = 255;
+
+// RFC 1035, section 4.2.1: Messages carried by UDP are restricted to 512
+// bytes (not counting the IP nor UDP headers).
+static const int kMaxUDPSize = 512;
+
+// RFC 6762, section 17: Messages over the local link are restricted by the
+// medium's MTU, and must be under 9000 bytes
+static const int kMaxMulticastSize = 9000;
+
+// DNS class types.
+//
+// https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-2
+static const uint16_t kClassIN = 1;
+
+// DNS resource record types.
+//
+// https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4
+static const uint16_t kTypeA = 1;
+static const uint16_t kTypeCNAME = 5;
+static const uint16_t kTypePTR = 12;
+static const uint16_t kTypeTXT = 16;
+static const uint16_t kTypeAAAA = 28;
+static const uint16_t kTypeSRV = 33;
+static const uint16_t kTypeNSEC = 47;
+
+// DNS reply codes (RCODEs).
+//
+// https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6
+static const uint8_t kRcodeNOERROR = 0;
+static const uint8_t kRcodeFORMERR = 1;
+static const uint8_t kRcodeSERVFAIL = 2;
+static const uint8_t kRcodeNXDOMAIN = 3;
+static const uint8_t kRcodeNOTIMP = 4;
+static const uint8_t kRcodeREFUSED = 5;
+
+// DNS header flags.
+//
+// https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-12
+static const uint16_t kFlagResponse = 0x8000;
+static const uint16_t kFlagRD = 0x100; // Recursion Desired - query flag.
+static const uint16_t kFlagTC = 0x200; // Truncated - server flag.
+
+} // namespace dns_protocol
+
+} // namespace net
+
+#endif // PATCHPANEL_DNS_DNS_PROTOCOL_H_
diff --git a/patchpanel/dns/dns_response.cc b/patchpanel/dns/dns_response.cc
new file mode 100644
index 0000000..78e59f5
--- /dev/null
+++ b/patchpanel/dns/dns_response.cc
@@ -0,0 +1,233 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "patchpanel/dns/dns_response.h"
+
+#include <limits>
+
+#include "base/strings/string_util.h"
+#include "base/sys_byteorder.h"
+
+#include "patchpanel/dns/big_endian.h"
+#include "patchpanel/dns/dns_protocol.h"
+#include "patchpanel/dns/io_buffer.h"
+
+namespace net {
+
+namespace {
+
+const size_t kHeaderSize = sizeof(dns_protocol::Header);
+
+const uint8_t kRcodeMask = 0xf;
+
+} // namespace
+
+DnsResourceRecord::DnsResourceRecord() = default;
+
+DnsResourceRecord::~DnsResourceRecord() = default;
+
+DnsRecordParser::DnsRecordParser() : packet_(nullptr), length_(0), cur_(0) {}
+
+DnsRecordParser::DnsRecordParser(const void* packet,
+ size_t length,
+ size_t offset)
+ : packet_(reinterpret_cast<const char*>(packet)),
+ length_(length),
+ cur_(packet_ + offset) {
+ DCHECK_LE(offset, length);
+}
+
+unsigned DnsRecordParser::ReadName(const void* const vpos,
+ std::string* out) const {
+ const char* const pos = reinterpret_cast<const char*>(vpos);
+ DCHECK(packet_);
+ DCHECK_LE(packet_, pos);
+ DCHECK_LE(pos, packet_ + length_);
+
+ const char* p = pos;
+ const char* end = packet_ + length_;
+ // Count number of seen bytes to detect loops.
+ unsigned seen = 0;
+ // Remember how many bytes were consumed before first jump.
+ unsigned consumed = 0;
+
+ if (pos >= end)
+ return 0;
+
+ if (out) {
+ out->clear();
+ out->reserve(dns_protocol::kMaxNameLength);
+ }
+
+ for (;;) {
+ // The first two bits of the length give the type of the length. It's
+ // either a direct length or a pointer to the remainder of the name.
+ switch (*p & dns_protocol::kLabelMask) {
+ case dns_protocol::kLabelPointer: {
+ if (p + sizeof(uint16_t) > end)
+ return 0;
+ if (consumed == 0) {
+ consumed = p - pos + sizeof(uint16_t);
+ if (!out)
+ return consumed; // If name is not stored, that's all we need.
+ }
+ seen += sizeof(uint16_t);
+ // If seen the whole packet, then we must be in a loop.
+ if (seen > length_)
+ return 0;
+ uint16_t offset;
+ base::ReadBigEndian<uint16_t>(p, &offset);
+ offset &= dns_protocol::kOffsetMask;
+ p = packet_ + offset;
+ if (p >= end)
+ return 0;
+ break;
+ }
+ case dns_protocol::kLabelDirect: {
+ uint8_t label_len = *p;
+ ++p;
+ // Note: root domain (".") is NOT included.
+ if (label_len == 0) {
+ if (consumed == 0) {
+ consumed = p - pos;
+ } // else we set |consumed| before first jump
+ return consumed;
+ }
+ if (p + label_len >= end)
+ return 0; // Truncated or missing label.
+ if (out) {
+ if (!out->empty())
+ out->append(".");
+ out->append(p, label_len);
+ }
+ p += label_len;
+ seen += 1 + label_len;
+ break;
+ }
+ default:
+ // unhandled label type
+ return 0;
+ }
+ }
+}
+
+bool DnsRecordParser::ReadRecord(DnsResourceRecord* out) {
+ DCHECK(packet_);
+ size_t consumed = ReadName(cur_, &out->name);
+ if (!consumed)
+ return false;
+ base::BigEndianReader reader(cur_ + consumed,
+ packet_ + length_ - (cur_ + consumed));
+ uint16_t rdlen;
+ if (reader.ReadU16(&out->type) && reader.ReadU16(&out->klass) &&
+ reader.ReadU32(&out->ttl) && reader.ReadU16(&rdlen) &&
+ reader.ReadPiece(&out->rdata, rdlen)) {
+ cur_ = reader.ptr();
+ return true;
+ }
+ return false;
+}
+
+bool DnsRecordParser::SkipQuestion() {
+ size_t consumed = ReadName(cur_, nullptr);
+ if (!consumed)
+ return false;
+
+ const char* next = cur_ + consumed + 2 * sizeof(uint16_t); // QTYPE + QCLASS
+ if (next > packet_ + length_)
+ return false;
+
+ cur_ = next;
+
+ return true;
+}
+
+DnsResponse::DnsResponse()
+ : io_buffer_(new IOBufferWithSize(dns_protocol::kMaxUDPSize + 1)) {}
+
+DnsResponse::DnsResponse(size_t length)
+ : io_buffer_(new IOBufferWithSize(length)) {}
+
+DnsResponse::DnsResponse(const void* data, size_t length, size_t answer_offset)
+ : io_buffer_(new IOBufferWithSize(length)),
+ parser_(io_buffer_->data(), length, answer_offset) {
+ DCHECK(data);
+ memcpy(io_buffer_->data(), data, length);
+}
+
+DnsResponse::~DnsResponse() = default;
+
+bool DnsResponse::InitParseWithoutQuery(int nbytes) {
+ DCHECK_GE(nbytes, 0);
+
+ if (nbytes < static_cast<int>(kHeaderSize) || nbytes >= io_buffer_->size())
+ return false;
+
+ parser_ = DnsRecordParser(io_buffer_->data(), nbytes, kHeaderSize);
+
+ unsigned qdcount = base::NetToHost16(header()->qdcount);
+ for (unsigned i = 0; i < qdcount; ++i) {
+ if (!parser_.SkipQuestion()) {
+ parser_ = DnsRecordParser(); // Make parser invalid again.
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool DnsResponse::IsValid() const {
+ return parser_.IsValid();
+}
+
+uint16_t DnsResponse::flags() const {
+ DCHECK(parser_.IsValid());
+ return base::NetToHost16(header()->flags) & ~(kRcodeMask);
+}
+
+uint8_t DnsResponse::rcode() const {
+ DCHECK(parser_.IsValid());
+ return base::NetToHost16(header()->flags) & kRcodeMask;
+}
+
+unsigned DnsResponse::answer_count() const {
+ DCHECK(parser_.IsValid());
+ return base::NetToHost16(header()->ancount);
+}
+
+unsigned DnsResponse::additional_answer_count() const {
+ DCHECK(parser_.IsValid());
+ return base::NetToHost16(header()->arcount);
+}
+
+base::StringPiece DnsResponse::qname() const {
+ DCHECK(parser_.IsValid());
+ // The response is HEADER QNAME QTYPE QCLASS ANSWER.
+ // |parser_| is positioned at the beginning of ANSWER, so the end of QNAME is
+ // two uint16_ts before it.
+ const size_t qname_size =
+ parser_.GetOffset() - 2 * sizeof(uint16_t) - kHeaderSize;
+ return base::StringPiece(io_buffer_->data() + kHeaderSize, qname_size);
+}
+
+uint16_t DnsResponse::qtype() const {
+ DCHECK(parser_.IsValid());
+ // QTYPE starts where QNAME ends.
+ const size_t type_offset = parser_.GetOffset() - 2 * sizeof(uint16_t);
+ uint16_t type;
+ base::ReadBigEndian<uint16_t>(io_buffer_->data() + type_offset, &type);
+ return type;
+}
+
+DnsRecordParser DnsResponse::Parser() const {
+ DCHECK(parser_.IsValid());
+ // Return a copy of the parser.
+ return parser_;
+}
+
+const dns_protocol::Header* DnsResponse::header() const {
+ return reinterpret_cast<const dns_protocol::Header*>(io_buffer_->data());
+}
+
+} // namespace net
diff --git a/patchpanel/dns/dns_response.h b/patchpanel/dns/dns_response.h
new file mode 100644
index 0000000..193fb01
--- /dev/null
+++ b/patchpanel/dns/dns_response.h
@@ -0,0 +1,163 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PATCHPANEL_DNS_DNS_RESPONSE_H_
+#define PATCHPANEL_DNS_DNS_RESPONSE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_piece.h"
+#include "base/time/time.h"
+
+#include "patchpanel/dns/io_buffer.h"
+#include "patchpanel/dns/net_export.h"
+
+namespace net {
+
+class AddressList;
+class DnsQuery;
+class IOBufferWithSize;
+
+namespace dns_protocol {
+struct Header;
+}
+
+// Structure representing a Resource Record as specified in RFC 1035, Section
+// 4.1.3.
+struct NET_EXPORT_PRIVATE DnsResourceRecord {
+ DnsResourceRecord();
+ ~DnsResourceRecord();
+
+ std::string name; // in dotted form
+ uint16_t type;
+ uint16_t klass;
+ uint32_t ttl;
+ base::StringPiece rdata; // points to the original response buffer
+};
+
+// Iterator to walk over resource records of the DNS response packet.
+class NET_EXPORT_PRIVATE DnsRecordParser {
+ public:
+ // Construct an uninitialized iterator.
+ DnsRecordParser();
+
+ // Construct an iterator to process the |packet| of given |length|.
+ // |offset| points to the beginning of the answer section.
+ DnsRecordParser(const void* packet, size_t length, size_t offset);
+
+ // Returns |true| if initialized.
+ bool IsValid() const { return packet_ != nullptr; }
+
+ // Returns |true| if no more bytes remain in the packet.
+ bool AtEnd() const { return cur_ == packet_ + length_; }
+
+ // Returns current offset into the packet.
+ size_t GetOffset() const { return cur_ - packet_; }
+
+ // Parses a (possibly compressed) DNS name from the packet starting at
+ // |pos|. Stores output (even partial) in |out| unless |out| is NULL. |out|
+ // is stored in the dotted form, e.g., "example.com". Returns number of bytes
+ // consumed or 0 on failure.
+ // This is exposed to allow parsing compressed names within RRDATA for TYPEs
+ // such as NS, CNAME, PTR, MX, SOA.
+ // See RFC 1035 section 4.1.4.
+ unsigned ReadName(const void* pos, std::string* out) const;
+
+ // Parses the next resource record into |record|. Returns true if succeeded.
+ bool ReadRecord(DnsResourceRecord* record);
+
+ // Skip a question section, returns true if succeeded.
+ bool SkipQuestion();
+
+ private:
+ const char* packet_;
+ size_t length_;
+ // Current offset within the packet.
+ const char* cur_;
+};
+
+// Buffer-holder for the DNS response allowing easy access to the header fields
+// and resource records. After reading into |io_buffer| must call InitParse to
+// position the RR parser.
+class NET_EXPORT_PRIVATE DnsResponse {
+ public:
+ // Possible results from ParseToAddressList.
+ enum Result {
+ DNS_PARSE_OK = 0,
+ DNS_MALFORMED_RESPONSE, // DnsRecordParser failed before the end of
+ // packet.
+ DNS_MALFORMED_CNAME, // Could not parse CNAME out of RRDATA.
+ DNS_NAME_MISMATCH, // Got an address but no ordered chain of CNAMEs
+ // leads there.
+ DNS_SIZE_MISMATCH, // Got an address but size does not match.
+ DNS_CNAME_AFTER_ADDRESS, // Found CNAME after an address record.
+ DNS_ADDRESS_TTL_MISMATCH, // OBSOLETE. No longer used.
+ DNS_NO_ADDRESSES, // OBSOLETE. No longer used.
+ // Only add new values here.
+ DNS_PARSE_RESULT_MAX, // Bounding value for histograms.
+ };
+
+ // Constructs a response buffer large enough to store one byte more than
+ // largest possible response, to detect malformed responses.
+ DnsResponse();
+
+ // Constructs a response buffer of given length. Used for TCP transactions.
+ explicit DnsResponse(size_t length);
+
+ // Constructs a response from |data|. Used for testing purposes only!
+ DnsResponse(const void* data, size_t length, size_t answer_offset);
+
+ ~DnsResponse();
+
+ // Internal buffer accessor into which actual bytes of response will be
+ // read.
+ IOBufferWithSize* io_buffer() { return io_buffer_.get(); }
+
+ // Assuming the internal buffer holds |nbytes| bytes, initialize the parser
+ // without matching it against an existing query.
+ bool InitParseWithoutQuery(int nbytes);
+
+ // Returns true if response is valid, that is, after successful InitParse.
+ bool IsValid() const;
+
+ // All of the methods below are valid only if the response is valid.
+
+ // Accessors for the header.
+ uint16_t flags() const; // excluding rcode
+ uint8_t rcode() const;
+
+ unsigned answer_count() const;
+ unsigned additional_answer_count() const;
+
+ // Accessors to the question. The qname is unparsed.
+ base::StringPiece qname() const;
+ uint16_t qtype() const;
+
+ // Returns an iterator to the resource records in the answer section.
+ // The iterator is valid only in the scope of the DnsResponse.
+ // This operation is idempotent.
+ DnsRecordParser Parser() const;
+
+ private:
+ // Convenience for header access.
+ const dns_protocol::Header* header() const;
+
+ // Buffer into which response bytes are read.
+ scoped_refptr<IOBufferWithSize> io_buffer_;
+
+ // Iterator constructed after InitParse positioned at the answer section.
+ // It is never updated afterwards, so can be used in accessors.
+ DnsRecordParser parser_;
+
+ DISALLOW_COPY_AND_ASSIGN(DnsResponse);
+};
+
+} // namespace net
+
+#endif // PATCHPANEL_DNS_DNS_RESPONSE_H_
diff --git a/patchpanel/dns/io_buffer.cc b/patchpanel/dns/io_buffer.cc
new file mode 100644
index 0000000..a15ca72
--- /dev/null
+++ b/patchpanel/dns/io_buffer.cc
@@ -0,0 +1,171 @@
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "patchpanel/dns/io_buffer.h"
+
+#include "base/logging.h"
+#include "base/numerics/safe_math.h"
+
+namespace net {
+
+namespace {
+
+// TODO(eroman): IOBuffer is being converted to require buffer sizes and offsets
+// be specified as "size_t" rather than "int" (crbug.com/488553). To facilitate
+// this move (since LOTS of code needs to be updated), both "size_t" and "int
+// are being accepted. When using "size_t" this function ensures that it can be
+// safely converted to an "int" without truncation.
+void AssertValidBufferSize(size_t size) {
+ base::CheckedNumeric<int>(size).ValueOrDie();
+}
+
+void AssertValidBufferSize(int size) {
+ CHECK_GE(size, 0);
+}
+
+} // namespace
+
+IOBuffer::IOBuffer() : data_(nullptr) {}
+
+IOBuffer::IOBuffer(int buffer_size) {
+ AssertValidBufferSize(buffer_size);
+ data_ = new char[buffer_size];
+}
+
+IOBuffer::IOBuffer(size_t buffer_size) {
+ AssertValidBufferSize(buffer_size);
+ data_ = new char[buffer_size];
+}
+
+IOBuffer::IOBuffer(char* data) : data_(data) {}
+
+IOBuffer::~IOBuffer() {
+ delete[] data_;
+ data_ = nullptr;
+}
+
+IOBufferWithSize::IOBufferWithSize(int size) : IOBuffer(size), size_(size) {
+ AssertValidBufferSize(size);
+}
+
+IOBufferWithSize::IOBufferWithSize(size_t size) : IOBuffer(size), size_(size) {
+ // Note: Size check is done in superclass' constructor.
+}
+
+IOBufferWithSize::IOBufferWithSize(char* data, int size)
+ : IOBuffer(data), size_(size) {
+ AssertValidBufferSize(size);
+}
+
+IOBufferWithSize::IOBufferWithSize(char* data, size_t size)
+ : IOBuffer(data), size_(size) {
+ AssertValidBufferSize(size);
+}
+
+IOBufferWithSize::~IOBufferWithSize() = default;
+
+StringIOBuffer::StringIOBuffer(const std::string& s)
+ : IOBuffer(nullptr), string_data_(s) {
+ AssertValidBufferSize(s.size());
+ data_ = const_cast<char*>(string_data_.data());
+}
+
+StringIOBuffer::StringIOBuffer(std::unique_ptr<std::string> s)
+ : IOBuffer(nullptr) {
+ AssertValidBufferSize(s->size());
+ string_data_.swap(*s.get());
+ data_ = const_cast<char*>(string_data_.data());
+}
+
+StringIOBuffer::~StringIOBuffer() {
+ // We haven't allocated the buffer, so remove it before the base class
+ // destructor tries to delete[] it.
+ data_ = nullptr;
+}
+
+DrainableIOBuffer::DrainableIOBuffer(IOBuffer* base, int size)
+ : IOBuffer(base->data()), base_(base), size_(size), used_(0) {
+ AssertValidBufferSize(size);
+}
+
+DrainableIOBuffer::DrainableIOBuffer(IOBuffer* base, size_t size)
+ : IOBuffer(base->data()), base_(base), size_(size), used_(0) {
+ AssertValidBufferSize(size);
+}
+
+void DrainableIOBuffer::DidConsume(int bytes) {
+ SetOffset(used_ + bytes);
+}
+
+int DrainableIOBuffer::BytesRemaining() const {
+ return size_ - used_;
+}
+
+// Returns the number of consumed bytes.
+int DrainableIOBuffer::BytesConsumed() const {
+ return used_;
+}
+
+void DrainableIOBuffer::SetOffset(int bytes) {
+ DCHECK_GE(bytes, 0);
+ DCHECK_LE(bytes, size_);
+ used_ = bytes;
+ data_ = base_->data() + used_;
+}
+
+DrainableIOBuffer::~DrainableIOBuffer() {
+ // The buffer is owned by the |base_| instance.
+ data_ = nullptr;
+}
+
+GrowableIOBuffer::GrowableIOBuffer() : IOBuffer(), capacity_(0), offset_(0) {}
+
+void GrowableIOBuffer::SetCapacity(int capacity) {
+ DCHECK_GE(capacity, 0);
+ // realloc will crash if it fails.
+ real_data_.reset(static_cast<char*>(realloc(real_data_.release(), capacity)));
+ capacity_ = capacity;
+ if (offset_ > capacity)
+ set_offset(capacity);
+ else
+ set_offset(offset_); // The pointer may have changed.
+}
+
+void GrowableIOBuffer::set_offset(int offset) {
+ DCHECK_GE(offset, 0);
+ DCHECK_LE(offset, capacity_);
+ offset_ = offset;
+ data_ = real_data_.get() + offset;
+}
+
+int GrowableIOBuffer::RemainingCapacity() {
+ return capacity_ - offset_;
+}
+
+char* GrowableIOBuffer::StartOfBuffer() {
+ return real_data_.get();
+}
+
+GrowableIOBuffer::~GrowableIOBuffer() {
+ data_ = nullptr;
+}
+
+PickledIOBuffer::PickledIOBuffer() = default;
+
+void PickledIOBuffer::Done() {
+ data_ = const_cast<char*>(static_cast<const char*>(pickle_.data()));
+}
+
+PickledIOBuffer::~PickledIOBuffer() {
+ data_ = nullptr;
+}
+
+WrappedIOBuffer::WrappedIOBuffer(const char* data)
+ : IOBuffer(const_cast<char*>(data)) {}
+
+WrappedIOBuffer::~WrappedIOBuffer() {
+ data_ = nullptr;
+}
+
+} // namespace net
diff --git a/patchpanel/dns/io_buffer.h b/patchpanel/dns/io_buffer.h
new file mode 100644
index 0000000..60cc840
--- /dev/null
+++ b/patchpanel/dns/io_buffer.h
@@ -0,0 +1,258 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PATCHPANEL_DNS_IO_BUFFER_H_
+#define PATCHPANEL_DNS_IO_BUFFER_H_
+
+#include <stddef.h>
+
+#include <memory>
+#include <string>
+
+#include "patchpanel/dns/net_export.h"
+#include "base/memory/free_deleter.h"
+#include "base/memory/ref_counted.h"
+#include "base/pickle.h"
+
+namespace net {
+
+// IOBuffers are reference counted data buffers used for easier asynchronous
+// IO handling.
+//
+// They are often used as the destination buffers for Read() operations, or as
+// the source buffers for Write() operations.
+//
+// IMPORTANT: Never re-use an IOBuffer after cancelling the IO operation that
+// was using it, since this may lead to memory corruption!
+//
+// -----------------------
+// Ownership of IOBuffers:
+// -----------------------
+//
+// Although IOBuffers are RefCountedThreadSafe, they are not intended to be
+// used as a shared buffer, nor should they be used simultaneously across
+// threads. The fact that they are reference counted is an implementation
+// detail for allowing them to outlive cancellation of asynchronous
+// operations.
+//
+// Instead, think of the underlying |char*| buffer contained by the IOBuffer
+// as having exactly one owner at a time.
+//
+// Whenever you call an asynchronous operation that takes an IOBuffer,
+// ownership is implicitly transferred to the called function, until the
+// operation has completed (at which point it transfers back to the caller).
+//
+// ==> The IOBuffer's data should NOT be manipulated, destroyed, or read
+// until the operation has completed.
+//
+// ==> Cancellation does NOT count as completion. If an operation using
+// an IOBuffer is cancelled, the caller should release their
+// reference to this IOBuffer at the time of cancellation since
+// they can no longer use it.
+//
+// For instance, if you were to call a Read() operation on some class which
+// takes an IOBuffer, and then delete that class (which generally will
+// trigger cancellation), the IOBuffer which had been passed to Read() should
+// never be re-used.
+//
+// This usage contract is assumed by any API which takes an IOBuffer, even
+// though it may not be explicitly mentioned in the function's comments.
+//
+// -----------------------
+// Motivation
+// -----------------------
+//
+// The motivation for transferring ownership during cancellation is
+// to make it easier to work with un-cancellable operations.
+//
+// For instance, let's say under the hood your API called out to the
+// operating system's synchronous ReadFile() function on a worker thread.
+// When cancelling through our asynchronous interface, we have no way of
+// actually aborting the in progress ReadFile(). We must let it keep running,
+// and hence the buffer it was reading into must remain alive. Using
+// reference counting we can add a reference to the IOBuffer and make sure
+// it is not destroyed until after the synchronous operation has completed.
+class NET_EXPORT IOBuffer : public base::RefCountedThreadSafe<IOBuffer> {
+ public:
+ IOBuffer();
+
+ // TODO(eroman): Deprecated. Use the size_t flavor instead. crbug.com/488553
+ explicit IOBuffer(int buffer_size);
+ explicit IOBuffer(size_t buffer_size);
+
+ char* data() const { return data_; }
+
+ protected:
+ friend class base::RefCountedThreadSafe<IOBuffer>;
+
+ // Only allow derived classes to specify data_.
+ // In all other cases, we own data_, and must delete it at destruction time.
+ explicit IOBuffer(char* data);
+
+ virtual ~IOBuffer();
+
+ char* data_;
+};
+
+// This version stores the size of the buffer so that the creator of the object
+// doesn't have to keep track of that value.
+// NOTE: This doesn't mean that we want to stop sending the size as an explicit
+// argument to IO functions. Please keep using IOBuffer* for API declarations.
+class NET_EXPORT IOBufferWithSize : public IOBuffer {
+ public:
+ // TODO(eroman): Deprecated. Use the size_t flavor instead. crbug.com/488553
+ explicit IOBufferWithSize(int size);
+ explicit IOBufferWithSize(size_t size);
+
+ int size() const { return size_; }
+
+ protected:
+ // TODO(eroman): Deprecated. Use the size_t flavor instead. crbug.com/488553
+ IOBufferWithSize(char* data, int size);
+
+ // Purpose of this constructor is to give a subclass access to the base class
+ // constructor IOBuffer(char*) thus allowing subclass to use underlying
+ // memory it does not own.
+ IOBufferWithSize(char* data, size_t size);
+ ~IOBufferWithSize() override;
+
+ int size_;
+};
+
+// This is a read only IOBuffer. The data is stored in a string and
+// the IOBuffer interface does not provide a proper way to modify it.
+class NET_EXPORT StringIOBuffer : public IOBuffer {
+ public:
+ explicit StringIOBuffer(const std::string& s);
+ explicit StringIOBuffer(std::unique_ptr<std::string> s);
+
+ int size() const { return static_cast<int>(string_data_.size()); }
+
+ private:
+ ~StringIOBuffer() override;
+
+ std::string string_data_;
+};
+
+// This version wraps an existing IOBuffer and provides convenient functions
+// to progressively read all the data.
+//
+// DrainableIOBuffer is useful when you have an IOBuffer that contains data
+// to be written progressively, and Write() function takes an IOBuffer rather
+// than char*. DrainableIOBuffer can be used as follows:
+//
+// // payload is the IOBuffer containing the data to be written.
+// buf = new DrainableIOBuffer(payload, payload_size);
+//
+// while (buf->BytesRemaining() > 0) {
+// // Write() takes an IOBuffer. If it takes char*, we could
+// // simply use the regular IOBuffer like payload->data() + offset.
+// int bytes_written = Write(buf, buf->BytesRemaining());
+// buf->DidConsume(bytes_written);
+// }
+//
+class NET_EXPORT DrainableIOBuffer : public IOBuffer {
+ public:
+ // TODO(eroman): Deprecated. Use the size_t flavor instead. crbug.com/488553
+ DrainableIOBuffer(IOBuffer* base, int size);
+ DrainableIOBuffer(IOBuffer* base, size_t size);
+
+ // DidConsume() changes the |data_| pointer so that |data_| always points
+ // to the first unconsumed byte.
+ void DidConsume(int bytes);
+
+ // Returns the number of unconsumed bytes.
+ int BytesRemaining() const;
+
+ // Returns the number of consumed bytes.
+ int BytesConsumed() const;
+
+ // Seeks to an arbitrary point in the buffer. The notion of bytes consumed
+ // and remaining are updated appropriately.
+ void SetOffset(int bytes);
+
+ int size() const { return size_; }
+
+ private:
+ ~DrainableIOBuffer() override;
+
+ scoped_refptr<IOBuffer> base_;
+ int size_;
+ int used_;
+};
+
+// This version provides a resizable buffer and a changeable offset.
+//
+// GrowableIOBuffer is useful when you read data progressively without
+// knowing the total size in advance. GrowableIOBuffer can be used as
+// follows:
+//
+// buf = new GrowableIOBuffer;
+// buf->SetCapacity(1024); // Initial capacity.
+//
+// while (!some_stream->IsEOF()) {
+// // Double the capacity if the remaining capacity is empty.
+// if (buf->RemainingCapacity() == 0)
+// buf->SetCapacity(buf->capacity() * 2);
+// int bytes_read = some_stream->Read(buf, buf->RemainingCapacity());
+// buf->set_offset(buf->offset() + bytes_read);
+// }
+//
+class NET_EXPORT GrowableIOBuffer : public IOBuffer {
+ public:
+ GrowableIOBuffer();
+
+ // realloc memory to the specified capacity.
+ void SetCapacity(int capacity);
+ int capacity() { return capacity_; }
+
+ // |offset| moves the |data_| pointer, allowing "seeking" in the data.
+ void set_offset(int offset);
+ int offset() { return offset_; }
+
+ int RemainingCapacity();
+ char* StartOfBuffer();
+
+ private:
+ ~GrowableIOBuffer() override;
+
+ std::unique_ptr<char, base::FreeDeleter> real_data_;
+ int capacity_;
+ int offset_;
+};
+
+// This versions allows a pickle to be used as the storage for a write-style
+// operation, avoiding an extra data copy.
+class NET_EXPORT PickledIOBuffer : public IOBuffer {
+ public:
+ PickledIOBuffer();
+
+ base::Pickle* pickle() { return &pickle_; }
+
+ // Signals that we are done writing to the pickle and we can use it for a
+ // write-style IO operation.
+ void Done();
+
+ private:
+ ~PickledIOBuffer() override;
+
+ base::Pickle pickle_;
+};
+
+// This class allows the creation of a temporary IOBuffer that doesn't really
+// own the underlying buffer. Please use this class only as a last resort.
+// A good example is the buffer for a synchronous operation, where we can be
+// sure that nobody is keeping an extra reference to this object so the lifetime
+// of the buffer can be completely managed by its intended owner.
+class NET_EXPORT WrappedIOBuffer : public IOBuffer {
+ public:
+ explicit WrappedIOBuffer(const char* data);
+
+ protected:
+ ~WrappedIOBuffer() override;
+};
+
+} // namespace net
+
+#endif // PATCHPANEL_DNS_IO_BUFFER_H_
diff --git a/patchpanel/dns/net_export.h b/patchpanel/dns/net_export.h
new file mode 100644
index 0000000..03054af
--- /dev/null
+++ b/patchpanel/dns/net_export.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PATCHPANEL_DNS_NET_EXPORT_H_
+#define PATCHPANEL_DNS_NET_EXPORT_H_
+
+// Defines NET_EXPORT so that functionality implemented by the net module can
+// be exported to consumers, and NET_EXPORT_PRIVATE that allows unit tests to
+// access features not intended to be used directly by real consumers.
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(NET_IMPLEMENTATION)
+#define NET_EXPORT __declspec(dllexport)
+#define NET_EXPORT_PRIVATE __declspec(dllexport)
+#else
+#define NET_EXPORT __declspec(dllimport)
+#define NET_EXPORT_PRIVATE __declspec(dllimport)
+#endif // defined(NET_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(NET_IMPLEMENTATION)
+#define NET_EXPORT __attribute__((visibility("default")))
+#define NET_EXPORT_PRIVATE __attribute__((visibility("default")))
+#else
+#define NET_EXPORT
+#define NET_EXPORT_PRIVATE
+#endif
+#endif
+
+#else /// defined(COMPONENT_BUILD)
+#define NET_EXPORT
+#define NET_EXPORT_PRIVATE
+#endif
+
+#endif // PATCHPANEL_DNS_NET_EXPORT_H_