secured DnsCache against time warp-related errors
authorChristian Herdtweck <christian.herdtweck@intra2net.com>
Fri, 19 Jun 2015 12:25:54 +0000 (14:25 +0200)
committerChristian Herdtweck <christian.herdtweck@intra2net.com>
Fri, 19 Jun 2015 12:25:54 +0000 (14:25 +0200)
src/dns/dnscache.cpp
src/dns/dnscache.h

index a15947d..a0c2a1a 100644 (file)
@@ -28,7 +28,6 @@
 #include <filefunc.hxx>   // I2n::file_exists
 #include <boost/foreach.hpp>
 #include <boost/bind.hpp>
-#include <boost/date_time/posix_time/posix_time.hpp>
 #include <boost/asio/placeholders.hpp>
 #include <boost/serialization/serialization.hpp>
 #include <boost/serialization/map.hpp>
@@ -46,7 +45,8 @@ using I2n::Logger::GlobalLogger;
 
 namespace Config
 {
-    int SaveTimerSeconds = 60;
+    const int SAVE_TIMER_SECONDS = 60;
+    const int CACHE_TIME_WARP_THRESH_HOURS = 24;
 }
 
 // -----------------------------------------------------------------------------
@@ -89,7 +89,7 @@ DnsCache::DnsCache(const IoServiceItem &io_serv,
     load_from_cachefile();
 
     // schedule next save
-    (void) SaveTimer.expires_from_now( seconds( Config::SaveTimerSeconds ) );
+    (void) SaveTimer.expires_from_now( seconds( Config::SAVE_TIMER_SECONDS ) );
     SaveTimer.async_wait( bind( &DnsCache::schedule_save, this,
                                 boost::asio::placeholders::error ) );
 }
@@ -129,7 +129,7 @@ void DnsCache::schedule_save(const boost::system::error_code &error)
         save_to_cachefile();
 
     // schedule next save
-    (void) SaveTimer.expires_from_now( seconds( Config::SaveTimerSeconds ) );
+    (void) SaveTimer.expires_from_now( seconds( Config::SAVE_TIMER_SECONDS ) );
     SaveTimer.async_wait( bind( &DnsCache::schedule_save, this,
                                 boost::asio::placeholders::error ) );
 }
@@ -147,12 +147,15 @@ void DnsCache::save_to_cachefile()
     {
         try
         {
+            // remember time of save
+            std::string cache_save_time_str = boost::posix_time::to_iso_string(
+                            boost::posix_time::second_clock::universal_time() );
+
             std::ofstream ofs( CacheFile.c_str() );
             boost::archive::xml_oarchive oa(ofs);
-            //oa << boost::serialization::make_nvp("IpCache", IpCache);
-            //oa << boost::serialization::make_nvp("CnameCache", CnameCache);
             oa & BOOST_SERIALIZATION_NVP(IpCache);
             oa & BOOST_SERIALIZATION_NVP(CnameCache);
+            oa & BOOST_SERIALIZATION_NVP(cache_save_time_str);
             GlobalLogger.info() << "DnsCache: saved to cache file "
                                 << CacheFile;
 
@@ -182,9 +185,17 @@ void DnsCache::load_from_cachefile()
             std::ifstream ifs( CacheFile.c_str() );
             boost::archive::xml_iarchive ia(ifs);
 
+            std::string cache_save_time_str;
+
             ia & BOOST_SERIALIZATION_NVP(IpCache);
             ia & BOOST_SERIALIZATION_NVP(CnameCache);
+            ia & BOOST_SERIALIZATION_NVP(cache_save_time_str);
+
+            boost::posix_time::ptime cache_save_time
+                    = boost::posix_time::from_iso_string(cache_save_time_str);
             GlobalLogger.info() << "DnsCache: loaded from file " << CacheFile;
+
+            check_timestamps(cache_save_time);
         }
         catch (boost::archive::archive_exception &exc)
         {
@@ -201,6 +212,48 @@ void DnsCache::load_from_cachefile()
 }
 
 
+/**
+ * @brief check that loaded cache really is from the past
+ *
+ * Added this to avoid trouble in case the system time is changed into the past.
+ * In that cast would have TTLs here in cache that are valid much too long.
+ *
+ * Therefore check SaveCacheTime and if that is in the future, set all TTLs to 0
+ *
+ * @returns true if had to re-set timestamps
+ */
+bool DnsCache::check_timestamps(const boost::posix_time::ptime &cache_save_time)
+{
+    // check if CacheSaveTime is in the future
+    boost::posix_time::ptime now
+             = boost::posix_time::second_clock::universal_time()
+             + boost::posix_time::hours( Config::CACHE_TIME_WARP_THRESH_HOURS );
+    if (now > cache_save_time)
+    {   // Cache was saved in the past -- everything alright
+        return false;
+    }
+
+    GlobalLogger.warning() << "DnsCache: loaded cache from the future (saved "
+                           << cache_save_time << ")! Resetting all TTLs to 0.";
+
+    // reset TTLs in IP cache
+    BOOST_FOREACH( const ip_map_type::value_type key_and_ip, IpCache )
+    {
+        HostAddressVec addr_reset;
+        BOOST_FOREACH( HostAddress address, key_and_ip.second )
+            addr_reset.push_back( HostAddress( address.get_ip(), 0 ) );
+        IpCache[key_and_ip.first] = addr_reset;
+    }
+
+    // reset TTLs in CNAME cache
+    BOOST_FOREACH( const cname_map_type::value_type key_and_cname, CnameCache )
+        CnameCache[key_and_cname.first] = Cname( key_and_cname.second.Host,
+                                                 TimeToLive(0) );
+
+    return true;
+}
+
+
 // -----------------------------------------------------------------------------
 // UPDATE
 // -----------------------------------------------------------------------------
index 9dc0bc7..b7862a9 100644 (file)
@@ -30,6 +30,7 @@
 #include <boost/system/error_code.hpp>
 #include <boost/archive/xml_oarchive.hpp>
 #include <boost/archive/xml_iarchive.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
 
 #include "host/pinger.h"    // for IoserviceItem
 #include "dns/dnsipprotocol.h"
@@ -95,6 +96,7 @@ private:
     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;
+    bool check_timestamps(const boost::posix_time::ptime &cache_save_time);
 
 };