Index: net/base/dns_response.cc |
diff --git a/net/base/dns_response.cc b/net/base/dns_response.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..24065aa21a2edd76382e6dd44f8126afbbfb6530 |
--- /dev/null |
+++ b/net/base/dns_response.cc |
@@ -0,0 +1,112 @@ |
+// 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 <netdb.h> // for EAI_NONAME |
+ |
+#include "net/base/address_list.h" |
+#include "net/base/dns_util.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; |
+ |
+// TODO(agayev): decide on |error_|, should we emulate getaddrinfo error |
+// messages and continue with net_error and os_error scheme or should we |
+// define more net_error codes and get rid of os_error, since there is no |
+// "OS" anymore. Currently, |error_| is EAI_NONAME in case of an error, 0 |
+// otherwise. |
+DnsResponse::DnsResponse(DnsQuery* query) |
+ : error_(EAI_NONAME), |
+ size_(kMaxResponseSize + 1), |
+ query_(query), |
+ io_buffer_(new IOBufferWithSize(size_)) { |
cbentzel
2011/06/01 17:17:03
DCHECK(query_) in the constructor [and maybe query
agayev
2011/06/01 19:15:01
Done.
|
+} |
+ |
+bool DnsResponse::Parse(int nbytes, AddressList* results) { |
+ DCHECK(query_->IsValid()); |
+ |
+ // Response includes query, it should be at least that size. |
+ if (nbytes < query_->size() || nbytes > kMaxResponseSize) |
+ return false; |
+ |
+ size_ = nbytes; |
+ DnsResponseBuffer response(reinterpret_cast<uint8*>(io_buffer_->data()), |
+ size_); |
+ |
+ uint16 id; |
+ if (!response.U16(&id) || id != query_->id()) // Make sure IDs match. |
+ return false; |
+ |
+ uint8 flags, rcode; |
+ if (!response.U8(&flags) || !response.U8(&rcode)) |
+ return false; |
+ |
+ if (flags & 2) // TC is set -- server wants TCP, we don't support it (yet?). |
+ return false; |
+ |
+ rcode &= 0x0f; |
+ if (rcode && (rcode != 3)) // 3 means NXDOMAIN, the rest means server failed. |
+ return false; |
+ |
+ 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 false; |
+ } |
+ |
+ if (query_count != 1) // Sent a single question, shouldn't have changed. |
+ return false; |
+ |
+ 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 false; |
+ } |
+ |
+ if (answer_count < 1) |
+ return false; |
+ |
+ std::vector<IPAddressNumber> rdatas; |
+ while (answer_count--) { |
+ uint32 ttl; |
+ uint16 rdlength; |
+ if (!response.DNSName(NULL) || |
cbentzel
2011/06/01 17:17:03
Why are you passing in NULL DNS name? Don't you wa
cbentzel
2011/06/01 17:17:03
Does DNSResponseBuffer handle the compressed form
agayev
2011/06/01 19:15:01
It does.
agayev
2011/06/01 19:15:01
djbdns skips names there; I assume legal name serv
|
+ !response.U16(&qtype) || |
+ !response.U16(&qclass) || |
+ !response.U32(&ttl) || |
+ !response.U16(&rdlength)) { |
+ return false; |
+ } |
+ |
+ if (qtype == query_->qtype() && |
+ qclass == kClassIN && |
+ (rdlength == kIPv4AddressSize || rdlength == kIPv6AddressSize)) { |
+ base::StringPiece rdata; |
+ if (!response.Block(&rdata, rdlength)) |
+ return false; |
+ rdatas.push_back(IPAddressNumber(rdata.begin(), rdata.end())); |
cbentzel
2011/06/01 17:17:03
At some point we'll want to preserve TTLs as well.
agayev
2011/06/01 19:15:01
Yep, will amend it then.
|
+ } else if (!response.Skip(rdlength)) |
cbentzel
2011/06/01 17:17:03
In the future, might be nice to keep track of CNAM
agayev
2011/06/01 19:15:01
Okay.
|
+ return false; |
+ } |
+ |
+ if (rdatas.empty()) |
+ return false; |
cbentzel
2011/06/01 17:17:03
This should distinguish invalid DNS responses from
agayev
2011/06/01 19:15:01
This is something agl pointed out too, I'm waiting
|
+ |
+ *results = AddressList::CreateFromIPAddressList(rdatas, query_->port()); |
+ error_ = 0; |
+ return true; |
+} |
+ |
+} // namespace net |