completed partial IPv6 compatibility in DNS; does retrieve and Cache IPv6 IPs
authorChristian Herdtweck <christian.herdtweck@intra2net.com>
Fri, 22 May 2015 08:16:36 +0000 (10:16 +0200)
committerChristian Herdtweck <christian.herdtweck@intra2net.com>
Fri, 22 May 2015 08:16:36 +0000 (10:16 +0200)
also added test for this and updated cache test for future cases of cache structure changes

23 files changed:
doc/pingcheck_icmp_distributor.graphml
src/CMakeLists.txt
src/dns/dnscache.cpp
src/dns/dnscache.h
src/dns/dnsipprotocol.cpp [new file with mode: 0644]
src/dns/dnsipprotocol.h [new file with mode: 0644]
src/dns/dnsmaster.cpp
src/dns/dnsmaster.h
src/dns/dnsresolver.cpp
src/dns/dnsresolver.h
src/dns/ippseudoresolver.h
src/dns/resolverbase.cpp
src/dns/resolverbase.h
src/host/pingerfactory.cpp
src/host/pingprotocol.cpp
src/host/pingprotocol.h
src/host/pingscheduler.cpp
src/icmp/icmppinger.cpp
test/CMakeLists.test_dns.txt
test/data/CMakeLists.txt
test/data/dns_cache_compatibility_test.xml [new file with mode: 0644]
test/data/dns_cache_example.xml [deleted file]
test/test_dns.cpp

index 7e532fa..2db6668 100644 (file)
@@ -2559,7 +2559,7 @@ shared_ptrs<y:LabelModel>
     <edge id="n0::e29" source="n0::n84" target="n0::n44">
       <data key="d10">
         <y:QuadCurveEdge straightness="0.1">
-          <y:Path sx="0.0" sy="21.423017741544847" tx="0.0" ty="0.0"/>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
           <y:LineStyle color="#000000" type="line" width="1.0"/>
           <y:Arrows source="none" target="standard"/>
         </y:QuadCurveEdge>
@@ -3259,6 +3259,28 @@ shared_ptrs<y:LabelModel>
         </y:SplineEdge>
       </data>
     </edge>
+    <edge id="n0::e96" source="n0::n39" target="n0::n84">
+      <data key="d9"/>
+      <data key="d10">
+        <y:SplineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+            <y:Point x="-152.3464868738588" y="2260.694553272394"/>
+          </y:Path>
+          <y:LineStyle color="#000000" type="dotted" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+        </y:SplineEdge>
+      </data>
+    </edge>
+    <edge id="n0::e97" source="n0::n23" target="n0::n83">
+      <data key="d9"/>
+      <data key="d10">
+        <y:SplineEdge>
+          <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+          <y:LineStyle color="#000000" type="dotted" width="1.0"/>
+          <y:Arrows source="none" target="standard"/>
+        </y:SplineEdge>
+      </data>
+    </edge>
   </graph>
   <data key="d7">
     <y:Resources/>
index efed741..10b4f12 100644 (file)
@@ -63,6 +63,7 @@ set(SOURCES
     config/option/dnscachefileoption.cpp
     dns/timetolive.cpp
     dns/hostaddress.cpp
+    dns/dnsipprotocol.cpp
     dns/dnscache.cpp
     dns/resolverbase.cpp
     dns/dnsresolver.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);
         }
     }
 
index 9268c77..e1ed495 100644 (file)
 #include <boost/archive/xml_iarchive.hpp>
 
 #include "host/pinger.h"    // for IoserviceItem
+#include "dns/dnsipprotocol.h"
 #include "dns/hostaddress.h"
 #include "dns/cname.h"
 
 typedef std::vector<HostAddress> HostAddressVec;
-typedef std::map<std::string, HostAddressVec> ip_map_type;
-typedef std::map<std::string, Cname> cname_map_type;
+typedef std::pair<std::string, DnsIpProtocol> ip_map_key_type;
+typedef std::map<ip_map_key_type, HostAddressVec> ip_map_type;
+typedef std::string cname_map_key_type;
+typedef std::map<cname_map_key_type, Cname> cname_map_type;
 
 // -----------------------------------------------------------------------------
 // DnsCache
@@ -56,15 +59,20 @@ public:
     ~DnsCache();
 
     // accessed from ResolverBase subclasses
-    void update(const std::string &hostname, const HostAddressVec &new_ips);
-    void update(const std::string &hostname, const Cname &cname);
+    void update(const std::string &hostname,
+                const DnsIpProtocol &protocol,
+                const HostAddressVec &new_ips);
+    void update(const std::string &hostname,
+                const Cname &cname);
 
     // retrieval
     HostAddressVec get_ips(const std::string &hostname,
+                           const DnsIpProtocol &protocol,
                            const bool check_up_to_date=false);
     Cname get_cname(const std::string &hostname,
-                     const bool check_up_to_date=false);
+                    const bool check_up_to_date=false);
     HostAddressVec get_ips_recursive(const std::string &hostname,
+                                     const DnsIpProtocol &protocol,
                                      const bool check_up_to_date=false);
     std::string get_first_outdated_cname(const std::string &hostname,
                                          const uint32_t ttl_thresh);
@@ -83,7 +91,9 @@ private:
     void schedule_save(const boost::system::error_code &error);
     void save_to_cachefile();
     void load_from_cachefile();
