diff options
Diffstat (limited to 'contrib')
29 files changed, 1397 insertions, 558 deletions
diff --git a/contrib/depends/Makefile b/contrib/depends/Makefile index bf33d706d..afa61b93b 100644 --- a/contrib/depends/Makefile +++ b/contrib/depends/Makefile @@ -94,8 +94,8 @@ $(host_arch)_$(host_os)_id_string+=$(shell $(host_CXX) --version 2>/dev/null) $(host_arch)_$(host_os)_id_string+=$(shell $(host_RANLIB) --version 2>/dev/null) $(host_arch)_$(host_os)_id_string+=$(shell $(host_STRIP) --version 2>/dev/null) - -packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) +qt_packages_$(NO_QT) = $(qt_packages) +packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(qt_packages_) native_packages += $($(host_arch)_$(host_os)_native_packages) $($(host_os)_native_packages) all_packages = $(packages) $(native_packages) diff --git a/contrib/depends/packages/cmake/conf/mxe-conf.cmake.in b/contrib/depends/packages/cmake/conf/mxe-conf.cmake.in deleted file mode 100644 index 8bd4cf1f7..000000000 --- a/contrib/depends/packages/cmake/conf/mxe-conf.cmake.in +++ /dev/null @@ -1,67 +0,0 @@ -# This file is part of MXE. See LICENSE.md for licensing information. - -# https://cmake.org/cmake/help/latest - -# Can't set `cmake_minimum_required` or `cmake_policy` in toolchain -# since toolchain is read before CMakeLists.txt -# See `target-cmake.in` for CMAKE_POLICY_DEFAULT_CMPNNNN - -# Check if we are using mxe supplied version -# - toolchain is included multiple times so set a guard in -# environment to suppress duplicate messages -if(NOT ${CMAKE_COMMAND} STREQUAL @PREFIX@/@BUILD@/bin/cmake AND NOT DEFINED ENV{_MXE_CMAKE_TOOLCHAIN_INCLUDED}) - message(WARNING " -** Warning: direct use of toolchain file is deprecated -** Please use prefixed wrapper script instead: - @TARGET@-cmake [options] <path-to-source> - - uses mxe supplied cmake version @CMAKE_VERSION@ - - loads toolchain - - loads common run results - - sets various policy defaults - ") - set(ENV{_MXE_CMAKE_TOOLCHAIN_INCLUDED} TRUE) -endif() - -## General configuration -set(CMAKE_SYSTEM_NAME Windows) -set(MSYS 1) -set(CMAKE_EXPORT_NO_PACKAGE_REGISTRY ON) -# Workaround for https://www.cmake.org/Bug/view.php?id=14075 -set(CMAKE_CROSS_COMPILING ON) - - -## Library config -set(BUILD_SHARED_LIBS @CMAKE_SHARED_BOOL@ CACHE BOOL "BUILD_SHARED_LIBS" FORCE) -set(BUILD_STATIC_LIBS @CMAKE_STATIC_BOOL@ CACHE BOOL "BUILD_STATIC_LIBS" FORCE) -set(BUILD_SHARED @CMAKE_SHARED_BOOL@ CACHE BOOL "BUILD_SHARED" FORCE) -set(BUILD_STATIC @CMAKE_STATIC_BOOL@ CACHE BOOL "BUILD_STATIC" FORCE) -set(LIBTYPE @LIBTYPE@) - - -## Paths etc. -set(CMAKE_FIND_ROOT_PATH @PREFIX@/@TARGET@) -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_PREFIX_PATH @PREFIX@/@TARGET@) -set(CMAKE_INSTALL_PREFIX @PREFIX@/@TARGET@ CACHE PATH "Installation Prefix") -# For custom mxe FindPackage scripts -set(CMAKE_MODULE_PATH "@PREFIX@/share/cmake/modules" ${CMAKE_MODULE_PATH}) - - -## Programs -set(CMAKE_C_COMPILER @PREFIX@/bin/@TARGET@-gcc) -set(CMAKE_CXX_COMPILER @PREFIX@/bin/@TARGET@-g++) -set(CMAKE_Fortran_COMPILER @PREFIX@/bin/@TARGET@-gfortran) -set(CMAKE_RC_COMPILER @PREFIX@/bin/@TARGET@-windres) -# CMAKE_RC_COMPILE_OBJECT is defined in: -# <cmake root>/share/cmake-X.Y/Modules/Platform/Windows-windres.cmake -set(CPACK_NSIS_EXECUTABLE @TARGET@-makensis) - -## Individual package configuration -file(GLOB mxe_cmake_files - "@CMAKE_TOOLCHAIN_DIR@/*.cmake" -) -foreach(mxe_cmake_file ${mxe_cmake_files}) - include(${mxe_cmake_file}) -endforeach() diff --git a/contrib/depends/packages/cmake/conf/target-cmake.in b/contrib/depends/packages/cmake/conf/target-cmake.in deleted file mode 100644 index a78bcf58d..000000000 --- a/contrib/depends/packages/cmake/conf/target-cmake.in +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash -echo "== Using MXE wrapper: @PREFIX@/bin/@TARGET@-cmake" - -# https://cmake.org/cmake/help/latest/manual/cmake-policies.7.html -# https://cmake.org/cmake/help/latest/variable/CMAKE_POLICY_DEFAULT_CMPNNNN.html -POLICIES=(0017,0020) - -unset NO_MXE_TOOLCHAIN -if echo -- "$@" | grep -Ewq "(--build|-E|--system-information)" ; then - NO_MXE_TOOLCHAIN=1 -fi -if [[ "$NO_MXE_TOOLCHAIN" == "1" ]]; then - echo "== Skip using MXE toolchain: @CMAKE_TOOLCHAIN_FILE@" - # see https://github.com/mxe/mxe/issues/932 - exec "@PREFIX@/@BUILD@/bin/cmake" "$@" -else - echo " - cmake version @CMAKE_VERSION@" - echo " - warnings for unused CMAKE_POLICY_DEFAULT variables can be ignored" - echo "== Using MXE toolchain: @CMAKE_TOOLCHAIN_FILE@" - echo "== Using MXE runresult: @CMAKE_RUNRESULT_FILE@" - if ! ( echo "$@" | grep --silent "DCMAKE_BUILD_TYPE" ) ; then - echo '== Adding "-DCMAKE_BUILD_TYPE=Release"' - set -- "-DCMAKE_BUILD_TYPE=Release" "$@" - fi - exec "@PREFIX@/@BUILD@/bin/cmake" \ - -DCMAKE_TOOLCHAIN_FILE="@CMAKE_TOOLCHAIN_FILE@" \ - `eval echo -DCMAKE_POLICY_DEFAULT_CMP{$POLICIES}=NEW` \ - -C"@CMAKE_RUNRESULT_FILE@" "$@" -fi diff --git a/contrib/depends/packages/cmake/test/CMakeLists.txt b/contrib/depends/packages/cmake/test/CMakeLists.txt deleted file mode 100644 index 6075a8f5a..000000000 --- a/contrib/depends/packages/cmake/test/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -# This file is part of MXE. See LICENSE.md for licensing information. - -# 2.8.9 is Debian Wheezy version -cmake_minimum_required(VERSION 2.8.9) - -# use default C and CXX languages -project(mxe) - -# see cmake --help-policy <cmp> for details -cmake_policy(SET CMP0017 NEW) -if (POLICY CMP0020) - cmake_policy(SET CMP0020 NEW) -endif() - -# so we can find pkg-test.cmake files to include -set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/../.. ${CMAKE_MODULE_PATH}) - -include(${PKG}-test) diff --git a/contrib/depends/packages/icu4c.mk b/contrib/depends/packages/icu4c.mk index 370a02683..2b3845488 100644 --- a/contrib/depends/packages/icu4c.mk +++ b/contrib/depends/packages/icu4c.mk @@ -6,7 +6,7 @@ $(package)_sha256_hash=1f912c54035533fb4268809701d65c7468d00e292efbc31e644490845 $(package)_patches=icu-001-dont-build-static-dynamic-twice.patch define $(package)_set_vars - $(package)_build_opts=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -DU_USING_ICU_NAMESPACE=0 --std=gnu++0x -DU_STATIC_IMPLEMENTATION -DU_COMBINED_IMPLEMENTATION -fPIC -DENABLE_STATIC=YES -DPGKDATA_MODE=static" + $(package)_build_opts=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -DU_USING_ICU_NAMESPACE=0 -DU_STATIC_IMPLEMENTATION -DU_COMBINED_IMPLEMENTATION -fPIC -DENABLE_STATIC=YES -DPGKDATA_MODE=static" endef define $(package)_config_cmds @@ -17,7 +17,7 @@ define $(package)_config_cmds sh ../source/runConfigureICU Linux &&\ make &&\ cd ../buildb &&\ - sh ../source/$($(package)_autoconf) --enable-static=yes --disable-shared --disable-layout --disable-layoutex --disable-tests --disable-samples --prefix=$(host_prefix) --with-cross-build=`pwd`/../builda &&\ + sh ../source/runConfigureICU MinGW --enable-static=yes --disable-shared --disable-layout --disable-layoutex --disable-tests --disable-samples --prefix=$(host_prefix) --with-cross-build=`pwd`/../builda &&\ $(MAKE) $($(package)_build_opts) endef diff --git a/contrib/depends/packages/native_protobuf.mk b/contrib/depends/packages/native_protobuf.mk index 83e602341..35f648b9a 100644 --- a/contrib/depends/packages/native_protobuf.mk +++ b/contrib/depends/packages/native_protobuf.mk @@ -15,12 +15,11 @@ define $(package)_config_cmds endef define $(package)_build_cmds - $(MAKE) -C src libprotobuf.la all + $(MAKE) -C src endef define $(package)_stage_cmds - $(MAKE) DESTDIR=$($(package)_staging_dir) -C src install install-libLTLIBRARIES install-nobase_includeHEADERS &&\ - $(MAKE) DESTDIR=$($(package)_staging_dir) install-pkgconfigDATA + $(MAKE) DESTDIR=$($(package)_staging_dir) -C src install endef define $(package)_postprocess_cmds diff --git a/contrib/depends/packages/openssl.mk b/contrib/depends/packages/openssl.mk index 5ee9f17a6..e920b4409 100644 --- a/contrib/depends/packages/openssl.mk +++ b/contrib/depends/packages/openssl.mk @@ -1,35 +1,28 @@ package=openssl -$(package)_version=1.0.1k +$(package)_version=1.0.2q $(package)_download_path=https://www.openssl.org/source $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=8f9faeaebad088e772f4ef5e38252d472be4d878c6b3a2718c10a4fcebe7a41c +$(package)_sha256_hash=5744cfcbcec2b1b48629f7354203bc1e5e9b5466998bbccc5b5fcde3b18eb684 define $(package)_set_vars $(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" $(package)_config_opts=--prefix=$(host_prefix) --openssldir=$(host_prefix)/etc/openssl -$(package)_config_opts+=no-camellia $(package)_config_opts+=no-capieng -$(package)_config_opts+=no-cast -$(package)_config_opts+=no-comp $(package)_config_opts+=no-dso $(package)_config_opts+=no-dtls1 $(package)_config_opts+=no-ec_nistp_64_gcc_128 $(package)_config_opts+=no-gost $(package)_config_opts+=no-gmp $(package)_config_opts+=no-heartbeats -$(package)_config_opts+=no-idea $(package)_config_opts+=no-jpake $(package)_config_opts+=no-krb5 $(package)_config_opts+=no-libunbound $(package)_config_opts+=no-md2 -$(package)_config_opts+=no-mdc2 -$(package)_config_opts+=no-rc4 $(package)_config_opts+=no-rc5 $(package)_config_opts+=no-rdrand $(package)_config_opts+=no-rfc3779 $(package)_config_opts+=no-rsax $(package)_config_opts+=no-sctp -$(package)_config_opts+=no-seed $(package)_config_opts+=no-sha0 $(package)_config_opts+=no-shared $(package)_config_opts+=no-ssl-trace @@ -39,7 +32,6 @@ $(package)_config_opts+=no-static_engine $(package)_config_opts+=no-store $(package)_config_opts+=no-unit-test $(package)_config_opts+=no-weak-ssl-ciphers -$(package)_config_opts+=no-whirlpool $(package)_config_opts+=no-zlib $(package)_config_opts+=no-zlib-dynamic $(package)_config_opts+=$($(package)_cflags) $($(package)_cppflags) diff --git a/contrib/depends/packages/packages.mk b/contrib/depends/packages/packages.mk index 4800c9936..1db50580b 100644 --- a/contrib/depends/packages/packages.mk +++ b/contrib/depends/packages/packages.mk @@ -1,10 +1,11 @@ -packages:=boost openssl zeromq cppzmq expat ldns cppzmq readline libiconv qt hidapi protobuf libusb +packages:=boost openssl zeromq cppzmq expat ldns cppzmq readline libiconv hidapi protobuf libusb native_packages := native_ccache native_protobuf darwin_native_packages = native_biplist native_ds_store native_mac_alias darwin_packages = sodium-darwin linux_packages = eudev +qt_packages = qt ifeq ($(host_os),linux) packages += unwind diff --git a/contrib/depends/packages/readline.mk b/contrib/depends/packages/readline.mk index 826c1029e..afefc7f07 100644 --- a/contrib/depends/packages/readline.mk +++ b/contrib/depends/packages/readline.mk @@ -1,9 +1,8 @@ package=readline -$(package)_version=6.3 -$(package)_download_path=ftp://ftp.cwru.edu/pub/bash/ +$(package)_version=8.0 +$(package)_download_path=https://ftp.gnu.org/gnu/readline $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=56ba6071b9462f980c5a72ab0023893b65ba6debb4eeb475d7a563dc65cafd43 -$(package)_patches=readline-1.patch +$(package)_sha256_hash=e339f51971478d369f8a053a330a190781acb9864cf4c541060f12078948e461 define $(package)_set_vars $(package)_build_opts=CC="$($(package)_cc)" @@ -15,7 +14,6 @@ define $(package)_set_vars endef define $(package)_config_cmds - patch -p1 < $($(package)_patch_dir)/readline-1.patch &&\ export bash_cv_have_mbstate_t=yes &&\ export bash_cv_wcwidth_broken=yes &&\ ./configure $($(package)_config_opts) @@ -29,5 +27,3 @@ define $(package)_stage_cmds $(MAKE) DESTDIR=$($(package)_staging_dir) install endef -define $(package)_postprocess_cmds -endef diff --git a/contrib/depends/patches/readline/readline-1.patch b/contrib/depends/patches/readline/readline-1.patch deleted file mode 100644 index 7610a29eb..000000000 --- a/contrib/depends/patches/readline/readline-1.patch +++ /dev/null @@ -1,187 +0,0 @@ -From c0572cecbeadc8fe24c70c5c39d49210a39ac719 Mon Sep 17 00:00:00 2001 -From: Timothy Gu <timothygu99@gmail.com> -Date: Tue, 30 Sep 2014 10:32:33 -0700 -Subject: [PATCH 1/2] signals: safeguard the remaining usage of frequently - missing signals - -diff --git a/input.c b/input.c -index 117dfe8..465f0b9 100644 ---- a/input.c -+++ b/input.c -@@ -532,9 +532,17 @@ rl_getc (stream) - Otherwise (not EINTR), some error occurred, also signifying EOF. */ - if (errno != EINTR) - return (RL_ISSTATE (RL_STATE_READCMD) ? READERR : EOF); -- else if (_rl_caught_signal == SIGHUP || _rl_caught_signal == SIGTERM) -+ else if (_rl_caught_signal == SIGTERM -+#if defined(SIGHUP) -+ || _rl_caught_signal == SIGHUP -+#endif -+ ) - return (RL_ISSTATE (RL_STATE_READCMD) ? READERR : EOF); -- else if (_rl_caught_signal == SIGINT || _rl_caught_signal == SIGQUIT) -+ else if (_rl_caught_signal == SIGINT -+#if defined(SIGQUIT) -+ || _rl_caught_signal == SIGQUIT -+#endif -+ ) - RL_CHECK_SIGNALS (); - - if (rl_signal_event_hook) -diff --git a/signals.c b/signals.c -index 61f02f9..7c921d6 100644 ---- a/signals.c -+++ b/signals.c -@@ -216,7 +216,9 @@ _rl_handle_signal (sig) - /* FALLTHROUGH */ - - case SIGTERM: -+#if defined (SIGHUP) - case SIGHUP: -+#endif - #if defined (SIGTSTP) - case SIGTSTP: - case SIGTTOU: -@@ -426,7 +428,9 @@ rl_set_signals () - - rl_maybe_set_sighandler (SIGINT, rl_signal_handler, &old_int); - rl_maybe_set_sighandler (SIGTERM, rl_signal_handler, &old_term); -+#if defined (SIGHUP) - rl_maybe_set_sighandler (SIGHUP, rl_signal_handler, &old_hup); -+#endif - #if defined (SIGQUIT) - rl_maybe_set_sighandler (SIGQUIT, rl_signal_handler, &old_quit); - #endif -@@ -491,7 +495,9 @@ rl_clear_signals () - overhead */ - rl_maybe_restore_sighandler (SIGINT, &old_int); - rl_maybe_restore_sighandler (SIGTERM, &old_term); -+#if defined (SIGHUP) - rl_maybe_restore_sighandler (SIGHUP, &old_hup); -+#endif - #if defined (SIGQUIT) - rl_maybe_restore_sighandler (SIGQUIT, &old_quit); - #endif --- -1.8.3.2 - - -From 6896ffa4fc85bf0dfae58e69a860d2076c1d9fd2 Mon Sep 17 00:00:00 2001 -From: Timothy Gu <timothygu99@gmail.com> -Date: Tue, 30 Sep 2014 17:16:32 -0700 -Subject: [PATCH 2/2] Handle missing S_IS* macros more gracefully - -diff --git a/colors.c b/colors.c -index 89d9035..ec19844 100644 ---- a/colors.c -+++ b/colors.c -@@ -152,14 +152,22 @@ _rl_print_color_indicator (char *f) - { - colored_filetype = C_FILE; - -+#if defined (S_ISUID) - if ((mode & S_ISUID) != 0 && is_colored (C_SETUID)) - colored_filetype = C_SETUID; -- else if ((mode & S_ISGID) != 0 && is_colored (C_SETGID)) -+ else -+#endif -+#if defined (S_ISGID) -+ if ((mode & S_ISGID) != 0 && is_colored (C_SETGID)) - colored_filetype = C_SETGID; -- else if (is_colored (C_CAP) && 0) //f->has_capability) -+ else -+#endif -+ if (is_colored (C_CAP) && 0) //f->has_capability) - colored_filetype = C_CAP; -+#if defined(S_IXUGO) - else if ((mode & S_IXUGO) != 0 && is_colored (C_EXEC)) - colored_filetype = C_EXEC; -+#endif - else if ((1 < astat.st_nlink) && is_colored (C_MULTIHARDLINK)) - colored_filetype = C_MULTIHARDLINK; - } -@@ -173,8 +181,10 @@ _rl_print_color_indicator (char *f) - colored_filetype = C_STICKY_OTHER_WRITABLE; - else - #endif -+#if defined (S_IWOTH) - if ((mode & S_IWOTH) != 0 && is_colored (C_OTHER_WRITABLE)) - colored_filetype = C_OTHER_WRITABLE; -+#endif - #if defined (S_ISVTX) - else if ((mode & S_ISVTX) != 0 && is_colored (C_STICKY)) - colored_filetype = C_STICKY; -diff --git a/colors.h b/colors.h -index fc926e5..e62edd0 100644 ---- a/colors.h -+++ b/colors.h -@@ -96,7 +96,7 @@ enum indicator_no - }; - - --#if !S_IXUGO -+#if !S_IXUGO && defined(S_IXUSR) && defined(S_IXGRP) && defined(S_IXOTH) - # define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) - #endif - -diff --git a/posixstat.h b/posixstat.h -index 3eb7f29..854a2c9 100644 ---- a/posixstat.h -+++ b/posixstat.h -@@ -78,30 +78,44 @@ - - #if defined (S_IFBLK) && !defined (S_ISBLK) - #define S_ISBLK(m) (((m)&S_IFMT) == S_IFBLK) /* block device */ -+#elif !defined (S_IFBLK) -+#define S_ISBLK(m) 0 - #endif - - #if defined (S_IFCHR) && !defined (S_ISCHR) - #define S_ISCHR(m) (((m)&S_IFMT) == S_IFCHR) /* character device */ -+#elif !defined (S_IFCHR) -+#define S_ISCHR(m) 0 - #endif - - #if defined (S_IFDIR) && !defined (S_ISDIR) - #define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) /* directory */ -+#elif !defined (S_IFDIR) -+#define S_ISDIR(m) 0 - #endif - - #if defined (S_IFREG) && !defined (S_ISREG) - #define S_ISREG(m) (((m)&S_IFMT) == S_IFREG) /* file */ -+#elif !defined (S_IFREG) -+#define S_ISREG(m) 0 - #endif - - #if defined (S_IFIFO) && !defined (S_ISFIFO) - #define S_ISFIFO(m) (((m)&S_IFMT) == S_IFIFO) /* fifo - named pipe */ -+#elif !defined (S_IFIFO) -+#define S_ISFIFO(m) 0 - #endif - - #if defined (S_IFLNK) && !defined (S_ISLNK) - #define S_ISLNK(m) (((m)&S_IFMT) == S_IFLNK) /* symbolic link */ -+#elif !defined (S_IFLNK) -+#define S_ISLNK(m) 0 - #endif - - #if defined (S_IFSOCK) && !defined (S_ISSOCK) - #define S_ISSOCK(m) (((m)&S_IFMT) == S_IFSOCK) /* socket */ -+#elif !defined (S_IFSOCK) -+#define S_ISSOCK(m) 0 - #endif - - /* -@@ -137,6 +151,8 @@ - /* These are non-standard, but are used in builtins.c$symbolic_umask() */ - #define S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH) - #define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH) -+#if defined(S_IXUSR) && defined(S_IXGRP) && defined(S_IXOTH) - #define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) -+#endif - - #endif /* _POSIXSTAT_H_ */ --- -1.8.3.2 - diff --git a/contrib/epee/include/math_helper.h b/contrib/epee/include/math_helper.h index e22e8ee6e..35b649972 100644 --- a/contrib/epee/include/math_helper.h +++ b/contrib/epee/include/math_helper.h @@ -243,6 +243,7 @@ namespace math_helper present = present << 32; present |= fileTime.dwLowDateTime; present /= 10; // mic-sec + return present; #else struct timeval tv; gettimeofday(&tv, NULL); diff --git a/contrib/epee/include/net/abstract_tcp_server2.h b/contrib/epee/include/net/abstract_tcp_server2.h index 37f4c782d..643b93b87 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.h +++ b/contrib/epee/include/net/abstract_tcp_server2.h @@ -46,6 +46,7 @@ #include <memory> #include <boost/asio.hpp> +#include <boost/asio/ssl.hpp> #include <boost/array.hpp> #include <boost/noncopyable.hpp> #include <boost/shared_ptr.hpp> @@ -102,15 +103,19 @@ namespace net_utils /// Construct a connection with the given io_service. explicit connection( boost::asio::io_service& io_service, boost::shared_ptr<shared_state> state, - t_connection_type connection_type); + t_connection_type connection_type, + epee::net_utils::ssl_support_t ssl_support, + ssl_context_t &ssl_context); explicit connection( boost::asio::ip::tcp::socket&& sock, - boost::shared_ptr<shared_state> state, - t_connection_type connection_type); + boost::shared_ptr<shared_state> state, + t_connection_type connection_type, + epee::net_utils::ssl_support_t ssl_support, + ssl_context_t &ssl_context); + + virtual ~connection() noexcept(false); - /// Get the socket associated with the connection. - boost::asio::ip::tcp::socket& socket(); /// Start the first asynchronous operation for the connection. bool start(bool is_income, bool is_multithreaded); @@ -143,6 +148,10 @@ namespace net_utils //------------------------------------------------------ boost::shared_ptr<connection<t_protocol_handler> > safe_shared_from_this(); bool shutdown(); + /// Handle completion of a receive operation. + void handle_receive(const boost::system::error_code& e, + std::size_t bytes_transferred); + /// Handle completion of a read operation. void handle_read(const boost::system::error_code& e, std::size_t bytes_transferred); @@ -160,7 +169,7 @@ namespace net_utils /// Buffer for incoming data. boost::array<char, 8192> buffer_; - //boost::array<char, 1024> buffer_; + size_t buffer_ssl_init_fill; t_connection_context context; @@ -199,6 +208,13 @@ namespace net_utils class boosted_tcp_server : private boost::noncopyable { + enum try_connect_result_t + { + CONNECT_SUCCESS, + CONNECT_FAILURE, + CONNECT_NO_SSL, + }; + public: typedef boost::shared_ptr<connection<t_protocol_handler> > connection_ptr; typedef typename t_protocol_handler::connection_context t_connection_context; @@ -212,8 +228,8 @@ namespace net_utils std::map<std::string, t_connection_type> server_type_map; void create_server_type_map(); - bool init_server(uint32_t port, const std::string address = "0.0.0.0"); - bool init_server(const std::string port, const std::string& address = "0.0.0.0"); + bool init_server(uint32_t port, const std::string address = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = std::make_pair(std::string(), std::string()), const std::list<std::string> &allowed_certificates = {}, bool allow_any_cert = false); + bool init_server(const std::string port, const std::string& address = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = std::make_pair(std::string(), std::string()), const std::list<std::string> &allowed_certificates = {}, bool allow_any_cert = false); /// Run the server's io_service loop. bool run_server(size_t threads_count, bool wait = true, const boost::thread::attributes& attrs = boost::thread::attributes()); @@ -241,10 +257,11 @@ namespace net_utils default_remote = std::move(remote); } - bool add_connection(t_connection_context& out, boost::asio::ip::tcp::socket&& sock, network_address real_remote); - bool connect(const std::string& adr, const std::string& port, uint32_t conn_timeot, t_connection_context& cn, const std::string& bind_ip = "0.0.0.0"); + bool add_connection(t_connection_context& out, boost::asio::ip::tcp::socket&& sock, network_address real_remote, epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect); + try_connect_result_t try_connect(connection_ptr new_connection_l, const std::string& adr, const std::string& port, boost::asio::ip::tcp::socket &sock_, const boost::asio::ip::tcp::endpoint &remote_endpoint, const std::string &bind_ip, uint32_t conn_timeout, epee::net_utils::ssl_support_t ssl_support); + bool connect(const std::string& adr, const std::string& port, uint32_t conn_timeot, t_connection_context& cn, const std::string& bind_ip = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect); template<class t_callback> - bool connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeot, const t_callback &cb, const std::string& bind_ip = "0.0.0.0"); + bool connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeot, const t_callback &cb, const std::string& bind_ip = "0.0.0.0", epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect); typename t_protocol_handler::config_type& get_config_object() { @@ -355,6 +372,9 @@ namespace net_utils boost::mutex connections_mutex; std::set<connection_ptr> connections_; + ssl_context_t m_ssl_context; + std::list<std::string> m_allowed_certificates; + }; // class <>boosted_tcp_server diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index 9c89a18cf..7a3abe9e9 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -78,19 +78,23 @@ PRAGMA_WARNING_DISABLE_VS(4355) template<class t_protocol_handler> connection<t_protocol_handler>::connection( boost::asio::io_service& io_service, boost::shared_ptr<shared_state> state, - t_connection_type connection_type + t_connection_type connection_type, + epee::net_utils::ssl_support_t ssl_support, + ssl_context_t &ssl_context ) - : connection(boost::asio::ip::tcp::socket{io_service}, std::move(state), connection_type) + : connection(boost::asio::ip::tcp::socket{io_service}, std::move(state), connection_type, ssl_support, ssl_context) { } template<class t_protocol_handler> connection<t_protocol_handler>::connection( boost::asio::ip::tcp::socket&& sock, boost::shared_ptr<shared_state> state, - t_connection_type connection_type + t_connection_type connection_type, + epee::net_utils::ssl_support_t ssl_support, + ssl_context_t &ssl_context ) : - connection_basic(std::move(sock), state), + connection_basic(std::move(sock), state, ssl_support, ssl_context), m_protocol_handler(this, check_and_get(state).config, context), m_connection_type( connection_type ), m_throttle_speed_in("speed_in", "throttle_speed_in"), @@ -109,17 +113,11 @@ PRAGMA_WARNING_DISABLE_VS(4355) { if(!m_was_shutdown) { - _dbg3("[sock " << socket_.native_handle() << "] Socket destroyed without shutdown."); + _dbg3("[sock " << socket().native_handle() << "] Socket destroyed without shutdown."); shutdown(); } - _dbg3("[sock " << socket_.native_handle() << "] Socket destroyed"); - } - //--------------------------------------------------------------------------------- - template<class t_protocol_handler> - boost::asio::ip::tcp::socket& connection<t_protocol_handler>::socket() - { - return socket_; + _dbg3("[sock " << socket().native_handle() << "] Socket destroyed"); } //--------------------------------------------------------------------------------- template<class t_protocol_handler> @@ -142,7 +140,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) TRY_ENTRY(); boost::system::error_code ec; - auto remote_ep = socket_.remote_endpoint(ec); + auto remote_ep = socket().remote_endpoint(ec); CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get remote endpoint: " << ec.message() << ':' << ec.value()); CHECK_AND_NO_ASSERT_MES(remote_ep.address().is_v4(), false, "IPv6 not supported here"); @@ -168,10 +166,11 @@ PRAGMA_WARNING_DISABLE_VS(4355) const boost::uuids::uuid random_uuid = boost::uuids::random_generator()(); context = t_connection_context{}; - context.set_details(random_uuid, std::move(real_remote), is_income); + bool ssl = m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled; + context.set_details(random_uuid, std::move(real_remote), is_income, ssl); boost::system::error_code ec; - auto local_ep = socket_.local_endpoint(ec); + auto local_ep = socket().local_endpoint(ec); CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get local endpoint: " << ec.message() << ':' << ec.value()); _dbg3("[sock " << socket_.native_handle() << "] new connection from " << print_connection_context_short(context) << @@ -180,7 +179,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) if(static_cast<shared_state&>(get_stats()).pfilter && !static_cast<shared_state&>(get_stats()).pfilter->is_remote_host_allowed(context.m_remote_address)) { - _dbg2("[sock " << socket_.native_handle() << "] host denied " << context.m_remote_address.host_str() << ", shutdowning connection"); + _dbg2("[sock " << socket().native_handle() << "] host denied " << context.m_remote_address.host_str() << ", shutdowning connection"); close(); return false; } @@ -192,11 +191,21 @@ PRAGMA_WARNING_DISABLE_VS(4355) reset_timer(get_default_timeout(), false); - socket_.async_read_some(boost::asio::buffer(buffer_), - strand_.wrap( - boost::bind(&connection<t_protocol_handler>::handle_read, self, - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred))); + // first read on the raw socket to detect SSL for the server + buffer_ssl_init_fill = 0; + if (is_income && m_ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_disabled) + socket().async_receive(boost::asio::buffer(buffer_), + boost::asio::socket_base::message_peek, + strand_.wrap( + boost::bind(&connection<t_protocol_handler>::handle_receive, self, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred))); + else + async_read_some(boost::asio::buffer(buffer_), + strand_.wrap( + boost::bind(&connection<t_protocol_handler>::handle_read, self, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred))); #if !defined(_WIN32) || !defined(__i686) // not supported before Windows7, too lazy for runtime check // Just exclude for 32bit windows builds @@ -204,12 +213,12 @@ PRAGMA_WARNING_DISABLE_VS(4355) int tos = get_tos_flag(); boost::asio::detail::socket_option::integer< IPPROTO_IP, IP_TOS > optionTos( tos ); - socket_.set_option( optionTos ); + socket().set_option( optionTos ); //_dbg1("Set ToS flag to " << tos); #endif boost::asio::ip::tcp::no_delay noDelayOption(false); - socket_.set_option(noDelayOption); + socket().set_option(noDelayOption); return true; @@ -234,7 +243,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) template<class t_protocol_handler> boost::asio::io_service& connection<t_protocol_handler>::get_io_service() { - return socket_.get_io_service(); + return socket().get_io_service(); } //--------------------------------------------------------------------------------- template<class t_protocol_handler> @@ -246,9 +255,9 @@ PRAGMA_WARNING_DISABLE_VS(4355) auto self = safe_shared_from_this(); if(!self) return false; - //_dbg3("[sock " << socket_.native_handle() << "] add_ref, m_peer_number=" << mI->m_peer_number); + //_dbg3("[sock " << socket().native_handle() << "] add_ref, m_peer_number=" << mI->m_peer_number); CRITICAL_REGION_LOCAL(self->m_self_refs_lock); - //_dbg3("[sock " << socket_.native_handle() << "] add_ref 2, m_peer_number=" << mI->m_peer_number); + //_dbg3("[sock " << socket().native_handle() << "] add_ref 2, m_peer_number=" << mI->m_peer_number); if(m_was_shutdown) return false; ++m_reference_count; @@ -262,9 +271,9 @@ PRAGMA_WARNING_DISABLE_VS(4355) { TRY_ENTRY(); boost::shared_ptr<connection<t_protocol_handler> > back_connection_copy; - LOG_TRACE_CC(context, "[sock " << socket_.native_handle() << "] release"); + LOG_TRACE_CC(context, "[sock " << socket().native_handle() << "] release"); CRITICAL_REGION_BEGIN(m_self_refs_lock); - CHECK_AND_ASSERT_MES(m_reference_count, false, "[sock " << socket_.native_handle() << "] m_reference_count already at 0 at connection<t_protocol_handler>::release() call"); + CHECK_AND_ASSERT_MES(m_reference_count, false, "[sock " << socket().native_handle() << "] m_reference_count already at 0 at connection<t_protocol_handler>::release() call"); // is this the last reference? if (--m_reference_count == 0) { // move the held reference to a local variable, keeping the object alive until the function terminates @@ -290,7 +299,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) std::string address, port; boost::system::error_code e; - boost::asio::ip::tcp::endpoint endpoint = socket_.remote_endpoint(e); + boost::asio::ip::tcp::endpoint endpoint = socket().remote_endpoint(e); if (e) { address = "<not connected>"; @@ -302,7 +311,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) port = boost::lexical_cast<std::string>(endpoint.port()); } MDEBUG(" connection type " << to_string( m_connection_type ) << " " - << socket_.local_endpoint().address().to_string() << ":" << socket_.local_endpoint().port() + << socket().local_endpoint().address().to_string() << ":" << socket().local_endpoint().port() << " <--> " << context.m_remote_address.str() << " (via " << address << ":" << port << ")"); } //--------------------------------------------------------------------------------- @@ -311,7 +320,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) std::size_t bytes_transferred) { TRY_ENTRY(); - //_info("[sock " << socket_.native_handle() << "] Async read calledback."); + //_info("[sock " << socket().native_handle() << "] Async read calledback."); if (!e) { @@ -347,7 +356,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) } while(delay > 0); } // any form of sleeping - //_info("[sock " << socket_.native_handle() << "] RECV " << bytes_transferred); + //_info("[sock " << socket().native_handle() << "] RECV " << bytes_transferred); logger_handle_net_read(bytes_transferred); context.m_last_recv = time(NULL); context.m_recv_cnt += bytes_transferred; @@ -355,7 +364,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) bool recv_res = m_protocol_handler.handle_recv(buffer_.data(), bytes_transferred); if(!recv_res) { - //_info("[sock " << socket_.native_handle() << "] protocol_want_close"); + //_info("[sock " << socket().native_handle() << "] protocol_want_close"); //some error in protocol, protocol handler ask to close connection boost::interprocess::ipcdetail::atomic_write32(&m_want_close_connection, 1); @@ -369,24 +378,24 @@ PRAGMA_WARNING_DISABLE_VS(4355) }else { reset_timer(get_timeout_from_bytes_read(bytes_transferred), false); - socket_.async_read_some(boost::asio::buffer(buffer_), + async_read_some(boost::asio::buffer(buffer_), strand_.wrap( boost::bind(&connection<t_protocol_handler>::handle_read, connection<t_protocol_handler>::shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred))); - //_info("[sock " << socket_.native_handle() << "]Async read requested."); + //_info("[sock " << socket().native_handle() << "]Async read requested."); } }else { - _dbg3("[sock " << socket_.native_handle() << "] Some not success at read: " << e.message() << ':' << e.value()); + _dbg3("[sock " << socket().native_handle() << "] Some not success at read: " << e.message() << ':' << e.value()); if(e.value() != 2) { - _dbg3("[sock " << socket_.native_handle() << "] Some problems at read: " << e.message() << ':' << e.value()); + _dbg3("[sock " << socket().native_handle() << "] Some problems at read: " << e.message() << ':' << e.value()); shutdown(); } else { - _dbg3("[sock " << socket_.native_handle() << "] peer closed connection"); + _dbg3("[sock " << socket().native_handle() << "] peer closed connection"); if (m_ready_to_close) shutdown(); } @@ -400,13 +409,85 @@ PRAGMA_WARNING_DISABLE_VS(4355) } //--------------------------------------------------------------------------------- template<class t_protocol_handler> + void connection<t_protocol_handler>::handle_receive(const boost::system::error_code& e, + std::size_t bytes_transferred) + { + TRY_ENTRY(); + if (e) + { + // offload the error case + handle_read(e, bytes_transferred); + return; + } + + reset_timer(get_timeout_from_bytes_read(bytes_transferred), false); + + buffer_ssl_init_fill += bytes_transferred; + if (buffer_ssl_init_fill <= get_ssl_magic_size()) + { + socket().async_receive(boost::asio::buffer(buffer_.data() + buffer_ssl_init_fill, buffer_.size() - buffer_ssl_init_fill), + boost::asio::socket_base::message_peek, + strand_.wrap( + boost::bind(&connection<t_protocol_handler>::handle_receive, connection<t_protocol_handler>::shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred))); + return; + } + + // detect SSL + if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect) + { + if (is_ssl((const unsigned char*)buffer_.data(), buffer_ssl_init_fill)) + { + MDEBUG("That looks like SSL"); + m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_enabled; // read/write to the SSL socket + } + else + { + MDEBUG("That does not look like SSL"); + m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_disabled; // read/write to the raw socket + } + } + + if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled) + { + // Handshake + if (!handshake(boost::asio::ssl::stream_base::server)) + { + MERROR("SSL handshake failed"); + boost::interprocess::ipcdetail::atomic_write32(&m_want_close_connection, 1); + bool do_shutdown = false; + CRITICAL_REGION_BEGIN(m_send_que_lock); + if(!m_send_que.size()) + do_shutdown = true; + CRITICAL_REGION_END(); + if(do_shutdown) + shutdown(); + return; + } + } + + async_read_some(boost::asio::buffer(buffer_), + strand_.wrap( + boost::bind(&connection<t_protocol_handler>::handle_read, connection<t_protocol_handler>::shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred))); + + // If an error occurs then no new asynchronous operations are started. This + // means that all shared_ptr references to the connection object will + // disappear and the object will be destroyed automatically after this + // handler returns. The connection class's destructor closes the socket. + CATCH_ENTRY_L0("connection<t_protocol_handler>::handle_receive", void()); + } + //--------------------------------------------------------------------------------- + template<class t_protocol_handler> bool connection<t_protocol_handler>::call_run_once_service_io() { TRY_ENTRY(); if(!m_is_multithreaded) { //single thread model, we can wait in blocked call - size_t cnt = socket_.get_io_service().run_one(); + size_t cnt = socket().get_io_service().run_one(); if(!cnt)//service is going to quit return false; }else @@ -416,7 +497,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) //if no handlers were called //TODO: Maybe we need to have have critical section + event + callback to upper protocol to //ask it inside(!) critical region if we still able to go in event wait... - size_t cnt = socket_.get_io_service().poll_one(); + size_t cnt = socket().get_io_service().poll_one(); if(!cnt) misc_utils::sleep_no_w(1); } @@ -525,7 +606,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) context.m_max_speed_up = std::max(context.m_max_speed_up, context.m_current_speed_up); } - //_info("[sock " << socket_.native_handle() << "] SEND " << cb); + //_info("[sock " << socket().native_handle() << "] SEND " << cb); context.m_last_send = time(NULL); context.m_send_cnt += cb; //some data should be wrote to stream @@ -570,7 +651,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) MDEBUG("do_send_chunk() NOW just queues: packet="<<size_now<<" B, is added to queue-size="<<m_send_que.size()); //do_send_handler_delayed( ptr , size_now ); // (((H))) // empty function - LOG_TRACE_CC(context, "[sock " << socket_.native_handle() << "] Async send requested " << m_send_que.front().size()); + LOG_TRACE_CC(context, "[sock " << socket().native_handle() << "] Async send requested " << m_send_que.front().size()); } else { // no active operation @@ -588,14 +669,14 @@ PRAGMA_WARNING_DISABLE_VS(4355) CHECK_AND_ASSERT_MES( size_now == m_send_que.front().size(), false, "Unexpected queue size"); reset_timer(get_default_timeout(), false); - boost::asio::async_write(socket_, boost::asio::buffer(m_send_que.front().data(), size_now ) , + async_write(boost::asio::buffer(m_send_que.front().data(), size_now ) , //strand_.wrap( boost::bind(&connection<t_protocol_handler>::handle_write, self, _1, _2) //) ); //_dbg3("(chunk): " << size_now); //logger_handle_net_write(size_now); - //_info("[sock " << socket_.native_handle() << "] Async send requested " << m_send_que.front().size()); + //_info("[sock " << socket().native_handle() << "] Async send requested " << m_send_que.front().size()); } //do_send_handler_stop( ptr , cb ); // empty function @@ -680,7 +761,8 @@ PRAGMA_WARNING_DISABLE_VS(4355) // Initiate graceful connection closure. m_timer.cancel(); boost::system::error_code ignored_ec; - socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); + socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); + socket().close(); if (!m_host.empty()) { try { host_count(m_host, -1); } catch (...) { /* ignore */ } @@ -698,7 +780,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) auto self = safe_shared_from_this(); if(!self) return false; - //_info("[sock " << socket_.native_handle() << "] Que Shutdown called."); + //_info("[sock " << socket().native_handle() << "] Que Shutdown called."); m_timer.cancel(); size_t send_que_size = 0; CRITICAL_REGION_BEGIN(m_send_que_lock); @@ -733,11 +815,11 @@ PRAGMA_WARNING_DISABLE_VS(4355) void connection<t_protocol_handler>::handle_write(const boost::system::error_code& e, size_t cb) { TRY_ENTRY(); - LOG_TRACE_CC(context, "[sock " << socket_.native_handle() << "] Async send calledback " << cb); + LOG_TRACE_CC(context, "[sock " << socket().native_handle() << "] Async send calledback " << cb); if (e) { - _dbg1("[sock " << socket_.native_handle() << "] Some problems at write: " << e.message() << ':' << e.value()); + _dbg1("[sock " << socket().native_handle() << "] Some problems at write: " << e.message() << ':' << e.value()); shutdown(); return; } @@ -752,7 +834,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) CRITICAL_REGION_BEGIN(m_send_que_lock); if(m_send_que.empty()) { - _erro("[sock " << socket_.native_handle() << "] m_send_que.size() == 0 at handle_write!"); + _erro("[sock " << socket().native_handle() << "] m_send_que.size() == 0 at handle_write!"); return; } @@ -772,11 +854,11 @@ PRAGMA_WARNING_DISABLE_VS(4355) if (speed_limit_is_enabled()) do_send_handler_write_from_queue(e, m_send_que.front().size() , m_send_que.size()); // (((H))) CHECK_AND_ASSERT_MES( size_now == m_send_que.front().size(), void(), "Unexpected queue size"); - boost::asio::async_write(socket_, boost::asio::buffer(m_send_que.front().data(), size_now) , - // strand_.wrap( - boost::bind(&connection<t_protocol_handler>::handle_write, connection<t_protocol_handler>::shared_from_this(), _1, _2) - // ) - ); + async_write(boost::asio::buffer(m_send_que.front().data(), size_now) , + // strand_.wrap( + boost::bind(&connection<t_protocol_handler>::handle_write, connection<t_protocol_handler>::shared_from_this(), _1, _2) + // ) + ); //_dbg3("(normal)" << size_now); } CRITICAL_REGION_END(); @@ -817,7 +899,8 @@ PRAGMA_WARNING_DISABLE_VS(4355) m_threads_count(0), m_thread_index(0), m_connection_type( connection_type ), - new_connection_() + new_connection_(), + m_ssl_context({boost::asio::ssl::context(boost::asio::ssl::context::sslv23), {}}) { create_server_type_map(); m_thread_name_prefix = "NET"; @@ -833,7 +916,8 @@ PRAGMA_WARNING_DISABLE_VS(4355) m_threads_count(0), m_thread_index(0), m_connection_type(connection_type), - new_connection_() + new_connection_(), + m_ssl_context({boost::asio::ssl::context(boost::asio::ssl::context::sslv23), {}}) { create_server_type_map(); m_thread_name_prefix = "NET"; @@ -855,12 +939,14 @@ PRAGMA_WARNING_DISABLE_VS(4355) } //--------------------------------------------------------------------------------- template<class t_protocol_handler> - bool boosted_tcp_server<t_protocol_handler>::init_server(uint32_t port, const std::string address) + bool boosted_tcp_server<t_protocol_handler>::init_server(uint32_t port, const std::string address, epee::net_utils::ssl_support_t ssl_support, const std::pair<std::string, std::string> &private_key_and_certificate_path, const std::list<std::string> &allowed_certificates, bool allow_any_cert) { TRY_ENTRY(); m_stop_signal_sent = false; m_port = port; m_address = address; + if (ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_disabled) + m_ssl_context = create_ssl_context(private_key_and_certificate_path, allowed_certificates, allow_any_cert); // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR). boost::asio::ip::tcp::resolver resolver(io_service_); boost::asio::ip::tcp::resolver::query query(address, boost::lexical_cast<std::string>(port), boost::asio::ip::tcp::resolver::query::canonical_name); @@ -872,7 +958,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_.local_endpoint(); m_port = binded_endpoint.port(); MDEBUG("start accept"); - new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type)); + new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support, m_ssl_context)); acceptor_.async_accept(new_connection_->socket(), boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this, boost::asio::placeholders::error)); @@ -894,7 +980,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) PUSH_WARNINGS DISABLE_GCC_WARNING(maybe-uninitialized) template<class t_protocol_handler> - bool boosted_tcp_server<t_protocol_handler>::init_server(const std::string port, const std::string& address) + bool boosted_tcp_server<t_protocol_handler>::init_server(const std::string port, const std::string& address, epee::net_utils::ssl_support_t ssl_support, const std::pair<std::string, std::string> &private_key_and_certificate_path, const std::list<std::string> &allowed_certificates, bool allow_any_cert) { uint32_t p = 0; @@ -902,7 +988,7 @@ DISABLE_GCC_WARNING(maybe-uninitialized) MERROR("Failed to convert port no = " << port); return false; } - return this->init_server(p, address); + return this->init_server(p, address, ssl_support, private_key_and_certificate_path, allowed_certificates, allow_any_cert); } POP_WARNINGS //--------------------------------------------------------------------------------- @@ -1067,11 +1153,18 @@ POP_WARNINGS if (!e) { if (m_connection_type == e_connection_type_RPC) { - MDEBUG("New server for RPC connections"); + const char *ssl_message = "unknown"; + switch (new_connection_->get_ssl_support()) + { + case epee::net_utils::ssl_support_t::e_ssl_support_disabled: ssl_message = "disabled"; break; + case epee::net_utils::ssl_support_t::e_ssl_support_enabled: ssl_message = "enabled"; break; + case epee::net_utils::ssl_support_t::e_ssl_support_autodetect: ssl_message = "autodetection"; break; + } + MDEBUG("New server for RPC connections, SSL " << ssl_message); new_connection_->setRpcStation(); // hopefully this is not needed actually } connection_ptr conn(std::move(new_connection_)); - new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type)); + new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, conn->get_ssl_support(), m_ssl_context)); acceptor_.async_accept(new_connection_->socket(), boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this, boost::asio::placeholders::error)); @@ -1079,10 +1172,16 @@ POP_WARNINGS boost::asio::socket_base::keep_alive opt(true); conn->socket().set_option(opt); + bool res; if (default_remote.get_type_id() == net_utils::address_type::invalid) - conn->start(true, 1 < m_threads_count); + res = conn->start(true, 1 < m_threads_count); else - conn->start(true, 1 < m_threads_count, default_remote); + res = conn->start(true, 1 < m_threads_count, default_remote); + if (!res) + { + conn->cancel(); + return; + } conn->save_dbg_log(); return; } @@ -1100,18 +1199,18 @@ POP_WARNINGS assert(m_state != nullptr); // always set in constructor _erro("Some problems at accept: " << e.message() << ", connections_count = " << m_state->sock_count); misc_utils::sleep_no_w(100); - new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type)); + new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, new_connection_->get_ssl_support(), m_ssl_context)); acceptor_.async_accept(new_connection_->socket(), boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept, this, boost::asio::placeholders::error)); } //--------------------------------------------------------------------------------- template<class t_protocol_handler> - bool boosted_tcp_server<t_protocol_handler>::add_connection(t_connection_context& out, boost::asio::ip::tcp::socket&& sock, network_address real_remote) + bool boosted_tcp_server<t_protocol_handler>::add_connection(t_connection_context& out, boost::asio::ip::tcp::socket&& sock, network_address real_remote, epee::net_utils::ssl_support_t ssl_support) { if(std::addressof(get_io_service()) == std::addressof(sock.get_io_service())) { - connection_ptr conn(new connection<t_protocol_handler>(std::move(sock), m_state, m_connection_type)); + connection_ptr conn(new connection<t_protocol_handler>(std::move(sock), m_state, m_connection_type, ssl_support, m_ssl_context)); if(conn->start(false, 1 < m_threads_count, std::move(real_remote))) { conn->get_context(out); @@ -1127,34 +1226,10 @@ POP_WARNINGS } //--------------------------------------------------------------------------------- template<class t_protocol_handler> - bool boosted_tcp_server<t_protocol_handler>::connect(const std::string& adr, const std::string& port, uint32_t conn_timeout, t_connection_context& conn_context, const std::string& bind_ip) + typename boosted_tcp_server<t_protocol_handler>::try_connect_result_t boosted_tcp_server<t_protocol_handler>::try_connect(connection_ptr new_connection_l, const std::string& adr, const std::string& port, boost::asio::ip::tcp::socket &sock_, const boost::asio::ip::tcp::endpoint &remote_endpoint, const std::string &bind_ip, uint32_t conn_timeout, epee::net_utils::ssl_support_t ssl_support) { TRY_ENTRY(); - connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type) ); - connections_mutex.lock(); - connections_.insert(new_connection_l); - MDEBUG("connections_ size now " << connections_.size()); - connections_mutex.unlock(); - epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ CRITICAL_REGION_LOCAL(connections_mutex); connections_.erase(new_connection_l); }); - boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket(); - - ////////////////////////////////////////////////////////////////////////// - boost::asio::ip::tcp::resolver resolver(io_service_); - boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name); - boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query); - boost::asio::ip::tcp::resolver::iterator end; - if(iterator == end) - { - _erro("Failed to resolve " << adr); - return false; - } - ////////////////////////////////////////////////////////////////////////// - - - //boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port); - boost::asio::ip::tcp::endpoint remote_endpoint(*iterator); - sock_.open(remote_endpoint.protocol()); if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" ) { @@ -1166,7 +1241,7 @@ POP_WARNINGS MERROR("Error binding to " << bind_ip << ": " << ec.message()); if (sock_.is_open()) sock_.close(); - return false; + return CONNECT_FAILURE; } } @@ -1200,14 +1275,14 @@ POP_WARNINGS { if (sock_.is_open()) sock_.close(); - return false; + return CONNECT_FAILURE; } if(local_shared_context->ec == boost::asio::error::would_block && !r) { //timeout sock_.close(); _dbg3("Failed to connect to " << adr << ":" << port << ", because of timeout (" << conn_timeout << ")"); - return false; + return CONNECT_FAILURE; } } ec = local_shared_context->ec; @@ -1217,11 +1292,79 @@ POP_WARNINGS _dbg3("Some problems at connect, message: " << ec.message()); if (sock_.is_open()) sock_.close(); - return false; + return CONNECT_FAILURE; } _dbg3("Connected success to " << adr << ':' << port); + const epee::net_utils::ssl_support_t ssl_support = new_connection_l->get_ssl_support(); + if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled || ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect) + { + // Handshake + MDEBUG("Handshaking SSL..."); + if (!new_connection_l->handshake(boost::asio::ssl::stream_base::client)) + { + if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect) + { + boost::system::error_code ignored_ec; + sock_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); + sock_.close(); + return CONNECT_NO_SSL; + } + MERROR("SSL handshake failed"); + if (sock_.is_open()) + sock_.close(); + return CONNECT_FAILURE; + } + } + + return CONNECT_SUCCESS; + + CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::try_connect", CONNECT_FAILURE); + } + //--------------------------------------------------------------------------------- + template<class t_protocol_handler> + bool boosted_tcp_server<t_protocol_handler>::connect(const std::string& adr, const std::string& port, uint32_t conn_timeout, t_connection_context& conn_context, const std::string& bind_ip, epee::net_utils::ssl_support_t ssl_support) + { + TRY_ENTRY(); + + connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support, m_ssl_context) ); + connections_mutex.lock(); + connections_.insert(new_connection_l); + MDEBUG("connections_ size now " << connections_.size()); + connections_mutex.unlock(); + epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ CRITICAL_REGION_LOCAL(connections_mutex); connections_.erase(new_connection_l); }); + boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket(); + + ////////////////////////////////////////////////////////////////////////// + boost::asio::ip::tcp::resolver resolver(io_service_); + boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name); + boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query); + boost::asio::ip::tcp::resolver::iterator end; + if(iterator == end) + { + _erro("Failed to resolve " << adr); + return false; + } + ////////////////////////////////////////////////////////////////////////// + + + //boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port); + boost::asio::ip::tcp::endpoint remote_endpoint(*iterator); + + auto try_connect_result = try_connect(new_connection_l, adr, port, sock_, remote_endpoint, bind_ip, conn_timeout, ssl_support); + if (try_connect_result == CONNECT_FAILURE) + return false; + if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect && try_connect_result == CONNECT_NO_SSL) + { + // we connected, but could not connect with SSL, try without + MERROR("SSL handshake failed on an autodetect connection, reconnecting without SSL"); + new_connection_l->disable_ssl(); + try_connect_result = try_connect(new_connection_l, adr, port, sock_, remote_endpoint, bind_ip, conn_timeout, epee::net_utils::ssl_support_t::e_ssl_support_disabled); + if (try_connect_result != CONNECT_SUCCESS) + return false; + } + // start adds the connection to the config object's list, so we don't need to have it locally anymore connections_mutex.lock(); connections_.erase(new_connection_l); @@ -1246,10 +1389,10 @@ POP_WARNINGS } //--------------------------------------------------------------------------------- template<class t_protocol_handler> template<class t_callback> - bool boosted_tcp_server<t_protocol_handler>::connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeout, const t_callback &cb, const std::string& bind_ip) + bool boosted_tcp_server<t_protocol_handler>::connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeout, const t_callback &cb, const std::string& bind_ip, epee::net_utils::ssl_support_t ssl_support) { TRY_ENTRY(); - connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type) ); + connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support, m_ssl_context) ); connections_mutex.lock(); connections_.insert(new_connection_l); MDEBUG("connections_ size now " << connections_.size()); diff --git a/contrib/epee/include/net/connection_basic.hpp b/contrib/epee/include/net/connection_basic.hpp index b1b271db9..328f9afbf 100644 --- a/contrib/epee/include/net/connection_basic.hpp +++ b/contrib/epee/include/net/connection_basic.hpp @@ -47,8 +47,10 @@ #include <memory> #include <boost/asio.hpp> +#include <boost/asio/ssl.hpp> #include "net/net_utils_base.h" +#include "net/net_ssl.h" #include "syncobj.h" namespace epee @@ -95,16 +97,56 @@ class connection_basic { // not-templated base class for rapid developmet of som /// Strand to ensure the connection's handlers are not called concurrently. boost::asio::io_service::strand strand_; /// Socket for the connection. - boost::asio::ip::tcp::socket socket_; + ssl_context_t &m_ssl_context; + ssl_support_t m_ssl_support; + boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_; public: // first counter is the ++/-- count of current sockets, the other socket_number is only-increasing ++ number generator - connection_basic(boost::asio::ip::tcp::socket&& socket, boost::shared_ptr<socket_stats> stats); + connection_basic(boost::asio::ip::tcp::socket&& socket, boost::shared_ptr<socket_stats> stats, ssl_support_t ssl_support, ssl_context_t &ssl_context); + connection_basic(boost::asio::io_service &io_service, boost::shared_ptr<socket_stats> stats, ssl_support_t ssl_support, ssl_context_t &ssl_context); virtual ~connection_basic() noexcept(false); //! \return `socket_stats` object passed in construction (ptr never changes). socket_stats& get_stats() noexcept { return *m_stats; /* verified in constructor */ } + connection_basic(boost::asio::io_service& io_service, std::atomic<long> &ref_sock_count, std::atomic<long> &sock_number, ssl_support_t ssl, ssl_context_t &ssl_context); + + boost::asio::ip::tcp::socket& socket() { return socket_.next_layer(); } + ssl_support_t get_ssl_support() const { return m_ssl_support; } + void disable_ssl() { m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_disabled; } + + bool handshake(boost::asio::ssl::stream_base::handshake_type type) + { + return ssl_handshake(socket_, type, m_ssl_context); + } + + template<typename MutableBufferSequence, typename ReadHandler> + void async_read_some(const MutableBufferSequence &buffers, ReadHandler &&handler) + { + if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled) + socket_.async_read_some(buffers, std::forward<ReadHandler>(handler)); + else + socket().async_read_some(buffers, std::forward<ReadHandler>(handler)); + } + + template<typename ConstBufferSequence, typename WriteHandler> + void async_write_some(const ConstBufferSequence &buffers, WriteHandler &&handler) + { + if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled) + socket_.async_write_some(buffers, std::forward<WriteHandler>(handler)); + else + socket().async_write_some(buffers, std::forward<WriteHandler>(handler)); + } + + template<typename ConstBufferSequence, typename WriteHandler> + void async_write(const ConstBufferSequence &buffers, WriteHandler &&handler) + { + if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled) + boost::asio::async_write(socket_, buffers, std::forward<WriteHandler>(handler)); + else + boost::asio::async_write(socket(), buffers, std::forward<WriteHandler>(handler)); + } // various handlers to be called from connection class: void do_send_handler_write(const void * ptr , size_t cb); diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h index e01691794..34b3ac06c 100644 --- a/contrib/epee/include/net/http_client.h +++ b/contrib/epee/include/net/http_client.h @@ -275,7 +275,10 @@ namespace net_utils chunked_state m_chunked_state; std::string m_chunked_cache; critical_section m_lock; - bool m_ssl; + epee::net_utils::ssl_support_t m_ssl_support; + std::pair<std::string, std::string> m_ssl_private_key_and_certificate_path; + std::list<std::string> m_ssl_allowed_certificates; + bool m_ssl_allow_any_cert; public: explicit http_simple_client_template() @@ -293,35 +296,39 @@ namespace net_utils , m_chunked_state() , m_chunked_cache() , m_lock() - , m_ssl(false) + , m_ssl_support(epee::net_utils::ssl_support_t::e_ssl_support_autodetect) {} const std::string &get_host() const { return m_host_buff; }; const std::string &get_port() const { return m_port; }; - bool set_server(const std::string& address, boost::optional<login> user, bool ssl = false) + bool set_server(const std::string& address, boost::optional<login> user, epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = {}, const std::list<std::string> &allowed_ssl_certificates = {}, bool allow_any_cert = false) { http::url_content parsed{}; const bool r = parse_url(address, parsed); CHECK_AND_ASSERT_MES(r, false, "failed to parse url: " << address); - set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user), ssl); + set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user), ssl_support, private_key_and_certificate_path, allowed_ssl_certificates, allow_any_cert); return true; } - void set_server(std::string host, std::string port, boost::optional<login> user, bool ssl = false) + void set_server(std::string host, std::string port, boost::optional<login> user, epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = {}, const std::list<std::string> &allowed_ssl_certificates = {}, bool allow_any_cert = false) { CRITICAL_REGION_LOCAL(m_lock); disconnect(); m_host_buff = std::move(host); m_port = std::move(port); m_auth = user ? http_client_auth{std::move(*user)} : http_client_auth{}; - m_ssl = ssl; + m_ssl_support = ssl_support; + m_ssl_private_key_and_certificate_path = private_key_and_certificate_path; + m_ssl_allowed_certificates = allowed_ssl_certificates; + m_ssl_allow_any_cert = allow_any_cert; + m_net_client.set_ssl(m_ssl_support, m_ssl_private_key_and_certificate_path, m_ssl_allowed_certificates, m_ssl_allow_any_cert); } bool connect(std::chrono::milliseconds timeout) { CRITICAL_REGION_LOCAL(m_lock); - return m_net_client.connect(m_host_buff, m_port, timeout, m_ssl); + return m_net_client.connect(m_host_buff, m_port, timeout, "0.0.0.0"); } //--------------------------------------------------------------------------- bool disconnect() @@ -330,10 +337,10 @@ namespace net_utils return m_net_client.disconnect(); } //--------------------------------------------------------------------------- - bool is_connected() + bool is_connected(bool *ssl = NULL) { CRITICAL_REGION_LOCAL(m_lock); - return m_net_client.is_connected(); + return m_net_client.is_connected(ssl); } //--------------------------------------------------------------------------- virtual bool handle_target_data(std::string& piece_of_transfer) diff --git a/contrib/epee/include/net/http_server_impl_base.h b/contrib/epee/include/net/http_server_impl_base.h index 5669824c1..236067580 100644 --- a/contrib/epee/include/net/http_server_impl_base.h +++ b/contrib/epee/include/net/http_server_impl_base.h @@ -58,7 +58,10 @@ namespace epee bool init(std::function<void(size_t, uint8_t*)> rng, const std::string& bind_port = "0", const std::string& bind_ip = "0.0.0.0", std::vector<std::string> access_control_origins = std::vector<std::string>(), - boost::optional<net_utils::http::login> user = boost::none) + boost::optional<net_utils::http::login> user = boost::none, + epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, + const std::pair<std::string, std::string> &private_key_and_certificate_path = {}, + const std::list<std::string> &allowed_certificates = std::list<std::string>(), bool allow_any_cert = false) { //set self as callback handler @@ -75,7 +78,7 @@ namespace epee m_net_server.get_config_object().m_user = std::move(user); MGINFO("Binding on " << bind_ip << ":" << bind_port); - bool res = m_net_server.init_server(bind_port, bind_ip); + bool res = m_net_server.init_server(bind_port, bind_ip, ssl_support, private_key_and_certificate_path, allowed_certificates, allow_any_cert); if(!res) { LOG_ERROR("Failed to bind server"); diff --git a/contrib/epee/include/net/net_helper.h b/contrib/epee/include/net/net_helper.h index 94744ac21..5d9bb61cf 100644 --- a/contrib/epee/include/net/net_helper.h +++ b/contrib/epee/include/net/net_helper.h @@ -40,6 +40,7 @@ #include <boost/lambda/lambda.hpp> #include <boost/interprocess/detail/atomic.hpp> #include "net/net_utils_base.h" +#include "net/net_ssl.h" #include "misc_language.h" #undef MONERO_DEFAULT_LOG_CATEGORY @@ -57,6 +58,13 @@ namespace net_utils class blocked_mode_client { + enum try_connect_result_t + { + CONNECT_SUCCESS, + CONNECT_FAILURE, + CONNECT_NO_SSL, + }; + struct handler_obj @@ -84,9 +92,9 @@ namespace net_utils m_connected(false), m_deadline(m_io_service), m_shutdowned(0), - m_ssl(false), - m_ctx(boost::asio::ssl::context::sslv23), - m_ssl_socket(m_io_service,m_ctx) + m_ssl_support(epee::net_utils::ssl_support_t::e_ssl_support_autodetect), + m_ctx({boost::asio::ssl::context(boost::asio::ssl::context::sslv23), {}}), + m_ssl_socket(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(m_io_service,m_ctx.context)) { @@ -110,28 +118,92 @@ namespace net_utils catch(...) { /* ignore */ } } + inline void set_ssl(epee::net_utils::ssl_support_t ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::pair<std::string, std::string> &private_key_and_certificate_path = {}, const std::list<std::string> &allowed_certificates = std::list<std::string>(), bool allow_any_cert = false) + { + if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_disabled) + m_ctx = {boost::asio::ssl::context(boost::asio::ssl::context::sslv23), {}}; + else + m_ctx = create_ssl_context(private_key_and_certificate_path, allowed_certificates, allow_any_cert); + m_ssl_support = ssl_support; + } + inline - bool connect(const std::string& addr, int port, std::chrono::milliseconds timeout, bool ssl = false, const std::string& bind_ip = "0.0.0.0") + bool connect(const std::string& addr, int port, std::chrono::milliseconds timeout, const std::string& bind_ip = "0.0.0.0") { - return connect(addr, std::to_string(port), timeout, ssl, bind_ip); + return connect(addr, std::to_string(port), timeout, bind_ip); } inline - bool connect(const std::string& addr, const std::string& port, std::chrono::milliseconds timeout, bool ssl = false, const std::string& bind_ip = "0.0.0.0") + try_connect_result_t try_connect(const std::string& addr, const std::string& port, const boost::asio::ip::tcp::endpoint &remote_endpoint, std::chrono::milliseconds timeout, const std::string& bind_ip, epee::net_utils::ssl_support_t ssl_support) { - m_connected = false; - m_ssl = ssl; + m_ssl_socket->next_layer().open(remote_endpoint.protocol()); + if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" ) + { + boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(addr.c_str()), 0); + m_ssl_socket->next_layer().bind(local_endpoint); + } + + + m_deadline.expires_from_now(timeout); + + boost::system::error_code ec = boost::asio::error::would_block; + + m_ssl_socket->next_layer().async_connect(remote_endpoint, boost::lambda::var(ec) = boost::lambda::_1); + while (ec == boost::asio::error::would_block) + { + m_io_service.run_one(); + } + + if (!ec && m_ssl_socket->next_layer().is_open()) + { + m_connected = true; + m_deadline.expires_at(std::chrono::steady_clock::time_point::max()); + // SSL Options + if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled || ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect) + { + if (!ssl_handshake(*m_ssl_socket, boost::asio::ssl::stream_base::client, m_ctx)) + { + if (ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect) + { + boost::system::error_code ignored_ec; + m_ssl_socket->next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); + m_ssl_socket->next_layer().close(); + m_connected = false; + return CONNECT_NO_SSL; + } + else + { + MWARNING("Failed to establish SSL connection"); + m_connected = false; + return CONNECT_FAILURE; + } + } + m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_enabled; + } + return CONNECT_SUCCESS; + }else + { + MWARNING("Some problems at connect, message: " << ec.message()); + return CONNECT_FAILURE; + } + + } + + inline + bool connect(const std::string& addr, const std::string& port, std::chrono::milliseconds timeout, const std::string& bind_ip = "0.0.0.0") + { + m_connected = false; try { - m_ssl_socket.next_layer().close(); + m_ssl_socket->next_layer().close(); // Set SSL options // disable sslv2 - m_ctx.set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2); - m_ctx.set_default_verify_paths(); + m_ctx.context.set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2); + m_ctx.context.set_default_verify_paths(); + m_ssl_socket.reset(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(m_io_service, m_ctx.context)); // Get a list of endpoints corresponding to the server name. - ////////////////////////////////////////////////////////////////////////// @@ -151,45 +223,20 @@ namespace net_utils //boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port); boost::asio::ip::tcp::endpoint remote_endpoint(*iterator); - - m_ssl_socket.next_layer().open(remote_endpoint.protocol()); - if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" ) - { - boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(addr.c_str()), 0); - m_ssl_socket.next_layer().bind(local_endpoint); - } - - - m_deadline.expires_from_now(timeout); - - - boost::system::error_code ec = boost::asio::error::would_block; - - m_ssl_socket.next_layer().async_connect(remote_endpoint, boost::lambda::var(ec) = boost::lambda::_1); - while (ec == boost::asio::error::would_block) - { - m_io_service.run_one(); - } - - if (!ec && m_ssl_socket.next_layer().is_open()) + try_connect_result_t try_connect_result = try_connect(addr, port, remote_endpoint, timeout, bind_ip, m_ssl_support); + if (try_connect_result == CONNECT_FAILURE) + return false; + if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect) { - m_connected = true; - m_deadline.expires_at(std::chrono::steady_clock::time_point::max()); - // SSL Options - if(m_ssl) { - // Disable verification of host certificate - m_ssl_socket.set_verify_mode(boost::asio::ssl::verify_peer); - // Handshake - m_ssl_socket.next_layer().set_option(boost::asio::ip::tcp::no_delay(true)); - m_ssl_socket.handshake(boost::asio::ssl::stream_base::client); + m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_enabled; + if (try_connect_result == CONNECT_NO_SSL) + { + MERROR("SSL handshake failed on an autodetect connection, reconnecting without SSL"); + m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_disabled; + if (try_connect(addr, port, remote_endpoint, timeout, bind_ip, m_ssl_support) != CONNECT_SUCCESS) + return false; } - return true; - }else - { - MWARNING("Some problems at connect, message: " << ec.message()); - return false; } - } catch(const boost::system::system_error& er) { @@ -213,9 +260,9 @@ namespace net_utils if(m_connected) { m_connected = false; - if(m_ssl) + if(m_ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_disabled) shutdown_ssl(); - m_ssl_socket.next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both); + m_ssl_socket->next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both); } } @@ -342,9 +389,13 @@ namespace net_utils return true; } - bool is_connected() + bool is_connected(bool *ssl = NULL) { - return m_connected && m_ssl_socket.next_layer().is_open(); + if (!m_connected || !m_ssl_socket->next_layer().is_open()) + return false; + if (ssl) + *ssl = m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled; + return true; } inline @@ -506,15 +557,15 @@ namespace net_utils { m_deadline.cancel(); boost::system::error_code ec; - if(m_ssl) + if(m_ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_disabled) shutdown_ssl(); - m_ssl_socket.next_layer().cancel(ec); + m_ssl_socket->next_layer().cancel(ec); if(ec) MDEBUG("Problems at cancel: " << ec.message()); - m_ssl_socket.next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); + m_ssl_socket->next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); if(ec) MDEBUG("Problems at shutdown: " << ec.message()); - m_ssl_socket.next_layer().close(ec); + m_ssl_socket->next_layer().close(ec); if(ec) MDEBUG("Problems at close: " << ec.message()); boost::interprocess::ipcdetail::atomic_write32(&m_shutdowned, 1); @@ -533,7 +584,7 @@ namespace net_utils boost::asio::ip::tcp::socket& get_socket() { - return m_ssl_socket.next_layer(); + return m_ssl_socket->next_layer(); } private: @@ -550,7 +601,7 @@ namespace net_utils // connect(), read_line() or write_line() functions to return. LOG_PRINT_L3("Timed out socket"); m_connected = false; - m_ssl_socket.next_layer().close(); + m_ssl_socket->next_layer().close(); // There is no longer an active deadline. The expiry is set to positive // infinity so that the actor takes no action until a new deadline is set. @@ -565,7 +616,7 @@ namespace net_utils // ssl socket shutdown blocks if server doesn't respond. We close after 2 secs boost::system::error_code ec = boost::asio::error::would_block; m_deadline.expires_from_now(std::chrono::milliseconds(2000)); - m_ssl_socket.async_shutdown(boost::lambda::var(ec) = boost::lambda::_1); + m_ssl_socket->async_shutdown(boost::lambda::var(ec) = boost::lambda::_1); while (ec == boost::asio::error::would_block) { m_io_service.run_one(); @@ -586,35 +637,39 @@ namespace net_utils bool write(const void* data, size_t sz, boost::system::error_code& ec) { bool success; - if(m_ssl) - success = boost::asio::write(m_ssl_socket, boost::asio::buffer(data, sz), ec); + if(m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled) + success = boost::asio::write(*m_ssl_socket, boost::asio::buffer(data, sz), ec); else - success = boost::asio::write(m_ssl_socket.next_layer(), boost::asio::buffer(data, sz), ec); + success = boost::asio::write(m_ssl_socket->next_layer(), boost::asio::buffer(data, sz), ec); return success; } void async_write(const void* data, size_t sz, boost::system::error_code& ec) { - if(m_ssl) - boost::asio::async_write(m_ssl_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1); + if(m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled) + boost::asio::async_write(*m_ssl_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1); else - boost::asio::async_write(m_ssl_socket.next_layer(), boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1); + boost::asio::async_write(m_ssl_socket->next_layer(), boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1); } void async_read(char* buff, size_t sz, boost::asio::detail::transfer_at_least_t transfer_at_least, handler_obj& hndlr) { - if(!m_ssl) - boost::asio::async_read(m_ssl_socket.next_layer(), boost::asio::buffer(buff, sz), transfer_at_least, hndlr); + if(m_ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_enabled) + boost::asio::async_read(m_ssl_socket->next_layer(), boost::asio::buffer(buff, sz), transfer_at_least, hndlr); else - boost::asio::async_read(m_ssl_socket, boost::asio::buffer(buff, sz), transfer_at_least, hndlr); + boost::asio::async_read(*m_ssl_socket, boost::asio::buffer(buff, sz), transfer_at_least, hndlr); } protected: boost::asio::io_service m_io_service; - boost::asio::ssl::context m_ctx; - boost::asio::ssl::stream<boost::asio::ip::tcp::socket> m_ssl_socket; - bool m_ssl; + epee::net_utils::ssl_context_t m_ctx; + std::shared_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> m_ssl_socket; + epee::net_utils::ssl_support_t m_ssl_support; + std::string m_ssl_private_key; + std::string m_ssl_certificate; + std::list<std::string> m_ssl_allowed_certificates; + bool m_ssl_allow_any_cerl; bool m_initialized; bool m_connected; boost::asio::steady_timer m_deadline; @@ -722,7 +777,7 @@ namespace net_utils // asynchronous operations are cancelled. This allows the blocked // connect(), read_line() or write_line() functions to return. LOG_PRINT_L3("Timed out socket"); - m_ssl_socket.next_layer().close(); + m_ssl_socket->next_layer().close(); // There is no longer an active deadline. The expiry is set to positive // infinity so that the actor takes no action until a new deadline is set. diff --git a/contrib/epee/include/net/net_ssl.h b/contrib/epee/include/net/net_ssl.h new file mode 100644 index 000000000..9ae1883af --- /dev/null +++ b/contrib/epee/include/net/net_ssl.h @@ -0,0 +1,68 @@ +// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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. +// + + + +#ifndef _NET_SSL_H +#define _NET_SSL_H + +#include <stdint.h> +#include <string> +#include <list> +#include <boost/utility/string_ref.hpp> +#include <boost/asio/ip/tcp.hpp> +#include <boost/asio/ssl.hpp> + +namespace epee +{ +namespace net_utils +{ + enum class ssl_support_t: uint8_t { + e_ssl_support_disabled, + e_ssl_support_enabled, + e_ssl_support_autodetect, + }; + + struct ssl_context_t + { + boost::asio::ssl::context context; + std::list<std::string> allowed_certificates; + bool allow_any_cert; + }; + + // https://security.stackexchange.com/questions/34780/checking-client-hello-for-https-classification + constexpr size_t get_ssl_magic_size() { return 9; } + bool is_ssl(const unsigned char *data, size_t len); + ssl_context_t create_ssl_context(const std::pair<std::string, std::string> &private_key_and_certificate_path, std::list<std::string> allowed_certificates, bool allow_any_cert); + void use_ssl_certificate(ssl_context_t &ssl_context, const std::pair<std::string, std::string> &private_key_and_certificate_path); + bool create_ssl_certificate(std::string &pkey_buffer, std::string &cert_buffer); + bool is_certificate_allowed(boost::asio::ssl::verify_context &ctx, const std::list<std::string> &allowed_certificates); + bool ssl_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socket, boost::asio::ssl::stream_base::handshake_type type, const epee::net_utils::ssl_context_t &ssl_context); + bool ssl_support_from_string(ssl_support_t &ssl, boost::string_ref s); +} +} + +#endif //_NET_SSL_H diff --git a/contrib/epee/include/net/net_utils_base.h b/contrib/epee/include/net/net_utils_base.h index 82f8a7fe8..7b5b07ef2 100644 --- a/contrib/epee/include/net/net_utils_base.h +++ b/contrib/epee/include/net/net_utils_base.h @@ -47,6 +47,7 @@ namespace net { class tor_address; + class i2p_address; } namespace epee @@ -196,7 +197,7 @@ namespace net_utils template<typename Type> const Type &as() const { return as_mutable<const Type>(); } BEGIN_KV_SERIALIZE_MAP() - // need to `#include "net/tor_address.h"` when serializing `network_address` + // need to `#include "net/[i2p|tor]_address.h"` when serializing `network_address` static constexpr std::integral_constant<bool, is_store> is_store_{}; std::uint8_t type = std::uint8_t(is_store ? this_ref.get_type_id() : address_type::invalid); @@ -209,6 +210,8 @@ namespace net_utils return this_ref.template serialize_addr<ipv4_network_address>(is_store_, stg, hparent_section); case address_type::tor: return this_ref.template serialize_addr<net::tor_address>(is_store_, stg, hparent_section); + case address_type::i2p: + return this_ref.template serialize_addr<net::i2p_address>(is_store_, stg, hparent_section); case address_type::invalid: default: break; @@ -241,6 +244,7 @@ namespace net_utils const network_address m_remote_address; const bool m_is_income; const time_t m_started; + const time_t m_ssl; time_t m_last_recv; time_t m_last_send; uint64_t m_recv_cnt; @@ -251,13 +255,14 @@ namespace net_utils double m_max_speed_up; connection_context_base(boost::uuids::uuid connection_id, - const network_address &remote_address, bool is_income, + const network_address &remote_address, bool is_income, bool ssl, time_t last_recv = 0, time_t last_send = 0, uint64_t recv_cnt = 0, uint64_t send_cnt = 0): m_connection_id(connection_id), m_remote_address(remote_address), m_is_income(is_income), m_started(time(NULL)), + m_ssl(ssl), m_last_recv(last_recv), m_last_send(last_send), m_recv_cnt(recv_cnt), @@ -272,6 +277,7 @@ namespace net_utils m_remote_address(), m_is_income(false), m_started(time(NULL)), + m_ssl(false), m_last_recv(0), m_last_send(0), m_recv_cnt(0), @@ -284,17 +290,17 @@ namespace net_utils connection_context_base& operator=(const connection_context_base& a) { - set_details(a.m_connection_id, a.m_remote_address, a.m_is_income); + set_details(a.m_connection_id, a.m_remote_address, a.m_is_income, a.m_ssl); return *this; } private: template<class t_protocol_handler> friend class connection; - void set_details(boost::uuids::uuid connection_id, const network_address &remote_address, bool is_income) + void set_details(boost::uuids::uuid connection_id, const network_address &remote_address, bool is_income, bool ssl) { this->~connection_context_base(); - new(this) connection_context_base(connection_id, remote_address, is_income); + new(this) connection_context_base(connection_id, remote_address, is_income, ssl); } }; diff --git a/contrib/epee/include/net/network_throttle-detail.hpp b/contrib/epee/include/net/network_throttle-detail.hpp index 955668d62..9d12291f4 100644 --- a/contrib/epee/include/net/network_throttle-detail.hpp +++ b/contrib/epee/include/net/network_throttle-detail.hpp @@ -36,6 +36,7 @@ #ifndef INCLUDED_throttle_detail_hpp #define INCLUDED_throttle_detail_hpp +#include <boost/circular_buffer.hpp> #include "network_throttle.hpp" namespace epee @@ -61,7 +62,7 @@ class network_throttle : public i_network_throttle { network_time_seconds m_slot_size; // the size of one slot. TODO: now hardcoded for 1 second e.g. in time_to_slot() // TODO for big window size, for performance better the substract on change of m_last_sample_time instead of recalculating average of eg >100 elements - std::vector< packet_info > m_history; // the history of bw usage + boost::circular_buffer< packet_info > m_history; // the history of bw usage network_time_seconds m_last_sample_time; // time of last history[0] - so we know when to rotate the buffer network_time_seconds m_start_time; // when we were created bool m_any_packet_yet; // did we yet got any packet to count diff --git a/contrib/epee/include/stats.h b/contrib/epee/include/stats.h new file mode 100644 index 000000000..1cf9c68fb --- /dev/null +++ b/contrib/epee/include/stats.h @@ -0,0 +1,58 @@ +#pragma once + +#include <vector> + +template<typename T, typename Tpod = T> +class Stats +{ +public: + Stats(const std::vector<T> &v): values(v), cached(0) {} + ~Stats() {} + + size_t get_size() const; + Tpod get_min() const; + Tpod get_max() const; + Tpod get_median() const; + double get_mean() const; + double get_confidence_interval_95() const; + double get_confidence_interval_99() const; + double get_standard_deviation() const; + double get_standard_error() const; + double get_variance() const; + double get_kurtosis() const; + double get_non_parametric_skew() const; + double get_t_test(T t) const; + double get_t_test(size_t npoints, double mean, double stddev) const; + double get_t_test(const Stats<T> &other) const; + double get_z_test(const Stats<T> &other) const; + double get_test(const Stats<T> &other) const; + std::vector<Tpod> get_quantiles(unsigned int quantiles) const; + std::vector<size_t> get_bins(unsigned int bins) const; + bool is_same_distribution_95(size_t npoints, double mean, double stddev) const; + bool is_same_distribution_95(const Stats<T> &other) const; + bool is_same_distribution_99(size_t npoints, double mean, double stddev) const; + bool is_same_distribution_99(const Stats<T> &other) const; + + double get_cdf95(size_t df) const; + double get_cdf95(const Stats<T> &other) const; + double get_cdf99(size_t df) const; + double get_cdf99(const Stats<T> &other) const; + +private: + inline bool is_cached(int bit) const; + inline void set_cached(int bit) const; + + const std::vector<T> &values; + + mutable uint64_t cached; + mutable Tpod min; + mutable Tpod max; + mutable Tpod median; + mutable double mean; + mutable double standard_deviation; + mutable double standard_error; + mutable double variance; + mutable double kurtosis; +}; + +#include "stats.inl" diff --git a/contrib/epee/include/stats.inl b/contrib/epee/include/stats.inl new file mode 100644 index 000000000..5a5cd0b93 --- /dev/null +++ b/contrib/epee/include/stats.inl @@ -0,0 +1,359 @@ +#include <math.h> +#include <limits> +#include <algorithm> +#include "stats.h" + +enum +{ + bit_min = 0, + bit_max, + bit_median, + bit_mean, + bit_standard_deviation, + bit_standard_error, + bit_variance, + bit_kurtosis, +}; + +static inline double square(double x) +{ + return x * x; +} + +template<typename T> +static inline double interpolate(T v, T v0, double i0, T v1, double i1) +{ + return i0 + (i1 - i0) * (v - v0) / (v1 - v0); +} + +template<typename T, typename Tpod> +inline bool Stats<T, Tpod>::is_cached(int bit) const +{ + return cached & (1<<bit); +} + +template<typename T, typename Tpod> +inline void Stats<T, Tpod>::set_cached(int bit) const +{ + cached |= 1<<bit; +} + +template<typename T, typename Tpod> +size_t Stats<T, Tpod>::get_size() const +{ + return values.size(); +} + +template<typename T, typename Tpod> +Tpod Stats<T, Tpod>::get_min() const +{ + if (!is_cached(bit_min)) + { + min = std::numeric_limits<Tpod>::max(); + for (const T &v: values) + min = std::min<Tpod>(min, v); + set_cached(bit_min); + } + return min; +} + +template<typename T, typename Tpod> +Tpod Stats<T, Tpod>::get_max() const +{ + if (!is_cached(bit_max)) + { + max = std::numeric_limits<Tpod>::min(); + for (const T &v: values) + max = std::max<Tpod>(max, v); + set_cached(bit_max); + } + return max; +} + +template<typename T, typename Tpod> +Tpod Stats<T, Tpod>::get_median() const +{ + if (!is_cached(bit_median)) + { + std::vector<Tpod> sorted; + sorted.reserve(values.size()); + for (const T &v: values) + sorted.push_back(v); + std::sort(sorted.begin(), sorted.end()); + if (sorted.size() & 1) + { + median = sorted[sorted.size() / 2]; + } + else + { + median = (sorted[(sorted.size() - 1) / 2] + sorted[sorted.size() / 2]) / 2; + } + set_cached(bit_median); + } + return median; +} + +template<typename T, typename Tpod> +double Stats<T, Tpod>::get_mean() const +{ + if (values.empty()) + return 0.0; + if (!is_cached(bit_mean)) + { + mean = 0.0; + for (const T &v: values) + mean += v; + mean /= values.size(); + set_cached(bit_mean); + } + return mean; +} + +template<typename T, typename Tpod> +double Stats<T, Tpod>::get_cdf95(size_t df) const +{ + static const double p[101] = { + -1, 12.706, 4.3027, 3.1824, 2.7765, 2.5706, 2.4469, 2.3646, 2.3060, 2.2622, 2.2281, 2.2010, 2.1788, 2.1604, 2.1448, 2.1315, + 2.1199, 2.1098, 2.1009, 2.0930, 2.0860, 2.0796, 2.0739, 2.0687, 2.0639, 2.0595, 2.0555, 2.0518, 2.0484, 2.0452, 2.0423, 2.0395, + 2.0369, 2.0345, 2.0322, 2.0301, 2.0281, 2.0262, 2.0244, 2.0227, 2.0211, 2.0195, 2.0181, 2.0167, 2.0154, 2.0141, 2.0129, 2.0117, + 2.0106, 2.0096, 2.0086, 2.0076, 2.0066, 2.0057, 2.0049, 2.0040, 2.0032, 2.0025, 2.0017, 2.0010, 2.0003, 1.9996, 1.9990, 1.9983, + 1.9977, 1.9971, 1.9966, 1.9960, 1.9955, 1.9949, 1.9944, 1.9939, 1.9935, 1.9930, 1.9925, 1.9921, 1.9917, 1.9913, 1.9908, 1.9905, + 1.9901, 1.9897, 1.9893, 1.9890, 1.9886, 1.9883, 1.9879, 1.9876, 1.9873, 1.9870, 1.9867, 1.9864, 1.9861, 1.9858, 1.9855, 1.9852, + 1.9850, 1.9847, 1.9845, 1.9842, 1.9840, + }; + if (df <= 100) + return p[df]; + if (df <= 120) + return interpolate<size_t>(df, 100, 1.9840, 120, 1.98); + return 1.96; +} + +template<typename T, typename Tpod> +double Stats<T, Tpod>::get_cdf95(const Stats<T> &other) const +{ + return get_cdf95(get_size() + other.get_size() - 2); +} + +template<typename T, typename Tpod> +double Stats<T, Tpod>::get_cdf99(size_t df) const +{ + static const double p[101] = { + -1, 9.9250, 5.8408, 4.6041, 4.0321, 3.7074, 3.4995, 3.3554, 3.2498, 3.1693, 3.1058, 3.0545, 3.0123, 2.9768, 2.9467, 2.9208, 2.8982, + 2.8784, 2.8609, 2.8453, 2.8314, 2.8188, 2.8073, 2.7970, 2.7874, 2.7787, 2.7707, 2.7633, 2.7564, 2.7500, 2.7440, 2.7385, 2.7333, + 2.7284, 2.7238, 2.7195, 2.7154, 2.7116, 2.7079, 2.7045, 2.7012, 2.6981, 2.6951, 2.6923, 2.6896, 2.6870, 2.6846, 2.6822, 2.6800, + 2.6778, 2.6757, 2.6737, 2.6718, 2.6700, 2.6682, 2.6665, 2.6649, 2.6633, 2.6618, 2.6603, 2.6589, 2.6575, 2.6561, 2.6549, 2.6536, + 2.6524, 2.6512, 2.6501, 2.6490, 2.6479, 2.6469, 2.6458, 2.6449, 2.6439, 2.6430, 2.6421, 2.6412, 2.6403, 2.6395, 2.6387, 2.6379, + 2.6371, 2.6364, 2.6356, 2.6349, 2.6342, 2.6335, 2.6329, 2.6322, 2.6316, 2.6309, 2.6303, 2.6297, 2.6291, 2.6286, 2.6280, 2.6275, + 2.6269, 2.6264, 2.6259, + }; + if (df <= 100) + return p[df]; + if (df <= 120) + return interpolate<size_t>(df, 100, 2.6529, 120, 2.617); + return 2.576; +} + +template<typename T, typename Tpod> +double Stats<T, Tpod>::get_cdf99(const Stats<T> &other) const +{ + return get_cdf99(get_size() + other.get_size() - 2); +} + +template<typename T, typename Tpod> +double Stats<T, Tpod>::get_confidence_interval_95() const +{ + const size_t df = get_size() - 1; + return get_standard_error() * get_cdf95(df); +} + +template<typename T, typename Tpod> +double Stats<T, Tpod>::get_confidence_interval_99() const +{ + const size_t df = get_size() - 1; + return get_standard_error() * get_cdf99(df); +} + +template<typename T, typename Tpod> +bool Stats<T, Tpod>::is_same_distribution_95(size_t npoints, double mean, double stddev) const +{ + return fabs(get_t_test(npoints, mean, stddev)) < get_cdf95(get_size() + npoints - 2); +} + +template<typename T, typename Tpod> +bool Stats<T, Tpod>::is_same_distribution_95(const Stats<T> &other) const +{ + return fabs(get_t_test(other)) < get_cdf95(other); +} + +template<typename T, typename Tpod> +bool Stats<T, Tpod>::is_same_distribution_99(size_t npoints, double mean, double stddev) const +{ + return fabs(get_t_test(npoints, mean, stddev)) < get_cdf99(get_size() + npoints - 2); +} + +template<typename T, typename Tpod> +bool Stats<T, Tpod>::is_same_distribution_99(const Stats<T> &other) const +{ + return fabs(get_t_test(other)) < get_cdf99(other); +} + +template<typename T, typename Tpod> +double Stats<T, Tpod>::get_standard_deviation() const +{ + if (values.size() <= 1) + return 0.0; + if (!is_cached(bit_standard_deviation)) + { + Tpod m = get_mean(), t = 0; + for (const T &v: values) + t += ((T)v - m) * ((T)v - m); + standard_deviation = sqrt(t / ((double)values.size() - 1)); + set_cached(bit_standard_deviation); + } + return standard_deviation; +} + +template<typename T, typename Tpod> +double Stats<T, Tpod>::get_standard_error() const +{ + if (!is_cached(bit_standard_error)) + { + standard_error = get_standard_deviation() / sqrt(get_size()); + set_cached(bit_standard_error); + } + return standard_error; +} + +template<typename T, typename Tpod> +double Stats<T, Tpod>::get_variance() const +{ + if (!is_cached(bit_variance)) + { + double stddev = get_standard_deviation(); + variance = stddev * stddev; + set_cached(bit_variance); + } + return variance; +} + +template<typename T, typename Tpod> +double Stats<T, Tpod>::get_kurtosis() const +{ + if (values.empty()) + return 0.0; + if (!is_cached(bit_kurtosis)) + { + double m = get_mean(); + double n = 0, d = 0; + for (const T &v: values) + { + T p2 = (v - m) * (v - m); + T p4 = p2 * p2; + n += p4; + d += p2; + } + n /= values.size(); + d /= values.size(); + d *= d; + kurtosis = n / d; + set_cached(bit_kurtosis); + } + return kurtosis; +} + +template<typename T, typename Tpod> +double Stats<T, Tpod>::get_non_parametric_skew() const +{ + return (get_mean() - get_median()) / get_standard_deviation(); +} + +template<typename T, typename Tpod> +double Stats<T, Tpod>::get_t_test(T t) const +{ + const double n = get_mean() - t; + const double d = get_standard_deviation() / sqrt(get_size()); + return n / d; +} + +template<typename T, typename Tpod> +double Stats<T, Tpod>::get_t_test(size_t npoints, double mean, double stddev) const +{ + const double n = get_mean() - mean; + const double d = sqrt(get_variance() / get_size() + square(stddev) / npoints); + return n / d; +} + +template<typename T, typename Tpod> +double Stats<T, Tpod>::get_t_test(const Stats<T> &other) const +{ + const double n = get_mean() - other.get_mean(); + const double d = sqrt(get_variance() / get_size() + other.get_variance() / other.get_size()); + return n / d; +} + +template<typename T, typename Tpod> +double Stats<T, Tpod>::get_z_test(const Stats<T> &other) const +{ + const double m0 = get_mean(); + const double m1 = other.get_mean(); + const double sd0 = get_standard_deviation(); + const double sd1 = other.get_standard_deviation(); + const size_t s0 = get_size(); + const size_t s1 = other.get_size(); + + const double n = m0 - m1; + const double d = sqrt(square(sd0 / sqrt(s0)) + square(sd1 / sqrt(s1))); + + return n / d; +} + +template<typename T, typename Tpod> +double Stats<T, Tpod>::get_test(const Stats<T> &other) const +{ + if (get_size() >= 30 && other.get_size() >= 30) + return get_z_test(other); + else + return get_t_test(other); +} + +template<typename T, typename Tpod> +std::vector<Tpod> Stats<T, Tpod>::get_quantiles(unsigned int quantiles) const +{ + std::vector<Tpod> sorted; + sorted.reserve(values.size()); + for (const T &v: values) + sorted.push_back(v); + std::sort(sorted.begin(), sorted.end()); + std::vector<Tpod> q(quantiles + 1, 0); + for (unsigned int i = 1; i <= quantiles; ++i) + { + unsigned idx = (unsigned)ceil(values.size() * i / (double)quantiles); + q[i] = sorted[idx - 1]; + } + if (!is_cached(bit_min)) + { + min = sorted.front(); + set_cached(bit_min); + } + q[0] = min; + if (!is_cached(bit_max)) + { + max = sorted.back(); + set_cached(bit_max); + } + return q; +} + +template<typename T, typename Tpod> +std::vector<size_t> Stats<T, Tpod>::get_bins(unsigned int bins) const +{ + std::vector<size_t> b(bins, 0); + const double scale = 1.0 / (get_max() - get_min()); + const T base = get_min(); + for (const T &v: values) + { + unsigned int idx = (v - base) * scale; + ++b[idx]; + } + return b; +} diff --git a/contrib/epee/src/CMakeLists.txt b/contrib/epee/src/CMakeLists.txt index cea50c9dd..e913211ea 100644 --- a/contrib/epee/src/CMakeLists.txt +++ b/contrib/epee/src/CMakeLists.txt @@ -27,7 +27,7 @@ # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp net_utils_base.cpp string_tools.cpp wipeable_string.cpp memwipe.c - connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp mlocker.cpp buffer.cpp) + connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp mlocker.cpp buffer.cpp net_ssl.cpp) if (USE_READLINE AND GNU_READLINE_FOUND) add_library(epee_readline STATIC readline_buffer.cpp) endif() diff --git a/contrib/epee/src/connection_basic.cpp b/contrib/epee/src/connection_basic.cpp index f5f9b59fe..377fb3452 100644 --- a/contrib/epee/src/connection_basic.cpp +++ b/contrib/epee/src/connection_basic.cpp @@ -48,7 +48,7 @@ #include "net/network_throttle-detail.hpp" #undef MONERO_DEFAULT_LOG_CATEGORY -#define MONERO_DEFAULT_LOG_CATEGORY "net.p2p" +#define MONERO_DEFAULT_LOG_CATEGORY "net.conn" // ################################################################################################ // local (TU local) headers @@ -113,14 +113,41 @@ connection_basic_pimpl::connection_basic_pimpl(const std::string &name) : m_thro int connection_basic_pimpl::m_default_tos; // methods: -connection_basic::connection_basic(boost::asio::ip::tcp::socket&& socket, boost::shared_ptr<socket_stats> stats) +connection_basic::connection_basic(boost::asio::ip::tcp::socket&& sock, boost::shared_ptr<socket_stats> stats, ssl_support_t ssl_support, ssl_context_t &ssl_context) : m_stats(std::move(stats)), mI( new connection_basic_pimpl("peer") ), - strand_(socket.get_io_service()), - socket_(std::move(socket)), + strand_(sock.get_io_service()), + socket_(sock.get_io_service(), ssl_context.context), + m_want_close_connection(false), + m_was_shutdown(false), + m_ssl_support(ssl_support), + m_ssl_context(ssl_context) +{ + // add nullptr checks if removed + CHECK_AND_ASSERT_THROW_MES(bool(m_stats), "stats shared_ptr cannot be null"); + + socket_.next_layer() = std::move(sock); + + ++(m_stats->sock_count); // increase the global counter + mI->m_peer_number = m_stats->sock_number.fetch_add(1); // use, and increase the generated number + + std::string remote_addr_str = "?"; + try { boost::system::error_code e; remote_addr_str = socket().remote_endpoint(e).address().to_string(); } catch(...){} ; + + _note("Spawned connection #"<<mI->m_peer_number<<" to " << remote_addr_str << " currently we have sockets count:" << m_stats->sock_count); +} + +connection_basic::connection_basic(boost::asio::io_service &io_service, boost::shared_ptr<socket_stats> stats, ssl_support_t ssl_support, ssl_context_t &ssl_context) + : + m_stats(std::move(stats)), + mI( new connection_basic_pimpl("peer") ), + strand_(io_service), + socket_(io_service, ssl_context.context), m_want_close_connection(false), - m_was_shutdown(false) + m_was_shutdown(false), + m_ssl_support(ssl_support), + m_ssl_context(ssl_context) { // add nullptr checks if removed CHECK_AND_ASSERT_THROW_MES(bool(m_stats), "stats shared_ptr cannot be null"); @@ -129,17 +156,18 @@ connection_basic::connection_basic(boost::asio::ip::tcp::socket&& socket, boost: mI->m_peer_number = m_stats->sock_number.fetch_add(1); // use, and increase the generated number std::string remote_addr_str = "?"; - try { boost::system::error_code e; remote_addr_str = socket_.remote_endpoint(e).address().to_string(); } catch(...){} ; + try { boost::system::error_code e; remote_addr_str = socket().remote_endpoint(e).address().to_string(); } catch(...){} ; - _note("Spawned connection p2p#"<<mI->m_peer_number<<" to " << remote_addr_str << " currently we have sockets count:" << m_stats->sock_count); + _note("Spawned connection #"<<mI->m_peer_number<<" to " << remote_addr_str << " currently we have sockets count:" << m_stats->sock_count); } connection_basic::~connection_basic() noexcept(false) { --(m_stats->sock_count); std::string remote_addr_str = "?"; - try { boost::system::error_code e; remote_addr_str = socket_.remote_endpoint(e).address().to_string(); } catch(...){} ; - _note("Destructing connection p2p#"<<mI->m_peer_number << " to " << remote_addr_str); + try { boost::system::error_code e; remote_addr_str = socket().remote_endpoint(e).address().to_string(); } catch(...){} ; + _note("Destructing connection #"<<mI->m_peer_number << " to " << remote_addr_str); +try { throw 0; } catch(...){} } void connection_basic::set_rate_up_limit(uint64_t limit) { diff --git a/contrib/epee/src/net_ssl.cpp b/contrib/epee/src/net_ssl.cpp new file mode 100644 index 000000000..941799078 --- /dev/null +++ b/contrib/epee/src/net_ssl.cpp @@ -0,0 +1,319 @@ +// Copyright (c) 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 <string.h> +#include <boost/asio/ssl.hpp> +#include <openssl/ssl.h> +#include <openssl/pem.h> +#include "misc_log_ex.h" +#include "net/net_ssl.h" + +#undef MONERO_DEFAULT_LOG_CATEGORY +#define MONERO_DEFAULT_LOG_CATEGORY "net.ssl" + +// openssl genrsa -out /tmp/KEY 4096 +// openssl req -new -key /tmp/KEY -out /tmp/REQ +// openssl x509 -req -days 999999 -sha256 -in /tmp/REQ -signkey /tmp/KEY -out /tmp/CERT + +namespace +{ + struct openssl_bio_free + { + void operator()(BIO* ptr) const noexcept + { + if (ptr) + BIO_free(ptr); + } + }; + using openssl_bio = std::unique_ptr<BIO, openssl_bio_free>; + + struct openssl_pkey_free + { + void operator()(EVP_PKEY* ptr) const noexcept + { + if (ptr) + EVP_PKEY_free(ptr); + } + }; + using openssl_pkey = std::unique_ptr<EVP_PKEY, openssl_pkey_free>; + +} + +namespace epee +{ +namespace net_utils +{ + +// https://stackoverflow.com/questions/256405/programmatically-create-x509-certificate-using-openssl +bool create_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert) +{ + MGINFO("Generating SSL certificate"); + pkey = EVP_PKEY_new(); + openssl_pkey pkey_deleter{pkey}; + if (!pkey) + { + MERROR("Failed to create new private key"); + return false; + } + RSA *rsa = RSA_generate_key(4096, RSA_F4, NULL, NULL); + if (!rsa) + { + MERROR("Error generating RSA private key"); + return false; + } + if (EVP_PKEY_assign_RSA(pkey, rsa) <= 0) + { + RSA_free(rsa); + MERROR("Error assigning RSA private key"); + return false; + } + + cert = X509_new(); + if (!cert) + { + MERROR("Failed to create new X509 certificate"); + return false; + } + ASN1_INTEGER_set(X509_get_serialNumber(cert), 1); + X509_gmtime_adj(X509_get_notBefore(cert), 0); + X509_gmtime_adj(X509_get_notAfter(cert), 3600 * 24 * 182); // half a year + if (!X509_set_pubkey(cert, pkey)) + { + MERROR("Error setting pubkey on certificate"); + X509_free(cert); + return false; + } + X509_NAME *name = X509_get_subject_name(cert); + X509_set_issuer_name(cert, name); + + if (X509_sign(cert, pkey, EVP_sha256()) == 0) + { + MERROR("Error signing certificate"); + X509_free(cert); + return false; + } + return true; +} + +bool create_ssl_certificate(std::string &pkey_buffer, std::string &cert_buffer) +{ + EVP_PKEY *pkey; + X509 *cert; + if (!create_ssl_certificate(pkey, cert)) + return false; + BIO *bio_pkey = BIO_new(BIO_s_mem()), *bio_cert = BIO_new(BIO_s_mem()); + openssl_bio bio_pkey_deleter{bio_pkey}; + bool success = PEM_write_bio_PrivateKey(bio_pkey, pkey, NULL, NULL, 0, NULL, NULL) && PEM_write_bio_X509(bio_cert, cert); + X509_free(cert); + if (!success) + { + MERROR("Failed to write cert and/or pkey: " << ERR_get_error()); + return false; + } + BUF_MEM *buf = NULL; + BIO_get_mem_ptr(bio_pkey, &buf); + if (!buf || !buf->data || !buf->length) + { + MERROR("Failed to write pkey: " << ERR_get_error()); + return false; + } + pkey_buffer = std::string(buf->data, buf->length); + buf = NULL; + BIO_get_mem_ptr(bio_cert, &buf); + if (!buf || !buf->data || !buf->length) + { + MERROR("Failed to write cert: " << ERR_get_error()); + return false; + } + cert_buffer = std::string(buf->data, buf->length); + return success; +} + +ssl_context_t create_ssl_context(const std::pair<std::string, std::string> &private_key_and_certificate_path, std::list<std::string> allowed_certificates, bool allow_any_cert) +{ + ssl_context_t ssl_context({boost::asio::ssl::context(boost::asio::ssl::context::sslv23), std::move(allowed_certificates)}); + + // disable sslv2 + ssl_context.context.set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2); + ssl_context.context.set_default_verify_paths(); + + // set options on the SSL context for added security + SSL_CTX *ctx = ssl_context.context.native_handle(); + CHECK_AND_ASSERT_THROW_MES(ctx, "Failed to get SSL context"); + SSL_CTX_clear_options(ctx, SSL_OP_LEGACY_SERVER_CONNECT); // SSL_CTX_SET_OPTIONS(3) + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); // https://stackoverflow.com/questions/22378442 +#ifdef SSL_OP_NO_TICKET + SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET); // https://stackoverflow.com/questions/22378442 +#endif +#ifdef SSL_OP_NO_RENEGOTIATION + SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION); +#endif +#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION + SSL_CTX_set_options(ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); +#endif +#ifdef SSL_OP_NO_COMPRESSION + SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION); +#endif + SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1); // https://github.com/ssllabs/research/wiki/SSL-and-TLS-Deployment-Best-Practices + + CHECK_AND_ASSERT_THROW_MES(private_key_and_certificate_path.first.empty() == private_key_and_certificate_path.second.empty(), "private key and certificate must be either both given or both empty"); + if (private_key_and_certificate_path.second.empty()) + { + std::string pkey, cert; + CHECK_AND_ASSERT_THROW_MES(create_ssl_certificate(pkey, cert), "Failed to create certificate"); + ssl_context.context.use_private_key(boost::asio::buffer(pkey), boost::asio::ssl::context::pem); + ssl_context.context.use_certificate(boost::asio::buffer(cert), boost::asio::ssl::context::pem); + } + else + { + ssl_context.context.use_private_key_file(private_key_and_certificate_path.first, boost::asio::ssl::context::pem); + ssl_context.context.use_certificate_file(private_key_and_certificate_path.second, boost::asio::ssl::context::pem); + } + ssl_context.allow_any_cert = allow_any_cert; + + return ssl_context; +} + +void use_ssl_certificate(ssl_context_t &ssl_context, const std::pair<std::string, std::string> &private_key_and_certificate_path) +{ + ssl_context.context.use_private_key_file(private_key_and_certificate_path.first, boost::asio::ssl::context::pem); + ssl_context.context.use_certificate_file(private_key_and_certificate_path.second, boost::asio::ssl::context::pem); +} + +bool is_ssl(const unsigned char *data, size_t len) +{ + if (len < get_ssl_magic_size()) + return false; + + // https://security.stackexchange.com/questions/34780/checking-client-hello-for-https-classification + MDEBUG("SSL detection buffer, " << len << " bytes: " + << (unsigned)(unsigned char)data[0] << " " << (unsigned)(unsigned char)data[1] << " " + << (unsigned)(unsigned char)data[2] << " " << (unsigned)(unsigned char)data[3] << " " + << (unsigned)(unsigned char)data[4] << " " << (unsigned)(unsigned char)data[5] << " " + << (unsigned)(unsigned char)data[6] << " " << (unsigned)(unsigned char)data[7] << " " + << (unsigned)(unsigned char)data[8]); + if (data[0] == 0x16) // record + if (data[1] == 3) // major version + if (data[5] == 1) // ClientHello + if (data[6] == 0 && data[3]*256 + data[4] == data[7]*256 + data[8] + 4) // length check + return true; + return false; +} + +bool is_certificate_allowed(boost::asio::ssl::verify_context &ctx, const std::list<std::string> &allowed_certificates) +{ + X509_STORE_CTX *sctx = ctx.native_handle(); + if (!sctx) + { + MERROR("Error getting verify_context handle"); + return false; + } + X509 *cert =X509_STORE_CTX_get_current_cert(sctx); + if (!cert) + { + MERROR("No certificate found in verify_context"); + return false; + } + + BIO *bio_cert = BIO_new(BIO_s_mem()); + openssl_bio bio_cert_deleter{bio_cert}; + bool success = PEM_write_bio_X509(bio_cert, cert); + if (!success) + { + MERROR("Failed to print certificate"); + return false; + } + BUF_MEM *buf = NULL; + BIO_get_mem_ptr(bio_cert, &buf); + if (!buf || !buf->data || !buf->length) + { + MERROR("Failed to write certificate: " << ERR_get_error()); + return false; + } + std::string certificate(std::string(buf->data, buf->length)); + return std::find(allowed_certificates.begin(), allowed_certificates.end(), certificate) != allowed_certificates.end(); +} + +bool ssl_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socket, boost::asio::ssl::stream_base::handshake_type type, const epee::net_utils::ssl_context_t &ssl_context) +{ + bool verified = false; + socket.next_layer().set_option(boost::asio::ip::tcp::no_delay(true)); + socket.set_verify_mode(boost::asio::ssl::verify_peer); + socket.set_verify_callback([&](bool preverified, boost::asio::ssl::verify_context &ctx) + { + if (!preverified) + { + const int err = X509_STORE_CTX_get_error(ctx.native_handle()); + const int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle()); + if (err != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || depth != 0) + { + MERROR("Invalid SSL certificate, error " << err << " at depth " << depth << ", connection dropped"); + return false; + } + } + if (!ssl_context.allow_any_cert && !ssl_context.allowed_certificates.empty() && !is_certificate_allowed(ctx, ssl_context.allowed_certificates)) + { + MERROR("Certificate is not in the allowed list, connection droppped"); + return false; + } + verified = true; + return true; + }); + + boost::system::error_code ec; + socket.handshake(type, ec); + if (ec) + { + MERROR("handshake failed, connection dropped"); + return false; + } + if (!ssl_context.allow_any_cert && !verified) + { + MERROR("Peer did not provide a certificate in the allowed list, connection dropped"); + return false; + } + MDEBUG("SSL handshake success"); + return true; +} + +bool ssl_support_from_string(ssl_support_t &ssl, boost::string_ref s) +{ + if (s == "enabled") + ssl = epee::net_utils::ssl_support_t::e_ssl_support_enabled; + else if (s == "disabled") + ssl = epee::net_utils::ssl_support_t::e_ssl_support_disabled; + else if (s == "autodetect") + ssl = epee::net_utils::ssl_support_t::e_ssl_support_autodetect; + else + return false; + return true; +} + +} // namespace +} // namespace + diff --git a/contrib/epee/src/network_throttle-detail.cpp b/contrib/epee/src/network_throttle-detail.cpp index d2e776df0..0b42402bd 100644 --- a/contrib/epee/src/network_throttle-detail.cpp +++ b/contrib/epee/src/network_throttle-detail.cpp @@ -135,6 +135,7 @@ network_throttle::network_throttle(const std::string &nameshort, const std::stri m_slot_size = 1.0; // hard coded in few places m_target_speed = 16 * 1024; // other defaults are probably defined in the command-line parsing code when this class is used e.g. as main global throttle m_last_sample_time = 0; + m_history.resize(m_window_size); } void network_throttle::set_name(const std::string &name) @@ -168,8 +169,7 @@ void network_throttle::tick() { _dbg3("Moving counter buffer by 1 second " << last_sample_time_slot << " < " << current_sample_time_slot << " (last time " << m_last_sample_time<<")"); // rotate buffer - for (size_t i=m_history.size()-1; i>=1; --i) m_history[i] = m_history[i-1]; - m_history[0] = packet_info(); + m_history.push_front(packet_info()); if (! m_any_packet_yet) { m_last_sample_time = time_now; @@ -191,7 +191,7 @@ void network_throttle::_handle_trafic_exact(size_t packet_size, size_t orginal_s calculate_times_struct cts ; calculate_times(packet_size, cts , false, -1); calculate_times_struct cts2; calculate_times(packet_size, cts2, false, 5); - m_history[0].m_size += packet_size; + m_history.front().m_size += packet_size; std::ostringstream oss; oss << "["; for (auto sample: m_history) oss << sample.m_size << " "; oss << "]" << std::ends; std::string history_str = oss.str(); diff --git a/contrib/gitian/README.md b/contrib/gitian/README.md index 0b13df344..b869bde87 100644 --- a/contrib/gitian/README.md +++ b/contrib/gitian/README.md @@ -1,7 +1,7 @@ Gitian building ================ -*Setup instructions for a Gitian build of Monero using a VM or physical system.* +*Setup instructions for a Gitian build of Monero.* Gitian is the deterministic build process that is used to build the Monero CLI executables. It provides a way to be reasonably sure that the @@ -13,6 +13,10 @@ Multiple developers build the source code by following a specific descriptor These results are compared and only if they match, the build is accepted and provided for download. +Gitian runs compilation steps in an isolated container. It is flexible and gives you full +control over the build environment, while still ensuring reproducibility and consistent output +formats. + More independent Gitian builders are needed, which is why this guide exists. It is preferred you follow these steps yourself instead of using someone else's VM image to avoid 'contaminating' the build. @@ -22,11 +26,17 @@ Preparing the Gitian builder host The first step is to prepare the host environment that will be used to perform the Gitian builds. This guide explains how to set up the environment, and how to start the builds. +Gitian offers to build with either `kvm`, `docker` or `lxc`. The default build +path chosen is `lxc`, but its setup is more complicated. You need to be logged in as the `gitianuser`. +If this user does not exist yet on your system, create it. Gitian can use +either kvm, lxc or docker as a host environment. This documentation will show +how to build with lxc and docker. While the docker setup is easy, the lxc setup +is more involved. + +LXC +--- -Gitian builds are for now executed on Ubuntu 18.04 "Bionic Beaver". A solution is being worked on to run -it in docker in the future. Please run Ubuntu in either a VM, or on your physical machine. -You need to be logged in as the `gitianuser` in order to build gitian builds. If this user does not exist yet on your system, -create it. +LXC builds should be run on Ubuntu 18.04 "Bionic Beaver". Note that a version of `lxc-execute` higher or equal to 2.1.1 is required. You can check the version with `lxc-execute --version`. @@ -63,15 +73,28 @@ reboot This setup is required to enable networking in the container. +Docker +------ + +Building in docker does not require much setup. Install docker on your host, then type the following: + +```bash +sudo apt-get install git make curl +sudo usermod -aG docker gitianuser +``` + Manual and Building ------------------- -The instructions below use the automated script [gitian-build.py](https://github.com/betcoin/bitcoin/blob/master/contrib/gitian-build.py) which only works in Ubuntu. -It calls all available descriptors. Help for the build steps taken can be accessed with `./gitian-build.py --help`. + +The instructions below use the automated script [gitian-build.py](gitian-build.py) which only works in Ubuntu. +It calls all available .yml descriptors, which in turn pass the build configurations for different platforms to gitian. +Help for the build steps taken can be accessed with `./gitian-build.py --help`. Initial Gitian Setup -------------------- -The `gitian-build.py` script will checkout different release tags, so it's best to copy it: + +The `gitian-build.py` script will checkout different release tags, so it's best to copy it to the top level directory: ```bash cp monero/contrib/gitian/gitian-build.py . @@ -79,11 +102,16 @@ cp monero/contrib/gitian/gitian-build.py . Setup the required environment, you only need to do this once: -``` +```bash ./gitian-build.py --setup fluffypony v0.14.0 ``` -Where `fluffypony` is your Github name and `v0.14.0` is the version tag you want to build. +Where `fluffypony` is your Github name and `v0.14.0` is the version tag you want to build. +If you are using docker, run it with: + +```bash +./gitian-build.py --setup --docker fluffypony v0.14.0 +``` While gitian and this build script does provide a way for you to sign the build directly, it is recommended to sign in a seperate step. This script is only there for convenience. Seperate steps for building can still be taken. @@ -98,9 +126,11 @@ git remote add fluffypony git@github.com:fluffypony/gitian.sigs.git Build Binaries ----------------------------- -To build the most recent tag: +To build the most recent tag (pass in `--docker` after setting up with docker): - `./gitian-build.py --detach-sign --no-commit -b fluffypony v0.14.0` +```bash +./gitian-build.py --detach-sign --no-commit -b fluffypony v0.14.0 +``` To speed up the build, use `-j 5 -m 5000` as the first arguments, where `5` is the number of CPU's you allocated to the VM plus one, and 5000 is a little bit less than then the MB's of RAM you allocated. If there is memory corruption on your machine, try to tweak these values. @@ -108,7 +138,7 @@ If all went well, this produces a number of (uncommited) `.assert` files in the If you do detached, offline signing, you need to copy these uncommited changes to your host machine, where you can sign them. For example: -``` +```bash export NAME=fluffypony export VERSION=v0.14.0 gpg --output $VERSION-linux/$NAME/monero-linux-$VERSION-build.assert.sig --detach-sign $VERSION-linux/$NAME/monero-linux-$VERSION-build.assert @@ -119,7 +149,7 @@ gpg --output $VERSION-win-unsigned/$NAME/monero-win-$VERSION-build.assert.sig -- Make a pull request (both the `.assert` and `.assert.sig` files) to the [monero-project/gitian.sigs](https://github.com/monero-project/gitian.sigs/) repository: -``` +```bash git checkout -b v0.14.0 git commit -S -a -m "Add $NAME v0.14.0" git push --set-upstream $NAME v0.14.0 @@ -131,3 +161,19 @@ git push --set-upstream $NAME v0.14.0 gpg --detach-sign ${VERSION}-osx-unsigned/${SIGNER}/monero-osx-*-build.assert ``` +More Build Options +------------------ + +You can choose your own remote and commit hash by running for example: +```bash +./gitian-build.py --detach-sign --no-commit --url https://github.com/moneromooo-monero/bitmonero -b moneromooo 1f5680c8db8f4cc7acc04a04c724b832003440fd +``` + +Note that you won't be able to build commits authored before the gitian scripts +were added. Gitian clones the source files from the given url, be sure to push +to the remote you provide before building. +To get all build options run: +```bash +./gitian-build.py --help +``` + diff --git a/contrib/gitian/gitian-build.py b/contrib/gitian/gitian-build.py index df1ba0d6b..cd88ecb20 100755 --- a/contrib/gitian/gitian-build.py +++ b/contrib/gitian/gitian-build.py @@ -116,7 +116,7 @@ def main(): parser.add_argument('-D', '--detach-sign', action='store_true', dest='detach_sign', help='Create the assert file for detached signing. Will not commit anything.') parser.add_argument('-n', '--no-commit', action='store_false', dest='commit_files', help='Do not commit anything to git') parser.add_argument('signer', help='GPG signer to sign each build assert file') - parser.add_argument('version', help='Version number, commit, or branch to build. If building a commit or branch, the -c option must be specified') + parser.add_argument('version', help='Version number, commit, or branch to build.') args = parser.parse_args() workdir = os.getcwd() diff --git a/contrib/gitian/gitian-osx.yml b/contrib/gitian/gitian-osx.yml index a6fcff0da..7de302353 100644 --- a/contrib/gitian/gitian-osx.yml +++ b/contrib/gitian/gitian-osx.yml @@ -12,21 +12,17 @@ packages: - "git" - "pkg-config" - "autoconf" -- "librsvg2-bin" -- "libtiff-tools" - "libtool" - "automake" - "faketime" - "bsdmainutils" - "cmake" -- "imagemagick" - "libcap-dev" - "libz-dev" - "libbz2-dev" - "python" - "python-dev" - "python-setuptools" -- "fonts-tuffy" remotes: - "url": "https://github.com/monero-project/monero.git" "dir": "monero" |