From 4fa344a0f7d912468b102b021cd86feb194e9223 Mon Sep 17 00:00:00 2001 From: SChernykh Date: Fri, 12 May 2023 10:35:13 +0200 Subject: [PATCH] Refactored DNS TXT resolver code --- src/p2p_server.cpp | 77 +++++++++------------------------------------- src/util.cpp | 72 +++++++++++++++++++++++++++++++++++++++++++ src/util.h | 5 +++ 3 files changed, 92 insertions(+), 62 deletions(-) diff --git a/src/p2p_server.cpp b/src/p2p_server.cpp index f61997a..2d84ef9 100644 --- a/src/p2p_server.cpp +++ b/src/p2p_server.cpp @@ -31,15 +31,6 @@ #include #include -#ifdef _WIN32 -#include -#elif defined(HAVE_RES_QUERY) -#include -#include -#include -#include -#endif - static constexpr char log_category_prefix[] = "P2PServer "; static constexpr char saved_peer_list_file_name[] = "p2pool_peers.txt"; static const char* seed_nodes[] = { "seeds.p2pool.io", ""}; @@ -140,10 +131,6 @@ P2PServer::P2PServer(p2pool* pool) PANIC_STOP(); } -#if !defined(_WIN32) && defined(HAVE_RES_QUERY) - res_init(); -#endif - load_peer_list(); start_listening(params.m_p2pAddresses, params.m_upnp); } @@ -499,55 +486,21 @@ void P2PServer::load_peer_list() // Load peers from seed nodes if we're on the default or mini sidechain auto load_from_seed_nodes = [&saved_list](const char** nodes, int p2p_port) { for (size_t i = 0; nodes[i][0]; ++i) { - LOGINFO(4, "loading peers from " << nodes[i]); + const char* cur_node = nodes[i]; + LOGINFO(4, "loading peers from " << cur_node); // Prefer DNS TXT records -#ifdef _WIN32 - PDNS_RECORD pQueryResults; - if (DnsQuery(nodes[i], DNS_TYPE_TEXT, DNS_QUERY_STANDARD, NULL, &pQueryResults, NULL) == 0) { - for (PDNS_RECORD p = pQueryResults; p; p = p->pNext) { - for (size_t j = 0; j < p->Data.TXT.dwStringCount; ++j) { - if (!saved_list.empty()) { - saved_list += ','; - } - LOGINFO(4, "added " << p->Data.TXT.pStringArray[j] << " from " << nodes[i]); - saved_list += p->Data.TXT.pStringArray[j]; - } + const bool has_txt = get_dns_txt_records(cur_node, [&saved_list, cur_node](const char* s, size_t n) { + if (!saved_list.empty()) { + saved_list += ','; } - DnsRecordListFree(pQueryResults, DnsFreeRecordList); + LOGINFO(4, "added " << log::const_buf(s, n) << " from " << cur_node); + saved_list.append(s, n); + }); + + if (has_txt) { continue; } -#elif defined(HAVE_RES_QUERY) - uint8_t answer[4096]; - const int anslen = res_query(nodes[i], ns_c_in, ns_t_txt, answer, sizeof(answer)); - - if ((0 < anslen) && (anslen < static_cast(sizeof(answer)))) { - ns_msg handle; - if (ns_initparse(answer, anslen, &handle) == 0) { - for (int rrnum = 0, n = ns_msg_count(handle, ns_s_an); rrnum < n; ++rrnum) { - ns_rr rr; - if ((ns_parserr(&handle, ns_s_an, rrnum, &rr) == 0) && (ns_rr_type(rr) == ns_t_txt)) { - const uint8_t* data = ns_rr_rdata(rr); - - const int len = std::min(ns_rr_rdlen(rr) - 1, *data); - if (len <= 0) { - continue; - } - ++data; - - if (!saved_list.empty()) { - saved_list += ','; - } - - const char* c = reinterpret_cast(data); - LOGINFO(4, "added " << log::const_buf(c, len) << " from " << nodes[i]); - saved_list.append(c, len); - } - } - continue; - } - } -#endif addrinfo hints{}; hints.ai_family = AF_UNSPEC; @@ -555,11 +508,11 @@ void P2PServer::load_peer_list() hints.ai_flags = AI_ADDRCONFIG; addrinfo* result; - int err = getaddrinfo(nodes[i], nullptr, &hints, &result); + int err = getaddrinfo(cur_node, nullptr, &hints, &result); if (err) { - LOGWARN(4, "getaddrinfo failed for " << nodes[i] << ": " << gai_strerror(err) << ", retrying with IPv4 only"); + LOGWARN(4, "getaddrinfo failed for " << cur_node << ": " << gai_strerror(err) << ", retrying with IPv4 only"); hints.ai_family = AF_INET; - err = getaddrinfo(nodes[i], nullptr, &hints, &result); + err = getaddrinfo(cur_node, nullptr, &hints, &result); } if (err == 0) { for (addrinfo* r = result; r != NULL; r = r->ai_next) { @@ -585,7 +538,7 @@ void P2PServer::load_peer_list() } if (s.m_pos) { - LOGINFO(4, "added " << static_cast(buf) << " from " << nodes[i]); + LOGINFO(4, "added " << static_cast(buf) << " from " << cur_node); if (!saved_list.empty()) { saved_list += ','; } @@ -595,7 +548,7 @@ void P2PServer::load_peer_list() freeaddrinfo(result); } else { - LOGWARN(3, "getaddrinfo failed for " << nodes[i] << ": " << gai_strerror(err)); + LOGWARN(3, "getaddrinfo failed for " << cur_node << ": " << gai_strerror(err)); } } }; diff --git a/src/util.cpp b/src/util.cpp index cfb7f67..4306371 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -31,6 +31,15 @@ #include "upnpcommands.h" #endif +#ifdef _WIN32 +#include +#elif defined(HAVE_RES_QUERY) +#include +#include +#include +#include +#endif + static constexpr char log_category_prefix[] = "Util "; namespace p2pool { @@ -462,6 +471,69 @@ bool resolve_host(std::string& host, bool& is_v6) return true; } +bool get_dns_txt_records_base(const std::string& host, Callback::Base&& callback) +{ + if (disable_resolve_host) { + LOGERR(1, "get_dns_txt_records was called with DNS disabled for host " << host); + return false; + } + +#ifdef _WIN32 + PDNS_RECORD pQueryResults; + if (DnsQuery(host.c_str(), DNS_TYPE_TEXT, DNS_QUERY_STANDARD, NULL, &pQueryResults, NULL) != 0) { + return false; + } + + for (PDNS_RECORD p = pQueryResults; p; p = p->pNext) { + for (size_t j = 0; j < p->Data.TXT.dwStringCount; ++j) { + const char* s = p->Data.TXT.pStringArray[j]; + const size_t n = strlen(s); + if (n > 0) { + callback(s, n); + } + } + } + + DnsRecordListFree(pQueryResults, DnsFreeRecordList); + + return true; +#elif defined(HAVE_RES_QUERY) + static const int res_init_result = res_init(); + if (res_init_result != 0) { + return false; + } + + uint8_t answer[4096]; + const int anslen = res_query(host.c_str(), ns_c_in, ns_t_txt, answer, sizeof(answer)); + if ((anslen <= 0) || (anslen > static_cast(sizeof(answer)))) { + return false; + } + + ns_msg handle; + if (ns_initparse(answer, anslen, &handle) != 0) { + return false; + } + + for (int rrnum = 0, n = ns_msg_count(handle, ns_s_an); rrnum < n; ++rrnum) { + ns_rr rr; + if ((ns_parserr(&handle, ns_s_an, rrnum, &rr) == 0) && (ns_rr_type(rr) == ns_t_txt)) { + const uint8_t* s = ns_rr_rdata(rr); + const int n = std::min(ns_rr_rdlen(rr) - 1, *s); + if (n > 0) { + callback(reinterpret_cast(s + 1), static_cast(n)); + } + } + } + + return true; +#else + (void)host; + (void)callback; + + return false; +#endif +} + RandomDeviceSeed RandomDeviceSeed::instance; struct BSR8 diff --git a/src/util.h b/src/util.h index ffbec6c..fa8888f 100644 --- a/src/util.h +++ b/src/util.h @@ -296,6 +296,11 @@ struct Callback }; }; +bool get_dns_txt_records_base(const std::string& host, Callback::Base&& callback); + +template +FORCEINLINE bool get_dns_txt_records(const std::string& host, T&& callback) { return get_dns_txt_records_base(host, Callback::Derived(std::move(callback))); } + } // namespace p2pool void memory_tracking_start();