added missing functions and config vars used by pingscheduler/pingrotate
authorChristian Herdtweck <christian.herdtweck@intra2net.com>
Fri, 10 Apr 2015 10:26:41 +0000 (12:26 +0200)
committerChristian Herdtweck <christian.herdtweck@intra2net.com>
Mon, 4 May 2015 14:57:57 +0000 (16:57 +0200)
* 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
src/dns_neww/dnsmaster.h
src/dns_neww/dnsresolver.cpp
src/dns_neww/dnsresolver.h
src/dns_neww/ippseudoresolver.h
src/dns_neww/resolverbase.h

index 5c791a7..7553eef 100644 (file)
@@ -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<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)
index 028e831..c8c5866 100644 (file)
 #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"
 
@@ -48,19 +51,23 @@ class DnsMaster;
 
 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:
@@ -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
index 35bd772..f1bbb6f 100644 (file)
@@ -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<boost::net::dns::a_resource *> (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<boost::net::dns::a6_resource *> (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)
 
index 5556502..d56df2a 100644 (file)
@@ -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;
index f5fd006..dd7b792 100644 (file)
@@ -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
 
index cbd6ae6..3b2a1ab 100644 (file)
@@ -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,