blob: 19cf6bcab4dda69325ad498eecc611a671c0a3b0 [file] [log] [blame]
Paul Stewarte6927402012-01-23 16:11:30 -08001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Paul Stewartc2350ee2011-10-19 12:28:40 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/dns_client.h"
6
7#include <arpa/inet.h>
8#include <netdb.h>
9#include <netinet/in.h>
10#include <sys/socket.h>
11
12#include <map>
13#include <set>
14#include <string>
15#include <tr1/memory>
16#include <vector>
17
Eric Shienbrood3e20a232012-02-16 11:35:56 -050018#include <base/bind.h>
19#include <base/bind_helpers.h>
20#include <base/stl_util.h>
Paul Stewartbdb02e62012-02-22 16:24:33 -080021#include <base/string_number_conversions.h>
Paul Stewartc2350ee2011-10-19 12:28:40 -070022
Darin Petkov89593a92012-02-21 10:59:48 +010023#include "shill/shill_ares.h"
24#include "shill/shill_time.h"
Paul Stewartc2350ee2011-10-19 12:28:40 -070025
Eric Shienbrood3e20a232012-02-16 11:35:56 -050026using base::Bind;
27using base::Unretained;
Paul Stewartc2350ee2011-10-19 12:28:40 -070028using std::map;
29using std::set;
30using std::string;
31using std::vector;
32
33namespace shill {
34
35const int DNSClient::kDefaultTimeoutMS = 2000;
36const char DNSClient::kErrorNoData[] = "The query response contains no answers";
37const char DNSClient::kErrorFormErr[] = "The server says the query is bad";
38const char DNSClient::kErrorServerFail[] = "The server says it had a failure";
39const char DNSClient::kErrorNotFound[] = "The queried-for domain was not found";
40const char DNSClient::kErrorNotImp[] = "The server doesn't implement operation";
41const char DNSClient::kErrorRefused[] = "The server replied, refused the query";
42const char DNSClient::kErrorBadQuery[] = "Locally we could not format a query";
43const char DNSClient::kErrorNetRefused[] = "The network connection was refused";
44const char DNSClient::kErrorTimedOut[] = "The network connection was timed out";
45const char DNSClient::kErrorUnknown[] = "DNS Resolver unknown internal error";
46
47// Private to the implementation of resolver so callers don't include ares.h
48struct DNSClientState {
49 ares_channel channel;
50 map< ares_socket_t, std::tr1::shared_ptr<IOHandler> > read_handlers;
51 map< ares_socket_t, std::tr1::shared_ptr<IOHandler> > write_handlers;
52 struct timeval start_time_;
53};
54
55DNSClient::DNSClient(IPAddress::Family family,
56 const string &interface_name,
57 const vector<string> &dns_servers,
58 int timeout_ms,
59 EventDispatcher *dispatcher,
Eric Shienbrood3e20a232012-02-16 11:35:56 -050060 const ClientCallback &callback)
Paul Stewartc2350ee2011-10-19 12:28:40 -070061 : address_(IPAddress(family)),
62 interface_name_(interface_name),
63 dns_servers_(dns_servers),
64 dispatcher_(dispatcher),
65 callback_(callback),
66 timeout_ms_(timeout_ms),
67 running_(false),
68 resolver_state_(NULL),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050069 weak_ptr_factory_(this),
Paul Stewartc2350ee2011-10-19 12:28:40 -070070 ares_(Ares::GetInstance()),
71 time_(Time::GetInstance()) {}
72
73DNSClient::~DNSClient() {
74 Stop();
75}
76
Paul Stewartbdb02e62012-02-22 16:24:33 -080077bool DNSClient::Start(const string &hostname, Error *error) {
Paul Stewartc2350ee2011-10-19 12:28:40 -070078 if (running_) {
Paul Stewartbdb02e62012-02-22 16:24:33 -080079 Error::PopulateAndLog(error, Error::kInProgress,
80 "Only one DNS request is allowed at a time");
Paul Stewartc2350ee2011-10-19 12:28:40 -070081 return false;
82 }
83
84 if (!resolver_state_.get()) {
85 struct ares_options options;
86 memset(&options, 0, sizeof(options));
87
88 vector<struct in_addr> server_addresses;
89 for (vector<string>::iterator it = dns_servers_.begin();
90 it != dns_servers_.end();
91 ++it) {
92 struct in_addr addr;
93 if (inet_aton(it->c_str(), &addr) != 0) {
94 server_addresses.push_back(addr);
95 }
96 }
97
98 if (server_addresses.empty()) {
Paul Stewartbdb02e62012-02-22 16:24:33 -080099 Error::PopulateAndLog(error, Error::kInvalidArguments,
100 "No valid DNS server addresses");
Paul Stewartc2350ee2011-10-19 12:28:40 -0700101 return false;
102 }
103
104 options.servers = server_addresses.data();
105 options.nservers = server_addresses.size();
106 options.timeout = timeout_ms_;
107
108 resolver_state_.reset(new DNSClientState);
109 int status = ares_->InitOptions(&resolver_state_->channel,
110 &options,
111 ARES_OPT_SERVERS | ARES_OPT_TIMEOUTMS);
112 if (status != ARES_SUCCESS) {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800113 Error::PopulateAndLog(error, Error::kOperationFailed,
114 "ARES initialization returns error code: " +
115 base::IntToString(status));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700116 resolver_state_.reset();
117 return false;
118 }
119
120 ares_->SetLocalDev(resolver_state_->channel, interface_name_.c_str());
121 }
122
123 running_ = true;
Paul Stewarte6927402012-01-23 16:11:30 -0800124 time_->GetTimeMonotonic(&resolver_state_->start_time_);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700125 ares_->GetHostByName(resolver_state_->channel, hostname.c_str(),
126 address_.family(), ReceiveDNSReplyCB, this);
127
128 if (!RefreshHandles()) {
129 LOG(ERROR) << "Impossibly short timeout.";
Paul Stewartbdb02e62012-02-22 16:24:33 -0800130 error->CopyFrom(error_);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700131 Stop();
132 return false;
133 }
134
135 return true;
136}
137
138void DNSClient::Stop() {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800139 VLOG(3) << "In " << __func__;
Paul Stewartc2350ee2011-10-19 12:28:40 -0700140 if (!resolver_state_.get()) {
141 return;
142 }
143
144 running_ = false;
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500145 weak_ptr_factory_.InvalidateWeakPtrs();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800146 error_.Reset();
147 address_.SetAddressToDefault();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700148 ares_->Destroy(resolver_state_->channel);
149 resolver_state_.reset();
150}
151
Paul Stewartbdb02e62012-02-22 16:24:33 -0800152// We delay our call to completion so that we exit all IOHandlers, and
153// can clean up all of our local state before calling the callback, or
154// during the process of the execution of the callee (which is free to
155// call our destructor safely).
156void DNSClient::HandleCompletion() {
157 VLOG(3) << "In " << __func__;
158 Error error;
159 error.CopyFrom(error_);
160 IPAddress address(address_);
161 if (!error.IsSuccess()) {
162 // If the DNS request did not succeed, do not trust it for future
163 // attempts.
164 Stop();
165 } else {
166 // Prepare our state for the next request without destroying the
167 // current ARES state.
168 error_.Reset();
169 address_.SetAddressToDefault();
170 }
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500171 callback_.Run(error, address);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800172}
173
Paul Stewartc2350ee2011-10-19 12:28:40 -0700174void DNSClient::HandleDNSRead(int fd) {
175 ares_->ProcessFd(resolver_state_->channel, fd, ARES_SOCKET_BAD);
176 RefreshHandles();
177}
178
179void DNSClient::HandleDNSWrite(int fd) {
180 ares_->ProcessFd(resolver_state_->channel, ARES_SOCKET_BAD, fd);
181 RefreshHandles();
182}
183
184void DNSClient::HandleTimeout() {
185 ares_->ProcessFd(resolver_state_->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800186 RefreshHandles();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700187}
188
189void DNSClient::ReceiveDNSReply(int status, struct hostent *hostent) {
190 if (!running_) {
191 // We can be called during ARES shutdown -- ignore these events.
192 return;
193 }
Paul Stewartbdb02e62012-02-22 16:24:33 -0800194 VLOG(3) << "In " << __func__;
Paul Stewartc2350ee2011-10-19 12:28:40 -0700195 running_ = false;
Paul Stewartf582b502012-04-04 21:39:22 -0700196 timeout_closure_.Cancel();
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500197 dispatcher_->PostTask(Bind(&DNSClient::HandleCompletion,
198 weak_ptr_factory_.GetWeakPtr()));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700199
200 if (status == ARES_SUCCESS &&
201 hostent != NULL &&
202 hostent->h_addrtype == address_.family() &&
Eric Shienbroodc74cf9c2012-03-02 15:00:35 -0500203 static_cast<size_t>(hostent->h_length) ==
204 IPAddress::GetAddressLength(address_.family()) &&
Paul Stewartc2350ee2011-10-19 12:28:40 -0700205 hostent->h_addr_list != NULL &&
206 hostent->h_addr_list[0] != NULL) {
207 address_ = IPAddress(address_.family(),
208 ByteString(reinterpret_cast<unsigned char *>(
209 hostent->h_addr_list[0]), hostent->h_length));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700210 } else {
211 switch (status) {
212 case ARES_ENODATA:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800213 error_.Populate(Error::kOperationFailed, kErrorNoData);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700214 break;
215 case ARES_EFORMERR:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800216 error_.Populate(Error::kOperationFailed, kErrorFormErr);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700217 break;
218 case ARES_ESERVFAIL:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800219 error_.Populate(Error::kOperationFailed, kErrorServerFail);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700220 break;
221 case ARES_ENOTFOUND:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800222 error_.Populate(Error::kOperationFailed, kErrorNotFound);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700223 break;
224 case ARES_ENOTIMP:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800225 error_.Populate(Error::kOperationFailed, kErrorNotImp);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700226 break;
227 case ARES_EREFUSED:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800228 error_.Populate(Error::kOperationFailed, kErrorRefused);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700229 break;
230 case ARES_EBADQUERY:
231 case ARES_EBADNAME:
232 case ARES_EBADFAMILY:
233 case ARES_EBADRESP:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800234 error_.Populate(Error::kOperationFailed, kErrorBadQuery);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700235 break;
236 case ARES_ECONNREFUSED:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800237 error_.Populate(Error::kOperationFailed, kErrorNetRefused);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700238 break;
239 case ARES_ETIMEOUT:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800240 error_.Populate(Error::kOperationTimeout, kErrorTimedOut);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700241 break;
242 default:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800243 error_.Populate(Error::kOperationFailed, kErrorUnknown);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700244 if (status == ARES_SUCCESS) {
245 LOG(ERROR) << "ARES returned success but hostent was invalid!";
246 } else {
247 LOG(ERROR) << "ARES returned unhandled error status " << status;
248 }
249 break;
250 }
Paul Stewartc2350ee2011-10-19 12:28:40 -0700251 }
252}
253
254void DNSClient::ReceiveDNSReplyCB(void *arg, int status,
255 int /*timeouts*/,
256 struct hostent *hostent) {
257 DNSClient *res = static_cast<DNSClient *>(arg);
258 res->ReceiveDNSReply(status, hostent);
259}
260
261bool DNSClient::RefreshHandles() {
262 map< ares_socket_t, std::tr1::shared_ptr<IOHandler> > old_read =
263 resolver_state_->read_handlers;
264 map< ares_socket_t, std::tr1::shared_ptr<IOHandler> > old_write =
265 resolver_state_->write_handlers;
266
267 resolver_state_->read_handlers.clear();
268 resolver_state_->write_handlers.clear();
269
270 ares_socket_t sockets[ARES_GETSOCK_MAXNUM];
271 int action_bits = ares_->GetSock(resolver_state_->channel, sockets,
Paul Stewartbdb02e62012-02-22 16:24:33 -0800272 ARES_GETSOCK_MAXNUM);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700273
Paul Stewartf582b502012-04-04 21:39:22 -0700274 base::Callback<void(int)> read_callback(
275 Bind(&DNSClient::HandleDNSRead, weak_ptr_factory_.GetWeakPtr()));
276 base::Callback<void(int)> write_callback(
277 Bind(&DNSClient::HandleDNSWrite, weak_ptr_factory_.GetWeakPtr()));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700278 for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
279 if (ARES_GETSOCK_READABLE(action_bits, i)) {
280 if (ContainsKey(old_read, sockets[i])) {
281 resolver_state_->read_handlers[sockets[i]] = old_read[sockets[i]];
282 } else {
283 resolver_state_->read_handlers[sockets[i]] =
284 std::tr1::shared_ptr<IOHandler> (
285 dispatcher_->CreateReadyHandler(sockets[i],
286 IOHandler::kModeInput,
Paul Stewartf582b502012-04-04 21:39:22 -0700287 read_callback));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700288 }
289 }
290 if (ARES_GETSOCK_WRITABLE(action_bits, i)) {
291 if (ContainsKey(old_write, sockets[i])) {
292 resolver_state_->write_handlers[sockets[i]] = old_write[sockets[i]];
293 } else {
294 resolver_state_->write_handlers[sockets[i]] =
295 std::tr1::shared_ptr<IOHandler> (
296 dispatcher_->CreateReadyHandler(sockets[i],
297 IOHandler::kModeOutput,
Paul Stewartf582b502012-04-04 21:39:22 -0700298 write_callback));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700299 }
300 }
301 }
302
303 if (!running_) {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800304 // We are here just to clean up socket handles, and the ARES state was
305 // cleaned up during the last call to ares_->ProcessFd().
Paul Stewartc2350ee2011-10-19 12:28:40 -0700306 return false;
307 }
308
309 // Schedule timer event for the earlier of our timeout or one requested by
310 // the resolver library.
311 struct timeval now, elapsed_time, timeout_tv;
Paul Stewarte6927402012-01-23 16:11:30 -0800312 time_->GetTimeMonotonic(&now);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700313 timersub(&now, &resolver_state_->start_time_, &elapsed_time);
314 timeout_tv.tv_sec = timeout_ms_ / 1000;
315 timeout_tv.tv_usec = (timeout_ms_ % 1000) * 1000;
Paul Stewartf582b502012-04-04 21:39:22 -0700316 timeout_closure_.Cancel();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800317
Paul Stewartc2350ee2011-10-19 12:28:40 -0700318 if (timercmp(&elapsed_time, &timeout_tv, >=)) {
319 // There are 3 cases of interest:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800320 // - If we got here from Start(), when we return, Stop() will be
321 // called, so our cleanup task will not run, so we will not have the
322 // side-effect of both invoking the callback and returning False
323 // in Start().
324 // - If we got here from the tail of an IO event, we can't call
325 // Stop() since that will blow away the IOHandler we are running
326 // in. We will perform the cleanup in the posted task below.
327 // - If we got here from a timeout handler, we will perform cleanup
328 // in the posted task.
Paul Stewartc2350ee2011-10-19 12:28:40 -0700329 running_ = false;
Paul Stewartbdb02e62012-02-22 16:24:33 -0800330 error_.Populate(Error::kOperationTimeout, kErrorTimedOut);
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500331 dispatcher_->PostTask(Bind(&DNSClient::HandleCompletion,
332 weak_ptr_factory_.GetWeakPtr()));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700333 return false;
334 } else {
335 struct timeval max, ret_tv;
336 timersub(&timeout_tv, &elapsed_time, &max);
337 struct timeval *tv = ares_->Timeout(resolver_state_->channel,
338 &max, &ret_tv);
Paul Stewartf582b502012-04-04 21:39:22 -0700339 timeout_closure_.Reset(
340 Bind(&DNSClient::HandleTimeout, weak_ptr_factory_.GetWeakPtr()));
341 dispatcher_->PostDelayedTask(timeout_closure_.callback(),
342 tv->tv_sec * 1000 + tv->tv_usec / 1000);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700343 }
344
345 return true;
346}
347
348} // namespace shill