From: Christian Herdtweck Date: Fri, 19 Jun 2015 12:25:54 +0000 (+0200) Subject: secured DnsCache against time warp-related errors X-Git-Url: http://developer.intra2net.com/git/?p=pingcheck;a=commitdiff_plain;h=77319ba894173774464b5d7633d29d6e527d4d79 secured DnsCache against time warp-related errors --- diff --git a/src/dns/dnscache.cpp b/src/dns/dnscache.cpp index a15947d..a0c2a1a 100644 --- a/src/dns/dnscache.cpp +++ b/src/dns/dnscache.cpp @@ -28,7 +28,6 @@ #include // I2n::file_exists #include #include -#include #include #include #include @@ -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 // ----------------------------------------------------------------------------- diff --git a/src/dns/dnscache.h b/src/dns/dnscache.h index 9dc0bc7..b7862a9 100644 --- a/src/dns/dnscache.h +++ b/src/dns/dnscache.h @@ -30,6 +30,7 @@ #include #include #include +#include #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); };