Compare commits

...
109 Commits
Author SHA1 Message Date
Adrien Béraud fa19897016 HexMap: align on 64 bits 2021-08-09 18:20:12 -04:00
Adrien Béraud 3806355509 gitignore: add DS_Store 2021-08-09 18:20:12 -04:00
Adrien Béraud 3f6738185b tests: fix testIdOps() 2021-08-05 12:42:29 -04:00
Adrien Béraud e58d09e5da dht: always display value ID as hex 2021-08-05 12:42:29 -04:00
heroku-miraheze 71cd9d22c6 Moved to Libera.chat. 2021-07-19 11:25:59 -04:00
Adrien Béraud 6c58d4f2e9 build: update version to 2.3.0 2021-06-09 16:56:19 -04:00
Adrien Béraud 4070eecea7 gitignore: add tools 2021-06-09 16:56:19 -04:00
Adrien Béraud ffb53ceb1d thread pool: add ExecutionContext 2021-06-09 13:59:33 -04:00
Adrien Béraud 0c00544798 remove embedded argon2, HTTP_PARSER_FORK 2021-06-09 13:57:10 -04:00
Adrien Béraud 471d443e4a tests: add multithread test 2021-06-07 14:45:58 -04:00
Adrien Béraud ba9a445263 securedht: clenup 2021-06-07 14:45:58 -04:00
Adrien Béraud 056bc2850b test putEncrypted(pk) 2021-06-07 14:45:58 -04:00
Adrien Béraud b668d6ad68 dhtrunner: add putEncrypted with public key 2021-06-07 14:45:58 -04:00
Adrien Béraud 29fab5560f dhtrunner: add getPublicKey() 2021-06-07 14:45:58 -04:00
Adrien Béraud 8aef63ce4a crypto: cache public key 2021-06-07 14:45:58 -04:00
Adrien Béraud 1ea7a2994e value: use non-const PublicKey 2021-06-07 14:45:58 -04:00
Adrien Béraud 208b3fa6fe SignedValue: add owner 2021-06-07 14:45:58 -04:00
Adrien Béraud d9ff95da49 Revert "dhtrunner: force execution of pending ops on shutdown"
This reverts commit c8a0b443f3.
2021-06-07 14:45:58 -04:00
Adrien Béraud c8a0b443f3 dhtrunner: force execution of pending ops on shutdown 2021-06-03 16:54:31 -04:00
Adrien Béraud 00e595d737 dht: fail if op key is null 2021-06-03 16:54:31 -04:00
Adrien Béraud a178a8f820 dht, dhtrunner: add shutdown stop argument 2021-05-31 14:43:57 -04:00
Adrien Béraud ec359d50fb proxy tester: increase shutdown timeout 2021-05-31 14:43:57 -04:00
Adrien Béraud 3c5aeccd53 dhtrunner: don't read port config if already configured 2021-05-28 13:17:25 -04:00
Adrien Béraud f99fe16a46 subset: use const ref 2021-05-28 13:17:25 -04:00
Adrien Béraud 43dc7cf222 sockaddr: fix warning 2021-05-28 13:17:25 -04:00
Sébastien Blin ad549098f8 proxyServer: use lockListener_ to protect pushListeners_ 2021-05-25 16:05:03 -04:00
Adrien Béraud 6795ba3838 cmake: fix building with peer discovery and without http 2021-05-20 15:49:11 -04:00
Adrien Béraud efb5f8e36a crypto: avoid generating 0 or negative certificate serial numbers 2021-05-15 01:08:07 -04:00
JUAN MÉNDEZ 8aa24f1289 Add python bindings for TypeValue
Signed-off-by: JUAN MÉNDEZ <vpsink@gmail.com>
2021-05-10 14:54:16 -04:00
Sébastien Blin 14d882d220 http: add support for TCP keep alive and handle broken pipes 2021-05-03 10:09:31 -04:00
Adrien Béraud f4c6c54a08 unit tests: add test for identityAnnouncedCb, putEncrypted 2021-04-16 16:11:02 -04:00
Adrien Béraud 4dc7a5ca0a dhtrunner: log warning if calling run() while already running 2021-04-16 15:54:45 -04:00
Adrien Béraud 40fdd04cb3 dht: cleanup handling of onConnectCallback 2021-04-16 15:13:07 -04:00
Adrien Béraud a24dedd225 proxy client: move callbacks to lambda 2021-04-16 15:04:19 -04:00
Adrien Béraud ae2445fd07 proxy client: schedule connectCallbacks in callback queue 2021-04-16 15:01:23 -04:00
Adrien Béraud 7ba53cb4b3 proxy client: use unique_ptr for timers 2021-04-16 15:00:48 -04:00
Adrien Béraud fbff8389c5 dhtrunner: build proxy with identity callback, logger 2021-04-16 14:45:33 -04:00
Adrien Béraud 827fdacc4b securedht: build with logger 2021-04-16 14:45:14 -04:00
Adrien Béraud 3efc27e9f3 securedht: avoid use-after-free 2021-04-16 14:42:45 -04:00
Adrien Béraud f7104199e3 securedht: fix typo 2021-04-15 12:50:31 -04:00
Adrien Béraud 5c0fbf7e68 securedht: pass IdentityAnnouncedCb by value, don't store 2021-04-15 12:47:18 -04:00
Adrien Béraud 55c595330a securedht: use onConnect callback 2021-04-15 12:36:57 -04:00
Adrien Béraud d3fc75589f dht: add onConnect callback 2021-04-15 12:36:03 -04:00
Sébastien Blin f8605f45f7 securedht: add IdentityAnnouncedCb to detect when identity is announced 2021-04-14 18:55:22 -04:00
Adrien Béraud d541b17fe1 sockaddr: cleanup 2021-04-13 21:35:31 -04:00
Adrien Béraud 29eb1d97f8 tests: add unit test for Dhtrunner::run(config, context) 2021-04-13 21:35:31 -04:00
Adrien Béraud 623b1c4585 dhtrunner: add async version of getPublicAddress 2021-04-13 21:35:31 -04:00
Adrien Béraud 74f7d7811e dhtrunner: use default bound address if not set 2021-04-13 21:35:31 -04:00
Adrien Béraud 7774331a20 dhtrunner: allow to provide address to bind in configuration 2021-04-13 21:35:31 -04:00
Sébastien Blin aae30c5891 docker: update restinio version 2021-04-12 11:55:45 -04:00
Adrien Béraud 41760e4b65 ocsp response: improve exception message 2021-03-25 00:02:51 -04:00
Adrien Béraud 9ca0de250b tests: add testOcsp 2021-03-24 23:29:53 -04:00
Adrien Béraud d0156b4637 crypto: add OcspRequest 2021-03-24 23:29:18 -04:00
Adrien Béraud f6cca88593 ocsp response: verifyDirect now returns revocation status 2021-03-24 23:11:59 -04:00
Adrien Béraud c6da80573e ocsp: fix leak 2021-03-24 23:09:24 -04:00
Adrien Béraud 5527869d13 Revert "dht: don't send unnecessary findNode"
This reverts commit 0b4caeda73.
2021-03-22 13:55:04 -04:00
Adrien Béraud 5c599b2feb ocsp: check the appropriate field for status 2021-03-22 13:54:39 -04:00
Adrien Béraud 122d814a33 TrustRequest: add default empty parameter for conversationId 2021-03-18 17:08:54 -04:00
Adrien Béraud a1a8adbe4b update to version 2.2.0 2021-03-18 10:39:59 -04:00
Adrien Béraud 5a370cabb5 crypto: disable legacy encryption
Require OpenDHT 2.x to decrypt encrypted data
2021-03-18 10:37:28 -04:00
Adrien Béraud 639ae26ac1 PEMCache: cleanup 2021-03-18 10:35:35 -04:00
Adrien Béraud 896b6de60c dht: remove default constructor 2021-03-18 10:35:35 -04:00
Adrien Béraud d025f9d1b5 crypto: add methods to sign/decrypt raw data 2021-03-18 10:35:35 -04:00
Sébastien Blin 0b029bc0bf types: add conversationId to TrustRequest 2021-03-18 09:13:43 -04:00
Adrien Béraud 2256434ec7 dht: add inspection methods 2021-03-09 17:43:57 -05:00
Adrien Béraud 0b4caeda73 dht: don't send unnecessary findNode 2021-03-09 17:43:35 -05:00
Adrien Béraud 18a1a1c47f callbacks: move function argument to lambda 2021-03-09 17:43:35 -05:00
Sébastien Blin 6702956521 infohash: add xor operator 2021-03-09 17:27:04 -05:00
Lucas Dias c996220685 network_engine::process could throw an exception in message type MessageType::ValueUpdate if rsocket does not exist. processMessage called process out of try-catch 2021-01-19 12:55:02 -05:00
Adrien Béraud df85abfabe cmake: use THREADS_PREFER_PTHREAD_FLAG 2020-12-30 10:32:27 -05:00
Bruno Pagani e6c760ec6b Fix use of OPENDHT_SYSTEMD_UNIT_FILE_LOCATION
For some reason 1778f64048 reverted part of 4d70c214b0

This commit fixes that.
2020-12-22 18:03:31 -05:00
Adrien Béraud a77dc855f0 OCSP: use RFC-mandated parameters
* use 32 bytes nounce
* use SHA-1 for the certificate ID
2020-12-17 12:35:33 -05:00
Adrien Béraud 2524e167d9 tests: add test for toHex 2020-12-08 14:39:25 -05:00
Adrien Béraud 638d1c91f1 toHex: use proper std::string constructor 2020-12-08 14:34:33 -05:00
Amin Bandali ba4058dfd9 cmake: fix atomic check, hopefully 2020-12-04 16:55:03 -05:00
Adrien Béraud ab90a170af http: checkOcsp is void 2020-11-24 16:16:11 -05:00
Adrien Béraud f780499241 ocsp response: add string constructor 2020-11-24 16:11:02 -05:00
Adrien Béraud 91709bc999 proxytester: disable https for now 2020-11-24 15:59:42 -05:00
Adrien Béraud 72725dc5c1 http: make OCSP check optional 2020-11-24 15:34:19 -05:00
Adrien Béraud 3098439db2 proxy client: set CA for every request 2020-11-24 15:22:14 -05:00
Adrien Béraud 6441a09e09 ocsp: fix memleaks 2020-11-20 14:42:55 -05:00
Adrien Béraud 57e7699723 update to version 2.1.9 2020-11-20 11:39:01 -05:00
Adrien Béraud 17e1cfbbbe crypto: export OCSP request as string 2020-11-20 11:38:11 -05:00
Adrien Béraud bfe1311ca8 crypto: cleanup OCSP result check 2020-11-19 17:12:54 -05:00
Adrien Béraud 537a1650f2 infohash: add toHex(const std::string&) 2020-11-19 17:07:06 -05:00
Kateryna Kostiuk 8c852c20e7 os_cert: do not load for iOS 2020-11-18 15:47:10 -05:00
Adrien Béraud 1da46382d3 cmake: add missing include in CheckAtomic 2020-11-17 16:30:36 -05:00
Adrien Béraud 4953888af3 update to version 2.1.8 2020-11-17 16:24:30 -05:00
Adrien Béraud 22de868c6c cmake: check for 64 bits atomic support 2020-11-17 16:23:43 -05:00
Adrien Béraud 0998707e03 automake: add os_cert 2020-11-17 15:48:13 -05:00
Adrien Béraud b5fcd49b7b os_cert: only build with http 2020-11-17 15:20:46 -05:00
Adrien Béraud 81cdd9650b os_cert: cleanup 2020-11-17 14:37:03 -05:00
Adrien Béraud e028cea687 os_cert: only define timegm on Windows 2020-11-17 13:15:22 -05:00
Adrien Béraud 17ed4a9e26 os_cert: include crypto/x509 from OpenSSL 3.0 2020-11-17 12:27:41 -05:00
Adrien Béraud 3ff318b9e4 os_cert: cleanup detection of ASN1_time_parse 2020-11-17 11:35:07 -05:00
Adrien Béraud 0c11c25c66 infohash: make toHex inline 2020-11-17 11:34:40 -05:00
Adrien Béraud 0d31139402 crypto: throw in case of certificate generation error 2020-11-16 17:35:00 -05:00
Adrien Béraud e970cac4d7 infohash: expose toHex 2020-11-16 14:58:35 -05:00
Adrien Béraud 7c8eecd745 update to version 2.1.7 2020-11-15 17:25:12 -05:00
Adrien Béraud 4d87c2267b os_cert: build ASN1_time_parse if not libressl 2020-11-15 00:42:29 -05:00
Adrien Béraud 88b2439deb http: use string for body, fix log arguments 2020-11-14 18:07:05 -05:00
Federico Ceratto 766a06c69a Remove line 2020-11-13 09:33:11 -05:00
Federico Ceratto aa502553bb Put @bindir@ back 2020-11-13 09:33:11 -05:00
Federico Ceratto 05ff4205d2 Configure dhtnode service sandboxing
Tested on Debian Sid
2020-11-13 09:33:11 -05:00
Adrien Béraud 9d937bb277 http: factor setting CA source 2020-11-12 19:00:02 -05:00
Andreas Traczyk 1621515b3c http: use local cache to store pre-decoded certs
- pre-decode certs from DER->PEM and store them so http connections
  can add them the ssl context x509 store
- fixes the windows build by adding the crypto/x509 header
2020-11-12 18:58:18 -05:00
Adrien Béraud 30261e70ad cache: cleanup, small perf improvements 2020-11-12 12:53:57 -05:00
Adrien Béraud c2a4f667a7 http: look for CA path in env 2020-11-12 12:53:03 -05:00
Adrien Béraud 05b95331d8 cmake: add CheckAtomic 2020-11-04 16:24:52 -05:00
58 changed files with 1421 additions and 716 deletions

No files matched your search

