changed how dns deals with cnames and recursion: remember cnames and implement recurs...
[pingcheck] / src / dns / dnsresolver.cpp
CommitLineData
36ad976b
CH
1/*
2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
4
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
7
8 As a special exception, if other files instantiate templates or use macros
9 or inline functions from this file, or you compile this file and link it
10 with other works to produce a work based on this file, this file
11 does not by itself cause the resulting work to be covered
12 by the GNU General Public License.
13
14 However the source code for this file must still be made available
15 in accordance with section (3) of the GNU General Public License.
16
17 This exception does not invalidate any other reasons why a work based
18 on this file might be covered by the GNU General Public License.
19
20 Christian Herdtweck, Intra2net AG 2015
4e7b6ff9
CH
21
22 with code copied from boost::net::dns::resolve.hpp
23 by Andreas Haberstroh (andreas at ibusy dot com)
24 from https://github.com/softwareace/Boost.DNS
36ad976b
CH
25 */
26
c5b4902d
CH
27#include "dns/dnsresolver.h"
28
29#include <stdint.h>
e91538f0 30#include <sstream>
36ad976b 31
4e7b6ff9
CH
32#include <boost/foreach.hpp>
33#include <boost/bind.hpp>
34#include <boost/function.hpp>
35#include <boost/net/dns.hpp>
36#include <boost/date_time/posix_time/posix_time.hpp>
ad83004d
CH
37#include <boost/uuid/uuid.hpp>
38#include <boost/uuid/uuid_io.hpp>
4e7b6ff9 39
36ad976b 40#include <logfunc.hpp>
4e7b6ff9 41
36ad976b 42using I2n::Logger::GlobalLogger;
4e7b6ff9
CH
43using boost::posix_time::seconds;
44using boost::posix_time::minutes;
36ad976b
CH
45
46namespace Config
47{
96779587
CH
48 const int ResolveTimeoutSeconds = 5;
49 const int PauseBeforeRetrySeconds = 10;
50 const int StaleDataLongtermMinutes = 15;
36ad976b 51 const int DNS_PORT = 53;
36ad976b
CH
52}
53
4e7b6ff9
CH
54DnsResolver::DnsResolver(IoServiceItem &io_serv,
55 const std::string &hostname,
923626c0 56 const DnsIpProtocol &protocol,
96779587 57 const DnsCacheItem cache,
96779587 58 const boost::asio::ip::address &name_server)
4e7b6ff9 59 : ResolverBase( io_serv, hostname, cache )
e91538f0
CH
60 , Socket( *io_serv, ip::udp::endpoint(ip::udp::v4(), 0))
61 // just connect to anything, will specify sender/receiver later
4e7b6ff9 62 , ReceiveBuffer()
ad83004d 63 , RequestBuffer()
923626c0 64 , Protocol( protocol )
4e7b6ff9 65 , NameServer( name_server, Config::DNS_PORT )
36ad976b
CH
66 , ResolveTimeoutTimer( *io_serv )
67 , PauseBeforeRetryTimer( *io_serv )
68 , StaleDataLongtermTimer( *io_serv )
4e7b6ff9 69 , NextIpIndex( 0 )
36ad976b
CH
70 , RetryCount( 0 )
71 , IsResolving( false )
e91538f0 72 , LogPrefix( "DnsResolver" )
ad83004d
CH
73 , RandomIdGenerator()
74 , RequestId( 0 )
e91538f0
CH
75{
76 std::stringstream temp;
77 temp << "Dns(" << ResolverBase::Hostname << "): ";
78 LogPrefix = temp.str();
ad83004d 79
e91538f0 80}
96779587 81
c5b4902d
CH
82DnsResolver::~DnsResolver()
83{
84 boost::system::error_code error;
e91538f0 85 Socket.shutdown(boost::asio::ip::udp::socket::shutdown_both, error);
c5b4902d 86 if ( error )
e91538f0 87 GlobalLogger.warning() << LogPrefix << "Received error " << error
c5b4902d
CH
88 << " when shutting down socket for DNS";
89 // in IcmpPinger always gave an error system:9
90 // (probably EBADF: Bad file descriptor)
91
92 Socket.close(error);
93 if ( error )
e91538f0 94 GlobalLogger.warning() << LogPrefix << "Received error " << error
c5b4902d
CH
95 << " when closing socket for DNS";
96}
97
98
96779587
CH
99
100//==============================================================================
101// ASYNC RESOLVE
102//==============================================================================
36ad976b
CH
103
104/**
c5b4902d 105 * copied here code from boost::net::dns::resolve.hpp, since want async
36ad976b 106 * operation and that is used only internally, there
36ad976b 107 */
4e7b6ff9 108void DnsResolver::do_resolve()
36ad976b 109{
36ad976b 110 // check if resolving already
4e7b6ff9 111 if (IsResolving)
36ad976b 112 {
e91538f0 113 GlobalLogger.info() << LogPrefix
4e7b6ff9 114 << "Call to do_resolve ignored since resolving already";
36ad976b
CH
115 return;
116 }
ad83004d 117 IsResolving = true;
36ad976b 118
e91538f0
CH
119 GlobalLogger.info() << LogPrefix << "start resolving";
120
36ad976b
CH
121 // just to be sure: cancel timers
122 ResolveTimeoutTimer.cancel();
123 PauseBeforeRetryTimer.cancel();
124 StaleDataLongtermTimer.cancel();
125
126 // create DNS request
4e7b6ff9 127 boost::net::dns::message dns_message( ResolverBase::Hostname,
ad83004d 128 boost::net::dns::type_a); //all ); DEBUG
36ad976b 129 dns_message.recursive(false);
4e7b6ff9
CH
130 dns_message.action(boost::net::dns::message::query);
131 dns_message.opcode(boost::net::dns::message::squery);
ad83004d
CH
132
133 // create random ID for message
134 boost::uuids::uuid message_id = RandomIdGenerator();
135 memcpy( &RequestId, message_id.data, sizeof(RequestId) );
136 dns_message.id( RequestId );
137 GlobalLogger.debug() << LogPrefix << "Request has ID "
138 << std::showbase << std::hex << dns_message.id();
36ad976b
CH
139
140 // setup receipt of reply
141 Socket.async_receive_from(
142 boost::asio::buffer(ReceiveBuffer.get_array()),
143 NameServer,
144 boost::bind( &DnsResolver::handle_dns_result, this,
145 boost::asio::placeholders::error,
146 boost::asio::placeholders::bytes_transferred)
4e7b6ff9 147 );
36ad976b
CH
148
149 // schedule timeout
4e7b6ff9
CH
150 (void) ResolveTimeoutTimer.expires_from_now(
151 seconds(Config::ResolveTimeoutSeconds));
152 ResolveTimeoutTimer.async_wait( boost::bind(
153 &DnsResolver::handle_resolve_timeout,
154 this, boost::asio::placeholders::error) );
36ad976b
CH
155
156 // send dns request
ad83004d 157 dns_message.encode(RequestBuffer);
e91538f0
CH
158 size_t bytes_sent;
159 try
160 {
161 bytes_sent = Socket.send_to(
ad83004d 162 boost::asio::buffer(RequestBuffer.get_array()),
e91538f0
CH
163 NameServer );
164 }
165 catch (boost::system::system_error &err)
166 {
167 GlobalLogger.warning() << LogPrefix
168 << "Sending of DNS request message failed: "
169 << err.what();
170 handle_unavailable();
171 return;
172 }
173
174 if ( bytes_sent == 0 )
175 {
176 GlobalLogger.warning() << LogPrefix << "Empty DNS request sent!";
177 handle_unavailable();
178 return;
179 }
180
181 GlobalLogger.info() << LogPrefix << "resolving under way";
36ad976b
CH
182}
183
184
4e7b6ff9 185void DnsResolver::handle_dns_result(const boost::system::error_code &error,
ad83004d 186 const std::size_t bytes_transferred)
36ad976b
CH
187{
188 if ( error == boost::asio::error::operation_aborted ) // cancelled
189 {
e91538f0
CH
190 GlobalLogger.info() << LogPrefix
191 << "DNS resolve operation was cancelled";
36ad976b 192 bool was_success = false;
96779587 193 finalize_resolve(was_success);
36ad976b
CH
194 }
195 else if (error)
196 {
e91538f0
CH
197 GlobalLogger.info() << LogPrefix << "DNS resolve resulted in error "
198 << error << " --> treat like unavailable";
36ad976b
CH
199 handle_unavailable();
200 return;
201 }
202
ad83004d
CH
203 GlobalLogger.debug() << LogPrefix << "Handling DNS result ("
204 << bytes_transferred << " bytes transferred)";
205
36ad976b
CH
206 // next 3(+1) lines copied from boost/net/dns/resolver.hpp:
207 // clamp the recvBuffer with the number of bytes transferred or decode buffr
208 ReceiveBuffer.length(bytes_transferred);
4e7b6ff9 209 boost::net::dns::message result_message;
36ad976b
CH
210 result_message.decode( ReceiveBuffer );
211
ad83004d
CH
212 // check ID
213 if (RequestId != result_message.id())
214 GlobalLogger.warning() << "Received answer for request ID "
215 << std::showbase << std::hex << result_message.id()
216 << " but expected ID " << RequestId;
217 else
218 GlobalLogger.debug() << LogPrefix << "Result has correct ID "
219 << std::showbase << std::hex << RequestId;
220
221 // loop over answers, remembering ips and cnames
4e7b6ff9
CH
222 // work with a regular pointer to list of answers since result_message is
223 // owner of data and that exists until end of function
224 // Items in answers list are shared_ptr to resource_base_t
ad83004d
CH
225 HostAddressVec ip_list;
226 std::vector<std::string> hosts_for_ips;
227 std::vector<string_pair> result_cnames;
228 std::vector<string_pair> result_nameservers;
36ad976b 229
ad83004d
CH
230 gather_results(result_message.answers(), &ip_list, &hosts_for_ips,
231 &result_cnames, &result_nameservers);
232
233 // remember cname tree (if there were any)
234 // assume each cname points to next ( source --> destination )
235 std::string source = ResolverBase::Hostname;
236 BOOST_FOREACH( const std::string &cname, result_cnames )
237 {
238 update_cache( source, cname );
239 source = cname;
240 }
241
242 // IPs point to last CNAME (or Hostname if no cnames given)
243 if ( !ip_list.empty() )
244 {
245 update_cache( source, ip_list );
246
247 // clean up
248 bool was_success = true;
249 finalize_resolve(was_success);
250 }
251 else if ( !result_cnames.empty() )
252 { // no IPs but a cname --> re-start resolving with that
253 handle_cname(source);
254 }
255 else
256 { // no answers --> check for nameservers in authorities section
257 // and corresponding IPs in additional section
258 if ( !result_nameservers.empty() )
259 GlobalLogger.warning() << "Received NS records in answers! "
260 << "That is quite unexpected..."
261 gather_results(result_message.authorites(), &ip_list, &hosts_for_ips,
262 &result_cnames, &result_nameservers);
263 gather_results(result_message.additionals(), &ip_list, &hosts_for_ips,
264 &result_cnames, &result_nameservers);
265
266 int index, index_found=-1;
267 // go through name servers
268 BOOST_FOREACH( const string_pair &nameserver, result_nameservers )
269 {
270 index = 0;
271 // go through ips and look for match
272 BOOST_FOREACH( const std::string &ip_host, hosts_for_ips )
273 {
274 if (nameserver.second == ip_host)
275 {
276 index_found = index;
277 break;
278 }
279 ++index;
280 }
281
282 if (index_found > -1)
283 break;
284 }
285 if (index_found > -1)
286 { // have a name server with ip
287 handle_recurse(ip_list[index_found]);
288
289
290 GlobalLogger.info() << LogPrefix << "Have " << result_ips.size()
291 << " IPs and " << result_cnames.size() << " CNAMEs";
292
293 // We expect either one single CNAME and no IPs or a list of IPs.
294 // But deal with other cases as well
295 if (result_ips.empty() && result_cnames.empty())
296 handle_unavailable(); // we just got crap, this is a dead end
297
298 bool do_resolve_cnames = !Config::DnsRequestsAreRecursive;
299
300 if (Config::DnsRequestsAreRecursive && !result_cnames.empty()
301 && result_ips.empty() )
302 {
303 GlobalLogger.warning() << LogPrefix << "CNAMES appear to be unresolved"
304 << " although DNS requests are recursive! --> try on our own";
305 do_resolve_cnames = true;
306 }
307 else
308 GlobalLogger.info() << LogPrefix << "Ignore CNAMES, assume they were "
309 << "resolved";
310
311 if (do_resolve_cnames)
312 {
313 BOOST_FOREACH( const std::string &cname, result_cnames )
314 handle_cname(cname); // will schedule another DNS call
315 }
316
317 if ( !result_ips.empty() )
318 handle_ips(result_ips);
319}
320
321void DnsResolver::gather_results(const boost::net::dns::rr_list_t *answers,
322 HostAddressVec *result_ips,
323 std::vector<std::string> *hosts_for_ips,
324 std::vector<string_pair> *result_cnames,
325 std::vector<string_pair> *result_nameservers)
326 const
327{
4e7b6ff9
CH
328 using boost::net::dns::resource_base_t;
329 BOOST_FOREACH( boost::shared_ptr<resource_base_t> rr_item, *answers )
36ad976b 330 {
4e7b6ff9 331 boost::net::dns::type_t rr_type = rr_item->rtype();
ad83004d
CH
332 uint32_t ttl = rr_item->ttl();
333 std::string domain = rr_item->domain();
36ad976b
CH
334
335 if (rr_type == boost::net::dns::type_a)
336 { // 'A' resource records carry IPv4 addresses
923626c0
CH
337 if (Protocol == DNS_IPv6)
338 {
e91538f0
CH
339 GlobalLogger.info() << LogPrefix << "Ignoring IPv4 address "
340 << "because resolver was configured to only use IPv6.";
923626c0
CH
341 continue;
342 }
4e7b6ff9
CH
343 boost::asio::ip::address_v4 ip =
344 ( dynamic_cast<boost::net::dns::a_resource *> (rr_item.get()) )
345 ->address();
ad83004d
CH
346 hosts_for_ips->push_back( domain );
347 result_ips->push_back( HostAddress(ip, ttl) );
348 GlobalLogger.debug() << LogPrefix << "IPv4 " << ip << " with TTL "
349 << ttl << "s for " << domain;
36ad976b
CH
350 }
351 else if (rr_type == boost::net::dns::type_a6)
352 { // 'AAAA' resource records carry IPv6 addresses
923626c0
CH
353 if (Protocol == DNS_IPv4)
354 {
e91538f0
CH
355 GlobalLogger.info() << LogPrefix << "Ignoring IPv6 address "
356 << "because resolver was configured to only use IPv4.";
923626c0
CH
357 continue;
358 }
4e7b6ff9
CH
359 boost::asio::ip::address_v6 ip =
360 ( dynamic_cast<boost::net::dns::a6_resource *> (rr_item.get()) )
361 ->address();
ad83004d
CH
362 hosts_for_ips->push_back( domain );
363 result_ips->push_back( HostAddress(ip, ttl) );
364 GlobalLogger.debug() << LogPrefix << "IPv6 " << ip << " with TTL "
365 << ttl << "s for " << domain;
36ad976b
CH
366 }
367 else if (rr_type == boost::net::dns::type_cname)
368 { // 'CNAME' resource records that carry aliases
4e7b6ff9
CH
369 std::string cname =
370 (dynamic_cast<boost::net::dns::cname_resource *>(rr_item.get()))
371 ->canonicalname();
ad83004d
CH
372 result_cnames->push_back( string_pair(domain, cname) );
373 GlobalLogger.debug() << LogPrefix << "CNAME " << cname
374 << " with TTL " << ttl << "s for " << domain;
36ad976b
CH
375 }
376 else if (rr_type == boost::net::dns::type_ns)
ad83004d
CH
377 { // NS (nameserver) resource records
378 std::string nameserver =
379 (dynamic_cast<boost::net::dns::ns_resource *>(rr_item.get()))
380 ->nameserver();
381 result_nameservers->push_back( string_pair(domain, nameserver) );
382 GlobalLogger.debug() << LogPrefix << "NameServer " << nameserver
383 << " with TTL " << ttl << "s for " << domain;
384 }
36ad976b 385 else if (rr_type == boost::net::dns::type_soa)
e91538f0 386 GlobalLogger.debug() << LogPrefix << "SOA resource";
36ad976b 387 else if (rr_type == boost::net::dns::type_ptr)
e91538f0 388 GlobalLogger.debug() << LogPrefix << "ptr resource";
36ad976b 389 else if (rr_type == boost::net::dns::type_hinfo)
e91538f0 390 GlobalLogger.debug() << LogPrefix << "hinfo resource";
36ad976b 391 else if (rr_type == boost::net::dns::type_mx)
e91538f0 392 GlobalLogger.debug() << LogPrefix << "mx resource";
36ad976b 393 else if (rr_type == boost::net::dns::type_txt)
e91538f0 394 GlobalLogger.debug() << LogPrefix << "txt resource";
36ad976b 395 else if (rr_type == boost::net::dns::type_srv)
e91538f0 396 GlobalLogger.debug() << LogPrefix << "srv resource";
36ad976b 397 else if (rr_type == boost::net::dns::type_axfr)
e91538f0 398 GlobalLogger.debug() << LogPrefix << "axfr resource";
36ad976b 399 else
ad83004d
CH
400 GlobalLogger.debug() << LogPrefix << "unknown resource type: "
401 << std::showbase << std::hex
402 << static_cast<unsigned>(rr_item->rtype());
36ad976b 403 }
36ad976b
CH
404}
405
406
4e7b6ff9 407void DnsResolver::handle_ips(const HostAddressVec &ips)
36ad976b 408{
36ad976b 409 // save in cache
96779587 410 ResolverBase::update_cache( ips );
36ad976b
CH
411
412 // clean up
413 bool was_success = true;
96779587 414 finalize_resolve(was_success);
36ad976b
CH
415}
416
417
418void DnsResolver::handle_unavailable()
419{
420 // schedule new attempt in quite a while
4e7b6ff9
CH
421 StaleDataLongtermTimer.expires_from_now(
422 minutes(Config::StaleDataLongtermMinutes));
36ad976b 423 StaleDataLongtermTimer.async_wait(
4e7b6ff9
CH
424 boost::bind( &DnsResolver::wait_timer_timeout_handler,
425 this, boost::asio::placeholders::error
36ad976b
CH
426 )
427 );
428
429 // for now, admit failure
430 bool was_success = false;
96779587 431 finalize_resolve(was_success);
36ad976b
CH
432}
433
434void DnsResolver::handle_cname(const std::string &canonical_name)
435{
436 // get resolver for canonical name
96779587 437 ResolverItem resolver = DnsMaster::get_instance()
923626c0 438 ->get_resolver_for(canonical_name, Protocol);
4e7b6ff9
CH
439 callback_type callback = boost::bind( &DnsResolver::cname_resolve_callback,
440 this, canonical_name, _1, _2 );
441 resolver->async_resolve( callback );
36ad976b
CH
442
443 stop_trying();
444}
445
446
4e7b6ff9
CH
447void DnsResolver::cname_resolve_callback(const std::string &canonical_name,
448 const bool was_success,
ad83004d 449 const int recursion_count)
36ad976b 450{
96779587 451 if (was_success)
4e7b6ff9 452 // tell cache to return cname's ips if queried for our hostname
96779587
CH
453 ResolverBase::update_cache(
454 ResolverBase::get_cached_results(canonical_name) );
96779587 455 else
e91538f0 456 GlobalLogger.info() << LogPrefix << "Cname resolution failed";
96779587 457
ad83004d
CH
458 // cname counts like one recursion step more...
459 finalize_resolve(was_success, recursion_count+1);
460}
461
462void DnsResolver::handle_recurse(const HostAddress &name_server)
463{
464 // get resolver for same hostname but using a different name server
465 if (Recursor)
466 {
467 GlobalLogger.warning() << "Recursor has not been reset!";
468 Recursor.reset();
469 }
470
471 Recursor = DnsMaster::get_instance()->get_recursor_for(
472 Hostname, Protocol, name_server.get_ip());
473 callback_type callback = boost::bind(
474 &DnsResolver::recursive_resolve_callback,
475 this, name_server.get_ttl().get_value(),
476 _1, _2 );
477 Recursor->async_resolve( callback );
478
479 stop_trying();
480}
481
482
483
484void DnsResolver::recursive_resolve_callback(const uint32_t min_ttl,
485 const bool was_success,
486 const int recursion_count)
487{
488 if (was_success)
489 // make sure the saved TTL is not larger than the one we found here
490 ResolverBase::update_cache_ttl(min_ttl);
491 else
492 GlobalLogger.info() << LogPrefix << "Recursive resolution failed";
493
494 // do not need recursor any more; next time re-create from different random
495 // name server
496 if ( !Recursor )
497 GlobalLogger.warning() << "Recursor was reset before callback!";
498 else
499 Recursor.reset();
500
501 finalize_resolve(was_success, recursion_count+1);
502
96779587
CH
503}
504
505
506void DnsResolver::finalize_resolve(const bool was_success,
ad83004d 507 const int recursion_count)
96779587
CH
508{
509 // stop timers
ad83004d 510 if (recursion_count > 0)
96779587
CH
511 stop_trying();
512 // else was called already from handle_cname
513
514 // schedule callbacks, clearing callback list
ad83004d 515 ResolverBase::schedule_callbacks(was_success, recursion_count);
96779587
CH
516
517 // finalize
e91538f0 518 GlobalLogger.notice() << LogPrefix << "Done resolving"
96779587 519 << " with success = " << was_success
ad83004d 520 << " and recursion_count = " << recursion_count;
96779587
CH
521 IsResolving = false;
522}
523
524void DnsResolver::stop_trying()
525{
526 // cancel timers
e91538f0 527 GlobalLogger.debug() << LogPrefix << "Cancelling timers";
96779587
CH
528 ResolveTimeoutTimer.cancel();
529 PauseBeforeRetryTimer.cancel();
530 StaleDataLongtermTimer.cancel();
531
532 // clean up
533 RetryCount = 0;
534}
535
4e7b6ff9 536void DnsResolver::handle_resolve_timeout(const boost::system::error_code &error)
96779587
CH
537{
538 if ( error == boost::asio::error::operation_aborted ) // cancelled
539 {
e91538f0
CH
540 GlobalLogger.warning() << LogPrefix
541 << "Resolve timeout timer was cancelled!";
96779587
CH
542 return;
543 }
544 else if (error)
545 {
e91538f0
CH
546 GlobalLogger.warning() << LogPrefix
547 << "resolve timeout handler received error "
96779587
CH
548 << error;
549 return;
550 }
551
e91538f0 552 GlobalLogger.notice() << LogPrefix << "DNS resolving timed out";
36ad976b 553
96779587
CH
554 // increment timer
555 ++RetryCount;
556
923626c0
CH
557 if ( RetryCount > DnsMaster::get_instance()
558 ->get_max_address_resolution_attempts() )
96779587
CH
559 {
560 handle_unavailable();
561 RetryCount = 0;
562 }
563 else
564 { // schedule retry
565 PauseBeforeRetryTimer.expires_from_now(
4e7b6ff9 566 seconds(Config::PauseBeforeRetrySeconds));
96779587 567 PauseBeforeRetryTimer.async_wait(
4e7b6ff9
CH
568 boost::bind( &DnsResolver::wait_timer_timeout_handler,
569 this, boost::asio::placeholders::error) );
96779587
CH
570 }
571}
572
573void DnsResolver::wait_timer_timeout_handler(
574 const boost::system::error_code &error)
575{
576 if ( error == boost::asio::error::operation_aborted ) // cancelled
e91538f0
CH
577 GlobalLogger.warning() << LogPrefix
578 << "Resolve timeout timer was cancelled!";
96779587 579 else if (error)
e91538f0
CH
580 GlobalLogger.warning() << LogPrefix
581 << "resolve timeout handler received error "
96779587
CH
582 << error;
583 else
584 {
e91538f0 585 GlobalLogger.info() << LogPrefix << "Done waiting --> re-try resolve";
4e7b6ff9 586 do_resolve();
96779587 587 }
36ad976b
CH
588}
589
590
96779587
CH
591//==============================================================================
592// RETRIEVAL
593//==============================================================================
594
4e7b6ff9 595HostAddress DnsResolver::get_next_ip()
36ad976b
CH
596{
597 // get cached data
4e7b6ff9 598 HostAddressVec cached_data = ResolverBase::get_cached_results();
96779587
CH
599
600 // if no results cached, return default-constructed HostAddress (0.0.0.0)
601 if ( cached_data.empty() )
4e7b6ff9
CH
602 {
603 HostAddress return_value;
604 return return_value;
605 }
36ad976b 606
96779587
CH
607 // check validity of index (cache may have changed since last call)
608 if (NextIpIndex >= cached_data.size())
609 NextIpIndex = 0;
36ad976b 610
96779587
CH
611 // return next IP
612 return cached_data[NextIpIndex++];
36ad976b
CH
613}
614
923626c0
CH
615bool DnsResolver::have_up_to_date_ip()
616{
617 // get cached data
618 HostAddressVec cached_data = ResolverBase::get_cached_results();
619
620 // get threshold
c5b4902d
CH
621 uint32_t resolved_ip_ttl_threshold = static_cast<uint32_t>(
622 DnsMaster::get_instance()->get_resolved_ip_ttl_threshold() );
923626c0
CH
623
624 // loop over addresses
625 BOOST_FOREACH( const HostAddress &addr, cached_data )
626 {
627 uint32_t ttl = addr.get_ttl().get_updated_value();
628 if ( ttl > resolved_ip_ttl_threshold )
629 return true;
630 }
631
632 // if not returned true by now, we have tried all IPs without success
633 return false;
634}
635
636int DnsResolver::get_resolved_ip_count()
637{
638 return ResolverBase::get_cached_results().size();
639}
640
36ad976b
CH
641// (created using vim -- the world's best text editor)
642