From: Christian Herdtweck Date: Thu, 23 Apr 2015 08:38:20 +0000 (+0200) Subject: finished self-implementation of DNS resolver recursion; will now remove all that! X-Git-Url: http://developer.intra2net.com/git/?p=pingcheck;a=commitdiff_plain;h=dbe986b996b27c1de97fc91d8cee8eb47f0c2e70 finished self-implementation of DNS resolver recursion; will now remove all that! implemented resolving that avoids caching by creating non-recursive queries that are directly talking to different name servers; will remove this now because firewalls might prevent direct communication and do not want to self-implement dnssec some time. --> now remove own implementation of recursion in resolving and try to deal with cached results --- diff --git a/src/dns/dnscache.cpp b/src/dns/dnscache.cpp index f065223..e87c039 100644 --- a/src/dns/dnscache.cpp +++ b/src/dns/dnscache.cpp @@ -36,6 +36,8 @@ #include #include +#include "dns/dnsmaster.h" + using boost::bind; using boost::posix_time::seconds; using I2n::Logger::GlobalLogger; @@ -43,10 +45,9 @@ using I2n::Logger::GlobalLogger; namespace Config { int SaveTimerSeconds = 60; + int MaxRetrievalRecursions = 10; } - - DnsCache::DnsCache(const IoServiceItem &io_serv, const std::string &cache_file) : IpCache() @@ -182,16 +183,16 @@ void DnsCache::update(const std::string &hostname, void DnsCache::update(const std::string &hostname, - const std::string &cname) + const Cname &cname) { GlobalLogger.info() << "DnsCache: update CNAME for " << hostname - << " to " << cname; + << " to " << cname.first; CnameCache[hostname] = cname; HasChanged = true; } -void DnsCache::update_ttl(const std::string &hostname, +void DnsCache::update(const std::string &hostname, const uint32_t new_ttl) { GlobalLogger.info() << "DnsCache: ensure TTL for IPs for " << hostname @@ -212,31 +213,72 @@ void DnsCache::update_ttl(const std::string &hostname, } -HostAddressVec& DnsCache::get_ips(const std::string &hostname) +HostAddressVec DnsCache::get_ips(const std::string &hostname, + const bool check_up_to_date) { + HostAddressVec result = IpCache[hostname]; + if (check_up_to_date) + { + HostAddressVec result_up_to_date; + int threshold = DnsMaster::get_instance() + ->get_resolved_ip_ttl_threshold(); + BOOST_FOREACH( const HostAddress &addr, result ) + { + if (addr.get_ttl().get_updated_value() > threshold) + result_up_to_date.push_back(addr); + } + GlobalLogger.debug() << "DnsCache: From cached list of size " + << result.size() << " return " << result_up_to_date.size() + << " since rest out of date"; + result = result_up_to_date; + } GlobalLogger.info() << "DnsCache: request IPs for " << hostname - << " --> " << IpCache[hostname].size() << "-list"; - return IpCache[hostname]; + << " --> " << result.size() << "-list"; + return result; } -std::string& DnsCache::get_cname(const std::string &hostname) +std::string DnsCache::get_cname(const std::string &hostname, + const bool check_up_to_date) { + Cname result_obj = CnameCache[hostname]; GlobalLogger.info() << "DnsCache: request CNAME for " << hostname - << " --> \"" << CnameCache[hostname] << "\""; - return CnameCache[hostname]; + << " --> \"" << result_obj.first << "\""; + if (check_up_to_date) + { + if (result_obj.second.get_updated_value() > DnsMaster::get_instance() + ->get_resolved_ip_ttl_threshold()) + return result_obj.first; + else + { + GlobalLogger.debug() << "DnsCache: Cname is out of date"; + return ""; + } + } + else + return result_obj.first; } -HostAddressVec& DnsCache::get_ips_recursive(const std::string &hostname) +// underlying assumption in this function: for a hostname, the cache has either +// a list of IPs saved or a cname saved, but never both +HostAddressVec DnsCache::get_ips_recursive(const std::string &hostname, + const bool check_up_to_date) { std::string current_host = hostname; - HostAddressVec& result = get_ips(current_host); + HostAddressVec result = get_ips(current_host); + int n_recursions = 0; while ( result.empty() ) { - current_host = get_cname(current_host); + current_host = get_cname(current_host, check_up_to_date); if (current_host.empty()) break; + else if (++n_recursions >= Config::MaxRetrievalRecursions) + { + GlobalLogger.warning() << "DnsCache: reached recursion limit of " + << n_recursions << " in recursive IP retrieval!"; + break; + } else - result = get_ips(current_host); + result = get_ips(current_host, check_up_to_date); } return result; } diff --git a/src/dns/dnscache.h b/src/dns/dnscache.h index c3879ae..c213777 100644 --- a/src/dns/dnscache.h +++ b/src/dns/dnscache.h @@ -31,10 +31,13 @@ #include "host/pinger.h" // for IoserviceItem #include "dns/hostaddress.h" +#include "dns/timetolive.h" typedef std::vector HostAddressVec; typedef std::map ip_map_type; -typedef std::map cname_map_type; +typedef std::pair Cname; +typedef std::map cname_map_type; + class DnsCache { @@ -45,11 +48,14 @@ public: // accessed from ResolverBase subclasses void update(const std::string &hostname, const HostAddressVec &new_data); - void update(const std::string &hostname, const std::string &cname); - void update_ttl(const std::string &hostname, const uint32_t ttl); - HostAddressVec& get_ips(const std::string &hostname); - std::string& get_cname(const std::string &hostname); - HostAddressVec& get_ips_recursive(const std::string &hostname); + void update(const std::string &hostname, const Cname &cname); + void update(const std::string &hostname, const uint32_t ttl); + HostAddressVec get_ips(const std::string &hostname, + const bool check_up_to_date=false); + std::string get_cname(const std::string &hostname, + const bool check_up_to_date=false); + HostAddressVec get_ips_recursive(const std::string &hostname, + const bool check_up_to_date=false); // variables private: diff --git a/src/dns/dnsmaster.cpp b/src/dns/dnsmaster.cpp index 0346fc5..5b0a1ce 100644 --- a/src/dns/dnsmaster.cpp +++ b/src/dns/dnsmaster.cpp @@ -103,7 +103,7 @@ ResolverItem& DnsMaster::get_resolver_for( const std::string &hostname, const PingProtocol &ping_protocol ) { // find suitable DnsIpProtocol for ping protocol - DnsIpProtocol protocol = DnsMaster::ping2dns_protocol(ping_protocol); + DnsIpProtocol protocol = ping2dns_protocol(ping_protocol); return get_resolver_for(hostname, protocol); } @@ -111,15 +111,13 @@ ResolverItem& DnsMaster::get_resolver_for( const std::string &hostname, ResolverItem& DnsMaster::get_resolver_for(const std::string &hostname, const DnsIpProtocol &protocol) { - DnsMasterItem master = get_instance(); - // create key to ResolverMap resolver_key_type key(hostname, protocol); - if ( master->ResolverMap.count(key) == 0 ) + if ( ResolverMap.count(key) == 0 ) { // need to create a resolver // check if it is an ip address, so can create a simple pseudo resolver - if ( master->is_ip(hostname) ) + if ( is_ip(hostname) ) { boost::asio::ip::address ip = boost::asio::ip::address::from_string(hostname); @@ -132,20 +130,21 @@ ResolverItem& DnsMaster::get_resolver_for(const std::string &hostname, ResolverItem new_resolver( new IpPseudoResolver(IoService, hostname, Cache) ); - master->ResolverMap[key] = new_resolver; + ResolverMap[key] = new_resolver; } else { - GlobalLogger.info() << "Creating Resolver for host " << hostname; + GlobalLogger.info() << "DnsMaster: Creating Resolver for host " + << hostname << " and protocol " << to_string(protocol); ResolverItem new_resolver( new DnsResolver(IoService, hostname, protocol, Cache, DefaultNameServer) ); - master->ResolverMap[key] = new_resolver; + ResolverMap[key] = new_resolver; } } - return master->ResolverMap[key]; + return ResolverMap[key]; } // create resolver but do not remember it in ResolverMap @@ -153,6 +152,15 @@ ResolverItem DnsMaster::get_recursor_for(const std::string &hostname, const DnsIpProtocol &protocol, const boost::asio::ip::address &name_server) { + resolver_key_type key(hostname, protocol); + if ( !ResolverMap[key] ) + GlobalLogger.warning() << "DnsMaster: requesting recursor for host " + << hostname << " and protocol " << to_string(protocol) + << " but have no regular resolver for this combination!"; + else + GlobalLogger.warning() << "DnsMaster: requesting recursor for host " + << hostname << " and protocol " << to_string(protocol); + ResolverItem new_resolver( new DnsResolver(IoService, hostname, protocol, diff --git a/src/dns/dnsmaster.h b/src/dns/dnsmaster.h index 128633f..63e5be9 100644 --- a/src/dns/dnsmaster.h +++ b/src/dns/dnsmaster.h @@ -61,6 +61,23 @@ typedef std::map resolver_map_type; std::string to_string(const DnsIpProtocol &protocol); +/** + * Factory and Cache of DNS resolvers + * + * to avoid having several resolvers resolving the same hostname which might + * result in conflicts with caching, this class is a singleton factory and the + * only place where Resolvers are constructed. They are remembered in an + * internal cache by hostname and IP version requested (v4, v6 or both). + * + * During resolving, several different name servers will have to be queried for + * the same hostname. These recursive resolvers are created using + * get_recursor_for and are NOT cached, so they should only be used from another + * "regular" resolver (created using get_resolver_for) + * + * The DnsMaster also remembers a few global variables that can be queried + * using public getter functions and it creates the DnsCache used by all its + * resolvers + */ class DnsMaster : boost::noncopyable { // Resolver factory @@ -93,7 +110,7 @@ public: // storage of global variables public: - //boost::asio::ip::address &get_name_server() const; // currently unused + //boost::asio::ip::address &get_default_name_server() const; // unused int get_resolved_ip_ttl_threshold() const; int get_max_address_resolution_attempts() const; diff --git a/src/dns/dnsresolver.cpp b/src/dns/dnsresolver.cpp index 5a9cef2..139219c 100644 --- a/src/dns/dnsresolver.cpp +++ b/src/dns/dnsresolver.cpp @@ -45,7 +45,7 @@ using boost::posix_time::minutes; namespace Config { - const int ResolveTimeoutSeconds = 0; + const int ResolveTimeoutSeconds = 3; const int PauseBeforeRetrySeconds = 10; const int StaleDataLongtermMinutes = 15; const int DNS_PORT = 53; @@ -224,17 +224,22 @@ void DnsResolver::handle_dns_result(const boost::system::error_code &error, // owner of data and that exists until end of function // Items in answers list are shared_ptr to resource_base_t std::vector result_ips; - std::vector result_cnames; - std::vector result_nameservers; + std::vector result_cnames; + std::vector result_name_servers; + GlobalLogger.debug() << "Checking ANSWERS section of dns reply"; gather_results(result_message.answers(), &result_ips, &result_cnames, - &result_nameservers); + &result_name_servers); // results should have the logical order // Hostname [ --> cname1 --> cname2 --> ... --> cnameN ] [ --> ips ] // remember cname list (if there were any) - BOOST_FOREACH( const string_pair &host_and_cname, result_cnames ) + BOOST_FOREACH( const src_cname_pair &host_and_cname, result_cnames ) + { + GlobalLogger.debug() << LogPrefix << "Remember CNAME " + << host_and_cname.first << " --> " << host_and_cname.second.first; ResolverBase::update_cache(host_and_cname.first, host_and_cname.second); + } if ( !result_ips.empty() ) handle_ips( result_ips ); @@ -243,29 +248,38 @@ void DnsResolver::handle_dns_result(const boost::system::error_code &error, // re-start resolving with that handle_cname(result_cnames); else - { // no answers --> check for nameservers in authorities section - if ( !result_nameservers.empty() ) + { // no answers --> check for name_servers in authorities section + if ( !result_name_servers.empty() ) GlobalLogger.warning() << LogPrefix << "Received NS records in answers! " << "That is quite unexpected..."; + GlobalLogger.debug() << "Checking AUTHORITIES section of dns reply"; gather_results(result_message.authorites(), &result_ips, - &result_cnames, &result_nameservers); + &result_cnames, &result_name_servers); + GlobalLogger.debug() << "Checking ADDITIONALS section of dns reply"; gather_results(result_message.additionals(), &result_ips, - &result_cnames, &result_nameservers); + &result_cnames, &result_name_servers); - // search for a nameserver for which an IP is given + // search for a name_server for which an IP is given bool have_recursed = false; - BOOST_FOREACH( const string_pair &nameserver, result_nameservers ) + BOOST_FOREACH( const string_pair &name_server, result_name_servers ) { + if (name_server.second == Hostname) + { // in case we try to resolve IP for name server, do not use same + GlobalLogger.debug() << LogPrefix + << "Name server found is same as hostname --> skip"; + continue; + } + // go through ips and look for match BOOST_FOREACH( const host_addr_pair &host_and_addr, result_ips ) { - if (nameserver.second == host_and_addr.first) + if (name_server.second == host_and_addr.first) { - GlobalLogger.info() << LogPrefix << "Ask next nameserver " - << nameserver.second << " with IP " + GlobalLogger.info() << LogPrefix << "Ask next name_server " + << name_server.second << " with IP " << host_and_addr.second.get_ip() << " (responsible for " - << nameserver.first << ")"; + << name_server.first << ")"; have_recursed = true; handle_recurse( host_and_addr.second ); break; @@ -276,8 +290,8 @@ void DnsResolver::handle_dns_result(const boost::system::error_code &error, } if ( !have_recursed ) - { // no nameserver with ip found -- strange - if (result_nameservers.empty()) + { // no name_server with ip found -- strange + if (result_name_servers.empty()) { GlobalLogger.error() << LogPrefix << "Result contained neither " << "IP nor CNAME nor name server --> cannot proceed!"; @@ -285,22 +299,10 @@ void DnsResolver::handle_dns_result(const boost::system::error_code &error, } else { - // TODO: check in cache for nameserver ips? - GlobalLogger.warning() << LogPrefix - << "There are " << result_nameservers.size() - << " nameservers given but none with IP " - << "--> need to resolve nameserver -- this sucks!"; - //handle_recurse_without_ip(result_nameservers[0].second); - - // would have to create a new resolver with previous nameserver - // to resolve new nameserver name; save in Recursor - // In callback reset Recursor, get ip(s) and continue in - // handle_recurse - GlobalLogger.warning() << LogPrefix << "Have not implemented " - << "resolution of name server; I sincerely hope this never " - << "happens or can be dealt with more easily another way!"; - handle_unavailable(); + << "There are " << result_name_servers.size() + << " name_servers given but none with IP!"; + handle_recurse_without_ip(result_name_servers[0].second); } } } @@ -308,16 +310,19 @@ void DnsResolver::handle_dns_result(const boost::system::error_code &error, void DnsResolver::gather_results(const boost::net::dns::rr_list_t *answers, std::vector *result_ips, - std::vector *result_cnames, - std::vector *result_nameservers) + std::vector *result_cnames, + std::vector *result_name_servers) const { using boost::net::dns::resource_base_t; + boost::posix_time::ptime now =boost::posix_time::second_clock::local_time(); BOOST_FOREACH( boost::shared_ptr rr_item, *answers ) { boost::net::dns::type_t rr_type = rr_item->rtype(); uint32_t ttl = rr_item->ttl(); std::string domain = rr_item->domain(); + std::string expiry = + boost::posix_time::to_simple_string(now + seconds(ttl)); if (rr_type == boost::net::dns::type_a) { // 'A' resource records carry IPv4 addresses @@ -331,8 +336,9 @@ void DnsResolver::gather_results(const boost::net::dns::rr_list_t *answers, ( dynamic_cast (rr_item.get()) ) ->address(); result_ips->push_back(host_addr_pair(domain, HostAddress(ip, ttl))); - GlobalLogger.debug() << LogPrefix << "IPv4 " << ip << " with TTL " - << ttl << "s for " << domain; + GlobalLogger.debug() << LogPrefix << domain << ": IPv4 " << ip + << " with TTL " << ttl << "s (until " + << expiry << ")"; } else if (rr_type == boost::net::dns::type_a6) { // 'AAAA' resource records carry IPv6 addresses @@ -346,26 +352,30 @@ void DnsResolver::gather_results(const boost::net::dns::rr_list_t *answers, ( dynamic_cast (rr_item.get()) ) ->address(); result_ips->push_back(host_addr_pair(domain, HostAddress(ip, ttl))); - GlobalLogger.debug() << LogPrefix << "IPv6 " << ip << " with TTL " - << ttl << "s for " << domain; + GlobalLogger.debug() << LogPrefix << domain << ": IPv6 " << ip + << " with TTL " << ttl << "s (until " + << expiry << ")"; } else if (rr_type == boost::net::dns::type_cname) { // 'CNAME' resource records that carry aliases std::string cname = (dynamic_cast(rr_item.get())) ->canonicalname(); - result_cnames->push_back( string_pair(domain, cname) ); - GlobalLogger.debug() << LogPrefix << "CNAME " << cname - << " with TTL " << ttl << "s for " << domain; + result_cnames->push_back( src_cname_pair(domain, + Cname(cname, ttl)) ); + GlobalLogger.debug() << LogPrefix << domain << ": CNAME to " + << cname << " with TTL " << ttl << "s (until " + << expiry << ")"; } else if (rr_type == boost::net::dns::type_ns) - { // NS (nameserver) resource records - std::string nameserver = + { // NS (name_server) resource records + std::string name_server = (dynamic_cast(rr_item.get())) ->nameserver(); - result_nameservers->push_back( string_pair(domain, nameserver) ); - GlobalLogger.debug() << LogPrefix << "NameServer " << nameserver - << " with TTL " << ttl << "s for " << domain; + result_name_servers->push_back( string_pair(domain, name_server) ); + GlobalLogger.debug() << LogPrefix << "NameServer " << name_server + << " for " << domain << " with TTL " << ttl + << "s (until " << expiry << ")"; } else if (rr_type == boost::net::dns::type_soa) GlobalLogger.debug() << LogPrefix << "SOA resource"; @@ -436,20 +446,22 @@ void DnsResolver::handle_ips(const std::vector &result_ips) } -void DnsResolver::handle_cname(const std::vector &result_cnames) +void DnsResolver::handle_cname(const std::vector &result_cnames) { // find the "last" cname in the list // Hostname --> cname1 --> cname2 --> ... --> cnameN // We assume here that this list might not be in order but that all cnames - // form a single list (without a break) + // form a single list (form one connected list and not several isolated) + + // host_and_cname.second is a Cname, which is a pair (destination, ttl) std::string last_cname = ""; bool could_be_last; - BOOST_REVERSE_FOREACH( const string_pair &host_and_cname, result_cnames ) + BOOST_REVERSE_FOREACH( const src_cname_pair &host_and_cname, result_cnames ) { could_be_last = true; - BOOST_REVERSE_FOREACH( const string_pair &other, result_cnames ) + BOOST_REVERSE_FOREACH( const src_cname_pair &other, result_cnames ) { - if (other.first == host_and_cname.second) + if (other.first == host_and_cname.second.first) { // found cname for current cname could_be_last = false; break; @@ -457,7 +469,7 @@ void DnsResolver::handle_cname(const std::vector &result_cnames) } if (could_be_last) { - last_cname = host_and_cname.second; + last_cname = host_and_cname.second.first; break; } } @@ -468,9 +480,9 @@ void DnsResolver::handle_cname(const std::vector &result_cnames) << "Could not identify \"last\" CNAME to handle -- " << "maybe we encountered a CNAME loop? Anyway, cannot proceed!"; GlobalLogger.info() << LogPrefix << "Result CNAMEs were:"; - BOOST_FOREACH( const string_pair &host_and_cname, result_cnames ) + BOOST_FOREACH( const src_cname_pair &host_and_cname, result_cnames ) GlobalLogger.info() << LogPrefix << host_and_cname.first << " --> " - << host_and_cname.second; + << host_and_cname.second.first; handle_unavailable(); } else @@ -577,7 +589,7 @@ void DnsResolver::recursive_resolve_callback(const uint32_t min_ttl, else Recursor.reset(); - f ( OperationCancelled ) + if ( OperationCancelled ) { // async_resolve was cancelled --> callbacks already called GlobalLogger.info() << LogPrefix << "Ignoring recursion results since we were cancelled"; @@ -586,7 +598,7 @@ void DnsResolver::recursive_resolve_callback(const uint32_t min_ttl, else if (was_success) { // make sure the saved TTL is not larger than the one we found here - ResolverBase::update_cache_ttl(min_ttl); + ResolverBase::update_cache(min_ttl); finalize_resolve(was_success, recursion_count+1); } else @@ -597,6 +609,73 @@ void DnsResolver::recursive_resolve_callback(const uint32_t min_ttl, } +void DnsResolver::handle_recurse_without_ip(const std::string &name_server) +{ + // get resolver for name_server + // save in Recursor although it is a "proper" resolver (so result is cached) + if (Recursor) + { + if (Recursor->is_resolving()) + { + GlobalLogger.warning() << LogPrefix << "Recursor is resolving! " + << "Will cancel and reset"; + Recursor->cancel_resolve(); + } + else + GlobalLogger.warning() << LogPrefix + << "Recursor has not been reset!"; + Recursor.reset(); + } + Recursor = DnsMaster::get_instance()->get_resolver_for(name_server, + Protocol); + + // check for IPs in cache + if (Recursor->get_resolved_ip_count() == 0) + { + GlobalLogger.info() << LogPrefix + << "Start to resolve address of name server " << name_server; + callback_type callback = boost::bind( + &DnsResolver::name_server_resolve_callback, + this, _1, _2); + Recursor->async_resolve( callback ); + } + else + { + GlobalLogger.info() << LogPrefix << "Use cached ip for name server " + << name_server; + HostAddress ip = Recursor->get_next_ip(); + Recursor.reset(); + handle_recurse(ip); + } +} + +void DnsResolver::name_server_resolve_callback(const bool was_success, + const int recursion_count) +{ + if (OperationCancelled) + { + GlobalLogger.info() << LogPrefix + << "Ignoring name server IP results since we were cancelled"; + return; + } + else if (was_success) + { + HostAddress ip = Recursor->get_next_ip(); + GlobalLogger.info() << LogPrefix << "Found IP " << ip.get_ip() + << " for name server " << Recursor->get_hostname(); + Recursor.reset(); + handle_recurse(ip); + } + else + { + GlobalLogger.info() << LogPrefix << "Failed to find IP for name server" + << Recursor->get_hostname() << " --> schedule retry"; + Recursor.reset(); + schedule_retry(); + } +} + + void DnsResolver::finalize_resolve(const bool was_success, const int recursion_count) { @@ -648,6 +727,13 @@ bool DnsResolver::is_resolving() } +/** + * cancel a earlier call to async_resolve + * + * callbacks will be called with was_success=false; all internal operations + * will be cancelled and internal callbacks (timers, dns results) have no + * effect any more + */ void DnsResolver::cancel_resolve() { if ( !IsResolving ) @@ -667,7 +753,7 @@ void DnsResolver::cancel_resolve() Recursor->cancel_resolve(); // does not hurt even if it is not resolving // set before finalize_resolve so can check in finalize_resolve that ID is - // always 0; ID is not used any more since handle_dns_result stops if + // always 0; ID is not used any more since handle_dns_result stops if // OperationCancelled is true RequestId = 0; @@ -676,7 +762,7 @@ void DnsResolver::cancel_resolve() finalize_resolve(was_success, recursion_count); // set after finalize_resolve, so can check in finalize_resolve that - // cancel is never true + // OperationCancelled is never true OperationCancelled = true; } @@ -694,19 +780,18 @@ void DnsResolver::handle_resolve_timeout(const boost::system::error_code &error) { GlobalLogger.warning() << LogPrefix << "resolve timeout handler received error " - << error; - return; + << error << " --> retry"; + schedule_retry(); } else if ( OperationCancelled ) { // async_resolve was cancelled --> callbacks already called GlobalLogger.info() << LogPrefix - << "Ignoring DNS timeout since we were cancelled"; + << "Ignoring DNS timeout since we were cancelled"; return; } else { GlobalLogger.notice() << LogPrefix << "DNS resolving timed out"; - schedule_retry(); } } @@ -714,10 +799,11 @@ void DnsResolver::handle_resolve_timeout(const boost::system::error_code &error) void DnsResolver::schedule_retry() { - // clean up a bit + // this function is called in all sorts of error cases + // --> need to clean up a bit if ( Recursor ) { - Recursor.cancel(); + Recursor->cancel_resolve(); Recursor.reset(); } ResolveTimeoutTimer.cancel(); @@ -803,23 +889,7 @@ HostAddress DnsResolver::get_next_ip() bool DnsResolver::have_up_to_date_ip() { - // get cached data - HostAddressVec cached_data = ResolverBase::get_cached_ips_recursively(); - - // get threshold - uint32_t resolved_ip_ttl_threshold = static_cast( - DnsMaster::get_instance()->get_resolved_ip_ttl_threshold() ); - - // loop over addresses - BOOST_FOREACH( const HostAddress &addr, cached_data ) - { - uint32_t ttl = addr.get_ttl().get_updated_value(); - if ( ttl > resolved_ip_ttl_threshold ) - return true; - } - - // if not returned true by now, we have tried all IPs without success - return false; + return ! ResolverBase::get_cached_ips_recursively("", true).empty(); } int DnsResolver::get_resolved_ip_count() diff --git a/src/dns/dnsresolver.h b/src/dns/dnsresolver.h index 15d2a28..a705f50 100644 --- a/src/dns/dnsresolver.h +++ b/src/dns/dnsresolver.h @@ -38,6 +38,7 @@ typedef std::pair string_pair; +typedef std::pair src_cname_pair; typedef std::pair host_addr_pair; @@ -81,19 +82,23 @@ private: const std::size_t bytes_transferred); void handle_unavailable(); void handle_ips(const std::vector &result_ips); - void handle_cname(const std::vector &result_cnames); + void handle_cname(const std::vector &result_cnames); void handle_recurse(const HostAddress &name_server); + void handle_recurse_without_ip(const std::string &name_server); void cname_resolve_callback(const bool was_success, const int recursion_count); void recursive_resolve_callback(const uint32_t min_ttl, const bool was_success, const int recursion_count); + void name_server_resolve_callback(const bool was_success, + const int recursion_count); + void schedule_retry(); void finalize_resolve(const bool success, const int recursion_count=0); void stop_trying(); void wait_timer_timeout_handler(const boost::system::error_code &error); void gather_results( const boost::net::dns::rr_list_t *answers, std::vector *result_ips, - std::vector *result_cnames, + std::vector *result_cnames, std::vector *result_nameservers ) const; // variables diff --git a/src/dns/hostaddress.h b/src/dns/hostaddress.h index 9696843..d5fdf18 100644 --- a/src/dns/hostaddress.h +++ b/src/dns/hostaddress.h @@ -28,7 +28,6 @@ on this file might be covered by the GNU General Public License. #include #include #include -#include #include "dns/timetolive.h" @@ -66,28 +65,18 @@ private: void save(Archive & ar, const unsigned int version) const { std::string ip = Ip.to_string(); - std::string ttl_creation_time = boost::posix_time::to_iso_string( - Ttl.TtlSetTime); ar & BOOST_SERIALIZATION_NVP(ip); - ar & BOOST_SERIALIZATION_NVP(Ttl.Ttl); - ar & BOOST_SERIALIZATION_NVP(ttl_creation_time); + ar & BOOST_SERIALIZATION_NVP(Ttl); } template void load(Archive & ar, const unsigned int version) { std::string ip; - uint32_t ttl_seconds; - std::string ttl_creation_time; ar & BOOST_SERIALIZATION_NVP(ip); - ar & BOOST_SERIALIZATION_NVP(ttl_seconds); - ar & BOOST_SERIALIZATION_NVP(ttl_creation_time); - - // now convert to Ip and Ttl + ar & BOOST_SERIALIZATION_NVP(Ttl); Ip = boost::asio::ip::address::from_string(ip); - Ttl = TimeToLive(); - Ttl.Ttl = ttl_seconds; - Ttl.TtlSetTime = boost::posix_time::from_iso_string(ttl_creation_time); + } BOOST_SERIALIZATION_SPLIT_MEMBER() diff --git a/src/dns/resolverbase.cpp b/src/dns/resolverbase.cpp index 721fc1e..d28b6eb 100644 --- a/src/dns/resolverbase.cpp +++ b/src/dns/resolverbase.cpp @@ -52,30 +52,33 @@ ResolverBase::ResolverBase(const IoServiceItem &io_serv, , CallbackList() {} +std::string ResolverBase::get_hostname() const +{ return Hostname; } + void ResolverBase::update_cache( const std::string &hostname, const HostAddressVec &new_results ) const { Cache->update( hostname, new_results ); } void ResolverBase::update_cache( const std::string &hostname, - const std::string &cname ) const + const Cname &cname ) const { Cache->update( hostname, cname ); } void ResolverBase::update_cache( const HostAddressVec &new_results ) const { Cache->update( Hostname, new_results ); } -void ResolverBase::update_cache( const std::string &cname ) const +void ResolverBase::update_cache( const Cname &cname ) const { Cache->update( Hostname, cname ); } -void ResolverBase::update_cache_ttl( const uint32_t ttl ) const -{ Cache->update_ttl( Hostname, ttl ); } +void ResolverBase::update_cache( const uint32_t ttl ) const +{ Cache->update( Hostname, ttl ); } -HostAddressVec& ResolverBase::get_cached_ips_recursively(const std::string host) - const +HostAddressVec ResolverBase::get_cached_ips_recursively(const std::string host, + bool check_up_to_date) const { if (host.empty()) - return Cache->get_ips_recursive(Hostname); + return Cache->get_ips_recursive(Hostname, check_up_to_date); else - return Cache->get_ips_recursive(host); + return Cache->get_ips_recursive(host, check_up_to_date); } void ResolverBase::schedule_callbacks(const bool was_success, diff --git a/src/dns/resolverbase.h b/src/dns/resolverbase.h index a063c6c..c731b66 100644 --- a/src/dns/resolverbase.h +++ b/src/dns/resolverbase.h @@ -55,6 +55,8 @@ public: virtual bool have_up_to_date_ip() = 0; virtual int get_resolved_ip_count() = 0; + std::string get_hostname() const; + protected: ResolverBase(const IoServiceItem &io_serv, const std::string &hostname, @@ -63,7 +65,7 @@ protected: // variables protected: IoServiceItem IoService; - std::string Hostname; + const std::string Hostname; DnsCacheItem Cache; callback_list_type CallbackList; @@ -71,15 +73,17 @@ protected: protected: virtual void do_resolve() = 0; + // convenient forwards to DnsCache that just insert Hostname void update_cache( const HostAddressVec &new_results ) const; - void update_cache( const std::string &cname ) const; + void update_cache( const Cname &cname ) const; void update_cache( const std::string &hostname, const HostAddressVec &new_results ) const; void update_cache( const std::string &hostname, - const std::string &cname ) const; - void update_cache_ttl( const uint32_t ttl ) const; + const Cname &cname ) const; + void update_cache( const uint32_t ttl ) const; - HostAddressVec& get_cached_ips_recursively(const std::string host="") const; + HostAddressVec get_cached_ips_recursively(const std::string host="", + const bool check_up_to_date=false) const; void schedule_callbacks(const bool was_success, const int cname_count); diff --git a/src/dns/timetolive.h b/src/dns/timetolive.h index e56d9eb..f1162dd 100644 --- a/src/dns/timetolive.h +++ b/src/dns/timetolive.h @@ -23,7 +23,10 @@ on this file might be covered by the GNU General Public License. #include #include -//#include "dns/hostaddress.h" +#include +#include +#include +#include // forward declaration class HostAddress; @@ -57,6 +60,32 @@ private: /// the time when the time-to-live was set, so it is possible to know the /// elapsed time boost::posix_time::ptime TtlSetTime; + + // serialization + friend class boost::serialization::access; + template + void save(Archive & ar, const unsigned int version) const + { + std::string ttl_creation_time = boost::posix_time::to_iso_string( + TtlSetTime); + ar & BOOST_SERIALIZATION_NVP(Ttl); + ar & BOOST_SERIALIZATION_NVP(ttl_creation_time); + } + + template + void load(Archive & ar, const unsigned int version) + { + uint32_t ttl_seconds; + std::string ttl_creation_time; + ar & BOOST_SERIALIZATION_NVP(ttl_seconds); + ar & BOOST_SERIALIZATION_NVP(ttl_creation_time); + + // now convert to Ip and Ttl + Ttl = ttl_seconds; + TtlSetTime = boost::posix_time::from_iso_string(ttl_creation_time); + } + + BOOST_SERIALIZATION_SPLIT_MEMBER() }; #endif // TIME_TO_LIVE_H