Experiments with own name server and recursive cnames showed that TTLs are not always the minimum.
This way we have better control about resulting TTLs
and debugging is easier since DNS caching is avoided.
Also create unique id for each dns message and check reply
and in main warn if using debug option max_exceptions.
DnsCache::DnsCache(const IoServiceItem &io_serv,
const std::string &cache_file)
- : DataCache()
+ : IpCache()
+ , CnameCache()
, SaveTimer( *io_serv )
, CacheFile( cache_file )
, HasChanged( false )
if ( error == boost::asio::error::operation_aborted ) // cancelled
{
- GlobalLogger.error() << "DNS Cache: SaveTimer was cancelled "
+ GlobalLogger.error() << "DnsCache: SaveTimer was cancelled "
<< "--> no save and no re-schedule of saving!";
return;
}
else if (error)
{
- GlobalLogger.error() << "DNS Cache: Received error " << error
+ GlobalLogger.error() << "DnsCache: Received error " << error
<< " in schedule_save "
<< "--> no save now but re-schedule saving";
}
{
if (!HasChanged)
{
- GlobalLogger.info() << "DNS Cache: skip saving because has not changed";
+ GlobalLogger.info() << "DnsCache: skip saving because has not changed";
return;
}
else if (CacheFile.empty())
{
GlobalLogger.warning()
- << "DNS Cache: skip saving because file name empty!";
+ << "DnsCache: skip saving because file name empty!";
return;
}
{
std::ofstream ofs( CacheFile.c_str() );
boost::archive::xml_oarchive oa(ofs);
- oa << boost::serialization::make_nvp("DataCache", DataCache);
- GlobalLogger.info() << "DNS Cache: saved to cache file " << CacheFile;
+ oa << boost::serialization::make_nvp("IpCache", IpCache);
+ oa << boost::serialization::make_nvp("CnameCache", CnameCache);
+ GlobalLogger.info() << "DnsCache: saved to cache file " << CacheFile;
HasChanged = false;
}
if (CacheFile.empty())
{
GlobalLogger.warning()
- << "DNS Cache: cannot load because cache file name is empty!";
+ << "DnsCache: cannot load because cache file name is empty!";
return;
}
else if ( !I2n::file_exists(CacheFile) )
{
- GlobalLogger.warning() << "DNS Cache: cannot load because cache file "
+ GlobalLogger.warning() << "DnsCache: cannot load because cache file "
<< CacheFile << " does not exist!";
return;
}
std::ifstream ifs( CacheFile.c_str() );
boost::archive::xml_iarchive ia(ifs);
- ia >> boost::serialization::make_nvp("DataCache", cache);
- GlobalLogger.info() << "DNS Cache: loaded from file " << CacheFile;
+ ia >> boost::serialization::make_nvp("IpCache", cache);
+ ia >> boost::serialization::make_nvp("CnameCache", cache);
+ GlobalLogger.info() << "DnsCache: loaded from file " << CacheFile;
}
catch (boost::archive::archive_exception &exc)
{
- GlobalLogger.warning() << "DNS Cache: archive exception loading from "
+ GlobalLogger.warning() << "DnsCache: archive exception loading from "
<< CacheFile << ": " << exc.what();
}
catch (std::exception &exc)
{
- GlobalLogger.warning() << "DNS Cache: exception while loading from "
+ GlobalLogger.warning() << "DnsCache: exception while loading from "
<< CacheFile << ": " << exc.what();
}
}
-/**
- *
- * in case the cached set is equal to the given new one, the old one is kept
- * with TTLs updated
- * @returns true if changed cache; returns false if new_data is same as cache
- */
void DnsCache::update(const std::string &hostname,
const HostAddressVec &new_data)
{
- GlobalLogger.info() << "DNS Cache: update IPs for " << hostname
+ GlobalLogger.info() << "DnsCache: update IPs for " << hostname
<< " to " << new_data.size() << "-list";
- DataCache[hostname] = new_data;
+ IpCache[hostname] = new_data;
HasChanged = true;
}
-HostAddressVec& DnsCache::get_data(const std::string &hostname)
+void DnsCache::update(const std::string &hostname,
+ const std::string &cname)
+{
+ GlobalLogger.info() << "DnsCache: update CNAME for " << hostname
+ << " to " << cname;
+ CnameCache[hostname] = cname;
+ HasChanged = true;
+}
+
+
+void DnsCache::update_ttl(const std::string &hostname,
+ const uint32_t new_ttl)
+{
+ GlobalLogger.info() << "DnsCache: ensure TTL for IPs for " << hostname
+ << " is below " << new_ttl;
+ HostAddressVec ips = IpCache[hostname];
+ uint32_t current_ttl;
+ TimeToLive current_ttl;
+ BOOST_FOREACH( HostAddress &addr, ips )
+ {
+ current_ttl = addr.get_ttl();
+ if (current_ttl.get_value() > new_ttl)
+ {
+ current_ttl.set_value(new_ttl);
+ addr.set_ttl(current_ttl);
+ HasChanged = true;
+ }
+ }
+ IpCache[hostname] = ip;
+}
+
+
+HostAddressVec& DnsCache::get_ips(const std::string &hostname)
{
- GlobalLogger.info() << "DNS Cache: request IPs for " << hostname
- << " --> " << DataCache[hostname].size() << "-list";
- return DataCache[hostname];
+ GlobalLogger.info() << "DnsCache: request IPs for " << hostname
+ << " --> " << IpCache[hostname].size() << "-list";
+ return IpCache[hostname];
}
+std::string& DnsCache::get_cname(const std::string &hostname)
+{
+ GlobalLogger.info() << "DnsCache: request CNAME for " << hostname
+ << " --> " << CnameCache[hostname];
+ return CnameCache[hostname];
+}
+
+
+
// (created using vim -- the world's best text editor)
#include "dns/hostaddress.h"
typedef std::vector<HostAddress> HostAddressVec;
-typedef std::map<std::string, HostAddressVec> cache_map_type;
+typedef std::map<std::string, HostAddressVec> ip_map_type;
+typedef std::map<std::string, std::string> cname_map_type;
class DnsCache
{
~DnsCache();
// accessed from ResolverBase subclasses
- void update(const std::string &host_name, const HostAddressVec &new_data);
- HostAddressVec& get_data(const std::string &hostname);
+ 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);
// variables
private:
- cache_map_type DataCache;
+ ip_map_type IpCache;
+ cname_map_type CnameCache;
boost::asio::deadline_timer SaveTimer;
std::string CacheFile;
bool HasChanged;
DnsMasterItem DnsMaster::TheOnlyInstance;
void DnsMaster::create_master(const IoServiceItem &io_serv,
- const boost::asio::ip::address &name_server,
- const int resolved_ip_ttl_threshold,
- const int max_address_resolution_attempts,
- const std::string &cache_file)
+ const boost::asio::ip::address &default_name_server,
+ const int resolved_ip_ttl_threshold,
+ const int max_address_resolution_attempts,
+ const std::string &cache_file)
{
if (TheOnlyInstance)
{
GlobalLogger.info() << "Creating DNS Cache and Master";
DnsCacheItem cache( new DnsCache(io_serv, cache_file) );
TheOnlyInstance.reset( new DnsMaster(io_serv,
- name_server,
+ default_name_server,
resolved_ip_ttl_threshold,
max_address_resolution_attempts,
cache)
DnsMaster::DnsMaster(const IoServiceItem &io_serv,
- const boost::asio::ip::address &name_server,
+ const boost::asio::ip::address &default_name_server,
const int resolved_ip_ttl_threshold,
const int max_address_resolution_attempts,
const DnsCacheItem &cache)
: IoService( io_serv )
- , NameServer( name_server )
+ , DefaultNameServer( default_name_server )
, ResolvedIpTtlThreshold( resolved_ip_ttl_threshold )
, MaxAddressResolutionAttempts( max_address_resolution_attempts )
, Cache(cache)
}
-ResolverItem& DnsMaster::get_resolver_for( const std::string &hostname,
- const DnsIpProtocol &protocol )
+ResolverItem& DnsMaster::get_resolver_for(const std::string &hostname,
+ const DnsIpProtocol &protocol)
{
DnsMasterItem master = get_instance();
hostname,
protocol,
Cache,
- NameServer) );
+ DefaultNameServer) );
master->ResolverMap[key] = new_resolver;
}
}
return master->ResolverMap[key];
}
+// create resolver but do not remember it in ResolverMap
+ResolverItem DnsMaster::get_recursor_for(const std::string &hostname,
+ const DnsIpProtocol &protocol,
+ const boost::asio::ip::address &name_server)
+{
+ ResolverItem new_resolver( new DnsResolver(IoService,
+ hostname,
+ protocol,
+ Cache,
+ name_server) );
+ return new_resolver;
+}
+
/**
* return true if given hostname string actually is an IP
*
ResolverItem& get_resolver_for(const std::string &hostname,
const PingProtocol &ping_protocol);
ResolverItem& get_resolver_for(const std::string &hostname,
- const DnsIpProtocol &protocol);
+ const DnsIpProtocol &protocol)
+ ResolverItem get_recursor_for(const std::string &hostname,
+ const DnsIpProtocol &protocol,
+ const boost::asio::ip::address &name_server);
// implementation of singleton
private:
static DnsMasterItem TheOnlyInstance;
DnsMaster(const IoServiceItem &io_serv,
- const boost::asio::ip::address &name_server,
+ const boost::asio::ip::address &default_name_server,
const int resolved_ip_ttl_threshold,
const int max_address_resolution_attempts,
const DnsCacheItem &cache);
public:
static void create_master(const IoServiceItem &io_serv,
- const boost::asio::ip::address &name_server,
- const int resolved_ip_ttl_threshold,
- const int max_address_resolution_attempts,
- const std::string &cache_file);
+ const boost::asio::ip::address &default_name_server,
+ const int resolved_ip_ttl_threshold,
+ const int max_address_resolution_attempts,
+ const std::string &cache_file);
static DnsMasterItem& get_instance();
~DnsMaster();
// variables
private:
IoServiceItem IoService;
- const boost::asio::ip::address NameServer;
+ const boost::asio::ip::address DefaultNameServer;
const int ResolvedIpTtlThreshold;
const int MaxAddressResolutionAttempts;
DnsCacheItem Cache;
#include <boost/function.hpp>
#include <boost/net/dns.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/uuid/uuid.hpp>
+#include <boost/uuid/uuid_io.hpp>
#include <logfunc.hpp>
const int PauseBeforeRetrySeconds = 10;
const int StaleDataLongtermMinutes = 15;
const int DNS_PORT = 53;
- const int UniqueID = 0xaffe;
}
DnsResolver::DnsResolver(IoServiceItem &io_serv,
, Socket( *io_serv, ip::udp::endpoint(ip::udp::v4(), 0))
// just connect to anything, will specify sender/receiver later
, ReceiveBuffer()
+ , RequestBuffer()
, Protocol( protocol )
, NameServer( name_server, Config::DNS_PORT )
, ResolveTimeoutTimer( *io_serv )
, RetryCount( 0 )
, IsResolving( false )
, LogPrefix( "DnsResolver" )
+ , RandomIdGenerator()
+ , RequestId( 0 )
{
std::stringstream temp;
temp << "Dns(" << ResolverBase::Hostname << "): ";
LogPrefix = temp.str();
+
}
DnsResolver::~DnsResolver()
<< "Call to do_resolve ignored since resolving already";
return;
}
+ IsResolving = true;
GlobalLogger.info() << LogPrefix << "start resolving";
// create DNS request
boost::net::dns::message dns_message( ResolverBase::Hostname,
- boost::net::dns::type_all );
+ boost::net::dns::type_a); //all ); DEBUG
dns_message.recursive(false);
dns_message.action(boost::net::dns::message::query);
dns_message.opcode(boost::net::dns::message::squery);
- dns_message.id(Config::UniqueID);
- boost::net::dns_buffer_t request_buffer;
- dns_message.encode(request_buffer);
+
+ // create random ID for message
+ boost::uuids::uuid message_id = RandomIdGenerator();
+ memcpy( &RequestId, message_id.data, sizeof(RequestId) );
+ dns_message.id( RequestId );
+ GlobalLogger.debug() << LogPrefix << "Request has ID "
+ << std::showbase << std::hex << dns_message.id();
// setup receipt of reply
Socket.async_receive_from(
this, boost::asio::placeholders::error) );
// send dns request
+ dns_message.encode(RequestBuffer);
size_t bytes_sent;
try
{
bytes_sent = Socket.send_to(
- boost::asio::buffer(request_buffer.get_array()),
+ boost::asio::buffer(RequestBuffer.get_array()),
NameServer );
}
catch (boost::system::system_error &err)
void DnsResolver::handle_dns_result(const boost::system::error_code &error,
- const std::size_t bytes_transferred)
+ const std::size_t bytes_transferred)
{
if ( error == boost::asio::error::operation_aborted ) // cancelled
{
return;
}
+ GlobalLogger.debug() << LogPrefix << "Handling DNS result ("
+ << bytes_transferred << " bytes transferred)";
+
// next 3(+1) lines copied from boost/net/dns/resolver.hpp:
// clamp the recvBuffer with the number of bytes transferred or decode buffr
ReceiveBuffer.length(bytes_transferred);
boost::net::dns::message result_message;
result_message.decode( ReceiveBuffer );
+ // check ID
+ if (RequestId != result_message.id())
+ GlobalLogger.warning() << "Received answer for request ID "
+ << std::showbase << std::hex << result_message.id()
+ << " but expected ID " << RequestId;
+ else
+ GlobalLogger.debug() << LogPrefix << "Result has correct ID "
+ << std::showbase << std::hex << RequestId;
+
+ // loop over answers, remembering ips and cnames
// work with a regular pointer to list of answers since result_message is
// owner of data and that exists until end of function
// Items in answers list are shared_ptr to resource_base_t
- boost::net::dns::rr_list_t *answers = result_message.answers();
- if (answers->size() == 0)
- handle_unavailable();
+ HostAddressVec ip_list;
+ std::vector<std::string> hosts_for_ips;
+ std::vector<string_pair> result_cnames;
+ std::vector<string_pair> result_nameservers;
- // loop over answers, remembering ips and cnames
- HostAddressVec result_ips;
- std::vector<std::string> result_cnames;
+ gather_results(result_message.answers(), &ip_list, &hosts_for_ips,
+ &result_cnames, &result_nameservers);
+
+ // remember cname tree (if there were any)
+ // assume each cname points to next ( source --> destination )
+ std::string source = ResolverBase::Hostname;
+ BOOST_FOREACH( const std::string &cname, result_cnames )
+ {
+ update_cache( source, cname );
+ source = cname;
+ }
+
+ // IPs point to last CNAME (or Hostname if no cnames given)
+ if ( !ip_list.empty() )
+ {
+ update_cache( source, ip_list );
+
+ // clean up
+ bool was_success = true;
+ finalize_resolve(was_success);
+ }
+ else if ( !result_cnames.empty() )
+ { // no IPs but a cname --> re-start resolving with that
+ handle_cname(source);
+ }
+ else
+ { // no answers --> check for nameservers in authorities section
+ // and corresponding IPs in additional section
+ if ( !result_nameservers.empty() )
+ GlobalLogger.warning() << "Received NS records in answers! "
+ << "That is quite unexpected..."
+ gather_results(result_message.authorites(), &ip_list, &hosts_for_ips,
+ &result_cnames, &result_nameservers);
+ gather_results(result_message.additionals(), &ip_list, &hosts_for_ips,
+ &result_cnames, &result_nameservers);
+
+ int index, index_found=-1;
+ // go through name servers
+ BOOST_FOREACH( const string_pair &nameserver, result_nameservers )
+ {
+ index = 0;
+ // go through ips and look for match
+ BOOST_FOREACH( const std::string &ip_host, hosts_for_ips )
+ {
+ if (nameserver.second == ip_host)
+ {
+ index_found = index;
+ break;
+ }
+ ++index;
+ }
+
+ if (index_found > -1)
+ break;
+ }
+ if (index_found > -1)
+ { // have a name server with ip
+ handle_recurse(ip_list[index_found]);
+
+
+ GlobalLogger.info() << LogPrefix << "Have " << result_ips.size()
+ << " IPs and " << result_cnames.size() << " CNAMEs";
+
+ // We expect either one single CNAME and no IPs or a list of IPs.
+ // But deal with other cases as well
+ if (result_ips.empty() && result_cnames.empty())
+ handle_unavailable(); // we just got crap, this is a dead end
+
+ bool do_resolve_cnames = !Config::DnsRequestsAreRecursive;
+
+ if (Config::DnsRequestsAreRecursive && !result_cnames.empty()
+ && result_ips.empty() )
+ {
+ GlobalLogger.warning() << LogPrefix << "CNAMES appear to be unresolved"
+ << " although DNS requests are recursive! --> try on our own";
+ do_resolve_cnames = true;
+ }
+ else
+ GlobalLogger.info() << LogPrefix << "Ignore CNAMES, assume they were "
+ << "resolved";
+
+ if (do_resolve_cnames)
+ {
+ BOOST_FOREACH( const std::string &cname, result_cnames )
+ handle_cname(cname); // will schedule another DNS call
+ }
+
+ if ( !result_ips.empty() )
+ handle_ips(result_ips);
+}
+
+void DnsResolver::gather_results(const boost::net::dns::rr_list_t *answers,
+ HostAddressVec *result_ips,
+ std::vector<std::string> *hosts_for_ips,
+ std::vector<string_pair> *result_cnames,
+ std::vector<string_pair> *result_nameservers)
+ const
+{
using boost::net::dns::resource_base_t;
BOOST_FOREACH( boost::shared_ptr<resource_base_t> rr_item, *answers )
{
- GlobalLogger.debug() << LogPrefix << std::showbase << std::hex
- << static_cast<unsigned>(rr_item->rtype()) << ": ";
- uint32_t ttl = rr_item->ttl();
boost::net::dns::type_t rr_type = rr_item->rtype();
+ uint32_t ttl = rr_item->ttl();
+ std::string domain = rr_item->domain();
if (rr_type == boost::net::dns::type_a)
{ // 'A' resource records carry IPv4 addresses
boost::asio::ip::address_v4 ip =
( dynamic_cast<boost::net::dns::a_resource *> (rr_item.get()) )
->address();
- result_ips.push_back( HostAddress(ip, ttl) );
+ hosts_for_ips->push_back( domain );
+ result_ips->push_back( HostAddress(ip, ttl) );
+ GlobalLogger.debug() << LogPrefix << "IPv4 " << ip << " with TTL "
+ << ttl << "s for " << domain;
}
else if (rr_type == boost::net::dns::type_a6)
{ // 'AAAA' resource records carry IPv6 addresses
boost::asio::ip::address_v6 ip =
( dynamic_cast<boost::net::dns::a6_resource *> (rr_item.get()) )
->address();
- result_ips.push_back( HostAddress(ip, ttl) );
+ hosts_for_ips->push_back( domain );
+ result_ips->push_back( HostAddress(ip, ttl) );
+ GlobalLogger.debug() << LogPrefix << "IPv6 " << ip << " with TTL "
+ << ttl << "s for " << domain;
}
else if (rr_type == boost::net::dns::type_cname)
{ // 'CNAME' resource records that carry aliases
std::string cname =
(dynamic_cast<boost::net::dns::cname_resource *>(rr_item.get()))
->canonicalname();
- result_cnames.push_back( cname );
+ result_cnames->push_back( string_pair(domain, cname) );
+ GlobalLogger.debug() << LogPrefix << "CNAME " << cname
+ << " with TTL " << ttl << "s for " << domain;
}
else if (rr_type == boost::net::dns::type_ns)
- GlobalLogger.debug() << LogPrefix << "NS resource";
+ { // NS (nameserver) resource records
+ std::string nameserver =
+ (dynamic_cast<boost::net::dns::ns_resource *>(rr_item.get()))
+ ->nameserver();
+ result_nameservers->push_back( string_pair(domain, nameserver) );
+ GlobalLogger.debug() << LogPrefix << "NameServer " << nameserver
+ << " with TTL " << ttl << "s for " << domain;
+ }
else if (rr_type == boost::net::dns::type_soa)
GlobalLogger.debug() << LogPrefix << "SOA resource";
else if (rr_type == boost::net::dns::type_ptr)
else if (rr_type == boost::net::dns::type_axfr)
GlobalLogger.debug() << LogPrefix << "axfr resource";
else
- GlobalLogger.debug() << LogPrefix << "unknown resource type";
+ GlobalLogger.debug() << LogPrefix << "unknown resource type: "
+ << std::showbase << std::hex
+ << static_cast<unsigned>(rr_item->rtype());
}
-
- GlobalLogger.info() << LogPrefix << "Have " << result_ips.size()
- << " IPs and " << result_cnames.size() << " CNAMEs";
-
- // We expect either one single CNAME and no IPs or a list of IPs.
- // But deal with other cases as well
- if (result_ips.empty() && result_cnames.empty())
- handle_unavailable(); // we just got crap, this is a dead end
- else if ( !result_ips.empty() && !result_cnames.empty())
- GlobalLogger.warning() << LogPrefix << "Have CNAMEs AND IPs "
- << "--> deal with both!";
-
- BOOST_FOREACH( const std::string &cname, result_cnames )
- handle_cname(cname); // will schedule another DNS call
-
- if ( !result_ips.empty() )
- handle_ips(result_ips);
}
void DnsResolver::cname_resolve_callback(const std::string &canonical_name,
const bool was_success,
- const int cname_count)
+ const int recursion_count)
{
if (was_success)
// tell cache to return cname's ips if queried for our hostname
else
GlobalLogger.info() << LogPrefix << "Cname resolution failed";
- finalize_resolve(was_success, cname_count+1);
+ // cname counts like one recursion step more...
+ finalize_resolve(was_success, recursion_count+1);
+}
+
+void DnsResolver::handle_recurse(const HostAddress &name_server)
+{
+ // get resolver for same hostname but using a different name server
+ if (Recursor)
+ {
+ GlobalLogger.warning() << "Recursor has not been reset!";
+ Recursor.reset();
+ }
+
+ Recursor = DnsMaster::get_instance()->get_recursor_for(
+ Hostname, Protocol, name_server.get_ip());
+ callback_type callback = boost::bind(
+ &DnsResolver::recursive_resolve_callback,
+ this, name_server.get_ttl().get_value(),
+ _1, _2 );
+ Recursor->async_resolve( callback );
+
+ stop_trying();
+}
+
+
+
+void DnsResolver::recursive_resolve_callback(const uint32_t min_ttl,
+ const bool was_success,
+ const int recursion_count)
+{
+ if (was_success)
+ // make sure the saved TTL is not larger than the one we found here
+ ResolverBase::update_cache_ttl(min_ttl);
+ else
+ GlobalLogger.info() << LogPrefix << "Recursive resolution failed";
+
+ // do not need recursor any more; next time re-create from different random
+ // name server
+ if ( !Recursor )
+ GlobalLogger.warning() << "Recursor was reset before callback!";
+ else
+ Recursor.reset();
+
+ finalize_resolve(was_success, recursion_count+1);
+
}
void DnsResolver::finalize_resolve(const bool was_success,
- const int cname_count)
+ const int recursion_count)
{
// stop timers
- if (cname_count > 0)
+ if (recursion_count > 0)
stop_trying();
// else was called already from handle_cname
// schedule callbacks, clearing callback list
- ResolverBase::schedule_callbacks(was_success, cname_count);
+ ResolverBase::schedule_callbacks(was_success, recursion_count);
// finalize
GlobalLogger.notice() << LogPrefix << "Done resolving"
<< " with success = " << was_success
- << " and cname_count = " << cname_count;
+ << " and recursion_count = " << recursion_count;
IsResolving = false;
}
#include <boost/asio/ip/address.hpp>
#include <boost/system/error_code.hpp>
#include <boost/net/network_array.hpp> // dns_buffer_t
+#include <boost/uuid/uuid_generators.hpp>
#include "dns/resolverbase.h"
#include "dns/dnsmaster.h"
#include "dns/dnscache.h"
+typedef std::pair<std::string, std::string> string_pair;
+
+
class DnsResolver : public ResolverBase
{
public:
void handle_unavailable();
void handle_ips(const HostAddressVec &ips);
void handle_cname(const std::string &canonical_name);
+ void handle_recurse(const HostAddress &name_server);
void cname_resolve_callback(const std::string &canonical_name,
const bool was_success,
- const int cname_count);
- void finalize_resolve(const bool success, const int cname_count=0);
+ const int recursion_count);
+ void recursive_resolve_callback(const uint32_t min_ttl,
+ const bool was_success,
+ const int recursion_count);
+ 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,
+ HostAddressVec *result_ips,
+ std::vector<string_pair> *result_cnames,
+ std::vector<string_pair> *result_nameservers ) const;
// variables
private:
boost::asio::ip::udp::socket Socket;
boost::net::dns_buffer_t ReceiveBuffer;
+ boost::net::dns_buffer_t RequestBuffer;
DnsIpProtocol Protocol;
boost::asio::ip::udp::endpoint NameServer;
boost::asio::deadline_timer ResolveTimeoutTimer;
int RetryCount;
bool IsResolving;
std::string LogPrefix;
+ boost::uuids::random_generator RandomIdGenerator;
+ uint16_t RequestId;
+ ResolverItem Recursor;
};
#endif
void ResolverBase::update_cache( const HostAddressVec &new_results ) const
{ Cache->update( Hostname, new_results ); }
+void ResolverBase::update_cache( const std::string &cname ) const
+{ Cache->update( Hostname, cname ); }
+
+void ResolverBase::update_cache_ttl( const uint32_t ttl ) const
+{ Cache->update_ttl( Hostname, ttl ); }
+
HostAddressVec& ResolverBase::get_cached_results(const std::string host) const
{
if (host.empty())
virtual void do_resolve() = 0;
void update_cache( const HostAddressVec &new_results ) const;
+ void update_cache( const std::string &cname ) const;
+ void update_cache_ttl( const uint32_t ttl ) const;
HostAddressVec& get_cached_results(const std::string host="") const;
}
void PingRotate::dns_resolve_callback(const bool was_success,
- const int cname_count)
+ const int recursion_count)
{
GlobalLogger.info() << "PingRotate: dns resolution finished "
<< "with success = " << was_success << " "
- << "and cname_count = " << cname_count;
+ << "and recursion_count = " << recursion_count;
+ throw std::runtime_error("Only debugging DNS -- exit by error");
if (DnsResolutionFinished)
{ // there were probably several calls to async_resolve before it could
// finish --> ignore this callback
IoServiceItem io_service;
int ret_code = 0;
unsigned n_exceptions = 0;
- unsigned max_exceptions = 0;
+ unsigned max_exceptions = 1;
+
try
{
GetConfigReturnType success_and_config = get_configuration( argc, argv );
if ( ret_code == 0 )
{
GlobalLogger.info() << "starting io_service main loop" << endl;
+
+ if (max_exceptions > 0)
+ GlobalLogger.warning() << "Limited number of acceptable exceptions,"
+ << " this is a debugging option!";
+
// call boost::asio main event loop, catching exceptions
while ( !signal_data.stopped )
{