blob: cbadb1e171872231e097a758b6672bf25b2733c7 [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
18#include <base/stl_util-inl.h>
Paul Stewartbdb02e62012-02-22 16:24:33 -080019#include <base/string_number_conversions.h>
Paul Stewartc2350ee2011-10-19 12:28:40 -070020
Darin Petkov89593a92012-02-21 10:59:48 +010021#include "shill/shill_ares.h"
22#include "shill/shill_time.h"
Paul Stewartc2350ee2011-10-19 12:28:40 -070023
24using std::map;
25using std::set;
26using std::string;
27using std::vector;
28
29namespace shill {
30
31const int DNSClient::kDefaultTimeoutMS = 2000;
32const char DNSClient::kErrorNoData[] = "The query response contains no answers";
33const char DNSClient::kErrorFormErr[] = "The server says the query is bad";
34const char DNSClient::kErrorServerFail[] = "The server says it had a failure";
35const char DNSClient::kErrorNotFound[] = "The queried-for domain was not found";
36const char DNSClient::kErrorNotImp[] = "The server doesn't implement operation";
37const char DNSClient::kErrorRefused[] = "The server replied, refused the query";
38const char DNSClient::kErrorBadQuery[] = "Locally we could not format a query";
39const char DNSClient::kErrorNetRefused[] = "The network connection was refused";
40const char DNSClient::kErrorTimedOut[] = "The network connection was timed out";
41const char DNSClient::kErrorUnknown[] = "DNS Resolver unknown internal error";
42
43// Private to the implementation of resolver so callers don't include ares.h
44struct DNSClientState {
45 ares_channel channel;
46 map< ares_socket_t, std::tr1::shared_ptr<IOHandler> > read_handlers;
47 map< ares_socket_t, std::tr1::shared_ptr<IOHandler> > write_handlers;
48 struct timeval start_time_;
49};
50
51DNSClient::DNSClient(IPAddress::Family family,
52 const string &interface_name,
53 const vector<string> &dns_servers,
54 int timeout_ms,
55 EventDispatcher *dispatcher,
Paul Stewartbdb02e62012-02-22 16:24:33 -080056 ClientCallback *callback)
Paul Stewartc2350ee2011-10-19 12:28:40 -070057 : address_(IPAddress(family)),
58 interface_name_(interface_name),
59 dns_servers_(dns_servers),
60 dispatcher_(dispatcher),
61 callback_(callback),
62 timeout_ms_(timeout_ms),
63 running_(false),
64 resolver_state_(NULL),
65 read_callback_(NewCallback(this, &DNSClient::HandleDNSRead)),
66 write_callback_(NewCallback(this, &DNSClient::HandleDNSWrite)),
67 task_factory_(this),
68 ares_(Ares::GetInstance()),
69 time_(Time::GetInstance()) {}
70
71DNSClient::~DNSClient() {
72 Stop();
73}
74
Paul Stewartbdb02e62012-02-22 16:24:33 -080075bool DNSClient::Start(const string &hostname, Error *error) {
Paul Stewartc2350ee2011-10-19 12:28:40 -070076 if (running_) {
Paul Stewartbdb02e62012-02-22 16:24:33 -080077 Error::PopulateAndLog(error, Error::kInProgress,
78 "Only one DNS request is allowed at a time");
Paul Stewartc2350ee2011-10-19 12:28:40 -070079 return false;
80 }
81
82 if (!resolver_state_.get()) {
83 struct ares_options options;
84 memset(&options, 0, sizeof(options));
85
86 vector<struct in_addr> server_addresses;
87 for (vector<string>::iterator it = dns_servers_.begin();
88 it != dns_servers_.end();
89 ++it) {
90 struct in_addr addr;
91 if (inet_aton(it->c_str(), &addr) != 0) {
92 server_addresses.push_back(addr);
93 }
94 }
95
96 if (server_addresses.empty()) {
Paul Stewartbdb02e62012-02-22 16:24:33 -080097 Error::PopulateAndLog(error, Error::kInvalidArguments,
98 "No valid DNS server addresses");
Paul Stewartc2350ee2011-10-19 12:28:40 -070099 return false;
100 }
101
102 options.servers = server_addresses.data();
103 options.nservers = server_addresses.size();
104 options.timeout = timeout_ms_;
105
106 resolver_state_.reset(new DNSClientState);
107 int status = ares_->InitOptions(&resolver_state_->channel,
108 &options,
109 ARES_OPT_SERVERS | ARES_OPT_TIMEOUTMS);
110 if (status != ARES_SUCCESS) {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800111 Error::PopulateAndLog(error, Error::kOperationFailed,
112 "ARES initialization returns error code: " +
113 base::IntToString(status));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700114 resolver_state_.reset();
115 return false;
116 }
117
118 ares_->SetLocalDev(resolver_state_->channel, interface_name_.c_str());
119 }
120
121 running_ = true;
Paul Stewarte6927402012-01-23 16:11:30 -0800122 time_->GetTimeMonotonic(&resolver_state_->start_time_);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700123 ares_->GetHostByName(resolver_state_->channel, hostname.c_str(),
124 address_.family(), ReceiveDNSReplyCB, this);
125
126 if (!RefreshHandles()) {
127 LOG(ERROR) << "Impossibly short timeout.";
Paul Stewartbdb02e62012-02-22 16:24:33 -0800128 error->CopyFrom(error_);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700129 Stop();
130 return false;
131 }
132
133 return true;
134}
135
136void DNSClient::Stop() {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800137 VLOG(3) << "In " << __func__;
Paul Stewartc2350ee2011-10-19 12:28:40 -0700138 if (!resolver_state_.get()) {
139 return;
140 }
141
142 running_ = false;
143 task_factory_.RevokeAll();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800144 error_.Reset();
145 address_.SetAddressToDefault();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700146 ares_->Destroy(resolver_state_->channel);
147 resolver_state_.reset();
148}
149
Paul Stewartbdb02e62012-02-22 16:24:33 -0800150// We delay our call to completion so that we exit all IOHandlers, and
151// can clean up all of our local state before calling the callback, or
152// during the process of the execution of the callee (which is free to
153// call our destructor safely).
154void DNSClient::HandleCompletion() {
155 VLOG(3) << "In " << __func__;
156 Error error;
157 error.CopyFrom(error_);
158 IPAddress address(address_);
159 if (!error.IsSuccess()) {
160 // If the DNS request did not succeed, do not trust it for future
161 // attempts.
162 Stop();
163 } else {
164 // Prepare our state for the next request without destroying the
165 // current ARES state.
166 error_.Reset();
167 address_.SetAddressToDefault();
168 }
169 callback_->Run(error, address);
170}
171
Paul Stewartc2350ee2011-10-19 12:28:40 -0700172void DNSClient::HandleDNSRead(int fd) {
173 ares_->ProcessFd(resolver_state_->channel, fd, ARES_SOCKET_BAD);
174 RefreshHandles();
175}
176
177void DNSClient::HandleDNSWrite(int fd) {
178 ares_->ProcessFd(resolver_state_->channel, ARES_SOCKET_BAD, fd);
179 RefreshHandles();
180}
181
182void DNSClient::HandleTimeout() {
183 ares_->ProcessFd(resolver_state_->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800184 RefreshHandles();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700185}
186
187void DNSClient::ReceiveDNSReply(int status, struct hostent *hostent) {
188 if (!running_) {
189 // We can be called during ARES shutdown -- ignore these events.
190 return;
191 }
Paul Stewartbdb02e62012-02-22 16:24:33 -0800192 VLOG(3) << "In " << __func__;
Paul Stewartc2350ee2011-10-19 12:28:40 -0700193 running_ = false;
Paul Stewartbdb02e62012-02-22 16:24:33 -0800194 task_factory_.RevokeAll();
195 dispatcher_->PostTask(task_factory_.NewRunnableMethod(
196 &DNSClient::HandleCompletion));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700197
198 if (status == ARES_SUCCESS &&
199 hostent != NULL &&
200 hostent->h_addrtype == address_.family() &&
201 hostent->h_length == IPAddress::GetAddressLength(address_.family()) &&
202 hostent->h_addr_list != NULL &&
203 hostent->h_addr_list[0] != NULL) {
204 address_ = IPAddress(address_.family(),
205 ByteString(reinterpret_cast<unsigned char *>(
206 hostent->h_addr_list[0]), hostent->h_length));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700207 } else {
208 switch (status) {
209 case ARES_ENODATA:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800210 error_.Populate(Error::kOperationFailed, kErrorNoData);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700211 break;
212 case ARES_EFORMERR:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800213 error_.Populate(Error::kOperationFailed, kErrorFormErr);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700214 break;
215 case ARES_ESERVFAIL:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800216 error_.Populate(Error::kOperationFailed, kErrorServerFail);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700217 break;
218 case ARES_ENOTFOUND:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800219 error_.Populate(Error::kOperationFailed, kErrorNotFound);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700220 break;
221 case ARES_ENOTIMP:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800222 error_.Populate(Error::kOperationFailed, kErrorNotImp);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700223 break;
224 case ARES_EREFUSED:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800225 error_.Populate(Error::kOperationFailed, kErrorRefused);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700226 break;
227 case ARES_EBADQUERY:
228 case ARES_EBADNAME:
229 case ARES_EBADFAMILY:
230 case ARES_EBADRESP:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800231 error_.Populate(Error::kOperationFailed, kErrorBadQuery);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700232 break;
233 case ARES_ECONNREFUSED:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800234 error_.Populate(Error::kOperationFailed, kErrorNetRefused);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700235 break;
236 case ARES_ETIMEOUT:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800237 error_.Populate(Error::kOperationTimeout, kErrorTimedOut);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700238 break;
239 default:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800240 error_.Populate(Error::kOperationFailed, kErrorUnknown);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700241 if (status == ARES_SUCCESS) {
242 LOG(ERROR) << "ARES returned success but hostent was invalid!";
243 } else {
244 LOG(ERROR) << "ARES returned unhandled error status " << status;
245 }
246 break;
247 }
Paul Stewartc2350ee2011-10-19 12:28:40 -0700248 }
249}
250
251void DNSClient::ReceiveDNSReplyCB(void *arg, int status,
252 int /*timeouts*/,
253 struct hostent *hostent) {
254 DNSClient *res = static_cast<DNSClient *>(arg);
255 res->ReceiveDNSReply(status, hostent);
256}
257
258bool DNSClient::RefreshHandles() {
259 map< ares_socket_t, std::tr1::shared_ptr<IOHandler> > old_read =
260 resolver_state_->read_handlers;
261 map< ares_socket_t, std::tr1::shared_ptr<IOHandler> > old_write =
262 resolver_state_->write_handlers;
263
264 resolver_state_->read_handlers.clear();
265 resolver_state_->write_handlers.clear();
266
267 ares_socket_t sockets[ARES_GETSOCK_MAXNUM];
268 int action_bits = ares_->GetSock(resolver_state_->channel, sockets,
Paul Stewartbdb02e62012-02-22 16:24:33 -0800269 ARES_GETSOCK_MAXNUM);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700270
271 for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
272 if (ARES_GETSOCK_READABLE(action_bits, i)) {
273 if (ContainsKey(old_read, sockets[i])) {
274 resolver_state_->read_handlers[sockets[i]] = old_read[sockets[i]];
275 } else {
276 resolver_state_->read_handlers[sockets[i]] =
277 std::tr1::shared_ptr<IOHandler> (
278 dispatcher_->CreateReadyHandler(sockets[i],
279 IOHandler::kModeInput,
280 read_callback_.get()));
281 }
282 }
283 if (ARES_GETSOCK_WRITABLE(action_bits, i)) {
284 if (ContainsKey(old_write, sockets[i])) {
285 resolver_state_->write_handlers[sockets[i]] = old_write[sockets[i]];
286 } else {
287 resolver_state_->write_handlers[sockets[i]] =
288 std::tr1::shared_ptr<IOHandler> (
289 dispatcher_->CreateReadyHandler(sockets[i],
290 IOHandler::kModeOutput,
291 write_callback_.get()));
292 }
293 }
294 }
295
296 if (!running_) {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800297 // We are here just to clean up socket handles, and the ARES state was
298 // cleaned up during the last call to ares_->ProcessFd().
Paul Stewartc2350ee2011-10-19 12:28:40 -0700299 return false;
300 }
301
302 // Schedule timer event for the earlier of our timeout or one requested by
303 // the resolver library.
304 struct timeval now, elapsed_time, timeout_tv;
Paul Stewarte6927402012-01-23 16:11:30 -0800305 time_->GetTimeMonotonic(&now);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700306 timersub(&now, &resolver_state_->start_time_, &elapsed_time);
307 timeout_tv.tv_sec = timeout_ms_ / 1000;
308 timeout_tv.tv_usec = (timeout_ms_ % 1000) * 1000;
Paul Stewartbdb02e62012-02-22 16:24:33 -0800309 task_factory_.RevokeAll();
310
Paul Stewartc2350ee2011-10-19 12:28:40 -0700311 if (timercmp(&elapsed_time, &timeout_tv, >=)) {
312 // There are 3 cases of interest:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800313 // - If we got here from Start(), when we return, Stop() will be
314 // called, so our cleanup task will not run, so we will not have the
315 // side-effect of both invoking the callback and returning False
316 // in Start().
317 // - If we got here from the tail of an IO event, we can't call
318 // Stop() since that will blow away the IOHandler we are running
319 // in. We will perform the cleanup in the posted task below.
320 // - If we got here from a timeout handler, we will perform cleanup
321 // in the posted task.
Paul Stewartc2350ee2011-10-19 12:28:40 -0700322 running_ = false;
Paul Stewartbdb02e62012-02-22 16:24:33 -0800323 error_.Populate(Error::kOperationTimeout, kErrorTimedOut);
324 dispatcher_->PostTask(task_factory_.NewRunnableMethod(
325 &DNSClient::HandleCompletion));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700326 return false;
327 } else {
328 struct timeval max, ret_tv;
329 timersub(&timeout_tv, &elapsed_time, &max);
330 struct timeval *tv = ares_->Timeout(resolver_state_->channel,
331 &max, &ret_tv);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700332 dispatcher_->PostDelayedTask(
333 task_factory_.NewRunnableMethod(&DNSClient::HandleTimeout),
334 tv->tv_sec * 1000 + tv->tv_usec / 1000);
335 }
336
337 return true;
338}
339
340} // namespace shill