diff --git a/external/unbound/config.h.cmake.in b/external/unbound/config.h.cmake.in index d9bfebf33..377bcd97f 100644 --- a/external/unbound/config.h.cmake.in +++ b/external/unbound/config.h.cmake.in @@ -575,7 +575,8 @@ #cmakedefine USE_GOST /* Define if you want to use internal select based events */ -#cmakedefine USE_MINI_EVENT +/* #cmakedefine USE_MINI_EVENT */ +#define USE_MINI_EVENT 1 /* Define this to enable SHA256 and SHA512 support. */ #cmakedefine USE_SHA2 diff --git a/src/common/dns_utils.cpp b/src/common/dns_utils.cpp index e442d3d81..5cb5ed2de 100644 --- a/src/common/dns_utils.cpp +++ b/src/common/dns_utils.cpp @@ -38,6 +38,8 @@ using namespace epee; namespace bf = boost::filesystem; +static std::mutex instance_lock; + namespace { @@ -98,8 +100,10 @@ namespace tools { // fuck it, I'm tired of dealing with getnameinfo()/inet_ntop/etc -std::string ipv4_to_string(const char* src) +std::string ipv4_to_string(const char* src, size_t len) { + assert(memchr(src, 0, len)); + std::stringstream ss; unsigned int bytes[4]; for (int i = 0; i < 4; i++) @@ -116,8 +120,10 @@ std::string ipv4_to_string(const char* src) // this obviously will need to change, but is here to reflect the above // stop-gap measure and to make the tests pass at least... -std::string ipv6_to_string(const char* src) +std::string ipv6_to_string(const char* src, size_t len) { + assert(memchr(src, 0, len)); + std::stringstream ss; unsigned int bytes[8]; for (int i = 0; i < 8; i++) @@ -136,6 +142,11 @@ std::string ipv6_to_string(const char* src) return ss.str(); } +std::string txt_to_string(const char* src, size_t len) +{ + return std::string(src+1, len-1); +} + // custom smart pointer. // TODO: see if std::auto_ptr and the like support custom destructors template @@ -164,8 +175,6 @@ private: }; typedef class scoped_ptr ub_result_ptr; -static void freestring(char *ptr) { free(ptr); } -typedef class scoped_ptr string_ptr; struct DNSResolverData { @@ -213,14 +222,13 @@ DNSResolver::~DNSResolver() } } -std::vector DNSResolver::get_ipv4(const std::string& url, bool& dnssec_available, bool& dnssec_valid) +std::vector DNSResolver::get_record(const std::string& url, int record_type, std::string (*reader)(const char *,size_t), bool& dnssec_available, bool& dnssec_valid) { std::vector addresses; dnssec_available = false; dnssec_valid = false; - string_ptr urlC(strdup(url.c_str())); - if (!check_address_syntax(urlC)) + if (!check_address_syntax(url.c_str())) { return addresses; } @@ -229,7 +237,7 @@ std::vector DNSResolver::get_ipv4(const std::string& url, bool& dns ub_result_ptr result; // call DNS resolver, blocking. if return value not zero, something went wrong - if (!ub_resolve(m_data->m_ub_context, urlC, DNS_TYPE_A, DNS_CLASS_IN, &result)) + if (!ub_resolve(m_data->m_ub_context, url.c_str(), record_type, DNS_CLASS_IN, &result)) { dnssec_available = (result->secure || (!result->secure && result->bogus)); dnssec_valid = result->secure && !result->bogus; @@ -237,7 +245,7 @@ std::vector DNSResolver::get_ipv4(const std::string& url, bool& dns { for (size_t i=0; result->data[i] != NULL; i++) { - addresses.push_back(ipv4_to_string(result->data[i])); + addresses.push_back((*reader)(result->data[i], result->len[i])); } } } @@ -245,70 +253,19 @@ std::vector DNSResolver::get_ipv4(const std::string& url, bool& dns return addresses; } +std::vector DNSResolver::get_ipv4(const std::string& url, bool& dnssec_available, bool& dnssec_valid) +{ + return get_record(url, DNS_TYPE_A, ipv4_to_string, dnssec_available, dnssec_valid); +} + std::vector DNSResolver::get_ipv6(const std::string& url, bool& dnssec_available, bool& dnssec_valid) { - std::vector addresses; - dnssec_available = false; - dnssec_valid = false; - - string_ptr urlC(strdup(url.c_str())); - if (!check_address_syntax(urlC)) - { - return addresses; - } - - ub_result_ptr result; - - // call DNS resolver, blocking. if return value not zero, something went wrong - if (!ub_resolve(m_data->m_ub_context, urlC, DNS_TYPE_AAAA, DNS_CLASS_IN, &result)) - { - dnssec_available = (result->secure || (!result->secure && result->bogus)); - dnssec_valid = result->secure && !result->bogus; - if (result->havedata) - { - for (size_t i=0; result->data[i] != NULL; i++) - { - addresses.push_back(ipv6_to_string(result->data[i])); - } - } - } - - return addresses; + return get_record(url, DNS_TYPE_AAAA, ipv6_to_string, dnssec_available, dnssec_valid); } std::vector DNSResolver::get_txt_record(const std::string& url, bool& dnssec_available, bool& dnssec_valid) { - std::vector records; - dnssec_available = false; - dnssec_valid = false; - - string_ptr urlC(strdup(url.c_str())); - if (!check_address_syntax(urlC)) - { - return records; - } - - ub_result_ptr result; - - // call DNS resolver, blocking. if return value not zero, something went wrong - if (!ub_resolve(m_data->m_ub_context, urlC, DNS_TYPE_TXT, DNS_CLASS_IN, &result)) - { - dnssec_available = (result->secure || (!result->secure && result->bogus)); - dnssec_valid = result->secure && !result->bogus; - if (result->havedata) - { - for (size_t i=0; result->data[i] != NULL; i++) - { - // plz fix this, but this does NOT work and spills over into parts of memory it shouldn't: records.push_back(result.ptr->data[i]); - char *restxt; - restxt = (char*) calloc(result->len[i]+1, 1); - memcpy(restxt, result->data[i]+1, result->len[i]-1); - records.push_back(restxt); - } - } - } - - return records; + return get_record(url, DNS_TYPE_TXT, txt_to_string, dnssec_available, dnssec_valid); } std::string DNSResolver::get_dns_format_from_oa_address(const std::string& oa_addr) @@ -326,6 +283,8 @@ std::string DNSResolver::get_dns_format_from_oa_address(const std::string& oa_ad DNSResolver& DNSResolver::instance() { + std::lock_guard lock(instance_lock); + static DNSResolver* staticInstance = NULL; if (staticInstance == NULL) { @@ -334,7 +293,12 @@ DNSResolver& DNSResolver::instance() return *staticInstance; } -bool DNSResolver::check_address_syntax(const char *addr) +DNSResolver DNSResolver::create() +{ + return DNSResolver(); +} + +bool DNSResolver::check_address_syntax(const char *addr) const { // if string doesn't contain a dot, we won't consider it a url for now. if (strchr(addr,'.') == NULL) diff --git a/src/common/dns_utils.h b/src/common/dns_utils.h index 5f39c8ca2..ff346ffc1 100644 --- a/src/common/dns_utils.h +++ b/src/common/dns_utils.h @@ -51,7 +51,7 @@ struct DNSResolverData; */ class DNSResolver { -public: +private: /** * @brief Constructs an instance of DNSResolver @@ -60,6 +60,8 @@ public: */ DNSResolver(); +public: + /** * @brief takes care of freeing C pointers and such */ @@ -121,8 +123,28 @@ public: */ static DNSResolver& instance(); + /** + * @brief Gets a new instance of DNSResolver + * + * @return returns a pointer to the new object + */ + static DNSResolver create(); + private: + /** + * @brief gets all records of a given type from a DNS query for the supplied URL; + * if no such record is present returns an empty vector. + * + * @param url A string containing a URL to query for + * @param record_type the record type to retrieve (DNS_TYPE_A, etc) + * @param reader a function that converts a record data to a string + * + * @return A vector of strings containing the requested record; or an empty vector + */ + // TODO: modify this to accomodate DNSSEC + std::vector get_record(const std::string& url, int record_type, std::string (*reader)(const char *,size_t), bool& dnssec_available, bool& dnssec_valid); + /** * @brief Checks a string to see if it looks like a URL * @@ -130,7 +152,7 @@ private: * * @return true if it looks enough like a URL, false if not */ - bool check_address_syntax(const char *addr); + bool check_address_syntax(const char *addr) const; DNSResolverData *m_data; }; // class DNSResolver diff --git a/tests/unit_tests/dns_resolver.cpp b/tests/unit_tests/dns_resolver.cpp index 0709a773f..3285f7732 100644 --- a/tests/unit_tests/dns_resolver.cpp +++ b/tests/unit_tests/dns_resolver.cpp @@ -35,7 +35,7 @@ TEST(DNSResolver, IPv4Success) { - tools::DNSResolver resolver; + tools::DNSResolver resolver = tools::DNSResolver::create(); bool avail, valid; @@ -55,7 +55,7 @@ TEST(DNSResolver, IPv4Success) TEST(DNSResolver, IPv4Failure) { // guaranteed by IANA/ICANN/RFC to be invalid - tools::DNSResolver resolver; + tools::DNSResolver resolver = tools::DNSResolver::create(); bool avail, valid; @@ -70,7 +70,7 @@ TEST(DNSResolver, IPv4Failure) TEST(DNSResolver, DNSSECSuccess) { - tools::DNSResolver resolver; + tools::DNSResolver resolver = tools::DNSResolver::create(); bool avail, valid; @@ -86,7 +86,7 @@ TEST(DNSResolver, DNSSECSuccess) TEST(DNSResolver, DNSSECFailure) { - tools::DNSResolver resolver; + tools::DNSResolver resolver = tools::DNSResolver::create(); bool avail, valid; @@ -103,7 +103,7 @@ TEST(DNSResolver, DNSSECFailure) // It would be great to include an IPv6 test and assume it'll pass, but not every ISP / resolver plays nicely with IPv6;) /*TEST(DNSResolver, IPv6Success) { - tools::DNSResolver resolver; + tools::DNSResolver resolver = tools::DNSResolver::create(); bool avail, valid; @@ -123,7 +123,7 @@ TEST(DNSResolver, DNSSECFailure) TEST(DNSResolver, IPv6Failure) { // guaranteed by IANA/ICANN/RFC to be invalid - tools::DNSResolver resolver; + tools::DNSResolver resolver = tools::DNSResolver::create(); bool avail, valid;