completed partial IPv6 compatibility in DNS; does retrieve and Cache IPv6 IPs
[pingcheck] / src / dns / dnscache.cpp
index d7c8182..bf68129 100644 (file)
@@ -208,33 +208,51 @@ void DnsCache::load_from_cachefile()
 // UPDATE
 // -----------------------------------------------------------------------------
 
-// warn if hostname is empty and remove trailing dot
-std::string DnsCache::key_for_hostname(const std::string &hostname) const
+/*
+ * warn if hostname is empty and remove trailing dot
+ * also warn if protocol is neither IPv4 nor IPv6
+ */
+ip_map_key_type DnsCache::key_for_ips(const std::string &hostname,
+                                   const DnsIpProtocol &protocol) const
 {
     if (hostname.empty())
     {
         GlobalLogger.info() << "DnsCache: empty host!";
-        return "";
+        return ip_map_key_type("", DNS_IPALL);
+    }
+    if (protocol == DNS_IPALL)
+    {
+        GlobalLogger.info() << "DnsCache: neither IPv4 nor v6!";
+        return ip_map_key_type("", DNS_IPALL);
     }
 
     // check whether last character is a dot
     if (hostname.rfind('.') == hostname.length()-1)
-        return hostname.substr(0, hostname.length()-1);
+        return ip_map_key_type( hostname.substr(0, hostname.length()-1),
+                             protocol );
     else
-        return hostname;
+        return ip_map_key_type( hostname,
+                             protocol );
 }
 
 
 void DnsCache::update(const std::string &hostname,
+                      const DnsIpProtocol &protocol,
                       const HostAddressVec &new_ips)
 {
-    std::string key = key_for_hostname(hostname);
+    // check for valid input arguments
+    ip_map_key_type key = key_for_ips(hostname, protocol);
+    if ( key.first.empty() )
+        return;
+
+    // ensure that there is never IP and CNAME for the same host
     if ( !get_cname(hostname).Host.empty() )
-    {   // ensure that there is never IP and CNAME for the same host
-        GlobalLogger.info() << "DnsCache: Saving IPs for " << key
+    {
+        GlobalLogger.info() << "DnsCache: Saving IPs for " << key.first
             << " removes CNAME to " << get_cname(hostname).Host << "!";
         update(hostname, Cname());   // overwrite with "empty" cname
     }
+
     // ensure min ttl of MinTimeBetweenResolves
     HostAddressVec ips_checked;
     BOOST_FOREACH( const HostAddress &addr, new_ips )
@@ -242,7 +260,7 @@ void DnsCache::update(const std::string &hostname,
         if ( addr.get_ttl().get_value() < MinTimeBetweenResolves )
         {
             GlobalLogger.info() << "DnsCache: Correcting TTL of IP for "
-                << hostname << " from " << addr.get_ttl().get_value() << "s to "
+                << key.first << " from " << addr.get_ttl().get_value() << "s to "
                 << MinTimeBetweenResolves << "s because was too short";
             ips_checked.push_back( HostAddress( addr.get_ip(),
                                                 MinTimeBetweenResolves) );
@@ -251,8 +269,9 @@ void DnsCache::update(const std::string &hostname,
             ips_checked.push_back(addr);
     }
 
+    // write IPs into one log line
     stringstream log_temp;
-    log_temp << "DnsCache: update IPs for " << key << " to "
+    log_temp << "DnsCache: update IPs for " << key.first << " to "
              << ips_checked.size() << "-list: ";
     BOOST_FOREACH( const HostAddress &ip, ips_checked )
         log_temp << ip.get_ip() << ", ";
@@ -263,32 +282,61 @@ void DnsCache::update(const std::string &hostname,
 }
 
 
+/*
+ * warn if hostname is empty and remove trailing dot
+ */
+cname_map_key_type DnsCache::key_for_cname(const std::string &hostname) const
+{
+    if (hostname.empty())
+    {
+        GlobalLogger.info() << "DnsCache: empty host!";
+        return "";
+    }
+
+    // check whether last character is a dot
+    if (hostname.rfind('.') == hostname.length()-1)
+        return hostname.substr(0, hostname.length()-1);
+    else
+        return hostname;
+}
+
+
 void DnsCache::update(const std::string &hostname,
                       const Cname &cname)
 {
-    std::string key = key_for_hostname(hostname);
-    if ( !get_ips(hostname).empty() )
-    {   // ensure that there is never IP and CNAME for the same host
+    // check for valid input arguments
+    cname_map_key_type key = key_for_cname(hostname);
+    if ( key.empty() )
+        return;
+
+    // ensure that there is never IP and CNAME for the same host
+    int n_ips = get_ips(hostname, DNS_IPv4).size()
+              + get_ips(hostname, DNS_IPv6).size();
+    if ( n_ips > 0 )
+    {
+        GlobalLogger.info() << "DnsCache: Saving IPs for " << key
+            << " removes CNAME to " << get_cname(hostname).Host << "!";
         GlobalLogger.info() << "DnsCache: Saving CNAME for " << key
-            << " removes " << get_ips(hostname).size() << " IPs for same host!";
-        update(hostname, HostAddressVec());   // overwrite with empty IP list
+            << " removes " <<  n_ips << " IPs for same host!";
+        update(hostname, DNS_IPv4, HostAddressVec());
+        update(hostname, DNS_IPv6, HostAddressVec());
     }
 
-    // remove possible trailing dot from cname
-    Cname to_save = Cname(key_for_hostname(cname.Host),
+    // remove possible trailing dot from cname's target host
+    Cname to_save = Cname(key_for_cname(cname.Host),  // implicit cast to string
                           cname.Ttl);
 
     // ensure min ttl of MinTimeBetweenResolves
     if ( to_save.Ttl.get_value() < MinTimeBetweenResolves )
     {
         GlobalLogger.info() << "DnsCache: Correcting TTL of CNAME of "
-            << hostname << " from " << to_save.Ttl.get_value() << "s to "
+            << key << " from " << to_save.Ttl.get_value() << "s to "
             << MinTimeBetweenResolves << "s because was too short";
         to_save.Ttl = TimeToLive(MinTimeBetweenResolves);
     }
 
     GlobalLogger.notice() << "DnsCache: update CNAME for " << key
-                        << " to " << to_save.Host;
+                          << " to " << to_save.Host;
     CnameCache[key] = to_save;
     HasChanged = true;
 }
@@ -302,9 +350,10 @@ void DnsCache::update(const std::string &hostname,
  * @returns empty list if no (up to date) ips for hostname in cache
  */
 HostAddressVec DnsCache::get_ips(const std::string &hostname,
+                                 const DnsIpProtocol &protocol,
                                  const bool check_up_to_date)
 {
-    std::string key = key_for_hostname(hostname);
+    ip_map_key_type key = key_for_ips(hostname, protocol);
     HostAddressVec result = IpCache[key];
     if (check_up_to_date)
     {
@@ -325,7 +374,7 @@ HostAddressVec DnsCache::get_ips(const std::string &hostname,
         }
         result = result_up_to_date;
     }
-    /*GlobalLogger.debug() << "DnsCache: request IPs for " << key
+    /*GlobalLogger.debug() << "DnsCache: request IPs for " << key.first
                          << " --> " << result.size() << "-list";
     BOOST_FOREACH( const HostAddress &addr, result )
         GlobalLogger.debug() << "DnsCache:    " << addr.get_ip().to_string()
@@ -340,7 +389,7 @@ HostAddressVec DnsCache::get_ips(const std::string &hostname,
 Cname DnsCache::get_cname(const std::string &hostname,
                           const bool check_up_to_date)
 {
-    std::string key = key_for_hostname(hostname);
+    cname_map_key_type key = key_for_cname(hostname);
     Cname result_obj = CnameCache[key];
     /*GlobalLogger.debug() << "DnsCache: request CNAME for " << key
                          << " --> \"" << result_obj.Host << "\" (TTL "
@@ -366,11 +415,12 @@ Cname DnsCache::get_cname(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 DnsIpProtocol &protocol,
                                            const bool check_up_to_date)
 {
     std::string current_host = hostname;
     Cname current_cname;
-    HostAddressVec result = get_ips(current_host, check_up_to_date);
+    HostAddressVec result = get_ips(current_host, protocol, check_up_to_date);
     int n_recursions = 0;
     uint32_t min_cname_ttl = 0xffff;   // largest possible unsigned 4-byte value
     int max_recursion_count = DnsMaster::get_instance()
@@ -379,9 +429,10 @@ HostAddressVec DnsCache::get_ips_recursive(const std::string &hostname,
     {
         current_cname = get_cname(current_host, check_up_to_date);
         if (current_cname.Host.empty())
-            break;
+            break;   // no ips (since result.empty()) and no cname
+                     // --> will return empty result
 
-        current_host = key_for_hostname(current_cname.Host);
+        current_host = current_cname.Host;
         if (++n_recursions >= max_recursion_count)
         {
             GlobalLogger.info() << "DnsCache: reached recursion limit of "
@@ -393,7 +444,7 @@ HostAddressVec DnsCache::get_ips_recursive(const std::string &hostname,
         {
             min_cname_ttl = min(min_cname_ttl,
                                 current_cname.Ttl.get_updated_value());
-            result = get_ips(current_host, check_up_to_date);
+            result = get_ips(current_host, protocol, check_up_to_date);
         }
     }