-    std::string key_for_hostname(const std::string &hostname) const;
+    ip_map_key_type key_for_ips(const std::string &hostname,
+                                const DnsIpProtocol &protocol) const;
+    cname_map_key_type key_for_cname(const std::string &hostname) const;
 
 };
 
diff --git a/src/dns/dnsipprotocol.cpp b/src/dns/dnsipprotocol.cpp
new file mode 100644 (file)
index 0000000..54ff4e7
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ The software in this package is distributed under the GNU General
+ Public License version 2 (with a special exception described below).
+
+ A copy of GNU General Public License (GPL) is included in this distribution,
+ in the file COPYING.GPL.
+
+ As a special exception, if other files instantiate templates or use macros
+ or inline functions from this file, or you compile this file and link it
+ with other works to produce a work based on this file, this file
+ does not by itself cause the resulting work to be covered
+ by the GNU General Public License.
+
+ However the source code for this file must still be made available
+ in accordance with section (3) of the GNU General Public License.
+
+ This exception does not invalidate any other reasons why a work based
+ on this file might be covered by the GNU General Public License.
+
+ Christian Herdtweck, Intra2net AG 2015
+ */
+
+#include "dns/dnsipprotocol.h"
+
+#include <logfunc.hpp>
+
+using I2n::Logger::GlobalLogger;
+
+
+std::string to_string(const DnsIpProtocol &protocol)
+{
+    switch (protocol)
+    {
+        case DNS_IPv4:  return "IPv4"; break;
+        case DNS_IPv6:  return "IPv6"; break;
+        case DNS_IPALL: return "IPv4/6"; break;
+        default: GlobalLogger.warning() << "Unexpected protocol in to_string!";
+                 return "Unexpected Protocol"; break;
+    }
+}
+
+DnsIpProtocol 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 in ping2dns_protocol: "
+                << static_cast<int>(pprot);
+            return DNS_IPALL;
+            break;
+    }
+}
+
+
diff --git a/src/dns/dnsipprotocol.h b/src/dns/dnsipprotocol.h
new file mode 100644 (file)
index 0000000..fb0c4bf
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ The software in this package is distributed under the GNU General
+ Public License version 2 (with a special exception described below).
+
+ A copy of GNU General Public License (GPL) is included in this distribution,
+ in the file COPYING.GPL.
+
+ As a special exception, if other files instantiate templates or use macros
+ or inline functions from this file, or you compile this file and link it
+ with other works to produce a work based on this file, this file
+ does not by itself cause the resulting work to be covered
+ by the GNU General Public License.
+
+ However the source code for this file must still be made available
+ in accordance with section (3) of the GNU General Public License.
+
+ This exception does not invalidate any other reasons why a work based
+ on this file might be covered by the GNU General Public License.
+
+ Christian Herdtweck, Intra2net AG 2015
+ */
+
+#ifndef DNS_IP_PROTOCOL_H
+#define DNS_IP_PROTOCOL_H
+
+#include <boost/net/dns.hpp>
+#include "host/pingprotocol.h"
+
+typedef boost::net::dns::type_t DnsIpProtocol;
+const DnsIpProtocol DNS_IPv4 = boost::net::dns::type_a;
+const DnsIpProtocol DNS_IPv6 = boost::net::dns::type_a6;
+const DnsIpProtocol DNS_IPALL = boost::net::dns::type_all;
+
+std::string to_string(const DnsIpProtocol &protocol);
+DnsIpProtocol ping2dns_protocol(const PingProtocol& pprot);
+
+#endif
index b0b4049..c6bca7f 100644 (file)
@@ -158,6 +158,7 @@ ResolverItem& DnsMaster::get_resolver_for(const std::string &hostname,
                                 << ip;
             ResolverItem new_resolver( new IpPseudoResolver(IoService,
                                                             hostname,
+                                                            protocol,
                                                             Cache) );
             ResolverMap[key] = new_resolver;
         }
@@ -196,22 +197,6 @@ bool DnsMaster::is_ip(const std::string &hostname) const
 }
 
 
