diff --git a/CMakeLists.txt b/CMakeLists.txt index 09973721..5655bfc8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,22 @@ cmake_minimum_required(VERSION 2.8.6) +set (CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") + +if (NOT DEFINED ENV{DEVELOPER_LOCAL_TOOLS}) + message(STATUS "Could not find DEVELOPER_LOCAL_TOOLS in env") + set(BOOST_IGNORE_SYSTEM_PATHS_DEFAULT OFF) +elseif ("$ENV{DEVELOPER_LOCAL_TOOLS}" EQUAL 1) + message(STATUS "found: env DEVELOPER_LOCAL_TOOLS = 1") + set(BOOST_IGNORE_SYSTEM_PATHS_DEFAULT ON) + option(BOOST_IGNORE_SYSTEM_PATHS "Ignore boost system paths for local boost installation" ON) +else() + message(STATUS "found: env DEVELOPER_LOCAL_TOOLS = 0") + set(BOOST_IGNORE_SYSTEM_PATHS_DEFAULT OFF) +endif() +message(STATUS "BOOST_IGNORE_SYSTEM_PATHS defaults to ${BOOST_IGNORE_SYSTEM_PATHS_DEFAULT}") +option(BOOST_IGNORE_SYSTEM_PATHS "Ignore boost system paths for local boost ins tallation" $BOOST_IGNORE_SYSTEM_PATHS_DEFAULT) + set_property(GLOBAL PROPERTY USE_FOLDERS ON) set(CMAKE_CONFIGURATION_TYPES "Debug;Release") enable_testing() @@ -51,25 +67,28 @@ endif() # elseif(CMAKE_SYSTEM_NAME MATCHES ".*BSDI.*") # set(BSDI TRUE) -function(set_static_flags) - if (NOT APPLE AND NOT FREEBSD) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++") - endif() -endfunction(set_static_flags) - include_directories(src contrib/epee/include external "${CMAKE_BINARY_DIR}/version") if(APPLE) include_directories(SYSTEM /usr/include/malloc) endif() -set(STATIC ${MSVC} CACHE BOOL "Link libraries statically") +if(MSVC OR MINGW) + set(DEFAULT_STATIC true) +else() + set(DEFAULT_STATIC false) +endif() +set(STATIC ${DEFAULT_STATIC} CACHE BOOL "Link libraries statically") if (UNIX AND NOT APPLE) # Note that at the time of this writing the -Wstrict-prototypes flag added below will make this fail find_package(Threads) endif() +# Find unbound - don't move this to the end, cmake is weird about this +find_package(Unbound REQUIRED) +include_directories(${UNBOUND_INCLUDE}) + if(MSVC) add_definitions("/bigobj /MP /W3 /GS- /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4345 /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /FIinline_c.h /D__SSE4_1__") # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Dinline=__inline") @@ -93,17 +112,11 @@ else() else() set(WARNINGS "${WARNINGS} -Wlogical-op -Wno-error=maybe-uninitialized") endif() - # Since gcc 4.9 the LTO format is non-standard (slim), so we need the gcc-specific ar and ranlib binaries - if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9.0)) - set(CMAKE_AR "gcc-ar") - set(CMAKE_RANLIB "gcc-ranlib") - endif() if(MINGW) - set(WARNINGS "${WARNINGS} -Wno-error=unused-value") - set(MINGW_FLAG "-DWIN32_LEAN_AND_MEAN") + set(WARNINGS "${WARNINGS} -Wno-error=unused-value -Wno-error=unused-but-set-variable") + set(MINGW_FLAG "${MINGW_FLAG} -DWIN32_LEAN_AND_MEAN") + set(Boost_THREADAPI win32) include_directories(SYSTEM src/platform/mingw) - else() - set(MINGW_FLAG "") endif() set(C_WARNINGS "-Waggregate-return -Wnested-externs -Wold-style-definition -Wstrict-prototypes") set(CXX_WARNINGS "-Wno-reorder -Wno-missing-field-initializers") @@ -123,14 +136,30 @@ else() else() set(DEBUG_FLAGS "-g3 -O0") endif() + set(RELEASE_FLAGS "-Ofast -DNDEBUG -Wno-unused-variable") - if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - # There is a clang bug that does not allow to compile code that uses AES-NI intrinsics if -flto is enabled - set(RELEASE_FLAGS "${RELEASE_FLAGS} -flto") + + if(NOT DEFINED USE_LTO_DEFAULT) + set(USE_LTO_DEFAULT true) endif() - #if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT MINGW) - # set(RELEASE_FLAGS "${RELEASE_FLAGS} -fno-fat-lto-objects") - #endif() + set(USE_LTO ${USE_LTO_DEFAULT} CACHE BOOL "Use Link-Time Optimization (Release mode only)") + + # There is a clang bug that does not allow to compile code that uses AES-NI intrinsics if -flto is enabled, so explicitly disable + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(USE_LTO false) + endif() + if(USE_LTO) + set(RELEASE_FLAGS "${RELEASE_FLAGS} -flto") + if(STATIC) + set(RELEASE_FLAGS "${RELEASE_FLAGS} -ffat-lto-objects") + endif() + # Since gcc 4.9 the LTO format is non-standard (slim), so we need the gcc-specific ar and ranlib binaries + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9.0)) + set(CMAKE_AR "gcc-ar") + set(CMAKE_RANLIB "gcc-ranlib") + endif() + endif() + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${DEBUG_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEBUG_FLAGS}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${RELEASE_FLAGS}") @@ -140,6 +169,10 @@ else() endif() endif() +if (BOOST_IGNORE_SYSTEM_PATHS) + set(Boost_NO_SYSTEM_PATHS TRUE) +endif() + if(STATIC) set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_RUNTIME ON) @@ -150,11 +183,11 @@ if((${Boost_MAJOR_VERSION} EQUAL 1) AND (${Boost_MINOR_VERSION} EQUAL 54)) endif() include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) if(MINGW) - set(Boost_LIBRARIES "${Boost_LIBRARIES};ws2_32;mswsock") + set(Boost_LIBRARIES "${Boost_LIBRARIES};pthread;mswsock;ws2_32") elseif(APPLE OR FREEBSD) set(Boost_LIBRARIES "${Boost_LIBRARIES}") elseif(NOT MSVC) - set(Boost_LIBRARIES "${Boost_LIBRARIES};rt;pthread") + #set(Boost_LIBRARIES "${Boost_LIBRARIES};rt;pthread") endif() file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/version") diff --git a/README.md b/README.md index e275c0eb..6f5b45d8 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Parts of the project are originally copyright (c) 2012-2013 The Cryptonote devel ### On Unix and Linux: -Dependencies: GCC 4.7.3 or later, CMake 2.8.6 or later, and Boost 1.53 or later (except 1.54, [more details here](http://goo.gl/RrCFmA)). +Dependencies: GCC 4.7.3 or later, CMake 2.8.6 or later, Unbound 1.4.16 or later, and Boost 1.53 or later (except 1.54, [more details here](http://goo.gl/RrCFmA)). **Basic Process:** @@ -77,16 +77,40 @@ Alternatively, it can be built in an easier and more automated fashion using Hom ### On Windows: -Dependencies: MSVC 2013 or later, CMake 2.8.6 or later, and Boost 1.53 or later (except 1.54, [more details here](http://goo.gl/RrCFmA)). +Dependencies: mingw-w64, msys2, CMake 2.8.6 or later, Unbound 1.4.16 or later, and Boost 1.53 or 1.55 (except 1.54, [more details here](http://goo.gl/RrCFmA), and 1.56 as it causes an internal compiler error on mingw-w64). -* To build, change to the root of the source code directory, and run these commands: +**Preparing the Build Environment** + +* Download the [MSYS2 installer](http://msys2.github.io), 64-bit or 32-bit as needed, and run it. +* Use the shortcut associated with your architecture to launch the MSYS2 environment. On 64-bit systems that would be the MinGW-w64 Win64 Shell shortcut. Note that if you are running 64-bit Windows, you will have both 64-bit and 32-bit environments. +* Update the packages in your MSYS2 install: +``` +pacman -Sy +pacman -Su --ignoregroup base +pacman -Su +``` +* For those of you already familiar with pacman, you can run the normal `pacman -Syu` to update, but you may get errors and need to restart MSYS2 if pacman's dependencies are updated. +* Install dependencies: `pacman -S mingw-w64-x86_64-gcc make mingw-w64-x86_64-cmake mingw-w64-x86_64-unbound` (note: in future, once the boost 1.56 mingw-w64 issues are fixed, you can add `mingw-w64-x86_64-boost` to that list to have it installed as well) +* Download the [boost 1.55 msys2 package](http://downloads.sourceforge.net/project/msys2/REPOS/MINGW/x86_64/mingw-w64-x86_64-boost-1.55.0-7-any.pkg.tar.xz), and install it by running `pacman -U mingw-w64-x86_64-boost-1.55.0-7-any.pkg.tar.xz` + +**Building** + +* From the root of the source code directory run: ``` mkdir build cd build -cmake -G "Visual Studio 12 Win64" -DBOOST_ROOT="c:\folder\to\boost_1_55_0" -DBOOST_LIBRARYDIR="c:\folder\to\boost_1_55_0\lib64-msvc-12.0" -msbuild Project.sln /p:Configuration=Release ``` -* If you don't have your path environment variable configured with the VS paths, you may may want to run `C:\program files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat` (or equivalent) to temporarily set the environment variables. +* If you are on a 64-bit system, run: +``` +cmake -G "MSYS Makefiles" -D CMAKE_BUILD_TYPE=Release -D CMAKE_TOOLCHAIN_FILE=../cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys64 .. +``` +* If you are on a 32-bit system, run: +``` +cmake -G "MSYS Makefiles" -D CMAKE_BUILD_TYPE=Release -D CMAKE_TOOLCHAIN_FILE=../cmake/32-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys32 .. +``` +* You can now run `make` to have it build + +If you installed MSYS2 in a folder other than c:/msys64, make the appropriate substitution above. ### On FreeBSD: diff --git a/cmake/32-bit-toolchain.cmake b/cmake/32-bit-toolchain.cmake new file mode 100644 index 00000000..4543c106 --- /dev/null +++ b/cmake/32-bit-toolchain.cmake @@ -0,0 +1,19 @@ +set (CMAKE_SYSTEM_NAME Windows) + +set (GCC_PREFIX i686-w64-mingw32) +set (CMAKE_C_COMPILER ${GCC_PREFIX}-gcc) +set (CMAKE_CXX_COMPILER ${GCC_PREFIX}-g++) +set (CMAKE_AR ar CACHE FILEPATH "" FORCE) +set (CMAKE_NM nm CACHE FILEPATH "" FORCE) +#set (CMAKE_RANLIB ${GCC_PREFIX}-gcc-ranlib CACHE FILEPATH "" FORCE) +set (CMAKE_RC_COMPILER windres) + +set (CMAKE_FIND_ROOT_PATH "${MSYS2_FOLDER}/mingw32") + +# Ensure cmake doesn't find things in the wrong places +set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # Find programs on host +set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) # Find libs in target +set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # Find includes in target + +set (MINGW_FLAG "-m32") +set (USE_LTO_DEFAULT false) diff --git a/cmake/64-bit-toolchain.cmake b/cmake/64-bit-toolchain.cmake new file mode 100644 index 00000000..e9b3cc51 --- /dev/null +++ b/cmake/64-bit-toolchain.cmake @@ -0,0 +1,19 @@ +set (CMAKE_SYSTEM_NAME Windows) + +set (GCC_PREFIX x86_64-w64-mingw32) +set (CMAKE_C_COMPILER ${GCC_PREFIX}-gcc) +set (CMAKE_CXX_COMPILER ${GCC_PREFIX}-g++) +set (CMAKE_AR ar CACHE FILEPATH "" FORCE) +set (CMAKE_NM nm CACHE FILEPATH "" FORCE) +#set (CMAKE_RANLIB ${GCC_PREFIX}-gcc-ranlib CACHE FILEPATH "" FORCE) +set (CMAKE_RC_COMPILER windres) + +set (CMAKE_FIND_ROOT_PATH "${MSYS2_FOLDER}/mingw64") + +# Ensure cmake doesn't find things in the wrong places +set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # Find programs on host +set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) # Find libs in target +set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # Find includes in target + +set (MINGW_FLAG "-m64") +set (USE_LTO_DEFAULT false) diff --git a/cmake/FindUnbound.cmake b/cmake/FindUnbound.cmake new file mode 100644 index 00000000..8d6f4ae7 --- /dev/null +++ b/cmake/FindUnbound.cmake @@ -0,0 +1,53 @@ +# Copyright (c) 2014, The Monero Project +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are +# permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list +# of conditions and the following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be +# used to endorse or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +MESSAGE("Looking for libunbound") + +FIND_PATH(UNBOUND_INCLUDE_DIR + NAMES unbound.h + PATH_SUFFIXES include/ include/unbound/ + PATHS "${PROJECT_SOURCE_DIR}" + ${UNBOUND_ROOT} + $ENV{UNBOUND_ROOT} + /usr/local/ + /usr/ +) + +find_library(UNBOUND_LIBRARIES unbound) + +IF(UNBOUND_INCLUDE_DIR) + MESSAGE(STATUS "Found unbound include in ${UNBOUND_INCLUDE_DIR}") + IF(UNBOUND_LIBRARIES) + MESSAGE(STATUS "Found unbound library") + set(UNBOUND_INCLUDE ${UNBOUND_INCLUDE_DIR}) + set(UNBOUND_LIBRARY ${UNBOUND_LIBRARIES}) + ELSE() + MESSAGE(FATAL_ERROR "Could not find unbound library") + ENDIF() +ELSE() + MESSAGE(FATAL_ERROR "Could not find unbound library") +ENDIF() diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index fd8cd4eb..f121162d 100755 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -216,7 +216,20 @@ MARK_AS_ADVANCED(MINIUPNP_INCLUDE_DIR MINIUPNP_LIBRARY) # And now on to the Monero part of things -if(MINIUPNP_FOUND AND MINIUPNPC_VERSION_1_7_OR_HIGHER) +# FreeBSD doesn't play well with the local copy +SET(USE_SHARED false) + +# If we have the correct shared version and we're not building static, use it +IF(MINIUPNP_FOUND AND MINIUPNPC_VERSION_1_7_OR_HIGHER AND !STATIC) + SET(USE_SHARED true) +ENDIF() + +# If we're on FreeBSD +IF(FREEBSD) + SET(USE_SHARED true) +ENDIF() + +if(USE_SHARED) message(STATUS "Using shared miniupnpc found at ${MINIUPNP_INCLUDE_DIR}") set(UPNP_STATIC false PARENT_SCOPE) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8138df3f..32115c8f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -65,18 +65,22 @@ add_library(mnemonics ${MNEMONICS}) add_executable(daemon ${DAEMON} ${P2P} ${CRYPTONOTE_PROTOCOL}) add_executable(connectivity_tool ${CONN_TOOL}) add_executable(simpleminer ${MINER}) -target_link_libraries(daemon rpc cryptonote_core crypto common ${UPNP_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) -target_link_libraries(connectivity_tool cryptonote_core crypto common ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) -target_link_libraries(simpleminer cryptonote_core crypto common ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(daemon rpc cryptonote_core crypto common ${UNBOUND_LIBRARIES} ${UPNP_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(connectivity_tool cryptonote_core crypto common ${UNBOUND_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(simpleminer cryptonote_core crypto common ${UNBOUND_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) add_library(rpc ${RPC}) add_library(wallet ${WALLET}) target_link_libraries(wallet mnemonics) add_executable(simplewallet ${SIMPLEWALLET} ) -target_link_libraries(simplewallet wallet rpc cryptonote_core crypto common mnemonics ${UPNP_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(simplewallet wallet rpc cryptonote_core crypto common mnemonics ${UNBOUND_LIBRARIES} ${UPNP_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) add_dependencies(daemon version) add_dependencies(rpc version) add_dependencies(simplewallet version) set_property(TARGET common crypto cryptonote_core rpc wallet PROPERTY FOLDER "libs") set_property(TARGET daemon simplewallet connectivity_tool simpleminer PROPERTY FOLDER "prog") +if (STATIC) + set_property(TARGET daemon simplewallet connectivity_tool simpleminer PROPERTY LINK_SEARCH_START_STATIC 1) + set_property(TARGET daemon simplewallet connectivity_tool simpleminer PROPERTY LINK_SEARCH_END_STATIC 1) +endif() set_property(TARGET daemon PROPERTY OUTPUT_NAME "bitmonerod") diff --git a/src/common/dns_utils.cpp b/src/common/dns_utils.cpp new file mode 100644 index 00000000..346761e7 --- /dev/null +++ b/src/common/dns_utils.cpp @@ -0,0 +1,231 @@ +// Copyright (c) 2014, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "common/dns_utils.h" +#include +#include +#include + +namespace tools +{ + +// fuck it, I'm tired of dealing with getnameinfo()/inet_ntop/etc +std::string ipv4_to_string(const char* src) +{ + std::stringstream ss; + unsigned int bytes[4]; + for (int i = 0; i < 4; i++) + { + unsigned char a = src[i]; + bytes[i] = a; + } + ss << bytes[0] << "." + << bytes[1] << "." + << bytes[2] << "." + << bytes[3]; + return ss.str(); +} + +// 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::stringstream ss; + unsigned int bytes[8]; + for (int i = 0; i < 8; i++) + { + unsigned char a = src[i]; + bytes[i] = a; + } + ss << bytes[0] << ":" + << bytes[1] << ":" + << bytes[2] << ":" + << bytes[3] << ":" + << bytes[4] << ":" + << bytes[5] << ":" + << bytes[6] << ":" + << bytes[7]; + return ss.str(); +} + +// custom smart pointer. +// TODO: see if std::auto_ptr and the like support custom destructors +class ub_result_ptr +{ +public: + ub_result_ptr() + { + ptr = nullptr; + } + ~ub_result_ptr() + { + ub_resolve_free(ptr); + } + ub_result* ptr; +}; + +struct DNSResolverData +{ + ub_ctx* m_ub_context; +}; + +DNSResolver::DNSResolver() : m_data(new DNSResolverData()) +{ + // init libunbound context + m_data->m_ub_context = ub_ctx_create(); + + char empty_string = '\0'; + + // look for "/etc/resolv.conf" and "/etc/hosts" or platform equivalent + ub_ctx_resolvconf(m_data->m_ub_context, &empty_string); + ub_ctx_hosts(m_data->m_ub_context, &empty_string); +} + +DNSResolver::~DNSResolver() +{ + if (m_data) + { + if (m_data->m_ub_context != NULL) + { + ub_ctx_delete(m_data->m_ub_context); + } + delete m_data; + } +} + +std::vector DNSResolver::get_ipv4(const std::string& url) +{ + std::vector addresses; + char urlC[1000]; // waaaay too big, but just in case... + + strncpy(urlC, url.c_str(), 999); + urlC[999] = '\0'; + if (!check_address_syntax(urlC)) + { + return addresses; + } + + // destructor takes care of cleanup + 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.ptr))) + { + if (result.ptr->havedata) + { + for (size_t i=0; result.ptr->data[i] != NULL; i++) + { + addresses.push_back(ipv4_to_string(result.ptr->data[i])); + } + } + } + + return addresses; +} + +std::vector DNSResolver::get_ipv6(const std::string& url) +{ + std::vector addresses; + char urlC[1000]; // waaaay too big, but just in case... + + strncpy(urlC, url.c_str(), 999); + urlC[999] = '\0'; + + 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.ptr))) + { + if (result.ptr->havedata) + { + for (size_t i=0; result.ptr->data[i] != NULL; i++) + { + addresses.push_back(ipv6_to_string(result.ptr->data[i])); + } + } + } + + return addresses; +} + +std::vector DNSResolver::get_txt_record(const std::string& url) +{ + std::vector records; + char urlC[1000]; // waaaay too big, but just in case... + + strncpy(urlC, url.c_str(), 999); + urlC[999] = '\0'; + + 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.ptr))) + { + if (result.ptr->havedata) + { + for (size_t i=0; result.ptr->data[i] != NULL; i++) + { + records.push_back(result.ptr->data[i]); + } + } + } + + return records; +} + +DNSResolver& DNSResolver::instance() +{ + static DNSResolver* staticInstance = NULL; + if (staticInstance == NULL) + { + staticInstance = new DNSResolver(); + } + return *staticInstance; +} + +bool DNSResolver::check_address_syntax(const std::string& addr) +{ + // if string doesn't contain a dot, we won't consider it a url for now. + if (addr.find(".") == std::string::npos) + { + return false; + } + return true; +} + +} // namespace tools diff --git a/src/common/dns_utils.h b/src/common/dns_utils.h new file mode 100644 index 00000000..dd6946dc --- /dev/null +++ b/src/common/dns_utils.h @@ -0,0 +1,122 @@ +// Copyright (c) 2014, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include +#include + +namespace tools +{ + +// RFC defines for record types and classes for DNS, gleaned from ldns source +const static int DNS_CLASS_IN = 1; +const static int DNS_TYPE_A = 1; +const static int DNS_TYPE_TXT = 16; +const static int DNS_TYPE_AAAA = 8; + +struct DNSResolverData; + +/** + * @brief Provides high-level access to DNS resolution + * + * This class is designed to provide a high-level abstraction to DNS resolution + * functionality, including access to TXT records and such. It will also + * handle DNSSEC validation of the results. + */ +class DNSResolver +{ +public: + + /** + * @brief Constructs an instance of DNSResolver + * + * Constructs a class instance and does setup stuff for the backend resolver. + */ + DNSResolver(); + + /** + * @brief takes care of freeing C pointers and such + */ + ~DNSResolver(); + + /** + * @brief gets ipv4 addresses from DNS query of a URL + * + * returns a vector of all IPv4 "A" records for given URL. + * If no "A" records found, returns an empty vector. + * + * @param url A string containing a URL to query for + * + * @return vector of strings containing ipv4 addresses + */ + std::vector get_ipv4(const std::string& url); + + /** + * @brief gets ipv6 addresses from DNS query + * + * returns a vector of all IPv6 "A" records for given URL. + * If no "A" records found, returns an empty vector. + * + * @param url A string containing a URL to query for + * + * @return vector of strings containing ipv6 addresses + */ + std::vector get_ipv6(const std::string& url); + + /** + * @brief gets all TXT records from a DNS query for the supplied URL; + * if no TXT record present returns an empty vector. + * + * @param url A string containing a URL to query for + * + * @return A vector of strings containing a TXT record; or an empty vector + */ + // TODO: modify this to accomodate DNSSEC + std::vector get_txt_record(const std::string& url); + + /** + * @brief Gets the singleton instance of DNSResolver + * + * @return returns a pointer to the singleton + */ + static DNSResolver& instance(); + +private: + + /** + * @brief Checks a string to see if it looks like a URL + * + * @param addr the string to be checked + * + * @return true if it looks enough like a URL, false if not + */ + bool check_address_syntax(const std::string& addr); + + DNSResolverData *m_data; +}; // class DNSResolver + +} // namespace tools diff --git a/src/crypto/slow-hash.c b/src/crypto/slow-hash.c index 3aff7bd5..d4f27e1e 100644 --- a/src/crypto/slow-hash.c +++ b/src/crypto/slow-hash.c @@ -41,12 +41,20 @@ #if defined(_MSC_VER) #include -#include +#include #define STATIC #define INLINE __inline #if !defined(RDATA_ALIGN16) #define RDATA_ALIGN16 __declspec(align(16)) #endif +#elif defined(__MINGW32__) +#include +#include +#define STATIC static +#define INLINE inline +#if !defined(RDATA_ALIGN16) +#define RDATA_ALIGN16 __attribute__ ((aligned(16))) +#endif #else #include #include @@ -287,7 +295,7 @@ STATIC INLINE void aes_pseudo_round_xor(const uint8_t *in, uint8_t *out, } } -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__MINGW32__) BOOL SetLockPagesPrivilege(HANDLE hProcess, BOOL bEnable) { struct @@ -325,7 +333,7 @@ void slow_hash_allocate_state(void) if(hp_state != NULL) return; -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__MINGW32__) SetLockPagesPrivilege(GetCurrentProcess(), TRUE); hp_state = (uint8_t *) VirtualAlloc(hp_state, MEMORY, MEM_LARGE_PAGES | MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); @@ -357,7 +365,7 @@ void slow_hash_free_state(void) free(hp_state); else { -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__MINGW32__) VirtualFree(hp_state, MEMORY, MEM_RELEASE); #else munmap(hp_state, MEMORY); diff --git a/src/cryptonote_core/checkpoints.cpp b/src/cryptonote_core/checkpoints.cpp index 3669a721..c76a2384 100644 --- a/src/cryptonote_core/checkpoints.cpp +++ b/src/cryptonote_core/checkpoints.cpp @@ -93,4 +93,13 @@ namespace cryptonote uint64_t checkpoint_height = it->first; return checkpoint_height < block_height; } + uint64_t checkpoints::get_max_height() + { + std::map< uint64_t, crypto::hash >::const_iterator highest = + std::max_element( m_points.begin(), m_points.end(), + ( boost::bind(&std::map< uint64_t, crypto::hash >::value_type::first, _1) < + boost::bind(&std::map< uint64_t, crypto::hash >::value_type::first, _2 ) ) ); + return highest->first; + } + } diff --git a/src/cryptonote_core/checkpoints.h b/src/cryptonote_core/checkpoints.h index 11c4b5eb..3dee4868 100644 --- a/src/cryptonote_core/checkpoints.h +++ b/src/cryptonote_core/checkpoints.h @@ -44,6 +44,7 @@ namespace cryptonote bool check_block(uint64_t height, const crypto::hash& h) const; bool check_block(uint64_t height, const crypto::hash& h, bool& is_a_checkpoint) const; bool is_alternative_block_allowed(uint64_t blockchain_height, uint64_t block_height) const; + uint64_t get_max_height(); private: std::map m_points; diff --git a/src/cryptonote_core/checkpoints_create.h b/src/cryptonote_core/checkpoints_create.h index 9d65dc24..7512ddd9 100644 --- a/src/cryptonote_core/checkpoints_create.h +++ b/src/cryptonote_core/checkpoints_create.h @@ -34,18 +34,79 @@ #include "misc_log_ex.h" #define ADD_CHECKPOINT(h, hash) CHECK_AND_ASSERT(checkpoints.add_checkpoint(h, hash), false); +#define JSON_HASH_FILE_NAME "checkpoints.json" + +struct t_hashline +{ + uint64_t height; + std::string hash; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(height) + KV_SERIALIZE(hash) + END_KV_SERIALIZE_MAP() +}; + +struct t_hash_json { + std::vector hashlines; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(hashlines) + END_KV_SERIALIZE_MAP() +}; namespace cryptonote { inline bool create_checkpoints(cryptonote::checkpoints& checkpoints) { + ADD_CHECKPOINT(1, "771fbcd656ec1464d3a02ead5e18644030007a0fc664c0a964d30922821a8148"); + ADD_CHECKPOINT(10, "c0e3b387e47042f72d8ccdca88071ff96bff1ac7cde09ae113dbb7ad3fe92381"); + ADD_CHECKPOINT(100, "ac3e11ca545e57c49fca2b4e8c48c03c23be047c43e471e1394528b1f9f80b2d"); + ADD_CHECKPOINT(1000, "5acfc45acffd2b2e7345caf42fa02308c5793f15ec33946e969e829f40b03876"); + ADD_CHECKPOINT(10000, "c758b7c81f928be3295d45e230646de8b852ec96a821eac3fea4daf3fcac0ca2"); ADD_CHECKPOINT(22231, "7cb10e29d67e1c069e6e11b17d30b809724255fee2f6868dc14cfc6ed44dfb25"); ADD_CHECKPOINT(29556, "53c484a8ed91e4da621bb2fa88106dbde426fe90d7ef07b9c1e5127fb6f3a7f6"); ADD_CHECKPOINT(50000, "0fe8758ab06a8b9cb35b7328fd4f757af530a5d37759f9d3e421023231f7b31c"); ADD_CHECKPOINT(80000, "a62dcd7b536f22e003ebae8726e9e7276f63d594e264b6f0cd7aab27b66e75e3"); ADD_CHECKPOINT(202612, "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698"); - ADD_CHECKPOINT(202613, "e2aa337e78df1f98f462b3b1e560c6b914dec47b610698b7b7d1e3e86b6197c2"); // from chainradar; verify this - ADD_CHECKPOINT(202614, "c29e3dc37d8da3e72e506e31a213a58771b24450144305bcba9e70fa4d6ea6fb"); // from chainradar; verify this - ADD_CHECKPOINT(205000, "5d3d7a26e6dc7535e34f03def711daa8c263785f73ec1fadef8a45880fde8063"); // from chainradar; verify this + ADD_CHECKPOINT(202613, "e2aa337e78df1f98f462b3b1e560c6b914dec47b610698b7b7d1e3e86b6197c2"); + ADD_CHECKPOINT(202614, "c29e3dc37d8da3e72e506e31a213a58771b24450144305bcba9e70fa4d6ea6fb"); + ADD_CHECKPOINT(205000, "5d3d7a26e6dc7535e34f03def711daa8c263785f73ec1fadef8a45880fde8063"); + ADD_CHECKPOINT(220000, "9613f455933c00e3e33ac315cc6b455ee8aa0c567163836858c2d9caff111553"); + ADD_CHECKPOINT(230300, "bae7a80c46859db355556e3a9204a337ae8f24309926a1312323fdecf1920e61"); + ADD_CHECKPOINT(230700, "93e631240ceac831da1aebfc5dac8f722c430463024763ebafa888796ceaeedf"); + ADD_CHECKPOINT(231350, "b5add137199b820e1ea26640e5c3e121fd85faa86a1e39cf7e6cc097bdeb1131"); + ADD_CHECKPOINT(232150, "955de8e6b6508af2c24f7334f97beeea651d78e9ade3ab18fec3763be3201aa8"); + + return true; + } + + inline bool load_checkpoins_from_json(cryptonote::checkpoints& checkpoints, std::string json_hashfile_fullpath) + { + boost::system::error_code errcode; + if (! (boost::filesystem::exists(json_hashfile_fullpath, errcode))) + { + LOG_PRINT_L0("Blockchain checkpoints file not found"); + return true; + } + + LOG_PRINT_L0("Adding checkpoints from blockchain hashfile"); + + uint64_t prev_max_height = checkpoints.get_max_height(); + LOG_PRINT_L0("Hard-coded max checkpoint height is " << prev_max_height); + t_hash_json hashes; + epee::serialization::load_t_from_json_file(hashes, json_hashfile_fullpath); + for (std::vector::const_iterator it = hashes.hashlines.begin(); it != hashes.hashlines.end(); ) + { + uint64_t height; + height = it->height; + if (height <= prev_max_height) { + LOG_PRINT_L0("ignoring checkpoint height " << height); + } else { + std::string blockhash = it->hash; + LOG_PRINT_L0("Adding checkpoint height " << height << ", hash=" << blockhash); + ADD_CHECKPOINT(height, blockhash); + } + ++it; + } + return true; } } diff --git a/src/cryptonote_core/difficulty.cpp b/src/cryptonote_core/difficulty.cpp index c26f8d90..d4d733e6 100644 --- a/src/cryptonote_core/difficulty.cpp +++ b/src/cryptonote_core/difficulty.cpp @@ -45,7 +45,7 @@ namespace cryptonote { using std::uint64_t; using std::vector; -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__MINGW32__) #include #include diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index 5eda6cb6..5c209482 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -44,6 +44,7 @@ using namespace epee; #include "p2p/net_node.h" #include "cryptonote_config.h" #include "cryptonote_core/checkpoints_create.h" +#include "cryptonote_core/checkpoints.h" #include "cryptonote_core/cryptonote_core.h" #include "rpc/core_rpc_server.h" #include "cryptonote_protocol/cryptonote_protocol_handler.h" @@ -203,6 +204,10 @@ int main(int argc, char* argv[]) cryptonote::checkpoints checkpoints; res = cryptonote::create_checkpoints(checkpoints); CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize checkpoints"); + boost::filesystem::path json(JSON_HASH_FILE_NAME); + boost::filesystem::path checkpoint_json_hashfile_fullpath = data_dir / json; + res = cryptonote::load_checkpoins_from_json(checkpoints, checkpoint_json_hashfile_fullpath.string().c_str()); + CHECK_AND_ASSERT_MES(res, 1, "Failed to load initial checkpoints"); //create objects and link them cryptonote::core ccore(NULL); diff --git a/src/daemon/daemon_commands_handler.h b/src/daemon/daemon_commands_handler.h index 58112e16..869c2adf 100644 --- a/src/daemon/daemon_commands_handler.h +++ b/src/daemon/daemon_commands_handler.h @@ -55,7 +55,7 @@ public: , bool testnet ) : m_srv(srv) - , m_testnet {testnet} + , m_testnet(testnet) { m_cmd_binder.set_handler("help", boost::bind(&daemon_cmmands_handler::help, this, _1), "Show this help"); m_cmd_binder.set_handler("print_pl", boost::bind(&daemon_cmmands_handler::print_pl, this, _1), "Print peer list"); diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 759b21fc..53a13f32 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -112,6 +112,13 @@ namespace nodetool size_t get_outgoing_connections_count(); peerlist_manager& get_peerlist_manager(){return m_peerlist;} private: + const std::vector m_seed_nodes_list = + { "seeds.moneroseeds.se" + , "seeds.moneroseeds.ae.org" + , "seeds.moneroseeds.ch" + , "seeds.moneroseeds.li" + }; + typedef COMMAND_REQUEST_STAT_INFO_T COMMAND_REQUEST_STAT_INFO; CHAIN_LEVIN_INVOKE_MAP2(p2p_connection_context); //move levin_commands_handler interface invoke(...) callbacks into invoke map diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 870e7572..08fd1d1e 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -35,6 +35,7 @@ #include "version.h" #include "string_tools.h" #include "common/util.h" +#include "common/dns_utils.h" #include "net/net_helper.h" #include "math_helper.h" #include "p2p_protocol_defs.h" @@ -195,7 +196,7 @@ namespace nodetool return true; } //----------------------------------------------------------------------------------- - inline void add_hardcoded_seed_node( + inline void append_net_address( std::vector & seed_nodes , std::string const & addr ) @@ -239,23 +240,39 @@ namespace nodetool { if (testnet) { - add_hardcoded_seed_node(m_seed_nodes, "107.152.187.202:28080"); - add_hardcoded_seed_node(m_seed_nodes, "197.242.158.240:28080"); - add_hardcoded_seed_node(m_seed_nodes, "107.152.130.98:28080"); + append_net_address(m_seed_nodes, "107.152.187.202:28080"); + append_net_address(m_seed_nodes, "197.242.158.240:28080"); + append_net_address(m_seed_nodes, "107.152.130.98:28080"); } else { - add_hardcoded_seed_node(m_seed_nodes, "62.210.78.186:18080"); - add_hardcoded_seed_node(m_seed_nodes, "195.12.60.154:18080"); - add_hardcoded_seed_node(m_seed_nodes, "54.241.246.125:18080"); - add_hardcoded_seed_node(m_seed_nodes, "107.170.157.169:18080"); - add_hardcoded_seed_node(m_seed_nodes, "54.207.112.216:18080"); - add_hardcoded_seed_node(m_seed_nodes, "78.27.112.54:18080"); - add_hardcoded_seed_node(m_seed_nodes, "209.222.30.57:18080"); - add_hardcoded_seed_node(m_seed_nodes, "80.71.13.55:18080"); - add_hardcoded_seed_node(m_seed_nodes, "107.178.112.126:18080"); - add_hardcoded_seed_node(m_seed_nodes, "107.158.233.98:18080"); - add_hardcoded_seed_node(m_seed_nodes, "64.22.111.2:18080"); + // for each hostname in the seed nodes list, attempt to DNS resolve and + // add the result addresses as seed nodes + // TODO: at some point add IPv6 support, but that won't be relevant + // for some time yet. + for (const std::string& addr_str : m_seed_nodes_list) + { + std::vector addr_list = tools::DNSResolver::instance().get_ipv4(addr_str); + for (const std::string& a : addr_list) + { + append_net_address(m_seed_nodes, a + ":18080"); + } + } + + if (!m_seed_nodes.size()) + { + append_net_address(m_seed_nodes, "62.210.78.186:18080"); + append_net_address(m_seed_nodes, "195.12.60.154:18080"); + append_net_address(m_seed_nodes, "54.241.246.125:18080"); + append_net_address(m_seed_nodes, "107.170.157.169:18080"); + append_net_address(m_seed_nodes, "54.207.112.216:18080"); + append_net_address(m_seed_nodes, "78.27.112.54:18080"); + append_net_address(m_seed_nodes, "209.222.30.57:18080"); + append_net_address(m_seed_nodes, "80.71.13.55:18080"); + append_net_address(m_seed_nodes, "107.178.112.126:18080"); + append_net_address(m_seed_nodes, "107.158.233.98:18080"); + append_net_address(m_seed_nodes, "64.22.111.2:18080"); + } } bool res = handle_command_line(vm, testnet); @@ -624,7 +641,9 @@ namespace nodetool peerlist_entry pe_local = AUTO_VAL_INIT(pe_local); pe_local.adr = na; pe_local.id = pi; - time(&pe_local.last_seen); + time_t last_seen; + time(&last_seen); + pe_local.last_seen = static_cast(last_seen); m_peerlist.append_with_peer_white(pe_local); //update last seen and push it to peerlist manager @@ -1102,7 +1121,9 @@ namespace nodetool peerlist_entry pe; pe.adr.ip = context.m_remote_ip; pe.adr.port = port_l; - time(&pe.last_seen); + time_t last_seen; + time(&last_seen); + pe.last_seen = static_cast(last_seen); pe.id = peer_id_l; this->m_peerlist.append_with_peer_white(pe); LOG_PRINT_CCONTEXT_L2("PING SUCCESS " << epee::string_tools::get_ip_string_from_int32(context.m_remote_ip) << ":" << port_l); diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h index b0232690..e3e387bb 100644 --- a/src/p2p/net_peerlist.h +++ b/src/p2p/net_peerlist.h @@ -128,7 +128,7 @@ namespace nodetool // access by peerlist_entry::net_adress boost::multi_index::ordered_unique, boost::multi_index::member >, // sort by peerlist_entry::last_seen< - boost::multi_index::ordered_non_unique, boost::multi_index::member > + boost::multi_index::ordered_non_unique, boost::multi_index::member > > > peers_indexed; @@ -140,7 +140,7 @@ namespace nodetool // access by peerlist_entry::net_adress boost::multi_index::ordered_unique, boost::multi_index::member >, // sort by peerlist_entry::last_seen< - boost::multi_index::ordered_non_unique, boost::multi_index::member > + boost::multi_index::ordered_non_unique, boost::multi_index::member > > > peers_indexed_old; public: diff --git a/src/p2p/p2p_protocol_defs.h b/src/p2p/p2p_protocol_defs.h index a14d00dc..44b8c5b5 100644 --- a/src/p2p/p2p_protocol_defs.h +++ b/src/p2p/p2p_protocol_defs.h @@ -53,7 +53,7 @@ namespace nodetool { net_address adr; peerid_type id; - time_t last_seen; + int64_t last_seen; }; struct connection_entry diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 22e95a1f..e80451cd 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -79,7 +79,7 @@ namespace cryptonote ) : m_core(cr) , m_p2p(p2p) - , m_testnet {testnet} + , m_testnet(testnet) {} //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::handle_command_line( diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 7a47dead..b10feb92 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -999,8 +1000,61 @@ bool simple_wallet::transfer(const std::vector &args_) cryptonote::tx_destination_entry de; if(!get_account_address_from_str(de.addr, m_wallet->testnet(), local_args[i])) { - fail_msg_writer() << "wrong address: " << local_args[i]; - return true; + // if treating as an address fails, try as url + bool dnssec_ok = false; + std::string url = local_args[i]; + + // attempt to get address from dns query + auto addresses_from_dns = tools::wallet2::addresses_from_url(url, dnssec_ok); + + // for now, move on only if one address found + if (addresses_from_dns.size() == 1) + { + if (get_account_address_from_str(de.addr, m_wallet->testnet(), addresses_from_dns[0])) + { + // if it was an address, prompt user for confirmation. + // inform user of DNSSEC validation status as well. + + std::string dnssec_str; + if (dnssec_ok) + { + dnssec_str = "DNSSEC validation PASSED!"; + } + else + { + dnssec_str = "DNSSEC validation FAILED!"; + } + std::stringstream prompt; + prompt << "For URL: " << url + << "," << dnssec_str << std::endl + << " Monero Address = " << addresses_from_dns[0] + << std::endl + << "Is this OK? (Y/n) " + ; + + // prompt the user for confirmation given the dns query and dnssec status + std::string confirm_dns_ok = command_line::input_line(prompt.str()); + if (confirm_dns_ok != "Y" && confirm_dns_ok != "y" && confirm_dns_ok != "Yes" && confirm_dns_ok != "yes") + { + fail_msg_writer() << "User terminated transfer request, disagreed with dns result from url: " << url; + return true; + } + } + else + { + fail_msg_writer() << "Failed to get a monero address from: " << local_args[i]; + return true; + } + } + else if (addresses_from_dns.size() > 1) + { + fail_msg_writer() << "Multiple Monero addresses found for given URL: " << url << ", this is not yet supported."; + } + else + { + fail_msg_writer() << "wrong address: " << local_args[i]; + return true; + } } bool ok = cryptonote::parse_amount(de.amount, local_args[i + 1]); diff --git a/src/version.cmake b/src/version.cmake index e851cdf0..2f3aa0b2 100644 --- a/src/version.cmake +++ b/src/version.cmake @@ -1,30 +1,83 @@ +# Copyright (c) 2014, The Monero Project +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are +# permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list +# of conditions and the following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be +# used to endorse or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +# Check what commit we're on execute_process(COMMAND "${GIT}" rev-parse --short HEAD RESULT_VARIABLE RET OUTPUT_VARIABLE COMMIT OUTPUT_STRIP_TRAILING_WHITESPACE) if(RET) + # Something went wrong, set the version tag to -unknown + message(WARNING "Cannot determine current commit. Make sure that you are building either from a Git working tree or from a source archive.") set(VERSIONTAG "unknown") configure_file("src/version.h.in" "${TO}") else() message(STATUS "You are currently on commit ${COMMIT}") + + # Get all the tags execute_process(COMMAND "${GIT}" show-ref --tags -d --abbrev RESULT_VARIABLE RET OUTPUT_VARIABLE TAGGEDCOMMITOUT OUTPUT_STRIP_TRAILING_WHITESPACE) - string(REPLACE " refs/" "\n" TAGGEDCOMMITOUT2 ${TAGGEDCOMMITOUT}) - string(REPLACE "\n" ";" TAGGEDCOMMITLIST ${TAGGEDCOMMITOUT2}) - list(GET TAGGEDCOMMITLIST -2 TAGGEDCOMMIT) - - if(RET OR NOT TAGGEDCOMMIT) - message(WARNING "Cannot determine most recent tag. Make sure that you are building either from a Git working tree or from a source archive.") - set(VERSIONTAG "${COMMIT}") + # Make sure we actually got some tags + if(TAGGEDCOMMITOUT) + string(LENGTH ${TAGGEDCOMMITOUT} TLEN) else() - message(STATUS "The most recent tag was at ${TAGGEDCOMMIT}") - if(${COMMIT} MATCHES ${TAGGEDCOMMIT}) - message(STATUS "You are building a tagged release") - set(VERSIONTAG "release") + set(TLEN 1) + endif() + + if(RET OR TLEN LESS 5) + message(WARNING "Cannot determine most recent tag. Make sure that you are building either from a Git working tree or from a source archive.") + set(VERSIONTAG "${COMMIT}") + else() + # Replace a bunch of things so we end up with a semi-colon separated list + string(REPLACE " refs/" "\n" TAGGEDCOMMITOUT2 ${TAGGEDCOMMITOUT}) + string(REPLACE "\n" ";" TAGGEDCOMMITLIST ${TAGGEDCOMMITOUT2}) + + # Grab the second-last item in the list, as that will be the hash of our most recent commit + list(GET TAGGEDCOMMITLIST -2 TAGGEDCOMMIT) + + if(NOT TAGGEDCOMMIT) + message(WARNING "Cannot determine most recent tag. Make sure that you are building either from a Git working tree or from a source archive.") + set(VERSIONTAG "${COMMIT}") else() - message(STATUS "You are ahead or behind of a tagged release") - set(VERSIONTAG "${COMMIT}") - endif() - endif() + message(STATUS "The most recent tag was at ${TAGGEDCOMMIT}") + + # Check if we're building that tagged commit or a different one + if(${COMMIT} MATCHES ${TAGGEDCOMMIT}) + message(STATUS "You are building a tagged release") + set(VERSIONTAG "release") + else() + message(STATUS "You are ahead or behind of a tagged release") + set(VERSIONTAG "${COMMIT}") + endif() + endif() + + endif() configure_file("src/version.h.in" "${TO}") endif() \ No newline at end of file diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 6222b0c0..b8f793d7 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -47,6 +47,7 @@ using namespace epee; #include "serialization/binary_utils.h" #include "cryptonote_protocol/blobdatatype.h" #include "mnemonics/electrum-words.h" +#include "common/dns_utils.h" extern "C" { @@ -751,6 +752,7 @@ void wallet2::add_unconfirmed_tx(const cryptonote::transaction& tx, uint64_t cha utd.m_sent_time = time(NULL); utd.m_tx = tx; } + //---------------------------------------------------------------------------------------------------- void wallet2::transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector& extra, cryptonote::transaction& tx, pending_tx& ptx) @@ -815,6 +817,67 @@ std::vector> split_amounts( } } // anonymous namespace +/** + * @brief gets a monero address from the TXT record of a DNS entry + * + * gets the monero address from the TXT record of the DNS entry associated + * with . If this lookup fails, or the TXT record does not contain an + * XMR address in the correct format, returns an empty string. + * will be set true or false according to whether or not the DNS query passes + * DNSSEC validation. + * + * @param url the url to look up + * @param dnssec_valid return-by-reference for DNSSEC status of query + * + * @return a monero address (as a string) or an empty string + */ +std::vector wallet2::addresses_from_url(const std::string& url, bool& dnssec_valid) +{ + // TODO: update this correctly once DNSResolver::get_txt_record() supports it. + dnssec_valid = false; + + std::vector addresses; + // get txt records + auto records = tools::DNSResolver::instance().get_txt_record(url); + + // for each txt record, try to find a monero address in it. + for (auto& rec : records) + { + std::string addr = address_from_txt_record(rec); + if (addr.size()) + { + addresses.push_back(addr); + } + } + + return addresses; +} + +//---------------------------------------------------------------------------------------------------- +// TODO: parse the string in a less stupid way, probably with regex +std::string wallet2::address_from_txt_record(const std::string& s) +{ + // make sure the txt record has "oa1:xmr" and find it + auto pos = s.find("oa1:xmr"); + + // search from there to find "recipient_address=" + pos = s.find("recipient_address=", pos); + + pos += 18; // move past "recipient_address=" + + // find the next semicolon + auto pos2 = s.find(";", pos); + if (pos2 != std::string::npos) + { + // length of address == 95, we can at least validate that much here + if (pos2 - pos == 95) + { + return s.substr(pos, 95); + } + } + return std::string(); +} + //---------------------------------------------------------------------------------------------------- // take a pending tx and actually send it to the daemon void wallet2::commit_tx(pending_tx& ptx) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 3311e343..90918677 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -196,6 +196,9 @@ namespace tools static bool parse_payment_id(const std::string& payment_id_str, crypto::hash& payment_id); + static std::vector addresses_from_url(const std::string& url, bool& dnssec_valid); + + static std::string address_from_txt_record(const std::string& s); private: bool store_keys(const std::string& keys_file_name, const std::string& password); void load_keys(const std::string& keys_file_name, const std::string& password); diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index 7914ff8e..ebec931e 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -383,11 +383,11 @@ namespace tools , uint64_t unlock_time , bool testnet ) - : transfer_error {std::move(loc), "transaction was not constructed"} - , m_sources {sources} - , m_destinations {destinations} - , m_unlock_time {unlock_time} - , m_testnet {testnet} + : transfer_error(std::move(loc), "transaction was not constructed") + , m_sources(sources) + , m_destinations(destinations) + , m_unlock_time(unlock_time) + , m_testnet(testnet) { } @@ -471,10 +471,10 @@ namespace tools , uint64_t fee , bool testnet ) - : transfer_error {std::move(loc), "transaction sum + fee exceeds " + cryptonote::print_money(std::numeric_limits::max())} - , m_destinations {destinations} - , m_fee {fee} - , m_testnet {testnet} + : transfer_error(std::move(loc), "transaction sum + fee exceeds " + cryptonote::print_money(std::numeric_limits::max())) + , m_destinations(destinations) + , m_fee(fee) + , m_testnet(testnet) { } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8bc68d9b..92c21dad 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -61,16 +61,16 @@ add_executable(unit_tests ${UNIT_TESTS}) add_executable(net_load_tests_clt net_load_tests/clt.cpp) add_executable(net_load_tests_srv net_load_tests/srv.cpp) -target_link_libraries(core_proxy cryptonote_core common crypto ${UPNP_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) -target_link_libraries(coretests cryptonote_core common crypto ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(core_proxy cryptonote_core common crypto ${UNBOUND_LIBRARIES} ${UPNP_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(coretests cryptonote_core common crypto ${UNBOUND_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) target_link_libraries(difficulty-tests cryptonote_core) -target_link_libraries(functional_tests cryptonote_core wallet common crypto ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(functional_tests cryptonote_core wallet common crypto ${UNBOUND_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) target_link_libraries(hash-tests crypto) target_link_libraries(hash-target-tests crypto cryptonote_core) -target_link_libraries(performance_tests cryptonote_core common crypto ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) -target_link_libraries(unit_tests cryptonote_core common crypto gtest_main ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) -target_link_libraries(net_load_tests_clt cryptonote_core common crypto gtest_main ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) -target_link_libraries(net_load_tests_srv cryptonote_core common crypto gtest_main ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(performance_tests cryptonote_core common crypto ${UNBOUND_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(unit_tests gtest_main cryptonote_core wallet crypto common ${UNBOUND_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(net_load_tests_clt cryptonote_core common crypto gtest_main ${UNBOUND_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(net_load_tests_srv cryptonote_core common crypto gtest_main ${UNBOUND_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) if(NOT MSVC) set_property(TARGET gtest gtest_main unit_tests net_load_tests_clt net_load_tests_srv APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-undef -Wno-sign-compare") diff --git a/tests/unit_tests/address_from_url.cpp b/tests/unit_tests/address_from_url.cpp new file mode 100644 index 00000000..22301d56 --- /dev/null +++ b/tests/unit_tests/address_from_url.cpp @@ -0,0 +1,107 @@ +// Copyright (c) 2014, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// FIXME: move this into a full wallet2 unit test suite, if possible + +#include "gtest/gtest.h" + +#include "wallet/wallet2.h" +#include + +TEST(AddressFromTXT, Success) +{ + std::string addr = "46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em"; + + std::string txtr = "oa1:xmr"; + txtr += " recipient_address="; + txtr += addr; + txtr += ";"; + + std::string res = tools::wallet2::address_from_txt_record(txtr); + + EXPECT_STREQ(addr.c_str(), res.c_str()); + + std::string txtr2 = "foobar"; + + txtr2 += txtr; + + txtr2 += "more foobar"; + + res = tools::wallet2::address_from_txt_record(txtr2); + + EXPECT_STREQ(addr.c_str(), res.c_str()); + + std::string txtr3 = "foobar oa1:xmr tx_description=\"Donation for Monero Development Fund\"; "; + txtr3 += "recipient_address="; + txtr3 += addr; + txtr3 += "; foobar"; + + res = tools::wallet2::address_from_txt_record(txtr3); + + EXPECT_STREQ(addr.c_str(), res.c_str()); +} + +TEST(AddressFromTXT, Failure) +{ + std::string txtr = "oa1:xmr recipient_address=not a real address"; + + std::string res = tools::wallet2::address_from_txt_record(txtr); + + ASSERT_STREQ("", res.c_str()); + + txtr += ";"; + + res = tools::wallet2::address_from_txt_record(txtr); + ASSERT_STREQ("", res.c_str()); +} + +TEST(AddressFromURL, Success) +{ + std::string addr = "46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em"; + + bool dnssec_result = false; + + std::vector addresses = tools::wallet2::addresses_from_url("donate.monero.cc", dnssec_result); + + EXPECT_EQ(1, addresses.size()); + if (addresses.size() == 1) + { + EXPECT_STREQ(addr.c_str(), addresses[0].c_str()); + } +} + +TEST(AddressFromURL, Failure) +{ + bool dnssec_result = false; + + std::vector addresses = tools::wallet2::addresses_from_url("example.invalid", dnssec_result); + + ASSERT_FALSE(dnssec_result); + + ASSERT_EQ(0, addresses.size()); +} diff --git a/tests/unit_tests/dns_resolver.cpp b/tests/unit_tests/dns_resolver.cpp new file mode 100644 index 00000000..27e981ef --- /dev/null +++ b/tests/unit_tests/dns_resolver.cpp @@ -0,0 +1,109 @@ +// Copyright (c) 2014, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include +#include + +#include "gtest/gtest.h" + +#include "common/dns_utils.h" + +TEST(DNSResolver, IPv4Success) +{ + tools::DNSResolver resolver; + + auto ips = resolver.get_ipv4("example.com"); + + ASSERT_EQ(1, ips.size()); + + ASSERT_STREQ("93.184.216.119", ips[0].c_str()); + + ips = tools::DNSResolver::instance().get_ipv4("example.com"); + + ASSERT_EQ(1, ips.size()); + + ASSERT_STREQ("93.184.216.119", ips[0].c_str()); +} + +TEST(DNSResolver, IPv4Failure) +{ + // guaranteed by IANA/ICANN/RFC to be invalid + tools::DNSResolver resolver; + + auto ips = resolver.get_ipv4("example.invalid"); + + ASSERT_EQ(0, ips.size()); + + ips = tools::DNSResolver::instance().get_ipv4("example.invalid"); + + ASSERT_EQ(0, ips.size()); +} + +TEST(DNSResolver, IPv6Success) +{ + tools::DNSResolver resolver; + + auto ips = resolver.get_ipv6("example.com"); + + ASSERT_EQ(1, ips.size()); + + ASSERT_STREQ("2606:2800:220:6d:26bf:1447:1097:aa7", ips[0].c_str()); + + ips = tools::DNSResolver::instance().get_ipv6("example.com"); + + ASSERT_EQ(1, ips.size()); + + ASSERT_STREQ("2606:2800:220:6d:26bf:1447:1097:aa7", ips[0].c_str()); +} + +TEST(DNSResolver, IPv6Failure) +{ + // guaranteed by IANA/ICANN/RFC to be invalid + tools::DNSResolver resolver; + + auto ips = resolver.get_ipv6("example.invalid"); + + ASSERT_EQ(0, ips.size()); + + ips = tools::DNSResolver::instance().get_ipv6("example.invalid"); + + ASSERT_EQ(0, ips.size()); +} + +TEST(DNSResolver, GetTXTRecord) +{ + + std::vector records = tools::DNSResolver::instance().get_txt_record("donate.monero.cc"); + + EXPECT_NE(0, records.size()); + + for (auto& rec : records) + { + std::cout << "TXT record for donate.monero.cc: " << rec << std::endl; + } +} diff --git a/utils/gpg_keys/oranjuice.asc b/utils/gpg_keys/oranjuice.asc new file mode 100644 index 00000000..48ef9fc8 --- /dev/null +++ b/utils/gpg_keys/oranjuice.asc @@ -0,0 +1,31 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQENBFQdV4IBCADBdDmK+nzA5ICNBe5hu3V+PGvJcgqZET6rtc9eAqWJJB+JkdqN +FEnlVtXNi00jM4aokCV3PSDKLhMsxmPgUjjDP7LCU/r1OYMlJGVsnvEYII6bpKji +J8bWb3FeA1ZJvD4dhn6RIkloCkBjTsgjWwyB1HraTdY4DfKjwoDl299M99gZi4LZ +YVz0klugeRmdbFg3SrURgpfx/jZArJXFEHwHac6cVRVxdlSOatf3wurFMMgOBb9c +Q44WAtxL+G7EtICdtN0y81OJ2cyFzN38jPGMh9uR1jDbOgLB27aYANo9FhXKi3xm +pYJCl7/B3VrUxfyDQxTztRhIcAY5wIu9GIhZABEBAAG0ME9yYW4gSnVpY2UgKC8v +IEdQRyBrZXkpIDxvcmFuanVpY2VzQGhvdG1haWwuY29tPokBPgQTAQIAKAUCVB1X +ggIbAwUJAeEzgAYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQccWvRsyygSR2 +KAf/b94PbLsKKwqDkoQYLCYDCjkWfqiY8R8f6jvAEhzmbW1BwRfSMbrCBbnT1li5 +80Ld2M1yHsefeU2D/wZd/sxtqa9jmpPh6GRBL4pWTV98SDqQOvo46N78Y8mzivg3 +e3rPyD6AiDY/c24d+FMynk29qc08YSR1evxbYt9K2ec02fHuutAb7ujTKc2IgkYG +YlQXgnd3sVTw6uiieH+yp0MD2HYLaPaneAboHG/H58EmFbR7fmPkyGTjetLR0o3J +PyYE2liU5GJWwuIxhuNxRh6EV3vmjYL5dQF1sl99JIBUSMmKQWch3Jq+uIKPFC28 +EUuvCc6sQEKTCg+yE0yXvPgXorkBDQRUHVeCAQgA7G7fRs16tmOLZjHwkqSMjNGg +6nAPzqTe+8xdfbgahgBJC9iq3ceK26jwZQkQjJWPZ6EXL8vB0nQTxc/ghGEorJ03 +Pa7vBNhX3WVWuG4sZqZhX4mfLN2DAYr197C4KOW5Hmw+PP/Ru55xuyIL7tUIv/Fi +ohe55P7HunZ811zu5ypk7nJIza97VnKhWj6U7gaFKTEA6DI/3D6fobjgT2jXT5uG +lKO9QyRSfuZpt6nvRzDOIjorkF0cg9XYktsL5T34KLvJ2vnHJoHAbxvo1LRTdFzq +gfomwrgi+dSe41uNZZwFSKZWz+NMnSADj3A4ea2yyCrEMDyOXJPQ/PdlsCmkywAR +AQABiQElBBgBAgAPBQJUHVeCAhsMBQkB4TOAAAoJEHHFr0bMsoEka/8IAKdYJ03D +MZ6chIfy3uEMBTi9kHBRffltqSG4Z5/l4eT/JmF5prY075c/hEy9iv8uGntPNfoG +TzIAFXUBtAifyzvTP0CQExXdRJQjGjwCKPpF3w8fYW0zNOITuyJi+MD1RPSMz7/v +hvFh1SSbUBCfY3yBL80P81diPYqSyWVCZzFADiLZ0BPJJnQW09NNcUvfu71PS2SQ +JCpgVbRaxu4h6oEeq7R1Oodwm4FD8KaEg+QBSjysqPXnyHLfd+zT+mfI6xqiQAcf +khMh42KT/uKuaqb3/Xpk1invRDBisQVY/D5Jp5ThWBHUb+LkVLQZd0cS0EQlb1CM +S3iMwD+QAYLrhZs= +=q3wo +-----END PGP PUBLIC KEY BLOCK----- diff --git a/utils/gpg_keys/tewinget.asc b/utils/gpg_keys/tewinget.asc new file mode 100644 index 00000000..1153d2c2 --- /dev/null +++ b/utils/gpg_keys/tewinget.asc @@ -0,0 +1,19 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQENBFQZzOoBCACidWQPdZTfNsJqQs7mTJQSH6IHlaZuDuFFXvnnD5c+FEdHInib +a3BgISAsZ9k54F+duJbel8GLJSu+/DfdFVkdLoIRIpiVTicvrQkh/a4cm+5Zmg/Z +R4Syo4VQFJK52CVu0nGFWISYVSoXalEbSna9AjoLPJ/ZSCyhTw1+LvjH6te5hoQP +VGuDj7ZxbQX5I1qT4QtuGxKRqSGf/ISSyWmbVjzarPv3Mzqqvza26cxksnvxVmib +o6ITmbp51ZncLyw/QRwQIdl28C4He6/CQgWZccuOVbO2T9aCT5toSkoyG8wYbBTH +AnV/IxogjFkLZIaq4HXjEvhJsMfSsNDftwl7ABEBAAG0O1Rob21hcyBXaW5nZXQg +KFNpZ25pbmcga2V5IGZvciBNb25lcm8pIDx0ZXdpbmdldEBnbWFpbC5jb20+iQE4 +BBMBAgAiBQJUGczqAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRBYExoW +B4nmMOTaB/952ZSgf0FdOeUNma2gI9Ipz5tFk73fvvVQ5YXZASIroAVWDJ7e6jTk +ESrrubrQnuiVSj5GHjPfqyWEcA0EJ2OKtKi3f1sM0j+aBsR1yfyC9tuWJvIC1E60 +4BTXXlK1q3tMXhnxBvrqOnNiuLouxWdx6q+R17xu3kguPkXrsrl8ZDEjUl9JaoXi +OKlmCmujB2IVCf5If44ZoRANoF6MdvlBq5TZv1p2etzz+sJ8cWrcalRlUdA8DcdJ +ENfsqndAsm8ID8fYokiCr49jE1QSypWElE65JDsVgX6Yjzz98BYy/9s15YbE5McG +Wvg1RzElvwv588XbqxJhEhDZTQW8Dx0z +=3FSH +-----END PGP PUBLIC KEY BLOCK----- \ No newline at end of file diff --git a/utils/gpg_keys/tomerkon.asc b/utils/gpg_keys/tomerkon.asc new file mode 100644 index 00000000..4e946a6e --- /dev/null +++ b/utils/gpg_keys/tomerkon.asc @@ -0,0 +1,30 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQENBFQi1rkBCAC/hoa6yhCpPG3tZINuGBbY/dJWIlKECJ/3dgDN/LMumHqEH91X +goS6Ulw0R+fwDWna/bYMWHNbw9mBujHfaZDBCmMzfbcMgAt1jC/+rnd39rNPcvh+ +4gpRx6Wt20hxqtkNAnND+5ce9t4RA9wXjZA2/M5R9EYXX/Xna0Z6tWkB51aKkxm4 +N5Wz6PmUjScmhCd1IP7P/yDv6Aen6M8Lu8ogCfui1C3a6Cel8MevfkC9fGCkMvoq +3v5NhEVop8Q8Am4Ts+DOcDNXSp8GPUlhyBy1cK7NelxLADM+TFtkPapEJZedW1KR ++V/nn3L1pKoT2XJAWWi0VXwpLIwrYQJuqrK1ABEBAAG0IXRvbWVyIGtvbmZvcnR5 +IDx0b21lcmtAa29uNDAuY29tPokBOAQTAQIAIgUCVCLWuQIbAwYLCQgHAwIGFQgC +CQoLBBYCAwECHgECF4AACgkQlqdxPzlO6quNRQgAratbsWbgSphSaBgLHrRYpO2D +8TWsK5Qy9ZxGVud2ynmXKcUZukqWRyw9+X22wpNTCeZNHI7srGohF7SeyfIemSx9 +7OfN6Tu2hxz1zi1lq7hMnCNoI9UQSdZaGDm+loI07OnMHugit7ojn9lcW3CKUYzP +AfTc1IAV5ZQpwPmPN0yf6SKnFIkD3X9SZRWhGeoUOZKr2KEMvBpNWoFfee91cCR2 +eTiTkaIE8P6Cfdv6rdlQFNqsj7TuBq6Zfru1DtUOdHYs089KR0av81W+U2RpGXc2 +AfOmn4kzVffZXdh6D/i4oTg8D6YcVvOZzVtAJVshayYSjD09kjNw+uKAO0nyebkB +DQRUIta5AQgA23KCSdFdnvTJK+kOcMD/99zZz1XMcqpjBc2aP8+zdilC6XjZDjcg +8+NSdOCYCCHeO80Zd16yynrjvUW4D+PnaM3thdoigYJjEelx7wJls7C4U8hKfcFs +U3YhZEKm2vXqomgrpCT5NExHcOjzi5yMUQ7ocUct79jui0XRhzkmj0vu67rSRWpT +fSpvBwrhCUnC71aNy2QgbadxziLw2Gm983cpdO/wd3wnoz3JTXAYntJOg+7Q8VDg +fiYesuPpCiAJLKZ3z/b5kQXMnK82Oi8H5FTFb10OEDhbgyIqABWOXmds2Uj211ux +Ui5IIH4AScKvo+iKRbgWCs1kCkXQaD9OvQARAQABiQEfBBgBAgAJBQJUIta5AhsM +AAoJEJancT85TuqrSCwH/Rpnp+35opS9b1MvfhUBuJAjIPy9tVwMuz4+NyUfh+g6 +M3ksbtGbzZ8EWZi3KJ3iQVdcwvzzMYZxFPXeLmH/FLu37uFtLTlBg7SDEzoHV6dE +/dvGtYRFM7/QdCu9rrWt7zaEDjH7UnasGoZ6mY/v78UK7Q506w7fG8rtMFFupq7D +rWfuA8Dbq31FJ0hdbkezGEF55+jsRwIqmVGHaNvdTm+GyiFibwkc7p6+ynBco8xv +zr98VSNx5fM50XBc+pzhAHxzxhIgrmwx5zsQxMmd8pAh4deZUKIyk40XKrwikjoy +KLjUdEc73bEjhr1rlVGj6tBVNspHVx5XbUvmDtD1s7E= +=EaRm +-----END PGP PUBLIC KEY BLOCK----- \ No newline at end of file