0

Revert 87809 - Added DnsQuery class

BUG=60149
TEST=dns_query_unittests

Review URL: http://codereview.chromium.org/7008021

TBR=agayev@chromium.org
Review URL: http://codereview.chromium.org/7056050

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@87812 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
agayev@chromium.org
2011-06-03 18:22:55 +00:00
parent 6a991cfd99
commit 16f473e080
10 changed files with 2 additions and 618 deletions

@ -1,108 +0,0 @@
// 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_);
}
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

@ -1,71 +0,0 @@
// 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);
// 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_

@ -1,109 +0,0 @@
// 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 int 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 int 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

@ -1,103 +0,0 @@
// 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());
}
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

@ -1,47 +0,0 @@
// 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);
// 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_

@ -1,152 +0,0 @@
// 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 int 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

@ -31,17 +31,13 @@ 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;

@ -98,6 +98,7 @@ 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

@ -231,23 +231,6 @@ 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.

@ -69,10 +69,6 @@
'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',
@ -843,8 +839,6 @@
'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',