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)
{
if (TheOnlyInstance)
return;
}
- GlobalLogger.info() << "Creating DNS Master";
+ GlobalLogger.info() << "Creating DNS Cache and Master";
DnsCacheItem cache( new DnsCache(io_serv, cache_file) );
- TheOnlyInstance.reset( new DnsMaster(io_serv, name_server, cache) );
+ TheOnlyInstance.reset( new DnsMaster(io_serv,
+ 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 int resolved_ip_ttl_threshold,
+ const int max_address_resolution_attempts,
const DnsCacheItem &cache)
: IoService( io_serv )
, NameServer( name_server )
+ , ResolvedIpTtlThreshold( resolved_ip_ttl_threshold )
+ , MaxAddressResolutionAttempts( max_address_resolution_attempts )
, Cache(cache)
, ResolverMap()
{
-ResolverItem& DnsMaster::get_resolver_for( const std::string &hostname )
+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);
+ return get_resolver_for(hostname, protocol);
+}
+
+
+ResolverItem& DnsMaster::get_resolver_for( const std::string &hostname,
+ const DnsIpProtocol &protocol )
{
DnsMasterItem master = get_instance();
- if ( master->ResolverMap.count(hostname) == 0 )
+
+ // create key to ResolverMap
+ resolver_key_type key(hostname, protocol);
+ if ( master->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) )
{
- GlobalLogger.info() << "Creating PseudoResolver for IP "
- << hostname;
+ boost::asio::ip::address ip
+ = boost::asio::ip::address::from_string(hostname);
+ if ( (protocol == DNS_IPv4 && !ip.is_v4()) ||
+ (protocol == DNS_IPv6 && !ip.is_v6()) )
+ GlobalLogger.warning() << "Asked to create a DNS resolver "
+ << "for wrong IP protocol: v4 != v6! "
+ << "We will comply.";
+ GlobalLogger.info() << "Creating PseudoResolver for IP " << ip;
ResolverItem new_resolver( new IpPseudoResolver(IoService,
hostname,
Cache) );
- master->ResolverMap[hostname] = new_resolver;
+ master->ResolverMap[key] = new_resolver;
}
else
{
GlobalLogger.info() << "Creating Resolver for host " << hostname;
ResolverItem new_resolver( new DnsResolver(IoService,
hostname,
+ protocol,
Cache,
NameServer) );
- master->ResolverMap[hostname] = new_resolver;
+ master->ResolverMap[key] = new_resolver;
}
}
- return master->ResolverMap[hostname];
+ return master->ResolverMap[key];
}
/**
}
}
-void DnsMaster::unregister_resolver(const std::string &hostname)
+
+DnsIpProtocol DnsMaster::ping2dns_protocol(const PingProtocol& pprot)
+{
+ switch (pprot)
+ {
+ case PingProtocol_ICMP: return DNS_IPv4; break;
+ case PingProtocol_ICMPv6: return DNS_IPv6; break;
+ case PingProtocol_TCP: return DNS_IPv4; break;
+ case PingProtocol_TCP_IPv6: return DNS_IPv6; break;
+ default:
+ GlobalLogger.warning() << "Unexpected ping protocol: "
+ << static_cast<int>(pprot);
+ return DNS_IPALL;
+ break;
+ }
+}
+
+/*boost::asio::ip::address &DnsMaster::get_name_server() const
+{
+ return NameServer;
+}*/
+
+int DnsMaster::get_resolved_ip_ttl_threshold() const
+{
+ return ResolvedIpTtlThreshold;
+}
+
+int DnsMaster::get_max_address_resolution_attempts() const
{
- int n_erased_reslv = ResolverMap.erase(hostname);
- if (n_erased_reslv == 1)
- GlobalLogger.info() << "Unregistered resolver for " << hostname
- << " from DNS master";
- else
- GlobalLogger.warning() << "Unregistered " << n_erased_reslv
- << "(!) resolvers for " << hostname
- << " from DNS master!";
+ return MaxAddressResolutionAttempts;
}
// (created using vim -- the world's best text editor)
#define DNS_MASTER_H
#include <map>
+#include <utility> // pair
#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>
+#include <boost/net/dns.hpp>
#include "host/pinger.h" // for IoserviceItem
+#include "host/pingprotocol.h"
#include "dns_neww/dnscache.h"
#include "dns_neww/resolverbase.h"
typedef boost::shared_ptr<DnsMaster> DnsMasterItem;
-typedef std::map<std::string, ResolverItem> resolver_map_type;
+typedef boost::net::dns::type_t DnsIpProtocol;
+DnsIpProtocol DNS_IPv4 = boost::net::dns::type_a;
+DnsIpProtocol DNS_IPv6 = boost::net::dns::type_a6;
+DnsIpProtocol DNS_IPALL = boost::net::dns::type_all;
+
+typedef std::pair<std::string, DnsIpProtocol> resolver_key_type;
+typedef std::map<resolver_key_type, ResolverItem> resolver_map_type;
class DnsMaster : boost::noncopyable
{
+// Resolver factory
public:
-// the two functions called during init
-public:
- static void create_master(const IoServiceItem &io_serv,
- const boost::asio::ip::address &name_server,
- const std::string &cache_file);
- ResolverItem& get_resolver_for(const std::string &hostname); // factory!
- void unregister_resolver(const std::string &hostname);
+ ResolverItem& get_resolver_for(const std::string &hostname,
+ const PingProtocol &ping_protocol);
+ ResolverItem& get_resolver_for(const std::string &hostname,
+ const DnsIpProtocol &protocol);
// implementation of singleton
private:
DnsMaster(const IoServiceItem &io_serv,
const boost::asio::ip::address &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);
static DnsMasterItem& get_instance();
~DnsMaster();
+// storage of global variables
+public:
+ //boost::asio::ip::address &get_name_server() const; // currently unused
+ int get_resolved_ip_ttl_threshold() const;
+ int get_max_address_resolution_attempts() const;
+
// variables
private:
IoServiceItem IoService;
const boost::asio::ip::address NameServer;
+ const int ResolvedIpTtlThreshold;
+ const int MaxAddressResolutionAttempts;
DnsCacheItem Cache;
resolver_map_type ResolverMap;
-
-// functions
+// internal helper functions
private:
bool is_ip(const std::string &hostname) const;
+ static DnsIpProtocol ping2dns_protocol(const PingProtocol& pprot);
};
#endif
const int StaleDataLongtermMinutes = 15;
const int DNS_PORT = 53;
const int UniqueID = 0xaffe;
- const int MaxRetryCount = 5;
}
DnsResolver::DnsResolver(IoServiceItem &io_serv,
const std::string &hostname,
+ const DnsIpProtocol &protocol,
const DnsCacheItem cache,
const boost::asio::ip::address &name_server)
: ResolverBase( io_serv, hostname, cache )
, Socket( *io_serv, ip::udp::endpoint(ip::udp::v4(), 0) )
, ReceiveBuffer()
+ , Protocol( protocol )
, NameServer( name_server, Config::DNS_PORT )
, ResolveTimeoutTimer( *io_serv )
, PauseBeforeRetryTimer( *io_serv )
if (rr_type == boost::net::dns::type_a)
{ // 'A' resource records carry IPv4 addresses
+ if (Protocol == DNS_IPv6)
+ {
+ GlobalLogger.info() << "Ignoring IPv4 address because resolver "
+ << "was configured to only use IPv6.";
+ continue;
+ }
boost::asio::ip::address_v4 ip =
( dynamic_cast<boost::net::dns::a_resource *> (rr_item.get()) )
->address();
}
else if (rr_type == boost::net::dns::type_a6)
{ // 'AAAA' resource records carry IPv6 addresses
+ if (Protocol == DNS_IPv4)
+ {
+ GlobalLogger.info() << "Ignoring IPv6 address because resolver "
+ << "was configured to only use IPv4.";
+ continue;
+ }
boost::asio::ip::address_v6 ip =
( dynamic_cast<boost::net::dns::a6_resource *> (rr_item.get()) )
->address();
{
// get resolver for canonical name
ResolverItem resolver = DnsMaster::get_instance()
- ->get_resolver_for(canonical_name);
+ ->get_resolver_for(canonical_name, Protocol);
callback_type callback = boost::bind( &DnsResolver::cname_resolve_callback,
this, canonical_name, _1, _2 );
resolver->async_resolve( callback );
// increment timer
++RetryCount;
- if (RetryCount > Config::MaxRetryCount)
+ if ( RetryCount > DnsMaster::get_instance()
+ ->get_max_address_resolution_attempts() )
{
handle_unavailable();
RetryCount = 0;
return cached_data[NextIpIndex++];
}
+bool DnsResolver::have_up_to_date_ip()
+{
+ // get cached data
+ HostAddressVec cached_data = ResolverBase::get_cached_results();
+
+ // get threshold
+ int resolved_ip_ttl_threshold = 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;
+}
+
+int DnsResolver::get_resolved_ip_count()
+{
+ return ResolverBase::get_cached_results().size();
+}
+
// (created using vim -- the world's best text editor)
// constructor accessible from friend DnsMaster
public:
friend ResolverItem& DnsMaster::get_resolver_for(
- const std::string &hostname);
+ const std::string &hostname,
+ const DnsIpProtocol &protocol);
private:
DnsResolver(IoServiceItem &io_serv,
const std::string &hostname,
+ const DnsIpProtocol &protocol,
const DnsCacheItem cache,
const boost::asio::ip::address &name_server);
// only real public function (called from pingers)
public:
HostAddress get_next_ip();
+ bool have_up_to_date_ip();
+ int get_resolved_ip_count();
// implementation of ResolverBase::async_resolve
protected:
private:
boost::asio::ip::udp::socket Socket;
boost::net::dns_buffer_t ReceiveBuffer;
+ DnsIpProtocol Protocol;
boost::asio::ip::udp::endpoint NameServer;
boost::asio::deadline_timer ResolveTimeoutTimer;
boost::asio::deadline_timer PauseBeforeRetryTimer;
// constructor accessible from friend DnsMaster
public:
friend ResolverItem& DnsMaster::get_resolver_for(
- const std::string &hostname);
+ const std::string &hostname,
+ const DnsIpProtocol &protocol);
private:
IpPseudoResolver(const IoServiceItem io_serv,
const std::string &ip_string,
// only real public function
public:
HostAddress get_next_ip() { return IpAddress; }
+ bool have_up_to_date_ip() { return true; }
+ int get_resolved_ip_count(){ return 1; }
// implementation of ResolverBase::async_resolve
protected:
void do_resolve()
- { ResolverBase::schedule_callbacks(true, 0); }
+ { ResolverBase::schedule_callbacks(true, 0); }
};
#endif
*/
void async_resolve(const callback_type &callback);
+ virtual bool have_up_to_date_ip() = 0;
+ virtual int get_resolved_ip_count() = 0;
+
protected:
ResolverBase(const IoServiceItem &io_serv,
const std::string &hostname,