summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/dns/dns_protocol.h2
-rw-r--r--net/dns/record_parsed.cc58
-rw-r--r--net/dns/record_parsed.h54
-rw-r--r--net/dns/record_parsed_unittest.cc35
-rw-r--r--net/dns/record_rdata.cc131
-rw-r--r--net/dns/record_rdata.h149
-rw-r--r--net/dns/record_rdata_unittest.cc146
-rw-r--r--net/net.gyp21
8 files changed, 596 insertions, 0 deletions
diff --git a/net/dns/dns_protocol.h b/net/dns/dns_protocol.h
index bbd8fa2..99563b5 100644
--- a/net/dns/dns_protocol.h
+++ b/net/dns/dns_protocol.h
@@ -103,8 +103,10 @@ static const uint16 kClassIN = 1;
// http://www.iana.org/assignments/dns-parameters
static const uint16 kTypeA = 1;
static const uint16 kTypeCNAME = 5;
+static const uint16 kTypePTR = 12;
static const uint16 kTypeTXT = 16;
static const uint16 kTypeAAAA = 28;
+static const uint16 kTypeSRV = 33;
// DNS rcode values.
static const uint8 kRcodeMask = 0xf;
diff --git a/net/dns/record_parsed.cc b/net/dns/record_parsed.cc
new file mode 100644
index 0000000..f02fbe3
--- /dev/null
+++ b/net/dns/record_parsed.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2013 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/dns/record_parsed.h"
+
+#include "net/dns/dns_response.h"
+#include "net/dns/record_rdata.h"
+
+namespace net {
+
+RecordParsed::RecordParsed(const std::string& name, uint16 type, uint16 klass,
+ uint32 ttl, scoped_ptr<const RecordRdata> rdata)
+ : name_(name), type_(type), klass_(klass), ttl_(ttl), rdata_(rdata.Pass()) {
+}
+
+RecordParsed::~RecordParsed() {
+}
+
+// static
+scoped_ptr<const RecordParsed> RecordParsed::CreateFrom(
+ DnsRecordParser* parser) {
+ DnsResourceRecord record;
+ scoped_ptr<const RecordRdata> rdata;
+
+ if (!parser->ReadRecord(&record))
+ return scoped_ptr<const RecordParsed>();
+
+ switch (record.type) {
+ case ARecordRdata::kType:
+ rdata = ARecordRdata::Create(record.rdata, *parser);
+ break;
+ case CnameRecordRdata::kType:
+ rdata = CnameRecordRdata::Create(record.rdata, *parser);
+ break;
+ case PtrRecordRdata::kType:
+ rdata = PtrRecordRdata::Create(record.rdata, *parser);
+ break;
+ case SrvRecordRdata::kType:
+ rdata = SrvRecordRdata::Create(record.rdata, *parser);
+ break;
+ case TxtRecordRdata::kType:
+ rdata = TxtRecordRdata::Create(record.rdata, *parser);
+ break;
+ default:
+ return scoped_ptr<const RecordParsed>();
+ }
+
+ if (!rdata.get())
+ return scoped_ptr<const RecordParsed>();
+
+ return scoped_ptr<const RecordParsed>(new RecordParsed(record.name,
+ record.type,
+ record.klass,
+ record.ttl,
+ rdata.Pass()));
+}
+}
diff --git a/net/dns/record_parsed.h b/net/dns/record_parsed.h
new file mode 100644
index 0000000..da58b26
--- /dev/null
+++ b/net/dns/record_parsed.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2013 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_DNS_RECORD_PARSED_H_
+#define NET_DNS_RECORD_PARSED_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+class DnsRecordParser;
+class RecordRdata;
+
+// Parsed record. This is a form of DnsResourceRecord where the rdata section
+// has been parsed into a data structure.
+class NET_EXPORT_PRIVATE RecordParsed {
+ public:
+ virtual ~RecordParsed();
+
+ // All records are inherently immutable. Return a const pointer.
+ static scoped_ptr<const RecordParsed> CreateFrom(DnsRecordParser* parser);
+
+ const std::string& name() const { return name_; }
+ uint16 type() const { return type_; }
+ uint16 klass() const { return klass_; }
+ uint32 ttl() const { return ttl_; }
+
+ template <class T> const T* rdata() const {
+ if (T::kType != type_)
+ return NULL;
+ return static_cast<const T*>(rdata_.get());
+ }
+
+ private:
+ RecordParsed(const std::string& name, uint16 type, uint16 klass, uint32 ttl,
+ scoped_ptr<const RecordRdata> rdata);
+
+ std::string name_; // in dotted form
+ const uint16 type_;
+ const uint16 klass_;
+ const uint32 ttl_;
+
+ const scoped_ptr<const RecordRdata> rdata_;
+
+ DISALLOW_COPY_AND_ASSIGN(RecordParsed);
+};
+
+} // namespace net
+
+#endif // NET_DNS_RECORD_PARSED_H_
diff --git a/net/dns/record_parsed_unittest.cc b/net/dns/record_parsed_unittest.cc
new file mode 100644
index 0000000..bb82b53
--- /dev/null
+++ b/net/dns/record_parsed_unittest.cc
@@ -0,0 +1,35 @@
+// Copyright (c) 2013 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/dns/record_parsed.h"
+
+#include "net/dns/dns_protocol.h"
+#include "net/dns/dns_response.h"
+#include "net/dns/dns_test_util.h"
+#include "net/dns/record_rdata.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+TEST(RecordParsedTest, ParseSingleRecord) {
+ DnsRecordParser parser(kT1ResponseDatagram, sizeof(kT1ResponseDatagram),
+ sizeof(dns_protocol::Header));
+ scoped_ptr<const RecordParsed> record;
+ const CnameRecordRdata* rdata;
+
+ parser.SkipQuestion();
+ record = RecordParsed::CreateFrom(&parser);
+ EXPECT_TRUE(record != NULL);
+
+ ASSERT_EQ("codereview.chromium.org", record->name());
+ ASSERT_EQ(dns_protocol::kTypeCNAME, record->type());
+ ASSERT_EQ(dns_protocol::kClassIN, record->klass());
+
+ rdata = record->rdata<CnameRecordRdata>();
+ ASSERT_TRUE(rdata != NULL);
+ ASSERT_EQ(kT1CanonName, rdata->cname());
+
+ ASSERT_FALSE(record->rdata<SrvRecordRdata>());
+}
+}
diff --git a/net/dns/record_rdata.cc b/net/dns/record_rdata.cc
new file mode 100644
index 0000000..1de3a4c
--- /dev/null
+++ b/net/dns/record_rdata.cc
@@ -0,0 +1,131 @@
+// Copyright (c) 2013 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/dns/record_rdata.h"
+
+#include "net/base/big_endian.h"
+#include "net/base/dns_util.h"
+#include "net/dns/dns_protocol.h"
+#include "net/dns/dns_response.h"
+
+namespace net {
+
+static const size_t kSrvRecordMinimumSize = 6;
+
+RecordRdata::RecordRdata() {
+}
+
+SrvRecordRdata::SrvRecordRdata() : priority_(0), weight_(0), port_(0) {
+}
+
+SrvRecordRdata::~SrvRecordRdata() {}
+
+// static
+scoped_ptr<SrvRecordRdata> SrvRecordRdata::Create(
+ const base::StringPiece& data,
+ const DnsRecordParser& parser) {
+ if (data.size() < kSrvRecordMinimumSize) return scoped_ptr<SrvRecordRdata>();
+
+ scoped_ptr<SrvRecordRdata> rdata(new SrvRecordRdata);
+
+ BigEndianReader reader(data.data(), data.size());
+ // 2 bytes for priority, 2 bytes for weight, 2 bytes for port.
+ reader.ReadU16(&rdata->priority_);
+ reader.ReadU16(&rdata->weight_);
+ reader.ReadU16(&rdata->port_);
+
+ if (!parser.ReadName(data.substr(kSrvRecordMinimumSize).begin(),
+ &rdata->target_))
+ return scoped_ptr<SrvRecordRdata>();
+
+ return rdata.Pass();
+}
+
+ARecordRdata::ARecordRdata() {
+}
+
+ARecordRdata::~ARecordRdata() {
+}
+
+// static
+scoped_ptr<ARecordRdata> ARecordRdata::Create(
+ const base::StringPiece& data,
+ const DnsRecordParser& parser) {
+ if (data.size() != kIPv4AddressSize)
+ return scoped_ptr<ARecordRdata>();
+
+ scoped_ptr<ARecordRdata> rdata(new ARecordRdata);
+
+ rdata->address_.resize(kIPv4AddressSize);
+ for (unsigned i = 0; i < kIPv4AddressSize; ++i) {
+ rdata->address_[i] = data[i];
+ }
+
+ return rdata.Pass();
+}
+
+CnameRecordRdata::CnameRecordRdata() {
+}
+
+CnameRecordRdata::~CnameRecordRdata() {
+}
+
+// static
+scoped_ptr<CnameRecordRdata> CnameRecordRdata::Create(
+ const base::StringPiece& data,
+ const DnsRecordParser& parser) {
+ scoped_ptr<CnameRecordRdata> rdata(new CnameRecordRdata);
+
+ if (!parser.ReadName(data.begin(), &rdata->cname_))
+ return scoped_ptr<CnameRecordRdata>();
+
+ return rdata.Pass();
+}
+
+PtrRecordRdata::PtrRecordRdata() {
+}
+
+PtrRecordRdata::~PtrRecordRdata() {
+}
+
+// static
+scoped_ptr<PtrRecordRdata> PtrRecordRdata::Create(
+ const base::StringPiece& data,
+ const DnsRecordParser& parser) {
+ scoped_ptr<PtrRecordRdata> rdata(new PtrRecordRdata);
+
+ if (!parser.ReadName(data.begin(), &rdata->ptrdomain_))
+ return scoped_ptr<PtrRecordRdata>();
+
+ return rdata.Pass();
+}
+
+TxtRecordRdata::TxtRecordRdata() {
+}
+
+TxtRecordRdata::~TxtRecordRdata() {
+}
+
+// static
+scoped_ptr<TxtRecordRdata> TxtRecordRdata::Create(
+ const base::StringPiece& data,
+ const DnsRecordParser& parser) {
+ scoped_ptr<TxtRecordRdata> rdata(new TxtRecordRdata);
+
+ for (size_t i = 0; i < data.size(); ) {
+ uint8 length = data[i];
+
+ if (i + length >= data.size())
+ return scoped_ptr<TxtRecordRdata>();
+
+ rdata->texts_.push_back(data.substr(i + 1, length).as_string());
+
+ // Move to the next string.
+ i += length + 1;
+ }
+
+ return rdata.Pass();
+}
+
+} // namespace net
diff --git a/net/dns/record_rdata.h b/net/dns/record_rdata.h
new file mode 100644
index 0000000..76e9b37
--- /dev/null
+++ b/net/dns/record_rdata.h
@@ -0,0 +1,149 @@
+// Copyright (c) 2013 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_DNS_RECORD_RDATA_H_
+#define NET_DNS_RECORD_RDATA_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_piece.h"
+#include "net/base/big_endian.h"
+#include "net/base/net_export.h"
+#include "net/base/net_util.h"
+#include "net/dns/dns_protocol.h"
+
+namespace net {
+
+class DnsRecordParser;
+
+// Parsed represenation of the extra data in a record. Does not include standard
+// DNS record data such as TTL, Name, Type and Class.
+class NET_EXPORT_PRIVATE RecordRdata {
+ public:
+ virtual ~RecordRdata() {}
+
+ protected:
+ RecordRdata();
+
+ DISALLOW_COPY_AND_ASSIGN(RecordRdata);
+};
+
+// SRV record format (http://www.ietf.org/rfc/rfc2782.txt):
+// 2 bytes network-order unsigned priority
+// 2 bytes network-order unsigned weight
+// 2 bytes network-order unsigned port
+// target: domain name (on-the-wire representation)
+class NET_EXPORT_PRIVATE SrvRecordRdata : public RecordRdata {
+ public:
+ static const uint16 kType = dns_protocol::kTypeSRV;
+
+ virtual ~SrvRecordRdata();
+ static scoped_ptr<SrvRecordRdata> Create(const base::StringPiece& data,
+ const DnsRecordParser& parser);
+
+ uint16 priority() const { return priority_; }
+ uint16 weight() const { return weight_; }
+ uint16 port() const { return port_; }
+
+ const std::string& target() const { return target_; }
+
+ private:
+ SrvRecordRdata();
+
+ uint16 priority_;
+ uint16 weight_;
+ uint16 port_;
+
+ std::string target_;
+
+ DISALLOW_COPY_AND_ASSIGN(SrvRecordRdata);
+};
+
+// A Record format (http://www.ietf.org/rfc/rfc1035.txt):
+// 4 bytes for IP address.
+class NET_EXPORT_PRIVATE ARecordRdata : public RecordRdata {
+ public:
+ static const uint16 kType = dns_protocol::kTypeA;
+
+ virtual ~ARecordRdata();
+ static scoped_ptr<ARecordRdata> Create(const base::StringPiece& data,
+ const DnsRecordParser& parser);
+
+ const IPAddressNumber& address() const { return address_; }
+
+ private:
+ ARecordRdata();
+
+ IPAddressNumber address_;
+
+ DISALLOW_COPY_AND_ASSIGN(ARecordRdata);
+};
+
+// CNAME record format (http://www.ietf.org/rfc/rfc1035.txt):
+// cname: On the wire representation of domain name.
+class NET_EXPORT_PRIVATE CnameRecordRdata : public RecordRdata {
+ public:
+ static const uint16 kType = dns_protocol::kTypeCNAME;
+
+ virtual ~CnameRecordRdata();
+ static scoped_ptr<CnameRecordRdata> Create(const base::StringPiece& data,
+ const DnsRecordParser& parser);
+
+ std::string cname() const { return cname_; }
+
+ private:
+ CnameRecordRdata();
+
+ std::string cname_;
+
+ DISALLOW_COPY_AND_ASSIGN(CnameRecordRdata);
+};
+
+// PTR record format (http://www.ietf.org/rfc/rfc1035.txt):
+// domain: On the wire representation of domain name.
+class NET_EXPORT_PRIVATE PtrRecordRdata : public RecordRdata {
+ public:
+ static const uint16 kType = dns_protocol::kTypePTR;
+
+ virtual ~PtrRecordRdata();
+ static scoped_ptr<PtrRecordRdata> Create(const base::StringPiece& data,
+ const DnsRecordParser& parser);
+
+ std::string ptrdomain() const { return ptrdomain_; }
+
+ private:
+ PtrRecordRdata();
+
+ std::string ptrdomain_;
+
+ DISALLOW_COPY_AND_ASSIGN(PtrRecordRdata);
+};
+
+// TXT record format (http://www.ietf.org/rfc/rfc1035.txt):
+// texts: One or more <character-string>s.
+// a <character-string> is a length octet followed by as many characters.
+class NET_EXPORT_PRIVATE TxtRecordRdata : public RecordRdata {
+ public:
+ static const uint16 kType = dns_protocol::kTypeTXT;
+
+ virtual ~TxtRecordRdata();
+ static scoped_ptr<TxtRecordRdata> Create(const base::StringPiece& data,
+ const DnsRecordParser& parser);
+
+ const std::vector<std::string>& texts() const { return texts_; }
+
+ private:
+ TxtRecordRdata();
+
+ std::vector<std::string> texts_;
+
+ DISALLOW_COPY_AND_ASSIGN(TxtRecordRdata);
+};
+}
+
+#endif // NET_DNS_RECORD_RDATA_H_
diff --git a/net/dns/record_rdata_unittest.cc b/net/dns/record_rdata_unittest.cc
new file mode 100644
index 0000000..c046b6f
--- /dev/null
+++ b/net/dns/record_rdata_unittest.cc
@@ -0,0 +1,146 @@
+// Copyright (c) 2013 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 "base/memory/scoped_ptr.h"
+#include "net/dns/record_rdata.h"
+#include "net/dns/dns_response.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+TEST(RecordRdataTest, ParseSrvRecord) {
+ scoped_ptr<SrvRecordRdata> record1_obj;
+ scoped_ptr<SrvRecordRdata> record2_obj;
+
+ // These are just the rdata portions of the DNS records, rather than complete
+ // records, but it works well enough for this test.
+
+ const char record[] = {
+ 0x00, 0x01,
+ 0x00, 0x02,
+ 0x00, 0x50,
+ 0x03, 'w', 'w', 'w',
+ 0x06, 'g', 'o', 'o', 'g', 'l', 'e',
+ 0x03, 'c', 'o', 'm',
+ 0x00,
+ 0x01, 0x01,
+ 0x01, 0x02,
+ 0x01, 0x03,
+ 0x04, 'w', 'w', 'w', '2',
+ 0xc0, 0x0a, // Pointer to "google.com"
+ };
+
+ DnsRecordParser parser(record, sizeof(record), 0);
+ const unsigned first_record_len = 22;
+ base::StringPiece record1_strpiece(record, first_record_len);
+ base::StringPiece record2_strpiece(
+ record + first_record_len, sizeof(record) - first_record_len);
+
+ record1_obj = SrvRecordRdata::Create(record1_strpiece, parser);
+ ASSERT_TRUE(record1_obj != NULL);
+ ASSERT_EQ(1, record1_obj->priority());
+ ASSERT_EQ(2, record1_obj->weight());
+ ASSERT_EQ(80, record1_obj->port());
+
+ ASSERT_EQ("www.google.com", record1_obj->target());
+
+ record2_obj = SrvRecordRdata::Create(record2_strpiece, parser);
+ ASSERT_TRUE(record2_obj != NULL);
+ ASSERT_EQ(257, record2_obj->priority());
+ ASSERT_EQ(258, record2_obj->weight());
+ ASSERT_EQ(259, record2_obj->port());
+
+ ASSERT_EQ("www2.google.com", record2_obj->target());
+}
+
+TEST(RecordRdataTest, ParseARecord) {
+ scoped_ptr<ARecordRdata> record_obj;
+
+ // These are just the rdata portions of the DNS records, rather than complete
+ // records, but it works well enough for this test.
+
+ const char record[] = {
+ 0x7F, 0x00, 0x00, 0x01 // 127.0.0.1
+ };
+
+ DnsRecordParser parser(record, sizeof(record), 0);
+ base::StringPiece record_strpiece(record, sizeof(record));
+
+ record_obj = ARecordRdata::Create(record_strpiece, parser);
+ ASSERT_TRUE(record_obj != NULL);
+
+ ASSERT_EQ("127.0.0.1", IPAddressToString(record_obj->address()));
+}
+
+TEST(RecordRdataTest, ParseCnameRecord) {
+ scoped_ptr<CnameRecordRdata> record_obj;
+
+ // These are just the rdata portions of the DNS records, rather than complete
+ // records, but it works well enough for this test.
+
+ const char record[] = {
+ 0x03, 'w', 'w', 'w',
+ 0x06, 'g', 'o', 'o', 'g', 'l', 'e',
+ 0x03, 'c', 'o', 'm',
+ 0x00
+ };
+
+ DnsRecordParser parser(record, sizeof(record), 0);
+ base::StringPiece record_strpiece(record, sizeof(record));
+
+ record_obj = CnameRecordRdata::Create(record_strpiece, parser);
+ ASSERT_TRUE(record_obj != NULL);
+
+ ASSERT_EQ("www.google.com", record_obj->cname());
+}
+
+TEST(RecordRdataTest, ParsePtrRecord) {
+ scoped_ptr<PtrRecordRdata> record_obj;
+
+ // These are just the rdata portions of the DNS records, rather than complete
+ // records, but it works well enough for this test.
+
+ const char record[] = {
+ 0x03, 'w', 'w', 'w',
+ 0x06, 'g', 'o', 'o', 'g', 'l', 'e',
+ 0x03, 'c', 'o', 'm',
+ 0x00
+ };
+
+ DnsRecordParser parser(record, sizeof(record), 0);
+ base::StringPiece record_strpiece(record, sizeof(record));
+
+ record_obj = PtrRecordRdata::Create(record_strpiece, parser);
+ ASSERT_TRUE(record_obj != NULL);
+
+ ASSERT_EQ("www.google.com", record_obj->ptrdomain());
+}
+
+TEST(RecordRdataTest, ParseTxtRecord) {
+ scoped_ptr<TxtRecordRdata> record_obj;
+
+ // These are just the rdata portions of the DNS records, rather than complete
+ // records, but it works well enough for this test.
+
+ const char record[] = {
+ 0x03, 'w', 'w', 'w',
+ 0x06, 'g', 'o', 'o', 'g', 'l', 'e',
+ 0x03, 'c', 'o', 'm'
+ };
+
+ DnsRecordParser parser(record, sizeof(record), 0);
+ base::StringPiece record_strpiece(record, sizeof(record));
+
+ record_obj = TxtRecordRdata::Create(record_strpiece, parser);
+ ASSERT_TRUE(record_obj != NULL);
+
+ std::vector<std::string> expected;
+ expected.push_back("www");
+ expected.push_back("google");
+ expected.push_back("com");
+
+ ASSERT_EQ(expected, record_obj->texts());
+}
+
+} // namespace net
diff --git a/net/net.gyp b/net/net.gyp
index eb5fc0a..05b9b01 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -444,6 +444,10 @@
'dns/mapped_host_resolver.h',
'dns/notify_watcher_mac.cc',
'dns/notify_watcher_mac.h',
+ 'dns/record_parsed.cc',
+ 'dns/record_parsed.h',
+ 'dns/record_rdata.cc',
+ 'dns/record_rdata.h',
'dns/serial_worker.cc',
'dns/serial_worker.h',
'dns/single_request_host_resolver.cc',
@@ -1277,6 +1281,14 @@
'spdy/spdy_websocket_stream.h',
],
}],
+ [ 'enable_mdns != 1', {
+ 'sources!' : [
+ 'dns/record_parsed.cc',
+ 'dns/record_parsed.h',
+ 'dns/record_rdata.cc',
+ 'dns/record_rdata.h',
+ ]
+ }],
[ 'OS == "win"', {
'sources!': [
'http/http_auth_handler_ntlm_portable.cc',
@@ -1509,6 +1521,8 @@
'dns/host_resolver_impl_unittest.cc',
'dns/mapped_host_resolver_unittest.cc',
'dns/serial_worker_unittest.cc',
+ 'dns/record_parsed_unittest.cc',
+ 'dns/record_rdata_unittest.cc',
'dns/single_request_host_resolver_unittest.cc',
'ftp/ftp_auth_cache_unittest.cc',
'ftp/ftp_ctrl_response_buffer_unittest.cc',
@@ -1882,6 +1896,13 @@
],
},
],
+
+ [ 'enable_mdns != 1', {
+ 'sources!' : [
+ 'dns/record_parsed_unittest.cc',
+ 'dns/record_rdata_unittest.cc',
+ ],
+ }],
[ 'OS == "win"', {
'sources!': [
'dns/dns_config_service_posix_unittest.cc',