Chromium Code Reviews| 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 |