diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-04 15:54:40 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-04 15:54:40 +0000 |
commit | b3ccac85bee8a3d89c7b5ca3a64ee311f3f565c3 (patch) | |
tree | 6a156892643928ceb04c3c6fe33243c2c9946bee | |
parent | 973ce28247510567d996b91ad5aa3f1da590fbcc (diff) | |
download | chromium_src-b3ccac85bee8a3d89c7b5ca3a64ee311f3f565c3.zip chromium_src-b3ccac85bee8a3d89c7b5ca3a64ee311f3f565c3.tar.gz chromium_src-b3ccac85bee8a3d89c7b5ca3a64ee311f3f565c3.tar.bz2 |
net: add DnsRRResovler to fetch arbitary DNS resource types.
(Linux/Mac only for now.)
TEST=net_unittests
BUG=none
http://codereview.chromium.org/3029035
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@54907 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | build/linux/system.gyp | 9 | ||||
-rw-r--r-- | net/base/dns_util.h | 10 | ||||
-rw-r--r-- | net/base/dnsrr_resolver.cc | 345 | ||||
-rw-r--r-- | net/base/dnsrr_resolver.h | 66 | ||||
-rw-r--r-- | net/base/dnsrr_resolver_unittest.cc | 154 | ||||
-rw-r--r-- | net/net.gyp | 4 |
6 files changed, 588 insertions, 0 deletions
diff --git a/build/linux/system.gyp b/build/linux/system.gyp index 876579a..f746ebf 100644 --- a/build/linux/system.gyp +++ b/build/linux/system.gyp @@ -308,6 +308,15 @@ ], }, }, + { + 'target_name': 'libresolv', + 'type': 'settings', + 'link_settings': { + 'libraries': [ + '-lresolv', + ], + }, + }, ], } diff --git a/net/base/dns_util.h b/net/base/dns_util.h index cd81420..88c48a8 100644 --- a/net/base/dns_util.h +++ b/net/base/dns_util.h @@ -8,6 +8,8 @@ #include <string> +#include "base/basictypes.h" + namespace net { // DNSDomainFromDot - convert a domain string to DNS format. From DJB's @@ -24,6 +26,14 @@ bool IsSTD3ASCIIValidCharacter(char c); // Returns the hostname by trimming the ending dot, if one exists. std::string TrimEndingDot(const std::string& host); +// DNS resource record types. See +// http://www.iana.org/assignments/dns-parameters + +static const uint16 kDNS_TXT = 16; +static const uint16 kDNS_RRSIG = 46; +static const uint16 kDNS_CERT = 37; +static const uint16 kDNS_ANY = 0xff; + } // namespace net #endif // NET_BASE_DNS_UTIL_H_ diff --git a/net/base/dnsrr_resolver.cc b/net/base/dnsrr_resolver.cc new file mode 100644 index 0000000..7a872dd --- /dev/null +++ b/net/base/dnsrr_resolver.cc @@ -0,0 +1,345 @@ +// Copyright (c) 2010 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/dnsrr_resolver.h" + +#if defined(OS_POSIX) +#include <resolv.h> +#endif + +#include "base/string_piece.h" +#include "base/task.h" +#include "base/worker_pool.h" +#include "net/base/dns_reload_timer.h" +#include "net/base/dns_util.h" +#include "net/base/net_errors.h" + +namespace net { + +static const uint16 kClassIN = 1; + +#if defined(OS_POSIX) + +// A Buffer is used for walking over a DNS packet. +class Buffer { + public: + Buffer(const uint8* p, unsigned len) + : p_(p), + packet_(p), + len_(len), + packet_len_(len) { + } + + bool U8(uint8* v) { + if (len_ < 1) + return false; + *v = *p_; + p_++; + len_--; + return true; + } + + bool U16(uint16* v) { + if (len_ < 2) + return false; + *v = static_cast<uint16>(p_[0]) << 8 | + static_cast<uint16>(p_[1]); + p_ += 2; + len_ -= 2; + return true; + } + + bool U32(uint32* v) { + if (len_ < 4) + return false; + *v = static_cast<uint32>(p_[0]) << 24 | + static_cast<uint32>(p_[1]) << 16 | + static_cast<uint32>(p_[2]) << 8 | + static_cast<uint32>(p_[3]); + p_ += 4; + len_ -= 4; + return true; + } + + bool Skip(unsigned n) { + if (len_ < n) + return false; + p_ += n; + len_ -= n; + return true; + } + + bool Block(base::StringPiece* out, unsigned len) { + if (len_ < len) + return false; + *out = base::StringPiece(reinterpret_cast<const char*>(p_), len); + p_ += len; + len_ -= len; + return true; + } + + // DNSName parses a (possibly compressed) DNS name from the packet. If |name| + // is not NULL, then the name is written into it. See RFC 1035 section 4.1.4. + bool DNSName(std::string* name) { + unsigned jumps = 0; + const uint8* p = p_; + unsigned len = len_; + + if (name) + name->clear(); + + for (;;) { + if (len < 1) + return false; + uint8 d = *p; + p++; + len--; + + // The two couple of 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. + if ((d & 0xc0) == 0xc0) { + // This limit matches the depth limit in djbdns. + if (jumps > 100) + return false; + if (len < 1) + return false; + uint16 offset = static_cast<uint16>(d) << 8 | + static_cast<uint16>(p[0]); + offset &= 0x3ff; + p++; + len--; + + if (jumps == 0) { + p_ = p; + len_ = len; + } + jumps++; + + if (offset >= packet_len_) + return false; + p = &packet_[offset]; + } else if ((d & 0xc0) == 0) { + uint8 label_len = d; + if (len < label_len) + return false; + if (name && label_len) { + if (!name->empty()) + name->append("."); + name->append(reinterpret_cast<const char*>(p), label_len); + } + p += label_len; + len -= label_len; + + if (jumps == 0) { + p_ = p; + len_ = len; + } + + if (label_len == 0) + break; + } else { + return false; + } + } + + return true; + } + + private: + const uint8* p_; + const uint8* const packet_; + unsigned len_; + const unsigned packet_len_; +}; + +bool DnsRRResolver::Response::ParseFromResponse(const uint8* p, unsigned len, + uint16 rrtype_requested) { + name.clear(); + ttl = 0; + dnssec = false; + rrdatas.clear(); + signatures.clear(); + + // RFC 1035 section 4.4.1 + uint8 flags2; + Buffer buf(p, len); + if (!buf.Skip(2) || // skip id + !buf.Skip(1) || // skip first flags byte + !buf.U8(&flags2)) { + return false; + } + + // Bit 5 is the Authenticated Data (AD) bit. See + // http://tools.ietf.org/html/rfc2535#section-6.1 + if (flags2 & 32) { + // AD flag is set. We'll trust it if it came from a local nameserver. + // Currently the resolv structure is IPv4 only, so we can't test for IPv6 + // loopback addresses. + if (_res.nscount == 1 && + memcmp(&_res.nsaddr_list[0].sin_addr, + "\x7f\x00\x00\x01" /* 127.0.0.1 */, 4) == 0) { + dnssec = true; + } + } + + uint16 query_count, answer_count, authority_count, additional_count; + if (!buf.U16(&query_count) || + !buf.U16(&answer_count) || + !buf.U16(&authority_count) || + !buf.U16(&additional_count)) { + return false; + } + + if (query_count != 1) + return false; + + uint16 type, klass; + if (!buf.DNSName(NULL) || + !buf.U16(&type) || + !buf.U16(&klass) || + type != rrtype_requested || + klass != kClassIN) { + return false; + } + + if (answer_count < 1) + return false; + + for (uint32 i = 0; i < answer_count; i++) { + std::string* name = NULL; + if (i == 0) + name = &this->name; + uint32 ttl; + uint16 rrdata_len; + if (!buf.DNSName(name) || + !buf.U16(&type) || + !buf.U16(&klass) || + !buf.U32(&ttl) || + !buf.U16(&rrdata_len)) { + return false; + } + + base::StringPiece rrdata; + if (!buf.Block(&rrdata, rrdata_len)) + return false; + + if (klass == kClassIN && type == rrtype_requested) { + if (i == 0) + this->ttl = ttl; + rrdatas.push_back(std::string(rrdata.data(), rrdata.size())); + } else if (klass == kClassIN && type == kDNS_RRSIG) { + signatures.push_back(std::string(rrdata.data(), rrdata.size())); + } + } + + return true; +} + +class ResolveTask : public Task { + public: + ResolveTask(const std::string& name, uint16 rrtype, + uint16 flags, CompletionCallback* callback, + DnsRRResolver::Response* response) + : name_(name), + rrtype_(rrtype), + flags_(flags), + callback_(callback), + response_(response) { + } + + virtual void Run() { + // Runs on a worker thread. + + if ((_res.options & RES_INIT) == 0) { + if (res_ninit(&_res) != 0) + return Failure(); + } + + unsigned long saved_options = _res.options; + bool r = Do(); + +#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) + if (!r && DnsReloadTimerHasExpired()) { + res_nclose(&_res); + if (res_ninit(&_res) == 0) + r = Do(); + } +#endif + _res.options = saved_options; + int error = r ? OK : ERR_NAME_NOT_RESOLVED; + callback_->Run(error); + } + + bool Do() { + // For DNSSEC, a 4K buffer is suggested + static const unsigned kMaxDNSPayload = 4096; + +#ifndef RES_USE_DNSSEC + // Some versions of libresolv don't have support for the DO bit. In this + // case, we proceed without it. + static const int RES_USE_DNSSEC = 0; +#endif + + // We set the options explicitly. Note that this removes several default + // options: RES_DEFNAMES and RES_DNSRCH (see res_init(3)). + _res.options = RES_INIT | RES_RECURSE | RES_USE_EDNS0 | RES_USE_DNSSEC; + uint8 answer[kMaxDNSPayload]; + int len = res_search(name_.c_str(), kClassIN, rrtype_, answer, + sizeof(answer)); + if (len == -1) + return false; + + return response_->ParseFromResponse(answer, len, rrtype_); + } + + private: + DISALLOW_COPY_AND_ASSIGN(ResolveTask); + + void Failure() { + callback_->Run(ERR_NAME_NOT_RESOLVED); + } + + const std::string name_; + const uint16 rrtype_; + const uint16 flags_; + CompletionCallback* const callback_; + DnsRRResolver::Response* const response_; +}; +#else // OS_POSIX +// On non-Linux platforms we fail everything for now. +class ResolveTask : public Task { + public: + ResolveTask(const std::string& name, uint16 rrtype, + uint16 flags, CompletionCallback* callback, + DnsRRResolver::Response* response) + : callback_(callback) { + } + + virtual void Run() { + callback_->Run(ERR_NAME_NOT_RESOLVED); + } + + private: + CompletionCallback* const callback_; + DISALLOW_COPY_AND_ASSIGN(ResolveTask); +}; +#endif + +// static +bool DnsRRResolver::Resolve(const std::string& name, uint16 rrtype, + uint16 flags, CompletionCallback* callback, + Response* response) { + if (!callback || !response || name.empty()) + return false; + + // Don't allow queries of type ANY + if (rrtype == kDNS_ANY) + return false; + + ResolveTask* task = new ResolveTask(name, rrtype, flags, callback, response); + + return WorkerPool::PostTask(FROM_HERE, task, true /* task is slow */); +} + +} // namespace net diff --git a/net/base/dnsrr_resolver.h b/net/base/dnsrr_resolver.h new file mode 100644 index 0000000..6dfea2f --- /dev/null +++ b/net/base/dnsrr_resolver.h @@ -0,0 +1,66 @@ +// Copyright (c) 2010 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_DNSRR_RESOLVER_H_ +#define NET_BASE_DNSRR_RESOLVER_H_ +#pragma once + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "build/build_config.h" +#include "net/base/completion_callback.h" + +namespace net { + +// DnsRRResolver resolves arbitary DNS resource record types. It should not be +// confused with HostResolver and should not be used to resolve A/AAAA records. +// +// HostResolver exists to lookup addresses and there are many details about +// address resolution over and above DNS (i.e. Bonjour, VPNs etc). +// +// DnsRRResolver should only be used when the data is specifically DNS data and +// the name is a fully qualified DNS domain. +class DnsRRResolver { + public: + // Response contains the details of a successful request. + struct Response { + // name contains the canonical name of the resulting domain. If the queried + // name was a CNAME then this can differ. + std::string name; + // ttl contains the TTL of the resource records. + uint32 ttl; + // dnssec is true if the response was DNSSEC validated. + bool dnssec; + std::vector<std::string> rrdatas; + // sigs contains the RRSIG records returned. + std::vector<std::string> signatures; + + // For testing only + bool ParseFromResponse(const uint8* data, unsigned len, + uint16 rrtype_requested); + }; + + enum { + // Try harder to get a DNSSEC signed response. This doesn't mean that the + // Response will always have the dnssec bit set. + FLAG_WANT_DNSSEC = 1, + }; + + // Resolve starts the resolution process. When complete, |callback| is called + // with a result. If the result is |OK| then |response| is filled with the + // result of the resolution. Note the |callback| is called from a random + // worker thread. + static bool Resolve(const std::string& name, uint16 rrtype, + uint16 flags, CompletionCallback* callback, + Response* response); + + private: + DISALLOW_COPY_AND_ASSIGN(DnsRRResolver); +}; + +} // namespace net + +#endif // NET_BASE_DNSRR_RESOLVER_H_ diff --git a/net/base/dnsrr_resolver_unittest.cc b/net/base/dnsrr_resolver_unittest.cc new file mode 100644 index 0000000..6e36126 --- /dev/null +++ b/net/base/dnsrr_resolver_unittest.cc @@ -0,0 +1,154 @@ +// Copyright (c) 2010 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/dnsrr_resolver.h" + +#include "base/callback.h" +#include "base/condition_variable.h" +#include "base/lock.h" +#include "net/base/dns_util.h" +#include "net/base/net_errors.h" +#include "net/base/test_completion_callback.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +class DnsRRResolverTest : public testing::Test { +}; + +#if defined(OS_LINUX) + +class Rendezvous : public CallbackRunner<Tuple1<int> > { + public: + Rendezvous() + : have_result_(false), + cv_(&lock_) { + } + + int WaitForResult() { + lock_.Acquire(); + while (!have_result_) + cv_.Wait(); + lock_.Release(); + return result_; + } + + virtual void RunWithParams(const Tuple1<int>& params) { + lock_.Acquire(); + result_ = params.a; + have_result_ = true; + lock_.Release(); + cv_.Broadcast(); + } + + private: + bool have_result_; + int result_; + Lock lock_; + ConditionVariable cv_; +}; + +// This test is disabled because it depends on the external network to pass. +// However, it may be useful when chaging the code. +TEST_F(DnsRRResolverTest, DISABLED_NetworkResolve) { + DnsRRResolver::Response response; + Rendezvous callback; + ASSERT_TRUE(DnsRRResolver::Resolve( + "agl._pka.imperialviolet.org", kDNS_TXT, 0, &callback, &response)); + ASSERT_EQ(OK, callback.WaitForResult()); + ASSERT_EQ(1u, response.rrdatas.size()); + ASSERT_EQ(1u, response.signatures.size()); + ASSERT_STREQ("]v=pka1;fpr=2AF0032B48E856CE06157A1AD43C670DE04AAA74;" + "uri=http://www.imperialviolet.org/key.asc", + response.rrdatas[0].c_str()); +} + +// This is a DNS packet resulting from querying a recursive resolver for a TXT +// record for agl._pka.imperialviolet.org. You should be able to get a +// replacement from a packet capture should it ever be needed. +static const uint8 kExamplePacket[] = { + 0xce, 0xfe, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x06, 0x00, 0x01, 0x03, + 0x61, 0x67, 0x6c, 0x04, 0x5f, 0x70, 0x6b, 0x61, 0x0e, 0x69, 0x6d, 0x70, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x76, 0x69, 0x6f, 0x6c, 0x65, 0x74, 0x03, 0x6f, 0x72, + 0x67, 0x00, 0x00, 0x10, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x10, 0x00, 0x01, 0x00, + 0x00, 0x01, 0x2c, 0x00, 0x5e, 0x5d, 0x76, 0x3d, 0x70, 0x6b, 0x61, 0x31, 0x3b, + 0x66, 0x70, 0x72, 0x3d, 0x32, 0x41, 0x46, 0x30, 0x30, 0x33, 0x32, 0x42, 0x34, + 0x38, 0x45, 0x38, 0x35, 0x36, 0x43, 0x45, 0x30, 0x36, 0x31, 0x35, 0x37, 0x41, + 0x31, 0x41, 0x44, 0x34, 0x33, 0x43, 0x36, 0x37, 0x30, 0x44, 0x45, 0x30, 0x34, + 0x41, 0x41, 0x41, 0x37, 0x34, 0x3b, 0x75, 0x72, 0x69, 0x3d, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6d, 0x70, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x76, 0x69, 0x6f, 0x6c, 0x65, 0x74, 0x2e, 0x6f, 0x72, 0x67, + 0x2f, 0x6b, 0x65, 0x79, 0x2e, 0x61, 0x73, 0x63, 0xc0, 0x0c, 0x00, 0x2e, 0x00, + 0x01, 0x00, 0x00, 0x01, 0x2c, 0x00, 0xc6, 0x00, 0x10, 0x05, 0x04, 0x00, 0x01, + 0x51, 0x80, 0x4c, 0x74, 0x2f, 0x1a, 0x4c, 0x4c, 0x9c, 0xeb, 0x45, 0xc9, 0x0e, + 0x69, 0x6d, 0x70, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x76, 0x69, 0x6f, 0x6c, 0x65, + 0x74, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x3b, 0x6d, 0x3d, 0xbb, 0xae, 0x1b, 0x07, + 0x8d, 0xa9, 0xb0, 0xa7, 0xa5, 0x7a, 0x84, 0x24, 0x34, 0x29, 0x43, 0x36, 0x3f, + 0x5a, 0x48, 0x3b, 0x79, 0xa3, 0x16, 0xa4, 0x28, 0x5b, 0xd7, 0x03, 0xc6, 0x93, + 0xba, 0x4e, 0x93, 0x4d, 0x18, 0x5c, 0x98, 0xc2, 0x0d, 0x57, 0xd2, 0x6b, 0x9a, + 0x72, 0xbd, 0xe5, 0x8d, 0x10, 0x7b, 0x03, 0xe7, 0x19, 0x1e, 0x51, 0xe5, 0x7e, + 0x49, 0x6b, 0xa3, 0xa8, 0xf1, 0xd3, 0x1b, 0xff, 0x40, 0x26, 0x82, 0x65, 0xd0, + 0x74, 0x8e, 0xcf, 0xc9, 0x71, 0xea, 0x91, 0x57, 0x7e, 0x50, 0x61, 0x4d, 0x4b, + 0x77, 0x05, 0x6a, 0xd8, 0x3f, 0x12, 0x87, 0x50, 0xc2, 0x35, 0x13, 0xab, 0x01, + 0x78, 0xd2, 0x3a, 0x55, 0xa2, 0x89, 0xc8, 0x87, 0xe2, 0x7b, 0xec, 0x51, 0x7c, + 0xc0, 0x24, 0xb5, 0xa3, 0x33, 0x78, 0x98, 0x28, 0x8e, 0x9b, 0x6b, 0x88, 0x13, + 0x25, 0xfa, 0x1d, 0xdc, 0xf1, 0xf0, 0xa6, 0x8d, 0x2a, 0xbb, 0xbc, 0xb0, 0xc7, + 0x97, 0x98, 0x8e, 0xef, 0xd9, 0x12, 0x24, 0xee, 0x38, 0x50, 0xdb, 0xd3, 0x59, + 0xcc, 0x30, 0x54, 0x4c, 0x38, 0x94, 0x24, 0xbc, 0x75, 0xa5, 0xc0, 0xc4, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x15, 0x02, 0x62, 0x30, 0x03, + 0x6f, 0x72, 0x67, 0x0b, 0x61, 0x66, 0x69, 0x6c, 0x69, 0x61, 0x73, 0x2d, 0x6e, + 0x73, 0x74, 0xc0, 0xc4, 0xc0, 0xc4, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x3a, 0x00, 0x19, 0x02, 0x63, 0x30, 0x03, 0x6f, 0x72, 0x67, 0x0b, 0x61, 0x66, + 0x69, 0x6c, 0x69, 0x61, 0x73, 0x2d, 0x6e, 0x73, 0x74, 0x04, 0x69, 0x6e, 0x66, + 0x6f, 0x00, 0xc0, 0xc4, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3a, 0x00, + 0x05, 0x02, 0x61, 0x30, 0xc1, 0x99, 0xc0, 0xc4, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x3a, 0x00, 0x05, 0x02, 0x62, 0x32, 0xc1, 0x78, 0xc0, 0xc4, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x05, 0x02, 0x64, 0x30, 0xc1, + 0x78, 0xc0, 0xc4, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x05, + 0x02, 0x61, 0x32, 0xc1, 0x99, 0x00, 0x00, 0x29, 0x10, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, +}; + +TEST_F(DnsRRResolverTest, ParseExample) { + DnsRRResolver::Response response; + ASSERT_TRUE(response.ParseFromResponse(kExamplePacket, + sizeof(kExamplePacket), kDNS_TXT)); + ASSERT_EQ(1u, response.rrdatas.size()); + ASSERT_EQ(1u, response.signatures.size()); + ASSERT_STREQ("agl._pka.imperialviolet.org", response.name.c_str()); + ASSERT_STREQ("]v=pka1;fpr=2AF0032B48E856CE06157A1AD43C670DE04AAA74;" + "uri=http://www.imperialviolet.org/key.asc", + response.rrdatas[0].c_str()); + ASSERT_FALSE(response.dnssec); +} + +TEST_F(DnsRRResolverTest, FuzzTruncation) { + DnsRRResolver::Response response; + + for (unsigned len = sizeof(kExamplePacket); len <= sizeof(kExamplePacket); + len--) { + response.ParseFromResponse(kExamplePacket, len, kDNS_TXT); + } +} + +TEST_F(DnsRRResolverTest, FuzzCorruption) { + DnsRRResolver::Response response; + uint8 copy[sizeof(kExamplePacket)]; + + + for (unsigned bit_to_corrupt = 0; bit_to_corrupt < sizeof(kExamplePacket) * 8; + bit_to_corrupt++) { + unsigned byte = bit_to_corrupt >> 3; + unsigned bit = bit_to_corrupt & 7; + + memcpy(copy, kExamplePacket, sizeof(copy)); + copy[byte] ^= (1 << bit); + + response.ParseFromResponse(copy, sizeof(copy), kDNS_TXT); + } +} + +#endif // OS_LINUX + +} // namespace net diff --git a/net/net.gyp b/net/net.gyp index 9ef2145..b7f6245 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -55,6 +55,8 @@ 'base/dns_reload_timer.h', 'base/dns_util.cc', 'base/dns_util.h', + 'base/dnsrr_resolver.cc', + 'base/dnsrr_resolver.h', 'base/escape.cc', 'base/escape.h', 'base/ev_root_ca_metadata.cc', @@ -188,6 +190,7 @@ '../build/linux/system.gyp:gconf', '../build/linux/system.gyp:gdk', '../build/linux/system.gyp:nss', + '../build/linux/system.gyp:libresolv', ], }, { # else: OS is not in the above list @@ -666,6 +669,7 @@ 'base/data_url_unittest.cc', 'base/directory_lister_unittest.cc', 'base/dns_util_unittest.cc', + 'base/dnsrr_resolver_unittest.cc', 'base/escape_unittest.cc', 'base/file_stream_unittest.cc', 'base/filter_unittest.cc', |