summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authoragayev@chromium.org <agayev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-03 21:26:49 +0000
committeragayev@chromium.org <agayev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-03 21:26:49 +0000
commitb5810641da6e56bc416deded72ba939b37c23922 (patch)
treea3f40b472e41552a0408b78ebef6cd4e5e779a59 /net
parent74b962aa204b487dabcdb2fb9e7c7c7c62db1c5f (diff)
downloadchromium_src-b5810641da6e56bc416deded72ba939b37c23922.zip
chromium_src-b5810641da6e56bc416deded72ba939b37c23922.tar.gz
chromium_src-b5810641da6e56bc416deded72ba939b37c23922.tar.bz2
Implements DnsRequest and DnsResponse classes.
BUG=60149 TEST=net_unittests --gtest_filter="DnsQuery*:DnsResponse*" Review URL: http://codereview.chromium.org/7065062 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@87868 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/base/dns_query.cc111
-rw-r--r--net/base/dns_query.h72
-rw-r--r--net/base/dns_query_unittest.cc109
-rw-r--r--net/base/dns_response.cc106
-rw-r--r--net/base/dns_response.h48
-rw-r--r--net/base/dns_response_unittest.cc152
-rw-r--r--net/base/dns_util.h6
-rw-r--r--net/base/dnsrr_resolver.cc1
-rw-r--r--net/base/net_error_list.h17
-rw-r--r--net/net.gyp6
10 files changed, 626 insertions, 2 deletions
diff --git a/net/base/dns_query.cc b/net/base/dns_query.cc
new file mode 100644
index 0000000..ba79150
--- /dev/null
+++ b/net/base/dns_query.cc
@@ -0,0 +1,111 @@
+// Copyright (c) 2011 The Chromium 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 "net/base/dns_query.h"
+
+#include <string>
+
+#include "base/rand_util.h"
+#include "net/base/address_family.h"
+#include "net/base/dns_util.h"
+
+namespace net {
+
+namespace {
+
+void PackUint16BE(char buf[2], uint16 v) {
+ buf[0] = v >> 8;
+ buf[1] = v & 0xff;
+}
+
+uint16 QTypeFromAddressFamily(AddressFamily address_family) {
+ switch (address_family) {
+ case ADDRESS_FAMILY_IPV4:
+ return kDNS_A;
+ case ADDRESS_FAMILY_IPV6:
+ return kDNS_AAAA;
+ default:
+ NOTREACHED() << "Bad address family";
+ return kDNS_A;
+ }
+}
+
+} // namespace
+
+// DNS query consists of a 12-byte header followed by a question section.
+// For details, see RFC 1035 section 4.1.1. This header template sets RD
+// bit, which directs the name server to pursue query recursively, and sets
+// the QDCOUNT to 1, meaning the question section has a single entry. The
+// first two bytes of the header form a 16-bit random query ID to be copied
+// in the corresponding reply by the name server -- randomized during
+// DnsQuery construction.
+static const char kHeader[] = {0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static const size_t kHeaderLen = arraysize(kHeader);
+
+DnsQuery::DnsQuery(const std::string& hostname,
+ AddressFamily address_family,
+ int port)
+ : port_(port),
+ id_(0),
+ qtype_(QTypeFromAddressFamily(address_family)),
+ hostname_(hostname) {
+ std::string qname;
+ if (!net::DNSDomainFromDot(hostname, &qname))
+ return;
+
+ size_t query_size = kHeaderLen + qname.size() +
+ sizeof(qtype_) + sizeof(kClassIN);
+
+ io_buffer_ = new IOBufferWithSize(query_size);
+
+ int byte_offset = 0;
+ char* buffer_head = io_buffer_->data();
+ memcpy(&buffer_head[byte_offset], kHeader, kHeaderLen);
+ byte_offset += kHeaderLen;
+ memcpy(&buffer_head[byte_offset], &qname[0], qname.size());
+ byte_offset += qname.size();
+ PackUint16BE(&buffer_head[byte_offset], qtype_);
+ byte_offset += sizeof(qtype_);
+ PackUint16BE(&buffer_head[byte_offset], kClassIN);
+
+ // Randomize ID, first two bytes.
+ id_ = base::RandUint64() & 0xffff;
+ PackUint16BE(&buffer_head[0], id_);
+}
+
+DnsQuery::~DnsQuery() {
+}
+
+int DnsQuery::port() const {
+ DCHECK(IsValid());
+ return port_;
+}
+
+uint16 DnsQuery::id() const {
+ DCHECK(IsValid());
+ return id_;
+}
+
+uint16 DnsQuery::qtype() const {
+ DCHECK(IsValid());
+ return qtype_;
+}
+
+AddressFamily DnsQuery::address_family() const {
+ DCHECK(IsValid());
+ return address_family_;
+}
+
+const std::string& DnsQuery::hostname() const {
+ DCHECK(IsValid());
+ return hostname_;
+}
+
+IOBufferWithSize* DnsQuery::io_buffer() const {
+ DCHECK(IsValid());
+ return io_buffer_.get();
+}
+
+} // namespace net
diff --git a/net/base/dns_query.h b/net/base/dns_query.h
new file mode 100644
index 0000000..bc25997
--- /dev/null
+++ b/net/base/dns_query.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2011 The Chromium 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 NET_BASE_DNS_QUERY_H_
+#define NET_BASE_DNS_QUERY_H_
+#pragma once
+
+#include <string>
+
+#include "net/base/address_family.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_util.h"
+
+namespace net{
+
+// A class that encapsulates bits and pieces related to DNS request processing.
+class DnsQuery {
+ public:
+ // Constructs an object containing an IOBuffer with raw DNS query string
+ // for |hostname| with the given |address_family|; |port| is here due to
+ // legacy -- getaddrinfo() takes service name, which is mapped to some
+ // port and returns sockaddr_in structures with ports filled in, so do we
+ // -- look at DnsResponse::Parse() to see where it is used.
+
+ // Every generated object has a random ID, hence two objects generated
+ // with the same set of constructor arguments are generally not equal;
+ // there is a 1/2^16 chance of them being equal due to size of |id_|.
+ DnsQuery(const std::string& hostname, AddressFamily address_family, int port);
+ ~DnsQuery();
+
+ // Returns true if the constructed object was valid.
+ bool IsValid() const { return io_buffer_.get() != NULL; }
+
+ // DnsQuery field accessors. These should only be called on an object
+ // for whom |IsValid| is true.
+ int port() const;
+ uint16 id() const;
+ uint16 qtype() const;
+ AddressFamily address_family() const;
+ const std::string& hostname() const;
+
+ // IOBuffer accessor to be used for writing out the query.
+ IOBufferWithSize* io_buffer() const;
+
+ private:
+ // Port to be used by corresponding DnsResponse when filling sockaddr_ins
+ // to be returned.
+ int port_;
+
+ // ID of the query.
+ uint16 id_;
+
+ // Type of query, currently, either A or AAAA.
+ uint16 qtype_;
+
+ // Address family of the query; used when constructing new object from
+ // this one.
+ AddressFamily address_family_;
+
+ // Hostname that we are trying to resolve.
+ std::string hostname_;
+
+ // Contains query bytes to be consumed by higher level Write() call.
+ scoped_refptr<IOBufferWithSize> io_buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(DnsQuery);
+};
+
+} // namespace net
+
+#endif // NET_BASE_DNS_QUERY_H_
diff --git a/net/base/dns_query_unittest.cc b/net/base/dns_query_unittest.cc
new file mode 100644
index 0000000..ba21c4e
--- /dev/null
+++ b/net/base/dns_query_unittest.cc
@@ -0,0 +1,109 @@
+// Copyright (c) 2011 The Chromium 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 "net/base/dns_query.h"
+#include "net/base/dns_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+// DNS query consists of a header followed by a question. Header format
+// and question format are described below. For the meaning of specific
+// fields, please see RFC 1035.
+
+// 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 | 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 |
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+TEST(DnsQueryTest, RandomIdTest) {
+ const std::string kHostname = "www.google.com";
+ const uint16 kPort = 80;
+
+ DnsQuery q1(kHostname, ADDRESS_FAMILY_IPV4, kPort);
+ EXPECT_TRUE(q1.IsValid());
+ EXPECT_EQ(kPort, q1.port());
+ EXPECT_EQ(kDNS_A, q1.qtype());
+ EXPECT_EQ(kHostname, q1.hostname());
+
+ DnsQuery q2(kHostname, ADDRESS_FAMILY_IPV4, kPort);
+ EXPECT_TRUE(q2.IsValid());
+ EXPECT_EQ(kPort, q2.port());
+ EXPECT_EQ(kDNS_A, q2.qtype());
+ EXPECT_EQ(kHostname, q2.hostname());
+
+ // This has a 1/2^16 probability of failure.
+ EXPECT_FALSE(q1.id() == q2.id());
+}
+
+TEST(DnsQueryTest, ConstructorTest) {
+ const std::string kHostname = "www.google.com";
+ const uint16 kPort = 80;
+
+ DnsQuery q1(kHostname, ADDRESS_FAMILY_IPV4, kPort);
+ EXPECT_TRUE(q1.IsValid());
+ EXPECT_EQ(kPort, q1.port());
+ EXPECT_EQ(kDNS_A, q1.qtype());
+ EXPECT_EQ(kHostname, q1.hostname());
+
+ uint8 id_hi = q1.id() >> 8, id_lo = q1.id() & 0xff;
+
+ // See the top of the file for the description of a DNS query.
+ const uint8 query_data[] = {
+ // Header
+ id_hi, id_lo,
+ 0x01, 0x00, // Flags -- set RD (recursion desired) bit.
+ 0x00, 0x01, // Set QDCOUNT (question count) to 1, all the
+ // rest are 0 for a query.
+ 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00,
+
+ // Question
+ 0x03, 0x77, 0x77, 0x77, // QNAME: www.google.com in DNS format.
+ 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+ 0x03, 0x63, 0x6f, 0x6d, 0x00,
+
+ 0x00, 0x01, // QTYPE: A query.
+ 0x00, 0x01, // QCLASS: IN class.
+ };
+
+ int expected_size = arraysize(query_data);
+ EXPECT_EQ(expected_size, q1.io_buffer()->size());
+ EXPECT_EQ(0, memcmp(q1.io_buffer()->data(), query_data,
+ q1.io_buffer()->size()));
+
+ // Query with a long hostname.
+ const char hostname_too_long[] = "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.1234";
+
+ DnsQuery q2(hostname_too_long, ADDRESS_FAMILY_IPV4, kPort);
+ EXPECT_FALSE(q2.IsValid());
+}
+
+} // namespace net
diff --git a/net/base/dns_response.cc b/net/base/dns_response.cc
new file mode 100644
index 0000000..9cfbae2
--- /dev/null
+++ b/net/base/dns_response.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 2011 The Chromium 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 "net/base/dns_response.h"
+
+#include "net/base/address_list.h"
+#include "net/base/dns_util.h"
+#include "net/base/net_errors.h"
+
+namespace net {
+
+// 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 kMaxResponseSize = 512;
+
+DnsResponse::DnsResponse(DnsQuery* query)
+ : query_(query),
+ io_buffer_(new IOBufferWithSize(kMaxResponseSize + 1)) {
+ DCHECK(query_);
+ DCHECK(query_->IsValid());
+}
+
+DnsResponse::~DnsResponse() {
+}
+
+int DnsResponse::Parse(int nbytes, AddressList* results) {
+ DCHECK(query_->IsValid());
+
+ // Response includes query, it should be at least that size.
+ if (nbytes < query_->io_buffer()->size() || nbytes > kMaxResponseSize)
+ return ERR_DNS_MALFORMED_RESPONSE;
+
+ DnsResponseBuffer response(reinterpret_cast<uint8*>(io_buffer_->data()),
+ io_buffer_->size());
+ uint16 id;
+ if (!response.U16(&id) || id != query_->id()) // Make sure IDs match.
+ return ERR_DNS_MALFORMED_RESPONSE;
+
+ uint8 flags, rcode;
+ if (!response.U8(&flags) || !response.U8(&rcode))
+ return ERR_DNS_MALFORMED_RESPONSE;
+
+ if (flags & 2) // TC is set -- server wants TCP, we don't support it (yet?).
+ return ERR_DNS_SERVER_REQUIRES_TCP;
+
+ rcode &= 0x0f; // 3 means NXDOMAIN, the rest means server failed.
+ if (rcode && (rcode != 3))
+ return ERR_DNS_SERVER_FAILED;
+
+ uint16 query_count, answer_count, authority_count, additional_count;
+ if (!response.U16(&query_count) ||
+ !response.U16(&answer_count) ||
+ !response.U16(&authority_count) ||
+ !response.U16(&additional_count)) {
+ return ERR_DNS_MALFORMED_RESPONSE;
+ }
+
+ if (query_count != 1) // Sent a single question, shouldn't have changed.
+ return ERR_DNS_MALFORMED_RESPONSE;
+
+ std::string hostname;
+ uint16 qtype, qclass;
+ if (!response.DNSName(&hostname) ||
+ !response.U16(&qtype) ||
+ !response.U16(&qclass) ||
+ hostname != query_->hostname() || // Make sure Question section
+ qtype != query_->qtype() || // echoed back.
+ qclass != kClassIN) {
+ return ERR_DNS_MALFORMED_RESPONSE;
+ }
+
+ if (answer_count < 1)
+ return ERR_NAME_NOT_RESOLVED;
+
+ std::vector<IPAddressNumber> rdatas;
+ while (answer_count--) {
+ uint32 ttl;
+ uint16 rdlength;
+ if (!response.DNSName(NULL) ||
+ !response.U16(&qtype) ||
+ !response.U16(&qclass) ||
+ !response.U32(&ttl) ||
+ !response.U16(&rdlength)) {
+ return ERR_DNS_MALFORMED_RESPONSE;
+ }
+
+ if (qtype == query_->qtype() &&
+ qclass == kClassIN &&
+ (rdlength == kIPv4AddressSize || rdlength == kIPv6AddressSize)) {
+ base::StringPiece rdata;
+ if (!response.Block(&rdata, rdlength))
+ return ERR_DNS_MALFORMED_RESPONSE;
+ rdatas.push_back(IPAddressNumber(rdata.begin(), rdata.end()));
+ } else if (!response.Skip(rdlength))
+ return ERR_DNS_MALFORMED_RESPONSE;
+ }
+
+ if (rdatas.empty())
+ return ERR_NAME_NOT_RESOLVED;
+
+ *results = AddressList::CreateFromIPAddressList(rdatas, query_->port());
+ return OK;
+}
+
+} // namespace net
diff --git a/net/base/dns_response.h b/net/base/dns_response.h
new file mode 100644
index 0000000..39ee47d
--- /dev/null
+++ b/net/base/dns_response.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2011 The Chromium 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 NET_BASE_DNS_RESPONSE_H_
+#define NET_BASE_DNS_RESPONSE_H_
+#pragma once
+
+#include "net/base/dns_query.h"
+
+namespace net{
+
+class AddressList;
+
+// A class that encapsulates bits and pieces related to DNS response
+// processing.
+class DnsResponse {
+ public:
+ // Constructs an object with an IOBuffer large enough to read
+ // one byte more than largest possible response, to detect malformed
+ // responses; |query| is a pointer to the DnsQuery for which |this|
+ // is supposed to be a response.
+ explicit DnsResponse(DnsQuery* query);
+ ~DnsResponse();
+
+ // Internal buffer accessor into which actual bytes of response will be
+ // read.
+ IOBufferWithSize* io_buffer() { return io_buffer_.get(); }
+
+ // Parses response of size nbytes and puts address into |results|,
+ // returns net_error code in case of failure.
+ int Parse(int nbytes, AddressList* results);
+
+ private:
+ // The matching query; |this| is the response for |query_|. We do not
+ // own it, lifetime of |this| should be within the limits of lifetime of
+ // |query_|.
+ const DnsQuery* const query_;
+
+ // Buffer into which response bytes are read.
+ scoped_refptr<IOBufferWithSize> io_buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(DnsResponse);
+};
+
+} // namespace net
+
+#endif // NET_BASE_DNS_RESPONSE_H_
diff --git a/net/base/dns_response_unittest.cc b/net/base/dns_response_unittest.cc
new file mode 100644
index 0000000..df56d2f
--- /dev/null
+++ b/net/base/dns_response_unittest.cc
@@ -0,0 +1,152 @@
+// Copyright (c) 2011 The Chromium 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 "net/base/address_list.h"
+#include "net/base/dns_response.h"
+#include "net/base/net_errors.h"
+#include "net/base/sys_addrinfo.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+// DNS response consists of a header followed by a question followed by
+// answer. Header format, question format and response format are
+// described below. For the meaning of specific fields, please see RFC
+// 1035.
+
+// 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 | 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 |
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+// Answser 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 /
+// / /
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+
+TEST(DnsResponseTest, ResponseWithCnameA) {
+ const std::string kHostname = "codereview.chromium.org";
+ const uint16 kPort = 80;
+
+ DnsQuery q1(kHostname, ADDRESS_FAMILY_IPV4, kPort);
+ uint8 id_hi = q1.id() >> 8, id_lo = q1.id() & 0xff;
+
+ uint8 ip[] = { // codereview.chromium.org resolves to
+ 0x4a, 0x7d, 0x5f, 0x79 // 74.125.95.121
+ };
+
+ uint8 response_data[] = {
+ // Header
+ id_hi, id_lo, // ID
+ 0x81, 0x80, // Standard query response, no error
+ 0x00, 0x01, // 1 question
+ 0x00, 0x02, // 2 RRs (answers)
+ 0x00, 0x00, // 0 authority RRs
+ 0x00, 0x00, // 0 additional RRs
+
+ // Question
+ 0x0a, 0x63, 0x6f, 0x64, // This part is echoed back from the
+ 0x65, 0x72, 0x65, 0x76, // respective query.
+ 0x69, 0x65, 0x77, 0x08,
+ 0x63, 0x68, 0x72, 0x6f,
+ 0x6d, 0x69, 0x75, 0x6d,
+ 0x03, 0x6f, 0x72, 0x67,
+ 0x00,
+ 0x00, 0x01,
+ 0x00, 0x01,
+
+ // Answer 1
+ 0xc0, 0x0c, // NAME is a pointer to name in Question section.
+ 0x00, 0x05, // TYPE is CNAME.
+ 0x00, 0x01, // CLASS is IN.
+ 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
+ 0x24, 0x74,
+ 0x00, 0x12, // RDLENGTH is 18 bytse.
+ 0x03, 0x67, 0x68, 0x73, // ghs.l.google.com in DNS format.
+ 0x01, 0x6c, 0x06, 0x67,
+ 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x03, 0x63, 0x6f,
+ 0x6d, 0x00,
+
+ // Answer 2
+ 0xc0, 0x35, // NAME is a pointer to name in Question section.
+ 0x00, 0x01, // TYPE is A.
+ 0x00, 0x01, // CLASS is IN.
+ 0x00, 0x00, // TTL (4 bytes) is 53 seconds.
+ 0x00, 0x35,
+ 0x00, 0x04, // RDLENGTH is 4 bytes.
+ ip[0], ip[1], ip[2], ip[3], // RDATA is the IP.
+ };
+
+ // Create a response object and simulate reading into it.
+ DnsResponse r1(&q1);
+ memcpy(r1.io_buffer()->data(), &response_data[0],
+ r1.io_buffer()->size());
+
+ int response_size = arraysize(response_data);
+ AddressList address_list;
+ EXPECT_EQ(OK, r1.Parse(response_size, &address_list));
+
+ // Verify AddressList content.
+ size_t sockaddr_size = sizeof(struct sockaddr_in);
+ const struct addrinfo* ai = address_list.head();
+ EXPECT_EQ(kPort, address_list.GetPort());
+
+ // addrinfo part.
+ EXPECT_TRUE(ai != NULL);
+ EXPECT_EQ(AF_INET, ai->ai_family);
+ EXPECT_EQ(SOCK_STREAM, ai->ai_socktype);
+ EXPECT_EQ(sockaddr_size, ai->ai_addrlen);
+
+ // sockaddr_in part.
+ struct sockaddr_in* sa = reinterpret_cast<sockaddr_in*>(ai->ai_addr);
+ ASSERT_TRUE(sa != NULL);
+ EXPECT_EQ(AF_INET, sa->sin_family);
+ EXPECT_EQ(kPort, ntohs(sa->sin_port));
+ EXPECT_EQ(0, memcmp(&sa->sin_addr, &ip[0], kIPv4AddressSize));
+}
+
+} // namespace net
diff --git a/net/base/dns_util.h b/net/base/dns_util.h
index 6c940c1..939a4a7 100644
--- a/net/base/dns_util.h
+++ b/net/base/dns_util.h
@@ -31,13 +31,17 @@ NET_TEST bool IsSTD3ASCIIValidCharacter(char c);
// Returns the hostname by trimming the ending dot, if one exists.
NET_API std::string TrimEndingDot(const std::string& host);
+// DNS class types.
+static const uint16 kClassIN = 1;
+
// DNS resource record types. See
// http://www.iana.org/assignments/dns-parameters
// WARNING: if you're adding any new values here you may need to add them to
// dnsrr_resolver.cc:DnsRRIsParsedByWindows.
-
+static const uint16 kDNS_A = 1;
static const uint16 kDNS_CNAME = 5;
static const uint16 kDNS_TXT = 16;
+static const uint16 kDNS_AAAA = 28;
static const uint16 kDNS_CERT = 37;
static const uint16 kDNS_DS = 43;
static const uint16 kDNS_RRSIG = 46;
diff --git a/net/base/dnsrr_resolver.cc b/net/base/dnsrr_resolver.cc
index 454a9fe..81f9111 100644
--- a/net/base/dnsrr_resolver.cc
+++ b/net/base/dnsrr_resolver.cc
@@ -98,7 +98,6 @@ static bool DnsRRIsParsedByWindows(uint16 rrtype) {
}
#endif
-static const uint16 kClassIN = 1;
// kMaxCacheEntries is the number of RRResponse objects that we'll cache.
static const unsigned kMaxCacheEntries = 32;
// kNegativeTTLSecs is the number of seconds for which we'll cache a negative
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h
index 19e5da0..9edc9ce 100644
--- a/net/base/net_error_list.h
+++ b/net/base/net_error_list.h
@@ -231,6 +231,23 @@ NET_ERROR(SSL_CLIENT_AUTH_SIGNATURE_FAILED, -141)
// which exceeds size threshold).
NET_ERROR(MSG_TOO_BIG, -142)
+// DNS resolver received a malformed response.
+NET_ERROR(DNS_MALFORMED_RESPONSE, -143)
+
+// DNS server requires TCP
+NET_ERROR(DNS_SERVER_REQUIRES_TCP, -144)
+
+// DNS server failed. This error is returned for all of the following
+// error conditions:
+// 1 - Format error - The name server was unable to interpret the query.
+// 2 - Server failure - The name server was unable to process this query
+// due to a problem with the name server.
+// 4 - Not Implemented - The name server does not support the requested
+// kind of query.
+// 5 - Refused - The name server refuses to perform the specified
+// operation for policy reasons.
+NET_ERROR(DNS_SERVER_FAILED, -145)
+
// Certificate error codes
//
// The values of certificate error codes must be consecutive.
diff --git a/net/net.gyp b/net/net.gyp
index 28173e4..b73eead 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -69,6 +69,10 @@
'base/data_url.h',
'base/directory_lister.cc',
'base/directory_lister.h',
+ 'base/dns_query.cc',
+ 'base/dns_query.h',
+ 'base/dns_response.cc',
+ 'base/dns_response.h',
'base/dns_reload_timer.cc',
'base/dns_reload_timer.h',
'base/dnssec_chain_verifier.cc',
@@ -839,6 +843,8 @@
'base/crl_filter_unittest.cc',
'base/data_url_unittest.cc',
'base/directory_lister_unittest.cc',
+ 'base/dns_query_unittest.cc',
+ 'base/dns_response_unittest.cc',
'base/dnssec_unittest.cc',
'base/dns_util_unittest.cc',
'base/dnsrr_resolver_unittest.cc',