blob: 06a401a6e34bd18ce740502dd6258b111b669b66 [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>
Alex Vakulenkoa41ab512014-07-23 14:24:23 -070013#include <memory>
Paul Stewartc2350ee2011-10-19 12:28:40 -070014#include <set>
15#include <string>
Paul Stewartc2350ee2011-10-19 12:28:40 -070016#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>
Ben Chana0ddf462014-02-06 11:32:42 -080021#include <base/strings/string_number_conversions.h>
Paul Stewartc2350ee2011-10-19 12:28:40 -070022
Christopher Wileyb691efd2012-08-09 13:51:51 -070023#include "shill/logging.h"
Darin Petkov89593a92012-02-21 10:59:48 +010024#include "shill/shill_ares.h"
25#include "shill/shill_time.h"
Paul Stewartc2350ee2011-10-19 12:28:40 -070026
Eric Shienbrood3e20a232012-02-16 11:35:56 -050027using base::Bind;
28using base::Unretained;
Paul Stewartc2350ee2011-10-19 12:28:40 -070029using std::map;
30using std::set;
31using std::string;
32using std::vector;
33
34namespace shill {
35
Paul Stewartc2350ee2011-10-19 12:28:40 -070036const 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 {
mukesh agrawalbd461362013-11-08 17:34:22 -080049 DNSClientState() : channel(NULL), start_time{} {}
Darin Petkove636c692012-05-31 10:22:17 +020050
Paul Stewartc2350ee2011-10-19 12:28:40 -070051 ares_channel channel;
Alex Vakulenko8a532292014-06-16 17:18:44 -070052 map< ares_socket_t, std::shared_ptr<IOHandler> > read_handlers;
53 map< ares_socket_t, std::shared_ptr<IOHandler> > write_handlers;
Darin Petkove636c692012-05-31 10:22:17 +020054 struct timeval start_time;
Paul Stewartc2350ee2011-10-19 12:28:40 -070055};
56
57DNSClient::DNSClient(IPAddress::Family family,
58 const string &interface_name,
59 const vector<string> &dns_servers,
60 int timeout_ms,
61 EventDispatcher *dispatcher,
Eric Shienbrood3e20a232012-02-16 11:35:56 -050062 const ClientCallback &callback)
Paul Stewartc2350ee2011-10-19 12:28:40 -070063 : address_(IPAddress(family)),
64 interface_name_(interface_name),
65 dns_servers_(dns_servers),
66 dispatcher_(dispatcher),
67 callback_(callback),
68 timeout_ms_(timeout_ms),
69 running_(false),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050070 weak_ptr_factory_(this),
Paul Stewartc2350ee2011-10-19 12:28:40 -070071 ares_(Ares::GetInstance()),
72 time_(Time::GetInstance()) {}
73
74DNSClient::~DNSClient() {
75 Stop();
76}
77
Paul Stewartbdb02e62012-02-22 16:24:33 -080078bool DNSClient::Start(const string &hostname, Error *error) {
Paul Stewartc2350ee2011-10-19 12:28:40 -070079 if (running_) {
Paul Stewartbdb02e62012-02-22 16:24:33 -080080 Error::PopulateAndLog(error, Error::kInProgress,
81 "Only one DNS request is allowed at a time");
Paul Stewartc2350ee2011-10-19 12:28:40 -070082 return false;
83 }
84
85 if (!resolver_state_.get()) {
86 struct ares_options options;
87 memset(&options, 0, sizeof(options));
88
89 vector<struct in_addr> server_addresses;
Paul Stewart6db7b242014-05-02 15:34:21 -070090 for (const auto &server : dns_servers_) {
Paul Stewartc2350ee2011-10-19 12:28:40 -070091 struct in_addr addr;
Paul Stewart6db7b242014-05-02 15:34:21 -070092 if (inet_aton(server.c_str(), &addr) != 0) {
Paul Stewartc2350ee2011-10-19 12:28:40 -070093 server_addresses.push_back(addr);
94 }
95 }
96
97 if (server_addresses.empty()) {
Paul Stewartbdb02e62012-02-22 16:24:33 -080098 Error::PopulateAndLog(error, Error::kInvalidArguments,
99 "No valid DNS server addresses");
Paul Stewartc2350ee2011-10-19 12:28:40 -0700100 return false;
101 }
102
103 options.servers = server_addresses.data();
104 options.nservers = server_addresses.size();
105 options.timeout = timeout_ms_;
106
107 resolver_state_.reset(new DNSClientState);
108 int status = ares_->InitOptions(&resolver_state_->channel,
109 &options,
110 ARES_OPT_SERVERS | ARES_OPT_TIMEOUTMS);
111 if (status != ARES_SUCCESS) {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800112 Error::PopulateAndLog(error, Error::kOperationFailed,
113 "ARES initialization returns error code: " +
114 base::IntToString(status));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700115 resolver_state_.reset();
116 return false;
117 }
118
119 ares_->SetLocalDev(resolver_state_->channel, interface_name_.c_str());
120 }
121
122 running_ = true;
Darin Petkove636c692012-05-31 10:22:17 +0200123 time_->GetTimeMonotonic(&resolver_state_->start_time);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700124 ares_->GetHostByName(resolver_state_->channel, hostname.c_str(),
125 address_.family(), ReceiveDNSReplyCB, this);
126
127 if (!RefreshHandles()) {
128 LOG(ERROR) << "Impossibly short timeout.";
Paul Stewartbdb02e62012-02-22 16:24:33 -0800129 error->CopyFrom(error_);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700130 Stop();
131 return false;
132 }
133
134 return true;
135}
136
137void DNSClient::Stop() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700138 SLOG(DNS, 3) << "In " << __func__;
Paul Stewartc2350ee2011-10-19 12:28:40 -0700139 if (!resolver_state_.get()) {
140 return;
141 }
142
143 running_ = false;
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500144 weak_ptr_factory_.InvalidateWeakPtrs();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800145 error_.Reset();
146 address_.SetAddressToDefault();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700147 ares_->Destroy(resolver_state_->channel);
148 resolver_state_.reset();
149}
150
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700151bool DNSClient::IsActive() const {
152 return running_;
153}
154
Paul Stewartbdb02e62012-02-22 16:24:33 -0800155// We delay our call to completion so that we exit all IOHandlers, and
156// can clean up all of our local state before calling the callback, or
157// during the process of the execution of the callee (which is free to
158// call our destructor safely).
159void DNSClient::HandleCompletion() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700160 SLOG(DNS, 3) << "In " << __func__;
Paul Stewartbdb02e62012-02-22 16:24:33 -0800161 Error error;
162 error.CopyFrom(error_);
163 IPAddress address(address_);
164 if (!error.IsSuccess()) {
165 // If the DNS request did not succeed, do not trust it for future
166 // attempts.
167 Stop();
168 } else {
169 // Prepare our state for the next request without destroying the
170 // current ARES state.
171 error_.Reset();
172 address_.SetAddressToDefault();
173 }
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500174 callback_.Run(error, address);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800175}
176
Paul Stewartc2350ee2011-10-19 12:28:40 -0700177void DNSClient::HandleDNSRead(int fd) {
178 ares_->ProcessFd(resolver_state_->channel, fd, ARES_SOCKET_BAD);
179 RefreshHandles();
180}
181
182void DNSClient::HandleDNSWrite(int fd) {
183 ares_->ProcessFd(resolver_state_->channel, ARES_SOCKET_BAD, fd);
184 RefreshHandles();
185}
186
187void DNSClient::HandleTimeout() {
188 ares_->ProcessFd(resolver_state_->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800189 RefreshHandles();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700190}
191
192void DNSClient::ReceiveDNSReply(int status, struct hostent *hostent) {
193 if (!running_) {
194 // We can be called during ARES shutdown -- ignore these events.
195 return;
196 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700197 SLOG(DNS, 3) << "In " << __func__;
Paul Stewartc2350ee2011-10-19 12:28:40 -0700198 running_ = false;
Paul Stewartf582b502012-04-04 21:39:22 -0700199 timeout_closure_.Cancel();
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500200 dispatcher_->PostTask(Bind(&DNSClient::HandleCompletion,
201 weak_ptr_factory_.GetWeakPtr()));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700202
203 if (status == ARES_SUCCESS &&
204 hostent != NULL &&
205 hostent->h_addrtype == address_.family() &&
Eric Shienbroodc74cf9c2012-03-02 15:00:35 -0500206 static_cast<size_t>(hostent->h_length) ==
207 IPAddress::GetAddressLength(address_.family()) &&
Paul Stewartc2350ee2011-10-19 12:28:40 -0700208 hostent->h_addr_list != NULL &&
209 hostent->h_addr_list[0] != NULL) {
210 address_ = IPAddress(address_.family(),
211 ByteString(reinterpret_cast<unsigned char *>(
212 hostent->h_addr_list[0]), hostent->h_length));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700213 } else {
214 switch (status) {
215 case ARES_ENODATA:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800216 error_.Populate(Error::kOperationFailed, kErrorNoData);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700217 break;
218 case ARES_EFORMERR:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800219 error_.Populate(Error::kOperationFailed, kErrorFormErr);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700220 break;
221 case ARES_ESERVFAIL:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800222 error_.Populate(Error::kOperationFailed, kErrorServerFail);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700223 break;
224 case ARES_ENOTFOUND:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800225 error_.Populate(Error::kOperationFailed, kErrorNotFound);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700226 break;
227 case ARES_ENOTIMP:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800228 error_.Populate(Error::kOperationFailed, kErrorNotImp);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700229 break;
230 case ARES_EREFUSED:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800231 error_.Populate(Error::kOperationFailed, kErrorRefused);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700232 break;
233 case ARES_EBADQUERY:
234 case ARES_EBADNAME:
235 case ARES_EBADFAMILY:
236 case ARES_EBADRESP:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800237 error_.Populate(Error::kOperationFailed, kErrorBadQuery);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700238 break;
239 case ARES_ECONNREFUSED:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800240 error_.Populate(Error::kOperationFailed, kErrorNetRefused);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700241 break;
242 case ARES_ETIMEOUT:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800243 error_.Populate(Error::kOperationTimeout, kErrorTimedOut);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700244 break;
245 default:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800246 error_.Populate(Error::kOperationFailed, kErrorUnknown);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700247 if (status == ARES_SUCCESS) {
248 LOG(ERROR) << "ARES returned success but hostent was invalid!";
249 } else {
250 LOG(ERROR) << "ARES returned unhandled error status " << status;
251 }
252 break;
253 }
Paul Stewartc2350ee2011-10-19 12:28:40 -0700254 }
255}
256
257void DNSClient::ReceiveDNSReplyCB(void *arg, int status,
258 int /*timeouts*/,
259 struct hostent *hostent) {
260 DNSClient *res = static_cast<DNSClient *>(arg);
261 res->ReceiveDNSReply(status, hostent);
262}
263
264bool DNSClient::RefreshHandles() {
Alex Vakulenko8a532292014-06-16 17:18:44 -0700265 map< ares_socket_t, std::shared_ptr<IOHandler> > old_read =
Paul Stewartc2350ee2011-10-19 12:28:40 -0700266 resolver_state_->read_handlers;
Alex Vakulenko8a532292014-06-16 17:18:44 -0700267 map< ares_socket_t, std::shared_ptr<IOHandler> > old_write =
Paul Stewartc2350ee2011-10-19 12:28:40 -0700268 resolver_state_->write_handlers;
269
270 resolver_state_->read_handlers.clear();
271 resolver_state_->write_handlers.clear();
272
273 ares_socket_t sockets[ARES_GETSOCK_MAXNUM];
274 int action_bits = ares_->GetSock(resolver_state_->channel, sockets,
Paul Stewartbdb02e62012-02-22 16:24:33 -0800275 ARES_GETSOCK_MAXNUM);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700276
Paul Stewartf582b502012-04-04 21:39:22 -0700277 base::Callback<void(int)> read_callback(
278 Bind(&DNSClient::HandleDNSRead, weak_ptr_factory_.GetWeakPtr()));
279 base::Callback<void(int)> write_callback(
280 Bind(&DNSClient::HandleDNSWrite, weak_ptr_factory_.GetWeakPtr()));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700281 for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
282 if (ARES_GETSOCK_READABLE(action_bits, i)) {
283 if (ContainsKey(old_read, sockets[i])) {
284 resolver_state_->read_handlers[sockets[i]] = old_read[sockets[i]];
285 } else {
286 resolver_state_->read_handlers[sockets[i]] =
Alex Vakulenko8a532292014-06-16 17:18:44 -0700287 std::shared_ptr<IOHandler> (
Paul Stewartc2350ee2011-10-19 12:28:40 -0700288 dispatcher_->CreateReadyHandler(sockets[i],
289 IOHandler::kModeInput,
Paul Stewartf582b502012-04-04 21:39:22 -0700290 read_callback));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700291 }
292 }
293 if (ARES_GETSOCK_WRITABLE(action_bits, i)) {
294 if (ContainsKey(old_write, sockets[i])) {
295 resolver_state_->write_handlers[sockets[i]] = old_write[sockets[i]];
296 } else {
297 resolver_state_->write_handlers[sockets[i]] =
Alex Vakulenko8a532292014-06-16 17:18:44 -0700298 std::shared_ptr<IOHandler> (
Paul Stewartc2350ee2011-10-19 12:28:40 -0700299 dispatcher_->CreateReadyHandler(sockets[i],
300 IOHandler::kModeOutput,
Paul Stewartf582b502012-04-04 21:39:22 -0700301 write_callback));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700302 }
303 }
304 }
305
306 if (!running_) {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800307 // We are here just to clean up socket handles, and the ARES state was
308 // cleaned up during the last call to ares_->ProcessFd().
Paul Stewartc2350ee2011-10-19 12:28:40 -0700309 return false;
310 }
311
312 // Schedule timer event for the earlier of our timeout or one requested by
313 // the resolver library.
314 struct timeval now, elapsed_time, timeout_tv;
Paul Stewarte6927402012-01-23 16:11:30 -0800315 time_->GetTimeMonotonic(&now);
Darin Petkove636c692012-05-31 10:22:17 +0200316 timersub(&now, &resolver_state_->start_time, &elapsed_time);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700317 timeout_tv.tv_sec = timeout_ms_ / 1000;
318 timeout_tv.tv_usec = (timeout_ms_ % 1000) * 1000;
Paul Stewartf582b502012-04-04 21:39:22 -0700319 timeout_closure_.Cancel();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800320
Paul Stewartc2350ee2011-10-19 12:28:40 -0700321 if (timercmp(&elapsed_time, &timeout_tv, >=)) {
322 // There are 3 cases of interest:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800323 // - If we got here from Start(), when we return, Stop() will be
324 // called, so our cleanup task will not run, so we will not have the
325 // side-effect of both invoking the callback and returning False
326 // in Start().
327 // - If we got here from the tail of an IO event, we can't call
328 // Stop() since that will blow away the IOHandler we are running
329 // in. We will perform the cleanup in the posted task below.
330 // - If we got here from a timeout handler, we will perform cleanup
331 // in the posted task.
Paul Stewartc2350ee2011-10-19 12:28:40 -0700332 running_ = false;
Paul Stewartbdb02e62012-02-22 16:24:33 -0800333 error_.Populate(Error::kOperationTimeout, kErrorTimedOut);
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500334 dispatcher_->PostTask(Bind(&DNSClient::HandleCompletion,
335 weak_ptr_factory_.GetWeakPtr()));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700336 return false;
337 } else {
338 struct timeval max, ret_tv;
339 timersub(&timeout_tv, &elapsed_time, &max);
340 struct timeval *tv = ares_->Timeout(resolver_state_->channel,
341 &max, &ret_tv);
Paul Stewartf582b502012-04-04 21:39:22 -0700342 timeout_closure_.Reset(
343 Bind(&DNSClient::HandleTimeout, weak_ptr_factory_.GetWeakPtr()));
344 dispatcher_->PostDelayedTask(timeout_closure_.callback(),
345 tv->tv_sec * 1000 + tv->tv_usec / 1000);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700346 }
347
348 return true;
349}
350
351} // namespace shill