From 82f7c7bb51ca6144c7cdfe2ac55420bd098b3266 Mon Sep 17 00:00:00 2001 From: Christian Herdtweck Date: Fri, 10 Apr 2015 14:27:03 +0200 Subject: [PATCH] moved new dns code from temp dir into proper dns dir --- src/dns/dnscache.cpp | 192 ++++++++++++++++++ src/dns/dnscache.h | 69 +++++++ src/dns/dnsmaster.cpp | 188 +++++++++++++++++ src/dns/dnsmaster.h | 114 +++++++++++ src/dns/dnsresolver.cpp | 423 +++++++++++++++++++++++++++++++++++++++ src/dns/dnsresolver.h | 95 +++++++++ src/dns/ippseudoresolver.h | 78 +++++++ src/dns/resolverbase.cpp | 79 ++++++++ src/dns/resolverbase.h | 87 ++++++++ src/dns_neww/dnscache.cpp | 192 ------------------ src/dns_neww/dnscache.h | 69 ------- src/dns_neww/dnsmaster.cpp | 188 ----------------- src/dns_neww/dnsmaster.h | 114 ----------- src/dns_neww/dnsresolver.cpp | 423 --------------------------------------- src/dns_neww/dnsresolver.h | 95 --------- src/dns_neww/ippseudoresolver.h | 78 ------- src/dns_neww/resolverbase.cpp | 79 -------- src/dns_neww/resolverbase.h | 87 -------- 18 files changed, 1325 insertions(+), 1325 deletions(-) create mode 100644 src/dns/dnscache.cpp create mode 100644 src/dns/dnscache.h create mode 100644 src/dns/dnsmaster.cpp create mode 100644 src/dns/dnsmaster.h create mode 100644 src/dns/dnsresolver.cpp create mode 100644 src/dns/dnsresolver.h create mode 100644 src/dns/ippseudoresolver.h create mode 100644 src/dns/resolverbase.cpp create mode 100644 src/dns/resolverbase.h delete mode 100644 src/dns_neww/dnscache.cpp delete mode 100644 src/dns_neww/dnscache.h delete mode 100644 src/dns_neww/dnsmaster.cpp delete mode 100644 src/dns_neww/dnsmaster.h delete mode 100644 src/dns_neww/dnsresolver.cpp delete mode 100644 src/dns_neww/dnsresolver.h delete mode 100644 src/dns_neww/ippseudoresolver.h delete mode 100644 src/dns_neww/resolverbase.cpp delete mode 100644 src/dns_neww/resolverbase.h diff --git a/src/dns/dnscache.cpp b/src/dns/dnscache.cpp new file mode 100644 index 0000000..6e7fcca --- /dev/null +++ b/src/dns/dnscache.cpp @@ -0,0 +1,192 @@ +/* + 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_neww/dnscache.h" + +#include +#include +#include // I2n::file_exists +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using boost::bind; +using boost::posix_time::seconds; +using I2n::Logger::GlobalLogger; + +namespace Config +{ + int SaveTimerSeconds = 60; +} + + + +DnsCache::DnsCache(const IoServiceItem &io_serv, + const std::string &cache_file) + : DataCache() + , SaveTimer( *io_serv ) + , CacheFile( cache_file ) + , HasChanged( false ) +{ + // load cache from file + load_from_cachefile(); + + // schedule next save + (void) SaveTimer.expires_from_now( seconds( Config::SaveTimerSeconds ) ); + SaveTimer.async_wait( bind( &DnsCache::schedule_save, this, + boost::asio::placeholders::error ) ); +} + + +DnsCache::~DnsCache() +{ + // save one last time without re-scheduling the next save + save_to_cachefile(); + + // cancel save timer + SaveTimer.cancel(); +} + + +void DnsCache::schedule_save(const boost::system::error_code &error) +{ + // just in case: ensure SaveTimer is cancelled + SaveTimer.cancel(); // (will do nothing if already expired/cancelled) + + if ( error == boost::asio::error::operation_aborted ) // cancelled + { + GlobalLogger.error() << "DNS Cache: SaveTimer was cancelled " + << "--> no save and no re-schedule of saving!"; + return; + } + else if (error) + { + GlobalLogger.error() << "DNS Cache: Received error " << error + << " in schedule_save " + << "--> no save now but re-schedule saving"; + } + else + save_to_cachefile(); + + // schedule next save + (void) SaveTimer.expires_from_now( seconds( Config::SaveTimerSeconds ) ); + SaveTimer.async_wait( bind( &DnsCache::schedule_save, this, + boost::asio::placeholders::error ) ); +} + +void DnsCache::save_to_cachefile() +{ + if (!HasChanged) + { + GlobalLogger.info() << "DNS Cache: skip saving because has not changed"; + return; + } + else if (CacheFile.empty()) + { + GlobalLogger.warning() + << "DNS Cache: skip saving because file name empty!"; + return; + } + + try + { + std::ofstream ofs( CacheFile.c_str() ); + boost::archive::xml_oarchive oa(ofs); + oa << boost::serialization::make_nvp("DataCache", DataCache); + GlobalLogger.info() << "DNS Cache: saved to cache file " << CacheFile; + + HasChanged = false; + } + catch (std::exception &exc) + { + GlobalLogger.warning() << "Saving failed: " << exc.what(); + } +} + + +void DnsCache::load_from_cachefile() +{ + if (CacheFile.empty()) + { + GlobalLogger.warning() + << "DNS Cache: cannot load because cache file name is empty!"; + return; + } + else if ( !I2n::file_exists(CacheFile) ) + { + GlobalLogger.warning() << "DNS Cache: cannot load because cache file " + << CacheFile << " does not exist!"; + return; + } + try + { + HostAddressVec cache; + + std::ifstream ifs( CacheFile.c_str() ); + boost::archive::xml_iarchive ia(ifs); + + ia >> boost::serialization::make_nvp("DataCache", cache); + GlobalLogger.info() << "DNS Cache: loaded from file " << CacheFile; + } + catch (boost::archive::archive_exception &exc) + { + GlobalLogger.warning() << "DNS Cache: archive exception loading from " + << CacheFile << ": " << exc.what(); + } + catch (std::exception &exc) + { + GlobalLogger.warning() << "DNS Cache: exception while loading from " + << CacheFile << ": " << exc.what(); + } +} + +/** + * + * in case the cached set is equal to the given new one, the old one is kept + * with TTLs updated + * @returns true if changed cache; returns false if new_data is same as cache + */ +void DnsCache::update(const std::string &hostname, + const HostAddressVec &new_data) +{ + GlobalLogger.info() << "DNS Cache: update IPs for " << hostname + << " to " << new_data.size() << "-list"; + DataCache[hostname] = new_data; + HasChanged = true; +} + + +HostAddressVec& DnsCache::get_data(const std::string &hostname) +{ + GlobalLogger.info() << "DNS Cache: request IPs for " << hostname + << " --> " << DataCache[hostname].size() << "-list"; + return DataCache[hostname]; +} + +// (created using vim -- the world's best text editor) + diff --git a/src/dns/dnscache.h b/src/dns/dnscache.h new file mode 100644 index 0000000..9600901 --- /dev/null +++ b/src/dns/dnscache.h @@ -0,0 +1,69 @@ +/* + 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_CACHE_H +#define DNS_CACHE_H + +#include + +#include +#include +#include + +#include "host/pinger.h" // for IoserviceItem +#include "dns/hostaddress.h" + +typedef std::vector HostAddressVec; +typedef std::map cache_map_type; + +class DnsCache +{ +public: + DnsCache( const IoServiceItem &io_serv, + const std::string &cache_file ); + ~DnsCache(); + + // accessed from ResolverBase subclasses + void update(const std::string &host_name, const HostAddressVec &new_data); + HostAddressVec& get_data(const std::string &hostname); + +// variables +private: + cache_map_type DataCache; + boost::asio::deadline_timer SaveTimer; + std::string CacheFile; + bool HasChanged; + +// functions +private: + void schedule_save(const boost::system::error_code &error); + void save_to_cachefile(); + void load_from_cachefile(); + +}; + +typedef boost::shared_ptr DnsCacheItem; + +#endif + +// (created using vim -- the world's best text editor) + diff --git a/src/dns/dnsmaster.cpp b/src/dns/dnsmaster.cpp new file mode 100644 index 0000000..7553eef --- /dev/null +++ b/src/dns/dnsmaster.cpp @@ -0,0 +1,188 @@ +/* + 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_neww/dnsmaster.h" + +#include +#include +#include + +#include "dns_neww/ippseudoresolver.h" +#include "dns_neww/dnsresolver.h" + +using boost::bind; +using I2n::Logger::GlobalLogger; + + +DnsMasterItem DnsMaster::TheOnlyInstance; + +void DnsMaster::create_master(const IoServiceItem &io_serv, + const boost::asio::ip::address &name_server, + const int resolved_ip_ttl_threshold, + const int max_address_resolution_attempts, + const std::string &cache_file) +{ + if (TheOnlyInstance) + { + GlobalLogger.warning() + << "Blocking attempt to create another DnsMaster instance!"; + return; + } + + GlobalLogger.info() << "Creating DNS Cache and Master"; + DnsCacheItem cache( new DnsCache(io_serv, cache_file) ); + TheOnlyInstance.reset( new DnsMaster(io_serv, + name_server, + resolved_ip_ttl_threshold, + max_address_resolution_attempts, + cache) + ); +} + + +DnsMaster::DnsMaster(const IoServiceItem &io_serv, + const boost::asio::ip::address &name_server, + const int resolved_ip_ttl_threshold, + const int max_address_resolution_attempts, + const DnsCacheItem &cache) + : IoService( io_serv ) + , NameServer( name_server ) + , ResolvedIpTtlThreshold( resolved_ip_ttl_threshold ) + , MaxAddressResolutionAttempts( max_address_resolution_attempts ) + , Cache(cache) + , ResolverMap() +{ +} + + +DnsMasterItem& DnsMaster::get_instance() +{ + if ( !TheOnlyInstance ) + GlobalLogger.error() + << "Request to return DnsMaster instance before creating it!"; + return TheOnlyInstance; +} + + + +ResolverItem& DnsMaster::get_resolver_for( const std::string &hostname, + const PingProtocol &ping_protocol ) +{ + // find suitable DnsIpProtocol for ping protocol + DnsIpProtocol protocol = DnsMaster::ping2dns_protocol(ping_protocol); + return get_resolver_for(hostname, protocol); +} + + +ResolverItem& DnsMaster::get_resolver_for( const std::string &hostname, + const DnsIpProtocol &protocol ) +{ + DnsMasterItem master = get_instance(); + + // create key to ResolverMap + resolver_key_type key(hostname, protocol); + if ( master->ResolverMap.count(key) == 0 ) + { // need to create a resolver + + // check if it is an ip address, so can create a simple pseudo resolver + if ( master->is_ip(hostname) ) + { + boost::asio::ip::address ip + = boost::asio::ip::address::from_string(hostname); + if ( (protocol == DNS_IPv4 && !ip.is_v4()) || + (protocol == DNS_IPv6 && !ip.is_v6()) ) + GlobalLogger.warning() << "Asked to create a DNS resolver " + << "for wrong IP protocol: v4 != v6! " + << "We will comply."; + GlobalLogger.info() << "Creating PseudoResolver for IP " << ip; + ResolverItem new_resolver( new IpPseudoResolver(IoService, + hostname, + Cache) ); + master->ResolverMap[key] = new_resolver; + } + else + { + GlobalLogger.info() << "Creating Resolver for host " << hostname; + ResolverItem new_resolver( new DnsResolver(IoService, + hostname, + protocol, + Cache, + NameServer) ); + master->ResolverMap[key] = new_resolver; + } + } + return master->ResolverMap[key]; +} + +/** + * return true if given hostname string actually is an IP + * + * delegates decision to boost::asio::ip::address::from_string + */ +bool DnsMaster::is_ip(const std::string &hostname) const +{ + try + { + boost::asio::ip::address ip = boost::asio::ip::address::from_string( + hostname); + return ip.is_v4() || ip.is_v6(); + } + catch ( const std::exception &ex ) + { + return false; + } +} + + +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() << "Unexpected ping protocol: " + << static_cast(pprot); + return DNS_IPALL; + break; + } +} + +/*boost::asio::ip::address &DnsMaster::get_name_server() const +{ + return NameServer; +}*/ + +int DnsMaster::get_resolved_ip_ttl_threshold() const +{ + return ResolvedIpTtlThreshold; +} + +int DnsMaster::get_max_address_resolution_attempts() const +{ + return MaxAddressResolutionAttempts; +} + +// (created using vim -- the world's best text editor) + diff --git a/src/dns/dnsmaster.h b/src/dns/dnsmaster.h new file mode 100644 index 0000000..c8c5866 --- /dev/null +++ b/src/dns/dnsmaster.h @@ -0,0 +1,114 @@ +/* + 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 + */ + +/** + * Two in one: a DNS resolver factory and a DNS cache + * + * Put these two things into one class because it is easier this way to avoid + * sync problems if e.g. there are 2 resolvers for the same host name + * + * This class is a Singleton. In case there are problems with this approach, + * there is an alternative: + * give every ResolverBase object a DnsMasterItem as variable, that is set + * during construction and call update / get_cached_results on that instance + */ + +#ifndef DNS_MASTER_H +#define DNS_MASTER_H + +#include +#include // pair + +#include +#include +#include + +#include "host/pinger.h" // for IoserviceItem +#include "host/pingprotocol.h" +#include "dns_neww/dnscache.h" +#include "dns_neww/resolverbase.h" + +class DnsMaster; + +typedef boost::shared_ptr DnsMasterItem; + +typedef boost::net::dns::type_t DnsIpProtocol; +DnsIpProtocol DNS_IPv4 = boost::net::dns::type_a; +DnsIpProtocol DNS_IPv6 = boost::net::dns::type_a6; +DnsIpProtocol DNS_IPALL = boost::net::dns::type_all; + +typedef std::pair resolver_key_type; +typedef std::map resolver_map_type; + + +class DnsMaster : boost::noncopyable +{ +// Resolver factory +public: + ResolverItem& get_resolver_for(const std::string &hostname, + const PingProtocol &ping_protocol); + ResolverItem& get_resolver_for(const std::string &hostname, + const DnsIpProtocol &protocol); + +// implementation of singleton +private: + static DnsMasterItem TheOnlyInstance; + + DnsMaster(const IoServiceItem &io_serv, + const boost::asio::ip::address &name_server, + const int resolved_ip_ttl_threshold, + const int max_address_resolution_attempts, + const DnsCacheItem &cache); +public: + static void create_master(const IoServiceItem &io_serv, + const boost::asio::ip::address &name_server, + const int resolved_ip_ttl_threshold, + const int max_address_resolution_attempts, + const std::string &cache_file); + static DnsMasterItem& get_instance(); + ~DnsMaster(); + +// storage of global variables +public: + //boost::asio::ip::address &get_name_server() const; // currently unused + int get_resolved_ip_ttl_threshold() const; + int get_max_address_resolution_attempts() const; + +// variables +private: + IoServiceItem IoService; + const boost::asio::ip::address NameServer; + const int ResolvedIpTtlThreshold; + const int MaxAddressResolutionAttempts; + DnsCacheItem Cache; + resolver_map_type ResolverMap; + +// internal helper functions +private: + bool is_ip(const std::string &hostname) const; + static DnsIpProtocol ping2dns_protocol(const PingProtocol& pprot); +}; + +#endif + +// (created using vim -- the world's best text editor) + diff --git a/src/dns/dnsresolver.cpp b/src/dns/dnsresolver.cpp new file mode 100644 index 0000000..f1bbb6f --- /dev/null +++ b/src/dns/dnsresolver.cpp @@ -0,0 +1,423 @@ +/* + 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 + + with code copied from boost::net::dns::resolve.hpp + by Andreas Haberstroh (andreas at ibusy dot com) + from https://github.com/softwareace/Boost.DNS + */ + +#include "dns_neww/dnsresolver.h" + +#include +#include +#include +#include +#include + +#include + +using I2n::Logger::GlobalLogger; +using boost::posix_time::seconds; +using boost::posix_time::minutes; + +namespace Config +{ + const int ResolveTimeoutSeconds = 5; + const int PauseBeforeRetrySeconds = 10; + const int StaleDataLongtermMinutes = 15; + const int DNS_PORT = 53; + const int UniqueID = 0xaffe; +} + +DnsResolver::DnsResolver(IoServiceItem &io_serv, + const std::string &hostname, + const DnsIpProtocol &protocol, + const DnsCacheItem cache, + const boost::asio::ip::address &name_server) + : ResolverBase( io_serv, hostname, cache ) + , Socket( *io_serv, ip::udp::endpoint(ip::udp::v4(), 0) ) + , ReceiveBuffer() + , Protocol( protocol ) + , NameServer( name_server, Config::DNS_PORT ) + , ResolveTimeoutTimer( *io_serv ) + , PauseBeforeRetryTimer( *io_serv ) + , StaleDataLongtermTimer( *io_serv ) + , NextIpIndex( 0 ) + , RetryCount( 0 ) + , IsResolving( false ) +{ } + + +//============================================================================== +// ASYNC RESOLVE +//============================================================================== + +/** + * copied here code from boost::net::dns::resolve.hpp, since want async + * operation and that is used only internally, there + */ +void DnsResolver::do_resolve() +{ + // check if resolving already + if (IsResolving) + { + GlobalLogger.info() + << "Call to do_resolve ignored since resolving already"; + return; + } + + // just to be sure: cancel timers + ResolveTimeoutTimer.cancel(); + PauseBeforeRetryTimer.cancel(); + StaleDataLongtermTimer.cancel(); + + // create DNS request + boost::net::dns::message dns_message( ResolverBase::Hostname, + boost::net::dns::type_all ); + dns_message.recursive(false); + dns_message.action(boost::net::dns::message::query); + dns_message.opcode(boost::net::dns::message::squery); + dns_message.id(Config::UniqueID); + boost::net::dns_buffer_t request_buffer; + dns_message.encode(request_buffer); + + // setup receipt of reply + Socket.async_receive_from( + boost::asio::buffer(ReceiveBuffer.get_array()), + NameServer, + boost::bind( &DnsResolver::handle_dns_result, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred) + ); + + // schedule timeout + (void) ResolveTimeoutTimer.expires_from_now( + seconds(Config::ResolveTimeoutSeconds)); + ResolveTimeoutTimer.async_wait( boost::bind( + &DnsResolver::handle_resolve_timeout, + this, boost::asio::placeholders::error) ); + + // send dns request + Socket.send_to( boost::asio::buffer(request_buffer.get_array()), + NameServer ); +} + + +void DnsResolver::handle_dns_result(const boost::system::error_code &error, + const std::size_t bytes_transferred) +{ + if ( error == boost::asio::error::operation_aborted ) // cancelled + { + GlobalLogger.info() << "DNS resolve operation was cancelled"; + bool was_success = false; + finalize_resolve(was_success); + } + else if (error) + { + GlobalLogger.info() << "DNS resolve resulted in error " << error + << " --> treat like unavailable"; + handle_unavailable(); + return; + } + + // next 3(+1) lines copied from boost/net/dns/resolver.hpp: + // clamp the recvBuffer with the number of bytes transferred or decode buffr + ReceiveBuffer.length(bytes_transferred); + boost::net::dns::message result_message; + result_message.decode( ReceiveBuffer ); + + // work with a regular pointer to list of answers since result_message is + // owner of data and that exists until end of function + // Items in answers list are shared_ptr to resource_base_t + boost::net::dns::rr_list_t *answers = result_message.answers(); + if (answers->size() == 0) + handle_unavailable(); + + // loop over answers, remembering ips and cnames + HostAddressVec result_ips; + std::vector result_cnames; + using boost::net::dns::resource_base_t; + BOOST_FOREACH( boost::shared_ptr rr_item, *answers ) + { + GlobalLogger.debug() << std::showbase << std::hex + << static_cast(rr_item->rtype()) << ": "; + uint32_t ttl = rr_item->ttl(); + boost::net::dns::type_t rr_type = rr_item->rtype(); + + if (rr_type == boost::net::dns::type_a) + { // 'A' resource records carry IPv4 addresses + if (Protocol == DNS_IPv6) + { + GlobalLogger.info() << "Ignoring IPv4 address because resolver " + << "was configured to only use IPv6."; + continue; + } + boost::asio::ip::address_v4 ip = + ( dynamic_cast (rr_item.get()) ) + ->address(); + result_ips.push_back( HostAddress(ip, ttl) ); + } + else if (rr_type == boost::net::dns::type_a6) + { // 'AAAA' resource records carry IPv6 addresses + if (Protocol == DNS_IPv4) + { + GlobalLogger.info() << "Ignoring IPv6 address because resolver " + << "was configured to only use IPv4."; + continue; + } + boost::asio::ip::address_v6 ip = + ( dynamic_cast (rr_item.get()) ) + ->address(); + result_ips.push_back( HostAddress(ip, ttl) ); + } + else if (rr_type == boost::net::dns::type_cname) + { // 'CNAME' resource records that carry aliases + std::string cname = + (dynamic_cast(rr_item.get())) + ->canonicalname(); + result_cnames.push_back( cname ); + } + else if (rr_type == boost::net::dns::type_ns) + GlobalLogger.debug() << "NS resource"; + else if (rr_type == boost::net::dns::type_soa) + GlobalLogger.debug() << "SOA resource"; + else if (rr_type == boost::net::dns::type_ptr) + GlobalLogger.debug() << "ptr resource"; + else if (rr_type == boost::net::dns::type_hinfo) + GlobalLogger.debug() << "hinfo resource"; + else if (rr_type == boost::net::dns::type_mx) + GlobalLogger.debug() << "mx resource"; + else if (rr_type == boost::net::dns::type_txt) + GlobalLogger.debug() << "txt resource"; + else if (rr_type == boost::net::dns::type_srv) + GlobalLogger.debug() << "srv resource"; + else if (rr_type == boost::net::dns::type_axfr) + GlobalLogger.debug() << "axfr resource"; + else + GlobalLogger.debug() << "unknown resource type"; + } + + GlobalLogger.info() << "Have " << result_ips.size() << " IPs and " + << result_cnames.size() << " CNAMEs"; + + // We expect either one single CNAME and no IPs or a list of IPs. + // But deal with other cases as well + if (result_ips.empty() && result_cnames.empty()) + handle_unavailable(); // we just got crap, this is a dead end + else if ( !result_ips.empty() && !result_cnames.empty()) + GlobalLogger.warning() << "Have CNAMEs AND IPs --> deal with both!"; + + BOOST_FOREACH( const std::string &cname, result_cnames ) + handle_cname(cname); // will schedule another DNS call + + if ( !result_ips.empty() ) + handle_ips(result_ips); +} + + +void DnsResolver::handle_ips(const HostAddressVec &ips) +{ + // save in cache + ResolverBase::update_cache( ips ); + + // clean up + bool was_success = true; + finalize_resolve(was_success); +} + + +void DnsResolver::handle_unavailable() +{ + // schedule new attempt in quite a while + StaleDataLongtermTimer.expires_from_now( + minutes(Config::StaleDataLongtermMinutes)); + StaleDataLongtermTimer.async_wait( + boost::bind( &DnsResolver::wait_timer_timeout_handler, + this, boost::asio::placeholders::error + ) + ); + + // for now, admit failure + bool was_success = false; + finalize_resolve(was_success); +} + +void DnsResolver::handle_cname(const std::string &canonical_name) +{ + // get resolver for canonical name + ResolverItem resolver = DnsMaster::get_instance() + ->get_resolver_for(canonical_name, Protocol); + callback_type callback = boost::bind( &DnsResolver::cname_resolve_callback, + this, canonical_name, _1, _2 ); + resolver->async_resolve( callback ); + + stop_trying(); +} + + +void DnsResolver::cname_resolve_callback(const std::string &canonical_name, + const bool was_success, + const int cname_count) +{ + if (was_success) + // tell cache to return cname's ips if queried for our hostname + ResolverBase::update_cache( + ResolverBase::get_cached_results(canonical_name) ); + else + GlobalLogger.info() << "Cname resolution failed"; + + finalize_resolve(was_success, cname_count+1); +} + + +void DnsResolver::finalize_resolve(const bool was_success, + const int cname_count) +{ + // stop timers + if (cname_count > 0) + stop_trying(); + // else was called already from handle_cname + + // schedule callbacks, clearing callback list + ResolverBase::schedule_callbacks(was_success, cname_count); + + // finalize + GlobalLogger.notice() << "Done resolving" + << " with success = " << was_success + << " and cname_count = " << cname_count; + IsResolving = false; +} + +void DnsResolver::stop_trying() +{ + // cancel timers + GlobalLogger.debug() << "Cancelling timers"; + ResolveTimeoutTimer.cancel(); + PauseBeforeRetryTimer.cancel(); + StaleDataLongtermTimer.cancel(); + + // clean up + RetryCount = 0; +} + +void DnsResolver::handle_resolve_timeout(const boost::system::error_code &error) +{ + if ( error == boost::asio::error::operation_aborted ) // cancelled + { + GlobalLogger.warning() << "Resolve timeout timer was cancelled!"; + return; + } + else if (error) + { + GlobalLogger.warning() << "resolve timeout handler received error " + << error; + return; + } + + GlobalLogger.notice() << "DNS resolving timed out"; + + // increment timer + ++RetryCount; + + if ( RetryCount > DnsMaster::get_instance() + ->get_max_address_resolution_attempts() ) + { + handle_unavailable(); + RetryCount = 0; + } + else + { // schedule retry + PauseBeforeRetryTimer.expires_from_now( + seconds(Config::PauseBeforeRetrySeconds)); + PauseBeforeRetryTimer.async_wait( + boost::bind( &DnsResolver::wait_timer_timeout_handler, + this, boost::asio::placeholders::error) ); + } +} + +void DnsResolver::wait_timer_timeout_handler( + const boost::system::error_code &error) +{ + if ( error == boost::asio::error::operation_aborted ) // cancelled + GlobalLogger.warning() << "Resolve timeout timer was cancelled!"; + else if (error) + GlobalLogger.warning() << "resolve timeout handler received error " + << error; + else + { + GlobalLogger.info() << "Done waiting --> re-try resolve"; + do_resolve(); + } +} + + +//============================================================================== +// RETRIEVAL +//============================================================================== + +HostAddress DnsResolver::get_next_ip() +{ + // get cached data + HostAddressVec cached_data = ResolverBase::get_cached_results(); + + // if no results cached, return default-constructed HostAddress (0.0.0.0) + if ( cached_data.empty() ) + { + HostAddress return_value; + return return_value; + } + + // check validity of index (cache may have changed since last call) + if (NextIpIndex >= cached_data.size()) + NextIpIndex = 0; + + // return next IP + return cached_data[NextIpIndex++]; +} + +bool DnsResolver::have_up_to_date_ip() +{ + // get cached data + HostAddressVec cached_data = ResolverBase::get_cached_results(); + + // get threshold + int resolved_ip_ttl_threshold = DnsMaster::get_instance() + ->get_resolved_ip_ttl_threshold(); + + // loop over addresses + BOOST_FOREACH( const HostAddress &addr, cached_data ) + { + uint32_t ttl = addr.get_ttl().get_updated_value(); + if ( ttl > resolved_ip_ttl_threshold ) + return true; + } + + // if not returned true by now, we have tried all IPs without success + return false; +} + +int DnsResolver::get_resolved_ip_count() +{ + return ResolverBase::get_cached_results().size(); +} + +// (created using vim -- the world's best text editor) + diff --git a/src/dns/dnsresolver.h b/src/dns/dnsresolver.h new file mode 100644 index 0000000..d56df2a --- /dev/null +++ b/src/dns/dnsresolver.h @@ -0,0 +1,95 @@ +/* + 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_RESOLVER_H +#define DNS_RESOLVER_H + +#include "dns_neww/dnsmaster.h" + +#include +#include +#include +#include +#include // dns_buffer_t + +#include "dns_neww/resolverbase.h" +#include "dns_neww/dnsmaster.h" +#include "dns_neww/dnscache.h" + + +class DnsResolver : public ResolverBase +{ +public: + ~DnsResolver(); + +// constructor accessible from friend DnsMaster +public: + friend ResolverItem& DnsMaster::get_resolver_for( + const std::string &hostname, + const DnsIpProtocol &protocol); +private: + DnsResolver(IoServiceItem &io_serv, + const std::string &hostname, + const DnsIpProtocol &protocol, + const DnsCacheItem cache, + const boost::asio::ip::address &name_server); + +// only real public function (called from pingers) +public: + HostAddress get_next_ip(); + bool have_up_to_date_ip(); + int get_resolved_ip_count(); + +// implementation of ResolverBase::async_resolve +protected: + void do_resolve(); + +private: + void handle_resolve_timeout(const boost::system::error_code &error); + void handle_dns_result(const boost::system::error_code &error, + const std::size_t bytes_transferred); + void handle_unavailable(); + void handle_ips(const HostAddressVec &ips); + void handle_cname(const std::string &canonical_name); + void cname_resolve_callback(const std::string &canonical_name, + const bool was_success, + const int cname_count); + void finalize_resolve(const bool success, const int cname_count=0); + void stop_trying(); + void wait_timer_timeout_handler(const boost::system::error_code &error); + +private: + boost::asio::ip::udp::socket Socket; + boost::net::dns_buffer_t ReceiveBuffer; + DnsIpProtocol Protocol; + boost::asio::ip::udp::endpoint NameServer; + boost::asio::deadline_timer ResolveTimeoutTimer; + boost::asio::deadline_timer PauseBeforeRetryTimer; + boost::asio::deadline_timer StaleDataLongtermTimer; + std::size_t NextIpIndex; + int RetryCount; + bool IsResolving; +}; + +#endif +// (created using vim -- the world's best text editor) + diff --git a/src/dns/ippseudoresolver.h b/src/dns/ippseudoresolver.h new file mode 100644 index 0000000..dd7b792 --- /dev/null +++ b/src/dns/ippseudoresolver.h @@ -0,0 +1,78 @@ +/* + 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 IP_PSEUDO_RESOLVER_H +#define IP_PSEUDO_RESOLVER_H + +#include +#include "dns/hostaddress.h" +#include "dns_neww/resolverbase.h" +#include "dns_neww/dnsmaster.h" + +namespace Config +{ + uint32_t DefaultTtl = 60*60*24*356; // 1 year in seconds (approx) +} + +/** @brief Degenerate case of a resolver: hostname is already an IP + * + * created by DnsMaster if given an IP address as hostname + * + * Will do nothing, just remember that IP and return it for every call to + * get_next_ip + * + * Since this is so boring, I did not create an own .cpp for it + */ +class IpPseudoResolver : public ResolverBase +{ +// constructor accessible from friend DnsMaster +public: + friend ResolverItem& DnsMaster::get_resolver_for( + const std::string &hostname, + const DnsIpProtocol &protocol); +private: + IpPseudoResolver(const IoServiceItem io_serv, + const std::string &ip_string, + const DnsCacheItem &cache ) + : ResolverBase( io_serv, ip_string, cache ) + , IpAddress( boost::asio::ip::address::from_string(ip_string), + Config::DefaultTtl ) + {} + +private: + HostAddress IpAddress; + +// only real public function +public: + HostAddress get_next_ip() { return IpAddress; } + bool have_up_to_date_ip() { return true; } + int get_resolved_ip_count(){ return 1; } + +// implementation of ResolverBase::async_resolve +protected: + void do_resolve() + { ResolverBase::schedule_callbacks(true, 0); } +}; +#endif + +// (created using vim -- the world's best text editor) + diff --git a/src/dns/resolverbase.cpp b/src/dns/resolverbase.cpp new file mode 100644 index 0000000..2587e63 --- /dev/null +++ b/src/dns/resolverbase.cpp @@ -0,0 +1,79 @@ +/* + 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_neww/resolverbase.h" +#include "dns_neww/dnsmaster.h" + +#include + +ResolverBase::~ResolverBase() +{ +} + +/** + * callbacks should be of type + * void resolve_callback(const bool was_success, + * const int cname_count) + */ +void ResolverBase::async_resolve(const callback_type &callback) +{ + // remember callback + CallbackList.push(callback); + + // let subclass do the resolving + do_resolve(); +} + +ResolverBase::ResolverBase(const IoServiceItem &io_serv, + const std::string &hostname, + const DnsCacheItem &cache ) + : IoService( io_serv ) + , Hostname( hostname ) + , Cache( cache ) + , CallbackList() +{} + +void ResolverBase::update_cache( const HostAddressVec &new_results ) const +{ Cache->update( Hostname, new_results ); } + +HostAddressVec& ResolverBase::get_cached_results(const std::string host) const +{ + if (host.empty()) + return Cache->get_data( Hostname ); + else + return Cache->get_data( host ); +} + +void ResolverBase::schedule_callbacks(const bool was_success, + const int cname_count) +{ + while ( !CallbackList.empty() ) + { + callback_type callback = CallbackList.front(); + CallbackList.pop(); + IoService->post( boost::bind( callback, + was_success, cname_count ) ); + } +} + +// (created using vim -- the world's best text editor) + diff --git a/src/dns/resolverbase.h b/src/dns/resolverbase.h new file mode 100644 index 0000000..3b2a1ab --- /dev/null +++ b/src/dns/resolverbase.h @@ -0,0 +1,87 @@ +/* + 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 RESOLVER_BASE_H +#define RESOLVER_BASE_H + +#include +#include + +#include +#include "host/pinger.h" +#include "dns/hostaddress.h" +#include "dns_neww/dnscache.h" + +typedef boost::function callback_type; +typedef std::queue callback_list_type; + +/** + * @brief: abstract base class for DnsResolver and IpPseudoResolver + */ +class ResolverBase +{ +public: + virtual HostAddress get_next_ip() = 0; + + virtual ~ResolverBase(); + + /** + * callbacks should be of type + * void resolve_callback(const bool was_success, + * const int cname_count) + */ + void async_resolve(const callback_type &callback); + + virtual bool have_up_to_date_ip() = 0; + virtual int get_resolved_ip_count() = 0; + +protected: + ResolverBase(const IoServiceItem &io_serv, + const std::string &hostname, + const DnsCacheItem &cache ); + +// variables +protected: + IoServiceItem IoService; + std::string Hostname; + DnsCacheItem Cache; + callback_list_type CallbackList; + +// functions for subclasses +protected: + virtual void do_resolve() = 0; + + void update_cache( const HostAddressVec &new_results ) const; + + HostAddressVec& get_cached_results(const std::string host="") const; + + void schedule_callbacks(const bool was_success, + const int cname_count); + +}; + +typedef boost::shared_ptr ResolverItem; + +#endif + +// (created using vim -- the world's best text editor) + diff --git a/src/dns_neww/dnscache.cpp b/src/dns_neww/dnscache.cpp deleted file mode 100644 index 6e7fcca..0000000 --- a/src/dns_neww/dnscache.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* - 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_neww/dnscache.h" - -#include -#include -#include // I2n::file_exists -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using boost::bind; -using boost::posix_time::seconds; -using I2n::Logger::GlobalLogger; - -namespace Config -{ - int SaveTimerSeconds = 60; -} - - - -DnsCache::DnsCache(const IoServiceItem &io_serv, - const std::string &cache_file) - : DataCache() - , SaveTimer( *io_serv ) - , CacheFile( cache_file ) - , HasChanged( false ) -{ - // load cache from file - load_from_cachefile(); - - // schedule next save - (void) SaveTimer.expires_from_now( seconds( Config::SaveTimerSeconds ) ); - SaveTimer.async_wait( bind( &DnsCache::schedule_save, this, - boost::asio::placeholders::error ) ); -} - - -DnsCache::~DnsCache() -{ - // save one last time without re-scheduling the next save - save_to_cachefile(); - - // cancel save timer - SaveTimer.cancel(); -} - - -void DnsCache::schedule_save(const boost::system::error_code &error) -{ - // just in case: ensure SaveTimer is cancelled - SaveTimer.cancel(); // (will do nothing if already expired/cancelled) - - if ( error == boost::asio::error::operation_aborted ) // cancelled - { - GlobalLogger.error() << "DNS Cache: SaveTimer was cancelled " - << "--> no save and no re-schedule of saving!"; - return; - } - else if (error) - { - GlobalLogger.error() << "DNS Cache: Received error " << error - << " in schedule_save " - << "--> no save now but re-schedule saving"; - } - else - save_to_cachefile(); - - // schedule next save - (void) SaveTimer.expires_from_now( seconds( Config::SaveTimerSeconds ) ); - SaveTimer.async_wait( bind( &DnsCache::schedule_save, this, - boost::asio::placeholders::error ) ); -} - -void DnsCache::save_to_cachefile() -{ - if (!HasChanged) - { - GlobalLogger.info() << "DNS Cache: skip saving because has not changed"; - return; - } - else if (CacheFile.empty()) - { - GlobalLogger.warning() - << "DNS Cache: skip saving because file name empty!"; - return; - } - - try - { - std::ofstream ofs( CacheFile.c_str() ); - boost::archive::xml_oarchive oa(ofs); - oa << boost::serialization::make_nvp("DataCache", DataCache); - GlobalLogger.info() << "DNS Cache: saved to cache file " << CacheFile; - - HasChanged = false; - } - catch (std::exception &exc) - { - GlobalLogger.warning() << "Saving failed: " << exc.what(); - } -} - - -void DnsCache::load_from_cachefile() -{ - if (CacheFile.empty()) - { - GlobalLogger.warning() - << "DNS Cache: cannot load because cache file name is empty!"; - return; - } - else if ( !I2n::file_exists(CacheFile) ) - { - GlobalLogger.warning() << "DNS Cache: cannot load because cache file " - << CacheFile << " does not exist!"; - return; - } - try - { - HostAddressVec cache; - - std::ifstream ifs( CacheFile.c_str() ); - boost::archive::xml_iarchive ia(ifs); - - ia >> boost::serialization::make_nvp("DataCache", cache); - GlobalLogger.info() << "DNS Cache: loaded from file " << CacheFile; - } - catch (boost::archive::archive_exception &exc) - { - GlobalLogger.warning() << "DNS Cache: archive exception loading from " - << CacheFile << ": " << exc.what(); - } - catch (std::exception &exc) - { - GlobalLogger.warning() << "DNS Cache: exception while loading from " - << CacheFile << ": " << exc.what(); - } -} - -/** - * - * in case the cached set is equal to the given new one, the old one is kept - * with TTLs updated - * @returns true if changed cache; returns false if new_data is same as cache - */ -void DnsCache::update(const std::string &hostname, - const HostAddressVec &new_data) -{ - GlobalLogger.info() << "DNS Cache: update IPs for " << hostname - << " to " << new_data.size() << "-list"; - DataCache[hostname] = new_data; - HasChanged = true; -} - - -HostAddressVec& DnsCache::get_data(const std::string &hostname) -{ - GlobalLogger.info() << "DNS Cache: request IPs for " << hostname - << " --> " << DataCache[hostname].size() << "-list"; - return DataCache[hostname]; -} - -// (created using vim -- the world's best text editor) - diff --git a/src/dns_neww/dnscache.h b/src/dns_neww/dnscache.h deleted file mode 100644 index 9600901..0000000 --- a/src/dns_neww/dnscache.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - 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_CACHE_H -#define DNS_CACHE_H - -#include - -#include -#include -#include - -#include "host/pinger.h" // for IoserviceItem -#include "dns/hostaddress.h" - -typedef std::vector HostAddressVec; -typedef std::map cache_map_type; - -class DnsCache -{ -public: - DnsCache( const IoServiceItem &io_serv, - const std::string &cache_file ); - ~DnsCache(); - - // accessed from ResolverBase subclasses - void update(const std::string &host_name, const HostAddressVec &new_data); - HostAddressVec& get_data(const std::string &hostname); - -// variables -private: - cache_map_type DataCache; - boost::asio::deadline_timer SaveTimer; - std::string CacheFile; - bool HasChanged; - -// functions -private: - void schedule_save(const boost::system::error_code &error); - void save_to_cachefile(); - void load_from_cachefile(); - -}; - -typedef boost::shared_ptr DnsCacheItem; - -#endif - -// (created using vim -- the world's best text editor) - diff --git a/src/dns_neww/dnsmaster.cpp b/src/dns_neww/dnsmaster.cpp deleted file mode 100644 index 7553eef..0000000 --- a/src/dns_neww/dnsmaster.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/* - 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_neww/dnsmaster.h" - -#include -#include -#include - -#include "dns_neww/ippseudoresolver.h" -#include "dns_neww/dnsresolver.h" - -using boost::bind; -using I2n::Logger::GlobalLogger; - - -DnsMasterItem DnsMaster::TheOnlyInstance; - -void DnsMaster::create_master(const IoServiceItem &io_serv, - const boost::asio::ip::address &name_server, - const int resolved_ip_ttl_threshold, - const int max_address_resolution_attempts, - const std::string &cache_file) -{ - if (TheOnlyInstance) - { - GlobalLogger.warning() - << "Blocking attempt to create another DnsMaster instance!"; - return; - } - - GlobalLogger.info() << "Creating DNS Cache and Master"; - DnsCacheItem cache( new DnsCache(io_serv, cache_file) ); - TheOnlyInstance.reset( new DnsMaster(io_serv, - name_server, - resolved_ip_ttl_threshold, - max_address_resolution_attempts, - cache) - ); -} - - -DnsMaster::DnsMaster(const IoServiceItem &io_serv, - const boost::asio::ip::address &name_server, - const int resolved_ip_ttl_threshold, - const int max_address_resolution_attempts, - const DnsCacheItem &cache) - : IoService( io_serv ) - , NameServer( name_server ) - , ResolvedIpTtlThreshold( resolved_ip_ttl_threshold ) - , MaxAddressResolutionAttempts( max_address_resolution_attempts ) - , Cache(cache) - , ResolverMap() -{ -} - - -DnsMasterItem& DnsMaster::get_instance() -{ - if ( !TheOnlyInstance ) - GlobalLogger.error() - << "Request to return DnsMaster instance before creating it!"; - return TheOnlyInstance; -} - - - -ResolverItem& DnsMaster::get_resolver_for( const std::string &hostname, - const PingProtocol &ping_protocol ) -{ - // find suitable DnsIpProtocol for ping protocol - DnsIpProtocol protocol = DnsMaster::ping2dns_protocol(ping_protocol); - return get_resolver_for(hostname, protocol); -} - - -ResolverItem& DnsMaster::get_resolver_for( const std::string &hostname, - const DnsIpProtocol &protocol ) -{ - DnsMasterItem master = get_instance(); - - // create key to ResolverMap - resolver_key_type key(hostname, protocol); - if ( master->ResolverMap.count(key) == 0 ) - { // need to create a resolver - - // check if it is an ip address, so can create a simple pseudo resolver - if ( master->is_ip(hostname) ) - { - boost::asio::ip::address ip - = boost::asio::ip::address::from_string(hostname); - if ( (protocol == DNS_IPv4 && !ip.is_v4()) || - (protocol == DNS_IPv6 && !ip.is_v6()) ) - GlobalLogger.warning() << "Asked to create a DNS resolver " - << "for wrong IP protocol: v4 != v6! " - << "We will comply."; - GlobalLogger.info() << "Creating PseudoResolver for IP " << ip; - ResolverItem new_resolver( new IpPseudoResolver(IoService, - hostname, - Cache) ); - master->ResolverMap[key] = new_resolver; - } - else - { - GlobalLogger.info() << "Creating Resolver for host " << hostname; - ResolverItem new_resolver( new DnsResolver(IoService, - hostname, - protocol, - Cache, - NameServer) ); - master->ResolverMap[key] = new_resolver; - } - } - return master->ResolverMap[key]; -} - -/** - * return true if given hostname string actually is an IP - * - * delegates decision to boost::asio::ip::address::from_string - */ -bool DnsMaster::is_ip(const std::string &hostname) const -{ - try - { - boost::asio::ip::address ip = boost::asio::ip::address::from_string( - hostname); - return ip.is_v4() || ip.is_v6(); - } - catch ( const std::exception &ex ) - { - return false; - } -} - - -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() << "Unexpected ping protocol: " - << static_cast(pprot); - return DNS_IPALL; - break; - } -} - -/*boost::asio::ip::address &DnsMaster::get_name_server() const -{ - return NameServer; -}*/ - -int DnsMaster::get_resolved_ip_ttl_threshold() const -{ - return ResolvedIpTtlThreshold; -} - -int DnsMaster::get_max_address_resolution_attempts() const -{ - return MaxAddressResolutionAttempts; -} - -// (created using vim -- the world's best text editor) - diff --git a/src/dns_neww/dnsmaster.h b/src/dns_neww/dnsmaster.h deleted file mode 100644 index c8c5866..0000000 --- a/src/dns_neww/dnsmaster.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - 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 - */ - -/** - * Two in one: a DNS resolver factory and a DNS cache - * - * Put these two things into one class because it is easier this way to avoid - * sync problems if e.g. there are 2 resolvers for the same host name - * - * This class is a Singleton. In case there are problems with this approach, - * there is an alternative: - * give every ResolverBase object a DnsMasterItem as variable, that is set - * during construction and call update / get_cached_results on that instance - */ - -#ifndef DNS_MASTER_H -#define DNS_MASTER_H - -#include -#include // pair - -#include -#include -#include - -#include "host/pinger.h" // for IoserviceItem -#include "host/pingprotocol.h" -#include "dns_neww/dnscache.h" -#include "dns_neww/resolverbase.h" - -class DnsMaster; - -typedef boost::shared_ptr DnsMasterItem; - -typedef boost::net::dns::type_t DnsIpProtocol; -DnsIpProtocol DNS_IPv4 = boost::net::dns::type_a; -DnsIpProtocol DNS_IPv6 = boost::net::dns::type_a6; -DnsIpProtocol DNS_IPALL = boost::net::dns::type_all; - -typedef std::pair resolver_key_type; -typedef std::map resolver_map_type; - - -class DnsMaster : boost::noncopyable -{ -// Resolver factory -public: - ResolverItem& get_resolver_for(const std::string &hostname, - const PingProtocol &ping_protocol); - ResolverItem& get_resolver_for(const std::string &hostname, - const DnsIpProtocol &protocol); - -// implementation of singleton -private: - static DnsMasterItem TheOnlyInstance; - - DnsMaster(const IoServiceItem &io_serv, - const boost::asio::ip::address &name_server, - const int resolved_ip_ttl_threshold, - const int max_address_resolution_attempts, - const DnsCacheItem &cache); -public: - static void create_master(const IoServiceItem &io_serv, - const boost::asio::ip::address &name_server, - const int resolved_ip_ttl_threshold, - const int max_address_resolution_attempts, - const std::string &cache_file); - static DnsMasterItem& get_instance(); - ~DnsMaster(); - -// storage of global variables -public: - //boost::asio::ip::address &get_name_server() const; // currently unused - int get_resolved_ip_ttl_threshold() const; - int get_max_address_resolution_attempts() const; - -// variables -private: - IoServiceItem IoService; - const boost::asio::ip::address NameServer; - const int ResolvedIpTtlThreshold; - const int MaxAddressResolutionAttempts; - DnsCacheItem Cache; - resolver_map_type ResolverMap; - -// internal helper functions -private: - bool is_ip(const std::string &hostname) const; - static DnsIpProtocol ping2dns_protocol(const PingProtocol& pprot); -}; - -#endif - -// (created using vim -- the world's best text editor) - diff --git a/src/dns_neww/dnsresolver.cpp b/src/dns_neww/dnsresolver.cpp deleted file mode 100644 index f1bbb6f..0000000 --- a/src/dns_neww/dnsresolver.cpp +++ /dev/null @@ -1,423 +0,0 @@ -/* - 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 - - with code copied from boost::net::dns::resolve.hpp - by Andreas Haberstroh (andreas at ibusy dot com) - from https://github.com/softwareace/Boost.DNS - */ - -#include "dns_neww/dnsresolver.h" - -#include -#include -#include -#include -#include - -#include - -using I2n::Logger::GlobalLogger; -using boost::posix_time::seconds; -using boost::posix_time::minutes; - -namespace Config -{ - const int ResolveTimeoutSeconds = 5; - const int PauseBeforeRetrySeconds = 10; - const int StaleDataLongtermMinutes = 15; - const int DNS_PORT = 53; - const int UniqueID = 0xaffe; -} - -DnsResolver::DnsResolver(IoServiceItem &io_serv, - const std::string &hostname, - const DnsIpProtocol &protocol, - const DnsCacheItem cache, - const boost::asio::ip::address &name_server) - : ResolverBase( io_serv, hostname, cache ) - , Socket( *io_serv, ip::udp::endpoint(ip::udp::v4(), 0) ) - , ReceiveBuffer() - , Protocol( protocol ) - , NameServer( name_server, Config::DNS_PORT ) - , ResolveTimeoutTimer( *io_serv ) - , PauseBeforeRetryTimer( *io_serv ) - , StaleDataLongtermTimer( *io_serv ) - , NextIpIndex( 0 ) - , RetryCount( 0 ) - , IsResolving( false ) -{ } - - -//============================================================================== -// ASYNC RESOLVE -//============================================================================== - -/** - * copied here code from boost::net::dns::resolve.hpp, since want async - * operation and that is used only internally, there - */ -void DnsResolver::do_resolve() -{ - // check if resolving already - if (IsResolving) - { - GlobalLogger.info() - << "Call to do_resolve ignored since resolving already"; - return; - } - - // just to be sure: cancel timers - ResolveTimeoutTimer.cancel(); - PauseBeforeRetryTimer.cancel(); - StaleDataLongtermTimer.cancel(); - - // create DNS request - boost::net::dns::message dns_message( ResolverBase::Hostname, - boost::net::dns::type_all ); - dns_message.recursive(false); - dns_message.action(boost::net::dns::message::query); - dns_message.opcode(boost::net::dns::message::squery); - dns_message.id(Config::UniqueID); - boost::net::dns_buffer_t request_buffer; - dns_message.encode(request_buffer); - - // setup receipt of reply - Socket.async_receive_from( - boost::asio::buffer(ReceiveBuffer.get_array()), - NameServer, - boost::bind( &DnsResolver::handle_dns_result, this, - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred) - ); - - // schedule timeout - (void) ResolveTimeoutTimer.expires_from_now( - seconds(Config::ResolveTimeoutSeconds)); - ResolveTimeoutTimer.async_wait( boost::bind( - &DnsResolver::handle_resolve_timeout, - this, boost::asio::placeholders::error) ); - - // send dns request - Socket.send_to( boost::asio::buffer(request_buffer.get_array()), - NameServer ); -} - - -void DnsResolver::handle_dns_result(const boost::system::error_code &error, - const std::size_t bytes_transferred) -{ - if ( error == boost::asio::error::operation_aborted ) // cancelled - { - GlobalLogger.info() << "DNS resolve operation was cancelled"; - bool was_success = false; - finalize_resolve(was_success); - } - else if (error) - { - GlobalLogger.info() << "DNS resolve resulted in error " << error - << " --> treat like unavailable"; - handle_unavailable(); - return; - } - - // next 3(+1) lines copied from boost/net/dns/resolver.hpp: - // clamp the recvBuffer with the number of bytes transferred or decode buffr - ReceiveBuffer.length(bytes_transferred); - boost::net::dns::message result_message; - result_message.decode( ReceiveBuffer ); - - // work with a regular pointer to list of answers since result_message is - // owner of data and that exists until end of function - // Items in answers list are shared_ptr to resource_base_t - boost::net::dns::rr_list_t *answers = result_message.answers(); - if (answers->size() == 0) - handle_unavailable(); - - // loop over answers, remembering ips and cnames - HostAddressVec result_ips; - std::vector result_cnames; - using boost::net::dns::resource_base_t; - BOOST_FOREACH( boost::shared_ptr rr_item, *answers ) - { - GlobalLogger.debug() << std::showbase << std::hex - << static_cast(rr_item->rtype()) << ": "; - uint32_t ttl = rr_item->ttl(); - boost::net::dns::type_t rr_type = rr_item->rtype(); - - if (rr_type == boost::net::dns::type_a) - { // 'A' resource records carry IPv4 addresses - if (Protocol == DNS_IPv6) - { - GlobalLogger.info() << "Ignoring IPv4 address because resolver " - << "was configured to only use IPv6."; - continue; - } - boost::asio::ip::address_v4 ip = - ( dynamic_cast (rr_item.get()) ) - ->address(); - result_ips.push_back( HostAddress(ip, ttl) ); - } - else if (rr_type == boost::net::dns::type_a6) - { // 'AAAA' resource records carry IPv6 addresses - if (Protocol == DNS_IPv4) - { - GlobalLogger.info() << "Ignoring IPv6 address because resolver " - << "was configured to only use IPv4."; - continue; - } - boost::asio::ip::address_v6 ip = - ( dynamic_cast (rr_item.get()) ) - ->address(); - result_ips.push_back( HostAddress(ip, ttl) ); - } - else if (rr_type == boost::net::dns::type_cname) - { // 'CNAME' resource records that carry aliases - std::string cname = - (dynamic_cast(rr_item.get())) - ->canonicalname(); - result_cnames.push_back( cname ); - } - else if (rr_type == boost::net::dns::type_ns) - GlobalLogger.debug() << "NS resource"; - else if (rr_type == boost::net::dns::type_soa) - GlobalLogger.debug() << "SOA resource"; - else if (rr_type == boost::net::dns::type_ptr) - GlobalLogger.debug() << "ptr resource"; - else if (rr_type == boost::net::dns::type_hinfo) - GlobalLogger.debug() << "hinfo resource"; - else if (rr_type == boost::net::dns::type_mx) - GlobalLogger.debug() << "mx resource"; - else if (rr_type == boost::net::dns::type_txt) - GlobalLogger.debug() << "txt resource"; - else if (rr_type == boost::net::dns::type_srv) - GlobalLogger.debug() << "srv resource"; - else if (rr_type == boost::net::dns::type_axfr) - GlobalLogger.debug() << "axfr resource"; - else - GlobalLogger.debug() << "unknown resource type"; - } - - GlobalLogger.info() << "Have " << result_ips.size() << " IPs and " - << result_cnames.size() << " CNAMEs"; - - // We expect either one single CNAME and no IPs or a list of IPs. - // But deal with other cases as well - if (result_ips.empty() && result_cnames.empty()) - handle_unavailable(); // we just got crap, this is a dead end - else if ( !result_ips.empty() && !result_cnames.empty()) - GlobalLogger.warning() << "Have CNAMEs AND IPs --> deal with both!"; - - BOOST_FOREACH( const std::string &cname, result_cnames ) - handle_cname(cname); // will schedule another DNS call - - if ( !result_ips.empty() ) - handle_ips(result_ips); -} - - -void DnsResolver::handle_ips(const HostAddressVec &ips) -{ - // save in cache - ResolverBase::update_cache( ips ); - - // clean up - bool was_success = true; - finalize_resolve(was_success); -} - - -void DnsResolver::handle_unavailable() -{ - // schedule new attempt in quite a while - StaleDataLongtermTimer.expires_from_now( - minutes(Config::StaleDataLongtermMinutes)); - StaleDataLongtermTimer.async_wait( - boost::bind( &DnsResolver::wait_timer_timeout_handler, - this, boost::asio::placeholders::error - ) - ); - - // for now, admit failure - bool was_success = false; - finalize_resolve(was_success); -} - -void DnsResolver::handle_cname(const std::string &canonical_name) -{ - // get resolver for canonical name - ResolverItem resolver = DnsMaster::get_instance() - ->get_resolver_for(canonical_name, Protocol); - callback_type callback = boost::bind( &DnsResolver::cname_resolve_callback, - this, canonical_name, _1, _2 ); - resolver->async_resolve( callback ); - - stop_trying(); -} - - -void DnsResolver::cname_resolve_callback(const std::string &canonical_name, - const bool was_success, - const int cname_count) -{ - if (was_success) - // tell cache to return cname's ips if queried for our hostname - ResolverBase::update_cache( - ResolverBase::get_cached_results(canonical_name) ); - else - GlobalLogger.info() << "Cname resolution failed"; - - finalize_resolve(was_success, cname_count+1); -} - - -void DnsResolver::finalize_resolve(const bool was_success, - const int cname_count) -{ - // stop timers - if (cname_count > 0) - stop_trying(); - // else was called already from handle_cname - - // schedule callbacks, clearing callback list - ResolverBase::schedule_callbacks(was_success, cname_count); - - // finalize - GlobalLogger.notice() << "Done resolving" - << " with success = " << was_success - << " and cname_count = " << cname_count; - IsResolving = false; -} - -void DnsResolver::stop_trying() -{ - // cancel timers - GlobalLogger.debug() << "Cancelling timers"; - ResolveTimeoutTimer.cancel(); - PauseBeforeRetryTimer.cancel(); - StaleDataLongtermTimer.cancel(); - - // clean up - RetryCount = 0; -} - -void DnsResolver::handle_resolve_timeout(const boost::system::error_code &error) -{ - if ( error == boost::asio::error::operation_aborted ) // cancelled - { - GlobalLogger.warning() << "Resolve timeout timer was cancelled!"; - return; - } - else if (error) - { - GlobalLogger.warning() << "resolve timeout handler received error " - << error; - return; - } - - GlobalLogger.notice() << "DNS resolving timed out"; - - // increment timer - ++RetryCount; - - if ( RetryCount > DnsMaster::get_instance() - ->get_max_address_resolution_attempts() ) - { - handle_unavailable(); - RetryCount = 0; - } - else - { // schedule retry - PauseBeforeRetryTimer.expires_from_now( - seconds(Config::PauseBeforeRetrySeconds)); - PauseBeforeRetryTimer.async_wait( - boost::bind( &DnsResolver::wait_timer_timeout_handler, - this, boost::asio::placeholders::error) ); - } -} - -void DnsResolver::wait_timer_timeout_handler( - const boost::system::error_code &error) -{ - if ( error == boost::asio::error::operation_aborted ) // cancelled - GlobalLogger.warning() << "Resolve timeout timer was cancelled!"; - else if (error) - GlobalLogger.warning() << "resolve timeout handler received error " - << error; - else - { - GlobalLogger.info() << "Done waiting --> re-try resolve"; - do_resolve(); - } -} - - -//============================================================================== -// RETRIEVAL -//============================================================================== - -HostAddress DnsResolver::get_next_ip() -{ - // get cached data - HostAddressVec cached_data = ResolverBase::get_cached_results(); - - // if no results cached, return default-constructed HostAddress (0.0.0.0) - if ( cached_data.empty() ) - { - HostAddress return_value; - return return_value; - } - - // check validity of index (cache may have changed since last call) - if (NextIpIndex >= cached_data.size()) - NextIpIndex = 0; - - // return next IP - return cached_data[NextIpIndex++]; -} - -bool DnsResolver::have_up_to_date_ip() -{ - // get cached data - HostAddressVec cached_data = ResolverBase::get_cached_results(); - - // get threshold - int resolved_ip_ttl_threshold = DnsMaster::get_instance() - ->get_resolved_ip_ttl_threshold(); - - // loop over addresses - BOOST_FOREACH( const HostAddress &addr, cached_data ) - { - uint32_t ttl = addr.get_ttl().get_updated_value(); - if ( ttl > resolved_ip_ttl_threshold ) - return true; - } - - // if not returned true by now, we have tried all IPs without success - return false; -} - -int DnsResolver::get_resolved_ip_count() -{ - return ResolverBase::get_cached_results().size(); -} - -// (created using vim -- the world's best text editor) - diff --git a/src/dns_neww/dnsresolver.h b/src/dns_neww/dnsresolver.h deleted file mode 100644 index d56df2a..0000000 --- a/src/dns_neww/dnsresolver.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - 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_RESOLVER_H -#define DNS_RESOLVER_H - -#include "dns_neww/dnsmaster.h" - -#include -#include -#include -#include -#include // dns_buffer_t - -#include "dns_neww/resolverbase.h" -#include "dns_neww/dnsmaster.h" -#include "dns_neww/dnscache.h" - - -class DnsResolver : public ResolverBase -{ -public: - ~DnsResolver(); - -// constructor accessible from friend DnsMaster -public: - friend ResolverItem& DnsMaster::get_resolver_for( - const std::string &hostname, - const DnsIpProtocol &protocol); -private: - DnsResolver(IoServiceItem &io_serv, - const std::string &hostname, - const DnsIpProtocol &protocol, - const DnsCacheItem cache, - const boost::asio::ip::address &name_server); - -// only real public function (called from pingers) -public: - HostAddress get_next_ip(); - bool have_up_to_date_ip(); - int get_resolved_ip_count(); - -// implementation of ResolverBase::async_resolve -protected: - void do_resolve(); - -private: - void handle_resolve_timeout(const boost::system::error_code &error); - void handle_dns_result(const boost::system::error_code &error, - const std::size_t bytes_transferred); - void handle_unavailable(); - void handle_ips(const HostAddressVec &ips); - void handle_cname(const std::string &canonical_name); - void cname_resolve_callback(const std::string &canonical_name, - const bool was_success, - const int cname_count); - void finalize_resolve(const bool success, const int cname_count=0); - void stop_trying(); - void wait_timer_timeout_handler(const boost::system::error_code &error); - -private: - boost::asio::ip::udp::socket Socket; - boost::net::dns_buffer_t ReceiveBuffer; - DnsIpProtocol Protocol; - boost::asio::ip::udp::endpoint NameServer; - boost::asio::deadline_timer ResolveTimeoutTimer; - boost::asio::deadline_timer PauseBeforeRetryTimer; - boost::asio::deadline_timer StaleDataLongtermTimer; - std::size_t NextIpIndex; - int RetryCount; - bool IsResolving; -}; - -#endif -// (created using vim -- the world's best text editor) - diff --git a/src/dns_neww/ippseudoresolver.h b/src/dns_neww/ippseudoresolver.h deleted file mode 100644 index dd7b792..0000000 --- a/src/dns_neww/ippseudoresolver.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - 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 IP_PSEUDO_RESOLVER_H -#define IP_PSEUDO_RESOLVER_H - -#include -#include "dns/hostaddress.h" -#include "dns_neww/resolverbase.h" -#include "dns_neww/dnsmaster.h" - -namespace Config -{ - uint32_t DefaultTtl = 60*60*24*356; // 1 year in seconds (approx) -} - -/** @brief Degenerate case of a resolver: hostname is already an IP - * - * created by DnsMaster if given an IP address as hostname - * - * Will do nothing, just remember that IP and return it for every call to - * get_next_ip - * - * Since this is so boring, I did not create an own .cpp for it - */ -class IpPseudoResolver : public ResolverBase -{ -// constructor accessible from friend DnsMaster -public: - friend ResolverItem& DnsMaster::get_resolver_for( - const std::string &hostname, - const DnsIpProtocol &protocol); -private: - IpPseudoResolver(const IoServiceItem io_serv, - const std::string &ip_string, - const DnsCacheItem &cache ) - : ResolverBase( io_serv, ip_string, cache ) - , IpAddress( boost::asio::ip::address::from_string(ip_string), - Config::DefaultTtl ) - {} - -private: - HostAddress IpAddress; - -// only real public function -public: - HostAddress get_next_ip() { return IpAddress; } - bool have_up_to_date_ip() { return true; } - int get_resolved_ip_count(){ return 1; } - -// implementation of ResolverBase::async_resolve -protected: - void do_resolve() - { ResolverBase::schedule_callbacks(true, 0); } -}; -#endif - -// (created using vim -- the world's best text editor) - diff --git a/src/dns_neww/resolverbase.cpp b/src/dns_neww/resolverbase.cpp deleted file mode 100644 index 2587e63..0000000 --- a/src/dns_neww/resolverbase.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - 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_neww/resolverbase.h" -#include "dns_neww/dnsmaster.h" - -#include - -ResolverBase::~ResolverBase() -{ -} - -/** - * callbacks should be of type - * void resolve_callback(const bool was_success, - * const int cname_count) - */ -void ResolverBase::async_resolve(const callback_type &callback) -{ - // remember callback - CallbackList.push(callback); - - // let subclass do the resolving - do_resolve(); -} - -ResolverBase::ResolverBase(const IoServiceItem &io_serv, - const std::string &hostname, - const DnsCacheItem &cache ) - : IoService( io_serv ) - , Hostname( hostname ) - , Cache( cache ) - , CallbackList() -{} - -void ResolverBase::update_cache( const HostAddressVec &new_results ) const -{ Cache->update( Hostname, new_results ); } - -HostAddressVec& ResolverBase::get_cached_results(const std::string host) const -{ - if (host.empty()) - return Cache->get_data( Hostname ); - else - return Cache->get_data( host ); -} - -void ResolverBase::schedule_callbacks(const bool was_success, - const int cname_count) -{ - while ( !CallbackList.empty() ) - { - callback_type callback = CallbackList.front(); - CallbackList.pop(); - IoService->post( boost::bind( callback, - was_success, cname_count ) ); - } -} - -// (created using vim -- the world's best text editor) - diff --git a/src/dns_neww/resolverbase.h b/src/dns_neww/resolverbase.h deleted file mode 100644 index 3b2a1ab..0000000 --- a/src/dns_neww/resolverbase.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - 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 RESOLVER_BASE_H -#define RESOLVER_BASE_H - -#include -#include - -#include -#include "host/pinger.h" -#include "dns/hostaddress.h" -#include "dns_neww/dnscache.h" - -typedef boost::function callback_type; -typedef std::queue callback_list_type; - -/** - * @brief: abstract base class for DnsResolver and IpPseudoResolver - */ -class ResolverBase -{ -public: - virtual HostAddress get_next_ip() = 0; - - virtual ~ResolverBase(); - - /** - * callbacks should be of type - * void resolve_callback(const bool was_success, - * const int cname_count) - */ - void async_resolve(const callback_type &callback); - - virtual bool have_up_to_date_ip() = 0; - virtual int get_resolved_ip_count() = 0; - -protected: - ResolverBase(const IoServiceItem &io_serv, - const std::string &hostname, - const DnsCacheItem &cache ); - -// variables -protected: - IoServiceItem IoService; - std::string Hostname; - DnsCacheItem Cache; - callback_list_type CallbackList; - -// functions for subclasses -protected: - virtual void do_resolve() = 0; - - void update_cache( const HostAddressVec &new_results ) const; - - HostAddressVec& get_cached_results(const std::string host="") const; - - void schedule_callbacks(const bool was_success, - const int cname_count); - -}; - -typedef boost::shared_ptr ResolverItem; - -#endif - -// (created using vim -- the world's best text editor) - -- 1.7.1