Remove openssl, unbound, expat, OpenAlias

openssl is a miserable dependency to fight with, especially for
iOS/Android, and we use it for very little:

- it gets (mis)used to write base64 data to a file in wallet2 for things
  like multisig data.  However this mode is *not* enabled by default,
  basically completely unknown, completely unused, only exists in the
  cli wallet, and is just dumb.  (Honestly the justification given in
  the PR is that "Windows users might want it", presupposing that there
  exists Windows users who are capable of generating a multisig wallet
  in a CLI-only application and yet are incapable of dealing with binary
  files).

- it's a dependency of unbound (in order to do dnssec, I believe).
  Unbound itself is fairly useless for Oxen, so I've removed it too:
    - it does OpenAlias lookups, which are a Monero thing that has never
      been used outside Monero, doesn't work reliably (because it fails
      if the result isn't DNSSEC validated) and is pointless when we
      have ONS.

    - it does DNS resolution on seed nodes, but we have never set seed
      nodes by name and just use seed node IPs instead (which seems a
      bit better anyway since the DNS lookup leaks some metadata).

- it *was* being used for sha256, but an earlier commit in this PR
  already replaced that with libsodium (entirely coincidentally).

- for static deps, it enables HTTPS support for the wallet.  However
  only the CLI wallet actually supports this (the GUI and mobile wallets
  don't), and since oxend hasn't support this for a while I have strong
  doubts it is being used anywhere.  (Plus wallet3 will do everything
  encrypted using zmq/libsodium, so doesn't need this to be secure).
  Note here that it is *only* removed by this commit for static builds:
  if doing a system build that links to libcurl supporting HTTPS then
  HTTPS support will still work.

Libexpat is also gone because it was only there for libunbound.
This commit is contained in:
Jason Rhinelander 2022-04-14 20:11:36 -03:00
parent 5d42ae4c4d
commit 5e95cef882
No known key found for this signature in database
GPG Key ID: C4992CE7A88D4262
34 changed files with 77 additions and 1853 deletions

View File

@ -428,24 +428,6 @@ find_package(Threads)
if (APPLE AND NOT IOS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=x86-64 -fvisibility=default")
if (NOT OpenSSL_DIR)
EXECUTE_PROCESS(COMMAND brew --prefix openssl
OUTPUT_VARIABLE OPENSSL_ROOT_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE)
message(STATUS "Using OpenSSL found at ${OPENSSL_ROOT_DIR}")
endif()
endif()
if(BUILD_STATIC_DEPS)
# SSL::* targets already set up
else()
find_package(OpenSSL REQUIRED)
endif()
message(STATUS "Using OpenSSL include dir at ${OPENSSL_INCLUDE_DIR}")
if(MINGW)
# OpenSSL doesn't seem to properly set up its dependencies on Windows, leading to linking errors
target_link_libraries(OpenSSL::Crypto INTERFACE ws2_32)
endif()
add_definition_if_library_exists(c memset_s "string.h" HAVE_MEMSET_S)
@ -794,7 +776,7 @@ set(Boost_USE_MULTITHREADED TRUE) # Needed for macOS, at least, and won't hurt e
if(BUILD_STATIC_DEPS)
# StaticBuild.cmake sets Boost targets up for us
else()
find_package(Boost 1.58 QUIET REQUIRED COMPONENTS system thread serialization program_options)
find_package(Boost 1.62 QUIET REQUIRED COMPONENTS system thread serialization program_options)
endif()
set(CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_LIB_SUFFIXES})
@ -802,12 +784,6 @@ if(NOT Boost_FOUND)
message(FATAL_ERROR "Could not find Boost libraries, please make sure you have installed Boost or libboost-all-dev (>=1.58) or the equivalent")
elseif(Boost_FOUND)
message(STATUS "Found Boost Version: ${Boost_VERSION}")
if (OPENSSL_VERSION VERSION_GREATER_EQUAL 1.1 AND (
Boost_VERSION VERSION_LESS 1.62.0 OR (Boost_VERSION VERSION_GREATER 100000 AND Boost_VERSION VERSION_LESS 106200)))
message(FATAL_ERROR "Boost ${Boost_VERSION} (older than 1.62) is too old to link with OpenSSL ${OPENSSL_VERSION} (1.1 or newer) found at ${OPENSSL_INCLUDE_DIR} and ${OPENSSL_LIBRARIES}. "
"Update Boost or install OpenSSL 1.0 and set path to it when running cmake: "
"cmake -DOPENSSL_ROOT_DIR='/usr/include/openssl-1.0'")
endif()
endif()
# Interface target for random extra system libraries that we need to link everything against

View File

@ -43,18 +43,14 @@ library archives (`.a`).
| CMake | 3.10 | NO | `cmake` | `cmake` | `cmake` | NO | |
| pkg-config | any | NO | `pkg-config` | `base-devel` | `pkgconf` | NO | |
| Boost | 1.65 | NO | `libboost-all-dev`[2] | `boost` | `boost-devel` | NO | C++ libraries |
| OpenSSL | basically any | NO | `libssl-dev` | `openssl` | `openssl-devel` | NO | sha256 sum |
| libzmq | 4.3.0 | YES | `libzmq3-dev` | `zeromq` | `zeromq-devel` | NO | ZeroMQ library |
| sqlite3 | ? | YES | `libsqlite3-dev` | `sqlite` | `sqlite-devel` | NO | Oxen Name System |
| libunbound | 1.4.16 | NO | `libunbound-dev` | `unbound` | `unbound-devel` | NO | DNS resolver |
| libsodium | 1.0.9 | YES | `libsodium-dev` | `libsodium` | `libsodium-devel` | NO | cryptography |
| libcurl | 4.0 | NO | `libcurl4-openssl-dev` | `curl` | `curl-devel` | NO | HTTP RPC |
| libcurl | 4.0 | NO | `libcurl4-dev` | `curl` | `curl-devel` | NO | HTTP RPC |
| libuv (Win) | any | NO | (Windows only) | -- | -- | NO | RPC event loop |
| libunwind | any | NO | `libunwind8-dev` | `libunwind` | `libunwind-devel` | YES | Stack traces |
| liblzma | any | NO | `liblzma-dev` | `xz` | `xz-devel` | YES | For libunwind |
| libreadline | 6.3.0 | NO | `libreadline-dev` | `readline` | `readline-devel` | YES | Input editing |
| ldns | 1.6.17 | NO | `libldns-dev` | `ldns` | `ldns-devel` | YES | SSL toolkit |
| expat | 1.1 | NO | `libexpat1-dev` | `expat` | `expat-devel` | YES | XML parsing |
| Doxygen | any | NO | `doxygen` | `doxygen` | `doxygen` | YES | Documentation |
| Graphviz | any | NO | `graphviz` | `graphviz` | `graphviz` | YES | Documentation |
| Qt tools | 5.x | NO | `qttools5-dev` | `qt5-tools` | `qt5-linguist` | YES | Translations |
@ -73,14 +69,14 @@ breakdown of the minimum set of required boost packages.
Install all dependencies at once on Debian/Ubuntu:
```
sudo apt update && sudo apt install build-essential cmake pkg-config libboost-all-dev libssl-dev libzmq3-dev libunbound-dev libsodium-dev libunwind8-dev liblzma-dev libreadline6-dev libldns-dev libexpat1-dev doxygen graphviz libpgm-dev libsqlite3-dev libcurl4-openssl-dev
sudo apt update && sudo apt install build-essential cmake pkg-config libboost-all-dev libzmq3-dev libsodium-dev libunwind8-dev liblzma-dev libreadline6-dev doxygen graphviz libpgm-dev libsqlite3-dev libcurl4-dev
```
Install all dependencies at once on macOS with the provided Brewfile:
``` brew update && brew bundle --file=contrib/brew/Brewfile ```
FreeBSD one liner for required to build dependencies
```pkg install git gmake cmake pkgconf boost-libs libzmq4 libsodium sqlite3 openssl unbound```
```pkg install git gmake cmake pkgconf boost-libs libzmq4 libsodium sqlite3```
### Build instructions
@ -190,13 +186,13 @@ application.
To build for 64-bit Windows:
```bash
pacman -S git mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-sqlite3 mingw-w64-x86_64-unbound
pacman -S git mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-boost mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-sqlite3
```
To build for 32-bit Windows:
```bash
pacman -S git mingw-w64-i686-toolchain make mingw-w64-i686-cmake mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-zeromq mingw-w64-i686-libsodium mingw-w64-i686-hidapi mingw-w64-i686-sqlite3 mingw-w64-i686-unbound
pacman -S git mingw-w64-i686-toolchain make mingw-w64-i686-cmake mingw-w64-i686-boost mingw-w64-i686-zeromq mingw-w64-i686-libsodium mingw-w64-i686-hidapi mingw-w64-i686-sqlite3
```
* Close and reopen the MSYS MinGW shell via `MSYS2 MinGW 64-bit` shortcut on

View File

@ -5,26 +5,6 @@
set(LOCAL_MIRROR "" CACHE STRING "local mirror path/URL for lib downloads")
set(OPENSSL_VERSION 3.0.2 CACHE STRING "openssl version")
set(OPENSSL_MIRROR ${LOCAL_MIRROR} https://www.openssl.org/source CACHE STRING "openssl download mirror(s)")
set(OPENSSL_SOURCE openssl-${OPENSSL_VERSION}.tar.gz)
set(OPENSSL_HASH SHA256=98e91ccead4d4756ae3c9cde5e09191a8e586d9f4d50838e7ec09d6411dfdb63
CACHE STRING "openssl source hash")
set(EXPAT_VERSION 2.4.4 CACHE STRING "expat version")
string(REPLACE "." "_" EXPAT_TAG "R_${EXPAT_VERSION}")
set(EXPAT_MIRROR ${LOCAL_MIRROR} https://github.com/libexpat/libexpat/releases/download/${EXPAT_TAG}
CACHE STRING "expat download mirror(s)")
set(EXPAT_SOURCE expat-${EXPAT_VERSION}.tar.xz)
set(EXPAT_HASH SHA512=c88a82f4732e27340eb9480c082bcc909b0284e16b368ee9feeb4e2dd058e8f7c42fd48feacd5272cc76cb78bd183df33eb5d0b135fdd1d3c493cb156572ab76
CACHE STRING "expat source hash")
set(UNBOUND_VERSION 1.15.0 CACHE STRING "unbound version")
set(UNBOUND_MIRROR ${LOCAL_MIRROR} https://nlnetlabs.nl/downloads/unbound CACHE STRING "unbound download mirror(s)")
set(UNBOUND_SOURCE unbound-${UNBOUND_VERSION}.tar.gz)
set(UNBOUND_HASH SHA256=a480dc6c8937447b98d161fe911ffc76cfaffa2da18788781314e81339f1126f
CACHE STRING "unbound source hash")
set(BOOST_VERSION 1.79.0 CACHE STRING "boost version")
set(BOOST_MIRROR ${LOCAL_MIRROR} https://boostorg.jfrog.io/artifactory/main/release/${BOOST_VERSION}/source
CACHE STRING "boost download mirror(s)")
@ -141,16 +121,12 @@ if (ANDROID)
endif()
if(CMAKE_ANDROID_ARCH_ABI MATCHES x86_64)
set(android_clang x86_64-linux-android${ANDROID_PLATFORM_LEVEL}-clang)
set(openssl_machine android-x86_64)
elseif(CMAKE_ANDROID_ARCH_ABI MATCHES x86)
set(android_clang i686-linux-android${ANDROID_PLATFORM_LEVEL}-clang)
set(openssl_machine android-x86)
elseif(CMAKE_ANDROID_ARCH_ABI MATCHES armeabi-v7a)
set(android_clang armv7a-linux-androideabi${ANDROID_PLATFORM_LEVEL}-clang)
set(openssl_machine android-arm)
elseif(CMAKE_ANDROID_ARCH_ABI MATCHES arm64-v8a)
set(android_clang aarch64-linux-android${ANDROID_PLATFORM_LEVEL}-clang)
set(openssl_machine android-arm64)
else()
message(FATAL_ERROR "Don't know how to build for android arch abi ${CMAKE_ANDROID_ARCH_ABI}")
endif()
@ -276,81 +252,6 @@ add_static_target(zlib zlib_external libz.a)
set(openssl_configure_extra)
set(openssl_system_env "")
set(openssl_cc "${deps_cc}")
if(CMAKE_CROSSCOMPILING)
if(ARCH_TRIPLET STREQUAL x86_64-w64-mingw32)
set(openssl_configure_extra mingw64)
set(openssl_system_env RC=${CMAKE_RC_COMPILER})
elseif(ARCH_TRIPLET STREQUAL i686-w64-mingw32)
set(openssl_configure_extra mingw)
set(openssl_system_env RC=${CMAKE_RC_COMPILER})
elseif(ANDROID)
set(openssl_configure_extra ${openssl_machine} -D__ANDROID_API__=21)
set(openssl_system_env ${cross_extra})
list(APPEND openssl_system_env "ANDROID_NDK_ROOT=${ANDROID_NDK}")
list(APPEND openssl_system_env "PATH=${ANDROID_TOOLCHAIN_ROOT}/bin:${ANDROID_NDK}/toolchains/${ANDROID_TOOLCHAIN_NAME}/prebuilt/linux-x86_64/bin:$ENV{PATH}")
set(openssl_extra_opts no-asm)
elseif(IOS)
get_filename_component(apple_toolchain "${CMAKE_C_COMPILER}" DIRECTORY)
get_filename_component(apple_sdk "${CMAKE_OSX_SYSROOT}" NAME)
if(NOT ${apple_toolchain} MATCHES Xcode OR NOT ${apple_sdk} MATCHES "iPhone(OS|Simulator)")
message(FATAL_ERROR "didn't find your toolchain and sdk correctly from ${CMAKE_C_COMPILER}/${CMAKE_OSX_SYSROOT}: found toolchain=${apple_toolchain}, sdk=${apple_sdk}")
endif()
set(openssl_system_env CROSS_COMPILE=${apple_toolchain}/ CROSS_TOP=${CMAKE_DEVELOPER_ROOT} CROSS_SDK=${apple_sdk})
set(openssl_configure ./Configure iphoneos-cross)
set(openssl_cc "clang")
endif()
endif()
build_external(openssl
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env CC=${openssl_cc} "CFLAGS=${deps_CFLAGS}" ${openssl_system_env}
./Configure ${openssl_configure_extra} --prefix=${DEPS_DESTDIR} --libdir=lib ${openssl_extra_opts}
no-shared no-capieng no-dso no-dtls1 no-ec_nistp_64_gcc_128 no-gost
no-md2 no-rc5 no-rdrand no-rfc3779 no-sctp no-ssl-trace no-ssl3
no-static-engine no-tests no-weak-ssl-ciphers no-zlib-dynamic
BUILD_COMMAND ${CMAKE_COMMAND} -E env CC=${openssl_cc} ${openssl_system_env} make
INSTALL_COMMAND make install_sw
BUILD_BYPRODUCTS
${DEPS_DESTDIR}/lib/libssl.a ${DEPS_DESTDIR}/lib/libcrypto.a
${DEPS_DESTDIR}/include/openssl/ssl.h ${DEPS_DESTDIR}/include/openssl/crypto.h
)
add_static_target(OpenSSL::SSL openssl_external libssl.a)
add_static_target(OpenSSL::Crypto openssl_external libcrypto.a)
set(OPENSSL_INCLUDE_DIR ${DEPS_DESTDIR}/include)
build_external(expat
CONFIGURE_COMMAND ./configure ${cross_host} --prefix=${DEPS_DESTDIR} --enable-static
--disable-shared --with-pic --without-examples --without-tests --without-docbook --without-xmlwf
"CC=${deps_cc}" "CFLAGS=${deps_CFLAGS}"
)
add_static_target(expat expat_external libexpat.a)
set(unbound_extra)
if(APPLE AND IOS)
# I have no idea why this is necessary: without this it runs `clang -E` which should work, but
# doesn't because... hurray ios is wonderful?
set(unbound_extra CPP=cpp)
endif()
build_external(unbound
DEPENDS openssl_external expat_external
CONFIGURE_COMMAND ./configure ${cross_host} ${cross_extra} --prefix=${DEPS_DESTDIR} --disable-shared
--enable-static --with-libunbound-only --with-pic --disable-gost
--$<IF:$<BOOL:${USE_LTO}>,enable,disable>-flto --with-ssl=${DEPS_DESTDIR}
--with-libexpat=${DEPS_DESTDIR}
"CC=${deps_cc}" "CFLAGS=${deps_CFLAGS}" ${unbound_extra}
)
add_static_target(libunbound unbound_external libunbound.a)
target_link_libraries(libunbound INTERFACE OpenSSL::SSL OpenSSL::Crypto)
if(WIN32)
target_link_libraries(libunbound INTERFACE ws2_32 crypt32 iphlpapi)
endif()
set(boost_threadapi "pthread")
set(boost_bootstrap_cxx "--cxx=${deps_cxx}")
set(boost_toolset "")
@ -631,16 +532,12 @@ set_target_properties(libzmq PROPERTIES
set(curl_extra)
if(WIN32)
set(curl_ssl_opts --without-ssl --with-schannel)
elseif(APPLE)
set(curl_ssl_opts --without-ssl --with-secure-transport)
if(APPLE)
if(IOS)
# This CPP crap shouldn't be necessary but is because Apple's toolchain is trash
set(curl_extra "LDFLAGS=-L${DEPS_DESTDIR}/lib -isysroot ${CMAKE_OSX_SYSROOT}" CPP=cpp)
endif()
else()
set(curl_ssl_opts --with-ssl=${DEPS_DESTDIR})
set(curl_extra "LIBS=-pthread")
endif()
@ -672,7 +569,7 @@ foreach(curl_arch ${curl_arches})
build_external(curl
TARGET_SUFFIX ${curl_target_suffix}
DEPENDS openssl_external zlib_external
DEPENDS zlib_external
CONFIGURE_COMMAND ./configure ${cross_host} ${cross_extra} --prefix=${curl_prefix} --disable-shared
--enable-static --disable-ares --disable-ftp --disable-ldap --disable-laps --disable-rtsp
--disable-dict --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smb
@ -680,7 +577,8 @@ foreach(curl_arch ${curl_arches})
--enable-ipv6 --disable-threaded-resolver --disable-pthreads --disable-verbose --disable-sspi
--enable-crypto-auth --disable-ntlm-wb --disable-tls-srp --disable-unix-sockets --disable-cookies
--enable-http-auth --enable-doh --disable-mime --enable-dateparse --disable-netrc --without-libidn2
--disable-progress-meter --without-brotli --with-zlib=${DEPS_DESTDIR} ${curl_ssl_opts}
--disable-progress-meter --without-brotli --with-zlib=${DEPS_DESTDIR}
--without-ssl --without-schannel --without-secure-transport
--without-librtmp --disable-versioned-symbols --enable-hidden-symbols
--without-zsh-functions-dir --without-fish-functions-dir
"CC=${deps_cc}" "CFLAGS=${deps_noarch_CFLAGS}${cflags_extra}" ${curl_extra}
@ -710,9 +608,9 @@ endif()
add_static_target(CURL::libcurl curl_external libcurl.a)
set(libcurl_link_libs zlib)
if(CMAKE_CROSSCOMPILING AND ARCH_TRIPLET MATCHES mingw)
list(APPEND libcurl_link_libs crypt32)
list(APPEND libcurl_link_libs ws2_32)
elseif(APPLE)
list(APPEND libcurl_link_libs "-framework Security")
list(APPEND libcurl_link_libs "-framework SystemConfiguration")
endif()
set_target_properties(CURL::libcurl PROPERTIES
INTERFACE_LINK_LIBRARIES "${libcurl_link_libs}"

View File

@ -32,7 +32,6 @@ add_library(common
base58.cpp
combinator.cpp
command_line.cpp
dns_utils.cpp
error.cpp
expect.cpp
file.cpp
@ -68,6 +67,5 @@ target_link_libraries(common
filesystem
fmt::fmt
PRIVATE
libunbound
sodium
extra)

View File

@ -32,7 +32,6 @@
namespace tools
{
class DNSResolver;
struct login;
class password_container;
class t_http_connection;

View File

@ -1,670 +0,0 @@
// Copyright (c) 2014-2019, The Monero Project
// Copyright (c) 2018, The Loki 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"
// check local first (in the event of static or in-source compilation of libunbound)
#include "common/string_util.h"
#include "unbound.h"
#include <chrono>
#include <optional>
#include <stdexcept>
#include <cstdlib>
#include <cstdio>
#include "epee/misc_log_ex.h"
#include "common/threadpool.h"
#include "crypto/crypto.h"
#undef OXEN_DEFAULT_LOG_CATEGORY
#define OXEN_DEFAULT_LOG_CATEGORY "net.dns"
using namespace std::literals;
static constexpr std::array DEFAULT_DNS_PUBLIC_ADDR =
{
"194.150.168.168"sv, // CCC (Germany)
"80.67.169.40"sv, // FDN (France)
"89.233.43.71"sv, // http://censurfridns.dk (Denmark)
"109.69.8.51"sv, // punCAT (Spain)
"193.58.251.251"sv, // SkyDNS (Russia)
};
namespace
{
/*
* The following two functions were taken from unbound-anchor.c, from
* the unbound library packaged with this source. The license and source
* can be found in $PROJECT_ROOT/external/unbound
*/
/* Cert builtin commented out until it's used, as the compiler complains
// return the built in root update certificate
static const char*
get_builtin_cert(void)
{
return
// The ICANN CA fetched at 24 Sep 2010. Valid to 2028
"-----BEGIN CERTIFICATE-----\n"
"MIIDdzCCAl+gAwIBAgIBATANBgkqhkiG9w0BAQsFADBdMQ4wDAYDVQQKEwVJQ0FO\n"
"TjEmMCQGA1UECxMdSUNBTk4gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAUBgNV\n"
"BAMTDUlDQU5OIFJvb3QgQ0ExCzAJBgNVBAYTAlVTMB4XDTA5MTIyMzA0MTkxMloX\n"
"DTI5MTIxODA0MTkxMlowXTEOMAwGA1UEChMFSUNBTk4xJjAkBgNVBAsTHUlDQU5O\n"
"IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1JQ0FOTiBSb290IENB\n"
"MQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKDb\n"
"cLhPNNqc1NB+u+oVvOnJESofYS9qub0/PXagmgr37pNublVThIzyLPGCJ8gPms9S\n"
"G1TaKNIsMI7d+5IgMy3WyPEOECGIcfqEIktdR1YWfJufXcMReZwU4v/AdKzdOdfg\n"
"ONiwc6r70duEr1IiqPbVm5T05l1e6D+HkAvHGnf1LtOPGs4CHQdpIUcy2kauAEy2\n"
"paKcOcHASvbTHK7TbbvHGPB+7faAztABLoneErruEcumetcNfPMIjXKdv1V1E3C7\n"
"MSJKy+jAqqQJqjZoQGB0necZgUMiUv7JK1IPQRM2CXJllcyJrm9WFxY0c1KjBO29\n"
"iIKK69fcglKcBuFShUECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n"
"Af8EBAMCAf4wHQYDVR0OBBYEFLpS6UmDJIZSL8eZzfyNa2kITcBQMA0GCSqGSIb3\n"
"DQEBCwUAA4IBAQAP8emCogqHny2UYFqywEuhLys7R9UKmYY4suzGO4nkbgfPFMfH\n"
"6M+Zj6owwxlwueZt1j/IaCayoKU3QsrYYoDRolpILh+FPwx7wseUEV8ZKpWsoDoD\n"
"2JFbLg2cfB8u/OlE4RYmcxxFSmXBg0yQ8/IoQt/bxOcEEhhiQ168H2yE5rxJMt9h\n"
"15nu5JBSewrCkYqYYmaxyOC3WrVGfHZxVI7MpIFcGdvSb2a1uyuua8l0BKgk3ujF\n"
"0/wsHNeP22qNyVO+XVBzrM8fk8BSUFuiT/6tZTYXRtEt5aKQZgXbKU5dUF3jT9qg\n"
"j/Br5BZw3X/zd325TvnswzMC1+ljLzHnQGGk\n"
"-----END CERTIFICATE-----\n"
;
}
*/
/** return the built in root DS trust anchor */
constexpr auto get_builtin_ds()
{
return std::array{
". IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5\n",
". IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D\n",
};
}
/************************************************************
************************************************************
***********************************************************/
} // anonymous namespace
namespace tools
{
static constexpr const char *get_record_name(int record_type)
{
switch (record_type)
{
case DNS_TYPE_A: return "A";
case DNS_TYPE_TXT: return "TXT";
case DNS_TYPE_AAAA: return "AAAA";
default: return "unknown";
}
}
// fuck it, I'm tired of dealing with getnameinfo()/inet_ntop/etc
std::optional<std::string> ipv4_to_string(const char* src, size_t len)
{
if (len < 4)
{
MERROR("Invalid IPv4 address: " << std::string(src, len));
return std::nullopt;
}
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::optional<std::string> ipv6_to_string(const char* src, size_t len)
{
if (len < 8)
{
MERROR("Invalid IPv4 address: " << std::string(src, len));
return std::nullopt;
}
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();
}
std::optional<std::string> txt_to_string(const char* src, size_t len)
{
if (len == 0)
return std::nullopt;
return std::string(src+1, len-1);
}
void ub_ctx_deleter::operator()(ub_ctx* ctx) {
ub_ctx_delete(ctx);
}
namespace {
struct ub_result_deleter {
void operator()(ub_result* result) {
ub_resolve_free(result);
}
};
using ub_result_ptr = std::unique_ptr<ub_result, ub_result_deleter>;
void add_anchors(ub_ctx *ctx)
{
for (const char* ds : get_builtin_ds())
{
MINFO("adding trust anchor: " << *ds);
ub_ctx_add_ta(ctx, const_cast<char*>(ds));
}
}
} // anonymous namespace
DNSResolver::DNSResolver()
{
int use_dns_public = 0;
std::vector<std::string> dns_public_addr;
const char *DNS_PUBLIC = getenv("DNS_PUBLIC");
if (DNS_PUBLIC)
{
dns_public_addr = tools::dns_utils::parse_dns_public(DNS_PUBLIC);
if (!dns_public_addr.empty())
{
MGINFO("Using public DNS server(s): " << tools::join(", ", dns_public_addr) << " (TCP)");
use_dns_public = 1;
}
else
{
MERROR("Failed to parse DNS_PUBLIC");
}
}
// init libunbound context
m_ctx = ub_ctx_create();
if (use_dns_public)
{
for (const auto &ip: dns_public_addr)
ub_ctx_set_fwd(m_ctx, ip.c_str());
ub_ctx_set_option(m_ctx, "do-udp:", "no");
ub_ctx_set_option(m_ctx, "do-tcp:", "yes");
}
else {
// look for "/etc/resolv.conf" and "/etc/hosts" or platform equivalent
ub_ctx_resolvconf(m_ctx, NULL);
ub_ctx_hosts(m_ctx, NULL);
}
add_anchors(m_ctx);
if (!DNS_PUBLIC)
{
// TODO(oxen): Don't probe moneropulse for Loki
#if 0
// if no DNS_PUBLIC specified, we try a lookup to what we know
// should be a valid DNSSEC record, and switch to known good
// DNSSEC resolvers if verification fails
bool available, valid;
static const char *probe_hostname = "updates.moneropulse.org";
auto records = get_txt_record(probe_hostname, available, valid);
if (!valid)
{
MINFO("Failed to verify DNSSEC record from " << probe_hostname << ", falling back to TCP with well known DNSSEC resolvers");
ub_ctx_delete(m_ctx);
m_ctx = ub_ctx_create();
add_anchors(m_ctx);
for (const auto &ip: DEFAULT_DNS_PUBLIC_ADDR)
ub_ctx_set_fwd(m_ctx, string_copy(ip));
ub_ctx_set_option(m_ctx, string_copy("do-udp:"), string_copy("no"));
ub_ctx_set_option(m_ctx, string_copy("do-tcp:"), string_copy("yes"));
}
#endif
}
}
std::vector<std::string> DNSResolver::get_record(const std::string& url, int record_type, std::optional<std::string> (*reader)(const char *,size_t), bool& dnssec_available, bool& dnssec_valid)
{
std::vector<std::string> addresses;
dnssec_available = false;
dnssec_valid = false;
if (url.find('.') == std::string::npos)
{
return addresses;
}
ub_result* result_raw = nullptr;
// call DNS resolver, blocking. if return value not zero, something went wrong
if (!ub_resolve(m_ctx, url.c_str(), record_type, DNS_CLASS_IN, &result_raw))
{
// destructor takes care of cleanup
ub_result_ptr result{result_raw};
dnssec_available = (result->secure || result->bogus);
dnssec_valid = result->secure && !result->bogus;
if (result->havedata)
{
for (size_t i=0; result->data[i] != NULL; i++)
{
if (auto res = (*reader)(result->data[i], result->len[i]))
{
MINFO("Found \"" << *res << "\" in " << get_record_name(record_type) << " record for " << url);
addresses.push_back(*res);
}
}
}
}
return addresses;
}
std::vector<std::string> 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<std::string> DNSResolver::get_ipv6(const std::string& url, bool& dnssec_available, bool& dnssec_valid)
{
return get_record(url, DNS_TYPE_AAAA, ipv6_to_string, dnssec_available, dnssec_valid);
}
std::vector<std::string> DNSResolver::get_txt_record(const std::string& url, bool& dnssec_available, bool& dnssec_valid)
{
return get_record(url, DNS_TYPE_TXT, txt_to_string, dnssec_available, dnssec_valid);
}
namespace {
// Data pack that we pass into the unbound callback:
struct dns_results {
int& all_done;
const std::string& hostname;
const char* record_name;
std::vector<std::string>& results;
std::optional<std::string> (*reader)(const char*, size_t);
int async_id{0};
bool done{false};
bool dnssec;
bool dnssec_required;
dns_results(int& a, const std::string& h, const char* rn, std::vector<std::string>& r, std::optional<std::string> (*rdr)(const char*, size_t), bool dnssec, bool dnssec_req)
: all_done{a}, hostname{h}, record_name{rn}, results{r}, reader{rdr}, dnssec{dnssec}, dnssec_required{dnssec_req}
{}
};
}
extern "C" void DNSResolver_async_callback(void* data, int err, ub_result* result_raw)
{
ub_result_ptr result{result_raw};
auto &res = *static_cast<dns_results*>(data);
res.all_done++;
res.done = true;
if (err)
MWARNING("resolution of " << res.hostname << " failed: " << ub_strerror(err));
else if ((res.dnssec || res.dnssec_required) && result->bogus)
MWARNING("resolution of " << res.hostname << " failed DNSSEC validation: " << result->why_bogus);
else if (res.dnssec_required && !result->secure)
MWARNING("resolution of " << res.hostname << " failed: DNSSEC validate is required but is not available");
else if (result->havedata)
{
for (size_t i = 0; result->data[i] != NULL; i++)
{
if (auto r = (*res.reader)(result->data[i], result->len[i]))
{
MINFO("Found \"" << *r << "\" in " << res.record_name << " record for " << res.hostname);
res.results.push_back(*r);
}
}
}
}
std::vector<std::vector<std::string>> DNSResolver::get_many(int type, const std::vector<std::string>& hostnames, std::chrono::milliseconds timeout, bool dnssec, bool dnssec_required)
{
auto* reader = type == DNS_TYPE_A ? ipv4_to_string : type == DNS_TYPE_AAAA ? ipv6_to_string : type == DNS_TYPE_TXT ? txt_to_string : nullptr;
if (!reader)
throw std::invalid_argument("Invalid lookup type: " + std::to_string(type));
std::vector<std::vector<std::string>> results;
if (hostnames.empty())
return results;
int num_done = 0;
std::vector<dns_results> result_packs;
results.reserve(hostnames.size());
result_packs.reserve(hostnames.size());
ub_ctx_async(m_ctx, true); // Tells libunbound to use a thread instead of a fork
// Initiate lookups:
for (auto& host : hostnames)
{
auto& pack = result_packs.emplace_back(num_done, host, get_record_name(type), results.emplace_back(), reader, dnssec, dnssec_required);
int err = ub_resolve_async(m_ctx, host.c_str(), type, DNS_CLASS_IN, static_cast<void*>(&pack), DNSResolver_async_callback, &pack.async_id);
if (err)
{
MWARNING("unable to initiate lookup for " << host << ": " << ub_strerror(err));
num_done++;
pack.done = true;
}
}
// Wait for results
auto expiry = std::chrono::steady_clock::now() + timeout;
while (num_done < (int)results.size() && std::chrono::steady_clock::now() < expiry)
{
std::this_thread::sleep_for(5ms);
int err = ub_process(m_ctx);
if (err)
{
MWARNING("ub_process returned an error while waiting for async results: " << ub_strerror(err));
break;
}
}
// Cancel any outstanding requests
for (auto& pack : result_packs)
{
if (!pack.done)
ub_cancel(m_ctx, pack.async_id);
}
return results;
}
std::string DNSResolver::get_dns_format_from_oa_address(std::string_view addr_v)
{
std::string addr{addr_v};
auto first_at = addr.find("@");
if (first_at == std::string::npos)
return addr;
// convert name@domain.tld to name.domain.tld
addr.replace(first_at, 1, ".");
return addr;
}
DNSResolver& DNSResolver::instance()
{
static DNSResolver staticInstance;
return staticInstance;
}
DNSResolver DNSResolver::create()
{
return DNSResolver();
}
namespace dns_utils
{
//-----------------------------------------------------------------------
// TODO: parse the string in a less stupid way, probably with regex
std::string address_from_txt_record(std::string_view s)
{
// make sure the txt record has the addr_type and find it
constexpr auto addr_type = "oa1:xmr"sv;
if (auto pos = s.find(addr_type); pos != std::string_view::npos)
s.remove_prefix(pos + addr_type.size()); // remove it and everything before it
else
return {}; // not found.
constexpr auto recipient_address = "recipient_address="sv;
if (auto pos = s.find(recipient_address); pos != std::string_view::npos)
s.remove_prefix(pos + recipient_address.size()); // delete it and everything up to it
else
return {}; // not found
// find the next semicolon
if (auto pos = s.find(';'); pos != std::string::npos)
{
// length of address == 95, we can at least validate that much here
if (pos == 95)
return std::string{s.substr(0, 95)};
else if (pos == 106) // length of address == 106 --> integrated address
return std::string{s.substr(0, 106)};
}
return {};
}
/**
* @brief gets a oxen address from the TXT record of a DNS entry
*
* gets the oxen address from the TXT record of the DNS entry associated
* with <url>. If this lookup fails, or the TXT record does not contain an
* XMR address in the correct format, returns an empty string. <dnssec_valid>
* 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 oxen address (as a string) or an empty string
*/
std::vector<std::string> addresses_from_url(const std::string_view url, bool& dnssec_valid)
{
std::vector<std::string> addresses;
// get txt records
bool dnssec_available, dnssec_isvalid;
std::string oa_addr = DNSResolver::instance().get_dns_format_from_oa_address(url);
auto records = DNSResolver::instance().get_txt_record(oa_addr, dnssec_available, dnssec_isvalid);
// TODO: update this to allow for conveying that dnssec was not available
if (dnssec_available && dnssec_isvalid)
{
dnssec_valid = true;
}
else dnssec_valid = false;
// for each txt record, try to find a oxen address in it.
for (auto& rec : records)
{
std::string addr = address_from_txt_record(rec);
if (addr.size())
{
addresses.push_back(std::move(addr));
}
}
return addresses;
}
std::string get_account_address_as_str_from_url(const std::string_view url, bool& dnssec_valid,
std::function<std::string(const std::string_view, const std::vector<std::string>&, bool)> dns_confirm)
{
// attempt to get address from dns query
auto addresses = addresses_from_url(url, dnssec_valid);
if (addresses.empty())
{
LOG_ERROR("wrong address: " << url);
return {};
}
return dns_confirm(url, addresses, dnssec_valid);
}
namespace
{
bool dns_records_match(const std::vector<std::string>& a, const std::vector<std::string>& b)
{
if (a.size() != b.size()) return false;
for (const auto& record_in_a : a)
{
bool ok = false;
for (const auto& record_in_b : b)
{
if (record_in_a == record_in_b)
{
ok = true;
break;
}
}
if (!ok) return false;
}
return true;
}
}
bool load_txt_records_from_dns(std::vector<std::string> &good_records, const std::vector<std::string> &dns_urls)
{
// Prevent infinite recursion when distributing
if (dns_urls.empty()) return false;
std::vector<std::vector<std::string> > records;
records.resize(dns_urls.size());
size_t first_index = crypto::rand_idx(dns_urls.size());
// send all requests in parallel
std::deque<bool> avail(dns_urls.size(), false), valid(dns_urls.size(), false);
tools::threadpool& tpool = tools::threadpool::getInstance();
tools::threadpool::waiter waiter;
for (size_t n = 0; n < dns_urls.size(); ++n)
{
tpool.submit(&waiter,[n, dns_urls, &records, &avail, &valid](){
records[n] = tools::DNSResolver::instance().get_txt_record(dns_urls[n], avail[n], valid[n]);
});
}
waiter.wait(&tpool);
size_t cur_index = first_index;
do
{
const std::string &url = dns_urls[cur_index];
if (!avail[cur_index])
{
records[cur_index].clear();
LOG_PRINT_L2("DNSSEC not available for hostname: " << url << ", skipping.");
}
if (!valid[cur_index])
{
records[cur_index].clear();
LOG_PRINT_L2("DNSSEC validation failed for hostname: " << url << ", skipping.");
}
cur_index++;
if (cur_index == dns_urls.size())
{
cur_index = 0;
}
} while (cur_index != first_index);
size_t num_valid_records = 0;
for( const auto& record_set : records)
{
if (record_set.size() != 0)
{
num_valid_records++;
}
}
if (num_valid_records < 2)
{
LOG_PRINT_L0("WARNING: no two valid DNS TXT records were received");
return false;
}
int good_records_index = -1;
for (size_t i = 0; i < records.size() - 1; ++i)
{
if (records[i].size() == 0) continue;
for (size_t j = i + 1; j < records.size(); ++j)
{
if (dns_records_match(records[i], records[j]))
{
good_records_index = i;
break;
}
}
if (good_records_index >= 0) break;
}
if (good_records_index < 0)
{
LOG_PRINT_L0("WARNING: no two DNS TXT records matched");
return false;
}
good_records = records[good_records_index];
return true;
}
std::vector<std::string> parse_dns_public(const char *s)
{
unsigned ip0, ip1, ip2, ip3;
char c;
std::vector<std::string> dns_public_addr;
if (s == "tcp"sv)
{
for (auto& default_dns : DEFAULT_DNS_PUBLIC_ADDR)
dns_public_addr.emplace_back(default_dns);
LOG_PRINT_L0("Using default public DNS server(s): " << tools::join(", ", dns_public_addr) << " (TCP)");
}
else if (std::sscanf(s, "tcp://%u.%u.%u.%u%c", &ip0, &ip1, &ip2, &ip3, &c) == 4)
{
if (ip0 > 255 || ip1 > 255 || ip2 > 255 || ip3 > 255)
{
MERROR("Invalid IP: " << s << ", using default");
}
else
{
dns_public_addr.emplace_back(s + 6);
}
}
else
{
MERROR("Invalid DNS_PUBLIC contents, ignored");
}
return dns_public_addr;
}
} // namespace tools::dns_utils
} // namespace tools

View File

@ -1,186 +0,0 @@
// Copyright (c) 2014-2019, 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.
#pragma once
#include <vector>
#include <string>
#include <functional>
#include <optional>
#include <chrono>
#include <string_view>
struct ub_ctx;
namespace tools
{
using namespace std::literals;
// RFC defines for record types and classes for DNS, gleaned from ldns source
constexpr int DNS_CLASS_IN = 1;
constexpr int DNS_TYPE_A = 1;
constexpr int DNS_TYPE_TXT = 16;
constexpr int DNS_TYPE_AAAA = 8;
struct ub_ctx_deleter { void operator()(ub_ctx*); };
/**
* @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
{
private:
/**
* @brief Constructs an instance of DNSResolver
*
* Constructs a class instance and does setup stuff for the backend resolver.
*/
DNSResolver();
public:
/**
* @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
*
* @param dnssec_available
*
* @return vector of strings containing ipv4 addresses
*/
std::vector<std::string> get_ipv4(const std::string& url, bool& dnssec_available, bool& dnssec_valid);
/**
* @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<std::string> get_ipv6(const std::string& url, bool& dnssec_available, bool& dnssec_valid);
/**
* @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 accommodate DNSSEC
std::vector<std::string> get_txt_record(const std::string& url, bool& dnssec_available, bool& dnssec_valid);
/**
* @brief query multiple hostnames simultaneously for results, waiting up to a fixed amount of
* time for results before returning.
*
* @param type `DNS_TYPE_A` or `DNS_TYPE_AAAA` or `DNS_TYPE_TXT` indicating the lookup type.
* @param hostnames a vector of hostnames to look up
* @param timeout how long to wait for results before giving up. Any results not yet retrieved by
* the timeout are left empty.
* @param dnssec if true then validate DNSSEC if available (i.e. reject DNSSEC failures, but allow insecure results when DNSSEC not available)
* @param dnssec_required if true then require and validate DNSSEC (i.e. reject failures and reject when DNSSEC not available)
*
* Returns a vector of vector of results: the results for address [i] are in result element [i].
* If lookup failed (or DNSSEC failed with the relevant options given) for element [i] then vector
* [i] will be empty.
*/
// TODO: this could be extended to support doing multiple lookup types at once (e.g. A and AAAA).
std::vector<std::vector<std::string>> get_many(int type, const std::vector<std::string>& hostnames, std::chrono::milliseconds timeout = 10s, bool dnssec = false, bool dnssec_required = false);
/**
* @brief Gets a DNS address from OpenAlias format
*
* If the address looks good, but contains one @ symbol, replace that with a .
* e.g. donate@getmonero.org becomes donate.getmonero.org
*
* @param oa_addr OpenAlias address
*
* @return dns_addr DNS address
*/
std::string get_dns_format_from_oa_address(std::string_view oa_addr);
/**
* @brief Gets the singleton instance of DNSResolver
*
* @return returns a reference to the singleton
*/
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 accommodate DNSSEC
std::vector<std::string> get_record(const std::string& url, int record_type, std::optional<std::string> (*reader)(const char *,size_t), bool& dnssec_available, bool& dnssec_valid);
ub_ctx* m_ctx = nullptr;
}; // class DNSResolver
namespace dns_utils
{
std::string address_from_txt_record(std::string_view s);
std::vector<std::string> addresses_from_url(const std::string_view url, bool& dnssec_valid);
std::string get_account_address_as_str_from_url(const std::string_view url, bool& dnssec_valid,
std::function<std::string(const std::string_view, const std::vector<std::string>&, bool)> confirm_dns);
bool load_txt_records_from_dns(std::vector<std::string> &records, const std::vector<std::string> &dns_urls);
std::vector<std::string> parse_dns_public(const char *s);
} // namespace tools::dns_utils
} // namespace tools

View File

@ -33,8 +33,6 @@
#include <iomanip>
#include <thread>
#include "unbound.h"
#include "epee/string_tools.h"
#include "epee/wipeable_string.h"
#include "crypto/crypto.h"
@ -57,21 +55,6 @@
namespace tools
{
static bool unbound_built_with_threads()
{
ub_ctx *ctx = ub_ctx_create();
if (!ctx) return false; // cheat a bit, should not happen unless OOM
char *oxen = strdup("oxen"), *unbound = strdup("unbound");
ub_ctx_zone_add(ctx, oxen, unbound); // this calls ub_ctx_finalize first, then errors out with UB_SYNTAX
free(unbound);
free(oxen);
// if no threads, bails out early with UB_NOERROR, otherwise fails with UB_AFTERFINAL id already finalized
bool with_threads = ub_ctx_async(ctx, 1) != 0; // UB_AFTERFINAL is not defined in public headers, check any error
ub_ctx_delete(ctx);
MINFO("libunbound was built " << (with_threads ? "with" : "without") << " threads");
return with_threads;
}
bool disable_core_dumps()
{
#ifdef __GLIBC__
@ -112,9 +95,6 @@ namespace tools
MCLOG_RED(el::Level::Warning, "global", "Running with glibc " << ver << ", hangs may occur - change glibc version if possible");
#endif
if (!unbound_built_with_threads())
MCLOG_RED(el::Level::Warning, "global", "libunbound was not built with threads enabled - crashes may occur");
return true;
}
namespace

View File

@ -39,7 +39,6 @@
#include "common/base58.h"
#include "crypto/hash.h"
#include "epee/int-util.h"
#include "common/dns_utils.h"
#include "common/oxen.h"
#include <cfenv>
@ -282,21 +281,6 @@ namespace cryptonote {
return true;
}
//--------------------------------------------------------------------------------
bool get_account_address_from_str_or_url(
address_parse_info& info
, network_type nettype
, const std::string_view str_or_url
, std::function<std::string(const std::string_view, const std::vector<std::string>&, bool)> dns_confirm
)
{
if (get_account_address_from_str(info, nettype, str_or_url))
return true;
bool dnssec_valid;
std::string address_str = tools::dns_utils::get_account_address_as_str_from_url(str_or_url, dnssec_valid, dns_confirm);
return !address_str.empty() &&
get_account_address_from_str(info, nettype, address_str);
}
//--------------------------------------------------------------------------------
bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b) {
return cryptonote::get_transaction_hash(a) == cryptonote::get_transaction_hash(b);
}

View File

@ -140,13 +140,6 @@ namespace cryptonote {
, const std::string_view str
);
bool get_account_address_from_str_or_url(
address_parse_info& info
, network_type nettype
, const std::string_view str_or_url
, std::function<std::string(const std::string_view, const std::vector<std::string>&, bool)> dns_confirm = return_first_address
);
bool is_coinbase(const transaction& tx);
bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b);

View File

@ -56,7 +56,6 @@ extern "C" {
#include "common/command_line.h"
#include "common/hex.h"
#include "common/base58.h"
#include "common/dns_utils.h"
#include "epee/warnings.h"
#include "crypto/crypto.h"
#include "cryptonote_config.h"

View File

@ -29,7 +29,6 @@
#include <forward_list>
#include "common/dns_utils.h"
#include "common/command_line.h"
#include "common/hex.h"
#include "version.h"
@ -490,45 +489,17 @@ bool command_parser_executor::start_mining(const std::vector<std::string>& args)
}
cryptonote::address_parse_info info;
cryptonote::network_type nettype = cryptonote::MAINNET;
if(!cryptonote::get_account_address_from_str(info, cryptonote::MAINNET, args.front()))
cryptonote::network_type nettype;
if (cryptonote::get_account_address_from_str(info, cryptonote::MAINNET, args.front()))
nettype = cryptonote::MAINNET;
else if (cryptonote::get_account_address_from_str(info, cryptonote::TESTNET, args.front()))
nettype = cryptonote::TESTNET;
else if (cryptonote::get_account_address_from_str(info, cryptonote::DEVNET, args.front()))
nettype = cryptonote::DEVNET;
else
{
if(!cryptonote::get_account_address_from_str(info, cryptonote::TESTNET, args.front()))
{
if(!cryptonote::get_account_address_from_str(info, cryptonote::DEVNET, args.front()))
{
bool dnssec_valid;
std::string address_str = tools::dns_utils::get_account_address_as_str_from_url(args.front(), dnssec_valid,
[](const std::string_view url, const std::vector<std::string> &addresses, bool dnssec_valid){return addresses[0];});
if(!cryptonote::get_account_address_from_str(info, cryptonote::MAINNET, address_str))
{
if(!cryptonote::get_account_address_from_str(info, cryptonote::TESTNET, address_str))
{
if(!cryptonote::get_account_address_from_str(info, cryptonote::DEVNET, address_str))
{
std::cout << "target account address has wrong format" << std::endl;
return true;
}
else
{
nettype = cryptonote::DEVNET;
}
}
else
{
nettype = cryptonote::TESTNET;
}
}
}
else
{
nettype = cryptonote::DEVNET;
}
}
else
{
nettype = cryptonote::TESTNET;
}
std::cout << "target account address has wrong format" << std::endl;
return true;
}
if (info.is_subaddress)
{

View File

@ -48,17 +48,3 @@ target_link_libraries(object_sizes
cpr::cpr
extra
)
set(dns_checks_sources
dns_checks.cpp
)
oxen_add_executable(dns_checks "oxen-utils-dns-checks" dns_checks.cpp)
target_link_libraries(dns_checks
PRIVATE
common
epee
version
Boost::program_options
Boost::thread)

View File

@ -1,149 +0,0 @@
// Copyright (c) 2019, 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 <string>
#include <vector>
#include <map>
#include <algorithm>
#include <boost/program_options.hpp>
#include "epee/misc_log_ex.h"
#include "common/util.h"
#include "common/command_line.h"
#include "common/dns_utils.h"
#include "version.h"
#undef OXEN_DEFAULT_LOG_CATEGORY
#define OXEN_DEFAULT_LOG_CATEGORY "debugtools.dnschecks"
namespace po = boost::program_options;
enum lookup_t { LOOKUP_A, LOOKUP_TXT };
static std::vector<std::string> lookup(lookup_t type, const char *hostname)
{
bool dnssec_available = false, dnssec_valid = false;
std::vector<std::string> res;
switch (type)
{
case LOOKUP_A: res = tools::DNSResolver::instance().get_ipv4(hostname, dnssec_available, dnssec_valid); break;
case LOOKUP_TXT: res = tools::DNSResolver::instance().get_txt_record(hostname, dnssec_available, dnssec_valid); break;
default: MERROR("Invalid lookup type: " << (int)type); return {};
}
if (!dnssec_available)
{
MWARNING("No DNSSEC for " << hostname);
return {};
}
if (!dnssec_valid)
{
MWARNING("Invalid DNSSEC check for " << hostname);
return {};
}
MINFO(res.size() << " valid signed result(s) for " << hostname);
return res;
}
static void lookup(lookup_t type, const std::vector<std::string> hostnames)
{
std::vector<std::vector<std::string>> results;
for (const std::string &hostname: hostnames)
{
auto res = lookup(type, hostname.c_str());
if (!res.empty())
{
std::sort(res.begin(), res.end());
results.push_back(res);
}
}
std::map<std::vector<std::string>, size_t> counter;
for (const auto &e: results)
counter[e]++;
size_t count = 0;
for (const auto &e: counter)
count = std::max(count, e.second);
if (results.size() > 1)
{
if (count < results.size())
MERROR("Only " << count << "/" << results.size() << " records match");
else
MINFO(count << "/" << results.size() << " records match");
}
}
int main(int argc, char* argv[])
{
TRY_ENTRY();
tools::on_startup();
po::options_description desc_cmd_only("Command line options");
po::options_description desc_cmd_sett("Command line options and settings options");
command_line::add_arg(desc_cmd_only, command_line::arg_help);
po::options_description desc_options("Allowed options");
desc_options.add(desc_cmd_only).add(desc_cmd_sett);
po::variables_map vm;
bool r = command_line::handle_error_helper(desc_options, [&]()
{
po::store(po::parse_command_line(argc, argv, desc_options), vm);
po::notify(vm);
return true;
});
if (! r)
return 1;
if (command_line::get_arg(vm, command_line::arg_help))
{
std::cout << "Oxen '" << OXEN_RELEASE_NAME << "' (v" << OXEN_VERSION_FULL << ")\n\n";
std::cout << desc_options << std::endl;
return 1;
}
mlog_configure("", true);
mlog_set_categories("+" OXEN_DEFAULT_LOG_CATEGORY ":INFO");
lookup(LOOKUP_A, {"seeds.moneroseeds.se", "seeds.moneroseeds.ae.org", "seeds.moneroseeds.ch", "seeds.moneroseeds.li"});
lookup(LOOKUP_TXT, {"updates.moneropulse.org", "updates.moneropulse.net", "updates.moneropulse.co", "updates.moneropulse.se"});
lookup(LOOKUP_TXT, {"checkpoints.moneropulse.org", "checkpoints.moneropulse.net", "checkpoints.moneropulse.co", "checkpoints.moneropulse.se"});
// those are in the code, but don't seem to actually exist
#if 0
lookup(LOOKUP_TXT, {"testpoints.moneropulse.org", "testpoints.moneropulse.net", "testpoints.moneropulse.co", "testpoints.moneropulse.se");
lookup(LOOKUP_TXT, {"stagenetpoints.moneropulse.org", "stagenetpoints.moneropulse.net", "stagenetpoints.moneropulse.co", "stagenetpoints.moneropulse.se"});
#endif
lookup(LOOKUP_TXT, {"segheights.moneropulse.org", "segheights.moneropulse.net", "segheights.moneropulse.co", "segheights.moneropulse.se"});
return 0;
CATCH_ENTRY_L0("main", 1);
}

View File

@ -38,7 +38,6 @@ target_link_libraries(device
common
cncrypto
ringct_basic
OpenSSL::Crypto
Boost::serialization
PRIVATE
version

View File

@ -265,10 +265,6 @@ namespace nodetool
virtual void clear_used_stripe_peers();
private:
const std::vector<std::string> m_seed_nodes_list =
{
// TODO(oxen): "seeds.oxen.network"
};
bool islimitup=false;
bool islimitdown=false;

View File

@ -45,7 +45,6 @@
#include "version.h"
#include "epee/string_tools.h"
#include "common/file.h"
#include "common/dns_utils.h"
#include "common/pruning.h"
#include "net/error.h"
#include "common/periodic_task.h"
@ -599,50 +598,12 @@ namespace nodetool
std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes()
{
if (!m_exclusive_peers.empty() || m_offline)
{
return {};
}
if (m_nettype == cryptonote::TESTNET)
{
return get_seed_nodes(cryptonote::TESTNET);
}
if (m_nettype == cryptonote::DEVNET)
{
return get_seed_nodes(cryptonote::DEVNET);
}
std::set<std::string> full_addrs;
// 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.
auto dns_results = tools::DNSResolver::instance().get_many(tools::DNS_TYPE_A, m_seed_nodes_list, ::config::DNS_TIMEOUT);
for (size_t i = 0; i < dns_results.size(); i++)
{
const auto& result = dns_results[i];
MDEBUG("DNS lookup for " << m_seed_nodes_list[i] << ": " << result.size() << " results");
// if no results for seed node then lookup failed or timed out
for (const auto& addr_string : result)
full_addrs.insert(addr_string + ":" + std::to_string(cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT));
}
// append the fallback nodes if we have too few seed nodes to start with
if (full_addrs.size() < MIN_WANTED_SEED_NODES)
{
if (full_addrs.empty())
MINFO("DNS seed node lookup either timed out or failed, falling back to defaults");
else
MINFO("Not enough DNS seed nodes found, using fallback defaults too");
for (const auto &peer: get_seed_nodes(cryptonote::MAINNET))
full_addrs.insert(peer);
m_fallback_seed_nodes_added.test_and_set();
}
return full_addrs;
return get_seed_nodes(cryptonote::MAINNET);
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>

View File

@ -38,8 +38,6 @@ target_link_libraries(ringct_basic
PUBLIC
common
PRIVATE
OpenSSL::SSL
OpenSSL::Crypto
extra)
add_library(ringct
@ -51,6 +49,4 @@ target_link_libraries(ringct
cryptonote_basic
device
PRIVATE
OpenSSL::SSL
OpenSSL::Crypto
extra)

View File

@ -75,7 +75,6 @@ target_link_libraries(rpc
cryptonote_protocol
Boost::thread
Boost::program_options
OpenSSL::SSL
extra)
target_link_libraries(daemon_rpc_server

View File

@ -375,7 +375,7 @@ void simple_wallet::mms_signer(const std::vector<std::string> &args)
if (args.size() == 4)
{
cryptonote::address_parse_info info;
bool ok = cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), args[3], oa_prompter);
bool ok = cryptonote::get_account_address_from_str(info, m_wallet->nettype(), args[3]);
if (!ok)
{
fail_msg_writer() << tr("Invalid Oxen address");

View File

@ -59,7 +59,6 @@
#include "common/command_line.h"
#include "common/util.h"
#include "common/signal_handler.h"
#include "common/dns_utils.h"
#include "common/base58.h"
#include "common/scoped_message_writer.h"
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
@ -427,42 +426,6 @@ namespace
return "invalid";
}
std::string oa_prompter(const std::string_view url, const std::vector<std::string> &addresses, bool dnssec_valid)
{
if (addresses.empty())
return {};
// prompt user for confirmation.
// inform user of DNSSEC validation status as well.
std::string dnssec_str;
if (dnssec_valid)
{
dnssec_str = sw::tr("DNSSEC validation passed");
}
else
{
dnssec_str = sw::tr("WARNING: DNSSEC validation was unsuccessful, this address may not be correct!");
}
std::stringstream prompt;
prompt << sw::tr("For URL: ") << url
<< ", " << dnssec_str << std::endl
<< sw::tr(" Oxen Address = ") << addresses[0]
<< std::endl
<< sw::tr("Is this OK?")
;
// prompt the user for confirmation given the dns query and dnssec status
std::string confirm_dns_ok = input_line(prompt.str(), true);
if (std::cin.eof())
{
return {};
}
if (!command_line::is_yes(confirm_dns_ok))
{
std::cout << sw::tr("you have cancelled the transfer request") << std::endl;
return {};
}
return addresses[0];
}
std::optional<std::pair<uint32_t, uint32_t>> parse_subaddress_lookahead(const std::string& str)
{
auto r = tools::parse_subaddress_lookahead(str);
@ -1212,7 +1175,7 @@ bool simple_wallet::export_multisig_main(const std::vector<std::string> &args EN
else
#endif
{
bool r = m_wallet->save_to_file(filename, ciphertext);
bool r = tools::dump_file(filename, ciphertext);
if (!r)
{
fail_msg_writer() << tr("failed to save file ") << filename.u8string();
@ -1275,7 +1238,7 @@ bool simple_wallet::import_multisig_main(const std::vector<std::string> &args EN
{
const fs::path filename = fs::u8path(args[n]);
std::string data;
bool r = m_wallet->load_from_file(filename, data);
bool r = tools::slurp_file(filename, data);
if (!r)
{
fail_msg_writer() << tr("failed to read file ") << filename.u8string();
@ -1592,7 +1555,7 @@ bool simple_wallet::export_raw_multisig(const std::vector<std::string> &args)
if (!filenames.empty())
filenames += ", ";
filenames += fn.u8string();
if (!m_wallet->save_to_file(fn, cryptonote::tx_to_blob(ptx.tx)))
if (!tools::dump_file(fn, cryptonote::tx_to_blob(ptx.tx)))
{
fail_msg_writer() << tr("Failed to export multisig transaction to file ") << fn.u8string();
return true;
@ -2555,35 +2518,6 @@ bool simple_wallet::set_device_name(const std::vector<std::string> &args/* = std
return true;
}
bool simple_wallet::set_export_format(const std::vector<std::string> &args/* = std::vector<std::string()*/)
{
if (args.size() < 2)
{
fail_msg_writer() << tr("Export format not specified");
return true;
}
if (boost::algorithm::iequals(args[1], "ascii"))
{
m_wallet->set_export_format(tools::wallet2::ExportFormat::Ascii);
}
else if (boost::algorithm::iequals(args[1], "binary"))
{
m_wallet->set_export_format(tools::wallet2::ExportFormat::Binary);
}
else
{
fail_msg_writer() << tr("Export format not recognized.");
return true;
}
const auto pwd_container = get_and_verify_password();
if (pwd_container)
{
m_wallet->rewrite(m_wallet_file, pwd_container->password());
}
return true;
}
bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
if(args.empty())
@ -3234,7 +3168,6 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
success_msg_writer() << "ignore-outputs-below = " << cryptonote::print_money(m_wallet->ignore_outputs_below());
success_msg_writer() << "track-uses = " << m_wallet->track_uses();
success_msg_writer() << "device_name = " << m_wallet->device_name();
success_msg_writer() << "export-format = " << (m_wallet->export_format() == tools::wallet2::ExportFormat::Ascii ? "ascii" : "binary");
success_msg_writer() << "inactivity-lock-timeout = " << m_wallet->inactivity_lock_timeout().count()
#ifdef _WIN32
<< " (disabled on Windows)"
@ -3293,7 +3226,6 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
CHECK_SIMPLE_VARIABLE("track-uses", set_track_uses, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("inactivity-lock-timeout", set_inactivity_lock_timeout, tr("unsigned integer (seconds, 0 to disable)"));
CHECK_SIMPLE_VARIABLE("device-name", set_device_name, tr("<device_name[:device_spec]>"));
CHECK_SIMPLE_VARIABLE("export-format", set_export_format, tr("\"binary\" or \"ascii\""));
}
fail_msg_writer() << tr("set: unrecognized argument(s)");
return true;
@ -5940,12 +5872,12 @@ bool simple_wallet::transfer_main(Transfer transfer_type, const std::vector<std:
if (i + 1 < local_args.size())
{
r = cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), local_args[i], oa_prompter);
r = cryptonote::get_account_address_from_str(info, m_wallet->nettype(), local_args[i]);
if (!r && m_wallet->is_trusted_daemon())
{
std::optional<std::string> address = m_wallet->resolve_address(local_args[i]);
if (address)
r = cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), *address, oa_prompter);
r = cryptonote::get_account_address_from_str(info, m_wallet->nettype(), *address);
}
if(!r)
{
@ -7464,7 +7396,7 @@ bool simple_wallet::sweep_main(uint32_t account, uint64_t below, Transfer transf
else
addr = m_wallet->get_subaddress_as_str({m_current_subaddress_account, 0});
if (!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), addr, oa_prompter))
if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), addr))
{
fail_msg_writer() << tr("failed to parse address");
print_usage();
@ -7560,7 +7492,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
}
cryptonote::address_parse_info info;
if (!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), local_args[1], oa_prompter))
if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), local_args[1]))
{
fail_msg_writer() << tr("failed to parse address");
return true;
@ -8021,7 +7953,7 @@ bool simple_wallet::get_tx_proof(const std::vector<std::string> &args)
}
cryptonote::address_parse_info info;
if(!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), args[1], oa_prompter))
if(!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), args[1]))
{
fail_msg_writer() << tr("failed to parse address");
return true;
@ -8033,7 +7965,7 @@ bool simple_wallet::get_tx_proof(const std::vector<std::string> &args)
{
std::string sig_str = m_wallet->get_tx_proof(txid, info.address, info.is_subaddress, args.size() == 3 ? args[2] : "");
const fs::path filename{"oxen_tx_proof"};
if (m_wallet->save_to_file(filename, sig_str, true))
if (tools::dump_file(filename, sig_str))
success_msg_writer() << tr("signature file saved to: ") << filename.u8string();
else
fail_msg_writer() << tr("failed to save signature file");
@ -8089,7 +8021,7 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
}
cryptonote::address_parse_info info;
if(!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), local_args[2], oa_prompter))
if(!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), local_args[2]))
{
fail_msg_writer() << tr("failed to parse address");
return true;
@ -8153,7 +8085,7 @@ bool simple_wallet::check_tx_proof(const std::vector<std::string> &args)
// parse address
cryptonote::address_parse_info info;
if(!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), args[1], oa_prompter))
if(!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), args[1]))
{
fail_msg_writer() << tr("failed to parse address");
return true;
@ -8161,7 +8093,7 @@ bool simple_wallet::check_tx_proof(const std::vector<std::string> &args)
// read signature file
std::string sig_str;
if (!m_wallet->load_from_file(args[2], sig_str))
if (!tools::slurp_file(args[2], sig_str))
{
fail_msg_writer() << tr("failed to load signature file");
return true;
@ -8245,7 +8177,7 @@ bool simple_wallet::get_spend_proof(const std::vector<std::string> &args)
{
const std::string sig_str = m_wallet->get_spend_proof(txid, args.size() == 2 ? args[1] : "");
const fs::path filename{"oxen_spend_proof"};
if (m_wallet->save_to_file(filename, sig_str, true))
if (tools::dump_file(filename, sig_str))
success_msg_writer() << tr("signature file saved to: ") << filename.u8string();
else
fail_msg_writer() << tr("failed to save signature file");
@ -8275,7 +8207,7 @@ bool simple_wallet::check_spend_proof(const std::vector<std::string> &args)
return true;
std::string sig_str;
if (!m_wallet->load_from_file(args[1], sig_str))
if (!tools::slurp_file(args[1], sig_str))
{
fail_msg_writer() << tr("failed to load signature file");
return true;
@ -8334,7 +8266,7 @@ bool simple_wallet::get_reserve_proof(const std::vector<std::string> &args)
{
const std::string sig_str = m_wallet->get_reserve_proof(account_minreserve, args.size() == 2 ? args[1] : "");
const fs::path filename{"oxen_reserve_proof"};
if (m_wallet->save_to_file(filename, sig_str, true))
if (tools::dump_file(filename, sig_str))
success_msg_writer() << tr("signature file saved to: ") << filename.u8string();
else
fail_msg_writer() << tr("failed to save signature file");
@ -8357,7 +8289,7 @@ bool simple_wallet::check_reserve_proof(const std::vector<std::string> &args)
return true;
cryptonote::address_parse_info info;
if(!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), args[0], oa_prompter))
if(!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), args[0]))
{
fail_msg_writer() << tr("failed to parse address");
return true;
@ -8369,7 +8301,7 @@ bool simple_wallet::check_reserve_proof(const std::vector<std::string> &args)
}
std::string sig_str;
if (!m_wallet->load_from_file(args[1], sig_str))
if (!tools::slurp_file(args[1], sig_str))
{
fail_msg_writer() << tr("failed to load signature file");
return true;
@ -9388,7 +9320,7 @@ bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::v
else if (args[0] == "add")
{
cryptonote::address_parse_info info;
if(!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), args[1], oa_prompter))
if(!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), args[1]))
{
fail_msg_writer() << tr("failed to parse address");
return true;
@ -9621,7 +9553,7 @@ bool simple_wallet::sign(const std::vector<std::string> &args)
const fs::path filename = fs::u8path(args.back());
std::string data;
if (!m_wallet->load_from_file(filename, data))
if (!tools::slurp_file(filename, data))
{
fail_msg_writer() << tr("failed to read file ") << filename.u8string();
return true;
@ -9633,7 +9565,7 @@ bool simple_wallet::sign(const std::vector<std::string> &args)
bool simple_wallet::verify_string(std::string_view value, std::string_view address, std::string_view signature)
{
cryptonote::address_parse_info info;
if(!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), address, oa_prompter))
if(!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), address))
fail_msg_writer() << tr("failed to parse address");
else if (!m_wallet->verify(value, info.address, signature))
fail_msg_writer() << tr("Bad signature from ") << address;
@ -9653,7 +9585,7 @@ bool simple_wallet::verify(const std::vector<std::string> &args)
}
fs::path filename = fs::u8path(args[0]);
std::string data;
if (!m_wallet->load_from_file(filename, data))
if (!tools::slurp_file(filename, data))
{
fail_msg_writer() << tr("failed to read file ") << filename.u8string();
return true;
@ -9892,7 +9824,7 @@ bool simple_wallet::export_outputs(const std::vector<std::string> &args)
try
{
std::string data = m_wallet->export_outputs_to_str(all);
bool r = m_wallet->save_to_file(filename, data);
bool r = tools::dump_file(filename, data);
if (!r)
{
fail_msg_writer() << tr("failed to save file ") << filename.u8string();
@ -9925,7 +9857,7 @@ bool simple_wallet::import_outputs(const std::vector<std::string> &args)
const fs::path filename = fs::u8path(args[0]);
std::string data;
bool r = m_wallet->load_from_file(filename, data);
bool r = tools::slurp_file(filename, data);
if (!r)
{
fail_msg_writer() << tr("failed to read file ") << filename.u8string();
@ -10149,7 +10081,7 @@ void simple_wallet::commit_or_save(std::vector<tools::wallet2::pending_tx>& ptx_
const std::string blob_hex = oxenc::to_hex(blob);
fs::path filename = fs::u8path("raw_oxen_tx");
if (ptx_vector.size() > 1) filename += "_" + std::to_string(i++);
bool success = m_wallet->save_to_file(filename, blob_hex, true);
bool success = tools::dump_file(filename, blob_hex);
if (success) msg_buf += tr("Transaction successfully saved to ");
else msg_buf += tr("Failed to save transaction to ");

View File

@ -154,7 +154,6 @@ namespace cryptonote
bool set_track_uses(const std::vector<std::string> &args = std::vector<std::string>());
bool set_inactivity_lock_timeout(const std::vector<std::string> &args = std::vector<std::string>());
bool set_device_name(const std::vector<std::string> &args = std::vector<std::string>());
bool set_export_format(const std::vector<std::string> &args = std::vector<std::string>());
bool help(const std::vector<std::string> &args = std::vector<std::string>());
bool start_mining(const std::vector<std::string> &args);
bool stop_mining(const std::vector<std::string> &args);

View File

@ -62,8 +62,6 @@ target_link_libraries(wallet
filesystem
Boost::thread
PRIVATE
OpenSSL::SSL
OpenSSL::Crypto
extra)
oxen_add_executable(wallet_rpc_server "oxen-wallet-rpc"

View File

@ -125,9 +125,6 @@ if (STATIC AND BUILD_STATIC_DEPS)
# Static deps:
Boost::program_options Boost::serialization Boost::system Boost::thread
zlib
OpenSSL::SSL OpenSSL::Crypto
expat
libunbound
SQLite::SQLite3
${merged_protobuf}
sodium

View File

@ -1210,9 +1210,6 @@ struct WalletManagerBase
//! returns current block target
virtual uint64_t blockTarget() = 0;
//! resolves an OpenAlias address to a monero address
virtual std::string resolveOpenAlias(const std::string &address, bool &dnssec_valid) const = 0;
};
struct WalletManagerFactory

View File

@ -35,7 +35,6 @@
#include "rpc/core_rpc_server_commands_defs.h"
#include "wallet.h"
#include "common_defines.h"
#include "common/dns_utils.h"
#include "common/util.h"
#include "version.h"
#include "common/fs.h"
@ -271,15 +270,6 @@ uint64_t WalletManagerImpl::blockTarget()
return res ? res->target : 0;
}
EXPORT
std::string WalletManagerImpl::resolveOpenAlias(const std::string &address, bool &dnssec_valid) const
{
std::vector<std::string> addresses = tools::dns_utils::addresses_from_url(address, dnssec_valid);
if (addresses.empty())
return "";
return addresses.front();
}
///////////////////// WalletManagerFactory implementation //////////////////////
EXPORT
WalletManagerBase *WalletManagerFactory::getWalletManager()

View File

@ -76,7 +76,6 @@ public:
uint64_t blockchainHeight() override;
uint64_t blockchainTargetHeight() override;
uint64_t blockTarget() override;
std::string resolveOpenAlias(const std::string &address, bool &dnssec_valid) const override;
private:
WalletManagerImpl() {}

View File

@ -35,8 +35,6 @@
#include <optional>
#include <mutex>
#include <boost/format.hpp>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <type_traits>
#include <cpr/parameters.h>
#include <oxenc/base64.h>
@ -76,7 +74,6 @@
#include "epee/memwipe.h"
#include "common/base58.h"
#include "common/combinator.h"
#include "common/dns_utils.h"
#include "common/notify.h"
#include "common/perf_timer.h"
#include "common/hex.h"
@ -1085,8 +1082,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_devices_registered(false),
m_device_last_key_image_sync(0),
m_offline(false),
m_rpc_version(0),
m_export_format(ExportFormat::Binary)
m_rpc_version(0)
{
}
@ -3869,7 +3865,7 @@ bool wallet2::store_keys(const fs::path& keys_file_name, const epee::wipeable_st
bool r = false;
try {
buf = serialization::dump_binary(*keys_file_data);
r = save_to_file(tmp_file_name, buf);
r = tools::dump_file(tmp_file_name, buf);
} catch (...) {}
CHECK_AND_ASSERT_MES(r, false, "failed to generate wallet keys file " << tmp_file_name);
@ -4047,9 +4043,6 @@ std::optional<wallet2::keys_file_data> wallet2::get_keys_file_data(const epee::w
value2.SetInt(m_original_keys_available ? 1 : 0);
json.AddMember("original_keys_available", value2, json.GetAllocator());
value2.SetInt(m_export_format);
json.AddMember("export_format", value2, json.GetAllocator());
value2.SetUint(1);
json.AddMember("encrypted_secret_keys", value2, json.GetAllocator());
@ -4123,7 +4116,7 @@ void wallet2::change_password(const fs::path& filename, const epee::wipeable_str
bool wallet2::load_keys(const fs::path& keys_file_name, const epee::wipeable_string& password)
{
std::string keys_file_buf;
bool r = load_from_file(keys_file_name, keys_file_buf);
bool r = tools::slurp_file(keys_file_name, keys_file_buf);
THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, keys_file_name);
// Load keys from buffer
@ -4206,7 +4199,6 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st
m_subaddress_lookahead_major = SUBADDRESS_LOOKAHEAD_MAJOR;
m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR;
m_original_keys_available = false;
m_export_format = ExportFormat::Binary;
m_device_name = "";
m_device_derivation_path = "";
m_key_device_type = hw::device::type::SOFTWARE;
@ -4372,9 +4364,6 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, encrypted_secret_keys, uint32_t, Uint, false, false);
encrypted_secret_keys = field_encrypted_secret_keys;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, export_format, ExportFormat, Int, false, Binary);
m_export_format = field_export_format;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, device_name, std::string, String, false, std::string());
if (m_device_name.empty())
{
@ -4513,7 +4502,7 @@ bool wallet2::verify_password(const fs::path& keys_file_name, const epee::wipeab
wallet2::keys_file_data keys_file_data;
std::string buf;
bool encrypted_secret_keys = false;
bool r = load_from_file(keys_file_name, buf);
bool r = tools::slurp_file(keys_file_name, buf);
THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, keys_file_name);
// Decrypt the contents
@ -4610,7 +4599,7 @@ void wallet2::create_keys_file(const fs::path &wallet_, bool watch_only, const e
{
auto addrfile = m_wallet_file;
addrfile += ".address.txt";
r = save_to_file(addrfile, m_account.get_public_address_str(m_nettype), true);
r = tools::dump_file(addrfile, m_account.get_public_address_str(m_nettype));
if(!r) MERROR("String with address text not saved");
}
}
@ -4632,7 +4621,7 @@ bool wallet2::query_device(hw::device::type& device_type, const fs::path& keys_f
rapidjson::Document json;
wallet2::keys_file_data keys_file_data;
std::string buf;
bool r = load_from_file(keys_file_name, buf);
bool r = tools::slurp_file(keys_file_name, buf);
THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, keys_file_name);
// Decrypt the contents
@ -4958,7 +4947,7 @@ void wallet2::restore_from_device(const fs::path& wallet_, const epee::wipeable_
if (hwdev_label) {
fs::path hwdev_txt = m_wallet_file;
hwdev_txt += ".hwdev.txt";
if (!save_to_file(hwdev_txt, *hwdev_label, true))
if (!tools::dump_file(hwdev_txt, *hwdev_label))
MERROR("failed to write .hwdev.txt comment file");
}
if (progress_callback)
@ -5209,7 +5198,7 @@ std::string wallet2::exchange_multisig_keys(const epee::wipeable_string &passwor
addrfile += ".address.txt";
if (fs::exists(addrfile))
{
r = save_to_file(addrfile, m_account.get_public_address_str(m_nettype), true);
r = tools::dump_file(addrfile, m_account.get_public_address_str(m_nettype));
if(!r) MERROR("String with address text not saved");
}
}
@ -5685,7 +5674,7 @@ void wallet2::load(const fs::path& wallet_, const epee::wipeable_string& passwor
bool r = true;
if (use_fs)
{
load_from_file(m_wallet_file, cache_file_buf);
r = tools::slurp_file(m_wallet_file, cache_file_buf);
THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, m_wallet_file);
}
@ -5910,7 +5899,7 @@ void wallet2::store_to(const fs::path &path, const epee::wipeable_string &passwo
// save address to the new file
fs::path address_file = path;
address_file += ".address.txt";
r = save_to_file(address_file, m_account.get_public_address_str(m_nettype), true);
r = tools::dump_file(address_file, m_account.get_public_address_str(m_nettype));
THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_wallet_file);
// remove old address file
if (!fs::remove(old_address_file, ec))
@ -7044,7 +7033,7 @@ bool wallet2::save_tx(const std::vector<pending_tx>& ptx_vector, const fs::path&
std::string ciphertext = dump_tx_to_str(ptx_vector);
if (ciphertext.empty())
return false;
return save_to_file(filename, ciphertext);
return tools::dump_file(filename, ciphertext);
}
//----------------------------------------------------------------------------------------------------
std::string wallet2::dump_tx_to_str(const std::vector<pending_tx> &ptx_vector) const
@ -7085,7 +7074,7 @@ bool wallet2::load_unsigned_tx(const fs::path& unsigned_filename, unsigned_tx_se
}
std::string s;
if (!load_from_file(unsigned_filename, s))
if (!tools::slurp_file(unsigned_filename, s))
{
LOG_PRINT_L0("Failed to load from " << unsigned_filename);
return false;
@ -7309,7 +7298,7 @@ bool wallet2::sign_tx(unsigned_tx_set& exported_txs, const fs::path& signed_file
return false;
}
if (!save_to_file(signed_filename, ciphertext))
if (!tools::dump_file(signed_filename, ciphertext))
{
LOG_PRINT_L0("Failed to save file to " << signed_filename);
return false;
@ -7323,7 +7312,7 @@ bool wallet2::sign_tx(unsigned_tx_set& exported_txs, const fs::path& signed_file
fs::path raw_filename = signed_filename;
raw_filename += "_raw";
if (signed_txes.ptx.size() > 1) raw_filename += "_" + std::to_string(i);
if (!save_to_file(raw_filename, tx_as_hex))
if (!tools::dump_file(raw_filename, tx_as_hex))
{
LOG_PRINT_L0("Failed to save file to " << raw_filename);
return false;
@ -7368,7 +7357,7 @@ bool wallet2::load_tx(const fs::path& signed_filename, std::vector<tools::wallet
}
std::string s;
if (!load_from_file(signed_filename, s))
if (!tools::slurp_file(signed_filename, s))
{
LOG_PRINT_L0("Failed to load from " << signed_filename);
return false;
@ -7497,7 +7486,7 @@ bool wallet2::save_multisig_tx(const multisig_tx_set& txs, const fs::path& filen
std::string ciphertext = save_multisig_tx(txs);
if (ciphertext.empty())
return false;
return save_to_file(filename, ciphertext);
return tools::dump_file(filename, ciphertext);
}
//----------------------------------------------------------------------------------------------------
wallet2::multisig_tx_set wallet2::make_multisig_tx_set(const std::vector<pending_tx>& ptx_vector) const
@ -7525,7 +7514,7 @@ bool wallet2::save_multisig_tx(const std::vector<pending_tx>& ptx_vector, const
std::string ciphertext = save_multisig_tx(ptx_vector);
if (ciphertext.empty())
return false;
return save_to_file(filename, ciphertext);
return tools::dump_file(filename, ciphertext);
}
//----------------------------------------------------------------------------------------------------
bool wallet2::parse_multisig_tx_from_str(std::string_view multisig_tx_st, multisig_tx_set &exported_txs) const
@ -7614,7 +7603,7 @@ bool wallet2::load_multisig_tx_from_file(const fs::path& filename, multisig_tx_s
}
std::string s;
if (!load_from_file(filename, s))
if (!tools::slurp_file(filename, s))
{
LOG_PRINT_L0("Failed to load from " << filename);
return false;
@ -13334,7 +13323,7 @@ bool wallet2::export_key_images_to_file(const fs::path& filename, bool requested
PERF_TIMER(export_key_images_encrypt);
std::string ciphertext{KEY_IMAGE_EXPORT_FILE_MAGIC};
ciphertext += encrypt_with_view_secret_key(data);
return save_to_file(filename, ciphertext);
return tools::dump_file(filename, ciphertext);
}
//----------------------------------------------------------------------------------------------------
@ -13397,7 +13386,7 @@ uint64_t wallet2::import_key_images_from_file(const fs::path& filename, uint64_t
{
PERF_TIMER(__FUNCTION__);
std::string data;
bool r = load_from_file(filename, data);
bool r = tools::slurp_file(filename, data);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, std::string(tr("failed to read file ")) + filename.u8string());
@ -14748,71 +14737,6 @@ std::string wallet2::get_rpc_status(const std::string &s) const
return "<error>";
}
//----------------------------------------------------------------------------------------------------
bool wallet2::save_to_file(const fs::path& path_to_file, std::string_view binary, bool is_printable) const
{
if (is_printable || m_export_format == ExportFormat::Binary)
{
return tools::dump_file(path_to_file, binary);
}
#ifdef _WIN32
FILE *fp = _wfopen(path_to_file.c_str(), L"w+");
#else
FILE *fp = fopen(path_to_file.c_str(), "w+");
#endif
if (!fp)
{
MERROR("Failed to open wallet file for writing: " << path_to_file << ": " << strerror(errno));
return false;
}
// Save the result b/c we need to close the fp before returning success/failure.
int write_result = PEM_write(fp, ASCII_OUTPUT_MAGIC.c_str(), "", reinterpret_cast<const unsigned char *>(binary.data()), binary.length());
fclose(fp);
return write_result != 0;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::load_from_file(const fs::path& path_to_file, std::string& target_str)
{
std::string data;
if (!tools::slurp_file(path_to_file, data))
return false;
if (data.find(ASCII_OUTPUT_MAGIC) == std::string::npos)
{
// It's NOT our ascii dump.
target_str = std::move(data);
return true;
}
// Creating a BIO and calling PEM_read_bio instead of simpler PEM_read
// to avoid reading the file from disk twice.
BIO* b = BIO_new_mem_buf((const void*) data.data(), data.length());
char *name = nullptr;
char *header = nullptr;
unsigned char *openssl_data = nullptr;
long len = 0;
// Save the result b/c we need to free the data before returning success/failure.
bool success = PEM_read_bio(b, &name, &header, &openssl_data, &len);
if (success)
{
target_str.clear();
target_str.append((const char*) openssl_data, len);
}
OPENSSL_free((void *) name);
OPENSSL_free((void *) header);
OPENSSL_free((void *) openssl_data);
BIO_free(b);
return success;
}
//----------------------------------------------------------------------------------------------------
void wallet2::hash_m_transfer(const transfer_details & transfer, crypto::hash &hash) const
{
KECCAK_CTX state;

View File

@ -258,11 +258,6 @@ private:
AskPasswordToDecrypt = 2,
};
enum ExportFormat {
Binary = 0,
Ascii,
};
static const char* tr(const char* str);
static const char *ERR_MSG_NETWORK_VERSION_QUERY_FAILED;
static const char *ERR_MSG_NETWORK_HEIGHT_QUERY_FAILED;
@ -1043,8 +1038,6 @@ private:
void device_address(std::string device_address) { m_device_address = std::move(device_address); }
const std::string & device_derivation_path() const { return m_device_derivation_path; }
void device_derivation_path(const std::string &device_derivation_path) { m_device_derivation_path = device_derivation_path; }
const ExportFormat & export_format() const { return m_export_format; }
void set_export_format(const ExportFormat& export_format) { m_export_format = export_format; }
bool get_tx_key_cached(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys) const;
void set_tx_key(const crypto::hash &txid, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys);
@ -1448,9 +1441,6 @@ private:
bool frozen(const crypto::key_image &ki) const;
bool frozen(const transfer_details &td) const;
bool save_to_file(const fs::path& path_to_file, std::string_view binary, bool is_printable = false) const;
static bool load_from_file(const fs::path& path_to_file, std::string& target_str);
uint64_t get_bytes_sent() const;
uint64_t get_bytes_received() const;
@ -1738,8 +1728,6 @@ private:
std::shared_ptr<tools::Notify> m_tx_notify;
std::unique_ptr<wallet_device_callback> m_device_callback;
ExportFormat m_export_format;
inline static std::mutex default_daemon_address_mutex;
inline static std::string default_daemon_address;
};

View File

@ -870,41 +870,19 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
cryptonote::address_parse_info wallet_rpc_server::extract_account_addr(
cryptonote::network_type nettype,
std::string_view addr_or_url)
std::string_view addr)
{
cryptonote::address_parse_info info;
if (m_wallet->is_trusted_daemon())
{
std::optional<std::string> address = m_wallet->resolve_address(std::string{addr_or_url});
if (address)
{
cryptonote::address_parse_info info;
if (!get_account_address_from_str_or_url(info, nettype, *address,
[](const std::string_view url, const std::vector<std::string> &addresses, bool dnssec_valid) {
if (!dnssec_valid)
throw wallet_rpc_error{error_code::WRONG_ADDRESS, "Invalid DNSSEC for "s + std::string{url}};
if (addresses.empty())
throw wallet_rpc_error{error_code::WRONG_ADDRESS, "No Oxen address found at "s + std::string{url}};
return addresses[0];
}))
throw wallet_rpc_error{error_code::WRONG_ADDRESS, "Invalid address: "s + std::string{addr_or_url}};
std::optional<std::string> address = m_wallet->resolve_address(std::string{addr});
if (cryptonote::address_parse_info info; address && get_account_address_from_str(info, nettype, *address))
return info;
} else {
throw wallet_rpc_error{error_code::WRONG_ADDRESS, "Invalid address: "s + std::string{addr_or_url}};
}
} else {
cryptonote::address_parse_info info;
if (!get_account_address_from_str_or_url(info, nettype, addr_or_url,
[](const std::string_view url, const std::vector<std::string> &addresses, bool dnssec_valid) {
if (!dnssec_valid)
throw wallet_rpc_error{error_code::WRONG_ADDRESS, "Invalid DNSSEC for "s + std::string{url}};
if (addresses.empty())
throw wallet_rpc_error{error_code::WRONG_ADDRESS, "No Oxen address found at "s + std::string{url}};
return addresses[0];
}))
throw wallet_rpc_error{error_code::WRONG_ADDRESS, "Invalid address: "s + std::string{addr_or_url}};
return info;
}
return {};
else if (get_account_address_from_str(info, nettype, addr))
return info;
throw wallet_rpc_error{error_code::WRONG_ADDRESS, "Invalid address: "s + std::string{addr}};
}
//------------------------------------------------------------------------------------------------------------------------------
void wallet_rpc_server::validate_transfer(const std::list<wallet::transfer_destination>& destinations, const std::string& payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, bool at_least_one_destination)

View File

@ -57,7 +57,7 @@ int SignatureFuzzer::init()
wallet.generate("", "", spendkey, true, false);
cryptonote::address_parse_info info;
if (!cryptonote::get_account_address_from_str_or_url(info, cryptonote::TESTNET, "9uVsvEryzpN8WH2t1WWhFFCG5tS8cBNdmJYNRuckLENFimfauV5pZKeS1P2CbxGkSDTUPHXWwiYE5ZGSXDAGbaZgDxobqDN"))
if (!cryptonote::get_account_address_from_str(info, cryptonote::TESTNET, "9uVsvEryzpN8WH2t1WWhFFCG5tS8cBNdmJYNRuckLENFimfauV5pZKeS1P2CbxGkSDTUPHXWwiYE5ZGSXDAGbaZgDxobqDN"))
{
std::cerr << "failed to parse address" << std::endl;
return 1;

View File

@ -29,7 +29,6 @@
add_executable(unit_tests
account.cpp
apply_permutation.cpp
address_from_url.cpp
base58.cpp
blockchain_db.cpp
block_queue.cpp
@ -40,7 +39,6 @@ add_executable(unit_tests
command_line.cpp
crypto.cpp
device.cpp
dns_resolver.cpp
epee_boosted_tcp_server.cpp
epee_levin_protocol_handler_async.cpp
epee_utils.cpp

View File

@ -1,118 +0,0 @@
// Copyright (c) 2014-2018, 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 "common/dns_utils.h"
#include "simplewallet/simplewallet.h"
#include <string>
TEST(AddressFromTXT, Success)
{
std::string addr = "46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em";
std::string txtr = "oa1:xmr";
txtr += " recipient_address=";
txtr += addr;
txtr += ";";
std::string res = tools::dns_utils::address_from_txt_record(txtr);
EXPECT_STREQ(addr.c_str(), res.c_str());
std::string txtr2 = "foobar";
txtr2 += txtr;
txtr2 += "more foobar";
res = tools::dns_utils::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::dns_utils::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::dns_utils::address_from_txt_record(txtr);
ASSERT_STREQ("", res.c_str());
txtr += ";";
res = tools::dns_utils::address_from_txt_record(txtr);
ASSERT_STREQ("", res.c_str());
}
TEST(AddressFromURL, Success)
{
const std::string addr = "888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H";
bool dnssec_result = false;
std::vector<std::string> addresses = tools::dns_utils::addresses_from_url("donate.getmonero.org", dnssec_result);
EXPECT_EQ(1, addresses.size());
if (addresses.size() == 1)
{
EXPECT_STREQ(addr.c_str(), addresses[0].c_str());
}
// OpenAlias address with an @ instead of first .
addresses = tools::dns_utils::addresses_from_url("donate@getmonero.org", 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<std::string> addresses = tools::dns_utils::addresses_from_url("example.veryinvalid", dnssec_result);
// for a non-existing domain such as "example.invalid", the non-existence is proved with NSEC records
ASSERT_TRUE(dnssec_result);
ASSERT_EQ(0, addresses.size());
}

View File

@ -1,184 +0,0 @@
// Copyright (c) 2014-2018, 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 <iostream>
#include <vector>
#include "gtest/gtest.h"
#include "common/dns_utils.h"
TEST(DNSResolver, IPv4Success)
{
tools::DNSResolver resolver = tools::DNSResolver::create();
bool avail, valid;
auto ips = resolver.get_ipv4("example.com", avail, valid);
ASSERT_EQ(1, ips.size());
//ASSERT_STREQ("93.184.216.119", ips[0].c_str());
ips = tools::DNSResolver::instance().get_ipv4("example.com", avail, valid);
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 = tools::DNSResolver::create();
bool avail, valid;
auto ips = resolver.get_ipv4("example.invalid", avail, valid);
ASSERT_EQ(0, ips.size());
ips = tools::DNSResolver::instance().get_ipv4("example.invalid", avail, valid);
ASSERT_EQ(0, ips.size());
}
TEST(DNSResolver, DNSSECSuccess)
{
tools::DNSResolver resolver = tools::DNSResolver::create();
bool avail, valid;
auto ips = resolver.get_ipv4("example.com", avail, valid);
ASSERT_EQ(1, ips.size());
//ASSERT_STREQ("93.184.216.119", ips[0].c_str());
ASSERT_TRUE(avail);
ASSERT_TRUE(valid);
}
TEST(DNSResolver, DNSSECFailure)
{
tools::DNSResolver resolver = tools::DNSResolver::create();
bool avail, valid;
auto ips = resolver.get_ipv4("dnssec-failed.org", avail, valid);
ASSERT_EQ(1, ips.size());
//ASSERT_STREQ("93.184.216.119", ips[0].c_str());
ASSERT_TRUE(avail);
ASSERT_FALSE(valid);
}
// 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::create();
bool avail, valid;
auto ips = resolver.get_ipv6("example.com", avail, valid);
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", avail, valid);
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 = tools::DNSResolver::create();
bool avail, valid;
auto ips = resolver.get_ipv6("example.invalid", avail, valid);
ASSERT_EQ(0, ips.size());
ips = tools::DNSResolver::instance().get_ipv6("example.invalid", avail, valid);
ASSERT_EQ(0, ips.size());
}
TEST(DNSResolver, GetTXTRecord)
{
bool avail, valid;
std::vector<std::string> records = tools::DNSResolver::instance().get_txt_record("donate.getmonero.org", avail, valid);
EXPECT_NE(0, records.size());
for (auto& rec : records)
{
std::cout << "TXT record for donate.getmonero.org: " << rec << std::endl;
}
// replace first @ with .
std::string addr = tools::DNSResolver::instance().get_dns_format_from_oa_address("donate@getmonero.org");
EXPECT_STREQ("donate.getmonero.org", addr.c_str());
// no change
addr = tools::DNSResolver::instance().get_dns_format_from_oa_address("donate.getmonero.org");
EXPECT_STREQ("donate.getmonero.org", addr.c_str());
}
TEST(DNSResolver, GetMulti)
{
auto records = tools::DNSResolver::instance().get_many(tools::DNS_TYPE_A, {"oxen.io", "example.invalid", "lokinet.org"});
EXPECT_EQ(records.size(), 3);
EXPECT_TRUE(records[0].size() > 0);
EXPECT_EQ(records[1].size(), 0);
EXPECT_TRUE(records[2].size() > 0);
}
std::vector<std::string> testval(const char* s) { return {{s}}; }
TEST(DNS_PUBLIC, empty) { EXPECT_TRUE(tools::dns_utils::parse_dns_public("").empty()); }
TEST(DNS_PUBLIC, default) { EXPECT_TRUE(tools::dns_utils::parse_dns_public("tcp").size() > 0); }
TEST(DNS_PUBLIC, invalid_scheme) { EXPECT_TRUE(tools::dns_utils::parse_dns_public("invalid").empty()); }
TEST(DNS_PUBLIC, invalid_ip_alpha) { EXPECT_TRUE(tools::dns_utils::parse_dns_public("tcp://invalid").empty()); }
TEST(DNS_PUBLIC, invalid_ip_num1) { EXPECT_TRUE(tools::dns_utils::parse_dns_public("tcp://3").empty()); }
TEST(DNS_PUBLIC, invalid_ip_num3) { EXPECT_TRUE(tools::dns_utils::parse_dns_public("tcp://3.4.5").empty()); }
TEST(DNS_PUBLIC, invalid_ip_num4_extra) { EXPECT_TRUE(tools::dns_utils::parse_dns_public("tcp://3.4.5.6x").empty()); }
TEST(DNS_PUBLIC, invalid_ip_num4_range) { EXPECT_TRUE(tools::dns_utils::parse_dns_public("tcp://3.4.542.6").empty()); }
TEST(DNS_PUBLIC, invalid_ip_dot) { EXPECT_TRUE(tools::dns_utils::parse_dns_public("tcp://3.4.5.6.").empty()); }
TEST(DNS_PUBLIC, invalid_ip_num5) { EXPECT_TRUE(tools::dns_utils::parse_dns_public("tcp://3.4.5.6.7").empty()); }
TEST(DNS_PUBLIC, invalid_ip_4_missing) { EXPECT_TRUE(tools::dns_utils::parse_dns_public("tcp://3.4..7").empty()); }
TEST(DNS_PUBLIC, valid_ip_lo) { EXPECT_EQ(testval("127.0.0.1"), tools::dns_utils::parse_dns_public("tcp://127.0.0.1")); }
TEST(DNS_PUBLIC, valid_ip) { EXPECT_EQ(testval("3.4.5.6"), tools::dns_utils::parse_dns_public("tcp://3.4.5.6")); }