-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() << "DnsMaster: Unexpected ping protocol: "
-                                   << static_cast<int>(pprot);
-            return DNS_IPALL;
-            break;
-    }
-}
-
 /*boost::asio::ip::address &DnsMaster::get_name_server() const
 {
     return NameServer;
@@ -232,14 +217,3 @@ int DnsMaster::get_max_recursion_count() const
     return MaxRecursionCount;
 }
 
-std::string to_string(const DnsIpProtocol &protocol)
-{
-    switch (protocol)
-    {
-        case DNS_IPv4:  return "IPv4"; break;
-        case DNS_IPv6:  return "IPv6"; break;
-        case DNS_IPALL: return "IPv4/6"; break;
-        default: GlobalLogger.warning() << "Unexpected protocol in to_string!";
-                 return "Unexpected Protocol"; break;
-    }
-}
index ad26341..6b2a8b9 100644 (file)
@@ -44,6 +44,7 @@
 
 #include "host/pinger.h"    // for IoserviceItem
 #include "host/pingprotocol.h"
+#include "dns/dnsipprotocol.h"
 #include "dns/dnscache.h"
 #include "dns/resolverbase.h"
 
@@ -51,16 +52,9 @@ class DnsMaster;
 
 typedef boost::shared_ptr<DnsMaster> DnsMasterItem;
 
-typedef boost::net::dns::type_t DnsIpProtocol;
-const DnsIpProtocol DNS_IPv4 = boost::net::dns::type_a;
-const DnsIpProtocol DNS_IPv6 = boost::net::dns::type_a6;
-const 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;
 
-std::string to_string(const DnsIpProtocol &protocol);
-
 /**
  * Factory and Cache of DNS resolvers
  * 
@@ -134,7 +128,6 @@ private:
 // internal helper functions
 private:
     bool is_ip(const std::string &hostname) const;
-    static DnsIpProtocol ping2dns_protocol(const PingProtocol& pprot);
 };
 
 #endif
index 13a00eb..ff376ea 100644 (file)
@@ -55,12 +55,11 @@ DnsResolver::DnsResolver(IoServiceItem &io_serv,
                          const DnsIpProtocol &protocol,
                          const DnsCacheItem cache,
                          const boost::asio::ip::address &name_server)
-    : ResolverBase( io_serv, hostname, cache )
+    : ResolverBase( io_serv, hostname, protocol, cache )
     , 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 )
     , PauseBeforeRetryTimer( *io_serv )
@@ -465,7 +464,7 @@ void DnsResolver::handle_cname(const int recursion_count,
     else
     {   // check cache for IP for this cname
         bool check_up_to_date = true;
-        HostAddressVec cached_data = Cache->get_ips_recursive(last_cname,
+        HostAddressVec cached_data = get_cached_ips_recursively(last_cname,
                                                               check_up_to_date);
         if ( !cached_data.empty() )
         {
index 5ab1fd2..0201dfa 100644 (file)
@@ -101,7 +101,6 @@ 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;
     boost::asio::deadline_timer PauseBeforeRetryTimer;
index 0e194b8..abe9299 100644 (file)
@@ -52,8 +52,9 @@ public:
 private:
     IpPseudoResolver(const IoServiceItem io_serv,
                      const std::string &ip_string,
+                     const DnsIpProtocol &protocol,
                      const DnsCacheItem &cache )
-        : ResolverBase( io_serv, ip_string, cache )
+        : ResolverBase( io_serv, ip_string, protocol, cache )
         , IpAddress( boost::asio::ip::address::from_string(ip_string),
                      Config::DefaultTtl )
     {}
index 367f46e..da76115 100644 (file)
@@ -66,9 +66,11 @@ void ResolverBase::async_resolve(const callback_type &callback,
 
 ResolverBase::ResolverBase(const IoServiceItem &io_serv,
              const std::string &hostname,
+             const DnsIpProtocol &protocol,
              const DnsCacheItem &cache )
     : IoService( io_serv )
     , Hostname( hostname )
+    , Protocol( protocol )
     , Cache( cache )
     , CallbackList()
 {}
@@ -90,26 +92,33 @@ std::string ResolverBase::get_skip_cname() const
 
 void ResolverBase::update_cache( const std::string &hostname,
                                  const HostAddressVec &new_ips ) const
-{   Cache->update( hostname, new_ips );  }
+{   Cache->update( hostname, Protocol, new_ips );  }
 
 void ResolverBase::update_cache( const std::string &hostname,
                                  const Cname &cname ) const
 {   Cache->update( hostname, cname );  }
 
 void ResolverBase::update_cache( const HostAddressVec &new_ips ) const
-{   Cache->update( Hostname, new_ips );  }
+{   Cache->update( Hostname, Protocol, new_ips );  }
 
 void ResolverBase::update_cache( const Cname &cname ) const
 {   Cache->update( Hostname, cname );  }
 
 
+/**
+ * @brief get IPs like a "real" resolver, i.e. recursively going through CNAMEs
+ *
+ * if host is empty, will use this Resolver's Hostname and Protocol
+ *
+ * just calls DnsCache::get_ips_recursive
+ */
 HostAddressVec ResolverBase::get_cached_ips_recursively(const std::string host,
                                                     bool check_up_to_date) const
 {
     if (host.empty())
-        return Cache->get_ips_recursive(Hostname, check_up_to_date);
+        return Cache->get_ips_recursive(Hostname, Protocol, check_up_to_date);
     else
-        return Cache->get_ips_recursive(host, check_up_to_date);
+        return Cache->get_ips_recursive(host, Protocol, check_up_to_date);
 }
 
 void ResolverBase::schedule_callbacks(const bool was_success,
index ee33447..1c9a573 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <queue>
 #include "host/pinger.h"
+#include "dns/dnsipprotocol.h"
 #include "dns/hostaddress.h"
 #include "dns/dnscache.h"
 
@@ -68,12 +69,14 @@ public:
 protected:
     ResolverBase(const IoServiceItem &io_serv,
                  const std::string &hostname,
+                 const DnsIpProtocol &protocol,
                  const DnsCacheItem &cache );
 
 // variables
 protected:
     IoServiceItem IoService;
     const std::string Hostname;
+    const DnsIpProtocol Protocol;
     DnsCacheItem Cache;
     callback_list_type CallbackList;
 
index a919b9a..75d43ed 100644 (file)
@@ -117,7 +117,8 @@ PingerItem PingerFactory::createPinger(
     {
         // Raw sockets are locked down by Unix operating systems to prevent
         // malware and security holes, thus it requires root access to use it.
-        GlobalLogger.error() << "Pingcheck must run as root (" << ex.what() << ")" << endl;
+        GlobalLogger.error() << "Error creating Pinger: " << ex.what()
+            << " (you may have to run pingcheck as root)" << endl;
         exit( EXIT_FAILURE );
     }
 
index 6e57c87..6698526 100644 (file)
@@ -60,3 +60,18 @@ PingProtocol get_ping_protocol_from_string( const string & protocol_string )
 
     return protocol;
 }
+
+std::string ping_protocol_to_string( const PingProtocol &protocol)
+{
+    switch(protocol)
+    {
+        case PingProtocol_ICMP:     return "ICMPv4"; break;
+        case PingProtocol_ICMPv6:   return "ICMPv6"; break;
+        case PingProtocol_TCP:      return "TCPv4";  break;
+        case PingProtocol_TCP_IPv6: return "TCPv6";  break;
+        default:
+            BOOST_ASSERT(
+                    !"unexpected PingProtocol in ping_protocol_to_string!" );
+            break;
+    }
+}
index 2e0bda1..54c91db 100644 (file)
@@ -39,6 +39,7 @@ enum PingProtocol
 };
 
 PingProtocol get_ping_protocol_from_string( const std::string & protocol_string );
