From 923626c0374eb916438326ce55dff0511f93dc6b Mon Sep 17 00:00:00 2001 From: Christian Herdtweck Date: Fri, 10 Apr 2015 12:26:41 +0200 Subject: [PATCH] added missing functions and config vars used by pingscheduler/pingrotate * functions have_up_to_date_ips and get_resolved_ip_count to resolvers * limitation to only IPv4/v6 to DnsResolver * --> DnsMaster remembers resolvers by pair(host name, ip version) * DnsMaster holds global config vars NameServer, ResolvedIpTtlThreshold and MaxAddressResolutionAttempts and provides public getters for them --- src/dns_neww/dnsmaster.cpp | 87 +++++++++++++++++++++++++++++++-------- src/dns_neww/dnsmaster.h | 42 ++++++++++++++---- src/dns_neww/dnsresolver.cpp | 46 +++++++++++++++++++- src/dns_neww/dnsresolver.h | 7 +++- src/dns_neww/ippseudoresolver.h | 7 ++- src/dns_neww/resolverbase.h | 3 + 6 files changed, 158 insertions(+), 34 deletions(-) diff --git a/src/dns_neww/dnsmaster.cpp b/src/dns_neww/dnsmaster.cpp index 5c791a7..7553eef 100644 --- a/src/dns_neww/dnsmaster.cpp +++ b/src/dns_neww/dnsmaster.cpp @@ -37,6 +37,8 @@ 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) { if (TheOnlyInstance) @@ -46,17 +48,26 @@ void DnsMaster::create_master(const IoServiceItem &io_serv, 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() { @@ -73,33 +84,53 @@ DnsMasterItem& DnsMaster::get_instance() -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]; } /** @@ -121,16 +152,36 @@ bool DnsMaster::is_ip(const std::string &hostname) const } } -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(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) diff --git a/src/dns_neww/dnsmaster.h b/src/dns_neww/dnsmaster.h index 028e831..c8c5866 100644 --- a/src/dns_neww/dnsmaster.h +++ b/src/dns_neww/dnsmaster.h @@ -36,11 +36,14 @@ #define DNS_MASTER_H #include +#include // pair #include #include +#include #include "host/pinger.h" // for IoserviceItem +#include "host/pingprotocol.h" #include "dns_neww/dnscache.h" #include "dns_neww/resolverbase.h" @@ -48,19 +51,23 @@ class DnsMaster; typedef boost::shared_ptr DnsMasterItem; -typedef std::map 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 resolver_key_type; +typedef std::map 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: @@ -68,22 +75,37 @@ 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 diff --git a/src/dns_neww/dnsresolver.cpp b/src/dns_neww/dnsresolver.cpp index 35bd772..f1bbb6f 100644 --- a/src/dns_neww/dnsresolver.cpp +++ b/src/dns_neww/dnsresolver.cpp @@ -45,16 +45,17 @@ namespace Config 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 ) @@ -163,6 +164,12 @@ void DnsResolver::handle_dns_result(const boost::system::error_code &error, 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 (rr_item.get()) ) ->address(); @@ -170,6 +177,12 @@ void DnsResolver::handle_dns_result(const boost::system::error_code &error, } 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 (rr_item.get()) ) ->address(); @@ -251,7 +264,7 @@ void DnsResolver::handle_cname(const std::string &canonical_name) { // 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 ); @@ -324,7 +337,8 @@ void DnsResolver::handle_resolve_timeout(const boost::system::error_code &error) // increment timer ++RetryCount; - if (RetryCount > Config::MaxRetryCount) + if ( RetryCount > DnsMaster::get_instance() + ->get_max_address_resolution_attempts() ) { handle_unavailable(); RetryCount = 0; @@ -379,5 +393,31 @@ HostAddress DnsResolver::get_next_ip() 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) diff --git a/src/dns_neww/dnsresolver.h b/src/dns_neww/dnsresolver.h index 5556502..d56df2a 100644 --- a/src/dns_neww/dnsresolver.h +++ b/src/dns_neww/dnsresolver.h @@ -44,16 +44,20 @@ public: // 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: @@ -76,6 +80,7 @@ private: 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; diff --git a/src/dns_neww/ippseudoresolver.h b/src/dns_neww/ippseudoresolver.h index f5fd006..dd7b792 100644 --- a/src/dns_neww/ippseudoresolver.h +++ b/src/dns_neww/ippseudoresolver.h @@ -47,7 +47,8 @@ class IpPseudoResolver : public ResolverBase // 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, @@ -63,11 +64,13 @@ private: // 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 diff --git a/src/dns_neww/resolverbase.h b/src/dns_neww/resolverbase.h index cbd6ae6..3b2a1ab 100644 --- a/src/dns_neww/resolverbase.h +++ b/src/dns_neww/resolverbase.h @@ -51,6 +51,9 @@ public: */ 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, -- 1.7.1