From 26650731efc6ed486243532f0aa566577773d702 Mon Sep 17 00:00:00 2001 From: Guilherme Maciel Ferreira Date: Fri, 15 Apr 2011 13:04:13 +0200 Subject: [PATCH] Using the boost-net-dns library to resolve DNS host names --- .gitignore | 4 + lib/boost-net-dns/boost/net/basic_dns_resolver.hpp | 62 + .../boost/net/basic_dns_resolver_service.hpp | 98 + lib/boost-net-dns/boost/net/dns.hpp | 2622 ++++++++++++++++++++ lib/boost-net-dns/boost/net/dns_cache.hpp | 388 +++ lib/boost-net-dns/boost/net/dns_debug.hpp | 293 +++ lib/boost-net-dns/boost/net/dns_resolver.hpp | 22 + .../boost/net/impl/dns_resolver_impl.hpp | 547 ++++ lib/boost-net-dns/boost/net/network_array.hpp | 483 ++++ lib/boost-net-dns/boost/net/resolve.hpp | 232 ++ lib/boost-net-dns/boost/net/rfc1035_414.hpp | 218 ++ src/CMakeLists.txt | 7 +- src/dns/dnsresolver.cpp | 49 +- src/dns/hostaddress.cpp | 9 + src/dns/hostaddress.h | 1 + 15 files changed, 5020 insertions(+), 15 deletions(-) create mode 100755 lib/boost-net-dns/boost/net/basic_dns_resolver.hpp create mode 100755 lib/boost-net-dns/boost/net/basic_dns_resolver_service.hpp create mode 100755 lib/boost-net-dns/boost/net/dns.hpp create mode 100755 lib/boost-net-dns/boost/net/dns_cache.hpp create mode 100755 lib/boost-net-dns/boost/net/dns_debug.hpp create mode 100755 lib/boost-net-dns/boost/net/dns_resolver.hpp create mode 100755 lib/boost-net-dns/boost/net/impl/dns_resolver_impl.hpp create mode 100755 lib/boost-net-dns/boost/net/network_array.hpp create mode 100755 lib/boost-net-dns/boost/net/resolve.hpp create mode 100755 lib/boost-net-dns/boost/net/rfc1035_414.hpp diff --git a/.gitignore b/.gitignore index f04e513..3fea642 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,7 @@ Debug # uml cache files *.vpp~* + +# version control (CVS, SVN, GIT) +.cvs +.svn diff --git a/lib/boost-net-dns/boost/net/basic_dns_resolver.hpp b/lib/boost-net-dns/boost/net/basic_dns_resolver.hpp new file mode 100755 index 0000000..50a7fbf --- /dev/null +++ b/lib/boost-net-dns/boost/net/basic_dns_resolver.hpp @@ -0,0 +1,62 @@ +// +// basic_dns_resolver.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2008 Andreas Haberstroh (andreas at ibusy dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#ifndef BOOST_NET_BASIC_DNS_RESOLVER_HPP +#define BOOST_NET_BASIC_DNS_RESOLVER_HPP + +namespace boost { + namespace net { + namespace dns { + + template + class basic_dns_resolver : public boost::asio::basic_io_object + { + public: + explicit basic_dns_resolver(boost::asio::io_service &io_service) + : boost::asio::basic_io_object(io_service) + { + } + + void add_nameserver(ip::address addr) + { + this->service.add_nameserver(this->implementation, addr); + } + + template + void async_resolve(const net::dns::question & question, CallbackHandler handler) + { + this->service.async_resolve(this->implementation, question, handler); + } + + template + void async_resolve(const string & domain, const net::dns::type_t rrtype, CallbackHandler handler) + { + this->service.async_resolve(this->implementation, domain, rrtype, handler); + } + + rr_list_t resolve(const net::dns::question & question) + { + return this->service.resolve(this->implementation, question); + } + + rr_list_t resolve(const string & domain, const net::dns::type_t rrtype) + { + return this->service.resolve(this->implementation, domain, rrtype); + } + }; + +#if !defined(GENERATING_DOCUMENTATION) + typedef basic_dns_resolver > dns_resolver; +#endif + + } // namespace dns + } // namespace net +} // namespace boost + +#endif // BOOST_NET_BASIC_DNS_RESOLVER_HPP diff --git a/lib/boost-net-dns/boost/net/basic_dns_resolver_service.hpp b/lib/boost-net-dns/boost/net/basic_dns_resolver_service.hpp new file mode 100755 index 0000000..ecd873e --- /dev/null +++ b/lib/boost-net-dns/boost/net/basic_dns_resolver_service.hpp @@ -0,0 +1,98 @@ +// +// basic_dns_resolver_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2008 Andreas Haberstroh (andreas at ibusy dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#ifndef BOOST_NET_BASIC_DNS_RESOLVER_SERVICE_HPP +#define BOOST_NET_BASIC_DNS_RESOLVER_SERVICE_HPP + +#include +#include + +namespace boost { + namespace net { + namespace dns { + + template + class basic_dns_resolver_service : public boost::asio::io_service::service + { + public: + static boost::asio::io_service::id id; + + explicit basic_dns_resolver_service(boost::asio::io_service &io_service) + : boost::asio::io_service::service(io_service), + work_(new boost::asio::io_service::work(work_io_service_)), + work_thread_(boost::bind(&boost::asio::io_service::run, &work_io_service_)) + { + } + + virtual ~basic_dns_resolver_service() + { + work_.reset(); + work_io_service_.stop(); + work_thread_.join(); + } + + typedef boost::shared_ptr implementation_type; + + void construct(implementation_type &impl) + { + impl.reset(new DnsResolverImplementation(this->get_io_service())); + } + + void destroy(implementation_type &impl) + { + impl->destroy(); + impl.reset(); + } + + rr_list_t resolve(implementation_type &impl, const net::dns::question & question) + { + return impl->resolve(question); + } + + rr_list_t resolve(implementation_type &impl, const string & domain, const net::dns::type_t rrtype) + { + return impl->resolve(domain, rrtype); + } + + template + void async_resolve(implementation_type &impl, const net::dns::question & question, CallbackHandler handler) + { + impl->async_resolve(question, handler); + } + + template + void async_resolve(implementation_type &impl, const string & domain, const net::dns::type_t rrtype, CallbackHandler handler) + { + net::dns::question question(domain, rrtype); + impl->async_resolve(question, handler); + } + + void add_nameserver(implementation_type &impl, ip::address addr) + { + impl->add_nameserver(addr); + } + + private: + void shutdown_service() + { + } + + boost::asio::io_service work_io_service_; + boost::scoped_ptr work_; + boost::thread work_thread_; + }; +#if !defined(GENERATING_DOCUMENTATION) + template + boost::asio::io_service::id basic_dns_resolver_service::id; +#endif + } // namespace dns + } // namespace net +} // namespace boost + +#endif // BOOST_NET_BASIC_DNS_RESOLVER_SERVICE_HPP diff --git a/lib/boost-net-dns/boost/net/dns.hpp b/lib/boost-net-dns/boost/net/dns.hpp new file mode 100755 index 0000000..510f61e --- /dev/null +++ b/lib/boost-net-dns/boost/net/dns.hpp @@ -0,0 +1,2622 @@ +// +// dns.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 1998-2008 Andreas Haberstroh (andreas at ibusy dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#ifndef BOOST_NET_DNS_HPP +#define BOOST_NET_DNS_HPP + +#include + +#include +#include + +#include +#include +#include + +using namespace std; +using namespace boost; +using namespace boost::algorithm; + +namespace boost { + namespace net { + namespace dns { + +// quick forward declarations +class message; +class request_base_t; +class resource_base_t; + +//! Shared Resource Base Pointer +typedef shared_ptr shared_resource_base_t; + +//! A list of resource records +typedef std::vector rr_list_t; + +//! A shared list of resource records +typedef shared_ptr shared_rr_list_t; + +//! Shared Request Base Pointer +typedef shared_ptr shared_request_base_t; + +//! Class identification for resource records. Included is the QCLASS that is in the 0xF0 range. +typedef enum +{ + class_none = 0x00, //!< No class definition + class_in, //!< Internet class. Default class + class_cs, //!< CSNET class, obsolete, used for examples. + class_ch, //!< CHAOS class + class_hs, //!< Hesiod [Dyer 87] + class_all = 0xff //!< Query all classes +} class_t; + +//! Type identification for resource records. Included are the QTYPE's that are in the 0xF0 range +typedef enum +{ + type_none = 0x00, //!< No type definition. + type_a = 0x01, //!< Address type + type_ns = 0x02, //!< Name Server type + type_cname = 0x05, //!< Canonical name type + type_soa = 0x06, //!< Start of Authority type + type_ptr = 0x0c, //!< Pointer type + type_hinfo = 0x0d, //!< Host Information type + type_mx = 0x0f, //!< Mail Exchanger type + type_txt = 0x10, //!< Text type + type_a6 = 0x1c, //!< Address (IP6) type + type_srv = 0x21, //!< Service type + type_axfr = 0xfc, //!< Zone transfer type + type_all = 0xff //!< Query all types +} type_t; + + +/*! +Basic definition of a DNS request. + +Shared by Questions and all the different resource record types +*/ +class request_base_t +{ +protected: + /// Domain name of the resource record + string rr_domain; + + /// Resource record type + uint16_t rr_type; + + /// Resource record class + uint16_t rr_class; + +public: + /// Default constructor + request_base_t() + : rr_domain(), + rr_type(type_none), + rr_class(class_none) + {} + + /*! + Copy contructor + + \param o request_base_t to copy + */ + request_base_t(const request_base_t & o) + : rr_domain(o.rr_domain), + rr_type(o.rr_type), + rr_class(o.rr_class) + { + } + + /*! + Constructs a request_base_t + + \param t Resource type to create object for + \param c Resource class to create object for + */ + request_base_t(const type_t t, const class_t c=class_in) + : rr_domain(), + rr_type(t), + rr_class(c) + { + } + + /*! + Constructs a request_base_t + + \param d Domain name to create object for + \param t Resource type to create object for + \param c Resource class to create object for + */ + request_base_t(const string & d, const type_t t, const class_t c=class_in) + : rr_domain(d), + rr_type(t), + rr_class(c) + {} + + /*! + Constructor that creates the request_base_t from a network buffer + + \param buffer Memory buffer to read from + \param offset_map DNS label compression map for label/offset values + */ + request_base_t(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + : rr_domain(), + rr_type(), + rr_class() + { + decode(buffer, offset_map); + } + + /// Virtual Destructor + virtual ~request_base_t() + { + } + + /*! + Sets the domain name + + \param s Domain name to assign to the request_base_t + \return current domain name + */ + const string& domain(const string& s) + { + return domain(s.c_str()); + } + + /*! + Sets the domain name + + \param s Domain name to assign to the request_base_t. + \return current domain name + */ + const string& domain(const char* s) + { + rr_domain = s; + return rr_domain; + } + + /*! + Gets the domain name + + \return current domain name + */ + const string& domain() const + { + return rr_domain; + } + + + /*! + Sets the resource record type + + \param t resource type to assign to the request_base_t. + \return Current type + */ + type_t rtype(const type_t t) + { + rr_type = t; + return (type_t)rr_type; + } + + /*! + Gets the resource record type + + \return Current type + */ + type_t rtype() const + { + return (type_t)rr_type; + } + + /*! + Sets the resource record class + + \param c resource class to assign to the request_base_t. + \return current class + */ + class_t rclass(const class_t c) + { + rr_class = c; + return (class_t)rr_class; + } + + /*! + Gets the resource record class + + \return current class + */ + class_t rclass() const + { + return (class_t)rr_class; + } + + /// Friend to tie to the containers in the message class. + friend class message; + +protected: + /*! + Encodes the request_base_t into a memory buffer + + \param buffer Buffer to encode the request into + \param offset_map DNS label compression map for label/offset values + */ + void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + offset_map.write_label(rr_domain, buffer); + BOOST_ASSERT( rr_type != 0x0000 ); + buffer.put( rr_type ); + BOOST_ASSERT( rr_class != 0x0000 ); + buffer.put( rr_class ); + } + + /*! + Decodes the request_base_t into a memory buffer + + \param buffer Buffer to decode the request into + \param offset_map DNS label compression map for label/offset values + */ + void decode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + offset_map.read_label(rr_domain, buffer); + buffer.get( rr_type ); + buffer.get( rr_class ); + } +}; + +/// A question is a simple thing +class question : public request_base_t +{ +public: + /// Default constructor + question() + : request_base_t() + {} + + /*! + Copy contructor + + \param o question to copy + */ + question(const request_base_t & o) + : request_base_t(o) + { + } + + /*! + Copy contructor + + \param o question to copy + */ + question(const question & o) + : request_base_t() + { + domain(o.domain()); + rtype(o.rtype()); + rclass(o.rclass()); + } + + /*! + Constructs a question + + \param t Resource type to create object for + \param c Resource class to create object for + */ + question(const type_t t, const class_t c=class_in) + : request_base_t(t, c) + { + } + + /*! + Constructs a question + + \param d Domain name to create object for + \param t Resource type to create object for + \param c Resource class to create object for + */ + question(const string & d, const type_t t, const class_t c=class_in) + : request_base_t(d, t, c) + {} + + /*! + Constructor that creates the question from a network buffer + + \param buffer Memory buffer to read from + \param offset_map DNS label compression map for label/offset values + */ + question(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + : request_base_t(buffer, offset_map) + { + } + + /// Virtual Destructor + virtual ~question() + { + } +}; + +/*! +Basic definition of a DNS resource record. + +*/ +class resource_base_t : public request_base_t +{ +private: + /// Time To Live value for the resource record + uint32_t rr_ttl; + + /// Resource Record payload length + uint16_t rr_length; + +public: + /// Constructs an empty resource_base_t + resource_base_t() + : request_base_t(), + rr_ttl(0), + rr_length(0) + {} + + /*! + Copy contructor + + \param o resource_base_t to copy + */ + resource_base_t(const resource_base_t& o) + : request_base_t(o), + rr_ttl(o.rr_ttl), + rr_length(o.rr_length) + {} + + /*! + Sets the resource type and defaults the resource class to class_in. + + \param t Resource type to create object for + */ + resource_base_t(const type_t t) + : request_base_t(t,class_in), + rr_ttl(0), + rr_length(0) + {} + + /*! + Defaults the resource class to class_in. + + \param s Domain name to create object for + \param t Resource type to create object for + */ + resource_base_t(const string& s, const type_t t) + : request_base_t(s,t,class_in), + rr_ttl(0), + rr_length(0) + {} + + /*! + Constructor that creates the resource_base_t from a memory buffer + + \param buffer Memory buffer to read from + \param offset_map + */ + resource_base_t(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + : rr_ttl(0), + rr_length(0) + { + decode(buffer, offset_map); + } + + virtual ~resource_base_t() + { + } + + /*! + Clones an existing resource record object + */ + virtual shared_resource_base_t clone() const + { + return shared_resource_base_t(new resource_base_t(*this)); + } + + /*! + Sets the Time To Live value + + \param t Time to Live to assign to the resource_base_t. + \return TTL value + */ + uint32_t ttl(const uint32_t t) + { + rr_ttl = t; + return rr_ttl; + } + + /*! + Gets the Time To Live value + + \return TTL value + */ + uint32_t ttl() const + { + return rr_ttl; + } + + /*! + Sets the payload length of the resource record + + \param t Payload length to assign to the resource_base_t. + \return payload length + */ + uint16_t length(const uint16_t t) + { + rr_length = t; + return rr_length; + } + + /*! + Gets the payload length of the resource record + + \return payload length + */ + uint16_t length() const + { + return rr_length; + } + + /// Friend to tie to the containers in the message class. + friend class message; + +protected: + /*! + Encodes the resource_base_t into a memory buffer + + \param buffer Buffer to encode the request into + \param offset_map DNS label compression map for label/offset values + */ + virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + request_base_t::encode(buffer, offset_map); + buffer.put( rr_ttl ); + buffer.put( rr_length ); + } + + /*! + Decodes the resource_base_t from a memory buffer + + \param buffer Buffer to decode the request into + \param offset_map DNS label compression map for label/offset values + */ + virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + request_base_t::decode(buffer, offset_map); + buffer.get( rr_ttl ); + buffer.get( rr_length ); + } +}; + +/*! + Definition for an unknown resource + + The RFC states that DNS cache servers should handle unknown RR types and simply pass them on as requested. + For instance, the original RFC didn't specify SRV records. And, many servers couldn't handle those types. + So, this class has an "unknown" type and simply passes unknown RRR types along as needed. +*/ +class unknown_resource : public resource_base_t +{ +protected: + /// Raw data for the unknown resource records. + shared_ptr _data; + +public: + /// Default contructor + unknown_resource() : resource_base_t(), _data() {;} + + /*! + Copy Constructor + + \param o unknown resource to copy from + */ + unknown_resource(const unknown_resource& o) + : resource_base_t(o), + _data( new uint8_t[length()] ) + { + memcpy( _data.get(), o._data.get(), length() ); + } + + /*! + Copy Constructor + + \param o resource_base_t to copy from + */ + unknown_resource(const resource_base_t& o) + : resource_base_t(o), + _data() + { + ; + } + + /// Virtual Destructor + virtual ~unknown_resource() + { + } + + /*! + Clones an existing resource record object + */ + virtual shared_resource_base_t clone() const + { + return shared_resource_base_t(new unknown_resource(*this)); + } + + /// Friend to tie to the containers in the message class. + friend class message; + +protected: + /*! + Encodes the a resource into a memory buffer + + \param buffer Buffer to encode the request into + \param offset_map DNS label compression map for label/offset values + */ + virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + resource_base_t::encode(buffer, offset_map); + + for( size_t i = 0; i < length(); ++i ) + buffer.put( _data.get()[i] ); + } + + /*! + Decodes the a resource into a memory buffer + + \param buffer Buffer to decode the request into + \param offset_map DNS label compression map for label/offset values + */ + virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& /*offset_map*/) + { + _data = shared_ptr( new uint8_t[length()] ); + for( size_t i = 0; i < length(); ++i ) + buffer.get( _data.get()[i] ); + } +}; + +/*! +Definition for an A resource record +*/ +class a_resource : public resource_base_t +{ +protected: + /// IP 4 address + ip::address_v4 rr_address; + +public: + /// Default contructor + a_resource() : resource_base_t(type_a), rr_address(0) {;} + + /*! + Constructs a a_resource + + \param s Host name for the A record + */ + a_resource(const string& s) : resource_base_t(s, type_a), rr_address(0) {;} + + /// Virtual Destructor + virtual ~a_resource() + { + } + + /*! + Sets the IP4 address from a ip::address_v4 + + \param addr Address to assign to the a_resource. + \return Address + */ + const ip::address_v4& address(const ip::address_v4& addr) + { + rr_address = addr; + return rr_address; + } + + /*! + Sets the IP4 address from a dotted decimal string + + \param s Address to assign to the a_resource. + \return Address + */ + const ip::address_v4& address(const char* s) + { + return address(ip::address_v4::from_string(s)); + } + + /*! + Gets the IP4 address + + \return Address + */ + const ip::address_v4& address() const + { + return rr_address; + } + + /*! + Clones an existing resource record object + */ + virtual shared_resource_base_t clone() const + { + return shared_resource_base_t(new a_resource(*this)); + } + + /// Friend to tie to the containers in the message class. + friend class message; + +protected: + /*! + Copy Constructor + + \param o a_resource to copy from + */ + a_resource(const a_resource& o) : resource_base_t(o), rr_address(o.rr_address) { ; } + + /*! + Copy Constructor + + \param o resource_base_t to copy from + */ + a_resource(const resource_base_t& o) : resource_base_t(o), rr_address(0) { ; } + + + /*! + Encodes the a resource into a memory buffer + + \param buffer Buffer to encode the request into + \param offset_map DNS label compression map for label/offset values + */ + virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + resource_base_t::encode(buffer, offset_map); + + // the length offset for the resource record + size_t lenOffset( buffer.position() - sizeof(uint16_t) ); + + size_t len(0); + + len = buffer.put( rr_address ); + + // lastly, update the length field + buffer.put( (uint16_t)len, lenOffset, false ); + } + + /* + Decodes the a resource into a memory buffer + + \param buffer Buffer to decode the request into + \param offset_map DNS label compression map for label/offset values + */ + virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& /*offset_map*/) + { + buffer.get(rr_address); + } +}; + +/*! +Definition for an NS resource record + +*/ +class ns_resource : public resource_base_t +{ +protected: + /// name server name + string rr_nsdname; + +public: + /// Default contructor + ns_resource() : resource_base_t(type_ns), rr_nsdname() {;} + + /*! + Constructs a ns_resource from a string + + \param s Host name for the NS record + */ + ns_resource(const string& s) : resource_base_t(s, type_ns), rr_nsdname(s) {;} + + /// Virtual Destructor + virtual ~ns_resource() + { + } + + /*! + Sets the nameserver from a string + + \param s Nameserver to assign to the ns_resource. + \return Nameserver + */ + const string& nameserver(const string& s) + { + return nameserver(s.c_str()); + } + + /*! + Sets the nameserver from a null-terminated C tring + + \param s Nameserver string to assign to the ns_resource. + \return Nameserver + */ + const string& nameserver(const char* s) + { + rr_nsdname = s; + return rr_nsdname; + } + + /*! + Sets the nameserver + + \return Nameserver + */ + const string& nameserver() const + { + return rr_nsdname; + } + + /*! + Clones an existing resource record object + */ + virtual shared_resource_base_t clone() const + { + return shared_resource_base_t(new ns_resource(*this)); + } + + /// Friend to tie to the containers in the message class. + friend class message; + +protected: + /*! + Copy Constructor + + \param o ns_resource to copy from + */ + ns_resource(const ns_resource& o) : resource_base_t(o), rr_nsdname(o.rr_nsdname) { ; } + + /*! + Copy Constructor + + \param o resource_base_t to copy from + */ + ns_resource(const resource_base_t& o) + : resource_base_t(o), + rr_nsdname() + { + } + + /*! + Encodes the ns resource into a memory buffer + + \param buffer Buffer to encode the request into + \param offset_map DNS label compression map for label/offset values + */ + virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + resource_base_t::encode(buffer, offset_map); + + size_t lenOffset( buffer.position() - sizeof(uint16_t) ); + size_t len = offset_map.write_label(rr_nsdname, buffer); + + // lastly, update the length field + buffer.put( (uint16_t)len, lenOffset, false ); + } + + /*! + Decodes the ns resource into a memory buffer + + \param buffer Buffer to decode the request into + \param offset_map DNS label compression map for label/offset values + */ + virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + offset_map.read_label(rr_nsdname, buffer); + } +}; + +/*! +Definition of a CNAME resource +*/ +class cname_resource : public resource_base_t +{ +protected: + /// Canonical Name + string rr_cname; + +public: + /// Default contructor + cname_resource() : resource_base_t(type_cname), rr_cname() {;} + + /*! + Constructs a cname_resource + + \param s Host name for the CNAME record + */ + cname_resource(const string& s) : resource_base_t(s, type_cname), rr_cname(s) {;} + + /// Virtual Destructor + virtual ~cname_resource() + { + } + + /*! + Sets the Canonical name + + \param s Canonical name to assign to the cname_resource. + \return Canonical Name + */ + const string& canonicalname(const string& s) + { + return canonicalname(s.c_str()); + } + + /*! + Sets the Canonical name + + \param s Canonical name string to assign to the cname_resource. + \return Canonical name + */ + const string& canonicalname(const char* s) + { + rr_cname = s; + return rr_cname; + } + + /*! + Gets the Canonical name + + \return Canonical name + */ + const string& canonicalname() const + { + return rr_cname; + } + + /*! + Clones an existing resource record object + */ + virtual shared_resource_base_t clone() const + { + return shared_resource_base_t(new cname_resource(*this)); + } + + /// Friend to tie to the containers in the message class. + friend class message; + +protected: + /*! + Copy Constructor + + \param o cname_resource to copy from + */ + cname_resource(const cname_resource& o) : resource_base_t(o), rr_cname(o.rr_cname) { ; } + + /*! + Copy Constructor + + \param o resource_base_t to copy from + */ + cname_resource(const resource_base_t& o) : resource_base_t(o), rr_cname() { ; } + + /*! + Encodes the cname resource into a memory buffer + + \param buffer Buffer to encode the request into + \param offset_map DNS label compression map for label/offset values + */ + virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + resource_base_t::encode(buffer, offset_map); + + size_t lenOffset( buffer.position() - sizeof(uint16_t) ); + size_t len = offset_map.write_label(rr_cname, buffer); + + // lastly, update the length field + buffer.put( (uint16_t)len, lenOffset, false ); + } + + /*! + Decodes the cname resource into a memory buffer + + \param buffer Buffer to decode the request into + \param offset_map DNS label compression map for label/offset values + */ + virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + offset_map.read_label(rr_cname, buffer); + } +}; + +/*! +Definition of a SOA resource +*/ +class soa_resource : public resource_base_t +{ +protected: + /// Master Name + string rr_mname; + /// Responsible Name + string rr_rname; + /// Serial Number for SOA record + uint32_t rr_serial; + /// Refresh Time + uint32_t rr_refresh; + /// Retry Time + uint32_t rr_retry; + /// Exipiration Time + uint32_t rr_expire; + /// Minimum TTL + uint32_t rr_minttl; + +public: + /// Default contructor + soa_resource() + : resource_base_t(type_soa), + rr_mname(), + rr_rname(), + rr_serial(0), + rr_refresh(0), + rr_retry(0), + rr_expire(0), + rr_minttl(0) + { + ; + } + + /*! + Constructs a soa_resource + + \param s Host name for the SOA record + */ + soa_resource(const string& s) + : resource_base_t(s, type_soa), + rr_mname(), + rr_rname(), + rr_serial(0), + rr_refresh(0), + rr_retry(0), + rr_expire(0), + rr_minttl(0) + { + ; + } + + /// Virtual Destructor + virtual ~soa_resource() + { + } + + /*! + Sets the Master Name + + \param s Master Name to assign to the soa_resource. + \return Master Name + */ + const string& master_name(const string& s) + { + return master_name(s.c_str()); + } + + /*! + Sets the Master Name + + \param s Master Name string to assign to the soa_resource. + \return Master Name + */ + const string& master_name(const char* s) + { + rr_mname = s; + return rr_mname; + } + + /*! + Gets the Master Name + + \return Master Name + */ + const string& master_name() const + { + return rr_mname; + } + + /*! + Sets the Responsible Name + + \param s Responsible Name to assign to the soa_resource. + \return Responsible Name + */ + const string& responsible_name(const string& s) + { + return responsible_name(s.c_str()); + } + + /*! + Sets the Responsible Name + + \param s Responsible Name to assign to the soa_resource. + \return Responsible Name + */ + const string& responsible_name(const char* s) + { + rr_rname = s; + return rr_rname; + } + + /*! + Gets the Responsible Name + + \return Responsible Name + */ + const string& responsible_name() const + { + return rr_rname; + } + + /*! + Sets the Serial number + + \param d Serial number to assign to the soa_resouce. + \return Serial number + */ + uint32_t serial_number(const uint32_t d) + { + rr_serial = d; + return rr_serial; + } + + /*! + Gets the Serial number + + \return Serial number + */ + uint32_t serial_number() const + { + return rr_serial; + } + + /*! + Sets the refresh time + + \param d Refresh time to assign to the soa_resouce. + \return Refresh time + */ + uint32_t refresh(const uint32_t d) + { + rr_refresh = d; + return rr_refresh; + } + + /*! + Gets the refresh time + + \return Refresh time + */ + uint32_t refresh() const + { + return rr_refresh; + } + + /*! + Sets the Retry time + + \param d Retry time to assign to the soa_resouce. + \return Retry time + */ + uint32_t retry(const uint32_t d) + { + rr_retry = d; + return rr_retry; + } + + /*! + Gets the Retry time + + \return Retry time + */ + uint32_t retry() const + { + return rr_retry; + } + + /*! + Sets the Exipiration time + + \param d Exipiration time to assign to the soa_resouce. + \return Exipiration time + */ + uint32_t expire(const uint32_t d) + { + rr_expire = d; + return rr_expire; + } + + /*! + Gets the Exipiration time + + \return Exipiration time + */ + uint32_t expire() const + { + return rr_expire; + } + + /*! + Sets the Minimum TTL + + \param d Minimum TTL to assign to the soa_resouce. + \return Minimum TTL + */ + uint32_t minttl(const uint32_t d) + { + rr_minttl = d; + return rr_minttl; + } + + /*! + Gets the Minimum TTL + + \return Minimum TTL + */ + uint32_t minttl() const + { + return rr_minttl; + } + + /*! + Clones an existing resource record object + */ + virtual shared_resource_base_t clone() const + { + return shared_resource_base_t(new soa_resource(*this)); + } + + /// Friend to tie to the containers in the message class. + friend class message; + +protected: + /*! + Copy Constructor + + \param o soa_resource to copy from + */ + soa_resource(const soa_resource& o) + : resource_base_t(o), + rr_mname(o.rr_mname), + rr_rname(o.rr_rname), + rr_serial(o.rr_serial), + rr_refresh(o.rr_refresh), + rr_retry(o.rr_retry), + rr_expire(o.rr_expire), + rr_minttl(o.rr_minttl) + { + } + + /*! + Copy Constructor + + \param o resource_base_t to copy from + */ + soa_resource(const resource_base_t& o) + : resource_base_t(o), + rr_mname(), + rr_rname(), + rr_serial(0), + rr_refresh(0), + rr_retry(0), + rr_expire(0), + rr_minttl(0) + { + ; + } + + /*! + Encodes the soa resource into a memory buffer + + \param buffer Buffer to encode the request into + \param offset_map DNS label compression map for label/offset values + */ + virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + resource_base_t::encode(buffer, offset_map); + + size_t lenOffset( buffer.position() - sizeof(uint16_t) ); + size_t len(0); + + len += offset_map.write_label(rr_mname, buffer); + len += offset_map.write_label(rr_rname, buffer); + len += buffer.put( rr_serial ); + len += buffer.put( rr_refresh ); + len += buffer.put( rr_retry ); + len += buffer.put( rr_expire ); + len += buffer.put( rr_minttl ); + + // lastly, update the length field + buffer.put( (uint16_t)len, lenOffset, false ); + } + + /*! + Decodes the soa_resource into a memory buffer + + \param buffer Buffer to decode the request into + \param offset_map DNS label compression map for label/offset values + */ + virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + offset_map.read_label(rr_mname, buffer); + offset_map.read_label(rr_rname, buffer); + + buffer.get( rr_serial ); + buffer.get( rr_refresh ); + buffer.get( rr_retry ); + buffer.get( rr_expire ); + buffer.get( rr_minttl ); + } + +}; + +/*! +Definition of a PTR resource +*/ +class ptr_resource : public resource_base_t +{ +protected: + /// Pointer name + string rr_ptrdname; + +public: + /// Default contructor + ptr_resource() : resource_base_t(type_ptr), rr_ptrdname() {;} + + /// Constructs a ptr_resource + /* + \param s Host name for the PTR record + */ + ptr_resource(const string& s) : resource_base_t(s, type_ptr), rr_ptrdname(s) {;} + + /// Virtual Destructor + virtual ~ptr_resource() + { + } + + /// Pointer set function + /* + \param t Pointer to assign to the ptr_resource. + \return Pointer + */ + const string& pointer(const string& s) + { + return pointer(s.c_str()); + } + + /// Pointer get/set function + /* + \param t Pointer string to assign to the ptr_resource. If left blank, will return the + current pointer only. + \return Pointer + */ + const string& pointer(const char* s=0) + { + if( s ) rr_ptrdname = s; + return rr_ptrdname; + } + + /*! + Clones an existing resource record object + */ + virtual shared_resource_base_t clone() const + { + return shared_resource_base_t(new ptr_resource(*this)); + } + + /// Friend to tie to the containers in the message class. + friend class message; + +protected: + /// Copy Constructor + /* + \param o ptr_resource to copy from + */ + ptr_resource(const ptr_resource& o) : resource_base_t(o), rr_ptrdname(o.rr_ptrdname) { ; } + + /// Copy Constructor + /* + \param o resource_base_t to copy from + */ + ptr_resource(const resource_base_t& o) : resource_base_t(o), rr_ptrdname() { ; } + + /// Encodes the ptr resource into a memory buffer + /* + \param buffer Buffer to encode the request into + \param offset_map DNS label compression map for label/offset values + */ + virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + resource_base_t::encode(buffer, offset_map); + + size_t lenOffset( buffer.position() - sizeof(uint16_t) ); + size_t len = offset_map.write_label(rr_ptrdname, buffer); + + buffer.put( (uint16_t)len, lenOffset, false ); + } + + /// Decodes the ptr resource into a memory buffer + /* + \param buffer Buffer to decode the request into + */ + virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + offset_map.read_label(rr_ptrdname, buffer); + } +}; + +/// Definition of a HINFO resource +/** +*/ +class hinfo_resource : public resource_base_t +{ +protected: + /// CPU description + string rr_cpu; + /// OS description + string rr_os; + +public: + /// Default contructor + hinfo_resource() : resource_base_t(type_hinfo), rr_cpu(), rr_os() {;} + + /// Constructs a hinfo_resource + /* + \param s Host name for the PTR record + */ + hinfo_resource(const string& s) : resource_base_t(s, type_hinfo), rr_cpu(), rr_os() {;} + + /// Virtual Destructor + virtual ~hinfo_resource() + { + } + + /// CPU description set function + /* + \param t CPU description to assign to the hinfo_resource. + \return CPU description + */ + const string& cpu(const string& s) + { + return cpu(s.c_str()); + } + + /// CPU description get/set function + /* + \param t CPU description string to assign to the hinfo_resource. If left blank, will return the + current CPU description only. + \return CPU description + */ + const string& cpu(const char* s=0) + { + if( s ) rr_cpu = s; + return rr_cpu; + } + + /// OS description set function + /* + \param t OS description to assign to the hinfo_resource. + \return OS description + */ + const string& os(const string& s) + { + return os(s.c_str()); + } + + /// OS description get/set function + /* + \param t OS description string to assign to the hinfo_resource. If left blank, will return the + current OS description only. + \return OS description + */ + const string& os(const char* s=0) + { + if( s ) rr_os = s; + return rr_os; + } + + /*! + Clones an existing resource record object + */ + virtual shared_resource_base_t clone() const + { + return shared_resource_base_t(new hinfo_resource(*this)); + } + + /// Friend to tie to the containers in the message class. + friend class message; + +protected: + /// Copy Constructor + /* + \param o hinfo_resource to copy from + */ + hinfo_resource(const hinfo_resource& o) : resource_base_t(o), rr_cpu(o.rr_cpu), rr_os(o.rr_os) { ; } + + /// Copy Constructor + /* + \param o resource_base_t to copy from + */ + hinfo_resource(const resource_base_t& o) : resource_base_t(o), rr_cpu(), rr_os() { ; } + + /// Encodes the hinfo resource into a memory buffer + /* + \param buffer Buffer to encode the request into + \param offset_map DNS label compression map for label/offset values + */ + virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + resource_base_t::encode(buffer, offset_map); + + size_t lenOffset( buffer.position() - sizeof(uint16_t) ); + size_t len(0); + + len += buffer.put( (uint8_t)rr_cpu.length() ); + len += buffer.put( rr_cpu, rr_cpu.length() ); + len += buffer.put( (uint8_t)rr_os.length() ); + len += buffer.put( rr_os, rr_os.length() ); + + // lastly, update the length field + buffer.put( (uint16_t)len, lenOffset, false ); + } + + /// Decodes the hinfo resource into a memory buffer + /* + \param buffer Buffer to decode the request into + */ + virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& /*offset_map*/) + { + uint16_t len(0); + + buffer.get(len); + buffer.get(rr_cpu, len); + + buffer.get(len); + buffer.get(rr_os, len); + } +}; + +/// Definition of a MX resource +/* +*/ +class mx_resource : public resource_base_t +{ +protected: + /// Preference value + uint16_t rr_preference; + /// Mail Exchange(server) + string rr_exchange; + +public: + /// Default contructor + mx_resource() : resource_base_t(type_mx), rr_preference(0), rr_exchange() {} + + /// Constructs a mx_resource + /* + \param s Host name for the MX record + */ + mx_resource(const string& s) : resource_base_t(s, type_mx), rr_preference(0), rr_exchange() {} + + /// Virtual Destructor + virtual ~mx_resource() + { + } + + /// Mail exchange(server) set function + /* + \param t Mail exchange(server) to assign to the mx_resource. + \return Mail exchange(server) + */ + const string& exchange(const string& s) + { + return exchange(s.c_str()); + + } + + /// Mail Exchange(server) get/set function + /* + \param t Mail exchange(server) string to assign to the mx_resource. If left blank, will return the + current mail exchange(server) only. + \return Mail exchange(server) + */ + const string& exchange(const char* s=0) + { + if( s ) rr_exchange = s; + return rr_exchange; + } + + /// Preference value get/set function + /* + \param t Preference value to assign to the mx_resource. If left blank, will return the + current preference value only. + \return Preference value + */ + uint16_t preference(const uint16_t d = 0xffff) + { + if( d != 0xffff ) rr_preference = d; + return rr_preference; + } + + /*! + Clones an existing resource record object + */ + virtual shared_resource_base_t clone() const + { + return shared_resource_base_t(new mx_resource(*this)); + } + + /// Friend to tie to the containers in the message class. + friend class message; + +protected: + /// Copy Constructor + /* + \param o mx_resource to copy from + */ + mx_resource(const mx_resource& o) + : resource_base_t(o), + rr_preference(o.rr_preference), + rr_exchange(o.rr_exchange) + { + ; + } + + /// Copy Constructor + /* + \param o resource_base_t to copy from + */ + mx_resource(const resource_base_t& o) + : resource_base_t(o), + rr_preference(0), + rr_exchange() + { } + + + /// Encodes the mx resource into a memory buffer + /* + \param buffer Buffer to encode the request into + \param offset_map DNS label compression map for label/offset values + */ + virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + resource_base_t::encode(buffer, offset_map); + + size_t lenOffset( buffer.position() - sizeof(uint16_t) ); + size_t len(0); + + len += buffer.put( rr_preference ); + len += offset_map.write_label(rr_exchange, buffer); + + // lastly, update the length field + buffer.put( (uint16_t)len, lenOffset, false ); + } + + /// Decodes the mx resource into a memory buffer + /* + \param buffer Buffer to decode the request into + */ + virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + buffer.get( rr_preference ); + offset_map.read_label(rr_exchange, buffer); + } + +}; + +/// Definition of a TXT resource +/** +*/ +class txt_resource : public resource_base_t +{ +protected: + /// Text string + string rr_text; + +public: + /// Default contructor + txt_resource() : resource_base_t(type_txt), rr_text() {;} + + /// Constructs a txt_resource + /* + \param s Host name for the TXT record + */ + txt_resource(const string& s) : resource_base_t(s, type_txt), rr_text(s) {;} + + /// Virtual Destructor + virtual ~txt_resource() + { + } + + /// Text string set function + /* + \param t Text string to assign to the txt_resource. + \return Text string + */ + const string& text(const string& s) + { + return text(s.c_str()); + } + + /// Text string get/set function + /* + \param t Text string to assign to the txt_resource. If left blank, will return the + current text string only. + \return Text string + */ + const string& text(const char* s=0) + { + if( s ) rr_text = s; + return rr_text; + } + + /*! + Clones an existing resource record object + */ + virtual shared_resource_base_t clone() const + { + return shared_resource_base_t(new txt_resource(*this)); + } + + /// Friend to tie to the containers in the message class. + friend class message; + +protected: + /// Copy Constructor + /* + \param o txt_resource to copy from + */ + txt_resource(const txt_resource& o) : resource_base_t(o), rr_text(o.rr_text) { ; } + + /// Copy Constructor + /* + \param o resource_base_t to copy from + */ + txt_resource(const resource_base_t& o) : resource_base_t(o), rr_text() { ; } + + /// Encodes the txt resource into a memory buffer + /* + \param buffer Buffer to encode the request into + \param offset_map DNS label compression map for label/offset values + */ + virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + resource_base_t::encode(buffer, offset_map); + + size_t lenOffset( buffer.position() - sizeof(uint16_t) ); + size_t len(0); + + len += buffer.put( (uint8_t)rr_text.length() ); + len += buffer.put( rr_text, rr_text.length() ); + + // lastly, update the length field + buffer.put( (uint16_t)len, lenOffset, false ); + } + + /// Decodes the txt resource into a memory buffer + /* + \param buffer Buffer to decode the request into + */ + virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& /*offset_map*/) + { + uint8_t len; + buffer.get(len); + buffer.get(rr_text, len); + } + +}; + +/// Definition for an A6 resource record +/* +*/ +class a6_resource : public resource_base_t +{ +protected: + /// IP 6 address + ip::address_v6 rr_address; + +public: + /// Default contructor + a6_resource() : resource_base_t(type_a6), rr_address() {;} + + /// Constructs a a6_resource + /* + \param s Host name for the A record + */ + a6_resource(const string& s) : resource_base_t(s, type_a6), rr_address() {;} + + /// Virtual Destructor + virtual ~a6_resource() + { + } + + /// Address set function + /* + \param t Address to assign to the a6_resource. + \return Address + */ + const ip::address_v6& address(const ip::address_v6& addr) + { + rr_address = addr; + return rr_address; + } + + /// Address get/set function + /* + \param t Dotted decimal address string to assign to the a6_resource. If left blank, will return the + current address only. + \return Address + */ + const ip::address_v6& address(const char* s=0) + { + if( s != 0 ) return address(ip::address_v6::from_string(s)); + return rr_address; + } + + /*! + Clones an existing resource record object + */ + virtual shared_resource_base_t clone() const + { + return shared_resource_base_t(new a6_resource(*this)); + } + + /// Friend to tie to the containers in the message class. + friend class message; + +protected: + /// Copy Constructor + /* + \param o a6_resource to copy from + */ + a6_resource(const a6_resource& o) : resource_base_t(o), rr_address(o.rr_address) { ; } + + /// Copy Constructor + /* + \param o resource_base_t to copy from + */ + a6_resource(const resource_base_t& o) : resource_base_t(o), rr_address() { ; } + + /// Encodes the a resource into a memory buffer + /* + \param buffer Buffer to encode the request into + \param offset_map DNS label compression map for label/offset values + */ + virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + resource_base_t::encode(buffer, offset_map); + + // the length offset for the resource record + size_t lenOffset( buffer.position() - sizeof(uint16_t) ); + + size_t len(0); + + len = buffer.put( rr_address ); + + // lastly, update the length field + buffer.put( (uint16_t)len, lenOffset, false ); + } + + /// Decodes the a resource into a memory buffer + /* + \param buffer Buffer to decode the request into + */ + virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& /*offset_map*/) + { + buffer.get(rr_address); + } +}; + +/// Definition of a SRV resource +/* +*/ +class srv_resource : public resource_base_t +{ +protected: + uint16_t rr_priority; //!< Priority of the target host + uint16_t rr_weight; //!< Weight of the record, used as a selection method + uint16_t rr_port; //!< Port for the target host's service + string rr_target; //!< Target name of the host + +public: + /// Default contructor + srv_resource() + : resource_base_t(type_srv), + rr_priority(0), + rr_weight(0), + rr_port(0), + rr_target() + { + ; + } + + /// Constructs a srv_resource + /* + \param s Host name for the TXT record + */ + srv_resource(const string& s) + : resource_base_t(s, type_srv), + rr_priority(0), + rr_weight(0), + rr_port(0), + rr_target(s) + { + ; + } + + /// Virtual Destructor + virtual ~srv_resource() + { + } + + /// Priority value get/set function + /* + \param t Priority value to assign to the srv_resource. If left blank, will return the current priority value only. + \return Priority value + */ + uint16_t priority(const uint16_t d = 0xffff) + { + if( d != 0xffff ) rr_priority = d; + return rr_priority; + } + + /// Weight value get/set function + /* + \param t Weight value to assign to the srv_resource. If left blank, will return the current weight value only. + \return Weight value + */ + uint16_t weight(const uint16_t d = 0xffff) + { + if( d != 0xffff ) rr_weight = d; + return rr_weight; + } + + /// Port value get/set function + /* + \param t Port value to assign to the srv_resource. If left blank, will return the current port value only. + \return Port value + */ + uint16_t port(const uint16_t d = 0xffff) + { + if( d != 0xffff ) rr_port = d; + return rr_port; + } + + /// Target host set function + /* + \param t Target host string to assign to the srv_resource. + \return Target host string + */ + const string& targethost(const string& s) + { + return targethost(s.c_str()); + + } + + /// Target host get/set function + /* + \param t Target host name to assign to the srv_resource. If left blank, will return the current target host string only. + \return Target host string + */ + const string& targethost(const char* s=0) + { + if( s ) rr_target = s; + return rr_target; + } + + /*! + Clones an existing resource record object + */ + virtual shared_resource_base_t clone() const + { + return shared_resource_base_t(new srv_resource(*this)); + } + + /// Friend to tie to the containers in the message class. + friend class message; + +protected: + /// Copy Constructor + /* + \param o srv_resource to copy from + */ + srv_resource(const srv_resource& o) + : resource_base_t(o), + rr_priority(o.rr_priority), + rr_weight(o.rr_weight), + rr_port(o.rr_port), + rr_target(o.rr_target) + { + ; + } + + /// Copy Constructor + /* + \param o resource_base_t to copy from + */ + srv_resource(const resource_base_t& o) + : resource_base_t(o), + rr_priority(0), + rr_weight(0), + rr_port(0), + rr_target() + { + ; + } + + + /// Encodes the srv resource into a memory buffer + /* + \param buffer Buffer to encode the request into + \param offset_map DNS label compression map for label/offset values + */ + virtual void encode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + resource_base_t::encode(buffer, offset_map); + + size_t lenOffset( buffer.position() - sizeof(uint16_t) ); + size_t len(0); + + len += buffer.put(rr_priority); + len += buffer.put(rr_weight); + len += buffer.put(rr_port); + len += offset_map.write_label(rr_target, buffer); + + // lastly, update the length field + buffer.put( (uint16_t)len, lenOffset, false ); + } + + /// Decodes the srv resource into a memory buffer + /* + \param buffer Buffer to decode the request into + */ + virtual void decode(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + buffer.get(rr_priority); + buffer.get(rr_weight); + buffer.get(rr_port); + offset_map.read_label(rr_target, buffer); + } + +}; + +/// DNS Request/Response Message +/** +*/ +class message +{ +private: + /// Bit fields for the header + typedef struct bit_fields_header + { + /// Defines the action of the message, query/response + uint16_t Action:1, + /// Operation code of the message + OpCode:4, + /// Defines if the message is from an authority + Authority:1, + /// Defines if the message was truncated due to size limitation of the transmission channel + Truncated:1, + /// Defines if name server being queried should recursively find an answer. + RD:1, + /// Defines if the names server supports recursive queries + RA:1, + /// Reserved bits + Z:3, + /// Response code for the query + RCODE:4; + } bit_fields_header; + + /// Header bytes of the message + typedef struct opaque_header + { + /// Message id + uint16_t Id; + /// Bitfields as defined in the bit_fields_header structure + uint16_t bit_fields; + /// Question count + uint16_t QdCount; + /// Resource record answer count + uint16_t AnCount; + /// Name server count + uint16_t NsCount; + /// Additional resource records + uint16_t ArCount; + } opaque_header; + +public: + /// Used by the action field of the header + typedef enum + { + /// No action to take. + no_action = -1, + /// Query the name server + query = 0, + /// Response from the name server + response + } action_t; + + /// Specifies the type of request operation. + typedef enum + { + /// No operation to take + no_opcode = -1, + /// Standard query + squery = 0, + /// Inverse query + iquery, + /// Server status query + status + } opcode_t; + + /// Response codes from a request operation + typedef enum + { + /// No error + noerror = 0, + /// Message is malformed + format_error, + /// Server had an internal error + server_error, + /// The domain name does not exist on the name server being queried + name_error, + /// Name server does not support the query + not_implemented, + /// Name server refused the request + refused, + /// No result + no_result + } result_t; + + /// A list of questions + typedef std::vector questions_t; + +private: + /// Header bytes of the message + uint8_t header[sizeof(opaque_header)]; + + /// Question list + questions_t question_section; + /// Answer list + rr_list_t answer_section; + /// Authoritative records list + rr_list_t authority_section; + /// Additional records list + rr_list_t additional_section; + +public: + /// Default constructor + message() + : question_section(), + answer_section(), + authority_section(), + additional_section() + { + memset(&header, 0x00, sizeof(header)); + } + + /*! + Constructs a query message with a default question + + \param q question to ask + */ + message( const dns::question& q) + : question_section(), + answer_section(), + authority_section(), + additional_section() + { + memset(&header, 0x00, sizeof(header)); + question_section.push_back( q ); + + recursive(true); + action(dns::message::query); + opcode(dns::message::squery); + } + + /*! + Constructs a query message with a default question + + \param d Domain to query + \param t Resource type to query + */ + message(const string & d, const type_t t) + : question_section(), + answer_section(), + authority_section(), + additional_section() + { + memset(&header, 0x00, sizeof(header)); + question_section.push_back( dns::question(d, t) ); + + recursive(true); + action(dns::message::query); + opcode(dns::message::squery); + } + + /*! + Copy constructor + + \param p message to copy from + */ + message(const message& p) + : question_section(), + answer_section(), + authority_section(), + additional_section() + { + operator=(p); + } + + /*! + Assignment operator + + \param p message to assign from + */ + message& operator=(const message& p) + { + memcpy(&header, &p.header, sizeof(header)); + + rr_list_t::const_iterator rIter; + questions_t::const_iterator qIter; + + question_section.clear(); + for( qIter = p.question_section.begin(); qIter != p.question_section.end(); ++qIter) + question_section.push_back( (*qIter) ); + + answer_section.clear(); + for( rIter = p.answer_section.begin(); rIter != p.answer_section.end(); ++rIter) + answer_section.push_back( (*rIter) ); + + authority_section.clear(); + for( rIter = p.authority_section.begin(); rIter != p.authority_section.end(); ++rIter) + authority_section.push_back( (*rIter) ); + + additional_section.clear(); + for( rIter = p.additional_section.begin(); rIter != p.additional_section.end(); ++rIter) + additional_section.push_back( (*rIter) ); + + return *this; + } + + /*! + Set the message id + \param d Message id to assign to the message + \return id + */ + uint16_t id(const uint16_t d) + { + ((opaque_header*)header)->Id = d; + return ((opaque_header*)header)->Id; + } + + /*! + Get the message id + + \return id + */ + uint16_t id() const + { + return ((opaque_header*)header)->Id; + } + + /*! + Sets the Query action + + \param e Query action to assign to the message. + \return query action + */ + action_t action(const action_t e) + { + (e == query) ? + ((opaque_header*)header)->bit_fields &= static_cast(~0x8000) : + ((opaque_header*)header)->bit_fields |= static_cast(0x8000); + + return (action_t)(((opaque_header*)header)->bit_fields & 0x8000); + } + + /*! + Gets the Query action + + \return query action + */ + action_t action() const + { + return (action_t)(((opaque_header*)header)->bit_fields & 0x8000); + } + + + /*! + Sets the Opcode + + \param oc Opcode to assign to the message. + \return Opcode + */ + opcode_t opcode(const opcode_t oc) + { + switch( oc ) + { + case squery: + ((opaque_header*)header)->bit_fields &= static_cast(~0x3000); + return squery; + case iquery: + ((opaque_header*)header)->bit_fields |= 0x1000; + return iquery; + case status: + ((opaque_header*)header)->bit_fields |= 0x2000; + return status; + case no_opcode: + break; + } + + if( ((opaque_header*)header)->bit_fields & 0x1000 ) + return iquery; + if( ((opaque_header*)header)->bit_fields & 0x2000 ) + return status; + + return squery; + } + + /*! + Gets the Opcode + + \return Opcode + */ + opcode_t opcode() const + { + if( ((opaque_header*)header)->bit_fields & 0x1000 ) + return iquery; + if( ((opaque_header*)header)->bit_fields & 0x2000 ) + return status; + + return squery; + } + + /*! + Sets the 'authority' field + + Setting the 'authority' field is a function used by servers that are answering a request. + + \param _authority True if the server answering is the authority + */ + void authority(const bool _authority) + { + (_authority) ? ((opaque_header*)header)->bit_fields |= static_cast(0x400) : + ((opaque_header*)header)->bit_fields &= static_cast(~0x400); + } + + /*! + Gets the 'authority' field + + \return True if the server answering is the authority + */ + bool is_authority() const + { + return( ((opaque_header*)header)->bit_fields & 0x400 ); + } + + /*! + Sets the 'truncated' field. + + Setting the 'truncated' field is a function used by servers to notify the + client that message has been truncated, due to the large volume of answers. + + \param _truncated True if the server is truncating + */ + void truncated(const bool _truncated) + { + (_truncated) ? ((opaque_header*)header)->bit_fields |= static_cast(0x200) : + ((opaque_header*)header)->bit_fields &= static_cast(~0x200); + } + + /*! + Gets the 'truncated' field + + \return True if the server is truncating the message + */ + bool is_truncated() const { return( ((opaque_header*)header)->bit_fields & 0x200 ); } + + /*! + Sets the 'recursive' field. + + Setting the 'recursive' field is a function used by clients to notify the + server that message if the DNS question is not answerable by the server, the + server can ask other DNS servers for a response. + + \param recursive True if the server should recursively seek an answer. + */ + void recursive(const bool _recursive) + { + (_recursive) ? ((opaque_header*)header)->bit_fields |= static_cast(0x100) : + ((opaque_header*)header)->bit_fields &= static_cast(~0x100); + } + + /*! + Gets the 'recursive' field. + + \return True if the server can recursively seek an answer. + */ + bool is_recursive() const { return( ((opaque_header*)header)->bit_fields & 0x100 ); } + + /*! + Sets the 'recursion availability' field. + + Setting the 'recursion availability' field is a function used by servers to notify the + client that recursion is supported. Some servers are only authority servers and do not + act as proxies when the domain does not reside with them. + + \param _recursion_avail True if the server can recursively seek an answer. + */ + void recursion_avail(const bool _recursion_avail) + { + (_recursion_avail) ? ((opaque_header*)header)->bit_fields |= static_cast(0x80) : + ((opaque_header*)header)->bit_fields &= static_cast(~0x80); + } + + /*! + Gets the 'recursion availability' field. + + \return True if the server can recursively seek an answer. + */ + bool is_recursion_avail() const + { + return( ((opaque_header*)header)->bit_fields & 0x80 ); + } + + /*! + Sets the result code for the message. + + \param r Result code to assign to the message + \return Result code + */ + result_t result(const result_t r) + { + switch( r ) + { + case noerror: + ((opaque_header*)header)->bit_fields &= static_cast(~0x07); + break; + + default: + ((opaque_header*)header)->bit_fields |= static_cast(r); + break; + } + + if( ((opaque_header*)header)->bit_fields & 0x01 ) + return format_error; + + if( ((opaque_header*)header)->bit_fields & 0x02 ) + return server_error; + + if( ((opaque_header*)header)->bit_fields & 0x03 ) + return name_error; + + if( ((opaque_header*)header)->bit_fields & 0x04 ) + return not_implemented; + + if( ((opaque_header*)header)->bit_fields & 0x05 ) + return refused; + + if( ((opaque_header*)header)->bit_fields & 0x06 ) + return no_result; + + return noerror; + } + + /*! + Gets the result code for the message. + + \return Result code + */ + result_t result() const + { + if( ((opaque_header*)header)->bit_fields & 0x01 ) + return format_error; + + if( ((opaque_header*)header)->bit_fields & 0x02 ) + return server_error; + + if( ((opaque_header*)header)->bit_fields & 0x03 ) + return name_error; + + if( ((opaque_header*)header)->bit_fields & 0x04 ) + return not_implemented; + + if( ((opaque_header*)header)->bit_fields & 0x05 ) + return refused; + + if( ((opaque_header*)header)->bit_fields & 0x06 ) + return no_result; + + return noerror; + } + + /// Returns the questions container + questions_t* questions() { return &question_section; } + /// Returns the answers container + rr_list_t* answers() { return &answer_section; } + /// Returns the authorites container + rr_list_t* authorites() { return &authority_section; } + /// Returns the additionals container + rr_list_t* additionals() { return &additional_section; } + + /// Encodes the dns message into a memory buffer + /* + \param buffer Buffer to encode the message into + */ + void encode(dns_buffer_t& buffer) + { + // reset the buffer to the 0th position and reset the length + buffer.position(0); + + rfc1035_414_t offset_map; + + buffer.put( ((opaque_header*)header)->Id ); + buffer.put( ((opaque_header*)header)->bit_fields ); + buffer.put( (uint16_t)question_section.size() ); + buffer.put( (uint16_t)answer_section.size() ); + buffer.put( (uint16_t)authority_section.size() ); + buffer.put( (uint16_t)additional_section.size() ); + + questions_t::iterator qiter; + for( qiter = question_section.begin(); qiter != question_section.end(); ++qiter ) + ((question)*qiter).encode(buffer, offset_map); + + rr_list_t::iterator riter; + for( riter = answer_section.begin(); riter != answer_section.end(); ++riter ) + (*riter)->encode(buffer, offset_map); + for( riter = authority_section.begin(); riter != authority_section.end(); ++riter ) + (*riter)->encode(buffer, offset_map); + for( riter = additional_section.begin(); riter != additional_section.end(); ++riter ) + (*riter)->encode(buffer, offset_map); + } + + /// Decodes the dns message into a memory buffer + /* + \param buffer Buffer to decode the message into + */ + void decode(dns_buffer_t& buffer) + { + // clean out the different sections + question_section.erase(question_section.begin(), question_section.end()); + answer_section.erase(answer_section.begin(), answer_section.end()); + authority_section.erase(authority_section.begin(), authority_section.end()); + additional_section.erase(additional_section.begin(), additional_section.end()); + + // start at 0th + buffer.position(0); + + opaque_header* pHeader = (opaque_header*)header; + + buffer.get( pHeader->Id ); + buffer.get( pHeader->bit_fields ); + buffer.get( pHeader->QdCount ); + buffer.get( pHeader->AnCount ); + buffer.get( pHeader->NsCount ); + buffer.get( pHeader->ArCount ); + + rfc1035_414_t offset_map; + + // read the sections + for( uint16_t i = 0; i < pHeader->QdCount; ++ i ) + question_section.push_back( question(buffer, offset_map) ); + + for( uint16_t i = 0; i < pHeader->AnCount; ++ i ) + answer_section.push_back( unpack_record(buffer,offset_map) ); + + for( uint16_t i = 0; i < pHeader->NsCount; ++ i ) + authority_section.push_back( unpack_record(buffer,offset_map) ); + + for( uint16_t i = 0; i < pHeader->ArCount; ++ i ) + additional_section.push_back( unpack_record(buffer,offset_map) ); + } + +private: + shared_resource_base_t unpack_record(dns_buffer_t& buffer, rfc1035_414_t& offset_map) + { + shared_resource_base_t ptr; + + /* + catch 22, can't decode a "type" unless we know the "type" + So, we treat this as a pre-amble to the data and then decode the payload later + */ + resource_base_t preamble; + preamble.decode(buffer, offset_map); + + switch( preamble.rtype() ) + { + case type_a: + { + dns::a_resource* aPtr = new dns::a_resource(preamble); + aPtr->decode(buffer, offset_map); + ptr = shared_resource_base_t(aPtr); + } + break; + case type_ns: + { + dns::ns_resource* nsPtr = new dns::ns_resource(preamble); + nsPtr->decode(buffer, offset_map); + ptr = shared_resource_base_t(nsPtr); + } + break; + case type_cname: + { + dns::cname_resource* cnamePtr = new dns::cname_resource(preamble); + cnamePtr->decode(buffer, offset_map); + ptr = shared_resource_base_t(cnamePtr); + } + break; + case type_soa: + { + dns::soa_resource* soaPtr = new dns::soa_resource(preamble); + soaPtr->decode(buffer, offset_map); + ptr = shared_resource_base_t(soaPtr); + } + break; + case type_ptr: + { + dns::ptr_resource* ptrPtr = new dns::ptr_resource(preamble); + ptrPtr->decode(buffer, offset_map); + ptr = shared_resource_base_t(ptrPtr); + } + break; + case type_hinfo: + { + dns::hinfo_resource* hinfoPtr = new dns::hinfo_resource(preamble); + hinfoPtr->decode(buffer, offset_map); + ptr = shared_resource_base_t(hinfoPtr); + } + break; + case type_mx: + { + dns::mx_resource* mxPtr = new dns::mx_resource(preamble); + mxPtr->decode(buffer, offset_map); + ptr = shared_resource_base_t(mxPtr); + } + break; + case type_txt: + { + dns::txt_resource* txtPtr = new dns::txt_resource(preamble); + txtPtr->decode(buffer, offset_map); + ptr = shared_resource_base_t(txtPtr); + } + break; + case type_a6: + { + dns::a6_resource* a6Ptr = new dns::a6_resource(preamble); + a6Ptr->decode(buffer, offset_map); + ptr = shared_resource_base_t(a6Ptr); + } + break; + case type_srv: + { + dns::srv_resource* srvPtr = new dns::srv_resource(preamble); + srvPtr->decode(buffer, offset_map); + ptr = shared_resource_base_t(srvPtr); + } + break; + default: + { + // An unknown record. Save the data and move on. + unknown_resource *unkPtr = new unknown_resource(preamble); + unkPtr->decode(buffer, offset_map); + ptr = shared_resource_base_t(unkPtr); + } + break; + } + + return ptr; + } +}; + + } // namespace dns + } // namespace net +} // namespace boost + +#include + +#endif // BOOST_NET_DNS_HPP diff --git a/lib/boost-net-dns/boost/net/dns_cache.hpp b/lib/boost-net-dns/boost/net/dns_cache.hpp new file mode 100755 index 0000000..18463a9 --- /dev/null +++ b/lib/boost-net-dns/boost/net/dns_cache.hpp @@ -0,0 +1,388 @@ +// +// dns_cache.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2008 Andreas Haberstroh (andreas at ibusy dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#ifndef BOOST_NET_DNS_CACHE_HPP +#define BOOST_NET_DNS_CACHE_HPP + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::multi_index; +using namespace boost::posix_time; +using namespace std; + +namespace boost { + namespace net { + namespace dns { + + /*! + Implementation for a simple DNS cache. + This cache uses two methods to remove a "stale" record. + + #1 - Expiration date + + #2 - Hit count + + */ + class dns_cache_t + { + private: + + /*! + + */ + struct dns_hasher + { + public: + /*! + */ + static size_t query(const string& domain, const type_t rType, const class_t rClass = class_in) + { + boost::hash hString; + boost::hash hType; + boost::hash hClass; + return size_t(hString(domain) + hType(rType) + hClass(rClass)); + } + + /*! + */ + static std::size_t query(const request_base_t& dnr) + { + return query(dnr.domain(), dnr.rtype(), dnr.rclass()); + } + + /*! + */ + static std::size_t query(const shared_resource_base_t& dnr) + { + return query(dnr->domain(), dnr->rtype(), dnr->rclass()); + } + + /*! + */ + static std::size_t record(const shared_resource_base_t& rr) + { + std::size_t hashCode(dns_hasher::query(rr)); + + boost::hash h32; + boost::hash hString; + + switch( rr->rtype() ) + { + case type_a: + hashCode += h32( ((a_resource*)rr.get())->address().to_ulong() ); + break; + case type_ns: + hashCode += hString( ((ns_resource*)rr.get())->nameserver() ); + break; + case type_cname: + hashCode += hString( ((cname_resource*)rr.get())->canonicalname() ); + break; + case type_soa: + hashCode += h32( ((soa_resource*)rr.get())->serial_number() ); + break; + case type_ptr: + hashCode += hString( ((ptr_resource*)rr.get())->pointer() ); + break; + case type_mx: + hashCode += hString( ((mx_resource*)rr.get())->exchange() ) + h32( ((mx_resource*)rr.get())->preference() ); + break; + + case type_a6: + case type_srv: + break; + + case type_none: + case type_hinfo: + case type_txt: + case type_axfr: + case type_all: + break; + + } + + return hashCode; + } + }; + + /*! + */ + struct rr_cache + { + size_t _rHash; + size_t _qHash; + size_t _dHash; + uint32_t _hits; + time_period _expirationTime; + ptime _timeRetrieved; + bool _perm; + + shared_resource_base_t record; + + /*! + */ + rr_cache(const shared_resource_base_t& rr, const bool perm) + : _hits(0), + _expirationTime(second_clock::local_time(), seconds(rr->ttl())), + _timeRetrieved(second_clock::local_time()), + _perm(perm), + record(rr) + { + _rHash = dns_hasher::record(rr); + _qHash = dns_hasher::query(rr); + + boost::hash hString; + _dHash = hString(record.get()->domain()); + } + + /*! + */ + virtual ~rr_cache() + { + } + + /*! + */ + bool expired() const + { + if( _perm ) + return false; + + ptime nowTime = second_clock::local_time(); + return (!_expirationTime.contains(nowTime)); + } + + uint32_t hits() const + { + if( _perm ) + return 0xFFFFFFFF; + + return _hits; + } + + }; + /*! + */ + typedef shared_ptr shared_rr_cache; + + struct by_d{}; + struct by_r{}; + struct by_q{}; + struct by_hits{}; + struct by_ttl{}; +#if !defined(GENERATING_DOCUMENTATION) + /*! + */ + typedef boost::multi_index::multi_index_container< + shared_rr_cache, + boost::multi_index::indexed_by< + boost::multi_index::hashed_non_unique< + boost::multi_index::tag, + boost::multi_index::member + >, + boost::multi_index::hashed_unique< + boost::multi_index::tag, + boost::multi_index::member + >, + boost::multi_index::hashed_non_unique< + boost::multi_index::tag, + boost::multi_index::member + >, + boost::multi_index::ordered_non_unique< + boost::multi_index::tag, + boost::multi_index::const_mem_fun + >, + boost::multi_index::ordered_non_unique< + boost::multi_index::tag, + boost::multi_index::const_mem_fun + > + > + > rr_container_t; +#endif + typedef rr_container_t::index::type::iterator d_iter_t; + typedef rr_container_t::index::type::iterator r_iter_t; + typedef rr_container_t::index::type::iterator q_iter_t; + typedef rr_container_t::index::type::iterator hits_iter_t; + typedef rr_container_t::index::type::iterator ttl_iter_t; + + /// + rr_container_t _cache; + /// + const uint32_t _max_elements; + /// + boost::mutex _mutex; + + public: + /*! + */ + dns_cache_t() + : _max_elements(16) + { + } + + /*! + */ + bool exists(const question& q) + { + boost::mutex::scoped_lock scopeLock(_mutex); + + size_t qHash = dns_hasher::query(q); + + q_iter_t rrIter = _cache.get().find(qHash); + if( rrIter == _cache.get().end() ) + return false; + + return true; + } + + /*! + */ + bool exists(const std::string& domain, const type_t rType) + { + question q(domain,rType); + return exists(q); + } + + /*! + */ + rr_list_t get(const question& q) + { + boost::mutex::scoped_lock scopeLock(_mutex); + + rr_list_t retList; + + std::pair rrIter = _cache.get().equal_range(dns_hasher::query(q)); + while( rrIter.first != rrIter.second ) + { + (*rrIter.first)->_hits++; + (*rrIter.first)->_timeRetrieved = second_clock::local_time(); + + retList.push_back( (*rrIter.first)->record ); + rrIter.first++; + } + + return retList; + } + + /*! + */ + rr_list_t get(const std::string& domain, const type_t rType) + { + question q(domain,rType); + return get(q); + } + + /*! + */ + void add(const shared_resource_base_t& rr, const bool perm = false) + { + if( _cache.size() > _max_elements ) + reserve(4, *rr.get() ); + + boost::mutex::scoped_lock scopeLock(_mutex); + shared_rr_cache rrItem(new rr_cache(rr,perm)); + _cache.insert(rrItem); + } + + /*! + */ + void reserve(const size_t reserve_count, request_base_t& q) + { + size_t cacheSize = _cache.size(); + if( cacheSize < (_max_elements - reserve_count) ) + return ; + + expiredCleanup(reserve_count, q); + cacheSize = _cache.size(); + if( reserve_count < (_max_elements - _cache.size()) ) + return; + + uint32_t lowMark(0); + while( reserve_count > (_max_elements - _cache.size()) ) + lowestHitCleanup(reserve_count, q, lowMark++); + } + + /*! + */ + void show_cache() + { + d_iter_t iter; + + for( iter = _cache.get().begin(); iter != _cache.get().end(); ++iter ) + { + cout << "+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+" << endl + << " Hits: " << (*iter)->_hits << endl + << " Lifetime at: " << to_simple_string((*iter)->_expirationTime) << endl + << "Last Retrieved: " << to_simple_string((*iter)->_timeRetrieved) << endl; + debug::dump_record(cout, (*iter)->record.get() ); + } + } + + private: + /*! + */ + int expiredCleanup(size_t reserve_count, request_base_t& q) + { + boost::mutex::scoped_lock scopeLock(_mutex); + int count(0); + std::pair range_iter; + for( + range_iter = _cache.get().equal_range(true); + range_iter.first != range_iter.second; + ++range_iter.first, ++count ) + { + if( q.domain() != (*range_iter.first)->record->domain() ) + { + _cache.get().erase(range_iter.first); + if( --reserve_count == 0 ) + break; + } + } + + return count; + } + + /*! + */ + uint32_t lowestHitCleanup(size_t reserve_count, request_base_t& q, uint32_t lowMark = 0) + { + boost::mutex::scoped_lock scopeLock(_mutex); + int count(0); + + std::pair range_iter; + for( + range_iter = _cache.get().equal_range(lowMark); + range_iter.first != range_iter.second; + ++range_iter.first, ++count ) + { + if( q.domain() != (*range_iter.first)->record->domain() ) + { + _cache.get().erase(range_iter.first); + if( --reserve_count == 0 ) + break; + } + } + + return count; + } + }; + + } // namespace dns + } // namespace net +} // namespace boost + +#endif // BOOST_NET_DNS_CACHE_HPP diff --git a/lib/boost-net-dns/boost/net/dns_debug.hpp b/lib/boost-net-dns/boost/net/dns_debug.hpp new file mode 100755 index 0000000..b3ec92d --- /dev/null +++ b/lib/boost-net-dns/boost/net/dns_debug.hpp @@ -0,0 +1,293 @@ +// +// dns_debug.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 1998-2006 Andreas Haberstroh (andreas at ibusy dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#ifndef BOOST_NET_DNS_DEBUG_HPP +#define BOOST_NET_DNS_DEBUG_HPP + +#include + +#include + +namespace boost { + namespace net { + namespace dns { + +/*! +The debug class offers some quick functions used for debuging DNS records +*/ +class debug +{ +public: + /*! + Returns a string representation of a class_t type. + \param qclass Class to retrieve the string name of + \returns String name of the class + */ + static const char *get_class_string(const dns::class_t qclass) + { + + switch( qclass ) + { + case dns::class_in: + return "IN"; + + case dns::class_cs: + return "CSNET"; + + case dns::class_ch: + return "CHAOS"; + + case dns::class_hs: + return "Hesiod"; + + case dns::class_all: + return "All"; + + case dns::class_none: + return "!CLASS NOT SET!"; + break; + } + + return "!INVALID CLASS!"; + } + + /*! + Returns a string representation of a type_t type. + \param qtype Type to retrieve the string name of + \returns String name of the type + */ + static const char *get_type_string(const dns::type_t qtype) + { + switch( qtype ) + { + case dns::type_a: + return "A"; + + case dns::type_ns: + return "NS"; + + case dns::type_cname: + return "CNAME"; + + case dns::type_soa: + return "SOA"; + + case dns::type_ptr: + return "PTR"; + + case dns::type_hinfo: + return "HINFO"; + + case dns::type_mx: + return "MX"; + + case dns::type_txt: + return "TXT"; + + case dns::type_a6: + return "AAAA"; + + case dns::type_srv: + return "SRV"; + + case dns::type_axfr: + return "AXFR"; + + case dns::type_all: + return "ALL"; + + case dns::type_none: + return "!TYPE NOT SET!"; + } + + return "!INVALID TYPE!"; + } + + static void dump_a(ostream& strm, dns::resource_base_t* Ptr) + { + strm + << ((dns::a_resource*)Ptr)->domain() << "\t" + << ((dns::a_resource*)Ptr)->ttl() << "\t" + << get_class_string(((dns::a_resource*)Ptr)->rclass()) << "\t" + << get_type_string(((dns::a_resource*)Ptr)->rtype()) << "\t" + << ((dns::a_resource*)Ptr)->address().to_string() << endl; + } + + static void dump_a6(ostream& strm, dns::resource_base_t* Ptr) + { + try + { + strm + << ((dns::a6_resource*)Ptr)->domain() << "\t" + << ((dns::a6_resource*)Ptr)->ttl() << "\t" + << get_class_string(((dns::a6_resource*)Ptr)->rclass()) << "\t" + << get_type_string(((dns::a6_resource*)Ptr)->rtype()) << "\t" + << ((dns::a6_resource*)Ptr)->address().to_string() << endl; + } + catch(boost::system::error_code& ec) + { + strm << ec.message() << endl; + } + } + + static void dump_ns(ostream& strm, dns::resource_base_t* Ptr) + { + strm + << ((dns::ns_resource*)Ptr)->domain() << "\t" + << ((dns::ns_resource*)Ptr)->ttl() << "\t" + << get_class_string(((dns::ns_resource*)Ptr)->rclass()) << "\t" + << get_type_string(((dns::ns_resource*)Ptr)->rtype()) << "\t" + << ((dns::ns_resource*)Ptr)->nameserver() << endl; + } + + static void dump_mx(ostream& strm, dns::resource_base_t* Ptr) + { + strm + << ((dns::mx_resource*)Ptr)->domain() << "\t" + << ((dns::mx_resource*)Ptr)->ttl() << "\t" + << get_class_string(((dns::mx_resource*)Ptr)->rclass()) << "\t" + << get_type_string(((dns::mx_resource*)Ptr)->rtype()) << "\t" + << ((dns::mx_resource*)Ptr)->preference() << "\t" + << ((dns::mx_resource*)Ptr)->exchange() << endl; + } + + static void dump_soa(ostream& strm, dns::resource_base_t* Ptr) + { + strm + << ((dns::soa_resource*)Ptr)->domain() << "\t" + << ((dns::soa_resource*)Ptr)->ttl() << "\t" + << "SOA\t" + << get_class_string(((dns::soa_resource*)Ptr)->rclass()) << "\t" + << get_type_string(((dns::soa_resource*)Ptr)->rtype()) << "\t" + << ((dns::soa_resource*)Ptr)->master_name() << "\t" + << ((dns::soa_resource*)Ptr)->responsible_name() << "\t" + << ((dns::soa_resource*)Ptr)->serial_number() << "\t" + << ((dns::soa_resource*)Ptr)->refresh() << "\t" + << ((dns::soa_resource*)Ptr)->retry() << "\t" + << ((dns::soa_resource*)Ptr)->expire() << "\t" + << ((dns::soa_resource*)Ptr)->minttl() << endl; + } + + static void dump_cname(ostream& strm, dns::resource_base_t* Ptr) + { + strm + << ((dns::cname_resource*)Ptr)->domain() << "\t" + << ((dns::cname_resource*)Ptr)->ttl() << "\t" + << get_class_string(((dns::cname_resource*)Ptr)->rclass()) << "\t" + << get_type_string(((dns::cname_resource*)Ptr)->rtype()) << "\t" + << ((dns::cname_resource*)Ptr)->canonicalname() << endl; + } + + static void dump_hinfo(ostream& strm, dns::resource_base_t* Ptr) + { + strm + << ((dns::hinfo_resource*)Ptr)->domain() << "\t" + << ((dns::hinfo_resource*)Ptr)->ttl() << "\t" + << get_class_string(((dns::hinfo_resource*)Ptr)->rclass()) << "\t" + << get_type_string(((dns::hinfo_resource*)Ptr)->rtype()) << "\t" + << ((dns::hinfo_resource*)Ptr)->cpu() << "\t" + << ((dns::hinfo_resource*)Ptr)->os() << endl; + } + + static void dump_text(ostream& strm, dns::resource_base_t* Ptr) + { + strm + << ((dns::txt_resource*)Ptr)->domain() << "\t" + << ((dns::txt_resource*)Ptr)->ttl() << "\t" + << get_class_string(((dns::txt_resource*)Ptr)->rclass()) << "\t" + << get_type_string(((dns::txt_resource*)Ptr)->rtype()) << "\t" + << ((dns::txt_resource*)Ptr)->text() << endl; + } + + static void dump_ptr(ostream& strm, dns::resource_base_t* Ptr) + { + strm + << ((dns::ptr_resource*)Ptr)->domain() << "\t" + << ((dns::ptr_resource*)Ptr)->ttl() << "\t" + << get_class_string(((dns::ptr_resource*)Ptr)->rclass()) << "\t" + << get_type_string(((dns::ptr_resource*)Ptr)->rtype()) << "\t" + << ((dns::ptr_resource*)Ptr)->pointer() << endl; + } + + static void dump_srv(ostream& strm, dns::resource_base_t* Ptr) + { + strm + << ((dns::srv_resource*)Ptr)->domain() << "\t" + << ((dns::srv_resource*)Ptr)->ttl() << "\t" + << get_class_string(((dns::srv_resource*)Ptr)->rclass()) << "\t" + << get_type_string(((dns::srv_resource*)Ptr)->rtype()) << "\t" + << ((dns::srv_resource*)Ptr)->priority() << "\t" + << ((dns::srv_resource*)Ptr)->weight() << "\t" + << ((dns::srv_resource*)Ptr)->port() << "\t" + << ((dns::srv_resource*)Ptr)->targethost() << endl; + } + + /*! + Used to dump out a record to a ostream object. + \param strm Ostream to write to + \param ptr Resource base object to dump + */ + static void dump_record(ostream& strm, dns::resource_base_t * ptr ) + { + switch( ptr->rtype() ) + { + case dns::type_a: + dump_a(strm, ptr); + break; + + case dns::type_ns: + dump_ns(strm, ptr); + break; + + case dns::type_cname: + dump_cname(strm, ptr); + break; + + case dns::type_soa: + dump_soa(strm, ptr); + break; + + case dns::type_ptr: + dump_ptr(strm, ptr); + break; + + case dns::type_hinfo: + dump_hinfo(strm, ptr); + break; + + case dns::type_mx: + dump_mx(strm, ptr); + break; + + case dns::type_txt: + dump_text(strm, ptr); + break; + + case dns::type_a6: + dump_a6(strm, ptr); + break; + + case dns::type_srv: + dump_srv(strm, ptr); + break; + + default: + strm << "Unhandled record type!" << endl; + break; + } + } +}; + + } // namespace dns + } // namespace net +} // namespace boost + +#include + +#endif // BOOST_NET_DNS_DEBUG_HPP diff --git a/lib/boost-net-dns/boost/net/dns_resolver.hpp b/lib/boost-net-dns/boost/net/dns_resolver.hpp new file mode 100755 index 0000000..3a13b23 --- /dev/null +++ b/lib/boost-net-dns/boost/net/dns_resolver.hpp @@ -0,0 +1,22 @@ +// +// dns_resolver.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2008 Andreas Haberstroh (andreas at ibusy dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#ifndef BOOST_NET_DNS_RESOLVER_HPP +#define BOOST_NET_DNS_RESOLVER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // BOOST_NET_DNS_RESOLVER_HPP diff --git a/lib/boost-net-dns/boost/net/impl/dns_resolver_impl.hpp b/lib/boost-net-dns/boost/net/impl/dns_resolver_impl.hpp new file mode 100755 index 0000000..903f1a2 --- /dev/null +++ b/lib/boost-net-dns/boost/net/impl/dns_resolver_impl.hpp @@ -0,0 +1,547 @@ +// +// dns_resolver_impl.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2008 Andreas Haberstroh (andreas at ibusy dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#ifndef BOOST_NET_DNS_RESOLVER_IMPL_HPP +#define BOOST_NET_DNS_RESOLVER_IMPL_HPP + +#include + +#include +#include +#include +#include + +using namespace boost::multi_index; + +namespace boost { + namespace net { + namespace dns { + +/// Single instance of the dns cache +typedef boost::detail::thread::singleton dns_cache_object; + +class dns_resolver_impl +{ +private: + /// Outbound DNS request buffer + typedef vector ep_vector_t; + + class dns_handler_base + { + public: + dns_handler_base() + { + } + + virtual ~dns_handler_base() + { + } + + virtual void invoke(io_service& ios, const shared_resource_base_t& record, const boost::system::error_code& ec) + { + } + }; + + typedef shared_ptr dns_handler_base_t; + + /// Handler to wrap asynchronous callback function + template + class dns_handler : public dns_handler_base + { + public: + dns_handler(Handler h) + : dns_handler_base(), + handler_(h) + { + } + + virtual ~dns_handler() + { + } + + virtual void invoke(io_service& ios, const shared_resource_base_t& record, const boost::system::error_code& ec) + { + ios.post( + boost::asio::detail::bind_handler(handler_, record, ec) + ) + ; + } + + private: + Handler handler_; + }; + + /*! + DNS Query structure + */ + struct dns_query_t + { + dns_query_t(const net::dns::question& q) + : _query_start(posix_time::second_clock::local_time(), posix_time::seconds(30)), + _query_sent(posix_time::second_clock::local_time(), posix_time::seconds(2)) + { + _question = q; +// _qbuffer = shared_ptr(new net::network_buffer_t(_mbuffer.data(), _mbuffer.size())); + } + + dns_query_t(const dns_query_t& o) + : _query_start(posix_time::time_period(o._query_start.begin(), o._query_start.last())), + _query_sent(posix_time::time_period(o._query_sent.begin(), o._query_sent.last())) + { + operator=(o); + } + + virtual ~dns_query_t() + { + } + + dns_query_t& operator=(const dns_query_t& o) + { + _question_id = o._question_id; + _dns = o._dns; + _mbuffer = o._mbuffer; + // _qbuffer = o._qbuffer; + _question = o._question; + _completion_callback = o._completion_callback; + _query_start = posix_time::time_period(o._query_start.begin(), o._query_start.last()); + _query_sent = posix_time::time_period(o._query_sent.begin(), o._query_sent.last()); + return *this; + } + + /// Question ID + uint16_t _question_id; + + /// Domain Name Server Address to send request to + ip::udp::endpoint _dns; + + /// DNS Query Buffer + dns_buffer_t _mbuffer; +// shared_dns_buffer_t _qbuffer; + + /// DNS Query question + net::dns::question _question; + + /// DNS Completion handler + dns_handler_base_t _completion_callback; + + /// Time period the request is good for + posix_time::time_period _query_start; + + /// Time period which the last request was sent + posix_time::time_period _query_sent; + + bool operator<( const uint16_t& id ) const + { + return _question_id < id; + } + + bool expired() const + { + posix_time::ptime nowTime = posix_time::second_clock::local_time(); + return !_query_start.contains(nowTime); + } + + bool resend() const + { + posix_time::ptime nowTime = posix_time::second_clock::local_time(); + return _query_sent.contains(nowTime); + } + }; + + typedef shared_ptr shared_dq_t; + + struct by_question_id{}; + struct by_expired{}; + struct by_resend{}; +#if !defined(GENERATING_DOCUMENTATION) + typedef + multi_index_container< + shared_dq_t, + indexed_by< + ordered_non_unique< + tag, + const_mem_fun + >, + ordered_non_unique< + tag, + const_mem_fun + >, + ordered_non_unique< + tag, + member + > + > + > query_container_t; +#endif + typedef query_container_t::index::type::iterator question_id_iterator_t; + typedef query_container_t::index::type::iterator expired_iterator_t; + typedef query_container_t::index::type::iterator resend_iterator_t; + + + io_service& _ios; + deadline_timer _timer; + ip::udp::socket _socket; + ep_vector_t _dnsList; + query_container_t _query_list; + boost::mutex _resolver_mutex; + mutable bool _outstanding_read; + boost::mt19937 _rng; + +public: + dns_resolver_impl(io_service& ios) + : _ios(ios), + _timer(_ios), + _socket(_ios), + _outstanding_read(false) + { + } + + void destroy() + { + } + + void add_nameserver(ip::address addr) + { + ip::udp::endpoint endpoint(addr, 53); + _dnsList.push_back(endpoint); + } + + void cancel() + { + _socket.cancel(); + } + + template + void async_resolve(const net::dns::question & question, CallbackHandler handler) + { + if( dns_cache_object::instance().exists(question) ) + { + boost::system::error_code callbackError; + dns_handler caller(handler); + + rr_list_t record_list = dns_cache_object::instance().get(question); + for( rr_list_t::iterator iter = record_list.begin(); + iter != record_list.end(); + ++iter ) + { + caller.invoke(_ios, (*iter), callbackError ); + } + } + else + { + boost::mutex::scoped_lock scopeLock(_resolver_mutex); + if( !_socket.is_open() ) + { + _socket.open(ip::udp::v4()); + _socket.bind(ip::udp::endpoint(ip::udp::v4(), 0)); + } + + _timer.expires_from_now(posix_time::seconds(2)); + _timer.async_wait( + boost::bind( + &dns_resolver_impl::handle_timeout, + this, + boost::asio::placeholders::error + ) + ); + + net::dns::message qmessage(question); + + // set a few defaults for a message + qmessage.recursive(true); + qmessage.action(net::dns::message::query); + qmessage.opcode(net::dns::message::squery); + + // make our message id unique + uint16_t quid( (uint16_t)_rng() ); + + for( ep_vector_t::iterator iter = _dnsList.begin(); iter != _dnsList.end(); ++iter) + { + shared_dq_t dq = shared_dq_t(new dns_query_t(question)); + + dq->_question_id = (uint16_t)quid; + dq->_dns = *iter; + dq->_completion_callback = shared_ptr >(new dns_handler(handler)); + + qmessage.id( dq->_question_id ); + qmessage.encode( dq->_mbuffer ); + + _query_list.insert(dq); + send_request(dq); + } + } + } + + template + void async_resolve(const string & domain, const net::dns::type_t rrtype, CallbackHandler handler) + { + net::dns::question question(domain, rrtype); + async_resolve(question, handler); + } + + boost::asio::io_service & get_io_service() + { + return _ios; + } + + rr_list_t resolve(const net::dns::question & question, boost::system::error_code & ec) + { + rr_list_t _list; + return _list; + } + + rr_list_t resolve(const net::dns::question & question) + { + shared_rr_list_t _list(new rr_list_t); + + io_service thisIos; + dns_resolver_impl thisResolve(thisIos); + thisResolve._dnsList = _dnsList; + + thisResolve.async_resolve( + question, + bind( + &dns_resolver_impl::blocking_callback, + &thisResolve, + _list, _1, _2 + ) + ); + + thisIos.run(); + + return *_list.get(); + } + + rr_list_t resolve(const string & domain, const net::dns::type_t rrtype) + { + net::dns::question question(domain, rrtype); + return resolve(question); + } + + rr_list_t resolve(const string & domain, const net::dns::type_t rrtype, boost::system::error_code & ec) + { + rr_list_t _list; + return _list; + } + +private: + void send() + { + boost::mutex::scoped_lock scopeLock(_resolver_mutex); + + question_id_iterator_t iter; + for( iter = _query_list.get().begin(); iter != _query_list.get().end(); ++iter) + { + _ios.post( + bind( + &dns_resolver_impl::send_request, + this, + (*iter) + ) + ); + } + } + + void send_request(shared_dq_t& dq) + { +// cout << "send_request: " << dq->_dns.address().to_string() << endl; + _socket.async_send_to( + boost::asio::buffer( + dq->_mbuffer.data(), + dq->_mbuffer.length() + ), + dq->_dns, + boost::bind( + &dns_resolver_impl::handle_send, + this, + dq, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred + ) + ); + } + + void handle_send(shared_dq_t& dq, const boost::system::error_code& ec, size_t bytes_sent) + { + if (!ec || ec == boost::asio::error::message_size) + { + shared_dns_buffer_t rbuffer(new dns_buffer_t ); + + _socket.async_receive( + boost::asio::buffer( + *(rbuffer.get()) + ), + boost::bind( + &dns_resolver_impl::handle_recv, + this, + rbuffer, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred + ) + ); + } + } + + void handle_recv(shared_dns_buffer_t inBuffer, const boost::system::error_code& ec, std::size_t bytes_transferred) + { + boost::mutex::scoped_lock scopeLock(_resolver_mutex); + _outstanding_read = false; + + if( !ec && bytes_transferred ) // || ec == boost::asio::error::message_size) + { + inBuffer.get()->length(bytes_transferred); + + net::dns::message tmpMessage; + + uint16_t qid; + inBuffer.get()->get(qid); + + std::pair range_iter; + range_iter = _query_list.get().equal_range(qid); + if( range_iter.first == range_iter.second ) + return ; + + question_id_iterator_t qiter = range_iter.first; + + tmpMessage.decode( *inBuffer.get() ); + boost::system::error_code callbackError; + if( tmpMessage.result() != net::dns::message::noerror ) + { + callbackError = error::not_found; + shared_resource_base_t record; + (*qiter)->_completion_callback->invoke(_ios, record, callbackError); + } + else + { + net::dns::rr_list_t* records; + net::dns::rr_list_t::iterator iter; + + // Grab all the records, we'll probably need more info for additional queries + if( tmpMessage.additionals()->size() ) + { + records = tmpMessage.additionals(); + dns_cache_object::instance().reserve( records->size(), (*qiter)->_question ); + for( iter = records->begin(); iter != records->end(); ++iter ) + dns_cache_object::instance().add( (*iter) ); + } + + if( tmpMessage.authorites()->size() ) + { + records = tmpMessage.authorites(); + dns_cache_object::instance().reserve( records->size(), (*qiter)->_question ); + for( iter = records->begin(); iter != records->end(); ++iter ) + dns_cache_object::instance().add( (*iter) ); + } + + if( tmpMessage.answers()->size() ) + { + records = tmpMessage.answers(); + dns_cache_object::instance().reserve( records->size(), (*qiter)->_question ); + for( iter = records->begin(); iter != records->end(); ++iter ) + { + dns_cache_object::instance().add( (*iter) ); + (*qiter)->_completion_callback->invoke(_ios, (*iter), callbackError); + } + } + } + + _query_list.get().erase(range_iter.first, range_iter.second); + if( !_query_list.size() ) + { + _timer.cancel(); + _socket.close(); + } + } + else if (ec == error::operation_aborted) + { + inBuffer.get()->length(bytes_transferred); + + uint16_t qid; + inBuffer.get()->get(qid); + + std::pair range_iter; + range_iter = _query_list.get().equal_range(qid); + + if( range_iter.first != range_iter.second ) + { + shared_resource_base_t record; + (*range_iter.first)->_completion_callback->invoke(_ios, record, error::operation_aborted); + } + + _query_list.get().erase(range_iter.first, range_iter.second); + if( !_query_list.size() ) + { + _timer.cancel(); + _socket.close(); + } + } + else + { + } + } + + void handle_timeout(const boost::system::error_code& ec) + { + if( !ec && ec != error::operation_aborted ) + { + // Lock the list so we can manipulate it + boost::mutex::scoped_lock scopeLock(_resolver_mutex); + + if( _query_list.size() ) + { + shared_resource_base_t record; + + expired_iterator_t expired_iter = _query_list.get().find(true); + for( ; expired_iter != _query_list.get().end(); ++expired_iter ) + { + if( (*expired_iter)->expired() ) + { + (*expired_iter)->_completion_callback->invoke(_ios, record, error::timed_out); + _query_list.get().erase(expired_iter); + } + } + } + + if( _query_list.size() ) + { + _timer.expires_from_now(posix_time::seconds(2)); + _timer.async_wait( + boost::bind( + &dns_resolver_impl::handle_timeout, + this, + boost::asio::placeholders::error + ) + ); + + _ios.post( bind(&dns_resolver_impl::send, this) ); + } + else + { + _socket.close(); + } + } + } + + void blocking_callback(shared_rr_list_t& list, const shared_resource_base_t& record, const boost::system::error_code& ec) + { + // we're doing a asynch operation for a sync request + if( record ) + { + list->push_back(record); + } + else + cout << "blocking_callback: " << ec.message() << endl; + } +}; + + } // namespace dns + } // namespace net +} // namespace boost + +#endif // BOOST_NET_DNS_RESOLVER_IMPL_HPP diff --git a/lib/boost-net-dns/boost/net/network_array.hpp b/lib/boost-net-dns/boost/net/network_array.hpp new file mode 100755 index 0000000..7a0b7ac --- /dev/null +++ b/lib/boost-net-dns/boost/net/network_array.hpp @@ -0,0 +1,483 @@ +// +// network_array.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 1998-2006 Andreas Haberstroh (softwareace at yahoo dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_NET_NETWORK_ARRAY_HPP +#define BOOST_NET_NETWORK_ARRAY_HPP + +// Our primary dependency is boost::asio. We can't live without it! +#include + +#include +#include + +#include +#include +#include +#include +#include + +using namespace std; +using namespace boost; +using namespace boost::asio; + +namespace boost { + namespace net { + +/** + The network_array class template provides a static size array of bytes + that has accessors function to make getting and setting data network friendly. + + Uses the Endian/Non-Endian transform functions, (i.e. htons,ntohs) + + Derived from boost::array. + */ +template +class network_array +{ +private: + /// Array member + array data_array; + + /// Position in memory buffer for get/put + size_t nap; // acronym: network array position + + /// Total size of memory buffer, not necessarily the N size of the buffer + size_t nal; // acronym: network array length + +public: + /// Constructs an empty network_array + /* + + */ + network_array() + : data_array(), + nap(0), + nal(0) + { + data_array.assign((uint8_t)0x00); + } + + virtual ~network_array() + {} + + /// Get & Set the position in the array + /** + @param p Sets the current caret position in the array. If left blank, it does not change the position, but only reports the position. + @return The current caret position in the array + */ + size_t position(const size_t p=N+1) + { + if( p != N + 1 ) nap = p; + return nap; + } + + /// Get & Set the length of data in the array + /** + This function does not change the size of the array, but only the reporting aspect of the amount of data contained in the array. + @param l Sets the data length in the array. If left blank, it does not change the length, but only reports the length. + @return The current length of the array + */ + size_t length(const size_t l=N+1) + { + if( l != N + 1 ) nal = l; + return nal; + } + + /// Gets data from the array + /** + Gets a char from the array. + @param d Data to retrieve + @param p Position to retrieve data from. If left blank, will retrieve from the current caret position + @param incpos Increments the caret position in the array. If set to false the function acts like a peek + @return The amount of bytes retrieved from the array + */ + size_t get(char & d, const size_t p=N+1, const bool incpos=true) + { + if( p != N+1 ) + { + data_array.rangecheck(p); + position(p); + } + + d = (char)data_array.elems[nap]; + if( incpos ) nap += sizeof(d); + + return sizeof(d); + } + + /// Puts data into the array + /** + Puts a char into the array. + @param d Data to write into the array + @param p Position to write data to. If left blank, will write to the current caret position. + @param incpos Increments the caret position in the array. If set to false the function acts like a poke + @return The amount of bytes writen from the array + */ + size_t put(const char d, const size_t p=N+1, const bool incpos=true) + { + if( p != N+1 ) + { + data_array.rangecheck(p); + position(p); + } + + data_array.elems[nap] = (uint8_t)d; + if( incpos ) + { + nap += sizeof(d); + if( nap > nal ) + nal += sizeof(d); + } + + return sizeof(d); + } + + /// Gets data from the array + /** + Gets a uint8_t from the array. + @param d Data to retrieve + @param p Position to retrieve data from. If left blank, will retrieve from the current caret position + @param incpos Increments the caret position in the array. If set to false the function acts like a peek + @return The amount of bytes retrieved from the array + */ + size_t get(uint8_t & d, const size_t p=N+1, const bool incpos=true) + { + if( p != N+1 ) + { + data_array.rangecheck(p); + position(p); + } + + d = data_array.elems[nap]; + + if( incpos ) nap += sizeof(d); + return sizeof(d); + } + + /// Puts data into the array + /** + Puts a uint8_t into the array. + @param d Data to write into the array + @param p Position to write data to. If left blank, will write to the current caret position. + @param incpos Increments the caret position in the array. If set to false the function acts like a poke + @return The amount of bytes writen from the array + */ + size_t put(const uint8_t d, const size_t p=N+1, const bool incpos=true) + { + if( p != N+1 ) + { + data_array.rangecheck(p); + position(p); + } + + data_array.elems[nap] = d; + + if( incpos ) + { + nap += sizeof(d); + if( nap > nal ) + nal += sizeof(d); + } + + return sizeof(d); + } + + /// Gets data from the array + /** + Gets a uint16_t from the array. The data returned is host friendly. + @param d Data to retrieve + @param p Position to retrieve data from. If left blank, will retrieve from the current caret position + @param incpos Increments the caret position in the array. If set to false the function acts like a peek + @return The amount of bytes retrieved from the array + */ + size_t get(uint16_t & d, const size_t p=N+1, const bool incpos=true) + { + if( p != N+1 ) + { + data_array.rangecheck(p); + position(p); + } + + d = ntohs( *((uint16_t *)&data_array.elems[nap]) ); + + if( incpos ) nap += sizeof(d); + return sizeof(d); + } + + /// Puts data into the array + /** + Puts a uint16_t into the array. The data writen is network friendly. + @param d Data to write into the array + @param p Position to write data to. If left blank, will write to the current caret position. + @param incpos Increments the caret position in the array. If set to false the function acts like a poke + @return The amount of bytes writen from the array + */ + size_t put(const uint16_t d, const size_t p=N+1, const bool incpos=true) + { + if( p != N+1 ) + { + data_array.rangecheck(p); + position(p); + } + + *((uint16_t *)&data_array.elems[nap]) = htons(d); + + if( incpos ) + { + nap += sizeof(d); + if( nap > nal ) + nal += sizeof(d); + } + + return sizeof(d); + } + + /// Gets data from the array + /** + Gets a uint32_t from the array. The data is host friendly. + @param d Data to retrieve + @param p Position to retrieve data from. If left blank, will retrieve from the current caret position + @param incpos Increments the caret position in the array. If set to false the function acts like a peek + @return The amount of bytes retrieved from the array + */ + size_t get(uint32_t & d, const size_t p=N+1, const bool incpos=true) + { + if( p != N+1 ) + { + data_array.rangecheck(p); + position(p); + } + + d = ntohl( *((uint32_t *)&data_array.elems[nap]) ); + + if( incpos ) nap += sizeof(d); + return sizeof(d); + } + + /// Puts data into the array + /** + Puts a uint32_t into the array. The data writen is network friendly. + @param d Data to write into the array + @param p Position to write data to. If left blank, will write to the current caret position. + @param incpos Increments the caret position in the array. If set to false the function acts like a poke + @return The amount of bytes writen from the array + */ + size_t put(const uint32_t d, const size_t p=N+1, const bool incpos=true) + { + if( p != N+1 ) + { + data_array.rangecheck(p); + position(p); + } + + *((uint32_t *)&data_array.elems[nap]) = htonl(d); + + if( incpos ) + { + nap += sizeof(d); + if( nap > nal ) + nal += sizeof(d); + } + + return sizeof(d); + } + + /// Gets data from the array + /** + Gets a uint32_t from the array. The data is host friendly. + @param d Data to retrieve + @param p Position to retrieve data from. If left blank, will retrieve from the current caret position + @param incpos Increments the caret position in the array. If set to false the function acts like a peek + @return The amount of bytes retrieved from the array + */ + size_t get(ip::address_v4 & d, const size_t p=N+1, const bool incpos=true) + { + if( p != N+1 ) + { + data_array.rangecheck(p); + position(p); + } + + d = ip::address_v4( ntohl( *((uint32_t *)&data_array.elems[nap]) ) ); + + if( incpos ) nap += sizeof(uint32_t); + return sizeof(d); + } + + /// Puts data into the array + /** + Puts a uint32_t into the array. The data writen is network friendly. + @param d Data to write into the array + @param p Position to write data to. If left blank, will write to the current caret position. + @param incpos Increments the caret position in the array. If set to false the function acts like a poke + @return The amount of bytes writen from the array + */ + size_t put(const ip::address_v4 & d, const size_t p=N+1, const bool incpos=true) + { + if( p != N+1 ) + { + data_array.rangecheck(p); + position(p); + } + + *((uint32_t *)&data_array.elems[nap]) = htonl( + static_cast (d.to_ulong()) + ); + + if( incpos ) + { + nap += sizeof(uint32_t); + if( nap > nal ) + nal += sizeof(uint32_t); + } + + return sizeof(d); + } + + /// Gets data from the array + /** + Gets a uint32_t from the array. The data is host friendly. + @param d Data to retrieve + @param p Position to retrieve data from. If left blank, will retrieve from the current caret position + @param incpos Increments the caret position in the array. If set to false the function acts like a peek + @return The amount of bytes retrieved from the array + */ + size_t get(ip::address_v6 & d, const size_t p=N+1, const bool incpos=true) + { + if( p != N+1 ) + { + data_array.rangecheck(p); + position(p); + } + + ip::address_v6::bytes_type bytes; + memcpy( &bytes.elems[0], &data_array.elems[nap], 16); + d = ip::address_v6(bytes); + if( incpos ) + { + nap += 16; + if( nap > nal ) nal += 16; + } + return 16; + } + + /// Puts data into the array + /** + Puts a uint32_t into the array. The data writen is network friendly. + @param d Data to write into the array + @param p Position to write data to. If left blank, will write to the current caret position. + @param incpos Increments the caret position in the array. If set to false the function acts like a poke + @return The amount of bytes writen from the array + */ + size_t put(const ip::address_v6 & d, const size_t p=N+1, const bool incpos=true) + { + if( p != N+1 ) + { + data_array.rangecheck(p); + position(p); + } + + memcpy( &data_array.elems[nap], &d.to_bytes().elems[0], 16); + + if( incpos ) + { + nap += sizeof(uint32_t); + if( nap > nal ) + nal += sizeof(uint32_t); + } + + return sizeof(d); + } + + /// Gets data from the array + /** + Gets a std::string from the array. + @param d Data to retrieve + @param len Amount of chars to read. + @param p Position to retrieve data from. If left blank, will retrieve from the current caret position + @param incpos Increments the caret position in the array. If set to false the function acts like a peek + @return The amount of bytes retrieved from the array + */ + size_t get(string & d, const size_t len, const size_t p=N+1, const bool incpos=true) + { + if( p != N+1 ) + { + data_array.rangecheck(p); + position(p); + } + + scoped_array cPtr( new char[len + 1] ); + strncpy( cPtr.get(), (char*)&data_array.elems[nap], len); + cPtr.get()[len] = 0x00; + d = cPtr.get(); + + if( incpos ) + { + nap += len; + if( nap > nal ) + nal += len; + } + + return len; + } + + /// Puts data into the array + /** + Puts a std::string into the array. + @param d Data to write into the array + @param len Amount of chars to write + @param p Position to write data to. If left blank, will write to the current caret position. + @param incpos Increments the caret position in the array. If set to false the function acts like a poke + @return The amount of bytes writen from the array + */ + size_t put(const string & d, const size_t len, const size_t p=N+1, const bool incpos=true) + { + if( p != N+1 ) + { + data_array.rangecheck(p); + position(p); + } + + // make sure we can memcpy! + data_array.rangecheck(nap + len); + memcpy( &data_array.elems[nap], d.c_str(), len ); + + if( incpos ) + { + nap += len; + if( nap > nal ) + nal += len; + } + + return len; + } + + /// Returns the underline boost::array to provide a compatible object. + /** + Returns the underline boost::array to provide a compatible object. + @return A boost::array compatible object + */ + array& get_array() + { + return data_array; + } + +}; + +typedef network_array<576> dns_buffer_t; +typedef shared_ptr shared_dns_buffer_t; + + + } // namespace net +} // namespace boost + +#include + +#endif // BOOST_NET_NETWORK_ARRAY_HPP diff --git a/lib/boost-net-dns/boost/net/resolve.hpp b/lib/boost-net-dns/boost/net/resolve.hpp new file mode 100755 index 0000000..5ce0382 --- /dev/null +++ b/lib/boost-net-dns/boost/net/resolve.hpp @@ -0,0 +1,232 @@ +// +// resolve.hpp +// ~~~~~~~~ +// +// Copyright (c) 1998-2006 Andreas Haberstroh (andreas at ibusy dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_NET_DNS_RESOLVE_HPP +#define BOOST_NET_DNS_RESOLVE_HPP + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace boost; +using namespace boost::asio; + +namespace boost { + namespace net { + namespace dns { + +/// Provides DNS resolution using dns::message packets +/** +The resolve class makes a DNS resolution query synchronously. +Internally, the class does the work asynchronously when multiple servers are listed. +*/ +class resolve +{ +private: + + /* + need an atomic reference counter + */ + class reference_counter + { + public: + reference_counter() : mutex(), count(0) { } + int inc() + { + boost::mutex::scoped_lock scoped_lock(mutex); + return ++count; + } + int dec() + { + boost::mutex::scoped_lock scoped_lock(mutex); + return --count; + } + + private: + boost::mutex mutex; + mutable int count; + }; + +private: + /// resolve has it's own io_service handler + io_service ioservice; + ip::udp::socket socket; + + /// Timer used to retry sending a packet. Busy servers don't always anwers + deadline_timer retry_timer; + + /// Timer used to kill the async_dns_request if there isn't a response + deadline_timer death_timer; + + /// The maximum length async_dns_request should try to get a response. + uint32_t death_timeout; + + /// List of servers to request resolution from + vector endpointList; + + /// Response message to pass back when a request is resolved + dns::message responseMessage; + + /// Outbound DNS request buffer + dns_buffer_t reqBuffer; + + /// Number of servers left before + reference_counter requestCount; + + /// General mutex for locking buffers + boost::mutex bufferMutex; + +public: + /// Constructor for the resolve class + resolve() + : ioservice(), + socket(ioservice, ip::udp::endpoint(ip::udp::v4(), 0)), + retry_timer(ioservice), + death_timer(ioservice), + death_timeout(30), + endpointList(), + responseMessage(), + reqBuffer(), + requestCount(), + bufferMutex() + { + } + + /// Adds a name server to the list of servers that we will query + /** + @param addr IP address for the name server + */ + void addServer( ip::address & addr ) + { + boost::mutex::scoped_lock lock(bufferMutex); + ip::udp::endpoint endpoint(addr, 53); + endpointList.push_back( endpoint ); + } + + /// Executes the DNS query + /** + @param qmessage Query message to send to the server list + @return Query result. If the query failed or timed out, dns::message.result() will return no_result. + */ + dns::message & query(dns::message & qmessage) + { + // set a few defaults for a message + qmessage.recursive(true); + qmessage.action(dns::message::query); + qmessage.opcode(dns::message::squery); + + // make our message id unique + qmessage.id( 0xaffe ); + + qmessage.encode( reqBuffer ); + + // in the event nothing get's resolved, answer with the original question + responseMessage = qmessage; + responseMessage.result(dns::message::no_result); + + // die if we don't get a response within death_timeout + death_timer.expires_from_now(boost::posix_time::seconds(death_timeout)); + death_timer.async_wait(boost::bind(&resolve::request_timeout, this)); + + for( vector::iterator iter = endpointList.begin(); iter != endpointList.end(); ++iter ) + { + // we're waiting for N of requests + requestCount.inc(); + + // setup the receive buffer + shared_dns_buffer_t recvBuffer( new dns_buffer_t ); + socket.async_receive_from( + boost::asio::buffer( recvBuffer.get()->get_array() ), *iter, + boost::bind(&resolve::handle_recv, this, + recvBuffer, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } + + // kick off the request + send_packet(); + + // run a blocking service + ioservice.run(); + + return responseMessage; + } + +private: + void request_timeout() + { + retry_timer.cancel(); + death_timer.cancel(); + + // just tear everything down at this point. + if( socket.is_open() ) + socket.close(); + + if( requestCount.dec() == 0 ) + ioservice.stop(); + } + + void resend_timeout() + { + retry_timer.cancel(); + + // No response, so resend the message again + if( socket.is_open() ) + send_packet(); + else + // if the socket gets closed, then, we've probably received an answer! + request_timeout(); + } + + void send_packet() + { + // 2 seconds should be a good time to wait for a response. + retry_timer.expires_from_now(boost::posix_time::seconds(2)); + retry_timer.async_wait(boost::bind(&resolve::resend_timeout, this)); + + // send out the packets for request + for( vector::iterator iter = endpointList.begin(); iter != endpointList.end(); ++iter ) + socket.send_to(boost::asio::buffer(reqBuffer.get_array()), *iter); + } + + void handle_recv(shared_dns_buffer_t inBuffer, const boost::system::error_code& ec, std::size_t bytes_transferred) + { + if (!ec || ec == boost::asio::error::message_size) + { + // only decode if we haven't decoded already! + if( responseMessage.result() != dns::message::no_result ) + { + boost::mutex::scoped_lock lock(bufferMutex); + + // clamp the recvBuffer with the number of bytes transferred + inBuffer.get()->length(bytes_transferred); + + // decode the buffer and say we've succeeded + responseMessage.decode( *inBuffer.get() ); + } + + // consider the job done. + request_timeout(); + } + } +}; + + } // namespace dns + } // namespace net +} // namespace boost + +#include + +#endif // BOOST_NET_DNS_RESOLVE_HPP diff --git a/lib/boost-net-dns/boost/net/rfc1035_414.hpp b/lib/boost-net-dns/boost/net/rfc1035_414.hpp new file mode 100755 index 0000000..1112854 --- /dev/null +++ b/lib/boost-net-dns/boost/net/rfc1035_414.hpp @@ -0,0 +1,218 @@ +// +// rfc1035_414.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 1998-2006 Andreas Haberstroh (andreas at ibusy dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_NET_RFC1035_414_HPP +#define BOOST_NET_RFC1035_414_HPP + +#include + +#include +#include +#include + +#include +#include +#include +#include + + +using namespace std; +using namespace boost; + +namespace boost { + namespace net { + + typedef network_array<576> dns_buffer_t; + + /*! + The rfc1035_414_t class is a helper class for dealing with DNS label compression inside + of DNS type packets. This class takes its name after RFC1035, section 4.1.4. + */ + class rfc1035_414_t + { + private: + /*! + The domain_offset_map_t links buffer offsets to strings for the DNS label compression + requirements. + */ + typedef std::map domain_offset_map_t; + + domain_offset_map_t _offsets; + + public: + /// Default constructor + rfc1035_414_t() : _offsets() + { + } + + /// Copy constructor + rfc1035_414_t(const rfc1035_414_t& rfc) + : _offsets(rfc._offsets) + { + } + + /// Assignment operator + rfc1035_414_t& operator=(const rfc1035_414_t& rfc) + { + _offsets = rfc._offsets; + return *this; + } + + /*! + Breaks apart a domain name into it's label or compressed offset values and + writes it to the buffer + + \param domain Domain string to break apart into labels + \param buffer Memory buffer to write the labels to + + \returns Number of bytes written + */ + size_t write_label(const string& domain, dns_buffer_t & buffer) + { + // no length? no service + if( !domain.length() ) + return 0; + + string lowerDomain = to_lower_copy(domain); + // total length of the data written. + size_t length(0); + + // place to begin the substring at + string::size_type begin(0); + + bool done = false; + while( !done ) + { + // find the next '.' and cut the subdomain string from it. + string::size_type current = lowerDomain.find('.', begin); + string subdomain( lowerDomain.substr(begin) ); + + // get the length of this label + uint8_t l( (uint8_t)(current - begin) ); + if( current == string::npos ) + { + l = (uint8_t)subdomain.length(); + done = true; + } + + // some how we've read a blank label! + if( !l ) break; + + // current domain label + string label( lowerDomain.substr(begin, l) ); + + // deja vous? + domain_offset_map_t::iterator iter = _offsets.find( subdomain ); + if( iter == _offsets.end() ) + { + // save the position in the buffer + _offsets[ subdomain ] = buffer.position(); + + buffer.put( (uint8_t)label.length() ); + buffer.put( label, label.length() ); + length += sizeof(uint8_t) + label.length(); + begin = current + 1; + } + else + { + // compresses reference + size_t offset = (0xC000 | iter->second); + buffer.put( (uint8_t)(offset >> 8) ); + buffer.put( (uint8_t)(offset) ); + + // every byte counts + length += sizeof(uint16_t); + return length; + } + } + + // need a zero termination to identify the "last" label + buffer.put( (uint8_t)0x00 ); + length += sizeof(uint8_t); + + return length; + } + + /*! + Reads a sequence of labels from a memory buffer + + This function is recursive in it's decompress. One of the things to be aware + of are DNS packets that make circular offset references. Also, malformed packets + that reference "bad" areas of the packet are no-no's + + \param domain Domain label to return + \param buffer Memory buffer to read the domain from + \throws std::out_of_range + */ + void read_label(string& domain, dns_buffer_t & buffer) + { + while( true ) + { + uint8_t len; + + size_t thisPos = buffer.position(); + buffer.get(len); + + // 0xC0 denotes the offset + if( len & 0xC0 ) + { + uint8_t msb; + buffer.get(msb); + uint8_t lsb = len ^ 0xC0; + uint16_t offset = static_cast(lsb << 8 | msb); + + // bad dog! trying to reference the header + if( offset < 0x0C ) + throw std::out_of_range("Reference inside header"); // maybe we should throw a message? + + // bad dog! trying to reference ourselves! + if( offset == thisPos ) + throw std::out_of_range("Self Reference"); + + // bad dog! trying to reference out-of-bounds! + if( offset > buffer.length() ) + throw std::out_of_range("Out of Bounds"); + + // recurse the reference ! + size_t savedpos = buffer.position(); + + buffer.position(offset); // make the jump to the reference + + read_label(domain, buffer); + + // safe to restore! + if( savedpos < buffer.length() ) + buffer.position(savedpos); + + // the compressed reference has the ending 0x00 byte marker + break; + } + else if( len ) + { + string s; + buffer.get( s, len ); + + domain += to_lower_copy(s) + "."; + } + else + break; + } + + // we should always carry the "." in the name + if( !domain.length() ) domain = "."; + } + }; + + } // namespace net +} // namespace boost + +#include + +#endif // BOOST_NET_RFC1035_414_HPP diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 079cfa7..be4b8e9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,3 +1,6 @@ +# package: find external packages +include(FindPkgConfig) + # package: required boost libraries set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_MULTITHREADED ON) @@ -6,8 +9,8 @@ find_package(Boost COMPONENTS filesystem program_options system REQUIRED) include_directories(${Boost_INCLUDE_DIRS}) link_directories(${Boost_LIBRARY_DIRS}) -# package: find external packages -include(FindPkgConfig) +# package: boost-net-dns +include_directories(${CMAKE_SOURCE_DIR}/lib/boost-net-dns) # package: libi2ncommon pkg_check_modules(I2NCOMMON REQUIRED libi2ncommon) diff --git a/src/dns/dnsresolver.cpp b/src/dns/dnsresolver.cpp index 764ed95..4277ee3 100644 --- a/src/dns/dnsresolver.cpp +++ b/src/dns/dnsresolver.cpp @@ -3,12 +3,17 @@ #include #include +#include +#include #include "dns/hostaddress.h" using namespace std; using boost::asio::io_service; -using boost::asio::ip::tcp; +using boost::asio::ip::address; +using boost::net::dns::a_resource; +using boost::net::dns::message; +using boost::net::dns::rr_list_t; //----------------------------------------------------------------------------- // DnsResolver @@ -37,22 +42,38 @@ bool DnsResolver::resolve() try { - io_service io_serv; - tcp::resolver resolver( io_serv ); - tcp::resolver::query query( tcp::v4(), HostDnsAddress, "" ); - tcp::resolver::iterator it_first = resolver.resolve( query ); - tcp::resolver::iterator it_last = tcp::resolver::iterator(); - while ( it_first != it_last ) + address nameServer( address::from_string( "127.0.0.1" ) ); + boost::net::dns::resolve resolver; + resolver.addServer( nameServer ); + message dns_message( HostDnsAddress, boost::net::dns::type_a ); + message& dns_packet = resolver.query( dns_message ); + rr_list_t* answers = dns_packet.answers(); + int resolved_ip = answers->size(); + if ( resolved_ip < 1 ) { - string dest_ip = (*it_first).endpoint().address().to_string(); + cerr << "Error: host " << HostDnsAddress << " could not be resolved." << endl; + return false; + } + + for ( rr_list_t::iterator riter = answers->begin(); + riter != answers->end(); + ++riter ) + { + a_resource *resource_record = dynamic_cast ( + riter->get() + ); - HostAddress resolved_host; - resolved_host.set_ip( dest_ip ); - ResolvedHostAddressList.push_back( resolved_host ); + if ( ( resource_record != NULL ) && + ( resource_record->rtype() == boost::net::dns::type_a ) ) + { + string ip = resource_record->address().to_string(); + int ttl = resource_record->ttl(); - cout << "- " << dest_ip << endl; + HostAddress resolved_host( ip, ttl ); + ResolvedHostAddressList.push_back( resolved_host ); - ++it_first; + cout << "- " << ip << endl; + } } } catch ( const std::exception &ex ) @@ -96,5 +117,7 @@ string DnsResolver::get_next_ip() BOOST_ASSERT( list_size_before == list_size_after ); + // TODO check the ttl of the resolved IP, if it is next to zero, call the resolve again + return destination_ip; } diff --git a/src/dns/hostaddress.cpp b/src/dns/hostaddress.cpp index 46a60ca..a7cc69c 100644 --- a/src/dns/hostaddress.cpp +++ b/src/dns/hostaddress.cpp @@ -12,6 +12,15 @@ HostAddress::HostAddress() : { } +HostAddress::HostAddress( + string ip, + int ttl +) : + Ip( ip ), + Ttl( ttl ) +{ +} + HostAddress::~HostAddress() { } diff --git a/src/dns/hostaddress.h b/src/dns/hostaddress.h index 525761b..1185fa1 100644 --- a/src/dns/hostaddress.h +++ b/src/dns/hostaddress.h @@ -13,6 +13,7 @@ class HostAddress { public: HostAddress(); + HostAddress( std::string ip, int ttl ); virtual ~HostAddress(); std::string get_ip() const; -- 1.7.1