blob: 0cc5aa93122ccbbcd9eff300c2df2c5215e028be [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"
Peter Qiu8d6b5972014-10-28 15:33:34 -070024#include "shill/net/shill_time.h"
Darin Petkov89593a92012-02-21 10:59:48 +010025#include "shill/shill_ares.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
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -070036namespace Logging {
37static auto kModuleLogScope = ScopeLogger::kDNS;
38static string ObjectID(DNSClient *d) { return d->interface_name(); }
39}
40
Paul Stewartc2350ee2011-10-19 12:28:40 -070041const char DNSClient::kErrorNoData[] = "The query response contains no answers";
42const char DNSClient::kErrorFormErr[] = "The server says the query is bad";
43const char DNSClient::kErrorServerFail[] = "The server says it had a failure";
44const char DNSClient::kErrorNotFound[] = "The queried-for domain was not found";
45const char DNSClient::kErrorNotImp[] = "The server doesn't implement operation";
46const char DNSClient::kErrorRefused[] = "The server replied, refused the query";
47const char DNSClient::kErrorBadQuery[] = "Locally we could not format a query";
48const char DNSClient::kErrorNetRefused[] = "The network connection was refused";
49const char DNSClient::kErrorTimedOut[] = "The network connection was timed out";
50const char DNSClient::kErrorUnknown[] = "DNS Resolver unknown internal error";
51
Peter Qiuf3a8f902014-08-20 10:05:42 -070052const int DNSClient::kDefaultDNSPort = 53;
53
Paul Stewartc2350ee2011-10-19 12:28:40 -070054// Private to the implementation of resolver so callers don't include ares.h
55struct DNSClientState {
Ben Chancc225ef2014-09-30 13:26:51 -070056 DNSClientState() : channel(nullptr), start_time{} {}
Darin Petkove636c692012-05-31 10:22:17 +020057
Paul Stewartc2350ee2011-10-19 12:28:40 -070058 ares_channel channel;
Ben Chane2ee5e02014-09-19 19:29:42 -070059 map<ares_socket_t, std::shared_ptr<IOHandler>> read_handlers;
60 map<ares_socket_t, std::shared_ptr<IOHandler>> write_handlers;
Darin Petkove636c692012-05-31 10:22:17 +020061 struct timeval start_time;
Paul Stewartc2350ee2011-10-19 12:28:40 -070062};
63
64DNSClient::DNSClient(IPAddress::Family family,
65 const string &interface_name,
66 const vector<string> &dns_servers,
67 int timeout_ms,
68 EventDispatcher *dispatcher,
Eric Shienbrood3e20a232012-02-16 11:35:56 -050069 const ClientCallback &callback)
Paul Stewartc2350ee2011-10-19 12:28:40 -070070 : address_(IPAddress(family)),
71 interface_name_(interface_name),
72 dns_servers_(dns_servers),
73 dispatcher_(dispatcher),
74 callback_(callback),
75 timeout_ms_(timeout_ms),
76 running_(false),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050077 weak_ptr_factory_(this),
Paul Stewartc2350ee2011-10-19 12:28:40 -070078 ares_(Ares::GetInstance()),
79 time_(Time::GetInstance()) {}
80
81DNSClient::~DNSClient() {
82 Stop();
83}
84
Paul Stewartbdb02e62012-02-22 16:24:33 -080085bool DNSClient::Start(const string &hostname, Error *error) {
Paul Stewartc2350ee2011-10-19 12:28:40 -070086 if (running_) {
Paul Stewartbdb02e62012-02-22 16:24:33 -080087 Error::PopulateAndLog(error, Error::kInProgress,
88 "Only one DNS request is allowed at a time");
Paul Stewartc2350ee2011-10-19 12:28:40 -070089 return false;
90 }
91
92 if (!resolver_state_.get()) {
93 struct ares_options options;
94 memset(&options, 0, sizeof(options));
Peter Qiuf3a8f902014-08-20 10:05:42 -070095 options.timeout = timeout_ms_;
Paul Stewartc2350ee2011-10-19 12:28:40 -070096
Peter Qiuf3a8f902014-08-20 10:05:42 -070097 if (dns_servers_.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
Paul Stewartc2350ee2011-10-19 12:28:40 -0700103 resolver_state_.reset(new DNSClientState);
104 int status = ares_->InitOptions(&resolver_state_->channel,
105 &options,
Peter Qiuf3a8f902014-08-20 10:05:42 -0700106 ARES_OPT_TIMEOUTMS);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700107 if (status != ARES_SUCCESS) {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800108 Error::PopulateAndLog(error, Error::kOperationFailed,
109 "ARES initialization returns error code: " +
110 base::IntToString(status));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700111 resolver_state_.reset();
112 return false;
113 }
114
Peter Qiuf3a8f902014-08-20 10:05:42 -0700115 // Format DNS server addresses string as "host:port[,host:port...]" to be
116 // used in call to ares_set_servers_csv for setting DNS server addresses.
117 // There is a bug in ares library when parsing IPv6 addresses, where it
118 // always assumes the port number are specified when address contains ":".
119 // So when IPv6 address are given without port number as "xx:xx:xx::yy",the
120 // parser would parse the address as "xx:xx:xx:" and port number as "yy".
121 // To work around this bug, port number are added to each address.
122 //
123 // Alternatively, we can use ares_set_servers instead, where we would
124 // explicitly construct a link list of ares_addr_node.
125 string server_addresses;
126 bool first = true;
127 for (const auto &ip : dns_servers_) {
128 if (!first) {
129 server_addresses += ",";
130 } else {
131 first = false;
132 }
133 server_addresses += (ip + ":" + base::IntToString(kDefaultDNSPort));
134 }
135 status = ares_->SetServersCsv(resolver_state_->channel,
136 server_addresses.c_str());
137 if (status != ARES_SUCCESS) {
138 Error::PopulateAndLog(error, Error::kOperationFailed,
139 "ARES set DNS servers error code: " +
140 base::IntToString(status));
141 resolver_state_.reset();
142 return false;
143 }
144
Paul Stewartc2350ee2011-10-19 12:28:40 -0700145 ares_->SetLocalDev(resolver_state_->channel, interface_name_.c_str());
146 }
147
148 running_ = true;
Darin Petkove636c692012-05-31 10:22:17 +0200149 time_->GetTimeMonotonic(&resolver_state_->start_time);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700150 ares_->GetHostByName(resolver_state_->channel, hostname.c_str(),
151 address_.family(), ReceiveDNSReplyCB, this);
152
153 if (!RefreshHandles()) {
154 LOG(ERROR) << "Impossibly short timeout.";
Paul Stewartbdb02e62012-02-22 16:24:33 -0800155 error->CopyFrom(error_);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700156 Stop();
157 return false;
158 }
159
160 return true;
161}
162
163void DNSClient::Stop() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700164 SLOG(this, 3) << "In " << __func__;
Paul Stewartc2350ee2011-10-19 12:28:40 -0700165 if (!resolver_state_.get()) {
166 return;
167 }
168
169 running_ = false;
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500170 weak_ptr_factory_.InvalidateWeakPtrs();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800171 error_.Reset();
172 address_.SetAddressToDefault();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700173 ares_->Destroy(resolver_state_->channel);
174 resolver_state_.reset();
175}
176
Prathmesh Prabhu3e452f82013-04-10 16:31:44 -0700177bool DNSClient::IsActive() const {
178 return running_;
179}
180
Paul Stewartbdb02e62012-02-22 16:24:33 -0800181// We delay our call to completion so that we exit all IOHandlers, and
182// can clean up all of our local state before calling the callback, or
183// during the process of the execution of the callee (which is free to
184// call our destructor safely).
185void DNSClient::HandleCompletion() {
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700186 SLOG(this, 3) << "In " << __func__;
Paul Stewartbdb02e62012-02-22 16:24:33 -0800187 Error error;
188 error.CopyFrom(error_);
189 IPAddress address(address_);
190 if (!error.IsSuccess()) {
191 // If the DNS request did not succeed, do not trust it for future
192 // attempts.
193 Stop();
194 } else {
195 // Prepare our state for the next request without destroying the
196 // current ARES state.
197 error_.Reset();
198 address_.SetAddressToDefault();
199 }
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500200 callback_.Run(error, address);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800201}
202
Paul Stewartc2350ee2011-10-19 12:28:40 -0700203void DNSClient::HandleDNSRead(int fd) {
204 ares_->ProcessFd(resolver_state_->channel, fd, ARES_SOCKET_BAD);
205 RefreshHandles();
206}
207
208void DNSClient::HandleDNSWrite(int fd) {
209 ares_->ProcessFd(resolver_state_->channel, ARES_SOCKET_BAD, fd);
210 RefreshHandles();
211}
212
213void DNSClient::HandleTimeout() {
214 ares_->ProcessFd(resolver_state_->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
Paul Stewartbdb02e62012-02-22 16:24:33 -0800215 RefreshHandles();
Paul Stewartc2350ee2011-10-19 12:28:40 -0700216}
217
218void DNSClient::ReceiveDNSReply(int status, struct hostent *hostent) {
219 if (!running_) {
220 // We can be called during ARES shutdown -- ignore these events.
221 return;
222 }
Rebecca Silbersteinc9c31d82014-10-21 15:01:00 -0700223 SLOG(this, 3) << "In " << __func__;
Paul Stewartc2350ee2011-10-19 12:28:40 -0700224 running_ = false;
Paul Stewartf582b502012-04-04 21:39:22 -0700225 timeout_closure_.Cancel();
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500226 dispatcher_->PostTask(Bind(&DNSClient::HandleCompletion,
227 weak_ptr_factory_.GetWeakPtr()));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700228
229 if (status == ARES_SUCCESS &&
Ben Chancc225ef2014-09-30 13:26:51 -0700230 hostent != nullptr &&
Paul Stewartc2350ee2011-10-19 12:28:40 -0700231 hostent->h_addrtype == address_.family() &&
Eric Shienbroodc74cf9c2012-03-02 15:00:35 -0500232 static_cast<size_t>(hostent->h_length) ==
233 IPAddress::GetAddressLength(address_.family()) &&
Ben Chancc225ef2014-09-30 13:26:51 -0700234 hostent->h_addr_list != nullptr &&
235 hostent->h_addr_list[0] != nullptr) {
Paul Stewartc2350ee2011-10-19 12:28:40 -0700236 address_ = IPAddress(address_.family(),
237 ByteString(reinterpret_cast<unsigned char *>(
238 hostent->h_addr_list[0]), hostent->h_length));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700239 } else {
240 switch (status) {
241 case ARES_ENODATA:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800242 error_.Populate(Error::kOperationFailed, kErrorNoData);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700243 break;
244 case ARES_EFORMERR:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800245 error_.Populate(Error::kOperationFailed, kErrorFormErr);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700246 break;
247 case ARES_ESERVFAIL:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800248 error_.Populate(Error::kOperationFailed, kErrorServerFail);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700249 break;
250 case ARES_ENOTFOUND:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800251 error_.Populate(Error::kOperationFailed, kErrorNotFound);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700252 break;
253 case ARES_ENOTIMP:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800254 error_.Populate(Error::kOperationFailed, kErrorNotImp);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700255 break;
256 case ARES_EREFUSED:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800257 error_.Populate(Error::kOperationFailed, kErrorRefused);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700258 break;
259 case ARES_EBADQUERY:
260 case ARES_EBADNAME:
261 case ARES_EBADFAMILY:
262 case ARES_EBADRESP:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800263 error_.Populate(Error::kOperationFailed, kErrorBadQuery);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700264 break;
265 case ARES_ECONNREFUSED:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800266 error_.Populate(Error::kOperationFailed, kErrorNetRefused);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700267 break;
268 case ARES_ETIMEOUT:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800269 error_.Populate(Error::kOperationTimeout, kErrorTimedOut);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700270 break;
271 default:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800272 error_.Populate(Error::kOperationFailed, kErrorUnknown);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700273 if (status == ARES_SUCCESS) {
274 LOG(ERROR) << "ARES returned success but hostent was invalid!";
275 } else {
276 LOG(ERROR) << "ARES returned unhandled error status " << status;
277 }
278 break;
279 }
Paul Stewartc2350ee2011-10-19 12:28:40 -0700280 }
281}
282
283void DNSClient::ReceiveDNSReplyCB(void *arg, int status,
284 int /*timeouts*/,
285 struct hostent *hostent) {
286 DNSClient *res = static_cast<DNSClient *>(arg);
287 res->ReceiveDNSReply(status, hostent);
288}
289
290bool DNSClient::RefreshHandles() {
Ben Chane2ee5e02014-09-19 19:29:42 -0700291 map<ares_socket_t, std::shared_ptr<IOHandler>> old_read =
Paul Stewartc2350ee2011-10-19 12:28:40 -0700292 resolver_state_->read_handlers;
Ben Chane2ee5e02014-09-19 19:29:42 -0700293 map<ares_socket_t, std::shared_ptr<IOHandler>> old_write =
Paul Stewartc2350ee2011-10-19 12:28:40 -0700294 resolver_state_->write_handlers;
295
296 resolver_state_->read_handlers.clear();
297 resolver_state_->write_handlers.clear();
298
299 ares_socket_t sockets[ARES_GETSOCK_MAXNUM];
300 int action_bits = ares_->GetSock(resolver_state_->channel, sockets,
Paul Stewartbdb02e62012-02-22 16:24:33 -0800301 ARES_GETSOCK_MAXNUM);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700302
Paul Stewartf582b502012-04-04 21:39:22 -0700303 base::Callback<void(int)> read_callback(
304 Bind(&DNSClient::HandleDNSRead, weak_ptr_factory_.GetWeakPtr()));
305 base::Callback<void(int)> write_callback(
306 Bind(&DNSClient::HandleDNSWrite, weak_ptr_factory_.GetWeakPtr()));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700307 for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
308 if (ARES_GETSOCK_READABLE(action_bits, i)) {
309 if (ContainsKey(old_read, sockets[i])) {
310 resolver_state_->read_handlers[sockets[i]] = old_read[sockets[i]];
311 } else {
312 resolver_state_->read_handlers[sockets[i]] =
Alex Vakulenko8a532292014-06-16 17:18:44 -0700313 std::shared_ptr<IOHandler> (
Paul Stewartc2350ee2011-10-19 12:28:40 -0700314 dispatcher_->CreateReadyHandler(sockets[i],
315 IOHandler::kModeInput,
Paul Stewartf582b502012-04-04 21:39:22 -0700316 read_callback));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700317 }
318 }
319 if (ARES_GETSOCK_WRITABLE(action_bits, i)) {
320 if (ContainsKey(old_write, sockets[i])) {
321 resolver_state_->write_handlers[sockets[i]] = old_write[sockets[i]];
322 } else {
323 resolver_state_->write_handlers[sockets[i]] =
Alex Vakulenko8a532292014-06-16 17:18:44 -0700324 std::shared_ptr<IOHandler> (
Paul Stewartc2350ee2011-10-19 12:28:40 -0700325 dispatcher_->CreateReadyHandler(sockets[i],
326 IOHandler::kModeOutput,
Paul Stewartf582b502012-04-04 21:39:22 -0700327 write_callback));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700328 }
329 }
330 }
331
332 if (!running_) {
Paul Stewartbdb02e62012-02-22 16:24:33 -0800333 // We are here just to clean up socket handles, and the ARES state was
334 // cleaned up during the last call to ares_->ProcessFd().
Paul Stewartc2350ee2011-10-19 12:28:40 -0700335 return false;
336 }
337
338 // Schedule timer event for the earlier of our timeout or one requested by
339 // the resolver library.
340 struct timeval now, elapsed_time, timeout_tv;
Paul Stewarte6927402012-01-23 16:11:30 -0800341 time_->GetTimeMonotonic(&now);
Darin Petkove636c692012-05-31 10:22:17 +0200342 timersub(&now, &resolver_state_->start_time, &elapsed_time);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700343 timeout_tv.tv_sec = timeout_ms_ / 1000;
344 timeout_tv.tv_usec = (timeout_ms_ % 1000) * 1000;
Paul Stewartf582b502012-04-04 21:39:22 -0700345 timeout_closure_.Cancel();
Paul Stewartbdb02e62012-02-22 16:24:33 -0800346
Paul Stewartc2350ee2011-10-19 12:28:40 -0700347 if (timercmp(&elapsed_time, &timeout_tv, >=)) {
348 // There are 3 cases of interest:
Paul Stewartbdb02e62012-02-22 16:24:33 -0800349 // - If we got here from Start(), when we return, Stop() will be
350 // called, so our cleanup task will not run, so we will not have the
351 // side-effect of both invoking the callback and returning False
352 // in Start().
353 // - If we got here from the tail of an IO event, we can't call
354 // Stop() since that will blow away the IOHandler we are running
355 // in. We will perform the cleanup in the posted task below.
356 // - If we got here from a timeout handler, we will perform cleanup
357 // in the posted task.
Paul Stewartc2350ee2011-10-19 12:28:40 -0700358 running_ = false;
Paul Stewartbdb02e62012-02-22 16:24:33 -0800359 error_.Populate(Error::kOperationTimeout, kErrorTimedOut);
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500360 dispatcher_->PostTask(Bind(&DNSClient::HandleCompletion,
361 weak_ptr_factory_.GetWeakPtr()));
Paul Stewartc2350ee2011-10-19 12:28:40 -0700362 return false;
363 } else {
364 struct timeval max, ret_tv;
365 timersub(&timeout_tv, &elapsed_time, &max);
366 struct timeval *tv = ares_->Timeout(resolver_state_->channel,
367 &max, &ret_tv);
Paul Stewartf582b502012-04-04 21:39:22 -0700368 timeout_closure_.Reset(
369 Bind(&DNSClient::HandleTimeout, weak_ptr_factory_.GetWeakPtr()));
370 dispatcher_->PostDelayedTask(timeout_closure_.callback(),
371 tv->tv_sec * 1000 + tv->tv_usec / 1000);
Paul Stewartc2350ee2011-10-19 12:28:40 -0700372 }
373
374 return true;
375}
376
377} // namespace shill