+std::string ping_protocol_to_string( const PingProtocol &protocol);
 
 //-----------------------------------------------------------------------------
 // PingProtocolList
index 179a70b..481d394 100644 (file)
@@ -318,6 +318,12 @@ void PingScheduler::update_ping_protocol()
 
 void PingScheduler::get_next_ping_protocol()
 {
+    if (Ping)
+    {
+        Ping->stop_pinging();
+        Ping.reset();
+    }
+
     GlobalLogger.debug() << LogPrefix
         << "------------------------------------------------------------------";
     ++ProtocolIter;
@@ -327,9 +333,6 @@ void PingScheduler::get_next_ping_protocol()
     // --> ProtocolIter still points to currently used protocol which is
     //     required in dns_resolve_callback
 
-    if (Ping)
-        Ping->stop_pinging();
-
     Ping = PingerFactory::createPinger(ping_protocol, IoService,
                                        NetworkInterfaceName, PingReplyTimeout);
 
index 92a30fc..93a071d 100644 (file)
@@ -53,7 +53,7 @@ PingerItem IcmpPinger::create(
 {
     // get distributor
     IcmpPacketDistributorItem distributor = IcmpPacketDistributor::get_distributor(
-            icmp::v4(), source_network_interface, io_serv);
+            protocol, source_network_interface, io_serv);
 
     // create pinger
     IcmpPinger *ptr = new IcmpPinger(io_serv, protocol, echo_reply_timeout_in_sec, distributor);
@@ -439,8 +439,17 @@ IcmpPacketDistributorItem IcmpPacketDistributor::get_distributor(
     // check if there is an instance for this protocol and interface
     if ( Instances.count(identifier) == 0 )
     {   // need to create an instance for this protocol and network interface
+        std::string protocol_str;
+        if (protocol == icmp::v4())
+            protocol_str = "ICMPv4";
+        else if (protocol == icmp::v6())
+            protocol_str = "ICMPv6";
+        else
+            protocol_str = "unknown protocol!";
+
         GlobalLogger.info() << "Creating IcmpPacketDistributor for interface "
-                            << network_interface << std::endl;
+                            << network_interface << " and protocol "
+                            << protocol_str << std::endl;
         IcmpPacketDistributorItem new_instance( new IcmpPacketDistributor(
                     protocol, network_interface, io_serv ) );
         Instances[identifier] = new_instance;
index c93c79a..71ef23d 100644 (file)
@@ -8,6 +8,7 @@ add_executable(test_dns
     ${CMAKE_SOURCE_DIR}/src/host/pinger.cpp
     ${CMAKE_SOURCE_DIR}/src/dns/hostaddress.cpp
     ${CMAKE_SOURCE_DIR}/src/dns/timetolive.cpp
+    ${CMAKE_SOURCE_DIR}/src/dns/dnsipprotocol.cpp
     ${CMAKE_SOURCE_DIR}/src/dns/dnsmaster.cpp
     ${CMAKE_SOURCE_DIR}/src/dns/dnscache.cpp
     ${CMAKE_SOURCE_DIR}/src/dns/resolverbase.cpp
index f70f55b..e381d44 100644 (file)
@@ -3,4 +3,4 @@ configure_file(icmp_echorequest.pcap ${CMAKE_CURRENT_BINARY_DIR}/icmp_echoreques
 configure_file(icmp_echoreply.pcap ${CMAKE_CURRENT_BINARY_DIR}/icmp_echoreply.pcap COPYONLY)
 configure_file(icmp_timeexceeded.pcap ${CMAKE_CURRENT_BINARY_DIR}/icmp_timeexceeded.pcap COPYONLY)
 configure_file(icmp_destinationunreachable.pcap ${CMAKE_CURRENT_BINARY_DIR}/icmp_destinationunreachable.pcap COPYONLY)
-configure_file(dns_cache_example.xml ${CMAKE_CURRENT_BINARY_DIR}/dns_cache_example.xml COPYONLY)
+configure_file(dns_cache_compatibility_test.xml ${CMAKE_CURRENT_BINARY_DIR}/dns_cache_compatibility_test.xml COPYONLY)
diff --git a/test/data/dns_cache_compatibility_test.xml b/test/data/dns_cache_compatibility_test.xml
new file mode 100644 (file)
index 0000000..6a1e045
--- /dev/null
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<!DOCTYPE boost_serialization>
+<boost_serialization signature="serialization::archive" version="7">
+<IpCache class_id="0" tracking_level="0" version="0">
+       <count>3</count>
+       <item_version>0</item_version>
+       <item class_id="1" tracking_level="0" version="0">
+               <first class_id="2" tracking_level="0" version="0">
+                       <first>abc.xyz</first>
+                       <second>1</second>
+               </first>
+               <second class_id="3" tracking_level="0" version="0">
+                       <count>1</count>
+                       <item_version>0</item_version>
+                       <item class_id="4" tracking_level="0" version="0">
+                               <ip_str>11.22.33.44</ip_str>
+                               <Ttl class_id="5" tracking_level="0" version="0">
+                                       <Ttl>567</Ttl>
+                                       <ttl_creation_time>20150522T072136.957424</ttl_creation_time>
+                               </Ttl>
+                       </item>
+               </second>
+       </item>
+       <item>
+               <first>
+                       <first>cname1.xyz</first>
+                       <second>1</second>
+               </first>
+               <second>
+                       <count>0</count>
+                       <item_version>0</item_version>
+               </second>
+       </item>
+       <item>
+               <first>
+                       <first>cname1.xyz</first>
+                       <second>28</second>
+               </first>
+               <second>
+                       <count>0</count>
+                       <item_version>0</item_version>
+               </second>
+       </item>
+</IpCache>
+<CnameCache class_id="6" tracking_level="0" version="0">
+       <count>2</count>
+       <item_version>0</item_version>
+       <item class_id="7" tracking_level="0" version="0">
+               <first>abc.xyz</first>
+               <second class_id="8" tracking_level="0" version="0">
+                       <Host></Host>
+                       <Ttl>
+                               <Ttl>0</Ttl>
+                               <ttl_creation_time>20150522T072136.957426</ttl_creation_time>
+                       </Ttl>
+               </second>
+       </item>
+       <item>
+               <first>cname1.xyz</first>
+               <second>
+                       <Host>abc.xyz</Host>
+                       <Ttl>
+                               <Ttl>27</Ttl>
+                               <ttl_creation_time>20150522T072136.957467</ttl_creation_time>
+                       </Ttl>
+               </second>
+       </item>
+</CnameCache>
+</boost_serialization>
+
diff --git a/test/data/dns_cache_example.xml b/test/data/dns_cache_example.xml
deleted file mode 100644 (file)
index e3f61aa..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
-<!DOCTYPE boost_serialization>
-<boost_serialization signature="serialization::archive" version="7">
-<IpCache class_id="0" tracking_level="0" version="0">
-       <count>4</count>
-       <item_version>0</item_version>
-       <item class_id="1" tracking_level="0" version="0">
-               <first>abc.xyz</first>
-               <second class_id="2" tracking_level="0" version="0">
-                       <count>1</count>
-                       <item_version>0</item_version>
-                       <item class_id="3" tracking_level="0" version="0">
-                               <ip_str>11.22.33.44</ip_str>
-                               <Ttl class_id="4" tracking_level="0" version="0">
-                                       <Ttl>567</Ttl>
-                                       <ttl_creation_time>20150429T140512.609565</ttl_creation_time>
-                               </Ttl>
-                       </item>
-               </second>
-       </item>
-       <item>
-               <first>cname1.xyz</first>
-               <second>
-                       <count>0</count>
-                       <item_version>0</item_version>
-               </second>
-       </item>
-       <item>
-               <first>cname2.xyz</first>
-               <second>
-                       <count>0</count>
-                       <item_version>0</item_version>
-               </second>
-       </item>
-       <item>
-               <first>cname3.xyz</first>
-               <second>
-                       <count>0</count>
-                       <item_version>0</item_version>
-               </second>
-       </item>
-</IpCache>
-<CnameCache class_id="5" tracking_level="0" version="0">
-       <count>4</count>
-       <item_version>0</item_version>
-       <item class_id="6" tracking_level="0" version="0">
-               <first>abc.xyz</first>
-               <second class_id="7" tracking_level="0" version="0">
-                       <Host></Host>
-                       <Ttl>
-                               <Ttl>0</Ttl>
-                               <ttl_creation_time>20150429T131654.312043</ttl_creation_time>
-                       </Ttl>
-               </second>
-       </item>
-       <item>
-               <first>cname1.xyz</first>
-               <second>
-                       <Host>abc.xyz</Host>
-                       <Ttl>
-                               <Ttl>27</Ttl>
-                               <ttl_creation_time>20150429T140512.609555</ttl_creation_time>
-                       </Ttl>
-               </second>
-       </item>
-       <item>
-               <first>cname2.xyz</first>
-               <second>
-                       <Host>cname1.xyz</Host>
-                       <Ttl>
-                               <Ttl>207</Ttl>
-                               <ttl_creation_time>20150429T140512.609545</ttl_creation_time>
-                       </Ttl>
-               </second>
-       </item>
-       <item>
-               <first>cname3.xyz</first>
-               <second>
-                       <Host>cname2.xyz</Host>
-                       <Ttl>
-                               <Ttl>87</Ttl>
-                               <ttl_creation_time>20150429T140512.609533</ttl_creation_time>
-                       </Ttl>
-               </second>
-       </item>
-</CnameCache>
-</boost_serialization>
-
index 11e7e9d..7938aa3 100644 (file)
@@ -29,9 +29,11 @@ on this file might be covered by the GNU General Public License.
 #include <boost/bind.hpp>
 
 #include <logfunc.hpp>
+#include <filefunc.hxx>
 
 #include "host/pingprotocol.h"
 #include "dns/hostaddress.h"
+#include "dns/dnsipprotocol.h"
 #include "dns/dnsmaster.h"
 #include "dns/dnscache.h"
 #include "dns/resolverbase.h"
@@ -112,7 +114,7 @@ struct GlobalFixture
             HostAddress ip(address::from_string("192.168.42.1"), 61);
             HostAddressVec ips;
             ips.push_back(ip);
-            Cache->update("host1.test", ips);
+            Cache->update("host1.test", DNS_IPv4, ips);
         }
 
         {
@@ -121,7 +123,7 @@ struct GlobalFixture
             HostAddressVec ips;
             ips.push_back(ip1);
             ips.push_back(ip2);
-            Cache->update("host2_3.test", ips);
+            Cache->update("host2_3.test", DNS_IPv4, ips);
         }
 
         {
@@ -145,7 +147,7 @@ struct GlobalFixture
                                         resolved_ip_ttl_threshold ) );
             ips.push_back( HostAddress( address::from_string("192.168.42.7"),
                                         resolved_ip_ttl_threshold+1 ) );
-            Cache->update("host_outdated.test", ips);
+            Cache->update("host_outdated.test", DNS_IPv4, ips);
 
             Cache->update( "cname_outdated.test",
                       Cname("host_outdated.test", resolved_ip_ttl_threshold) );
@@ -158,7 +160,7 @@ struct GlobalFixture
             HostAddressVec ips;
             ips.push_back( HostAddress( address::from_string("192.128.42.8"),
                                         1 ) );
-            Cache->update("host_ttl_below_thresh.test", ips);
+            Cache->update("host_ttl_below_thresh.test", DNS_IPv4, ips);
 
             Cache->update( "cname_ttl_below_thresh.test",
                       Cname("host_ttl_below_thresh.test", 2) );
@@ -171,6 +173,18 @@ struct GlobalFixture
             Cache->update( "cname_loop3.test", Cname("cname_loop1.test", 60) );
         }
 
+        {   // create IPv4 and IPv6 for same host
+            HostAddressVec ips;
+            ips.push_back( HostAddress( address::from_string("192.168.42.8"),
+                                        432 ) );
+            Cache->update("host_v4_and_v6.test", DNS_IPv4, ips);
+            ips.clear();
+            ips.push_back( HostAddress(
+                        address::from_string("2a00:1450:4001:808::1004"),
+                        543 ) );
+            Cache->update("host_v4_and_v6.test", DNS_IPv6, ips);
+        }
+
         BOOST_TEST_MESSAGE( "Done filling cache." );
     }
 
@@ -231,7 +245,7 @@ BOOST_FIXTURE_TEST_SUITE( TestDnsCache, TestFixture )
 
 BOOST_AUTO_TEST_CASE( cache_retrieve_ip1 )
 {
-    HostAddressVec ips = Cache->get_ips("host1.test");
+    HostAddressVec ips = Cache->get_ips("host1.test", DNS_IPv4);
     BOOST_REQUIRE_EQUAL( ips.size(), 1 );
     HostAddress ip = ips.front();
     BOOST_CHECK( ip.is_valid() );
@@ -242,7 +256,7 @@ BOOST_AUTO_TEST_CASE( cache_retrieve_ip1 )
 
 BOOST_AUTO_TEST_CASE( cache_retrieve_ip2 )
 {
-    HostAddressVec ips = Cache->get_ips("host2_3.test");
+    HostAddressVec ips = Cache->get_ips("host2_3.test", DNS_IPv4);
     BOOST_CHECK_EQUAL( ips.size(), 2 );
     HostAddress ip = ips[0];
     BOOST_CHECK( ip.is_valid() );
@@ -256,7 +270,7 @@ BOOST_AUTO_TEST_CASE( cache_retrieve_ip2 )
 
 BOOST_AUTO_TEST_CASE( cache_retrieve_cname )
 {
-    HostAddressVec ips = Cache->get_ips("cname.test");
+    HostAddressVec ips = Cache->get_ips("cname.test", DNS_IPv4);
     BOOST_CHECK( ips.empty() );
 
     Cname cname = Cache->get_cname("cname.test");
@@ -267,7 +281,7 @@ BOOST_AUTO_TEST_CASE( cache_retrieve_cname )
 BOOST_AUTO_TEST_CASE( cache_retrieve_recursive1 )
 {
     // should get IP from host1 but ttl from cname since is smaller
-    HostAddressVec ips = Cache->get_ips_recursive("cname.test");
+    HostAddressVec ips = Cache->get_ips_recursive("cname.test", DNS_IPv4);
     BOOST_REQUIRE_EQUAL( ips.size(), 1 );
     HostAddress ip = ips.front();
     BOOST_CHECK( ip.is_valid() );
@@ -278,7 +292,7 @@ BOOST_AUTO_TEST_CASE( cache_retrieve_recursive1 )
 BOOST_AUTO_TEST_CASE( cache_retrieve_recursive2 )
 {
     // should get IP from host1 but ttl from cname2 since is smaller
-    HostAddressVec ips = Cache->get_ips_recursive("cname3.test");
+    HostAddressVec ips = Cache->get_ips_recursive("cname3.test", DNS_IPv4);
     BOOST_REQUIRE_EQUAL( ips.size(), 1 );
     HostAddress ip = ips.front();
     BOOST_CHECK( ip.is_valid() );
@@ -303,12 +317,13 @@ void cname_skip_test(const uint32_t ttl1, const uint32_t ttl2,
         HostAddressVec ips;
         ips.push_back( HostAddress( address::from_string("192.168.42.100"),
                                     ttl4 ) );
-        cache->update("skip_chain_fourth.test", ips);
+        cache->update("skip_chain_fourth.test", DNS_IPv4, ips);
     }
 
     // normal recursive call should give nothing since one cname is outdated
     bool check_up_to_date = true;
     HostAddressVec ips = cache->get_ips_recursive("skip_chain_first.test",
+                                                  DNS_IPv4,
                                                   check_up_to_date);
     bool one_is_out_of_date = (ttl1 < 5) || (ttl2 < 5)
                            || (ttl3 < 5) || (ttl4 < 5);
@@ -347,59 +362,118 @@ BOOST_AUTO_TEST_CASE( cache_skip_tests )
     BOOST_CHECK_EQUAL( Cache->get_first_outdated_cname("host1.test", 5), "" );
 }
 
-BOOST_AUTO_TEST_CASE( cache_load_test )
+
+void create_cache(const std::string &file_name, IoServiceItem io_serv)
 {
-    std::stringstream file_name;
-    file_name << DATA_DIR_STRING << "/" << "dns_cache_example.xml";
-    BOOST_TEST_MESSAGE( "loading cache from file " << file_name.str() );
-    DnsCache loaded_cache( IoService,
-                           file_name.str(),
+    BOOST_TEST_MESSAGE( "creating cache for file " << file_name );
+    if ( I2n::file_exists(file_name) )
+        BOOST_CHECK( I2n::unlink(file_name) );   // try to remove
+    DnsCache save_cache( io_serv, file_name, min_time_between_resolves );
+
+    HostAddressVec ips;
+    ips.push_back( HostAddress(address::from_string("11.22.33.44"), 567) );
+    save_cache.update("abc.xyz", DNS_IPv4, ips);
+
+    save_cache.update("cname1.xyz", Cname("abc.xyz", 27));
+
+    // is saved when destructed
+}
+
+
+void test_cache(const std::string &file_name, IoServiceItem io_serv)
+{
+    BOOST_TEST_MESSAGE( "loading cache from file " << file_name );
+    DnsCache loaded_cache( io_serv,
+                           file_name,
                            min_time_between_resolves );
-    HostAddressVec ips = loaded_cache.get_ips("abc.xyz");
-    BOOST_REQUIRE_EQUAL( ips.size(), 1 );
-    HostAddress ip = ips.front();
-    BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "11.22.33.44" );
-    BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 567 );
-    BOOST_CHECK_EQUAL( ip.get_ttl().get_updated_value(), 0 );
+    HostAddressVec ips = loaded_cache.get_ips("abc.xyz", DNS_IPv4);
+    BOOST_CHECK_EQUAL( ips.size(), 1 );
+    if (ips.size() == 1)
+    {
+        HostAddress ip = ips.front();
+        BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "11.22.33.44" );
+        BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 567 );
+        //BOOST_CHECK_EQUAL( ip.get_ttl().get_updated_value(), 0 );
+    }
 
     Cname cname = loaded_cache.get_cname("cname1.xyz");
     BOOST_CHECK_EQUAL( cname.Host, "abc.xyz" );
     BOOST_CHECK_EQUAL( cname.Ttl.get_value(), 27 );
-    BOOST_CHECK_EQUAL( cname.Ttl.get_updated_value(), 0 );
+    //BOOST_CHECK_EQUAL( cname.Ttl.get_updated_value(), 0 );
 
     // not testing Ttl set time since is private
 }
 
+
+BOOST_AUTO_TEST_CASE( cache_save_and_load_test )
+{
+    std::stringstream file_name_temp;
+    file_name_temp << DATA_DIR_STRING << "/" << "dns_cache_save_load_test.xml";
+    std::string file_name = file_name_temp.str();
+
+    // create and save
+    create_cache( file_name, IoService );
+
+    //  now load and test
+    test_cache( file_name, IoService );
+
+}
+
+BOOST_AUTO_TEST_CASE( cache_load_compatibility_test )
+{
+    std::stringstream file_name;
+    file_name << DATA_DIR_STRING << "/" << "dns_cache_compatibility_test.xml";
+    test_cache( file_name.str(), IoService );
+
+    // If this test fails because the cache structure was changed, 
+    // you can overwrite the dns_cache_compatibility_test.xml by uncommenting
+    // the following code line.
+    //create_cache( file_name.str(), IoService );
+    //
+    // Run test again with arg --log_level=MESSAGE and look out for message
+    //   "create cache for file [...]dns_cache_compatibility_test.xml"
+    // You should then copy the dns_cache_compatibility_test.xml to test/data
+    // in git and commit together with the new cache structure code
+}
+
 BOOST_AUTO_TEST_CASE( cache_outdated_test )
 {
     bool check_up_to_date = false;
-    HostAddressVec ips = Cache->get_ips("host_outdated.test", check_up_to_date);
+    HostAddressVec ips = Cache->get_ips("host_outdated.test", DNS_IPv4,
+                                                              check_up_to_date);
     BOOST_CHECK_EQUAL( ips.size(), 4 );
-    ips = Cache->get_ips_recursive("host_outdated.test", check_up_to_date);
+    ips = Cache->get_ips_recursive("host_outdated.test", DNS_IPv4,
+                                                         check_up_to_date);
     BOOST_CHECK_EQUAL( ips.size(), 4 );
     Cname cname = Cache->get_cname("cname_outdated.test", check_up_to_date);
     BOOST_CHECK( !cname.Host.empty() );
-    ips = Cache->get_ips_recursive("cname_outdated.test", check_up_to_date);
+    ips = Cache->get_ips_recursive("cname_outdated.test", DNS_IPv4,
+                                                          check_up_to_date);
     BOOST_CHECK_EQUAL( ips.size(), 4 );
-    ips = Cache->get_ips_recursive("cname_up_to_date.test", check_up_to_date);
+    ips = Cache->get_ips_recursive("cname_up_to_date.test", DNS_IPv4,
+                                                            check_up_to_date);
     BOOST_CHECK_EQUAL( ips.size(), 4 );
 
     check_up_to_date = true;
-    ips = Cache->get_ips( "host_outdated.test", check_up_to_date );
+    ips = Cache->get_ips( "host_outdated.test", DNS_IPv4, check_up_to_date );
     BOOST_CHECK_EQUAL( ips.size(), 1 );
-    ips = Cache->get_ips_recursive("host_outdated.test", check_up_to_date);
+    ips = Cache->get_ips_recursive("host_outdated.test", DNS_IPv4,
+                                                         check_up_to_date);
     BOOST_CHECK_EQUAL( ips.size(), 1 );
     cname = Cache->get_cname("cname_outdated.test", check_up_to_date);
     BOOST_CHECK( cname.Host.empty() );
-    ips = Cache->get_ips_recursive("cname_outdated.test", check_up_to_date);
+    ips = Cache->get_ips_recursive("cname_outdated.test", DNS_IPv4,
+                                                          check_up_to_date);
     BOOST_CHECK_EQUAL( ips.size(), 0 );
-    ips = Cache->get_ips_recursive("cname_up_to_date.test", check_up_to_date);
+    ips = Cache->get_ips_recursive("cname_up_to_date.test", DNS_IPv4,
+                                                            check_up_to_date);
     BOOST_CHECK_EQUAL( ips.size(), 1 );
 }
 
 BOOST_AUTO_TEST_CASE( cache_ttl_below_thresh_test )
 {
-    HostAddressVec ips = Cache->get_ips("host_ttl_below_thresh.test", false);
+    HostAddressVec ips = Cache->get_ips("host_ttl_below_thresh.test", DNS_IPv4,
+                                                                      false);
     BOOST_REQUIRE_EQUAL( ips.size(), 1 );
     HostAddress ip = ips.front();
     BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), min_time_between_resolves );
@@ -410,9 +484,30 @@ BOOST_AUTO_TEST_CASE( cache_ttl_below_thresh_test )
 
 BOOST_AUTO_TEST_CASE( cache_retrieve_loop )
 {
-    BOOST_CHECK_EQUAL( Cache->get_ips_recursive("cname_loop1.test").size(), 0 );
-    BOOST_CHECK_EQUAL( Cache->get_ips_recursive("cname_loop2.test").size(), 0 );
-    BOOST_CHECK_EQUAL( Cache->get_ips_recursive("cname_loop3.test").size(), 0 );
+    BOOST_CHECK_EQUAL(
+            Cache->get_ips_recursive("cname_loop1.test", DNS_IPv4).size(), 0 );
+    BOOST_CHECK_EQUAL(
+            Cache->get_ips_recursive("cname_loop2.test", DNS_IPv4).size(), 0 );
+    BOOST_CHECK_EQUAL(
+            Cache->get_ips_recursive("cname_loop3.test", DNS_IPv4).size(), 0 );
+}
+
+
+BOOST_AUTO_TEST_CASE( cache_IPv6 )
+{
+    HostAddressVec ips = Cache->get_ips("host_v4_and_v6.test", DNS_IPv4);
+    BOOST_REQUIRE_EQUAL( ips.size(), 1 );
+    HostAddress ip = ips.front();
+    BOOST_CHECK( ip.is_valid() );
+    BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "192.168.42.8" );
+    BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 432 );
+
+    ips = Cache->get_ips("host_v4_and_v6.test", DNS_IPv6);
+    BOOST_REQUIRE_EQUAL( ips.size(), 1 );
+    ip = ips.front();
+    BOOST_CHECK( ip.is_valid() );
+    BOOST_CHECK_EQUAL( ip.get_ip().to_string(), "2a00:1450:4001:808::1004" );
+    BOOST_CHECK_EQUAL( ip.get_ttl().get_value(), 543 );
 }