2 The software in this package is distributed under the GNU General
3 Public License version 2 (with a special exception described below).
5 A copy of GNU General Public License (GPL) is included in this distribution,
6 in the file COPYING.GPL.
8 As a special exception, if other files instantiate templates or use macros
9 or inline functions from this file, or you compile this file and link it
10 with other works to produce a work based on this file, this file
11 does not by itself cause the resulting work to be covered
12 by the GNU General Public License.
14 However the source code for this file must still be made available
15 in accordance with section (3) of the GNU General Public License.
17 This exception does not invalidate any other reasons why a work based
18 on this file might be covered by the GNU General Public License.
20 Christian Herdtweck, Intra2net AG 2015
23 #include "dns/dnscache.h"
26 #include <logfunc.hpp>
27 #include <filefunc.hxx> // I2n::file_exists
28 #include <boost/foreach.hpp>
29 #include <boost/bind.hpp>
30 #include <boost/date_time/posix_time/posix_time.hpp>
31 #include <boost/asio/placeholders.hpp>
32 #include <boost/serialization/serialization.hpp>
33 #include <boost/serialization/map.hpp>
34 #include <boost/serialization/string.hpp>
35 #include <boost/serialization/vector.hpp>
36 #include <boost/archive/xml_oarchive.hpp>
37 #include <boost/archive/xml_iarchive.hpp>
40 using boost::posix_time::seconds;
41 using I2n::Logger::GlobalLogger;
45 int SaveTimerSeconds = 60;
50 DnsCache::DnsCache(const IoServiceItem &io_serv,
51 const std::string &cache_file)
54 , SaveTimer( *io_serv )
55 , CacheFile( cache_file )
58 // load cache from file
59 load_from_cachefile();
62 (void) SaveTimer.expires_from_now( seconds( Config::SaveTimerSeconds ) );
63 SaveTimer.async_wait( bind( &DnsCache::schedule_save, this,
64 boost::asio::placeholders::error ) );
70 GlobalLogger.info() << "Dns Cache is being destructed";
72 // save one last time without re-scheduling the next save
80 void DnsCache::schedule_save(const boost::system::error_code &error)
82 // just in case: ensure SaveTimer is cancelled
83 SaveTimer.cancel(); // (will do nothing if already expired/cancelled)
85 if ( error == boost::asio::error::operation_aborted ) // cancelled
87 GlobalLogger.error() << "DnsCache: SaveTimer was cancelled "
88 << "--> no save and no re-schedule of saving!";
93 GlobalLogger.error() << "DnsCache: Received error " << error
94 << " in schedule_save "
95 << "--> no save now but re-schedule saving";
100 // schedule next save
101 (void) SaveTimer.expires_from_now( seconds( Config::SaveTimerSeconds ) );
102 SaveTimer.async_wait( bind( &DnsCache::schedule_save, this,
103 boost::asio::placeholders::error ) );
106 void DnsCache::save_to_cachefile()
110 GlobalLogger.info() << "DnsCache: skip saving because has not changed";
113 else if (CacheFile.empty())
115 GlobalLogger.warning()
116 << "DnsCache: skip saving because file name empty!";
122 std::ofstream ofs( CacheFile.c_str() );
123 boost::archive::xml_oarchive oa(ofs);
124 oa << boost::serialization::make_nvp("IpCache", IpCache);
125 oa << boost::serialization::make_nvp("CnameCache", CnameCache);
126 GlobalLogger.info() << "DnsCache: saved to cache file " << CacheFile;
130 catch (std::exception &exc)
132 GlobalLogger.warning() << "Saving failed: " << exc.what();
137 void DnsCache::load_from_cachefile()
139 if (CacheFile.empty())
141 GlobalLogger.warning()
142 << "DnsCache: cannot load because cache file name is empty!";
145 else if ( !I2n::file_exists(CacheFile) )
147 GlobalLogger.warning() << "DnsCache: cannot load because cache file "
148 << CacheFile << " does not exist!";
153 HostAddressVec cache;
155 std::ifstream ifs( CacheFile.c_str() );
156 boost::archive::xml_iarchive ia(ifs);
158 ia >> boost::serialization::make_nvp("IpCache", cache);
159 ia >> boost::serialization::make_nvp("CnameCache", cache);
160 GlobalLogger.info() << "DnsCache: loaded from file " << CacheFile;
162 catch (boost::archive::archive_exception &exc)
164 GlobalLogger.warning() << "DnsCache: archive exception loading from "
165 << CacheFile << ": " << exc.what();
167 catch (std::exception &exc)
169 GlobalLogger.warning() << "DnsCache: exception while loading from "
170 << CacheFile << ": " << exc.what();
174 void DnsCache::update(const std::string &hostname,
175 const HostAddressVec &new_data)
177 GlobalLogger.info() << "DnsCache: update IPs for " << hostname
178 << " to " << new_data.size() << "-list";
179 IpCache[hostname] = new_data;
184 void DnsCache::update(const std::string &hostname,
185 const std::string &cname)
187 GlobalLogger.info() << "DnsCache: update CNAME for " << hostname
189 CnameCache[hostname] = cname;
194 void DnsCache::update_ttl(const std::string &hostname,
195 const uint32_t new_ttl)
197 GlobalLogger.info() << "DnsCache: ensure TTL for IPs for " << hostname
198 << " is below " << new_ttl << "s";
199 HostAddressVec ips = IpCache[hostname];
200 TimeToLive current_ttl;
201 BOOST_FOREACH( HostAddress &addr, ips )
203 current_ttl = addr.get_ttl();
204 if (current_ttl.get_value() > new_ttl)
206 current_ttl.set_value(new_ttl);
207 addr.set_ttl(current_ttl);
211 IpCache[hostname] = ips;
215 HostAddressVec& DnsCache::get_ips(const std::string &hostname)
217 GlobalLogger.info() << "DnsCache: request IPs for " << hostname
218 << " --> " << IpCache[hostname].size() << "-list";
219 return IpCache[hostname];
222 std::string& DnsCache::get_cname(const std::string &hostname)
224 GlobalLogger.info() << "DnsCache: request CNAME for " << hostname
225 << " --> \"" << CnameCache[hostname] << "\"";
226 return CnameCache[hostname];
229 HostAddressVec& DnsCache::get_ips_recursive(const std::string &hostname)
231 std::string current_host = hostname;
232 HostAddressVec& result = get_ips(current_host);
233 while ( result.empty() )
235 current_host = get_cname(current_host);
236 if (current_host.empty())
239 result = get_ips(current_host);
244 // (created using vim -- the world's best text editor)