+4
View File
@@ -19,6 +19,9 @@
*.exe
*.out
*.app
**/dhtnode
**/dhtchat
**/dhtscanner
# Autotools
/ac
@@ -73,3 +76,4 @@ doc/Doxyfile
# build dir
build
.DS_Store
-4
View File
@@ -1,4 +0,0 @@
[submodule "argon2"]
path = argon2
url = https://github.com/P-H-C/phc-winner-argon2
ignore = dirty
+21 -58
View File
@@ -1,11 +1,13 @@
cmake_minimum_required (VERSION 3.1)
project (opendht)
include(CMakePackageConfigHelpers)
include(CMakeDependentOption)
include(FindPkgConfig)
include(cmake/CheckAtomic.cmake)
project (opendht)
set (opendht_VERSION_MAJOR 2)
set (opendht_VERSION_MINOR 1.6)
set (opendht_VERSION_MINOR 3.0)
set (opendht_VERSION ${opendht_VERSION_MAJOR}.${opendht_VERSION_MINOR})
set (PACKAGE_VERSION ${opendht_VERSION})
set (VERSION "${opendht_VERSION}")
@@ -18,7 +20,6 @@ option (OPENDHT_PYTHON "Build Python bindings" OFF)
option (OPENDHT_TOOLS "Build DHT tools" ON)
option (OPENDHT_SYSTEMD "Install systemd module" OFF)
option (OPENDHT_SYSTEMD_UNIT_FILE_LOCATION "Where to install systemd unit file")
option (OPENDHT_ARGON2 "Use included argon2 sources" OFF)
option (OPENDHT_LTO "Build with LTO" OFF)
option (OPENDHT_SANITIZE "Build with address sanitizer and stack protector" OFF)
option (OPENDHT_PROXY_SERVER "Enable DHT proxy server, use Restinio and jsoncpp" OFF)
@@ -26,7 +27,6 @@ option (OPENDHT_PUSH_NOTIFICATIONS "Enable push notifications support" OFF)
option (OPENDHT_PROXY_SERVER_IDENTITY "Allow clients to use the node identity" OFF)
option (OPENDHT_PROXY_CLIENT "Enable DHT proxy client, use Restinio and jsoncpp" OFF)
option (OPENDHT_PROXY_OPENSSL "Build DHT proxy with OpenSSL" ON)
option (OPENDHT_PROXY_HTTP_PARSER_FORK "Build DHT proxy with custom http_parser to support old API" OFF)
CMAKE_DEPENDENT_OPTION(OPENDHT_HTTP "Build embedded http(s) client" OFF "NOT OPENDHT_PROXY_SERVER;NOT OPENDHT_PROXY_CLIENT" ON)
option (OPENDHT_PEER_DISCOVERY "Enable multicast peer discovery" ON)
option (OPENDHT_INDEX "Build DHT indexation feature" OFF)
@@ -40,25 +40,16 @@ option (OPENDHT_DOCUMENTATION "Create and install the HTML based API documentati
# Dependencies
list (APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
if (NOT MSVC)
set (THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package (Threads)
find_package (PkgConfig REQUIRED)
find_package (GnuTLS 3.3 REQUIRED)
pkg_search_module (Nettle nettle)
pkg_search_module (Nettle REQUIRED nettle)
find_package (Msgpack 1.2 REQUIRED)
if (OPENDHT_TOOLS)
find_package (Readline 6 REQUIRED)
endif ()
if (NOT OPENDHT_ARGON2)
pkg_search_module(argon2 libargon2)
if (argon2_FOUND)
message("-- Found Argon2: " ${argon2_LIBRARY_DIRS} " (found version \"" ${argon2_VERSION} "\")")
link_directories (${argon2_LIBRARY_DIRS})
else ()
message("Argon2 not found, using included version.")
set(OPENDHT_ARGON2 ON)
endif()
endif ()
pkg_search_module(argon2 REQUIRED libargon2)
pkg_search_module(Jsoncpp jsoncpp)
if (Jsoncpp_FOUND)
add_definitions(-DOPENDHT_JSONCPP)
@@ -68,8 +59,11 @@ if (NOT MSVC)
)
endif()
if (OPENDHT_HTTP)
if (OPENDHT_HTTP OR OPENDHT_PEER_DISCOVERY)
find_path(ASIO_INCLUDE_DIR asio.hpp REQUIRED)
endif ()
if (OPENDHT_HTTP)
find_package(Restinio REQUIRED)
find_library(FMT_LIBRARY fmt)
add_library(fmt SHARED IMPORTED)
@@ -82,16 +76,13 @@ if (NOT MSVC)
# https://cmake.org/cmake/help/latest/module/FindOpenSSL.html
pkg_search_module(OPENSSL REQUIRED openssl)
if (OPENSSL_FOUND)
message(STATUS "Found OpenSSL ${OPENSSL_VERSION}")
include_directories(${OPENSSL_INCLUDE_DIRS})
message(STATUS "Found OpenSSL ${OPENSSL_VERSION} ${OPENSSL_INCLUDE_DIRS}")
include_directories(SYSTEM ${OPENSSL_INCLUDE_DIRS})
link_directories (${OPENSSL_LIBRARY_DIRS})
else ()
message(SEND_ERROR "OpenSSL is required for DHT proxy as specified")
endif()
endif()
if (OPENDHT_PROXY_HTTP_PARSER_FORK)
add_definitions(-DOPENDHT_PROXY_HTTP_PARSER_FORK)
endif()
else ()
set(OPENDHT_PROXY_OPENSSL OFF)
endif ()
@@ -181,6 +172,7 @@ if (Jsoncpp_INCLUDE_DIRS)
endif ()
link_directories (${Nettle_LIBRARY_DIRS})
link_directories (${Jsoncpp_LIBRARY_DIRS})
link_directories (${argon2_LIBRARY_DIRS})
include_directories (
./
include/
@@ -300,36 +292,16 @@ if (OPENDHT_HTTP)
list (APPEND opendht_HEADERS
include/opendht/proxy.h
include/opendht/http.h
src/compat/os_cert.h
)
list (APPEND opendht_SOURCES
src/http.cpp
src/compat/os_cert.cpp
)
endif ()
if(OPENDHT_ARGON2)
# make sure argon2 submodule is up to date and initialized
message("Initializing Argon2 submodule")
execute_process(COMMAND git submodule update --init)
# add local argon2 files to build
list (APPEND opendht_SOURCES
argon2/src/argon2.c
argon2/src/core.c
argon2/src/blake2/blake2b.c
argon2/src/thread.c
argon2/src/ref.c
argon2/src/encoding.c
)
include_directories(argon2/include/)
endif()
# cross-platform compatibility sources
set (COMPAT_DIR ${PROJECT_SOURCE_DIR}/src/compat/)
list (APPEND opendht_SOURCES ${COMPAT_DIR}/os_cert.cpp)
if (MSVC)
set (MSC_COMPAT_DIR ${COMPAT_DIR}/msvc/)
list (APPEND opendht_SOURCES ${MSC_COMPAT_DIR}/unistd.h)
list (APPEND opendht_HEADERS src/compat/msvc/unistd.h)
endif ()
# Targets
@@ -340,11 +312,7 @@ if (OPENDHT_STATIC)
${opendht_HEADERS}
)
set_target_properties (opendht-static PROPERTIES OUTPUT_NAME "opendht")
if (OPENDHT_ARGON2)
target_include_directories(opendht-static SYSTEM PRIVATE argon2)
else ()
target_include_directories(opendht-static SYSTEM PRIVATE ${argon2_INCLUDE_DIRS})
endif ()
target_include_directories(opendht-static SYSTEM PRIVATE ${argon2_INCLUDE_DIRS})
target_link_libraries(opendht-static
PRIVATE ${argon2_LIBRARIES}
PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${GNUTLS_LIBRARIES} ${Nettle_STATIC_LIBRARIES}
@@ -409,25 +377,20 @@ if (OPENDHT_SHARED)
set_target_properties (opendht PROPERTIES IMPORT_SUFFIX "_import.lib")
set_target_properties (opendht PROPERTIES SOVERSION ${opendht_VERSION_MAJOR} VERSION ${opendht_VERSION})
target_compile_definitions(opendht PRIVATE OPENDHT_BUILD)
if (OPENDHT_ARGON2)
target_include_directories(opendht SYSTEM PRIVATE argon2)
else ()
target_link_libraries(opendht PRIVATE ${argon2_LIBRARIES})
target_include_directories(opendht SYSTEM PRIVATE ${argon2_INCLUDE_DIRS})
endif ()
target_include_directories(opendht SYSTEM PRIVATE ${argon2_INCLUDE_DIRS})
if (APPLE)
target_link_libraries(opendht
PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES}
PRIVATE ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES}
${Jsoncpp_LIBRARIES}
${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY}
${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY} ${argon2_LIBRARIES}
SYSTEM "-framework CoreFoundation" "-framework Security")
else ()
target_link_libraries(opendht
PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES}
PRIVATE ${GNUTLS_LIBRARIES} ${Nettle_LIBRARIES}
${Jsoncpp_LIBRARIES}
${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY})
${FMT_LIBRARY} ${HTTP_PARSER_LIBRARY} ${argon2_LIBRARIES})
endif ()
install (TARGETS opendht DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT opendht)
+1 -1
View File
@@ -103,7 +103,7 @@ for r in results:
## Contact
IRC: join us on Freenode at [`#opendht`](https://webchat.freenode.net/?channels=%23opendht).
IRC: join us on Libera.chat at [`#opendht`](https://web.libera.chat/#opendht).
## License
Copyright (C) 2014-2020 Savoir-faire Linux Inc.
Submodule argon2 deleted from 62358ba212.
-1
View File
@@ -1,2 +1 @@
git submodule update --init
autoreconf --install --verbose -Wall
+95
View File
@@ -0,0 +1,95 @@
# University of Illinois/NCSA
# Open Source License
#
# Copyright (c) 2003-2017 University of Illinois at Urbana-Champaign.
# All rights reserved.
#
# Developed by:
#
# LLVM Team
#
# University of Illinois at Urbana-Champaign
#
# http://llvm.org
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal with
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimers.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimers in the
# documentation and/or other materials provided with the distribution.
#
# * Neither the names of the LLVM Team, University of Illinois at
# Urbana-Champaign, nor the names of its contributors may be used to
# endorse or promote products derived from this Software without specific
# prior written permission.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
# SOFTWARE.
include(CheckCXXSourceCompiles)
include(CheckLibraryExists)
# Sometimes linking against libatomic is required for atomic ops, if
# the platform doesn't support lock-free atomics.
function(check_working_cxx_atomics varname)
set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
get_directory_property(compile_options COMPILE_OPTIONS)
set(CMAKE_REQUIRED_FLAGS ${compile_options})
CHECK_CXX_SOURCE_COMPILES("
#include <atomic>
#include <cstdint>
std::atomic<int64_t> v1;
std::atomic<int64_t> v2;
int main(int, char**) {
return v1 + v2;
}" ${varname})
set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS})
endfunction(check_working_cxx_atomics)
if(NOT DEFINED PROXYGEN_COMPILER_IS_GCC_COMPATIBLE)
if(CMAKE_COMPILER_IS_GNUCXX)
set(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE ON)
elseif(MSVC)
set(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE OFF)
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE ON)
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Intel")
set(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE ON)
endif()
endif()
# This isn't necessary on MSVC, so avoid command-line switch annoyance
# by only running on GCC-like hosts.
if(PROXYGEN_COMPILER_IS_GCC_COMPATIBLE)
# First check if atomics work without the library.
check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITHOUT_LIB)
# If not, check if the library exists, and atomics work with it.
if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB)
check_library_exists(atomic __atomic_fetch_add_4 "" HAVE_LIBATOMIC)
if(HAVE_LIBATOMIC)
list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB)
if (NOT HAVE_CXX_ATOMICS_WITH_LIB)
message(FATAL_ERROR "Host compiler must support std::atomic!")
endif()
list(APPEND CMAKE_CXX_STANDARD_LIBRARIES -latomic)
else()
message(FATAL_ERROR "Host compiler appears to require libatomic, but cannot find it.")
endif()
endif()
endif()
+4 -31
View File
@@ -1,7 +1,7 @@
dnl define macros
m4_define([opendht_major_version], 2)
m4_define([opendht_minor_version], 1)
m4_define([opendht_patch_version], 6)
m4_define([opendht_minor_version], 3)
m4_define([opendht_patch_version], 0)
m4_define([opendht_version],
[opendht_major_version.opendht_minor_version.opendht_patch_version])
@@ -132,6 +132,8 @@ AM_CONDITIONAL(PROXY_CLIENT_OR_SERVER, test x$proxy_client == xyes || test x$pro
PKG_CHECK_MODULES([Nettle], [nettle >= 2.4])
PKG_CHECK_MODULES([GnuTLS], [gnutls >= 3.3])
PKG_CHECK_MODULES([MsgPack], [msgpack >= 1.2])
PKG_CHECK_MODULES([Argon2], [libargon2])
AC_SUBST(argon2_lib, [", libargon2"])
AC_ARG_WITH([jsoncpp], AS_HELP_STRING([--without-jsoncpp], [Build without JsonCpp support]))
AS_IF([test "x$with_jsoncpp" != "xno"],
@@ -157,14 +159,6 @@ AS_IF([test "x$have_openssl" = "xyes"], [
AC_MSG_NOTICE([Not using OpenSSL])
])
AC_ARG_WITH([http_parser_fork], AS_HELP_STRING([--with-http-parser-fork], [Build with http_parser fork to support old API]))
AS_IF([test "x$with_http_parser_fork" = "xyes"],[
AC_MSG_NOTICE([Using http_parser fork])
AC_DEFINE([OPENDHT_PROXY_HTTP_PARSER_FORK], [], [Define if using http parser fork])
], [
AC_MSG_NOTICE([Not using http_parser fork])
])
AM_COND_IF([PROXY_CLIENT_OR_SERVER], [
AC_CHECK_HEADERS([asio.hpp], exit,, AC_MSG_ERROR([Missing Asio headers files]))
CXXFLAGS="${CXXFLAGS} -DASIO_STANDALONE"
@@ -183,27 +177,6 @@ AM_COND_IF([PROXY_CLIENT_OR_SERVER], [
CXXFLAGS="${CXXFLAGS} -DMSGPACK_DISABLE_LEGACY_NIL -DMSGPACK_DISABLE_LEGACY_CONVERT"
dnl Check for Argon2
AC_ARG_WITH([argon2], AS_HELP_STRING([--without-argon2], [Use included Argon2]))
AS_IF([test "x$with_argon2" != "xno"],
[PKG_CHECK_MODULES([Argon2], [libargon2], [have_argon2=yes], [have_argon2=no])],
[have_argon2=no])
AS_IF([test "x$have_argon2" = "xyes"], [
AC_MSG_NOTICE([Using system Argon2])
AC_SUBST(argon2_lib, [", libargon2"])
], [
AS_IF([test "x$with_argon2" = "xyes"], [
AC_MSG_ERROR([Argon2 requested but not found])
],[
AC_MSG_NOTICE([Using included Argon2])
AC_SUBST(Argon2_CFLAGS, "-I\${top_srcdir}/argon2/src -I\${top_srcdir}/argon2/include")
AC_SUBST(Argon2_LIBS, "libargon2.la")
AC_SUBST(Argon2_LDFLAGS, "-L\${abs_top_srcdir}/argon2/src/.libs")
])
])
AM_CONDITIONAL([WITH_INCLUDED_ARGON2], [test "x$have_argon2" = "xno"])
AC_ARG_ENABLE([tools], AS_HELP_STRING([--disable-tools],[Disable tools (CLI DHT node)]),,build_tools=yes)
AM_CONDITIONAL(ENABLE_TOOLS, test x$build_tools == xyes)
AM_COND_IF([ENABLE_TOOLS], [
+3 -3
View File
@@ -17,9 +17,9 @@ RUN apt-get update && apt-get install -y \
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/2c0b6f5e5ba04d7a74e8406a3df1fd433680599d.tar.gz \
&& ls -l && tar -xzf 2c0b6f5e5ba04d7a74e8406a3df1fd433680599d.tar.gz \
&& cd restinio-2c0b6f5e5ba04d7a74e8406a3df1fd433680599d/dev \
&& wget https://github.com/aberaud/restinio/archive/2224ffedef52cb2b74645d63d871d61dbd0f165e.tar.gz \
&& ls -l && tar -xzf 2224ffedef52cb2b74645d63d871d61dbd0f165e.tar.gz \
&& cd restinio-2224ffedef52cb2b74645d63d871d61dbd0f165e/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
+3 -3
View File
@@ -18,9 +18,9 @@ ENV CXX c++
RUN echo "*** Downloading RESTinio ***" \
&& mkdir restinio && cd restinio \
&& wget https://github.com/aberaud/restinio/archive/2c0b6f5e5ba04d7a74e8406a3df1fd433680599d.tar.gz \
&& ls -l && tar -xzf 2c0b6f5e5ba04d7a74e8406a3df1fd433680599d.tar.gz \
&& cd restinio-2c0b6f5e5ba04d7a74e8406a3df1fd433680599d/dev \
&& wget https://github.com/aberaud/restinio/archive/2224ffedef52cb2b74645d63d871d61dbd0f165e.tar.gz \
&& ls -l && tar -xzf 2224ffedef52cb2b74645d63d871d61dbd0f165e.tar.gz \
&& cd restinio-2224ffedef52cb2b74645d63d871d61dbd0f165e/dev \
&& cmake -DCMAKE_INSTALL_PREFIX=/usr -DRESTINIO_TEST=OFF -DRESTINIO_SAMPLE=OFF \
-DRESTINIO_INSTALL_SAMPLES=OFF -DRESTINIO_BENCH=OFF -DRESTINIO_INSTALL_BENCHES=OFF \
-DRESTINIO_FIND_DEPS=ON -DRESTINIO_ALLOW_SOBJECTIZER=Off -DRESTINIO_USE_BOOST_ASIO=none . \
+10 -9
View File
@@ -132,7 +132,7 @@ struct OPENDHT_PUBLIC Config {
/* If non-0, overrides the default maximum store size. -1 means no limit. */
ssize_t max_store_size {0};
/**
/**
* Use appropriate bahavior for a public IP, stable node:
* - No connectivity change triggered when a search fails
* - Larger listen refresh time
@@ -148,7 +148,7 @@ struct OPENDHT_PUBLIC SecureDhtConfig
Config node_config {};
crypto::Identity id {};
/**
/**
* Cache all encountered public keys and certificates,
* for use by the certificate store, putEncrypted and putSigned
*/
@@ -164,6 +164,7 @@ using GetCallback = std::function<bool(const std::vector<std::shared_ptr<Value>>
using ValueCallback = std::function<bool(const std::vector<std::shared_ptr<Value>>& values, bool expired)>;
using GetCallbackSimple = std::function<bool(std::shared_ptr<Value> value)>;
using ShutdownCallback = std::function<void()>;
using IdentityAnnouncedCb = std::function<void(bool)>;
using CertificateStoreQuery = std::function<std::vector<std::shared_ptr<crypto::Certificate>>(const InfoHash& pk_id)>;
@@ -178,13 +179,13 @@ typedef bool (*FilterRaw)(const Value&, void *user_data);
using DoneCallbackSimple = std::function<void(bool success)>;
OPENDHT_PUBLIC GetCallbackSimple bindGetCb(const GetCallbackRaw& raw_cb, void* user_data);
OPENDHT_PUBLIC GetCallback bindGetCb(const GetCallbackSimple& cb);
OPENDHT_PUBLIC ValueCallback bindValueCb(const ValueCallbackRaw& raw_cb, void* user_data);
OPENDHT_PUBLIC ShutdownCallback bindShutdownCb(const ShutdownCallbackRaw& shutdown_cb_raw, void* user_data);
OPENDHT_PUBLIC GetCallbackSimple bindGetCb(GetCallbackRaw raw_cb, void* user_data);
OPENDHT_PUBLIC GetCallback bindGetCb(GetCallbackSimple cb);
OPENDHT_PUBLIC ValueCallback bindValueCb(ValueCallbackRaw raw_cb, void* user_data);
OPENDHT_PUBLIC ShutdownCallback bindShutdownCb(ShutdownCallbackRaw shutdown_cb_raw, void* user_data);
OPENDHT_PUBLIC DoneCallback bindDoneCb(DoneCallbackSimple donecb);
OPENDHT_PUBLIC DoneCallback bindDoneCb(const DoneCallbackRaw& raw_cb, void* user_data);
OPENDHT_PUBLIC DoneCallbackSimple bindDoneCbSimple(const DoneCallbackSimpleRaw& raw_cb, void* user_data);
OPENDHT_PUBLIC Value::Filter bindFilterRaw(const FilterRaw& raw_filter, void* user_data);
OPENDHT_PUBLIC DoneCallback bindDoneCb(DoneCallbackRaw raw_cb, void* user_data);
OPENDHT_PUBLIC DoneCallbackSimple bindDoneCbSimple(DoneCallbackSimpleRaw raw_cb, void* user_data);
OPENDHT_PUBLIC Value::Filter bindFilterRaw(FilterRaw raw_filter, void* user_data);
}
+39 -12
View File
@@ -80,6 +80,8 @@ struct OPENDHT_PUBLIC PublicKey
* Takes ownership of an existing gnutls_pubkey.
*/
PublicKey(gnutls_pubkey_t k) : pk(k) {}
/** Import public key from serialized data */
PublicKey(const uint8_t* dat, size_t dat_size);
PublicKey(const Blob& pk) : PublicKey(pk.data(), pk.size()) {}
PublicKey(PublicKey&& o) noexcept : pk(o.pk) { o.pk = nullptr; };
@@ -106,12 +108,12 @@ struct OPENDHT_PUBLIC PublicKey
PkId getLongId() const;
bool checkSignature(const uint8_t* data, size_t data_len, const uint8_t* signature, size_t signature_len) const;
bool checkSignature(const Blob& data, const Blob& signature) const {
inline bool checkSignature(const Blob& data, const Blob& signature) const {
return checkSignature(data.data(), data.size(), signature.data(), signature.size());
}
Blob encrypt(const uint8_t* data, size_t data_len) const;
Blob encrypt(const Blob& data) const {
inline Blob encrypt(const Blob& data) const {
return encrypt(data.data(), data.size());
}
@@ -162,7 +164,9 @@ struct OPENDHT_PUBLIC PrivateKey
~PrivateKey();
explicit operator bool() const { return key; }
PublicKey getPublicKey() const;
const PublicKey& getPublicKey() const;
const std::shared_ptr<PublicKey>& getSharedPublicKey() const;
int serialize(uint8_t* out, size_t* out_len, const std::string& password = {}) const;
Blob serialize(const std::string& password = {}) const;
@@ -170,14 +174,16 @@ struct OPENDHT_PUBLIC PrivateKey
* Sign the provided binary object.
* @returns the signature data.
*/
Blob sign(const Blob&) const;
Blob sign(const uint8_t* data, size_t data_len) const;
inline Blob sign(const Blob& dat) const { return sign(dat.data(), dat.size()); }
/**
* Try to decrypt the provided cypher text.
* In case of failure a CryptoException is thrown.
* @returns the decrypted data.
*/
Blob decrypt(const Blob& cypher) const;
Blob decrypt(const uint8_t* cypher, size_t cypher_len) const;
Blob decrypt(const Blob& cypher) const { return decrypt(cypher.data(), cypher.size()); }
/**
* Generate a new RSA key pair
@@ -195,7 +201,7 @@ private:
PrivateKey& operator=(const PrivateKey&) = delete;
Blob decryptBloc(const uint8_t* src, size_t src_size) const;
//friend dht::crypto::Identity dht::crypto::generateIdentity(const std::string&, dht::crypto::Identity, unsigned key_length);
mutable std::shared_ptr<PublicKey> publicKey_ {};
};
class OPENDHT_PUBLIC RevocationList
@@ -310,10 +316,29 @@ private:
gnutls_x509_crq_t request {nullptr};
};
class OPENDHT_PUBLIC OcspRequest
{
public:
OcspRequest(gnutls_ocsp_req_t r) : request(r) {};
OcspRequest(const uint8_t* dat_ptr, size_t dat_size);
~OcspRequest();
/*
* Get OCSP Request in readable format.
*/
std::string toString(const bool compact = true) const;
Blob pack() const;
Blob getNonce() const;
private:
gnutls_ocsp_req_t request;
};
class OPENDHT_PUBLIC OcspResponse
{
public:
OcspResponse(const uint8_t* dat_ptr, size_t dat_size);
OcspResponse(const std::string& response) : OcspResponse((const uint8_t*)response.data(), response.size()) {};
~OcspResponse();
Blob pack() const;
@@ -330,11 +355,11 @@ public:
gnutls_ocsp_cert_status_t getCertificateStatus() const;
/*
* Verify OCSP response.
* Return OCSP verify reason.
* Verify OCSP response and return OCSP status.
* Throws CryptoException in case of error in the response.
* http://www.gnu.org/software/gnutls/reference/gnutls-ocsp.html#gnutls-ocsp-verify-reason-t
*/
gnutls_ocsp_verify_reason_t verifyDirect(const Certificate& crt, const Blob& nonce);
gnutls_ocsp_cert_status_t verifyDirect(const Certificate& crt, const Blob& nonce);
private:
gnutls_ocsp_resp_t response;
@@ -565,7 +590,7 @@ struct OPENDHT_PUBLIC Certificate {
* Return GnuTLS error code.
* https://www.gnutls.org/manual/html_node/Error-codes.html
*/
std::pair<Blob,Blob> generateOcspRequest(gnutls_x509_crt_t& issuer);
std::pair<std::string, Blob> generateOcspRequest(gnutls_x509_crt_t& issuer);
gnutls_x509_crt_t cert {nullptr};
std::shared_ptr<Certificate> issuer {};
@@ -748,8 +773,10 @@ OPENDHT_PUBLIC Blob aesEncrypt(const Blob& data, const std::string& password);
/**
* AES-GCM decryption.
*/
OPENDHT_PUBLIC Blob aesDecrypt(const Blob& data, const Blob& key);
OPENDHT_PUBLIC Blob aesDecrypt(const Blob& data, const std::string& password);
OPENDHT_PUBLIC Blob aesDecrypt(const uint8_t* data, size_t data_length, const Blob& key);
OPENDHT_PUBLIC inline Blob aesDecrypt(const Blob& data, const Blob& key) { return aesDecrypt(data.data(), data.size(), key); }
OPENDHT_PUBLIC Blob aesDecrypt(const uint8_t* data, size_t data_length, const std::string& password);
OPENDHT_PUBLIC inline Blob aesDecrypt(const Blob& data, const std::string& password) { return aesDecrypt(data.data(), data.size(), password); }
}
}
+8 -4
View File
@@ -66,8 +66,10 @@ private:
public:
virtual void unpackValue(const Value& v) override {
if (v.owner)
if (v.owner) {
owner = v.owner;
from = v.owner->getId();
}
BaseClass::unpackValue(v);
}
@@ -75,6 +77,7 @@ public:
return [](const Value& v){ return v.isSigned(); };
}
Sp<crypto::PublicKey> owner;
dht::InfoHash from;
};
@@ -144,17 +147,18 @@ public:
static const ValueType TYPE;
TrustRequest() {}
TrustRequest(std::string s) : service(s) {}
TrustRequest(std::string s, const Blob& d) : service(s), payload(d) {}
TrustRequest(std::string s, std::string ci = {}) : service(s), conversationId(ci) {}
TrustRequest(std::string s, std::string ci, const Blob& d) : service(s), conversationId(ci), payload(d) {}
static Value::Filter getFilter() {
return EncryptedValue::getFilter();
}
std::string service;
std::string conversationId;
Blob payload;
bool confirm {false};
MSGPACK_DEFINE_MAP(service, payload, confirm)
MSGPACK_DEFINE_MAP(service, conversationId, payload, confirm)
};
class OPENDHT_PUBLIC IceCandidates : public EncryptedValue<IceCandidates>
+3 -4
View File
@@ -61,9 +61,6 @@ struct LocalListener;
*/
class OPENDHT_PUBLIC Dht final : public DhtInterface {
public:
Dht();
/**
* Initialise the Dht with two open sockets (for IPv4 and IP6)
* and an ID for the node.
@@ -98,7 +95,7 @@ public:
/**
* Performs final operations before quitting.
*/
void shutdown(ShutdownCallback cb) override;
void shutdown(ShutdownCallback cb, bool stop = false) override;
/**
* Returns true if the node is running (have access to an open socket).
@@ -515,6 +512,8 @@ private:
void confirmNodes();
void expire();
void onConnected();
void onDisconnected();
/**
+10 -1
View File
@@ -21,6 +21,8 @@
#include "infohash.h"
#include "log_enable.h"
#include <queue>
namespace dht {
namespace net {
@@ -46,6 +48,10 @@ public:
virtual NodeStatus getStatus(sa_family_t af) const = 0;
virtual NodeStatus getStatus() const = 0;
void addOnConnectedCallback(std::function<void()> cb) {
onConnectCallbacks_.emplace(std::move(cb));
}
virtual net::DatagramSocket* getSocket() const { return {}; };
/**
@@ -55,8 +61,10 @@ public:
/**
* Performs final operations before quitting.
* stop: if true, cancel ongoing operations and call their 'done'
* callbacks synchronously.
*/
virtual void shutdown(ShutdownCallback cb) = 0;
virtual void shutdown(ShutdownCallback cb, bool stop = false) = 0;
/**
* Returns true if the node is running (have access to an open socket).
@@ -264,6 +272,7 @@ public:
protected:
std::shared_ptr<Logger> logger_ {};
std::queue<std::function<void()>> onConnectCallbacks_ {};
};
} // namespace dht
+12 -12
View File
@@ -85,7 +85,7 @@ public:
/**
* Performs final operations before quitting.
*/
void shutdown(ShutdownCallback cb) override;
void shutdown(ShutdownCallback cb, bool) override;
/**
* Returns true if the node is running (have access to an open socket).
@@ -107,13 +107,13 @@ public:
*/
virtual void get(const InfoHash& key, GetCallback cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) override;
virtual void get(const InfoHash& key, GetCallback cb, DoneCallbackSimple donecb={}, Value::Filter&& f={}, Where&& w = {}) override {
get(key, cb, bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
get(key, cb, bindDoneCb(std::move(donecb)), std::forward<Value::Filter>(f), std::forward<Where>(w));
}
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallback donecb={}, Value::Filter&& f={}, Where&& w = {}) override {
get(key, bindGetCb(cb), donecb, std::forward<Value::Filter>(f), std::forward<Where>(w));
get(key, bindGetCb(cb), std::move(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
}
virtual void get(const InfoHash& key, GetCallbackSimple cb, DoneCallbackSimple donecb, Value::Filter&& f={}, Where&& w = {}) override {
get(key, bindGetCb(cb), bindDoneCb(donecb), std::forward<Value::Filter>(f), std::forward<Where>(w));
get(key, bindGetCb(cb), bindDoneCb(std::move(donecb)), std::forward<Value::Filter>(f), std::forward<Where>(w));
}
/**
@@ -134,7 +134,7 @@ public:
time_point created=time_point::max(),
bool permanent = false) override
{
put(key, v, bindDoneCb(cb), created, permanent);
put(key, v, bindDoneCb(std::move(cb)), created, permanent);
}
void put(const InfoHash& key,
@@ -143,7 +143,7 @@ public:
time_point created=time_point::max(),
bool permanent = false) override
{
put(key, std::make_shared<Value>(std::move(v)), cb, created, permanent);
put(key, std::make_shared<Value>(std::move(v)), std::move(cb), created, permanent);
}
void put(const InfoHash& key,
Value&& v,
@@ -151,7 +151,7 @@ public:
time_point created=time_point::max(),
bool permanent = false) override
{
put(key, std::forward<Value>(v), bindDoneCb(cb), created, permanent);
put(key, std::forward<Value>(v), bindDoneCb(std::move(cb)), created, permanent);
}
/**
@@ -176,14 +176,14 @@ public:
virtual size_t listen(const InfoHash&, ValueCallback, Value::Filter={}, Where={}) override;
virtual size_t listen(const InfoHash& key, GetCallback cb, Value::Filter f={}, Where w={}) override {
return listen(key, [cb](const std::vector<Sp<Value>>& vals, bool expired){
return listen(key, [cb=std::move(cb)](const std::vector<Sp<Value>>& vals, bool expired){
if (not expired)
return cb(vals);
return true;
}, std::forward<Value::Filter>(f), std::forward<Where>(w));
}
virtual size_t listen(const InfoHash& key, GetCallbackSimple cb, Value::Filter f={}, Where w={}) override {
return listen(key, bindGetCb(cb), std::forward<Value::Filter>(f), std::forward<Where>(w));
return listen(key, bindGetCb(std::move(cb)), std::forward<Value::Filter>(f), std::forward<Where>(w));
}
/*
* This function relies on the cache implementation.
@@ -214,7 +214,7 @@ public:
*/
virtual void query(const InfoHash& /*key*/, QueryCallback /*cb*/, DoneCallback /*done_cb*/ = {}, Query&& /*q*/ = {}) override { }
virtual void query(const InfoHash& key, QueryCallback cb, DoneCallbackSimple done_cb = {}, Query&& q = {}) override {
query(key, cb, bindDoneCb(done_cb), std::forward<Query>(q));
query(key, cb, bindDoneCb(std::move(done_cb)), std::forward<Query>(q));
}
/**
@@ -378,8 +378,8 @@ private:
* Retrieve if we can connect to the proxy (update statusIpvX_)
*/
void handleProxyConfirm(const asio::error_code &ec);
Sp<asio::steady_timer> nextProxyConfirmationTimer_;
Sp<asio::steady_timer> listenerRestartTimer_;
std::unique_ptr<asio::steady_timer> nextProxyConfirmationTimer_;
std::unique_ptr<asio::steady_timer> listenerRestartTimer_;
/**
* Relaunch LISTEN requests if the client disconnect/reconnect.
-1
View File
@@ -445,7 +445,6 @@ private:
std::map<InfoHash, std::vector<Listener>> listeners;
MSGPACK_DEFINE_ARRAY(listeners)
};
std::mutex lockPushListeners_;
std::map<std::string, PushListener> pushListeners_;
proxy::ListenToken tokenPushNotif_ {0};
#endif //OPENDHT_PUSH_NOTIFICATIONS
+26 -20
View File
@@ -65,6 +65,7 @@ public:
bool peer_publish {false};
std::shared_ptr<dht::crypto::Certificate> server_ca;
dht::crypto::Identity client_identity;
SockAddr bind4 {}, bind6 {};
};
struct Context {
@@ -73,6 +74,7 @@ public:
std::shared_ptr<PeerDiscovery> peerDiscovery {};
StatusCallback statusChangedCallback {};
CertificateStoreQuery certificateStore {};
IdentityAnnouncedCb identityAnnouncedCb {};
Context() {}
};
@@ -97,7 +99,7 @@ public:
template <class T>
void get(InfoHash hash, std::function<bool(std::vector<T>&&)> cb, DoneCallbackSimple dcb={})
{
get(hash, [=](const std::vector<std::shared_ptr<Value>>& vals) {
get(hash, [cb=std::move(cb)](const std::vector<std::shared_ptr<Value>>& vals) {
return cb(unpackVector<T>(vals));
},
dcb,
@@ -106,7 +108,7 @@ public:
template <class T>
void get(InfoHash hash, std::function<bool(T&&)> cb, DoneCallbackSimple dcb={})
{
get(hash, [=](const std::vector<std::shared_ptr<Value>>& vals) {
get(hash, [cb=std::move(cb)](const std::vector<std::shared_ptr<Value>>& vals) {
for (const auto& v : vals) {
try {
if (not cb(Value::unpack<T>(*v)))
@@ -155,7 +157,7 @@ public:
std::future<size_t> listen(InfoHash key, ValueCallback vcb, Value::Filter f = {}, Where w = {});
std::future<size_t> listen(InfoHash key, GetCallback cb, Value::Filter f={}, Where w={}) {
return listen(key, [cb](const std::vector<Sp<Value>>& vals, bool expired){
return listen(key, [cb=std::move(cb)](const std::vector<Sp<Value>>& vals, bool expired){
if (not expired)
return cb(vals);
return true;
@@ -169,7 +171,7 @@ public:
template <class T>
std::future<size_t> listen(InfoHash hash, std::function<bool(std::vector<T>&&)> cb)
{
return listen(hash, [=](const std::vector<std::shared_ptr<Value>>& vals) {
return listen(hash, [cb=std::move(cb)](const std::vector<std::shared_ptr<Value>>& vals) {
return cb(unpackVector<T>(vals));
},
getFilterSet<T>());
@@ -177,7 +179,7 @@ public:
template <class T>
std::future<size_t> listen(InfoHash hash, std::function<bool(std::vector<T>&&, bool)> cb)
{
return listen(hash, [=](const std::vector<std::shared_ptr<Value>>& vals, bool expired) {
return listen(hash, [cb=std::move(cb)](const std::vector<std::shared_ptr<Value>>& vals, bool expired) {
return cb(unpackVector<T>(vals), expired);
},
getFilterSet<T>());
@@ -186,7 +188,7 @@ public:
template <typename T>
std::future<size_t> listen(InfoHash hash, std::function<bool(T&&)> cb, Value::Filter f = {}, Where w = {})
{
return listen(hash, [=](const std::vector<std::shared_ptr<Value>>& vals) {
return listen(hash, [cb=std::move(cb)](const std::vector<std::shared_ptr<Value>>& vals) {
for (const auto& v : vals) {
try {
if (not cb(Value::unpack<T>(*v)))
@@ -202,7 +204,7 @@ public:
template <typename T>
std::future<size_t> listen(InfoHash hash, std::function<bool(T&&, bool)> cb, Value::Filter f = {}, Where w = {})
{
return listen(hash, [=](const std::vector<std::shared_ptr<Value>>& vals, bool expired) {
return listen(hash, [cb=std::move(cb)](const std::vector<std::shared_ptr<Value>>& vals, bool expired) {
for (const auto& v : vals) {
try {
if (not cb(Value::unpack<T>(*v), expired))
@@ -255,6 +257,17 @@ public:
}
void putEncrypted(const std::string& key, InfoHash to, Value&& value, DoneCallback cb={}, bool permanent = false);
void putEncrypted(InfoHash hash, const std::shared_ptr<crypto::PublicKey>& to, std::shared_ptr<Value> value, DoneCallback cb={}, bool permanent = false);
void putEncrypted(InfoHash hash, const std::shared_ptr<crypto::PublicKey>& to, std::shared_ptr<Value> value, DoneCallbackSimple cb, bool permanent = false) {
putEncrypted(hash, to, value, bindDoneCb(cb), permanent);
}
void putEncrypted(InfoHash hash, const std::shared_ptr<crypto::PublicKey>& to, Value&& value, DoneCallback cb={}, bool permanent = false);
void putEncrypted(InfoHash hash, const std::shared_ptr<crypto::PublicKey>& to, Value&& value, DoneCallbackSimple cb, bool permanent = false) {
putEncrypted(hash, to, std::forward<Value>(value), bindDoneCb(cb), permanent);
}
/**
* Insert known nodes to the routing table, without necessarly ping them.
* Usefull to restart a node and get things running fast without putting load on the network.
@@ -301,6 +314,7 @@ public:
* Get the public key fingerprint if an identity is used with this node, 0 otherwise.
*/
InfoHash getId() const;
std::shared_ptr<crypto::PublicKey> getPublicKey() const;
/**
* Get the ID of the DHT node.
@@ -359,6 +373,7 @@ public:
std::string getSearchLog(const InfoHash&, sa_family_t af = AF_UNSPEC) const;
std::vector<SockAddr> getPublicAddress(sa_family_t af = AF_UNSPEC);
std::vector<std::string> getPublicAddressStr(sa_family_t af = AF_UNSPEC);
void getPublicAddress(std::function<void(std::vector<SockAddr>&&)>, sa_family_t af = AF_UNSPEC);
// securedht methods
@@ -379,22 +394,12 @@ public:
config.threaded = threaded;
run(port, config);
}
void run(in_port_t port, const Config& config, Context&& context = {});
/**
* @param local4: Local IPv4 address and port to bind. Can be null.
* @param local6: Local IPv6 address and port to bind. Can be null.
* You should allways bind to a global IPv6 address.
* @param identity: RSA key pair to use for cryptographic operations.
* @param threaded: If false, loop() must be called periodically. Otherwise a thread is launched.
* @param cb: Optional callback to receive general state information.
*/
void run(SockAddr& local4, SockAddr& local6, const Config& config, Context&& context = {});
void run(in_port_t port, Config& config, Context&& context = {});
/**
* Same as @run(sockaddr_in, sockaddr_in6, Identity, bool, StatusCallback), but with string IP addresses and service (port).
*/
void run(const char* ip4, const char* ip6, const char* service, const Config& config, Context&& context = {});
void run(const char* ip4, const char* ip6, const char* service, Config& config, Context&& context = {});
void run(const Config& config, Context&& context);
@@ -415,7 +420,7 @@ public:
/**
* Gracefuly disconnect from network.
*/
void shutdown(ShutdownCallback cb = {});
void shutdown(ShutdownCallback cb = {}, bool stop = false);
/**
* Quit and wait for all threads to terminate.
@@ -481,6 +486,7 @@ private:
/** Current configuration */
Config config_;
IdentityAnnouncedCb identityAnnouncedCb_;
/**
* reset dht clients
+2 -12
View File
@@ -96,6 +96,7 @@ public:
inline unsigned int id() const { return id_; };
bool is_open() const;
bool is_ssl() const;
void checkOcsp(bool check = true) { checkOcsp_ = check; }
void set_ssl_verification(const std::string& hostname, const asio::ssl::verify_mode verify_mode);
@@ -143,6 +144,7 @@ private:
std::unique_ptr<asio::steady_timer> timeout_timer_;
std::shared_ptr<dht::Logger> logger_;
bool checkOcsp_ {false};
};
/**
@@ -373,15 +375,3 @@ private:
} // namespace http
} // namespace dht
#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK
namespace restinio
{
/* Custom HTTP-methods for RESTinio > 0.5.0.
* https://github.com/Stiffstream/restinio/issues/26
*/
constexpr const restinio::http_method_id_t method_listen {HTTP_LISTEN, "LISTEN"};
constexpr const restinio::http_method_id_t method_stats {HTTP_STATS, "STATS"};
constexpr const restinio::http_method_id_t method_sign {HTTP_SIGN, "SIGN"};
constexpr const restinio::http_method_id_t method_encrypt {HTTP_ENCRYPT, "ENCRYPT"};
} // namespace restinio
#endif
+1 -1
View File
@@ -335,7 +335,7 @@ public:
void lookup(Key k, LookupCallback cb = {}, DoneCallbackSimple done_cb = {}, bool exact_match = true);
void lookup(Key k, LookupCallbackSimple cb = {}, DoneCallbackSimple done_cb = {}, bool exact_match = true)
{
lookup(k, [=](std::vector<std::shared_ptr<Value>>& values, Prefix) { cb(values); }, done_cb, exact_match);
lookup(k, [cb=std::move(cb)](std::vector<std::shared_ptr<Value>>& values, Prefix) { cb(values); }, done_cb, exact_match);
}
/**
+35 -19
View File
@@ -54,9 +54,9 @@ namespace crypto {
}
/**
* Represents an InfoHash.
* An InfoHash is a byte array of HASH_LEN bytes.
* InfoHashes identify nodes and values in the Dht.
* Represents an Hash,
* a byte array of N bytes.
* Hashes identify nodes and values in the Dht.
*/
template <size_t N>
class OPENDHT_PUBLIC Hash {
@@ -93,6 +93,8 @@ public:
iterator end() { return data_.end(); }
const_iterator cend() const { return data_.cend(); }
static constexpr inline Hash zero() noexcept { return Hash{}; }
bool operator==(const Hash& h) const {
auto a = reinterpret_cast<const uint32_t*>(data_.data());
auto b = reinterpret_cast<const uint32_t*>(h.data_.data());
@@ -112,6 +114,14 @@ public:
return false;
}
Hash operator^(const Hash& o) const {
Hash result;
for(auto i = 0u; i < N; i++) {
result[i] = data_[i] ^ o.data_[i];
}
return result;
}
explicit operator bool() const {
auto a = reinterpret_cast<const uint32_t*>(data_.data());
auto b = reinterpret_cast<const uint32_t*>(data_.data() + N);
@@ -142,10 +152,6 @@ public:
return 8 * i + j;
}
/**
* Forget about the ``XOR-metric''. An id is just a path from the
* root of the tree, so bits are numbered from the start.
*/
static inline int cmp(const Hash& id1, const Hash& id2) {
return std::memcmp(id1.data_.data(), id2.data_.data(), N);
}
@@ -179,16 +185,12 @@ public:
int
xorCmp(const Hash& id1, const Hash& id2) const
{
for(unsigned i = 0; i < N; i++) {
uint8_t xor1, xor2;
for (unsigned i = 0; i < N; i++) {
if(id1.data_[i] == id2.data_[i])
continue;
xor1 = id1.data_[i] ^ data_[i];
xor2 = id2.data_[i] ^ data_[i];
if(xor1 < xor2)
return -1;
else
return 1;
uint8_t xor1 = id1.data_[i] ^ data_[i];
uint8_t xor2 = id2.data_[i] ^ data_[i];
return (xor1 < xor2) ? -1 : 1;
}
return 0;
}
@@ -340,7 +342,7 @@ Hash<N>::getRandom(Rd& rdev)
return h;
}
struct HexMap : public std::array<std::array<char, 2>, 256> {
struct alignas(std::max_align_t) HexMap : public std::array<std::array<char, 2>, 256> {
HexMap() {
for (size_t i=0; i<size(); i++) {
auto& e = (*this)[i];
@@ -354,11 +356,27 @@ private:
OPENDHT_PUBLIC extern const HexMap hex_map;
inline std::string
toHex(const uint8_t* data, size_t size) {
std::string ret(size * 2, '\0');
for (size_t i=0; i<size; i++) {
auto b = ret.data()+i*2;
const auto& m = hex_map[data[i]];
*((uint16_t*)b) = *((uint16_t*)&m);
}
return ret;
}
inline std::string
toHex(const std::vector<uint8_t>& data) {
return toHex(data.data(), data.size());
}
template <size_t N>
const char*
Hash<N>::to_c_str() const
{
thread_local std::array<char, N*2+1> buf;
alignas(std::max_align_t) thread_local std::array<char, N*2+1> buf;
for (size_t i=0; i<N; i++) {
auto b = buf.data()+i*2;
const auto& m = hex_map[data_[i]];
@@ -374,8 +392,6 @@ Hash<N>::toString() const
return std::string(to_c_str(), N*2);
}
const InfoHash zeroes {};
struct OPENDHT_PUBLIC NodeExport {
InfoHash id;
sockaddr_storage ss;
+1 -2
View File
@@ -214,7 +214,6 @@ public:
using RequestErrorCb = std::function<bool(const Request&, DhtProtocolException&&)>;
using RequestExpiredCb = std::function<void(const Request&, bool)>;
NetworkEngine(const Sp<Logger>& log, std::mt19937_64& rd, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock);
NetworkEngine(
InfoHash& myid,
NetworkConfig config,
@@ -293,7 +292,7 @@ public:
*/
Sp<Request>
sendPing(SockAddr&& sa, RequestCb&& on_done, RequestExpiredCb&& on_expired) {
return sendPing(std::make_shared<Node>(zeroes, std::move(sa), rd),
return sendPing(std::make_shared<Node>(InfoHash::zero(), std::move(sa), rd),
std::forward<RequestCb>(on_done),
std::forward<RequestExpiredCb>(on_expired));
}
+15 -10
View File
@@ -45,15 +45,13 @@ public:
return c;
}
SecureDht() {}
/**
* s, s6: bound socket descriptors for IPv4 and IPv6, respectively.
* For the Dht to be initialised, at least one of them must be >= 0.
* id: the identity to use for the crypto layer and to compute
* our own hash on the Dht.
*/
SecureDht(std::unique_ptr<DhtInterface> dht, Config config);
SecureDht(std::unique_ptr<DhtInterface> dht, Config config, IdentityAnnouncedCb iacb = {}, const std::shared_ptr<Logger>& l = {});
virtual ~SecureDht();
@@ -63,6 +61,9 @@ public:
PkId getLongId() const {
return key_ ? key_->getPublicKey().getLongId() : PkId();
}
Sp<crypto::PublicKey> getPublicKey() const {
return key_ ? key_->getSharedPublicKey() : Sp<crypto::PublicKey>{};
}
ValueType secureType(ValueType&& type);
@@ -117,6 +118,10 @@ public:
void putEncrypted(const InfoHash& hash, const InfoHash& to, Value&& v, DoneCallback callback, bool permanent = false) {
putEncrypted(hash, to, std::make_shared<Value>(std::move(v)), callback, permanent);
}
void putEncrypted(const InfoHash& hash, const crypto::PublicKey& to, Sp<Value> val, DoneCallback callback, bool permanent = false);
void putEncrypted(const InfoHash& hash, const crypto::PublicKey& to, Value&& v, DoneCallback callback, bool permanent = false) {
putEncrypted(hash, to, std::make_shared<Value>(std::move(v)), callback, permanent);
}
/**
* Take ownership of the value and sign it using our private key.
@@ -128,13 +133,13 @@ public:
Value decrypt(const Value& v);
void findCertificate(const InfoHash& node, const std::function<void(const Sp<crypto::Certificate>)>& cb);
void findPublicKey(const InfoHash& node, const std::function<void(const Sp<const crypto::PublicKey>)>& cb);
void findPublicKey(const InfoHash& node, const std::function<void(const Sp<crypto::PublicKey>)>& cb);
const Sp<crypto::Certificate> registerCertificate(const InfoHash& node, const Blob& cert);
Sp<crypto::Certificate> registerCertificate(const InfoHash& node, const Blob& cert);
void registerCertificate(Sp<crypto::Certificate>& cert);
const Sp<crypto::Certificate> getCertificate(const InfoHash& node) const;
const Sp<const crypto::PublicKey> getPublicKey(const InfoHash& node) const;
Sp<crypto::Certificate> getCertificate(const InfoHash& node) const;
Sp<crypto::PublicKey> getPublicKey(const InfoHash& node) const;
/**
* Allows to set a custom callback called by the library to find a locally-stored certificate.
@@ -148,8 +153,8 @@ public:
/**
* SecureDht to Dht proxy
*/
void shutdown(ShutdownCallback cb) override {
dht_->shutdown(cb);
void shutdown(ShutdownCallback cb, bool stop = false) override {
dht_->shutdown(cb, stop);
}
void dumpTables() const override {
dht_->dumpTables();
@@ -356,7 +361,7 @@ private:
// our certificate cache
std::map<InfoHash, Sp<crypto::Certificate>> nodesCertificates_ {};
std::map<InfoHash, Sp<const crypto::PublicKey>> nodesPubKeys_ {};
std::map<InfoHash, Sp<crypto::PublicKey>> nodesPubKeys_ {};
std::atomic_bool forward_all_ {false};
bool enableCache_ {false};
+6 -6
View File
@@ -68,7 +68,7 @@ public:
* Build from existing address.
*/
SockAddr(const sockaddr* sa, socklen_t length) {
if (length > sizeof(sockaddr_storage))
if (length > static_cast<socklen_t>(sizeof(sockaddr_storage)))
throw std::runtime_error("Socket address length is too large");
set(sa, length);
}
@@ -144,7 +144,7 @@ public:
if (len) addr.reset((sockaddr*)::calloc(len, 1));
else addr.reset();
}
if (len > sizeof(sa_family_t))
if (len)
addr->sa_family = af;
}
@@ -223,16 +223,16 @@ public:
*/
sockaddr* get() { return addr.get(); }
const sockaddr_in& getIPv4() const {
inline const sockaddr_in& getIPv4() const {
return *reinterpret_cast<const sockaddr_in*>(get());
}
const sockaddr_in6& getIPv6() const {
inline const sockaddr_in6& getIPv6() const {
return *reinterpret_cast<const sockaddr_in6*>(get());
}
sockaddr_in& getIPv4() {
inline sockaddr_in& getIPv4() {
return *reinterpret_cast<sockaddr_in*>(get());
}
sockaddr_in6& getIPv6() {
inline sockaddr_in6& getIPv6() {
return *reinterpret_cast<sockaddr_in6*>(get());
}
+67
View File
@@ -93,4 +93,71 @@ private:
void schedule();
};
class OPENDHT_PUBLIC ExecutionContext {
public:
ExecutionContext(ThreadPool& pool)
: threadPool_(pool), state_(std::make_shared<SharedState>())
{}
~ExecutionContext() {
state_->destroy();
}
/** Wait for ongoing tasks to complete execution and drop other pending tasks */
void stop() {
state_->destroy(false);
}
void run(std::function<void()>&& task) {
std::lock_guard<std::mutex> lock(state_->mtx);
if (state_->shutdown_) return;
state_->pendingTasks++;
threadPool_.get().run([task = std::move(task), state = state_] {
state->run(task);
});
}
private:
struct SharedState {
std::mutex mtx {};
std::condition_variable cv {};
unsigned pendingTasks {0};
unsigned ongoingTasks {0};
/** When true, prevents new tasks to be scheduled */
bool shutdown_ {false};
/** When true, prevents scheduled tasks to be executed */
std::atomic_bool destroyed {false};
void destroy(bool wait = true) {
std::unique_lock<std::mutex> lock(mtx);
if (destroyed) return;
if (wait) {
cv.wait(lock, [this] { return pendingTasks == 0 && ongoingTasks == 0; });
}
shutdown_ = true;
if (not wait) {
cv.wait(lock, [this] { return ongoingTasks == 0; });
}
destroyed = true;
}
void run(const std::function<void()>& task) {
{
std::lock_guard<std::mutex> lock(mtx);
pendingTasks--;
ongoingTasks++;
}
if (destroyed) return;
task();
{
std::lock_guard<std::mutex> lock(mtx);
ongoingTasks--;
cv.notify_all();
}
}
};
std::reference_wrapper<ThreadPool> threadPool_;
std::shared_ptr<SharedState> state_;
};
}
+6 -7
View File
@@ -205,7 +205,7 @@ struct OPENDHT_PUBLIC Value
}
static Filter chainOr(Filter&& f1, Filter&& f2) {
if (not f1 or not f2) return {};
return [f1,f2](const Value& v) {
return [f1=std::move(f1),f2=std::move(f2)](const Value& v) {
return f1(v) or f2(v);
};
}
@@ -231,8 +231,7 @@ struct OPENDHT_PUBLIC Value
}
static Filter TypeFilter(const ValueType& t) {
const auto tid = t.id;
return [tid](const Value& v) {
return [tid = t.id](const Value& v) {
return v.type == tid;
};
}
@@ -357,7 +356,7 @@ struct OPENDHT_PUBLIC Value
void sign(const crypto::PrivateKey& key) {
if (isEncrypted())
throw DhtException("Can't sign encrypted data.");
owner = std::make_shared<const crypto::PublicKey>(key.getPublicKey());
owner = key.getSharedPublicKey();
signature = key.sign(getToSign());
}
@@ -369,8 +368,8 @@ struct OPENDHT_PUBLIC Value
return isSigned() and owner->checkSignature(getToSign(), signature);
}
std::shared_ptr<const crypto::PublicKey> getOwner() const {
return std::static_pointer_cast<const crypto::PublicKey>(owner);
std::shared_ptr<crypto::PublicKey> getOwner() const {
return std::static_pointer_cast<crypto::PublicKey>(owner);
}
/**
@@ -595,7 +594,7 @@ struct OPENDHT_PUBLIC Value
/**
* Public key of the signer.
*/
std::shared_ptr<const crypto::PublicKey> owner {};
std::shared_ptr<crypto::PublicKey> owner {};
/**
* Hash of the recipient (optional).
+20 -8
View File
@@ -36,6 +36,7 @@ from libcpp.memory cimport shared_ptr
from cython.parallel import parallel, prange
from cython.operator cimport dereference as deref, preincrement as inc, predecrement as dec
from cpython cimport ref
from datetime import timedelta
cimport opendht_cpp as cpp
@@ -235,8 +236,9 @@ cdef class Where(object):
cdef class Value(object):
cdef shared_ptr[cpp.Value] _value
def __init__(self, bytes val=b''):
self._value.reset(new cpp.Value(val, len(val)))
def __init__(self, bytes val=b'', cpp.uint16_t id=0):
self._value.reset(new cpp.Value(id, val, len(val)))
def __str__(self):
return self._value.get().toString().decode()
property owner:
@@ -270,6 +272,14 @@ cdef class Value(object):
def __get__(self):
return self._value.get().size()
cdef class ValueType(object):
cdef cpp.ValueType * _value
def __init__(self, cpp.uint16_t id, str name, expiration: timedelta):
if not isinstance(expiration, timedelta):
raise TypeError("expiration argument must be of type timedelta")
cdef cpp.seconds duration = cpp.seconds(int(expiration.total_seconds()))
self._value = new cpp.ValueType(id, name.encode(), duration)
cdef class NodeSetIter(object):
cdef map[cpp.InfoHash, shared_ptr[cpp.Node]]* _nodes
cdef map[cpp.InfoHash, shared_ptr[cpp.Node]].iterator _curIter
@@ -319,11 +329,11 @@ cdef class PrivateKey(_WithID):
cdef shared_ptr[cpp.PrivateKey] _key
def getId(self):
h = InfoHash()
h._infohash = self._key.get().getPublicKey().getId()
h._infohash = self._key.get().getSharedPublicKey().get().getId()
return h
def getPublicKey(self):
pk = PublicKey()
pk._key = self._key.get().getPublicKey()
pk._key = self._key.get().getSharedPublicKey()
return pk
def decrypt(self, bytes dat):
cdef size_t d_len = len(dat)
@@ -348,17 +358,17 @@ cdef class PrivateKey(_WithID):
return k
cdef class PublicKey(_WithID):
cdef cpp.PublicKey _key
cdef cpp.shared_ptr[cpp.PublicKey] _key
def getId(self):
h = InfoHash()
h._infohash = self._key.getId()
h._infohash = self._key.get().getId()
return h
def encrypt(self, bytes dat):
cdef size_t d_len = len(dat)
cdef cpp.uint8_t* d_ptr = <cpp.uint8_t*>dat
cdef cpp.Blob indat
indat.assign(d_ptr, <cpp.uint8_t*>(d_ptr + d_len))
cdef cpp.Blob encrypted = self._key.encrypt(indat)
cdef cpp.Blob encrypted = self._key.get().encrypt(indat)
cdef char* encrypted_c_str = <char *>encrypted.data()
cdef Py_ssize_t length = encrypted.size()
return encrypted_c_str[:length]
@@ -430,7 +440,7 @@ cdef class Identity(object):
property publickey:
def __get__(self):
k = PublicKey()
k._key = self._id.first.get().getPublicKey()
k._key = self._id.first.get().getSharedPublicKey()
return k
property certificate:
def __get__(self):
@@ -513,6 +523,8 @@ cdef class DhtRunner(_WithID):
cb_obj = {'shutdown':shutdown_cb}
ref.Py_INCREF(cb_obj)
self.thisptr.get().shutdown(cpp.bindShutdownCb(shutdown_callback, <void*>cb_obj))
def registerType(self, ValueType type):
self.thisptr.get().registerType(deref(type._value))
def enableLogging(self):
cpp.enableLogging(self.thisptr.get()[0])
def disableLogging(self):
+17 -3
View File
@@ -26,6 +26,14 @@ from libc.string cimport const_char, const_uchar
ctypedef uint16_t in_port_t
ctypedef unsigned short int sa_family_t;
cdef extern from "<iostream>" namespace "std::chrono" nogil:
cdef cppclass duration[ulong]:
duration() except +
cdef cppclass seconds:
duration seconds(uint64_t) except +
duration seconds()
cdef extern from "<memory>" namespace "std" nogil:
cdef cppclass shared_ptr[T]:
shared_ptr() except +
@@ -89,7 +97,7 @@ cdef extern from "opendht/crypto.h" namespace "dht::crypto":
cdef cppclass PrivateKey:
PrivateKey()
PublicKey getPublicKey() const
shared_ptr[PublicKey] getSharedPublicKey() const
Blob decrypt(Blob data) const
@staticmethod
PrivateKey generate()
@@ -131,7 +139,6 @@ cdef extern from "opendht/value.h" namespace "dht::Value":
cdef extern from "opendht/value.h" namespace "dht::Value::Field":
cdef Field None
cdef Field Id
cdef Field ValueType
cdef Field OwnerPk
cdef Field SeqNum
cdef Field UserType
@@ -141,7 +148,7 @@ cdef extern from "opendht/value.h" namespace "dht":
cdef cppclass Value:
Value() except +
Value(vector[uint8_t]) except +
Value(const uint8_t* dat_ptr, size_t dat_len) except +
Value(const uint16_t t, const uint8_t* dat_ptr, size_t dat_len) except +
string toString() const
size_t size() const
uint64_t id
@@ -150,6 +157,12 @@ cdef extern from "opendht/value.h" namespace "dht":
vector[uint8_t] data
string user_type
cdef cppclass ValueType:
ValueType(uint16_t id, string name, seconds expiration) except +
uint16_t id
string name
seconds expiration
cdef cppclass Query:
Query() except +
Query(Select s, Where w) except +
@@ -234,6 +247,7 @@ cdef extern from "opendht/dhtrunner.h" namespace "dht":
void run(const_char*, const_char*, const_char*, Config config)
void join()
void shutdown(ShutdownCallback)
void registerType(ValueType& value);
bool isRunning()
SockAddr getBound(sa_family_t af) const
string getStorageLog() const
+3 -30
View File
@@ -2,7 +2,7 @@ lib_LTLIBRARIES = libopendht.la
libopendht_la_CPPFLAGS = @CPPFLAGS@ -I$(top_srcdir)/include/opendht @Argon2_CFLAGS@ @JsonCpp_CFLAGS@ @MsgPack_CFLAGS@ @OpenSSL_CFLAGS@ @Fmt_CFLAGS@
libopendht_la_LIBADD = @Argon2_LIBS@ @JsonCpp_LIBS@ @GnuTLS_LIBS@ @Nettle_LIBS@ @OpenSSL_LIBS@ @Fmt_LIBS@
libopendht_la_LDFLAGS = @LDFLAGS@ @Argon2_LDFLAGS@ -version-number @OPENDHT_MAJOR_VERSION@:@OPENDHT_MINOR_VERSION@:@OPENDHT_PATCH_VERSION@
libopendht_la_LDFLAGS = @LDFLAGS@ -version-number @OPENDHT_MAJOR_VERSION@:@OPENDHT_MINOR_VERSION@:@OPENDHT_PATCH_VERSION@
libopendht_la_SOURCES = \
dht.cpp \
storage.h \
@@ -71,8 +71,8 @@ endif
libopendht_la_SOURCES += base64.h base64.cpp
if PROXY_CLIENT_OR_SERVER
libopendht_la_SOURCES += http.cpp
nobase_include_HEADERS += ../include/opendht/proxy.h ../include/opendht/http.h
libopendht_la_SOURCES += http.cpp compat/os_cert.cpp
nobase_include_HEADERS += ../include/opendht/proxy.h ../include/opendht/http.h compat/os_cert.h
endif
if ENABLE_PEER_DISCOVERY
@@ -87,30 +87,3 @@ endif
clean-local:
rm -rf libargon2.la
######################
# ARGON2 submodule #
######################
if WITH_INCLUDED_ARGON2
noinst_LTLIBRARIES = libargon2.la
libopendht_la_DEPENDENCIES = libargon2.la
libargon2_la_CFLAGS = -std=c89 -fPIC -pthread -O3 -Wall -I@top_builddir@/argon2/include -I@top_builddir@/argon2/src
libargon2_la_SOURCES = \
@top_builddir@/argon2/src/argon2.c \
@top_builddir@/argon2/src/core.c \
@top_builddir@/argon2/src/blake2/blake2b.c \
@top_builddir@/argon2/src/thread.c \
@top_builddir@/argon2/src/ref.c \
@top_builddir@/argon2/src/encoding.c
noinst_HEADERS = \
@top_builddir@/argon2/include/argon2.h \
@top_builddir@/argon2/src/blake2/blake2.h \
@top_builddir@/argon2/src/blake2/blake2-impl.h \
@top_builddir@/argon2/src/blake2/blamka-round-ref.h \
@top_builddir@/argon2/src/core.h \
@top_builddir@/argon2/src/encoding.h \
@top_builddir@/argon2/src/thread.h
endif
+8 -8
View File
@@ -26,7 +26,7 @@ namespace dht {
GetCallbackSimple
bindGetCb(const GetCallbackRaw& raw_cb, void* user_data)
bindGetCb(GetCallbackRaw raw_cb, void* user_data)
{
if (not raw_cb) return {};
return [=](const std::shared_ptr<Value>& value) {
@@ -35,10 +35,10 @@ bindGetCb(const GetCallbackRaw& raw_cb, void* user_data)
}
GetCallback
bindGetCb(const GetCallbackSimple& cb)
bindGetCb(GetCallbackSimple cb)
{
if (not cb) return {};
return [=](const std::vector<std::shared_ptr<Value>>& values) {
return [cb=std::move(cb)](const std::vector<std::shared_ptr<Value>>& values) {
for (const auto& v : values)
if (not cb(v))
return false;
@@ -47,7 +47,7 @@ bindGetCb(const GetCallbackSimple& cb)
}
ValueCallback
bindValueCb(const ValueCallbackRaw& raw_cb, void* user_data)
bindValueCb(ValueCallbackRaw raw_cb, void* user_data)
{
if (not raw_cb) return {};
return [=](const std::vector<std::shared_ptr<Value>>& values, bool expired) {
@@ -59,7 +59,7 @@ bindValueCb(const ValueCallbackRaw& raw_cb, void* user_data)
}
ShutdownCallback
bindShutdownCb(const ShutdownCallbackRaw& shutdown_cb_raw, void* user_data)
bindShutdownCb(ShutdownCallbackRaw shutdown_cb_raw, void* user_data)
{
return [=]() { shutdown_cb_raw(user_data); };
}
@@ -69,11 +69,11 @@ bindDoneCb(DoneCallbackSimple donecb)
{
if (not donecb) return {};
using namespace std::placeholders;
return std::bind(donecb, _1);
return std::bind(std::move(donecb), _1);
}
DoneCallback
bindDoneCb(const DoneCallbackRaw& raw_cb, void* user_data)
bindDoneCb(DoneCallbackRaw raw_cb, void* user_data)
{
if (not raw_cb) return {};
return [=](bool success, const std::vector<std::shared_ptr<Node>>& nodes) {
@@ -82,7 +82,7 @@ bindDoneCb(const DoneCallbackRaw& raw_cb, void* user_data)
}
DoneCallbackSimple
bindDoneCbSimple(const DoneCallbackSimpleRaw& raw_cb, void* user_data) {
bindDoneCbSimple(DoneCallbackSimpleRaw raw_cb, void* user_data) {
if (not raw_cb) return {};
return [=](bool success) {
raw_cb(success, user_data);
+33 -51
View File
@@ -27,34 +27,20 @@
#endif
#include <openssl/ssl.h>
#ifdef __APPLE__
#ifdef TARGET_OS_OSX
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
#endif /*__APPLE__*/
#endif /*TARGET_OS_OSX*/
#ifdef _WIN32
#if EMBEDDED_ASN1_TIME_PARSE
#undef X509_NAME
#undef OCSP_REQUEST
#undef OCSP_RESPONSE
#define GENTIME_LENGTH 15
#define UTCTIME_LENGTH 13
#define ATOI2(ar) ((ar) += 2, ((ar)[-2] - '0') * 10 + ((ar)[-1] - '0'))
extern "C" {
// Taken from libressl/src/crypto/asn1/a_time_tm.c
/*
* Parse an RFC 5280 format ASN.1 time string.
*
* mode must be:
* 0 if we expect to parse a time as specified in RFC 5280 for an X509 object.
* V_ASN1_UTCTIME if we wish to parse an RFC5280 format UTC time.
* V_ASN1_GENERALIZEDTIME if we wish to parse an RFC5280 format Generalized time.
*
* Returns:
* -1 if the string was invalid.
* V_ASN1_UTCTIME if the string validated as a UTC time string.
* V_ASN1_GENERALIZEDTIME if the string validated as a Generalized time string.
*
* Fills in *tm with the corresponding time if tm is non NULL.
*/
int
ASN1_time_parse(const char* bytes, size_t len, struct tm* tm, int mode)
{
@@ -131,24 +117,17 @@ ASN1_time_parse(const char* bytes, size_t len, struct tm* tm, int mode)
return (-1);
}
return (type);
return type;
}
#endif /*_WIN32*/
}
#endif /* EMBEDDED_ASN1_TIME_PARSE */
namespace dht {
namespace http {
void
addSystemCaCertificates(SSL_CTX* ctx, const std::shared_ptr<Logger>& logger)
PEMCache::PEMCache(const std::shared_ptr<Logger>& l)
: logger(l)
{
X509_STORE* store = SSL_CTX_get_cert_store(ctx);
if (store == nullptr) {
if (logger)
logger->e("couldn't get the context cert store");
return;
}
X509* x509cert;
#ifdef _WIN32
PCCERT_CONTEXT pContext = NULL;
HCERTSTORE hSystemStore;
@@ -159,19 +138,13 @@ addSystemCaCertificates(SSL_CTX* ctx, const std::shared_ptr<Logger>& logger)
return;
}
while (pContext = CertEnumCertificatesInStore(hSystemStore, pContext)) {
x509cert = nullptr;
const uint8_t* encoded_cert = pContext->pbCertEncoded;
x509cert = d2i_X509(nullptr, &encoded_cert, pContext->cbCertEncoded);
if (x509cert) {
if (X509_STORE_add_cert(store, x509cert) == 1) {
if (logger)
logger->d("local certificate added");
}
X509_free(x509cert);
}
X509Ptr x509cert(d2i_X509(nullptr, &encoded_cert, pContext->cbCertEncoded), &X509_free);
if (x509cert)
pems_.emplace_back(std::move(x509cert));
}
CertCloseStore(hSystemStore, 0);
#elif __APPLE__
#elif TARGET_OS_OSX
CFArrayRef result = NULL;
OSStatus osStatus;
@@ -179,7 +152,7 @@ addSystemCaCertificates(SSL_CTX* ctx, const std::shared_ptr<Logger>& logger)
if (logger) {
CFStringRef statusString = SecCopyErrorMessageString(osStatus, NULL);
logger->d("Error enumerating certificates: %s",
CFStringGetCStringPtr(statusString, kCFStringEncodingASCII));
CFStringGetCStringPtr(statusString, kCFStringEncodingASCII));
CFRelease(statusString);
}
if (result != NULL) {
@@ -189,7 +162,6 @@ addSystemCaCertificates(SSL_CTX* ctx, const std::shared_ptr<Logger>& logger)
}
CFDataRef rawData = NULL;
for (CFIndex i = 0; i < CFArrayGetCount(result); i++) {
x509cert = nullptr;
SecCertificateRef cert = (SecCertificateRef) CFArrayGetValueAtIndex(result, i);
rawData = SecCertificateCopyData(cert);
if (!rawData) {
@@ -198,14 +170,9 @@ addSystemCaCertificates(SSL_CTX* ctx, const std::shared_ptr<Logger>& logger)
break;
}
const uint8_t* rawDataPtr = CFDataGetBytePtr(rawData);
x509cert = d2i_X509(nullptr, &rawDataPtr, CFDataGetLength(rawData));
if (x509cert) {
if (X509_STORE_add_cert(store, x509cert) == 1) {
if (logger)
logger->d("local certificate added");
}
X509_free(x509cert);
}
X509Ptr x509cert(d2i_X509(nullptr, &rawDataPtr, CFDataGetLength(rawData)), &X509_free);
if (x509cert)
pems_.emplace_back(std::move(x509cert));
CFRelease(rawData);
rawData = NULL;
}
@@ -215,7 +182,22 @@ addSystemCaCertificates(SSL_CTX* ctx, const std::shared_ptr<Logger>& logger)
if (rawData != NULL) {
CFRelease(rawData);
}
#endif /*__APPLE__, _WIN32*/
#endif /*TARGET_OS_OSX, _WIN32*/
}
void
PEMCache::fillX509Store(SSL_CTX* ctx)
{
if (logger)
logger->d("adding %d decoded certs to X509 store", pems_.size());
if (X509_STORE* store = SSL_CTX_get_cert_store(ctx)) {
for (const auto& pem : pems_) {
if (X509_STORE_add_cert(store, pem.get()) != 1)
if (logger)
logger->w("couldn't add local certificate");
}
} else if (logger)
logger->e("couldn't get the context cert store");
}
} /*namespace http*/
+47 -4
View File
@@ -24,15 +24,58 @@
#include <openssl/x509.h>
#ifdef _WIN32
#if (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER > 0x20501000L))
#define EMBEDDED_ASN1_TIME_PARSE 0
#else
#define EMBEDDED_ASN1_TIME_PARSE 1
#endif
#if EMBEDDED_ASN1_TIME_PARSE
#define V_ASN1_UTCTIME 23
#define V_ASN1_GENERALIZEDTIME 24
#define timegm _mkgmtime
extern "C" {
/*
* Parse an RFC 5280 format ASN.1 time string.
*
* mode must be:
* 0 if we expect to parse a time as specified in RFC 5280 for an X509 object.
* V_ASN1_UTCTIME if we wish to parse an RFC5280 format UTC time.
* V_ASN1_GENERALIZEDTIME if we wish to parse an RFC5280 format Generalized time.
*
* Returns:
* -1 if the string was invalid.
* V_ASN1_UTCTIME if the string validated as a UTC time string.
* V_ASN1_GENERALIZEDTIME if the string validated as a Generalized time string.
*
* Fills in *tm with the corresponding time if tm is non NULL.
*/
int ASN1_time_parse(const char* bytes, size_t len, struct tm* tm, int mode);
#endif /*_WIN32*/
}
#endif
namespace dht {
namespace http {
void addSystemCaCertificates(SSL_CTX* ctx, const std::shared_ptr<Logger>& logger);
// A singleton class used to cache the decoded certificates
// loaded from local cert stores that need to be added to the
// ssl context prior to each request.
class PEMCache
{
PEMCache(const std::shared_ptr<Logger>& l);
using X509Ptr = std::unique_ptr<X509, void(*)(X509*)>;
std::vector<X509Ptr> pems_;
std::shared_ptr<Logger> logger;
public:
static PEMCache& instance(const std::shared_ptr<Logger>& l)
{
static PEMCache instance_(l);
return instance_;
}
void fillX509Store(SSL_CTX* ctx);
};
}
} // namespace dht
+180 -121
View File
@@ -54,7 +54,7 @@ static std::uniform_int_distribution<uint8_t> rand_byte;
#define GNUTLS_PKCS_PBES2_AES_256 GNUTLS_PKCS_USE_PBES2_AES_256
#endif
#define DHT_AES_LEGACY_ENCRYPT 1
#define DHT_AES_LEGACY_ENCRYPT 0
#define DHT_AES_LEGACY_DECRYPT 1
namespace dht {
@@ -128,37 +128,37 @@ Blob aesEncrypt(const Blob& data, const std::string& password)
return encrypted;
}
Blob aesDecrypt(const Blob& data, const Blob& key)
Blob aesDecrypt(const uint8_t* data, size_t data_length, const Blob& key)
{
if (not aesKeySizeGood(key.size()))
throw DecryptError("Wrong key size");
if (data.size() <= GCM_IV_SIZE + GCM_DIGEST_SIZE)
if (data_length <= GCM_IV_SIZE + GCM_DIGEST_SIZE)
throw DecryptError("Wrong data size");
std::array<uint8_t, GCM_DIGEST_SIZE> digest;
struct gcm_aes_ctx aes;
gcm_aes_set_key(&aes, key.size(), key.data());
gcm_aes_set_iv(&aes, GCM_IV_SIZE, data.data());
gcm_aes_set_iv(&aes, GCM_IV_SIZE, data);
size_t data_sz = data.size() - GCM_IV_SIZE - GCM_DIGEST_SIZE;
size_t data_sz = data_length - GCM_IV_SIZE - GCM_DIGEST_SIZE;
Blob ret(data_sz);
gcm_aes_decrypt(&aes, data_sz, ret.data(), data.data() + GCM_IV_SIZE);
gcm_aes_decrypt(&aes, data_sz, ret.data(), data + GCM_IV_SIZE);
gcm_aes_digest(&aes, GCM_DIGEST_SIZE, digest.data());
if (not std::equal(digest.begin(), digest.end(), data.end() - GCM_DIGEST_SIZE)) {
if (not std::equal(digest.begin(), digest.end(), data + data_length - GCM_DIGEST_SIZE)) {
#if DHT_AES_LEGACY_DECRYPT
//gcm_aes_decrypt(&aes, data_sz, ret.data(), data.data() + GCM_IV_SIZE);
//gcm_aes_decrypt(&aes, data_sz, ret.data(), data + GCM_IV_SIZE);
Blob ret_tmp(data_sz);
struct gcm_aes_ctx aes_d;
gcm_aes_set_key(&aes_d, key.size(), key.data());
gcm_aes_set_iv(&aes_d, GCM_IV_SIZE, data.data());
gcm_aes_set_iv(&aes_d, GCM_IV_SIZE, data);
gcm_aes_update(&aes_d, ret.size(), ret.data());
gcm_aes_encrypt(&aes_d, ret.size(), ret_tmp.data(), ret.data());
gcm_aes_digest(&aes_d, GCM_DIGEST_SIZE, digest.data());
if (not std::equal(digest.begin(), digest.end(), data.end() - GCM_DIGEST_SIZE))
if (not std::equal(digest.begin(), digest.end(), data + data_length - GCM_DIGEST_SIZE))
throw DecryptError("Can't decrypt data");
#else
throw DecryptError("Can't decrypt data");
@@ -168,14 +168,13 @@ Blob aesDecrypt(const Blob& data, const Blob& key)
return ret;
}
Blob aesDecrypt(const Blob& data, const std::string& password)
Blob aesDecrypt(const uint8_t* data, size_t data_len, const std::string& password)
{
if (data.size() <= PASSWORD_SALT_LENGTH)
if (data_len <= PASSWORD_SALT_LENGTH)
throw DecryptError("Wrong data size");
Blob salt {data.begin(), data.begin()+PASSWORD_SALT_LENGTH};
Blob salt {data, data+PASSWORD_SALT_LENGTH};
Blob key = stretchKey(password, salt, 256/8);
Blob encrypted {data.begin()+PASSWORD_SALT_LENGTH, data.end()};
return aesDecrypt(encrypted, key);
return aesDecrypt(data+PASSWORD_SALT_LENGTH, data_len - PASSWORD_SALT_LENGTH, key);
}
Blob stretchKey(const std::string& password, Blob& salt, size_t key_length)
@@ -292,14 +291,14 @@ PrivateKey::operator=(PrivateKey&& o) noexcept
}
Blob
PrivateKey::sign(const Blob& data) const
PrivateKey::sign(const uint8_t* data, size_t data_length) const
{
if (!key)
throw CryptoException("Can't sign data: no private key set !");
if (std::numeric_limits<unsigned>::max() < data.size())
if (std::numeric_limits<unsigned>::max() < data_length)
throw CryptoException("Can't sign data: too large !");
gnutls_datum_t sig;
const gnutls_datum_t dat {(unsigned char*)data.data(), (unsigned)data.size()};
const gnutls_datum_t dat {(unsigned char*)data, (unsigned)data_length};
if (gnutls_privkey_sign_data(key, GNUTLS_DIG_SHA512, 0, &dat, &sig) != GNUTLS_E_SUCCESS)
throw CryptoException("Can't sign data !");
Blob ret(sig.data, sig.data+sig.size);
@@ -321,7 +320,7 @@ PrivateKey::decryptBloc(const uint8_t* src, size_t src_size) const
}
Blob
PrivateKey::decrypt(const Blob& cipher) const
PrivateKey::decrypt(const uint8_t* cypher, size_t cypher_len) const
{
if (!key)
throw CryptoException("Can't decrypt data without private key !");
@@ -334,12 +333,12 @@ PrivateKey::decrypt(const Blob& cipher) const
throw CryptoException("Must be an RSA key");
unsigned cypher_block_sz = key_len / 8;
if (cipher.size() < cypher_block_sz)
if (cypher_len < cypher_block_sz)
throw DecryptError("Unexpected cipher length");
else if (cipher.size() == cypher_block_sz)
return decryptBloc(cipher.data(), cypher_block_sz);
else if (cypher_len == cypher_block_sz)
return decryptBloc(cypher, cypher_block_sz);
return aesDecrypt(Blob {cipher.begin() + cypher_block_sz, cipher.end()}, decryptBloc(cipher.data(), cypher_block_sz));
return aesDecrypt(cypher + cypher_block_sz, cypher_len - cypher_block_sz, decryptBloc(cypher, cypher_block_sz));
}
Blob
@@ -369,13 +368,22 @@ PrivateKey::serialize(uint8_t* out, size_t* out_len, const std::string& password
: gnutls_x509_privkey_export_pkcs8(x509_key, GNUTLS_X509_FMT_PEM, password.c_str(), GNUTLS_PKCS_PBES2_AES_256, out, out_len);
}
PublicKey
const PublicKey&
PrivateKey::getPublicKey() const
{
PublicKey pk;
if (auto err = gnutls_pubkey_import_privkey(pk.pk, key, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN, 0))
return *getSharedPublicKey();
}
const std::shared_ptr<PublicKey>&
PrivateKey::getSharedPublicKey() const
{
if (publicKey_)
return publicKey_;
auto pk = std::make_shared<PublicKey>();
if (auto err = gnutls_pubkey_import_privkey(pk->pk, key, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN, 0))
throw CryptoException(std::string("Can't retreive public key: ") + gnutls_strerror(err));
return pk;
publicKey_ = pk;
return publicKey_;
}
PublicKey::PublicKey()
@@ -541,12 +549,7 @@ PublicKey::getId() const
return {};
InfoHash id;
size_t sz = id.size();
#if GNUTLS_VERSION_NUMBER < 0x030401
const int flags = 0;
#else
const int flags = (id.size() == 32) ? GNUTLS_KEYID_USE_SHA256 : 0;
#endif
if (auto err = gnutls_pubkey_get_key_id(pk, flags, id.data(), &sz))
if (auto err = gnutls_pubkey_get_key_id(pk, 0, id.data(), &sz))
throw CryptoException(std::string("Can't get public key ID: ") + gnutls_strerror(err));
if (sz != id.size())
throw CryptoException("Can't get public key ID: wrong output length.");
@@ -711,13 +714,13 @@ CertificateRequest::sign(const PrivateKey& key, const std::string& password)
}
bool
CertificateRequest::verify() const
CertificateRequest::verify() const
{
return gnutls_x509_crq_verify(request, 0) >= 0;
}
Blob
CertificateRequest::pack() const
Blob
CertificateRequest::pack() const
{
gnutls_datum_t dat {nullptr, 0};
if (auto err = gnutls_x509_crq_export2(request, GNUTLS_X509_FMT_PEM, &dat))
@@ -728,7 +731,7 @@ CertificateRequest::pack() const
}
std::string
CertificateRequest::toString() const
CertificateRequest::toString() const
{
gnutls_datum_t dat {nullptr, 0};
if (auto err = gnutls_x509_crq_export2(request, GNUTLS_X509_FMT_PEM, &dat))
@@ -1034,7 +1037,7 @@ Certificate::getPreferredDigest() const
return getPublicKey().getPreferredDigest();
}
std::pair<Blob,Blob>
std::pair<std::string, Blob>
Certificate::generateOcspRequest(gnutls_x509_crt_t& issuer)
{
gnutls_ocsp_req_t rreq;
@@ -1042,10 +1045,10 @@ Certificate::generateOcspRequest(gnutls_x509_crt_t& issuer)
if (err < 0)
throw CryptoException(gnutls_strerror(err));
std::unique_ptr<struct gnutls_ocsp_req_int, decltype(&gnutls_ocsp_req_deinit)> req(rreq, &gnutls_ocsp_req_deinit);
err = gnutls_ocsp_req_add_cert(req.get(), GNUTLS_DIG_SHA512, issuer, cert);
err = gnutls_ocsp_req_add_cert(req.get(), GNUTLS_DIG_SHA1, issuer, cert);
if (err < 0)
throw CryptoException(gnutls_strerror(err));
Blob noncebuf(64);
Blob noncebuf(32);
gnutls_datum_t nonce = { noncebuf.data(), (unsigned)noncebuf.size() };
err = gnutls_rnd(GNUTLS_RND_NONCE, nonce.data, nonce.size);
err = gnutls_ocsp_req_set_nonce(req.get(), 0, &nonce);
@@ -1055,9 +1058,9 @@ Certificate::generateOcspRequest(gnutls_x509_crt_t& issuer)
err = gnutls_ocsp_req_export(req.get(), &rdata);
if (err != 0)
throw CryptoException(gnutls_strerror(err));
Blob ret(rdata.data, rdata.data + rdata.size);
std::string ret((char*)rdata.data, (char*)rdata.data + rdata.size);
gnutls_free(rdata.data);
return std::make_pair<Blob,Blob>(std::move(ret), std::move(noncebuf));
return std::make_pair<std::string, Blob>(std::move(ret), std::move(noncebuf));
}
// PrivateKey
@@ -1148,8 +1151,8 @@ void
setRandomSerial(gnutls_x509_crt_t cert)
{
random_device rdev;
std::uniform_int_distribution<uint64_t> dist{};
uint64_t cert_serial = dist(rdev);
std::uniform_int_distribution<int64_t> dist{1};
int64_t cert_serial = dist(rdev);
gnutls_x509_crt_set_serial(cert, &cert_serial, sizeof(cert_serial));
}
@@ -1162,17 +1165,15 @@ Certificate::generate(const PrivateKey& key, const std::string& name, const Iden
Certificate ret {cert};
setValidityPeriod(cert, 10 * 365 * 24 * 60 * 60);
if (gnutls_x509_crt_set_key(cert, key.x509_key) != GNUTLS_E_SUCCESS) {
std::cerr << "Error when setting certificate key" << std::endl;
return {};
if (int err = gnutls_x509_crt_set_key(cert, key.x509_key)) {
throw CryptoException(std::string("Error when setting certificate key ") + gnutls_strerror(err));
}
if (gnutls_x509_crt_set_version(cert, 3) != GNUTLS_E_SUCCESS) {
std::cerr << "Error when setting certificate version" << std::endl;
return {};
if (int err = gnutls_x509_crt_set_version(cert, 3)) {
throw CryptoException(std::string("Error when setting certificate version ") + gnutls_strerror(err));
}
// TODO: compute the subject key using the recommended RFC method
auto pk = key.getPublicKey();
const auto& pk = key.getPublicKey();
auto pk_id = pk.getId();
const std::string uid_str = pk_id.toString();
@@ -1193,18 +1194,15 @@ Certificate::generate(const PrivateKey& key, const std::string& name, const Iden
if (ca.first && ca.second) {
if (not ca.second->isCA()) {
// Signing certificate must be CA.
return {};
throw CryptoException("Signing certificate must be CA");
}
if (gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, pk.getPreferredDigest(), 0) != GNUTLS_E_SUCCESS) {
std::cerr << "Error when signing certificate" << std::endl;
return {};
if (int err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, pk.getPreferredDigest(), 0)) {
throw CryptoException(std::string("Error when signing certificate ") + gnutls_strerror(err));
}
ret.issuer = ca.second;
} else {
if (gnutls_x509_crt_privkey_sign(cert, cert, key.key, pk.getPreferredDigest(), 0) != GNUTLS_E_SUCCESS) {
std::cerr << "Error when signing certificate" << std::endl;
return {};
if (int err = gnutls_x509_crt_privkey_sign(cert, cert, key.key, pk.getPreferredDigest(), 0)) {
throw CryptoException(std::string("Error when signing certificate ") + gnutls_strerror(err));
}
}
@@ -1246,6 +1244,70 @@ Certificate::getRevocationLists() const
return ret;
}
// OcspRequest
OcspRequest::OcspRequest(const uint8_t* dat_ptr, size_t dat_size)
{
int ret = gnutls_ocsp_req_init(&request);
if (ret < 0)
throw CryptoException(gnutls_strerror(ret));
gnutls_datum_t dat = {(unsigned char*)dat_ptr,(unsigned int)dat_size};
ret = gnutls_ocsp_req_import(request, &dat);
if (ret < 0){
gnutls_ocsp_req_deinit(request);
throw CryptoException(gnutls_strerror(ret));
}
}
OcspRequest::~OcspRequest()
{
if (request) {
gnutls_ocsp_req_deinit(request);
request = nullptr;
}
}
std::string
OcspRequest::toString(const bool compact) const
{
int ret;
gnutls_datum_t dat;
ret = gnutls_ocsp_req_print(request, compact ? GNUTLS_OCSP_PRINT_COMPACT : GNUTLS_OCSP_PRINT_FULL, &dat);
std::string str;
if (ret == 0) {
str = std::string((const char*)dat.data, (size_t)dat.size);
gnutls_free(dat.data);
} else
throw CryptoException(gnutls_strerror(ret));
return str;
}
Blob
OcspRequest::pack() const
{
gnutls_datum_t dat;
int err = gnutls_ocsp_req_export(request, &dat);
if (err < 0)
throw CryptoException(gnutls_strerror(err));
Blob ret {dat.data, dat.data + dat.size};
gnutls_free(dat.data);
return ret;
}
Blob
OcspRequest::getNonce() const
{
gnutls_datum_t dat;
unsigned critical;
int err = gnutls_ocsp_req_get_nonce(request, &critical, &dat);
if (err < 0)
throw CryptoException(gnutls_strerror(err));
Blob ret {dat.data, dat.data + dat.size};
gnutls_free(dat.data);
return ret;
}
// OcspResponse
OcspResponse::OcspResponse(const uint8_t* dat_ptr, size_t dat_size)
@@ -1270,10 +1332,12 @@ Blob
OcspResponse::pack() const
{
gnutls_datum_t dat;
int ret = gnutls_ocsp_resp_export(response, &dat);
if (ret < 0)
throw CryptoException(gnutls_strerror(ret));
return {dat.data, dat.data + dat.size};
int err = gnutls_ocsp_resp_export(response, &dat);
if (err < 0)
throw CryptoException(gnutls_strerror(err));
Blob ret {dat.data, dat.data + dat.size};
gnutls_free(dat.data);
return ret;
}
std::string
@@ -1303,68 +1367,63 @@ OcspResponse::getCertificateStatus() const
return (gnutls_ocsp_cert_status_t) status;
}
gnutls_ocsp_verify_reason_t
gnutls_ocsp_cert_status_t
OcspResponse::verifyDirect(const Certificate& crt, const Blob& nonce)
{
// https://www.gnutls.org/manual/html_node/Error-codes.html
int ret = -1;
// http://www.gnu.org/software/gnutls/reference/gnutls-ocsp.html#gnutls-ocsp-verify-reason-t
unsigned int verify = 0;
// http://www.gnu.org/software/gnutls/reference/gnutls-ocsp.html#gnutls-ocsp-cert-status-t
unsigned int status = 6; // by default assume GNUTLS_OCSP_RESP_UNAUTHORIZED
#if GNUTLS_VERSION_NUMBER >= 0x030103
/*
* This function will check whether the OCSP response is about the provided certificate.
* index: Specifies response number to get. Use (0) to get the first one.
*/
if ((ret = gnutls_ocsp_resp_check_crt(response, 0, crt.cert)) < 0)
goto end;
#endif
/*
* Verify signature of the Basic OCSP Response against the public key in the issuer certificate.
* http://www.gnu.org/software/gnutls/reference/gnutls-ocsp.html#gnutls-ocsp-resp-verify-direct
*/
ret = gnutls_ocsp_resp_verify_direct(response, crt.issuer->cert /*signer*/, &verify, 0);
// Check OCSP response
int ret = gnutls_ocsp_resp_get_status(response);
if (ret < 0)
goto end;
ret = gnutls_ocsp_resp_check_crt(response, 0 /*index*/, crt.cert);
if (ret < 0)
goto end;
/*
* This function will return the certificate information of the indx'ed response in the
* Basic OCSP Response resp. The information returned corresponds to the OCSP SingleResponse
* structure except the final singleExtensions.
* http://www.gnu.org/software/gnutls/reference/gnutls-ocsp.html#gnutls-ocsp-resp-get-single
*/
ret = gnutls_ocsp_resp_get_single(response, 0, NULL, NULL, NULL, NULL, &status, NULL, NULL, NULL, NULL);
if (ret < 0)
goto end;
gnutls_datum_t rnonce;
/*
* This function will return the Basic OCSP Response nonce extension data.
*/
ret = gnutls_ocsp_resp_get_nonce(response, NULL, &rnonce);
if (ret < 0)
goto end;
// Ensure no replay attack has been done
if (rnonce.size != nonce.size() || memcmp(nonce.data(), rnonce.data, nonce.size()) != 0){
ret = GNUTLS_E_OCSP_RESPONSE_ERROR;
goto end;
}
end:
/*
* OCSP validation outcome based on interogative aspects
*/
if (ret != GNUTLS_E_SUCCESS)
throw CryptoException(gnutls_strerror(ret));
else if (status != GNUTLS_OCSP_CERT_GOOD)
if (status == GNUTLS_OCSP_CERT_REVOKED)
throw CryptoException("Certificate was revoked");
else
throw CryptoException("Certificate is unknown");
else
return (gnutls_ocsp_verify_reason_t) verify;
gnutls_ocsp_resp_status_t status = (gnutls_ocsp_resp_status_t)ret;
if (status != GNUTLS_OCSP_RESP_SUCCESSFUL)
throw CryptoException("OCSP request unsuccessful: " + std::to_string(ret));
if (not nonce.empty()) {
// Ensure no replay attack has been done
gnutls_datum_t rnonce;
ret = gnutls_ocsp_resp_get_nonce(response, NULL, &rnonce);
if (ret < 0)
throw CryptoException(gnutls_strerror(ret));
if (rnonce.size != nonce.size() || memcmp(nonce.data(), rnonce.data, nonce.size()) != 0){
gnutls_free(rnonce.data);
throw CryptoException(gnutls_strerror(GNUTLS_E_OCSP_RESPONSE_ERROR));
}
gnutls_free(rnonce.data);
}
// Verify signature of the Basic OCSP response against the public key in the issuer certificate.
unsigned int verify = 0;
ret = gnutls_ocsp_resp_verify_direct(response, crt.issuer->cert, &verify, 0);
if (ret < 0)
throw CryptoException(gnutls_strerror(ret));
if (verify) {
if (verify & GNUTLS_OCSP_VERIFY_SIGNER_NOT_FOUND)
throw CryptoException("Signer cert not found");
if (verify & GNUTLS_OCSP_VERIFY_SIGNER_KEYUSAGE_ERROR)
throw CryptoException("Signer cert keyusage error");
if (verify & GNUTLS_OCSP_VERIFY_UNTRUSTED_SIGNER)
throw CryptoException("Signer cert is not trusted");
if (verify & GNUTLS_OCSP_VERIFY_INSECURE_ALGORITHM)
throw CryptoException("Insecure algorithm");
if (verify & GNUTLS_OCSP_VERIFY_SIGNATURE_FAILURE)
throw CryptoException("Signature failure");
if (verify & GNUTLS_OCSP_VERIFY_CERT_NOT_ACTIVATED)
throw CryptoException("Signer cert not yet activated");
if (verify & GNUTLS_OCSP_VERIFY_CERT_EXPIRED)
throw CryptoException("Signer cert expired");
throw CryptoException(gnutls_strerror(GNUTLS_E_OCSP_RESPONSE_ERROR));
}
// Check whether the OCSP response is about the provided certificate.
if ((ret = gnutls_ocsp_resp_check_crt(response, 0, crt.cert)) < 0)
throw CryptoException(gnutls_strerror(ret));
// Check certificate revocation status
unsigned status_ocsp;
ret = gnutls_ocsp_resp_get_single(response, 0, NULL, NULL, NULL, NULL, &status_ocsp, NULL, NULL, NULL, NULL);
if (ret < 0)
throw CryptoException(gnutls_strerror(ret));
return (gnutls_ocsp_cert_status_t)status_ocsp;
}
// RevocationList
+67 -20
View File
@@ -30,6 +30,8 @@
#include <sstream>
#include <fstream>
#include <inttypes.h>
namespace dht {
using namespace std::placeholders;
@@ -52,12 +54,7 @@ Dht::updateStatus(sa_family_t af)
if (other.status == NodeStatus::Disconnected && d.status == NodeStatus::Disconnected)
onDisconnected();
else if (other.status == NodeStatus::Connected || d.status == NodeStatus::Connected) {
// On connected
if (bootstrapJob) {
bootstrapJob->cancel();
bootstrapJob.reset();
}
bootstrap_period = std::chrono::seconds(10);
onConnected();
}
}
return d.status;
@@ -82,11 +79,27 @@ Dht::Kad::getStatus(time_point now) const
}
void
Dht::shutdown(ShutdownCallback cb)
Dht::shutdown(ShutdownCallback cb, bool stop)
{
if (not persistPath.empty())
saveState(persistPath);
if (stop) {
for (auto dht : {&dht4, &dht6}) {
for (auto& sr : dht->searches) {
for (const auto& r : sr.second->callbacks)
r.second.done_cb(false, {});
sr.second->callbacks.clear();
for (const auto& a : sr.second->announce) {
if (a.callback) a.callback(false, {});
}
sr.second->announce.clear();
sr.second->listeners.clear();
}
}
network_engine.clear();
}
if (not maintain_storage) {
if (cb) cb();
return;
@@ -478,7 +491,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr) {
/* only put the value if the node doesn't already have it */
if (not hasValue or seq_no < a.value->seq) {
if (logger_)
logger_->d(sr->id, sn->node->id, "[search %s] [node %s] sending 'put' (vid: %d)",
logger_->d(sr->id, sn->node->id, "[search %s] [node %s] sending 'put' (vid: %016" PRIx64 ")",
sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id);
auto created = a.permanent ? time_point::max() : a.created;
sn->acked[a.value->id] = {
@@ -487,13 +500,13 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr) {
};
} else if (hasValue and a.permanent) {
if (logger_)
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] sending 'refresh' (vid: %d)",
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] sending 'refresh' (vid: %016" PRIx64 ")",
sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id);
sn->acked[a.value->id] = {
network_engine.sendRefreshValue(sn->node, sr->id, a.value->id, sn->token, onDone,
[this, ws, node=sn->node, v=a.value,
onDone,
onExpired,
[this, ws, node=sn->node, v=a.value,
onDone,
onExpired,
created = a.permanent ? time_point::max() : a.created,
next_refresh_time
](const net::Request& /*req*/, net::DhtProtocolException&& e){
@@ -517,7 +530,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr) {
};
} else {
if (logger_)
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] already has value (vid: %d). Aborting.",
logger_->w(sr->id, sn->node->id, "[search %s] [node %s] already has value (vid: %016" PRIx64 "). Aborting.",
sr->id.toString().c_str(), sn->node->toString().c_str(), a.value->id);
auto ack_req = std::make_shared<net::Request>(net::Request::State::COMPLETED);
ack_req->reply_time = now;
@@ -556,7 +569,7 @@ void Dht::searchSendAnnounceValue(const Sp<Search>& sr) {
sendQuery = true;
} else {
if (logger_)
logger_->w(sr->id, n.node->id, "[search %s] [node %s] sending 'put' (vid: %d)",
logger_->w(sr->id, n.node->id, "[search %s] [node %s] sending 'put' (vid: %016" PRIx64 ")",
sr->id.toString().c_str(), n.node->toString().c_str(), a.value->id);
n.acked[a.value->id] = {
network_engine.sendAnnounceValue(n.node, sr->id, a.value, a.created, n.token, onDone, onExpired),
@@ -591,7 +604,7 @@ Dht::searchSynchedNodeListen(const Sp<Search>& sr, SearchNode& n)
std::weak_ptr<Search> ws = sr;
for (const auto& l : sr->listeners) {
const auto& query = l.second.query;
auto r = n.listenStatus.find(query);
if (n.getListenTime(r, listenExp) > scheduler.time())
continue;
@@ -725,7 +738,7 @@ Dht::searchStep(Sp<Search> sr)
while (sr->currentlySolicitedNodeCount() < MAX_REQUESTED_SEARCH_NODES and searchSendGetValues(sr));
if (sr->getNumberOfConsecutiveBadNodes() >= std::min<size_t>(sr->nodes.size(), SEARCH_MAX_BAD_NODES))
{
if (logger_)
@@ -862,6 +875,11 @@ Dht::listenTo(const InfoHash& id, sa_family_t af, ValueCallback cb, Value::Filte
size_t
Dht::listen(const InfoHash& id, ValueCallback cb, Value::Filter f, Where where)
{
if (not id) {
if (logger_)
logger_->w(id, "Listen called with invalid key");
return 0;
}
scheduler.syncTime();
auto token = ++listener_token;
@@ -944,7 +962,9 @@ struct GetStatus : public OpStatus {
void
Dht::put(const InfoHash& id, Sp<Value> val, DoneCallback callback, time_point created, bool permanent)
{
if (not val) {
if (not id or not val) {
if (logger_)
logger_->w(id, "Put called with invalid key or value");
if (callback)
callback(false, {});
return;
@@ -1014,6 +1034,13 @@ bool callbackWrapper(Cb get_cb, DoneCallback done_cb, const std::vector<Sp<T>>&
void
Dht::get(const InfoHash& id, GetCallback getcb, DoneCallback donecb, Value::Filter&& filter, Where&& where)
{
if (not id) {
if (logger_)
logger_->w(id, "Get called with invalid key");
if (donecb)
donecb(false, {});
return;
}
scheduler.syncTime();
auto op = std::make_shared<GetStatus<std::map<Value::Id, Sp<Value>>>>();
@@ -1054,6 +1081,13 @@ Dht::get(const InfoHash& id, GetCallback getcb, DoneCallback donecb, Value::Filt
void Dht::query(const InfoHash& id, QueryCallback cb, DoneCallback done_cb, Query&& q)
{
if (not id) {
if (logger_)
logger_->w(id, "Query called with invalid key");
if (done_cb)
done_cb(false, {});
return;
}
scheduler.syncTime();
auto op = std::make_shared<GetStatus<std::vector<Sp<FieldValueIndex>>>>();
auto f = q.where.getFilter();
@@ -1747,8 +1781,6 @@ fromDhtConfig(const Config& config)
return netConf;
}
Dht::Dht() : store(), network_engine(logger_, rd, scheduler, {}) {}
Dht::Dht(std::unique_ptr<net::DatagramSocket>&& sock, const Config& config, const Sp<Logger>& l)
: DhtInterface(l),
myid(config.node_id ? config.node_id : InfoHash::getRandom(rd)),
@@ -1983,6 +2015,21 @@ Dht::expire()
scheduler.add(expire_stuff_time, std::bind(&Dht::expire, this));
}
void
Dht::onConnected()
{
if (bootstrapJob) {
bootstrapJob->cancel();
bootstrapJob.reset();
}
bootstrap_period = std::chrono::seconds(10);
auto callbacks = std::move(onConnectCallbacks_);
while (not callbacks.empty()) {
callbacks.front()();
callbacks.pop();
}
}
void
Dht::onDisconnected()
{
@@ -2528,7 +2575,7 @@ Dht::saveState(const std::string& path) const
state.nodes = exportNodes();
state.values = exportValues();
std::ofstream file(path);
msgpack::pack(file, state);
msgpack::pack(file, state);
}
void
+14 -13
View File
@@ -155,10 +155,10 @@ DhtProxyClient::startProxy()
if (logger_)
logger_->d("[proxy:client] start proxy with %s", proxyUrl_.c_str());
nextProxyConfirmationTimer_ = std::make_shared<asio::steady_timer>(httpContext_, std::chrono::steady_clock::now());
nextProxyConfirmationTimer_ = std::make_unique<asio::steady_timer>(httpContext_, std::chrono::steady_clock::now());
nextProxyConfirmationTimer_->async_wait(std::bind(&DhtProxyClient::handleProxyConfirm, this, std::placeholders::_1));
listenerRestartTimer_ = std::make_shared<asio::steady_timer>(httpContext_);
listenerRestartTimer_ = std::make_unique<asio::steady_timer>(httpContext_);
loopSignal_();
}
@@ -242,7 +242,7 @@ DhtProxyClient::cancelAllListeners()
}
void
DhtProxyClient::shutdown(ShutdownCallback cb)
DhtProxyClient::shutdown(ShutdownCallback cb, bool)
{
stop();
if (cb)
@@ -636,6 +636,8 @@ DhtProxyClient::queryProxyInfo(const Sp<InfoState>& infoState, const Sp<http::Re
logger_->d("[proxy:client] [status] query ipv%i info", family == AF_INET ? 4 : 6);
try {
auto request = std::make_shared<http::Request>(httpContext_, resolver, family);
if (serverCertificate_)
request->set_certificate_authority(serverCertificate_);
auto reqid = request->id();
request->set_method(restinio::http_method_get());
setHeaderFields(*request);
@@ -721,6 +723,15 @@ DhtProxyClient::onProxyInfos(const Json::Value& proxyInfos, const sa_family_t fa
if (oldStatus == NodeStatus::Disconnected || oldStatus == NodeStatus::Connecting) {
listenerRestartTimer_->expires_at(std::chrono::steady_clock::now());
listenerRestartTimer_->async_wait(std::bind(&DhtProxyClient::restartListeners, this, std::placeholders::_1));
if (not onConnectCallbacks_.empty()) {
std::lock_guard<std::mutex> lock(lockCallbacks_);
callbacks_.emplace_back([cbs = std::move(onConnectCallbacks_)]() mutable {
while (not cbs.empty()) {
cbs.front()();
cbs.pop();
}
});
}
}
nextProxyConfirmationTimer_->expires_at(std::chrono::steady_clock::now() + std::chrono::minutes(15));
nextProxyConfirmationTimer_->async_wait(std::bind(&DhtProxyClient::handleProxyConfirm, this, std::placeholders::_1));
@@ -818,13 +829,8 @@ DhtProxyClient::listen(const InfoHash& key, ValueCallback cb, Value::Filter filt
restinio::http_request_header_t header;
if (deviceKey_.empty()){ // listen
method = ListenMethod::LISTEN;
#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK
header.method(restinio::method_listen);
header.request_target("/" + key.toString());
#else
header.method(restinio::http_method_get());
header.request_target("/key/" + key.toString() + "/listen");
#endif
}
else {
method = ListenMethod::SUBSCRIBE;
@@ -1140,13 +1146,8 @@ DhtProxyClient::restartListeners(const asio::error_code &ec)
auto cb = listener.cb;
// define header
restinio::http_request_header_t header;
#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK
header.method(restinio::method_listen);
header.request_target("/" + search.first.toString());
#else
header.method(restinio::http_method_get());
header.request_target("/key/" + search.first.toString() + "/listen");
#endif
sendListen(header, cb, opstate, listener, ListenMethod::LISTEN);
}
}
+1 -45
View File
@@ -39,26 +39,6 @@
using namespace std::placeholders;
using namespace std::chrono_literals;
#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK
namespace restinio {
struct custom_http_methods_t
{
static constexpr restinio::http_method_id_t from_nodejs(int m) noexcept {
if(m == method_listen.raw_id())
return method_listen;
else if(m == method_stats.raw_id())
return method_stats;
else if(m == method_sign.raw_id())
return method_sign;
else if(m == method_encrypt.raw_id())
return method_encrypt;
else
return restinio::default_http_methods_t::from_nodejs(m);
}
};
}
#endif
namespace dht {
constexpr char RESP_MSG_JSON_INCORRECT[] = "{\"err:\":\"Incorrect JSON\"}";
constexpr char RESP_MSG_SERVICE_UNAVAILABLE[] = "{\"err\":\"Incorrect DhtRunner\"}";
@@ -156,9 +136,6 @@ DhtProxyServer::onConnectionClosed(restinio::connection_id_t id)
struct DhtProxyServer::RestRouterTraitsTls : public restinio::default_tls_traits_t
{
using timer_manager_t = restinio::asio_timer_manager_t;
#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK
using http_methods_mapper_t = restinio::custom_http_methods_t;
#endif
using logger_t = opendht_logger_t;
using request_handler_t = RestRouter;
using connection_state_listener_t = ConnectionListener;
@@ -166,9 +143,6 @@ struct DhtProxyServer::RestRouterTraitsTls : public restinio::default_tls_traits
struct DhtProxyServer::RestRouterTraits : public restinio::default_traits_t
{
using timer_manager_t = restinio::asio_timer_manager_t;
#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK
using http_methods_mapper_t = restinio::custom_http_methods_t;
#endif
using logger_t = opendht_logger_t;
using request_handler_t = RestRouter;
using connection_state_listener_t = ConnectionListener;
@@ -613,11 +587,6 @@ DhtProxyServer::createRestRouter()
// **************************** LEGACY ROUTES ****************************
// node.info
router->http_get("/", std::bind(&DhtProxyServer::getNodeInfo, this, _1, _2));
#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK
// node.stats
router->add_handler(restinio::custom_http_methods_t::from_nodejs(restinio::method_stats.raw_id()),
"/", std::bind(&DhtProxyServer::getStats, this, _1, _2));
#endif
// key.options
router->add_handler(restinio::http_method_options(),
"/:hash", std::bind(&DhtProxyServer::options, this, _1, _2));
@@ -625,11 +594,6 @@ DhtProxyServer::createRestRouter()
router->http_get("/:hash", std::bind(&DhtProxyServer::get, this, _1, _2));
// key.post
router->http_post("/:hash", std::bind(&DhtProxyServer::put, this, _1, _2));
#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK
// key.listen
router->add_handler(restinio::custom_http_methods_t::from_nodejs(restinio::method_listen.raw_id()),
"/:hash", std::bind(&DhtProxyServer::listen, this, _1, _2));
#endif
#ifdef OPENDHT_PUSH_NOTIFICATIONS
// key.subscribe
router->add_handler(restinio::http_method_subscribe(),
@@ -639,14 +603,6 @@ DhtProxyServer::createRestRouter()
"/:hash", std::bind(&DhtProxyServer::unsubscribe, this, _1, _2));
#endif //OPENDHT_PUSH_NOTIFICATIONS
#ifdef OPENDHT_PROXY_SERVER_IDENTITY
#ifdef OPENDHT_PROXY_HTTP_PARSER_FORK
// key.sign
router->add_handler(restinio::custom_http_methods_t::from_nodejs(restinio::method_sign.raw_id()),
"/:hash", std::bind(&DhtProxyServer::putSigned, this, _1, _2));
// key.encrypt
router->add_handler(restinio::custom_http_methods_t::from_nodejs(restinio::method_encrypt.raw_id()),
"/:hash", std::bind(&DhtProxyServer::putEncrypted, this, _1, _2));
#endif
#endif // OPENDHT_PROXY_SERVER_IDENTITY
// **************************** NEW ROUTES ****************************
@@ -822,7 +778,7 @@ DhtProxyServer::subscribe(restinio::request_handle_t request,
logger_->d("[proxy:server] [subscribe %s] [client %s] [session %s]", infoHash.toString().c_str(), clientId.c_str(), sessionId.c_str());
// Insert new or return existing push listeners of a token
std::lock_guard<std::mutex> lock(lockPushListeners_);
std::lock_guard<std::mutex> lock(lockListener_);
auto& pushListener = pushListeners_[pushToken];
auto& pushListeners = pushListener.listeners[infoHash];
+139 -72
View File
@@ -76,19 +76,17 @@ DhtRunner::~DhtRunner()
}
void
DhtRunner::run(in_port_t port, const Config& config, Context&& context)
DhtRunner::run(in_port_t port, Config& config, Context&& context)
{
SockAddr sin4;
sin4.setFamily(AF_INET);
sin4.setPort(port);
SockAddr sin6;
sin6.setFamily(AF_INET6);
sin6.setPort(port);
run(sin4, sin6, config, std::move(context));
config.bind4.setFamily(AF_INET);
config.bind4.setPort(port);
config.bind6.setFamily(AF_INET6);
config.bind6.setPort(port);
run(config, std::move(context));
}
void
DhtRunner::run(const char* ip4, const char* ip6, const char* service, const Config& config, Context&& context)
DhtRunner::run(const char* ip4, const char* ip6, const char* service, Config& config, Context&& context)
{
auto res4 = SockAddr::resolve(ip4, service);
auto res6 = SockAddr::resolve(ip6, service);
@@ -96,44 +94,9 @@ DhtRunner::run(const char* ip4, const char* ip6, const char* service, const Conf
res4.emplace_back();
if (res6.empty())
res6.emplace_back();
run(res4.front(), res6.front(), config, std::move(context));
}
void
DhtRunner::run(SockAddr& local4, SockAddr& local6, const Config& config, Context&& context)
{
if (running == State::Idle) {
auto state_path = config.dht_config.node_config.persist_path;
if (not state_path.empty()) {
state_path += "_port.txt";
std::ifstream inConfig(state_path);
if (inConfig.is_open()) {
in_port_t port;
if (inConfig >> port) {
if (context.logger)
context.logger->d("[runner %p] Using IPv4 port %hu from saved configuration", this, port);
if (local4.getPort() == 0)
local4.setPort(port);
}
if (inConfig >> port) {
if (context.logger)
context.logger->d("[runner %p] Using IPv6 port %hu from saved configuration", this, port);
if (local6.getPort() == 0)
local6.setPort(port);
}
}
}
if (not context.sock)
context.sock.reset(new net::UdpSocket(local4, local6, context.logger));
if (not state_path.empty()) {
std::ofstream outConfig(state_path);
outConfig << context.sock->getBoundRef(AF_INET).getPort() << std::endl;
outConfig << context.sock->getBoundRef(AF_INET6).getPort() << std::endl;
}
run(config, std::move(context));
}
config.bind4 = std::move(res4.front());
config.bind6 = std::move(res6.front());
run(config, std::move(context));
}
void
@@ -141,8 +104,51 @@ DhtRunner::run(const Config& config, Context&& context)
{
std::lock_guard<std::mutex> lck(dht_mtx);
auto expected = State::Idle;
if (not running.compare_exchange_strong(expected, State::Running))
if (not running.compare_exchange_strong(expected, State::Running)) {
if (context.logger)
context.logger->w("[runner %p] Node is already running. Call join() first before calling run() again.");
return;
}
auto local4 = config.bind4;
auto local6 = config.bind6;
if (not local4 and not local6) {
if (context.logger)
context.logger->w("[runner %p] No address to bind specified in the configuration, using default addresses");
local4.setFamily(AF_INET);
local6.setFamily(AF_INET6);
}
auto state_path = config.dht_config.node_config.persist_path;
if (not state_path.empty() && (local4.getPort() == 0 || local6.getPort() == 0)) {
state_path += "_port.txt";
std::ifstream inConfig(state_path);
if (inConfig.is_open()) {
in_port_t port;
if (inConfig >> port) {
if (local4.getPort() == 0) {
if (context.logger)
context.logger->d("[runner %p] Using IPv4 port %hu from saved configuration", this, port);
local4.setPort(port);
}
}
if (inConfig >> port) {
if (local6.getPort() == 0) {
if (context.logger)
context.logger->d("[runner %p] Using IPv6 port %hu from saved configuration", this, port);
local6.setPort(port);
}
}
}
}
if (not context.sock)
context.sock.reset(new net::UdpSocket(local4, local6, context.logger));
if (not state_path.empty()) {
std::ofstream outConfig(state_path);
outConfig << context.sock->getBoundRef(AF_INET).getPort() << std::endl;
outConfig << context.sock->getBoundRef(AF_INET6).getPort() << std::endl;
}
if (context.logger) {
logger_ = context.logger;
@@ -167,12 +173,13 @@ DhtRunner::run(const Config& config, Context&& context)
return ret;
});
auto dht = std::unique_ptr<DhtInterface>(new Dht(std::move(context.sock), SecureDht::getConfig(config.dht_config), context.logger));
dht_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht), config.dht_config));
#ifdef OPENDHT_PROXY_CLIENT
config_ = config;
identityAnnouncedCb_ = context.identityAnnouncedCb;
#endif
auto dht = std::unique_ptr<DhtInterface>(new Dht(std::move(context.sock), SecureDht::getConfig(config.dht_config), context.logger));
dht_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht), config.dht_config, std::move(context.identityAnnouncedCb), context.logger));
enableProxy(not config.proxy_server.empty());
if (context.logger and dht_via_proxy_) {
dht_via_proxy_->setLogger(context.logger);
@@ -261,29 +268,31 @@ DhtRunner::run(const Config& config, Context&& context)
}
void
DhtRunner::shutdown(ShutdownCallback cb) {
DhtRunner::shutdown(ShutdownCallback cb, bool stop) {
std::unique_lock<std::mutex> lck(storage_mtx);
auto expected = State::Running;
if (not running.compare_exchange_strong(expected, State::Stopping)) {
if (expected == State::Stopping and ongoing_ops) {
std::lock_guard<std::mutex> lck(storage_mtx);
shutdownCallbacks_.emplace_back(std::move(cb));
}
else if (cb) cb();
else if (cb) {
lck.unlock();
cb();
}
return;
}
if (logger_)
logger_->d("[runner %p] state changed to Stopping, %zu ongoing ops", this, ongoing_ops.load());
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
shutdownCallbacks_.emplace_back(std::move(cb));
pending_ops_prio.emplace([=](SecureDht&) mutable {
pending_ops.emplace([=](SecureDht&) mutable {
auto onShutdown = [this]{ opEnded(); };
#ifdef OPENDHT_PROXY_CLIENT
if (dht_via_proxy_)
dht_via_proxy_->shutdown(onShutdown);
dht_via_proxy_->shutdown(onShutdown, stop);
#endif
if (dht_)
dht_->shutdown(onShutdown);
dht_->shutdown(onShutdown, stop);
});
cv.notify_all();
}
@@ -312,11 +321,11 @@ DhtRunner::bindOpDoneCallback(DoneCallbackSimple&& cb) {
bool
DhtRunner::checkShutdown() {
if (running != State::Stopping or ongoing_ops)
return false;
decltype(shutdownCallbacks_) cbs;
{
std::lock_guard<std::mutex> lck(storage_mtx);
if (running != State::Stopping or ongoing_ops)
return false;
cbs = std::move(shutdownCallbacks_);
}
for (auto& cb : cbs)
@@ -348,9 +357,13 @@ DhtRunner::join()
{
std::lock_guard<std::mutex> lck(storage_mtx);
if (ongoing_ops and logger_) {
logger_->w("[runner %p] stopping with %zu remaining ops", this, ongoing_ops.load());
}
pending_ops = decltype(pending_ops)();
pending_ops_prio = decltype(pending_ops_prio)();
ongoing_ops = 0;
shutdownCallbacks_.clear();
}
{
std::lock_guard<std::mutex> lck(dht_mtx);
@@ -393,6 +406,14 @@ DhtRunner::getId() const
return {};
}
std::shared_ptr<crypto::PublicKey>
DhtRunner::getPublicKey() const
{
if (auto dht = activeDht())
return dht->getPublicKey();
return {};
}
InfoHash
DhtRunner::getNodeId() const
{
@@ -593,6 +614,18 @@ DhtRunner::getPublicAddressStr(sa_family_t af)
return ret;
}
void
DhtRunner::getPublicAddress(std::function<void(std::vector<SockAddr>&&)> cb, sa_family_t af)
{
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops_prio.emplace([cb = std::move(cb), this, af](SecureDht& dht){
cb(dht.getPublicAddress(af));
opEnded();
});
cv.notify_all();
}
void
DhtRunner::registerCertificate(std::shared_ptr<crypto::Certificate> cert) {
std::lock_guard<std::mutex> lck(dht_mtx);
@@ -690,11 +723,12 @@ DhtRunner::loop_()
void
DhtRunner::get(InfoHash hash, GetCallback vcb, DoneCallback dcb, Value::Filter f, Where w)
{
std::unique_lock<std::mutex> lck(storage_mtx);
if (running != State::Running) {
lck.unlock();
if (dcb) dcb(false, {});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=](SecureDht& dht) mutable {
dht.get(hash, std::move(vcb), bindOpDoneCallback(std::move(dcb)), std::move(f), std::move(w));
@@ -709,11 +743,12 @@ DhtRunner::get(const std::string& key, GetCallback vcb, DoneCallbackSimple dcb,
}
void
DhtRunner::query(const InfoHash& hash, QueryCallback cb, DoneCallback done_cb, Query q) {
std::unique_lock<std::mutex> lck(storage_mtx);
if (running != State::Running) {
lck.unlock();
if (done_cb) done_cb(false, {});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=](SecureDht& dht) mutable {
dht.query(hash, std::move(cb), bindOpDoneCallback(std::move(done_cb)), std::move(q));
@@ -725,11 +760,12 @@ std::future<size_t>
DhtRunner::listen(InfoHash hash, ValueCallback vcb, Value::Filter f, Where w)
{
auto ret_token = std::make_shared<std::promise<size_t>>();
std::unique_lock<std::mutex> lck(storage_mtx);
if (running != State::Running) {
lck.unlock();
ret_token->set_value(0);
return ret_token->get_future();
}
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops.emplace([=](SecureDht& dht) mutable {
#ifdef OPENDHT_PROXY_CLIENT
auto tokenbGlobal = listener_token_++;
@@ -810,11 +846,12 @@ DhtRunner::cancelListen(InfoHash h, std::shared_future<size_t> ftoken)
void
DhtRunner::put(InfoHash hash, Value&& value, DoneCallback cb, time_point created, bool permanent)
{
std::unique_lock<std::mutex> lck(storage_mtx);
if (running != State::Running) {
lck.unlock();
if (cb) cb(false, {});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=,
cb = std::move(cb),
@@ -828,11 +865,12 @@ DhtRunner::put(InfoHash hash, Value&& value, DoneCallback cb, time_point created
void
DhtRunner::put(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb, time_point created, bool permanent)
{
std::unique_lock<std::mutex> lck(storage_mtx);
if (running != State::Running) {
lck.unlock();
if (cb) cb(false, {});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=, cb = std::move(cb)](SecureDht& dht) mutable {
dht.put(hash, value, bindOpDoneCallback(std::move(cb)), created, permanent);
@@ -869,11 +907,12 @@ DhtRunner::cancelPut(const InfoHash& h, const std::shared_ptr<Value>& value)
void
DhtRunner::putSigned(InfoHash hash, std::shared_ptr<Value> value, DoneCallback cb, bool permanent)
{
std::unique_lock<std::mutex> lck(storage_mtx);
if (running != State::Running) {
lck.unlock();
if (cb) cb(false, {});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=,
cb = std::move(cb),
@@ -899,11 +938,12 @@ DhtRunner::putSigned(const std::string& key, Value&& value, DoneCallbackSimple c
void
DhtRunner::putEncrypted(InfoHash hash, InfoHash to, std::shared_ptr<Value> value, DoneCallback cb, bool permanent)
{
std::unique_lock<std::mutex> lck(storage_mtx);
if (running != State::Running) {
lck.unlock();
if (cb) cb(false, {});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([=,
cb = std::move(cb),
@@ -926,6 +966,31 @@ DhtRunner::putEncrypted(const std::string& key, InfoHash to, Value&& value, Done
putEncrypted(InfoHash::get(key), to, std::forward<Value>(value), std::move(cb), permanent);
}
void
DhtRunner::putEncrypted(InfoHash hash, const std::shared_ptr<crypto::PublicKey>& to, std::shared_ptr<Value> value, DoneCallback cb, bool permanent)
{
std::unique_lock<std::mutex> lck(storage_mtx);
if (running != State::Running) {
lck.unlock();
if (cb) cb(false, {});
return;
}
ongoing_ops++;
pending_ops.emplace([=,
cb = std::move(cb),
value = std::move(value)
] (SecureDht& dht) mutable {
dht.putEncrypted(hash, *to, value, bindOpDoneCallback(std::move(cb)), permanent);
});
cv.notify_all();
}
void
DhtRunner::putEncrypted(InfoHash hash, const std::shared_ptr<crypto::PublicKey>& to, Value&& value, DoneCallback cb, bool permanent)
{
putEncrypted(hash, to, std::make_shared<Value>(std::move(value)), std::move(cb), permanent);
}
void
DhtRunner::bootstrap(const std::string& host, const std::string& service)
{
@@ -989,11 +1054,12 @@ DhtRunner::bootstrap(std::vector<SockAddr> nodes, DoneCallbackSimple&& cb)
void
DhtRunner::bootstrap(const SockAddr& addr, DoneCallbackSimple&& cb)
{
std::unique_lock<std::mutex> lck(storage_mtx);
if (running != State::Running) {
lck.unlock();
if (cb) cb(false);
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops_prio.emplace([addr, cb = bindOpDoneCallback(std::move(cb))](SecureDht& dht) mutable {
dht.pingNode(std::move(addr), std::move(cb));
@@ -1004,9 +1070,9 @@ DhtRunner::bootstrap(const SockAddr& addr, DoneCallbackSimple&& cb)
void
DhtRunner::bootstrap(const InfoHash& id, const SockAddr& address)
{
std::lock_guard<std::mutex> lck(storage_mtx);
if (running != State::Running)
return;
std::unique_lock<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([id, address](SecureDht& dht) mutable {
dht.insertNode(id, address);
});
@@ -1016,9 +1082,9 @@ DhtRunner::bootstrap(const InfoHash& id, const SockAddr& address)
void
DhtRunner::bootstrap(const std::vector<NodeExport>& nodes)
{
std::lock_guard<std::mutex> lck(storage_mtx);
if (running != State::Running)
return;
std::lock_guard<std::mutex> lck(storage_mtx);
pending_ops_prio.emplace([=](SecureDht& dht) {
for (auto& node : nodes)
dht.insertNode(node);
@@ -1042,11 +1108,12 @@ DhtRunner::connectivityChanged()
void
DhtRunner::findCertificate(InfoHash hash, std::function<void(const Sp<crypto::Certificate>&)> cb) {
std::unique_lock<std::mutex> lck(storage_mtx);
if (running != State::Running) {
lck.unlock();
cb({});
return;
}
std::lock_guard<std::mutex> lck(storage_mtx);
ongoing_ops++;
pending_ops.emplace([this, hash, cb = std::move(cb)] (SecureDht& dht) {
dht.findCertificate(hash, [this, cb = std::move(cb)](const Sp<crypto::Certificate>& crt){
@@ -1122,7 +1189,7 @@ DhtRunner::enableProxy(bool proxify)
if (not config_.push_token.empty())
dht_via_proxy->setPushNotificationToken(config_.push_token);
#endif
dht_via_proxy_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht_via_proxy), config_.dht_config));
dht_via_proxy_ = std::unique_ptr<SecureDht>(new SecureDht(std::move(dht_via_proxy), config_.dht_config, identityAnnouncedCb_, logger_));
// add current listeners
for (auto& l: listeners_)
l.second.tokenProxyDht = dht_via_proxy_->listen(l.second.hash, l.second.gcb, l.second.f, l.second.w);
+131 -48
View File
@@ -31,10 +31,14 @@
#include <openssl/ssl.h>
#include <openssl/asn1.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#define MAXAGE_SEC (14*24*60*60)
#define JITTER_SEC (60)
#define OCSP_MAX_RESPONSE_SIZE (20480)
#ifdef _WIN32
#define timegm _mkgmtime
#endif
namespace dht {
namespace http {
@@ -99,22 +103,44 @@ Url::toString() const
std::atomic_uint Connection::ids_ {1};
std::shared_ptr<asio::ssl::context>
newTlsClientContext(const std::shared_ptr<dht::Logger>& logger)
{
auto ctx = std::make_shared<asio::ssl::context>(asio::ssl::context::tls_client);
ctx->set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert);
if (char* path = getenv("CA_ROOT_FILE")) {
if (logger)
logger->d("Using CA file: %s", path);
ctx->load_verify_file(path);
} else if (char* path = getenv("CA_ROOT_PATH")) {
if (logger)
logger->d("Using CA path: %s", path);
ctx->add_verify_path(path);
} else {
#ifdef __ANDROID__
if (logger)
logger->d("Using CA path: /system/etc/security/cacerts");
ctx->add_verify_path("/system/etc/security/cacerts");
#elif defined(WIN32) || defined(TARGET_OS_OSX)
PEMCache::instance(logger).fillX509Store(ctx->native_handle());
#else
if (logger)
logger->d("Using default CA path");
ctx->set_default_verify_paths();
#endif
}
return ctx;
}
Connection::Connection(asio::io_context& ctx, const bool ssl, std::shared_ptr<dht::Logger> l)
: id_(Connection::ids_++), ctx_(ctx), istream_(&read_buf_), logger_(l)
{
if (ssl) {
ssl_ctx_ = std::make_shared<asio::ssl::context>(asio::ssl::context::tls_client);
ssl_ctx_->set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert);
#ifdef __ANDROID__
ssl_ctx_->add_verify_path("/system/etc/security/cacerts");
#elif defined(WIN32) || defined(__APPLE__)
addSystemCaCertificates(ssl_ctx_->native_handle(), l);
#else
ssl_ctx_->set_default_verify_paths();
#endif
ssl_ctx_ = newTlsClientContext(l);
ssl_socket_ = std::make_unique<ssl_socket_t>(ctx_, ssl_ctx_);
if (logger_)
logger_->d("[connection:%i] start https session", id_);
logger_->d("[connection:%i] start https session with system CA", id_);
}
else {
socket_ = std::make_unique<socket_t>(ctx);
@@ -127,23 +153,20 @@ Connection::Connection(asio::io_context& ctx, std::shared_ptr<dht::crypto::Certi
const dht::crypto::Identity& identity, std::shared_ptr<dht::Logger> l)
: id_(Connection::ids_++), ctx_(ctx), istream_(&read_buf_), logger_(l)
{
ssl_ctx_ = std::make_shared<asio::ssl::context>(asio::ssl::context::tls_client);
ssl_ctx_->set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert);
#ifdef __ANDROID__
ssl_ctx_->add_verify_path("/system/etc/security/cacerts");
#elif WIN32
addSystemCaCertificates(ssl_ctx_->native_handle(), l);
#else
ssl_ctx_->set_default_verify_paths();
#endif
asio::error_code ec;
if (server_ca){
if (server_ca) {
ssl_ctx_ = std::make_shared<asio::ssl::context>(asio::ssl::context::tls_client);
ssl_ctx_->set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert);
auto ca = server_ca->toString(false/*chain*/);
ssl_ctx_->add_certificate_authority(asio::const_buffer{ca.data(), ca.size()}, ec);
if (ec)
throw std::runtime_error("Error adding certificate authority: " + ec.message());
else if (logger_)
logger_->d("[connection:%i] certficate authority %s", id_, server_ca->getUID().c_str());
logger_->d("[connection:%i] start https with custom CA %s", id_, server_ca->getUID().c_str());
} else {
ssl_ctx_ = newTlsClientContext(l);
if (logger_)
logger_->d("[connection:%i] start https session with system CA", id_);
}
if (identity.first){
auto key = identity.first->serialize();
@@ -237,7 +260,7 @@ issuer_from_chain(STACK_OF(X509)* fullchain)
using OscpRequestPtr = std::unique_ptr<OCSP_REQUEST, decltype(&OCSP_REQUEST_free)>;
struct OscpRequestInfo {
OscpRequestPtr req {nullptr, &OCSP_REQUEST_free};
std::vector<uint8_t> data;
std::string data;
std::string url;
};
@@ -277,7 +300,7 @@ ocspRequestFromCert(STACK_OF(X509)* fullchain, const std::shared_ptr<Logger>& lo
auto request = std::make_unique<OscpRequestInfo>();
request->req = OscpRequestPtr(OCSP_REQUEST_new(), &OCSP_REQUEST_free);
request->url = strdup(url);
request->url = url;
X509_email_free(urls);
OCSP_CERTID* id = OCSP_cert_to_id(EVP_sha1(), cert, issuer);
@@ -307,7 +330,7 @@ ocspRequestFromCert(STACK_OF(X509)* fullchain, const std::shared_ptr<Logger>& lo
logger->e("Unable to allocte memory");
return {};
}
request->data = std::vector<uint8_t>(data, data+size);
request->data = std::string((char*)data, (char*)data+size);
free(data);
return request;
}
@@ -319,9 +342,6 @@ ocspValidateResponse(const OscpRequestInfo& info, STACK_OF(X509)* fullchain, con
const uint8_t* p = (const uint8_t*)response.data();
int status, cert_status=0, crl_reason=0;
time_t now, rev_t = -1, this_t, next_t;
OCSP_RESPONSE *resp;
OCSP_BASICRESP *bresp;
OCSP_CERTID *cid;
X509* cert = cert_from_chain(fullchain);
if (cert == nullptr) {
@@ -335,32 +355,39 @@ ocspValidateResponse(const OscpRequestInfo& info, STACK_OF(X509)* fullchain, con
logger->e("Unable to find issuer for cert");
return false;
}
if ((cid = OCSP_cert_to_id(nullptr, cert, issuer)) == nullptr) {
OCSP_CERTID *cidr;
if ((cidr = OCSP_cert_to_id(nullptr, cert, issuer)) == nullptr) {
if (logger)
logger->e("Unable to get issuer cert/CID");
return false;
}
std::unique_ptr<OCSP_CERTID, decltype(&OCSP_CERTID_free)> cid(cidr, &OCSP_CERTID_free);
if ((resp = d2i_OCSP_RESPONSE(nullptr, &p, response.size())) == nullptr) {
OCSP_RESPONSE *r;
if ((r = d2i_OCSP_RESPONSE(nullptr, &p, response.size())) == nullptr) {
if (logger)
logger->e("OCSP response unserializable");
return false;
}
std::unique_ptr<OCSP_RESPONSE, decltype(&OCSP_RESPONSE_free)> resp(r, &OCSP_RESPONSE_free);
if ((bresp = OCSP_response_get1_basic(resp)) == nullptr) {
OCSP_BASICRESP *brespr;
if ((brespr = OCSP_response_get1_basic(resp.get())) == nullptr) {
if (logger)
logger->e("Failed to load OCSP response");
return false;
}
std::unique_ptr<OCSP_BASICRESP, decltype(&OCSP_BASICRESP_free)> bresp(brespr, &OCSP_BASICRESP_free);
if (OCSP_basic_verify(bresp, fullchain, store, OCSP_TRUSTOTHER) != 1) {
if (OCSP_basic_verify(bresp.get(), fullchain, store, OCSP_TRUSTOTHER) != 1) {
if (logger)
logger->w("OCSP verify failed");
return false;
}
printf("OCSP response signature validated\n");
status = OCSP_response_status(resp);
status = OCSP_response_status(resp.get());
if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
if (logger)
logger->w("OCSP Failure: code %d (%s)", status, OCSP_response_status_str(status));
@@ -368,13 +395,13 @@ ocspValidateResponse(const OscpRequestInfo& info, STACK_OF(X509)* fullchain, con
}
// Check the nonce if we sent one
if (OCSP_check_nonce(info.req.get(), bresp) <= 0) {
if (OCSP_check_nonce(info.req.get(), bresp.get()) <= 0) {
if (logger)
logger->w("No OCSP nonce, or mismatch");
return false;
}
if (OCSP_resp_find_status(bresp, cid, &cert_status, &crl_reason,
if (OCSP_resp_find_status(bresp.get(), cid.get(), &cert_status, &crl_reason,
&revtime, &thisupd, &nextupd) != 1) {
if (logger)
logger->w("OCSP verify failed: no result for cert");
@@ -455,7 +482,7 @@ Connection::set_ssl_verification(const std::string& hostname, const asio::ssl::v
ssl_socket_->asio_ssl_stream().set_verify_mode(verify_mode);
if (verify_mode != asio::ssl::verify_none) {
ssl_socket_->asio_ssl_stream().set_verify_callback([
id = id_, logger = logger_, hostname
id = id_, logger = logger_, hostname, checkOcsp = checkOcsp_
] (bool preverified, asio::ssl::verify_context& ctx) -> bool {
X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
if (logger) {
@@ -470,23 +497,26 @@ Connection::set_ssl_verification(const std::string& hostname, const asio::ssl::v
auto verify_ec = X509_STORE_CTX_get_error(ctx.native_handle());
if (verify_ec != 0 /*X509_V_OK*/ and logger)
logger->e("[http::connection:%i] ssl verification error=%i %d", id, verify_ec, verified);
if (verified) {
auto chain = X509_STORE_CTX_get1_chain(ctx.native_handle());
if (auto ocspInfo = ocspRequestFromCert(chain, logger)) {
if (verified and checkOcsp) {
std::unique_ptr<stack_st_X509, void(*)(stack_st_X509*)> chain(
X509_STORE_CTX_get1_chain(ctx.native_handle()),
[](stack_st_X509* c){ sk_X509_pop_free(c, X509_free); });
if (auto ocspInfo = ocspRequestFromCert(chain.get(), logger)) {
if (logger)
logger->w("[http::connection:%i] TLS OCSP server: %s, request size: %zu", id, ocspInfo->url.c_str(), ocspInfo->data.size());
bool ocspVerified = false;
asio::io_context io_ctx;
auto ocspReq = std::make_shared<Request>(io_ctx, ocspInfo->url, [&](const Response& ocspResp){
if (ocspResp.status_code == 200) {
ocspVerified = ocspValidateResponse(*ocspInfo, chain, ocspResp.body, ctx.native_handle()->ctx, logger);
ocspVerified = ocspValidateResponse(*ocspInfo, chain.get(), ocspResp.body, X509_STORE_CTX_get0_store(ctx.native_handle()), logger);
} else {
if (logger)
logger->w("[http::connection:%i] TLS OCSP check error", id);
}
}, logger);
ocspReq->set_method(restinio::http_method_post());
ocspReq->set_body({ocspInfo->data.begin(), ocspInfo->data.end()});
ocspReq->set_header_field(restinio::http_field_t::content_type, "application/ocsp-request");
ocspReq->set_body(ocspInfo->data);
ocspReq->send();
io_ctx.run();
if (not ocspVerified)
@@ -531,12 +561,63 @@ void
Connection::async_connect(std::vector<asio::ip::tcp::endpoint>&& endpoints, ConnectHandlerCb cb)
{
std::lock_guard<std::mutex> lock(mutex_);
if (ssl_socket_)
asio::async_connect(ssl_socket_->lowest_layer(), std::move(endpoints), wrapCallabck(std::move(cb)));
else if (socket_)
asio::async_connect(*socket_, std::move(endpoints), wrapCallabck(std::move(cb)));
else if (cb)
if (!ssl_socket_ && !socket_) {
cb(asio::error::operation_aborted, {});
return;
}
auto& base = ssl_socket_? ssl_socket_->lowest_layer() : *socket_;
ConnectHandlerCb wcb = [&base, cb=std::move(cb)](const asio::error_code& ec, const asio::ip::tcp::endpoint& endpoint) {
if (!ec) {
auto socket = base.native_handle();
// Once connected, set a keep alive on the TCP socket with 30 seconds delay
// This will generate broken pipes as soon as possible.
// Note this needs to be done once connected to have a valid native_handle()
uint32_t start = 30;
uint32_t interval = 30;
uint32_t cnt = 1;
#ifdef _WIN32
std::string val = "1";
setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, val.c_str(), sizeof(val));
// TCP_KEEPIDLE and TCP_KEEPINTVL are available since Win 10 version 1709
// TCP_KEEPCNT since Win 10 version 1703
#ifdef TCP_KEEPIDLE
std::string start_str = std::to_string(start);
setsockopt(socket, IPPROTO_TCP, TCP_KEEPIDLE,
start_str.c_str(), sizeof(start_str));
#endif
#ifdef TCP_KEEPINTVL
std::string interval_str = std::to_string(interval);
setsockopt(socket, IPPROTO_TCP, TCP_KEEPINTVL,
interval_str.c_str(), sizeof(interval_str));
#endif
#ifdef TCP_KEEPCNT
std::string cnt_str = std::to_string(cnt);
setsockopt(socket, IPPROTO_TCP, TCP_KEEPCNT,
cnt_str.c_str(), sizeof(cnt_str));
#endif
#else
uint32_t val = 1;
setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(uint32_t));
#ifdef __APPLE__
// Apple devices only have one parameter
setsockopt(socket, IPPROTO_TCP, TCP_KEEPALIVE, &start, sizeof(uint32_t));
#else
// Linux based systems
setsockopt(socket, SOL_TCP, TCP_KEEPIDLE, &start, sizeof(uint32_t));
setsockopt(socket, SOL_TCP, TCP_KEEPINTVL, &interval, sizeof(uint32_t));
setsockopt(socket, SOL_TCP, TCP_KEEPCNT, &cnt, sizeof(uint32_t));
#endif
#endif
}
if (cb)
cb(ec, endpoint);
};
if (ssl_socket_)
asio::async_connect(ssl_socket_->lowest_layer(), std::move(endpoints), wrapCallabck(std::move(wcb)));
else
asio::async_connect(*socket_, std::move(endpoints), wrapCallabck(std::move(wcb)));
}
void
@@ -1224,9 +1305,11 @@ Request::terminate(const asio::error_code& ec)
return;
response_.aborted = ec == asio::error::operation_aborted;
if (ec == asio::error::basic_errors::broken_pipe)
response_.status_code = 0U; // Avoid to give a successful answer (happen with a broken pipe, takes the last status)
if (logger_) {
if (ec and ec != asio::error::eof and ec != asio::error::operation_aborted)
if (ec and ec != asio::error::eof and !response_.aborted)
logger_->e("[http:request:%i] end with error: %s", id_, ec.message().c_str());
else
logger_->d("[http:request:%i] done with status code %u", id_, response_.status_code);
@@ -1354,7 +1437,7 @@ Request::onHeadersComplete() {
}
bool startsWith(const std::string& haystack, const std::string& needle) {
return needle.length() <= haystack.length()
return needle.length() <= haystack.length()
&& std::equal(needle.begin(), needle.end(), haystack.begin());
}
@@ -1385,7 +1468,7 @@ Request::await()
std::unique_lock<std::mutex> lock(mtx);
std::condition_variable cv;
bool ok {false};
add_on_done_callback([&](const Response& resp){
add_on_done_callback([&](const Response&){
std::lock_guard<std::mutex> lk(mtx);
ok = true;
cv.notify_all();
+13 -9
View File
@@ -82,10 +82,6 @@ RequestAnswer::RequestAnswer(ParsedMessage&& msg)
nodes6(std::move(msg.nodes6))
{}
NetworkEngine::NetworkEngine(const Sp<Logger>& log, std::mt19937_64& rand, Scheduler& scheduler, std::unique_ptr<DatagramSocket>&& sock)
: myid(zeroes), dht_socket(std::move(sock)), logger_(log), rd(rand), cache(rd), rate_limiter((size_t)-1), scheduler(scheduler)
{}
NetworkEngine::NetworkEngine(InfoHash& myid, NetworkConfig c,
std::unique_ptr<DatagramSocket>&& sock,
const Sp<Logger>& log,
@@ -380,7 +376,7 @@ NetworkEngine::isMartian(const SockAddr& addr)
const uint8_t* address = (const uint8_t*)&sin6.sin6_addr;
return address[0] == 0xFF ||
(address[0] == 0xFE && (address[1] & 0xC0) == 0x80) ||
memcmp(address, zeroes.data(), 16) == 0 ||
memcmp(address, InfoHash::zero().data(), 16) == 0 ||
memcmp(address, v4prefix, 12) == 0;
}
default:
@@ -460,9 +456,13 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
pmsg_it->second.last_part = now;
// check data completion
if (pmsg_it->second.msg->complete()) {
// process the full message
process(std::move(pmsg_it->second.msg), from);
partial_messages.erase(pmsg_it);
try {
// process the full message
process(std::move(pmsg_it->second.msg), from);
partial_messages.erase(pmsg_it);
} catch (...) {
return;
}
} else
scheduler.add(now + RX_TIMEOUT, std::bind(&NetworkEngine::maintainRxBuffer, this, msg->tid));
}
@@ -485,7 +485,11 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, SockAddr f)
}
if (msg->value_parts.empty()) {
process(std::move(msg), from);
try {
process(std::move(msg), from);
} catch(...) {
return;
}
} else {
// starting partial message session
auto k = msg->tid;
+19 -6
View File
@@ -39,8 +39,10 @@ public:
}
static ValueCallback cacheCallback(ValueCallback&& cb, std::function<void()>&& onCancel) {
auto cache = std::make_shared<OpValueCache>(std::forward<ValueCallback>(cb));
return [cache, onCancel](const std::vector<Sp<Value>>& vals, bool expired){
return [
cache = std::make_shared<OpValueCache>(std::forward<ValueCallback>(cb)),
onCancel = std::move(onCancel)
](const std::vector<Sp<Value>>& vals, bool expired){
auto ret = cache->onValue(vals, expired);
if (not ret)
onCancel();
@@ -49,10 +51,9 @@ public:
}
bool onValue(const std::vector<Sp<Value>>& vals, bool expired, const system_clock::time_point& t = system_clock::time_point::min()) {
if (expired)
return onValuesExpired(vals, t);
else
return onValuesAdded(vals, t);
return expired
? onValuesExpired(vals, t)
: onValuesAdded(vals, t);
}
bool onValuesAdded(const std::vector<Sp<Value>>& vals, const system_clock::time_point& t = system_clock::time_point::min());
@@ -73,6 +74,7 @@ public:
std::vector<Sp<Value>> get(const Value::Filter& filter) const;
Sp<Value> get(Value::Id id) const;
std::vector<Sp<Value>> getValues() const;
size_t size() const { return values.size(); }
private:
OpValueCache(const OpValueCache&) = delete;
@@ -144,6 +146,10 @@ public:
}
time_point getExpiration() const;
size_t size() const {
return cache.size();
}
size_t searchToken;
private:
constexpr static const std::chrono::seconds EXPIRATION {60};
@@ -175,6 +181,13 @@ public:
std::vector<Sp<Value>> get(const Value::Filter& filter) const;
Sp<Value> get(Value::Id id) const;
std::pair<size_t, size_t> size() const {
size_t tot = 0;
for (const auto& c : ops)
tot += c.second->size();
return {ops.size(), tot};
}
private:
SearchCache(const SearchCache&) = delete;
SearchCache& operator=(const SearchCache&) = delete;
+20
View File
@@ -124,6 +124,14 @@ struct Dht::SearchNode {
return last_get_reply + Node::NODE_EXPIRE_TIME;
}
friend std::ostream& operator<< (std::ostream& s, const SearchNode& node) {
s << "getStatus:" << node.getStatus.size()
<< " listenStatus:" << node.listenStatus.size()
<< " acked:" << node.acked.size()
<< " cache:" << (node.listenStatus.empty() ? 0 : node.listenStatus.begin()->second.cache.size()) << std::endl;
return s;
}
/**
* Could a particular "get" request be sent to this node now ?
*
@@ -417,6 +425,18 @@ struct Dht::Search {
}
}
friend std::ostream& operator<< (std::ostream& s, const Search& sr) {
auto csize = sr.cache.size();
s << "announce:" << sr.announce.size()
<< " gets:" << sr.callbacks.size()
<< " listeners:" << sr.listeners.size()
<< " cache:" << csize.first << ',' << csize.second << std::endl;
s << "nodes:" << std::endl;
for (const auto& n : sr.nodes)
s << *n;
return s;
}
/**
* @returns true if the node was not present and added to the search
*/
+39 -20
View File
@@ -36,8 +36,8 @@ extern "C" {
namespace dht {
SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht, SecureDht::Config conf)
: dht_(std::move(dht)), key_(conf.id.first), certificate_(conf.id.second), enableCache_(conf.cert_cache_all)
SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht, SecureDht::Config conf, IdentityAnnouncedCb iacb, const std::shared_ptr<Logger>& l)
: DhtInterface(l), dht_(std::move(dht)), key_(conf.id.first), certificate_(conf.id.second), enableCache_(conf.cert_cache_all)
{
if (!dht_) return;
for (const auto& type : DEFAULT_TYPES)
@@ -52,16 +52,17 @@ SecureDht::SecureDht(std::unique_ptr<DhtInterface> dht, SecureDht::Config conf)
auto certId = certificate_->getId();
if (key_ and certId != key_->getPublicKey().getId())
throw DhtException("SecureDht: provided certificate doesn't match private key.");
dht_->put(certId, Value {
CERTIFICATE_TYPE,
*certificate_,
1
}, [this, certId](bool ok) {
if (ok)
dht_->addOnConnectedCallback([this, certId, cb=std::move(iacb)]{
dht_->put(certId, Value {
CERTIFICATE_TYPE,
*certificate_,
1
}, [this, certId, cb=std::move(cb)](bool ok) {
if (cb) cb(ok);
if (logger_)
logger_->d(certId, "SecureDht: public key announced successfully");
}, {}, true);
logger_->d(certId, "SecureDht: certificate announcement %s", ok ? "succeeded" : "failed");
}, {}, true);
});
}
}
@@ -117,7 +118,7 @@ SecureDht::secureType(ValueType&& type)
return type;
}
const Sp<crypto::Certificate>
Sp<crypto::Certificate>
SecureDht::getCertificate(const InfoHash& node) const
{
if (node == getId())
@@ -129,7 +130,7 @@ SecureDht::getCertificate(const InfoHash& node) const
return it->second;
}
const Sp<const crypto::PublicKey>
Sp<crypto::PublicKey>
SecureDht::getPublicKey(const InfoHash& node) const
{
if (node == getId())
@@ -141,7 +142,7 @@ SecureDht::getPublicKey(const InfoHash& node) const
return it->second;
}
const Sp<crypto::Certificate>
Sp<crypto::Certificate>
SecureDht::registerCertificate(const InfoHash& node, const Blob& data)
{
Sp<crypto::Certificate> crt;
@@ -199,8 +200,6 @@ SecureDht::findCertificate(const InfoHash& node, const std::function<void(const
auto found = std::make_shared<bool>(false);
dht_->get(node, [cb,node,found,this](const std::vector<Sp<Value>>& vals) {
if (*found)
return false;
for (const auto& v : vals) {
if (auto cert = registerCertificate(node, v->data)) {
*found = true;
@@ -211,7 +210,7 @@ SecureDht::findCertificate(const InfoHash& node, const std::function<void(const
return false;
}
}
return true;
return !*found;
}, [cb,found](bool) {
if (!*found and cb)
cb(nullptr);
@@ -219,7 +218,7 @@ SecureDht::findCertificate(const InfoHash& node, const std::function<void(const
}
void
SecureDht::findPublicKey(const InfoHash& node, const std::function<void(const Sp<const crypto::PublicKey>)>& cb)
SecureDht::findPublicKey(const InfoHash& node, const std::function<void(const Sp<crypto::PublicKey>)>& cb)
{
auto pk = getPublicKey(node);
if (pk && *pk) {
@@ -229,7 +228,7 @@ SecureDht::findPublicKey(const InfoHash& node, const std::function<void(const Sp
cb(pk);
return;
}
findCertificate(node, [=](const Sp<crypto::Certificate> crt) {
findCertificate(node, [=](const Sp<crypto::Certificate>& crt) {
if (crt && *crt) {
auto pk = std::make_shared<crypto::PublicKey>(crt->getPublicKey());
if (*pk) {
@@ -404,7 +403,7 @@ SecureDht::putEncrypted(const InfoHash& hash, const InfoHash& to, Sp<Value> val,
callback(false, {});
return;
}
findPublicKey(to, [=](const Sp<const crypto::PublicKey>& pk) {
findPublicKey(to, [this, hash, val = std::move(val), callback = std::move(callback), permanent](const Sp<crypto::PublicKey>& pk) {
if(!pk || !*pk) {
if (callback)
callback(false, {});
@@ -423,6 +422,26 @@ SecureDht::putEncrypted(const InfoHash& hash, const InfoHash& to, Sp<Value> val,
});
}
void
SecureDht::putEncrypted(const InfoHash& hash, const crypto::PublicKey& pk, Sp<Value> val, DoneCallback callback, bool permanent)
{
if (not key_) {
if (callback)
callback(false, {});
return;
}
if (logger_)
logger_->w("Encrypting data for PK: %s", pk.getLongId().to_c_str());
try {
dht_->put(hash, encrypt(*val, pk), callback, time_point::max(), permanent);
} catch (const std::exception& e) {
if (logger_)
logger_->e("Error putting encrypted data: %s", e.what());
if (callback)
callback(false, {});
}
}
void
SecureDht::sign(Value& v) const
{
+6 -9
View File
@@ -76,10 +76,7 @@ std::ostream& operator<< (std::ostream& s, const Value& v)
s.write((const char*)v.data.data(), v.data.size());
s << '"';
} else if (v.data.size() < 1024) {
s << std::hex;
for (auto i : v.data)
s << std::setfill('0') << std::setw(2) << (unsigned)i;
s << std::dec;
s << toHex(v.data.data(), v.data.size());
} else {
s << v.data.size() << " bytes";
}
@@ -166,7 +163,7 @@ Value::msgpack_unpack_body(const msgpack::object& o)
throw msgpack::type_error();
crypto::PublicKey new_owner;
new_owner.msgpack_unpack(*rowner);
owner = std::make_shared<const crypto::PublicKey>(std::move(new_owner));
owner = std::make_shared<crypto::PublicKey>(std::move(new_owner));
if (auto rrecipient = findMapValue(*rbody, VALUE_KEY_TO)) {
recipient = rrecipient->as<InfoHash>();
}
@@ -196,7 +193,7 @@ Value::Value(const Json::Value& json)
if (jowner.isString()) {
auto ownerStr = jowner.asString();
auto ownerBlob = std::vector<unsigned char>(ownerStr.begin(), ownerStr.end());
owner = std::make_shared<const crypto::PublicKey>(ownerBlob);
owner = std::make_shared<crypto::PublicKey>(ownerBlob);
}
const auto& jto = json[VALUE_KEY_TO];
if (jto.isString())
@@ -499,10 +496,10 @@ Query::msgpack_unpack(const msgpack::object& o)
}
template <typename T>
bool subset(std::vector<T> fds, std::vector<T> qfds)
bool subset(const std::vector<T>& fds, const std::vector<T>& qfds)
{
for (auto& fd : fds) {
if (std::find_if(qfds.begin(), qfds.end(), [&fd](T& _vfd) { return fd == _vfd; }) == qfds.end())
for (const auto& fd : fds) {
if (std::find_if(qfds.begin(), qfds.end(), [&fd](const T& _vfd) { return fd == _vfd; }) == qfds.end())
return false;
}
return true;
+6 -3
View File
@@ -142,6 +142,10 @@ public:
}
}
size_t size() const {
return values.size();
}
private:
// prevent copy
ValueCache(const ValueCache&) = delete;
@@ -192,11 +196,10 @@ private:
auto v = values.find(vid);
if (v == values.end())
return {};
const std::vector<Sp<Value>> val {std::move(v->second.data)};
std::vector<Sp<Value>> val {std::move(v->second.data)};
values.erase(v);
auto cb = callback;
CallbackQueue ret;
ret.emplace_back([cb, val]{
ret.emplace_back([cb = callback, val = std::move(val)]{
if (cb) cb(val, true);
});
return ret;
+13 -1
View File
@@ -33,7 +33,7 @@ CryptoTester::setUp() {
void
CryptoTester::testSignatureEncryption() {
auto key = dht::crypto::PrivateKey::generate();
auto public_key = key.getPublicKey();
const auto& public_key = key.getPublicKey();
std::vector<uint8_t> data1 {5, 10};
std::vector<uint8_t> data2(64 * 1024, 10);
@@ -44,6 +44,10 @@ CryptoTester::testSignatureEncryption() {
// check signature
CPPUNIT_ASSERT(public_key.checkSignature(data1, signature1));
CPPUNIT_ASSERT(public_key.checkSignature(data2, signature2));
signature1[7]++;
signature2[8]--;
CPPUNIT_ASSERT(!public_key.checkSignature(data1, signature1));
CPPUNIT_ASSERT(!public_key.checkSignature(data2, signature2));
// encrypt data
{
@@ -161,6 +165,14 @@ void CryptoTester::testCertificateSerialNumber()
CPPUNIT_ASSERT(std::equal(SERIAL.begin(), SERIAL.end(), serial.begin(), serial.end()));
}
void CryptoTester::testOcsp() {
auto ca = dht::crypto::generateIdentity("Test CA");
auto device = dht::crypto::generateIdentity("Test Device", ca);
auto ocspRequest = device.second->generateOcspRequest(ca.second->cert);
auto req = dht::crypto::OcspRequest((const uint8_t*)ocspRequest.first.data(), ocspRequest.first.size());
CPPUNIT_ASSERT(ocspRequest.second == req.getNonce());
}
void
CryptoTester::tearDown() {
+5
View File
@@ -32,6 +32,7 @@ class CryptoTester : public CppUnit::TestFixture {
CPPUNIT_TEST(testCertificateRevocation);
CPPUNIT_TEST(testCertificateRequest);
CPPUNIT_TEST(testCertificateSerialNumber);
CPPUNIT_TEST(testOcsp);
CPPUNIT_TEST_SUITE_END();
public:
@@ -59,6 +60,10 @@ class CryptoTester : public CppUnit::TestFixture {
* Test certificate serial number extraction
*/
void testCertificateSerialNumber();
/**
* Test OCSP
*/
void testOcsp();
};
} // namespace test
+49 -6
View File
@@ -46,15 +46,15 @@ DhtProxyTester::setUp() {
auto serverCAIdentity = dht::crypto::generateEcIdentity("DHT Node CA");
dht::ProxyServerConfig serverConfig;
serverConfig.identity = dht::crypto::generateIdentity("DHT Node", serverCAIdentity);
//serverConfig.identity = dht::crypto::generateIdentity("DHT Node", serverCAIdentity);
serverConfig.port = 8080;
serverConfig.pushServer = "127.0.0.1:8090";
// serverConfig.pushServer = "127.0.0.1:8090";
serverProxy = std::make_unique<dht::DhtProxyServer>(nodeProxy, serverConfig);
clientConfig.server_ca = serverCAIdentity.second;
/*clientConfig.server_ca = serverCAIdentity.second;
clientConfig.client_identity = dht::crypto::generateIdentity("DhtProxyTester");
clientConfig.push_node_id = "dhtnode";
clientConfig.proxy_server = "https://127.0.0.1:8080";
clientConfig.push_node_id = "dhtnode";*/
clientConfig.proxy_server = "http://127.0.0.1:8080";//"https://127.0.0.1:8080";
}
void
@@ -71,7 +71,7 @@ DhtProxyTester::tearDown() {
cv.notify_all();
});
std::unique_lock<std::mutex> lk(cv_m);
CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]{ return done; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 15s, [&]{ return done; }));
serverProxy.reset();
nodeProxy.reset();
}
@@ -289,4 +289,47 @@ DhtProxyTester::testFuzzy()
CPPUNIT_ASSERT(value->data == mtu);
}
void
DhtProxyTester::testShutdownStop()
{
constexpr size_t N = 40000;
constexpr unsigned C = 100;
// Arrange
auto key = dht::InfoHash::get("testShutdownStop");
std::vector<std::shared_ptr<dht::Value>> values;
std::vector<uint8_t> mtu;
mtu.reserve(N);
for (size_t i = 0; i < N; i++)
mtu.emplace_back((i % 2) ? 'T' : 'M');
std::atomic_uint callback_count {0};
// Act
for (size_t i = 0; i < C; i++) {
auto nodeTest = std::make_shared<dht::DhtRunner>();
nodeTest->run(0, clientConfig);
nodeTest->put(key, dht::Value(mtu), [&](bool ok) {
callback_count++;
});
nodeTest->get(key, [&](const std::vector<std::shared_ptr<dht::Value>>& vals){
values.insert(values.end(), vals.begin(), vals.end());
return true;
},[&](bool ok){
callback_count++;
});
bool done = false;
std::condition_variable cv;
std::mutex cv_m;
nodeTest->shutdown([&]{
std::lock_guard<std::mutex> lk(cv_m);
done = true;
cv.notify_all();
}, true);
std::unique_lock<std::mutex> lk(cv_m);
CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]{ return done; }));
}
CPPUNIT_ASSERT_EQUAL(2*C, callback_count.load());
}
} // namespace test
+3
View File
@@ -36,6 +36,7 @@ class DhtProxyTester : public CppUnit::TestFixture {
CPPUNIT_TEST(testResubscribeGetValues);
CPPUNIT_TEST(testPutGet40KChars);
CPPUNIT_TEST(testFuzzy);
CPPUNIT_TEST(testShutdownStop);
CPPUNIT_TEST_SUITE_END();
public:
@@ -68,6 +69,8 @@ class DhtProxyTester : public CppUnit::TestFixture {
void testFuzzy();
void testShutdownStop();
private:
dht::DhtRunner::Config clientConfig {};
dht::DhtRunner nodePeer;
+122 -1
View File
@@ -19,10 +19,13 @@
#include "dhtrunnertester.h"
#include <opendht/thread_pool.h>
#include <chrono>
#include <mutex>
#include <condition_variable>
using namespace std::chrono_literals;
using namespace std::literals;
namespace test {
CPPUNIT_TEST_SUITE_REGISTRATION(DhtRunnerTester);
@@ -51,7 +54,7 @@ DhtRunnerTester::tearDown() {
node1.shutdown(shutdown);
node2.shutdown(shutdown);
std::unique_lock<std::mutex> lk(cv_m);
CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]{ return done == 2; }));
CPPUNIT_ASSERT(cv.wait_for(lk, 12s, [&]{ return done == 2; }));
node1.join();
node2.join();
}
@@ -60,6 +63,12 @@ void
DhtRunnerTester::testConstructors() {
CPPUNIT_ASSERT(node1.getBoundPort() == 42222);
CPPUNIT_ASSERT(node2.getBoundPort() == 42232);
dht::DhtRunner::Config config {};
dht::DhtRunner::Context context {};
dht::DhtRunner testNode;
testNode.run(config, std::move(context));
CPPUNIT_ASSERT(testNode.getBoundPort());
}
void
@@ -167,6 +176,83 @@ DhtRunnerTester::testListen() {
node1.cancelListen(d, tokend);
}
void
DhtRunnerTester::testIdOps() {
std::mutex mutex;
std::condition_variable cv;
unsigned valueCount(0);
dht::DhtRunner::Config config2;
config2.dht_config.node_config.max_peer_req_per_sec = -1;
config2.dht_config.node_config.max_req_per_sec = -1;
config2.dht_config.id = dht::crypto::generateIdentity();
dht::DhtRunner::Context context2;
context2.identityAnnouncedCb = [&](bool ok) {
CPPUNIT_ASSERT(ok);
std::lock_guard<std::mutex> lk(mutex);
valueCount++;
cv.notify_all();
};
node2.join();
node2.run(42232, config2, std::move(context2));
node2.bootstrap(node1.getBound());
node1.findCertificate(node2.getId(), [&](const std::shared_ptr<dht::crypto::Certificate>& crt){
CPPUNIT_ASSERT(crt);
std::lock_guard<std::mutex> lk(mutex);
valueCount++;
cv.notify_all();
});
{
std::unique_lock<std::mutex> lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 2; }));
}
dht::DhtRunner::Context context1;
context1.identityAnnouncedCb = [&](bool ok) {
CPPUNIT_ASSERT(ok);
std::lock_guard<std::mutex> lk(mutex);
valueCount++;
cv.notify_all();
};
config2.dht_config.id = dht::crypto::generateIdentity();
node1.join();
node1.run(42222, config2, std::move(context1));
node1.bootstrap(node2.getBound());
auto key = dht::InfoHash::get("key");
node1.putEncrypted(key, node2.getId(), dht::Value("yo"), [&](bool ok){
CPPUNIT_ASSERT(ok);
std::lock_guard<std::mutex> lk(mutex);
valueCount++;
cv.notify_all();
});
node1.putEncrypted(key, node2.getPublicKey(), dht::Value("yo"), [&](bool ok){
CPPUNIT_ASSERT(ok);
std::lock_guard<std::mutex> lk(mutex);
valueCount++;
cv.notify_all();
});
node2.listen<std::string>(key, [&](std::string&& value){
CPPUNIT_ASSERT_EQUAL("yo"s, value);
std::lock_guard<std::mutex> lk(mutex);
valueCount++;
cv.notify_all();
return true;
});
{
std::unique_lock<std::mutex> lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]{ return valueCount == 7; }));
}
}
void
DhtRunnerTester::testListenLotOfBytes() {
std::mutex mutex;
@@ -214,4 +300,39 @@ DhtRunnerTester::testListenLotOfBytes() {
node3.cancelListen(foo, ftokenfoo.get());
}
void
DhtRunnerTester::testMultithread() {
std::mutex mutex;
std::condition_variable cv;
unsigned putCount(0);
unsigned putOkCount(0);
constexpr unsigned N = 2048;
for (unsigned i=0; i<N; i++) {
dht::ThreadPool::computation().run([&]{
node2.put(dht::InfoHash::get("123" + std::to_string(i)), "hehe", [&](bool ok) {
std::lock_guard<std::mutex> lock(mutex);
putCount++;
if (ok) putOkCount++;
cv.notify_all();
});
node2.get(dht::InfoHash::get("123" + std::to_string(N-i-1)), [](const std::shared_ptr<dht::Value>&){
return true;
}, [&](bool ok) {
std::lock_guard<std::mutex> lock(mutex);
putCount++;
if (ok) putOkCount++;
cv.notify_all();
});
});
}
std::unique_lock<std::mutex> lk(mutex);
CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]{ return putCount == 2*N; }));
CPPUNIT_ASSERT_EQUAL(2*N, putOkCount);
}
} // namespace test
+10
View File
@@ -33,6 +33,7 @@ class DhtRunnerTester : public CppUnit::TestFixture {
CPPUNIT_TEST(testGetPut);
CPPUNIT_TEST(testListen);
CPPUNIT_TEST(testListenLotOfBytes);
CPPUNIT_TEST(testIdOps);
CPPUNIT_TEST_SUITE_END();
dht::DhtRunner node1 {};
@@ -58,10 +59,19 @@ class DhtRunnerTester : public CppUnit::TestFixture {
* Test listen method
*/
void testListen();
/**
* Test methods requiring a node identity
*/
void testIdOps();
/**
* Test listen method with lot of datas
*/
void testListenLotOfBytes();
/**
* Test multithread
*/
void testMultithread();
};
} // namespace test
+9 -1
View File
@@ -73,7 +73,7 @@ InfoHashTester::testConstructors() {
}
void
InfoHashTester::testComperators() {
InfoHashTester::testComparators() {
auto nullHash = dht::InfoHash();
auto minHash = dht::InfoHash("0000000000000000000000000000000000111110");
auto maxHash = dht::InfoHash("0111110000000000000000000000000000000000");
@@ -136,6 +136,14 @@ InfoHashTester::testXorCmp() {
CPPUNIT_ASSERT_EQUAL(maxHash.xorCmp(minHash, nullHash), 1);
}
void
InfoHashTester::testHex() {
const std::string TEST_HASH_STR("01b20304d5060708090a010203e05060708090ae");
dht::InfoHash TEST_HASH(TEST_HASH_STR);
CPPUNIT_ASSERT_EQUAL(TEST_HASH_STR, TEST_HASH.toString());
CPPUNIT_ASSERT_EQUAL(TEST_HASH_STR, dht::toHex(TEST_HASH.data(), TEST_HASH.size()));
}
void
InfoHashTester::tearDown() {
+7 -2
View File
@@ -28,10 +28,11 @@ namespace test {
class InfoHashTester : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(InfoHashTester);
CPPUNIT_TEST(testConstructors);
CPPUNIT_TEST(testComperators);
CPPUNIT_TEST(testComparators);
CPPUNIT_TEST(testLowBit);
CPPUNIT_TEST(testCommonBits);
CPPUNIT_TEST(testXorCmp);
CPPUNIT_TEST(testHex);
CPPUNIT_TEST_SUITE_END();
public:
@@ -50,7 +51,7 @@ class InfoHashTester : public CppUnit::TestFixture {
/**
* Test compare operators
*/
void testComperators();
void testComparators();
/**
* Test lowbit method
*/
@@ -64,6 +65,10 @@ class InfoHashTester : public CppUnit::TestFixture {
*/
void testXorCmp();
/**
* Test hex conversion
*/
void testHex();
};
} // namespace test
+20 -3
View File
@@ -59,7 +59,7 @@ ThreadPoolTester::testExecutor()
auto executor8 = std::make_shared<dht::Executor>(pool, 8);
constexpr unsigned N = 64 * 1024;
std::atomic_uint count1 {0};
unsigned count1 {0};
std::atomic_uint count4 {0};
std::atomic_uint count8 {0};
for (unsigned i=0; i<N; i++) {
@@ -69,7 +69,7 @@ ThreadPoolTester::testExecutor()
}
auto start = clock::now();
while ((count1.load() != N ||
while ((count1 != N ||
count4.load() != N ||
count8.load() != N) && clock::now() - start < std::chrono::seconds(20))
{
@@ -78,11 +78,28 @@ ThreadPoolTester::testExecutor()
executor1.reset();
executor4.reset();
executor8.reset();
CPPUNIT_ASSERT_EQUAL(N, count1.load());
CPPUNIT_ASSERT_EQUAL(N, count1);
CPPUNIT_ASSERT_EQUAL(N, count4.load());
CPPUNIT_ASSERT_EQUAL(N, count8.load());
}
void
ThreadPoolTester::testContext()
{
std::atomic_uint count {0};
constexpr unsigned N = 64 * 1024;
{
dht::ExecutionContext ctx(dht::ThreadPool::computation());
for (unsigned i=0; i<N; i++) {
ctx.run([&] { count++; });
}
}
CPPUNIT_ASSERT_EQUAL(N, count.load());
}
void
ThreadPoolTester::tearDown() {
}
+2
View File
@@ -29,6 +29,7 @@ class ThreadPoolTester : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(ThreadPoolTester);
CPPUNIT_TEST(testThreadPool);
CPPUNIT_TEST(testExecutor);
CPPUNIT_TEST(testContext);
CPPUNIT_TEST_SUITE_END();
public:
@@ -43,6 +44,7 @@ class ThreadPoolTester : public CppUnit::TestFixture {
void testThreadPool();
void testExecutor();
void testContext();
};
} // namespace test
+8 -2
View File
@@ -39,8 +39,14 @@ endif ()
install (TARGETS dhtnode dhtscanner dhtchat RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
if (OPENDHT_SYSTEMD)
execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} systemd --variable=systemdsystemunitdir
OUTPUT_VARIABLE SYSTEMD_UNIT_INSTALL_DIR)
if (NOT DEFINED OPENDHT_SYSTEMD_UNIT_FILE_LOCATION)
execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} systemd --variable=systemdsystemunitdir
OUTPUT_VARIABLE SYSTEMD_UNIT_INSTALL_DIR)
message("-- Using Systemd unit installation directory by pkg-config: " ${SYSTEMD_UNIT_INSTALL_DIR})
else()
message("-- Using Systemd unit installation directory requested: " ${OPENDHT_SYSTEMD_UNIT_FILE_LOCATION})
set(SYSTEMD_UNIT_INSTALL_DIR ${OPENDHT_SYSTEMD_UNIT_FILE_LOCATION})
endif()
string(REGEX REPLACE "[ \t\n]+" "" SYSTEMD_UNIT_INSTALL_DIR "${SYSTEMD_UNIT_INSTALL_DIR}")
set (systemdunitdir "${SYSTEMD_UNIT_INSTALL_DIR}")
+3 -3
View File
@@ -4,10 +4,10 @@ noinst_HEADERS = tools_common.h
AM_CPPFLAGS = -isystem @top_srcdir@/include @JsonCpp_CFLAGS@ @MsgPack_CFLAGS@
dhtnode_SOURCES = dhtnode.cpp
dhtnode_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @Argon2_LDFLAGS@ @GnuTLS_LIBS@
dhtnode_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @GnuTLS_LIBS@
dhtchat_SOURCES = dhtchat.cpp
dhtchat_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @Argon2_LDFLAGS@ @GnuTLS_LIBS@
dhtchat_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @GnuTLS_LIBS@
dhtscanner_SOURCES = dhtscanner.cpp
dhtscanner_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @Argon2_LDFLAGS@ @GnuTLS_LIBS@
dhtscanner_LDFLAGS = -lopendht -lreadline -L@top_builddir@/src/.libs @GnuTLS_LIBS@
+1 -1
View File
@@ -467,7 +467,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& node, dht_params& params
<< " hash: " << p.hash() << std::endl;
std::cout << " entries:" << std::endl;
for (const auto& v : vals)
std::cout << " " << v->first.toString() << "[vid: " << v->second << "]" << std::endl;
std::cout << " " << v->first.toString() << "[vid: " << std::hex << v->second << std::dec << "]" << std::endl;
},
[start](bool ok) {
auto end = std::chrono::high_resolution_clock::now();
+34 -4
View File
@@ -1,14 +1,44 @@
[Unit]
Description=OpenDHT standalone node
Documentation=man:dhtnode(1)
After=network.target
[Service]
EnvironmentFile=@sysconfdir@/dhtnode.conf
ExecStart=@bindir@/dhtnode -s $DHT_ARGS
KillMode=process
Restart=on-failure
Type=simple
User=opendht
Group=opendht
ExecStart=@bindir@/dhtnode -s $DHT_ARGS
Restart=on-failure
RestartSec=2s
LimitNOFILE=65536
DynamicUser=yes
EnvironmentFile=@sysconfdir@/dhtnode.conf
KillMode=process
WorkingDirectory=/tmp
# Hardening
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
LockPersonality=yes
NoNewPrivileges=yes
PrivateDevices=yes
PrivateTmp=yes
PrivateUsers=yes
ProtectClock=yes
ProtectControlGroups=yes
ProtectHome=yes
ProtectHostname=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectSystem=strict
ReadOnlyDirectories=/
ReadWriteDirectories=-/proc/self
ReadWriteDirectories=-/var/run
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
RestrictNamespaces=yes
RestrictRealtime=yes
SystemCallArchitectures=native
SystemCallFilter=@system-service
[Install]
WantedBy=multi-user.target