added first half-ready versions of new DNS files in temp directory dns_neww to avoid...
authorChristian Herdtweck <christian.herdtweck@intra2net.com>
Wed, 1 Apr 2015 16:33:36 +0000 (18:33 +0200)
committerChristian Herdtweck <christian.herdtweck@intra2net.com>
Mon, 4 May 2015 14:57:57 +0000 (16:57 +0200)
src/dns_neww/dnsmaster.cpp [new file with mode: 0644]
src/dns_neww/dnsmaster.h [new file with mode: 0644]
src/dns_neww/dnsresolver.cpp [new file with mode: 0644]
src/dns_neww/dnsresolver.h [new file with mode: 0644]
src/dns_neww/ippseudoresolver.h [new file with mode: 0644]
src/dns_neww/resolverbase.h [new file with mode: 0644]

diff --git a/src/dns_neww/dnsmaster.cpp b/src/dns_neww/dnsmaster.cpp
new file mode 100644 (file)
index 0000000..625a9d3
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ 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 <logfunc.hpp>
+#include <boost/bind.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/asio/placeholders.hpp>
+
+using boost::bind;
+using boost::posix_time::seconds;
+using I2n::Logger::GlobalLogger;
+
+DnsMasterItem DnsMaster::TheOnlyInstance;
+
+void DnsMaster::create_master(const IoServiceImte &io_serv,
+                              const boost::ip::address &name_server,
+                              const std::string &cache_file)
+{
+    if (TheOnlyInstance)
+    {
+        GlobalLogger.warning()
+            << "Attempting to create another DnsMaster instance!";
+        return false;
+    }
+
+    TheOnlyInstance.reset( new DnsMaster(io_serv, name_server, cache_file) );
+    return true;
+}
+
+
+DnsMaster::DnsMaster(const IoServiceItem &io_serv,
+                     const boost::ip::address &name_server,
+                     const std::string &cache_file)
+    : IoService( io_serv )
+    , NameServer( name_server )
+    , SaveTimer( *io_serv )
+    , CacheFile( cache_file )
+    , ResolverMap()
+    , DataCache()
+{
+    // load cache from file
+    load_from_cachefile();
+
+    // schedule next save
+    (void) SaveTimer.expires_from_now( seconds( SaveTimerSeconds ) );
+    SaveTimer.async_wait( bind( &DnsMaster::schedule_save, this,
+                                boost::asio::placeholders::error ) );
+}
+
+
+DnsMasterItem& DnsMaster::get_instance()
+{
+    if ( !TheOnlyInstance )
+        GlobalLogger.error()
+            << "Request to return DnsMaster instance before creating it!";
+    return TheOnlyInstance;
+}
+
+
+
+DnsMaster::~DnsMaster()
+{
+    // save one last time without re-scheduling the next save
+    save_to_cachefile();
+
+    // cancel save timer
+    SaveTimer.cancel();
+}
+
+void DnsMaster::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() << "SaveTimer was cancelled "
+                             << "--> no save and no re-schedule of saving!";
+        return;
+    }
+    else if (error)
+    {
+        GlobalLogger.error() << "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( SaveTimerSeconds ) );
+    SaveTimer.async_wait( bind( &DnsMaster::schedule_save, this,
+                                boost::asio::placeholders::error ) );
+}
+
+void DnsMaster::save_to_cachefile() const
+{   // now do the saving
+    // TODO (see trusted_net_helper, boost serialization, xml)
+    GlobalLogger.error() << "Actual saving not implemented yet!";
+}
+
+
+bool DnsMaster::load_from_cachefile()
+{
+    // TODO: some boost serialization and xml stuff, see trusted_net_helper
+    GlobalLogger.error() << "Actual loading not implemented yet!";
+    return true;
+}
+
+ResolverItem DnsMaster::get_resolver_for( const std::string &hostname )
+{
+    DnsMasterItem master = get_instance();
+    if ( master->ResolverMap.count(hostname) == 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) )
+        {
+            ResolverItem new_resolver( new IpPseudoResolver(hostname) );
+            master->ResolverMap[hostname] = new_resolver;
+        }
+        else
+        {
+            ResolverItem new_resolver( new DnsResolver(IoService,
+                                                       NameServer,
+                                                       hostname) );
+            master->ResolverMap[hostname] = new_resolver;
+        }
+    }
+    return master->ResolverMap[hostname];
+}
+
+/**
+ * return true if given hostname string actually is an IP
+ *
+ * delegates decision to boost::ip::address::from_string
+ */
+bool DnsMaster::is_ip(const std::string &hostname) const
+{
+    try
+    {
+        boost::ip::address ip = boost::ip::address::from_string(hostname);
+        return ip.is_v4() || ip.is_v6();
+    }
+    catch ( const std::exception &ex )
+    {
+        return false;
+    }
+}
+
+// (created using vim -- the world's best text editor)
+
diff --git a/src/dns_neww/dnsmaster.h b/src/dns_neww/dnsmaster.h
new file mode 100644 (file)
index 0000000..bad242b
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ 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_MASTER_H
+#define DNS_MASTER_H
+
+#include <map>
+#include <pair>
+#include <list>
+
+#include <boost/smart_ptr.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/asio/deadline_timer.hpp>
+#include <boost/system/error_code.hpp>
+
+#include "dns_neww/dnsresolver.h"
+
+class DnsMaster;
+typedef boost::smart_ptr<DnsMaster> DnsMasterItem;
+
+typedef std::map<std::string, ResolverItem> resolver_map_type
+
+typedef boost::posix_time::ptime timestamp_type;
+typedef std::pair<HostAddress, timestamp_type> host_with_timestamp;
+typedef std::vector<host_with_timestamp> host_ttl_time_list;
+typedef std::map<std::string, host_ttl_time_list> cache_data_type;
+
+
+class DnsMaster : boost::noncopyable
+{
+// the two functions called during init
+public:
+    static void create_master(const IoServiceItem &io_serv,
+                              const boost::ip::address &name_server,
+                              const std::string &cache_file);
+    static ResolverItem get_resolver_for(const std::string &hostname);
+
+
+// friendly functions in DnsResolver and their friends here
+public:
+    friend void DnsResolver::update_master(const AddressList &ips);
+    friend std::string DnsResolver::get_next_ip();
+    friend void cname_resolve_callback(const boost::system::error_code &error,
+                                       const bool was_success,
+                                       const int cname_count)
+private:
+    void update_ips(const AddressList &ips);
+    host_ttl_time_list get_cached_results(std::string &hostname);
+
+
+// implementation of singleton
+private:
+    static DnsMasterItem TheOnlyInstance;
+
+    DnsMaster(const IoServiceItem &io_serv,
+              const boost::ip::address &name_server,
+              const std::string &cache_file);
+public:
+    ~DnsMaster();
+
+
+// variables
+private:
+    IoServiceItem IoService;
+    const boost::ip::address NameServer;
+    std::string CacheFile;
+    cache_data_type DataCache;
+    resolver_map_type ResolverMap;
+    boost::asio::deadline_timer SaveTimer;
+
+
+// functions
+private:
+    void schedule_save(const boost::system::error_code &error);
+    void save_to_cachefile() const;
+    void load_from_cachefile();
+
+};
+
+#endif
+
+// (created using vim -- the world's best text editor)
+
diff --git a/src/dns_neww/dnsresolver.cpp b/src/dns_neww/dnsresolver.cpp
new file mode 100644 (file)
index 0000000..c85eed7
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ 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/dnsresolver.h"
+
+#include <logfunc.hpp>
+using I2n::Logger::GlobalLogger;
+
+namespace Config
+{
+    const int ResolveTimeoutSeconds = 10;
+    const int DNS_PORT = 53;
+    const int UniqueID = 0xaffe;
+}
+
+DnsResolver::DnsResolver(IoServiceItem &io_serv,
+                         const boost::ip::address &name_server,
+                         const std::string &hostname)
+    : Hostname( hostname )
+    , Socket( *io_serv, ip::udp::endpoint(ip::udp::v4(), 0) )
+    , ReplyBuffer()
+    , NameServer( name_server, DNS_PORT )
+    , ResolveTimeoutTimer( *io_serv )
+    , PauseBeforeRetryTimer( *io_serv )
+    , StaleDataLongtermTimer( *io_serv )
+    , CallbackList()
+    , host_ttl_time_list::const_iterator()
+    , RetryCount( 0 )
+    , IsResolving( false )
+{
+    // add name server to resolver
+    resolver.addServer( nameServer );
+}
+
+/**
+ * copied here code from boost::net::dns::resolve.hpp, since want async 
+ * operation and that is used only internally, there
+ * --> give credit to Andreas Haberstroh (andreas at ibusy dot com)
+ *     from https://github.com/softwareace/Boost.DNS
+ */
+DnsResolver::async_resolve(const callback_type callback, const int cname_count)
+{
+    // remember callback
+    CallbackList.push_back(callback, cname_count);
+
+    // check if resolving already
+    if (isResolving)
+    {
+        GlobalLogger().info() << "Call to async_resolve(" << Hostname
+                              << ") 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( host_dns_address,
+                                          boost::net::dns::type_all );
+    dns_message.recursive(false);
+    dns_message.action(dns::message::query);
+    dns_message.opcode(dns::message::squery);
+    dns_message.id(UniqueID);
+    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(ResolveTimeoutSeconds));
+    ResolveTimeout.async_wait( bind( &DnsResolver::wait_timer_timeout_handler,
+                                     this, boost::asio::placeholders::error) );
+
+    // send dns request
+    Socket.send_to( boost::asio::buffer(request_buffer.get_array()),
+                    NameServer );
+}
+
+
+void 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;
+        bool inc_cname = false;
+        finalize_resolve(was_success, inc_cname);
+    }
+    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);
+    message result_message();
+    result_message.decode( ReceiveBuffer );
+
+    if (result_message.answers().size == 0)
+        handle_unavailable();
+
+    // loop over answers, remembering ips and cnames
+    typedef boost::shared_ptr<resource_base_t> rr_item_type;
+    typedef boost::shared_ptr<cname_resource> cname_item_type;
+    std::vector<HostAddress> ip_list;
+    std::vector<cname_item_type> cname_list;
+    BOOST_FOREACH( rr_item_type rr_item, result_message.answers() )
+    {
+        GlobalLogger.debug() << std::showbase << std::hex << rr_item->rtype()
+                             << ": ";
+        uint32_t ttl = rr_item->ttl();
+        type_t rr_type = rr_item->rtype();
+
+        if (rr_type == boost::net::dns::type_a)
+        {    // 'A' resource records carry IPv4 addresses
+            std::string ip = ( dynamic_cast<a_resource *> (rr_item.get()) )
+                             ->address();
+            ip_list.push_back( HostAddress(ip, ttl) );
+        }
+        else if (rr_type == boost::net::dns::type_a6)
+        {   // 'AAAA' resource records carry IPv6 addresses
+            std::string ip = ( dynamic_cast<a6_resource *> (rr_item.get()) )
+                             ->address();
+            ip_list.push_back( HostAddress(ip, ttl) );
+        }
+        else if (rr_type == boost::net::dns::type_cname)
+        {   // 'CNAME' resource records that carry aliases
+            cname_list.push_back(dynamic_cast<cname_item_type>(rr_item));
+        }
+        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 " << ip_list.size() << " IPs and "
+                        << cname_list.size() << " CNAMEs";
+
+    // We expect either one single CNAME and no IPs or a list of IPs.
+    // But deal with other cases as well
+    if (ip_list.empty() && cname_list.empty())
+        handle_unavailable();   // we just got crap, this is a dead end
+    else if ( !ip_list.empty() && !cname_list.empty())
+        GlobalLogger.warning() << "Have CNAMEs AND IPs --> deal with both!";
+
+    BOOST_FOREACH( const cname_resource &cname, cname_list )
+        handle_cname(cname);  // will schedule another DNS call
+
+    if ( !ip_list.empty() )
+        handle_ips(ip_list);
+}
+
+
+void DnsResolver::handle_ips(const boost::system::error_code &error,
+                             const IpTtlVec &ips)
+{
+    if (error)
+        GlobalLogger.warning() << "Received error " << error
+                               << " in handle_ips --> exit!";
+    // save in cache
+    update_master(ips);
+
+    // clean up
+    bool was_success = true;
+    bool inc_cname = false;
+    finalize_resolve(was_success, inc_cname);
+}
+
+
+void DnsResolver::handle_unavailable()
+{
+    // schedule new attempt in quite a while
+    StaleDataLongtermTimer.expires_from_now(seconds(StaleDataLongtermSeconds));
+    StaleDataLongtermTimer.async_wait(
+            bind( &DnsResolver::wait_timer_timeout_handler,
+                  this, boost::asio::placeholders::error
+            )
+    );
+
+    // for now, admit failure
+    bool was_success = false;
+    bool inc_cname = false;
+    finalize_resolve(was_success, inc_cname);
+}
+
+void DnsResolver::handle_cname(const std::string &canonical_name)
+{
+    // get resolver for canonical name
+    ResolverItem resolver = DnsMaster.get_instance()
+                            ->get_resolver_for(canonical_name);
+    resolver->async_resolve(
+            bind( &DnsResolver::cname_resolve_callback,
+                  this, boost::asio::placeholders::error, _1, _2
+            )
+    );
+
+    stop_trying();
+}
+
+
+void cname_resolve_callback(const boost::system::error_code &error,
+                            const bool was_success,
+                            const int cname_count)
+{
+    if (error)
+        GlobalLogger.error() << "todo"; // TODO
+    if (!was_success)
+        GlobalLogger.error() << "todo"; // TODO
+
+    // get all results
+    host_ttl_time_list results = DnsMaster.get_instance()->get_cached_results();
+}
+
+
+DnsResolver::get_next_ip()
+{
+    // get cached data
+    host_ttl_time_list cached_data = DnsMaster::get_instance()
+                                     ->get_cached_results(Hostname);
+
+
+}
+
+// (created using vim -- the world's best text editor)
+
diff --git a/src/dns_neww/dnsresolver.h b/src/dns_neww/dnsresolver.h
new file mode 100644 (file)
index 0000000..5c481b9
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ 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 <list>
+#include <boost/asio/deadline_timer.hpp>
+#include <boost/system/error_code.hpp>
+
+#include "dns_neww/resolverbase.h"
+#include "dns_neww/dnsmaster.h"
+
+typedef callback_type
+typedef std::list<callback_type> callback_list_type;
+
+typedef std::vector<HostAddress> IpTtlVec;
+
+class DnsResolver : public ResolverBase
+{
+// constructor accessible from friend DnsMaster
+public:
+    friend DnsMaster::get_resolver_for(const std::string &hostname);
+
+private:
+    DnsResolver(IoServiceItem &io_serv,
+                const boost::ip::address &name_server,
+                const std::string &hostname);
+
+// only real public function (called from pingers)
+public:
+    std::string get_next_ip();
+
+private:
+    void async_resolve(const callback_type &callback, const int cname_count=0);
+    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(const boost::system::error_code &error);
+    void handle_ips(const boost::system::error_code &error,
+                    const IpTtlVec &ips);
+    void handle_cname(const boost::system::error_code &error);
+    void cname_resolve_callback(const boost::system::error_code &error,
+                                const bool was_success,
+                                const int cname_count);
+    void update_master(const AddressList &ips);
+    void finalize_resolve(const bool success, const bool inc_cname);
+
+private:
+    const std::string Hostname;
+    ip::udp::socket Socket;
+    dns_buffer_t ReplyBuffer;
+    ip::udp::endpoint NameServer;
+    boost::asio::deadline_timer ResolveTimeoutTimer;
+    boost::asio::deadline_timer PauseBeforeRetryTimer;
+    boost::asio::deadline_timer StaleDataLongtermTimer;
+    callback_list_type CallbackList;
+    host_ttl_time_list::const_iterator NextIpIter;
+    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
new file mode 100644 (file)
index 0000000..015a312
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ 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 "dns_neww/resolverbase.h"
+#include "dns_neww/dnsmaster.h"
+
+/** @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 DnsMaster::create_resolver_for(const std::string &hostname);
+private:
+    IpPseudoResolver(const std::string ip) : IP(ip)  {}
+
+private:
+    const std::string IP;
+
+// only function, inherited from ResolverBase
+public:
+    std::string get_next_ip()  { return IP;  }
+};
+#endif
+
+// (created using vim -- the world's best text editor)
+
diff --git a/src/dns_neww/resolverbase.h b/src/dns_neww/resolverbase.h
new file mode 100644 (file)
index 0000000..0003520
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ 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 <boost/shared_ptr.hpp>
+
+/**
+ * @brief: abstract base class for DnsResolver and IpPseudoResolver
+ */
+class ResolverBase
+{
+public:
+    virtual std::string get_next_ip() = 0;
+};
+
+typedef boost::shared_ptr<ResolverBase> ResolverItem;
+
+#endif
+
+// (created using vim -- the world's best text editor)
+