diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f6e3af55078ebb3628e0f4d17913edf4598c795..60a134d688c02b9bd8acb6aaea4be945aedf4d02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,15 +7,15 @@ set (PACKAGE_VERSION ${opendht_VERSION}) set (VERSION "${opendht_VERSION}") # Options +option (OPENDHT_LIGHT "Build minimal version of the library" OFF) + option (OPENDHT_STATIC "Build static library" ON) + option (OPENDHT_SHARED "Build shared library" ON) -option (OPENDHT_LOG "Build with logs" ON) option (OPENDHT_PYTHON "Build Python bindings" OFF) option (OPENDHT_TOOLS "Build DHT tools" ON) option (OPENDHT_SYSTEMD "Install systemd module" OFF) 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) option (OPENDHT_PUSH_NOTIFICATIONS "Enable push notifications support" OFF) option (OPENDHT_PROXY_SERVER_IDENTITY "Allow clients to use the node identity" OFF) @@ -24,72 +24,89 @@ 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) option (OPENDHT_PEER_DISCOVERY "Enable multicast peer discovery" ON) option (OPENDHT_INDEX "Build DHT indexation feature" OFF) -option (OPENDHT_TESTS "Add unit tests executable" OFF) option (OPENDHT_C "Build C bindings" OFF) +option (OPENDHT_TESTS "Add unit tests executable" OFF) + +if (OPENDHT_LIGHT) + set(OPENDHT_SHARED OFF) + set(OPENDHT_TOOLS OFF) + set(OPENDHT_PROXY_SERVER OFF) + set(OPENDHT_PROXY_CLIENT OFF) + set(OPENDHT_PEER_DISCOVERY OFF) + set(OPENDHT_INDEX OFF) + set(OPENDHT_PYTHON OFF) + add_definitions(-DOPENDHT_LIGHT) +endif() + +option (OPENDHT_LOG "Build with logs" ON) +option (OPENDHT_LTO "Build with LTO" OFF) +option (OPENDHT_SANITIZE "Build with address sanitizer and stack protector" OFF) find_package(Doxygen) option (OPENDHT_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen)" ${DOXYGEN_FOUND}) # Dependencies list (APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") -find_package (Threads) find_package (PkgConfig) -find_package (GnuTLS 3.3 REQUIRED) -pkg_search_module (Nettle nettle) find_package (Msgpack 1.2 REQUIRED) -if (OPENDHT_TOOLS) - find_package (Readline 6 REQUIRED) -endif () -if (NOT OPENDHT_ARGON2) - find_package(PkgConfig) - 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(Jsoncpp jsoncpp) -if (Jsoncpp_FOUND) - add_definitions(-DOPENDHT_JSONCPP) - list (APPEND opendht_SOURCES - src/base64.h - src/base64.cpp - ) -endif() +if (NOT OPENDHT_LIGHT) + find_package (Threads) + find_package (GnuTLS 3.3 REQUIRED) + pkg_search_module (Nettle nettle) + if (OPENDHT_TOOLS) + find_package (Readline 6 REQUIRED) + endif () + if (NOT OPENDHT_ARGON2) + find_package(PkgConfig) + 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 () -if (OPENDHT_PROXY_SERVER OR OPENDHT_PROXY_CLIENT) - find_package(Restinio REQUIRED) - if (Restinio_FOUND) - find_library(FMT_LIBRARY fmt) - add_library(fmt SHARED IMPORTED) - find_library(HTTP_PARSER_LIBRARY http_parser) - add_library(http_parser SHARED IMPORTED) - endif() - if (NOT Jsoncpp_FOUND) - message(SEND_ERROR "Jsoncpp is required for DHT proxy support") + pkg_search_module(Jsoncpp jsoncpp) + if (Jsoncpp_FOUND) + add_definitions(-DOPENDHT_JSONCPP) + list (APPEND opendht_SOURCES + src/base64.h + src/base64.cpp + ) endif() - if (OPENDHT_PROXY_OPENSSL) - # 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}) - else () - message(SEND_ERROR "OpenSSL is required for DHT proxy as specified") + + if (OPENDHT_PROXY_SERVER OR OPENDHT_PROXY_CLIENT) + find_package(Restinio REQUIRED) + if (Restinio_FOUND) + find_library(FMT_LIBRARY fmt) + add_library(fmt SHARED IMPORTED) + find_library(HTTP_PARSER_LIBRARY http_parser) + add_library(http_parser SHARED IMPORTED) + endif() + if (NOT Jsoncpp_FOUND) + message(SEND_ERROR "Jsoncpp is required for DHT proxy support") + endif() + if (OPENDHT_PROXY_OPENSSL) + # 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}) + 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() - if (OPENDHT_PROXY_HTTP_PARSER_FORK) - add_definitions(-DOPENDHT_PROXY_HTTP_PARSER_FORK) + if (OPENDHT_PROXY_SERVER OR OPENDHT_PROXY_CLIENT OR OPENDHT_PEER_DISCOVERY) + add_definitions(-DASIO_STANDALONE) endif() -else() - set(OPENDHT_PROXY_OPENSSL OFF) -endif() -if (OPENDHT_PROXY_SERVER OR OPENDHT_PROXY_CLIENT OR OPENDHT_PEER_DISCOVERY) - add_definitions(-DASIO_STANDALONE) endif() # Build flags @@ -161,7 +178,6 @@ set (top_srcdir "${CMAKE_CURRENT_SOURCE_DIR}") list (APPEND opendht_SOURCES src/utils.cpp src/infohash.cpp - src/crypto.cpp src/default_types.cpp src/node.cpp src/value.cpp @@ -179,11 +195,7 @@ list (APPEND opendht_SOURCES src/routing_table.cpp src/node_cache.cpp src/network_engine.cpp - src/securedht.cpp - src/dhtrunner.cpp src/log.cpp - src/network_utils.cpp - src/thread_pool.cpp ) list (APPEND opendht_HEADERS @@ -191,7 +203,6 @@ list (APPEND opendht_HEADERS include/opendht/utils.h include/opendht/sockaddr.h include/opendht/rng.h - include/opendht/crypto.h include/opendht/infohash.h include/opendht/default_types.h include/opendht/node.h @@ -207,11 +218,27 @@ list (APPEND opendht_HEADERS include/opendht/securedht.h include/opendht/log.h include/opendht/log_enable.h - include/opendht/thread_pool.h - include/opendht/network_utils.h include/opendht.h ) +if (NOT OPENDHT_LIGHT) + list (APPEND opendht_SOURCES + src/crypto.cpp + src/securedht.cpp + src/dhtrunner.cpp + src/network_utils.cpp + src/thread_pool.cpp + ) + + list (APPEND opendht_HEADERS + include/opendht/crypto.h + include/opendht/securedht.h + include/opendht/dhtrunner.h + include/opendht/thread_pool.h + include/opendht/network_utils.h + ) +endif() + if (OPENDHT_PEER_DISCOVERY) list (APPEND opendht_SOURCES src/peer_discovery.cpp) list (APPEND opendht_HEADERS include/opendht/peer_discovery.h) @@ -384,13 +411,17 @@ if (OPENDHT_TESTS) tests/infohashtester.cpp tests/valuetester.h tests/valuetester.cpp - tests/cryptotester.h - tests/cryptotester.cpp - tests/dhtrunnertester.h - tests/dhtrunnertester.cpp - tests/threadpooltester.h - tests/threadpooltester.cpp ) + if (NOT OPENDHT_LIGHT) + list (APPEND test_FILES + tests/cryptotester.h + tests/cryptotester.cpp + tests/dhtrunnertester.h + tests/dhtrunnertester.cpp + tests/threadpooltester.h + tests/threadpooltester.cpp + ) + endif() if (OPENDHT_PROXY_SERVER AND OPENDHT_PROXY_CLIENT) list (APPEND test_FILES tests/httptester.h diff --git a/include/opendht/callbacks.h b/include/opendht/callbacks.h index 07b90bb44ebc944d3c726f2ff3848958ad3e96cb..b1fe2bbe600f6e9aade5462af33752b3b9a75f10 100644 --- a/include/opendht/callbacks.h +++ b/include/opendht/callbacks.h @@ -122,6 +122,7 @@ struct OPENDHT_PUBLIC Config { ssize_t max_peer_req_per_sec {0}; }; +#ifndef OPENDHT_LIGHT /** * SecureDht configuration. */ @@ -130,6 +131,7 @@ struct OPENDHT_PUBLIC SecureDhtConfig Config node_config {}; crypto::Identity id {}; }; +#endif static constexpr size_t DEFAULT_STORAGE_LIMIT {1024 * 1024 * 64}; diff --git a/include/opendht/default_types.h b/include/opendht/default_types.h index 11a3c558ba91e38156e8b71d1e8c3f1d03db3b1d..c4a33fc3bd87f2878ce4a82f6b984e053768ebc6 100644 --- a/include/opendht/default_types.h +++ b/include/opendht/default_types.h @@ -58,6 +58,7 @@ public: MSGPACK_DEFINE(service, data) }; +#ifndef OPENDHT_LIGHT template <typename T> class OPENDHT_PUBLIC SignedValue : public Value::Serializable<T> { @@ -102,7 +103,6 @@ public: - class OPENDHT_PUBLIC ImMessage : public SignedValue<ImMessage> { private: @@ -177,16 +177,8 @@ public: { pk.pack_array(2); pk.pack(id); -#if 1 pk.pack_bin(ice_data.size()); pk.pack_bin_body((const char*)ice_data.data(), ice_data.size()); -#else - // hack for backward compatibility with old opendht compiled with msgpack 1.0 - // remove when enough people have moved to new versions - pk.pack_array(ice_data.size()); - for (uint8_t b : ice_data) - pk.pack(b); -#endif } virtual void msgpack_unpack(msgpack::object o) @@ -200,6 +192,7 @@ public: Value::Id id {0}; Blob ice_data; }; +#endif /* "Peer" announcement */ @@ -261,8 +254,11 @@ private: SockAddr addr; }; - +#ifndef OPENDHT_LIGHT OPENDHT_PUBLIC extern const std::array<std::reference_wrapper<const ValueType>, 5> DEFAULT_TYPES; +#else +OPENDHT_PUBLIC extern const std::array<std::reference_wrapper<const ValueType>, 1> DEFAULT_TYPES; +#endif OPENDHT_PUBLIC extern const std::array<std::reference_wrapper<const ValueType>, 1> DEFAULT_INSECURE_TYPES; diff --git a/include/opendht/http.h b/include/opendht/http.h index 7c143ee3fb0b65f72826dda35d43550143ef3b21..8770156f49439e75274849f55c133aeb1ad6da30 100644 --- a/include/opendht/http.h +++ b/include/opendht/http.h @@ -118,7 +118,7 @@ private: template<typename T> T wrapCallabck(T cb) const { return [t=shared_from_this(),cb=std::move(cb)](auto ...params) { - cb(params...); + return cb(params...); }; } diff --git a/include/opendht/infohash.h b/include/opendht/infohash.h index e6d979af4819a996abdd6da3af79d8237938fb0e..13b916316e185705cdfffb63f614698f6835e037 100644 --- a/include/opendht/infohash.h +++ b/include/opendht/infohash.h @@ -50,7 +50,7 @@ namespace dht { using byte = uint8_t; namespace crypto { - OPENDHT_PUBLIC void hash(const uint8_t* data, size_t data_length, uint8_t* hash, size_t hash_length); +OPENDHT_PUBLIC void hash(const uint8_t* data, size_t data_length, uint8_t* hash, size_t hash_length); } /** diff --git a/include/opendht/value.h b/include/opendht/value.h index 4d58fe7c7886efc335580f412b03911a3eca91b3..9b1348d7c66de8cfd1bae5d19a5603cd37be5ed5 100644 --- a/include/opendht/value.h +++ b/include/opendht/value.h @@ -20,7 +20,7 @@ #pragma once #include "infohash.h" -#include "crypto.h" +//#include "crypto.h" #include "utils.h" #include "sockaddr.h" @@ -46,6 +46,12 @@ namespace dht { struct Value; struct Query; +namespace crypto { +class PublicKey; +class PrivateKey; +class Certificate; +} + /** * A storage policy is applied once to every incoming value storage requests. * If the policy returns false, the value is dropped. @@ -241,15 +247,9 @@ struct OPENDHT_PUBLIC Value }; } - static Filter OwnerFilter(const crypto::PublicKey& pk) { - return OwnerFilter(pk.getId()); - } + static Filter OwnerFilter(const crypto::PublicKey& pk); - static Filter OwnerFilter(const InfoHash& pkh) { - return [pkh](const Value& v) { - return v.owner and v.owner->getId() == pkh; - }; - } + static Filter OwnerFilter(const InfoHash& pkh); static Filter SeqNumFilter(uint16_t seq_no) { return [seq_no](const Value& v) { @@ -341,20 +341,13 @@ struct OPENDHT_PUBLIC Value * Afterward, checkSignature() will return true and owner will * be set to the corresponding public key. */ - void sign(const crypto::PrivateKey& key) { - if (isEncrypted()) - throw DhtException("Can't sign encrypted data."); - owner = std::make_shared<const crypto::PublicKey>(key.getPublicKey()); - signature = key.sign(getToSign()); - } + void sign(const crypto::PrivateKey& key); /** * Check that the value is signed and that the signature matches. * If true, the owner field will contain the signer public key. */ - bool checkSignature() const { - return isSigned() and owner->checkSignature(getToSign(), signature); - } + bool checkSignature() const; std::shared_ptr<const crypto::PublicKey> getOwner() const { return std::static_pointer_cast<const crypto::PublicKey>(owner); @@ -363,15 +356,7 @@ struct OPENDHT_PUBLIC Value /** * Sign the value with from and returns the encrypted version for to. */ - Value encrypt(const crypto::PrivateKey& from, const crypto::PublicKey& to) { - if (isEncrypted()) - throw DhtException("Data is already encrypted."); - setRecipient(to.getId()); - sign(from); - Value nv {id}; - nv.setCypher(to.encrypt(getToEncrypt())); - return nv; - } + Value encrypt(const crypto::PrivateKey& from, const crypto::PublicKey& to); Value() {} @@ -424,7 +409,11 @@ struct OPENDHT_PUBLIC Value inline bool operator== (const Value& o) { return id == o.id && (isEncrypted() ? cypher == o.cypher : - ((owner == o.owner || *owner == *o.owner) && type == o.type && data == o.data && user_type == o.user_type && signature == o.signature)); + ( +#ifndef OPENDHT_LIGHT + (owner == o.owner || *owner == *o.owner) && +#endif + type == o.type && data == o.data && user_type == o.user_type && signature == o.signature)); } void setRecipient(const InfoHash& r) { @@ -482,7 +471,8 @@ struct OPENDHT_PUBLIC Value template <typename Packer> void msgpack_pack_to_sign(Packer& pk) const { - bool has_owner = owner && *owner; +#ifndef OPENDHT_LIGHT + bool has_owner = owner && *owner pk.pack_map((user_type.empty()?0:1) + (has_owner?(recipient ? 5 : 4):2)); if (has_owner) { // isSigned pk.pack(std::string("seq")); pk.pack(seq); @@ -491,6 +481,9 @@ struct OPENDHT_PUBLIC Value pk.pack(std::string("to")); pk.pack(recipient); } } +#else + pk.pack_map((user_type.empty()?0:1) + 2); +#endif pk.pack(std::string("type")); pk.pack(type); pk.pack(std::string("data")); pk.pack_bin(data.size()); pk.pack_bin_body((const char*)data.data(), data.size()); @@ -535,9 +528,11 @@ struct OPENDHT_PUBLIC Value pk.pack(static_cast<uint64_t>(type)); break; case Value::Field::OwnerPk: +#ifndef OPENDHT_LIGHT if (owner) owner->msgpack_pack(pk); else +#endif InfoHash().msgpack_pack(pk); break; case Value::Field::SeqNum: diff --git a/src/default_types.cpp b/src/default_types.cpp index 6bf39f3d537b6ecdfc7d3ec43882c8aaedc6829b..b2abb49be142e8d7f6e833583c463e3813166138 100644 --- a/src/default_types.cpp +++ b/src/default_types.cpp @@ -15,6 +15,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include "default_types.h" @@ -83,6 +86,8 @@ IpServiceAnnouncement::storePolicy(InfoHash h, std::shared_ptr<Value>& v, const const ValueType DhtMessage::TYPE(1, "DHT message", std::chrono::minutes(5), DhtMessage::storePolicy); const ValueType IpServiceAnnouncement::TYPE(2, "Internet Service Announcement", std::chrono::minutes(15), IpServiceAnnouncement::storePolicy); + +#ifndef OPENDHT_LIGHT const ValueType ImMessage::TYPE = {3, "IM message", std::chrono::minutes(5)}; const ValueType TrustRequest::TYPE = {4, "Certificate trust request", std::chrono::hours(24*7)}; const ValueType IceCandidates::TYPE = {5, "ICE candidates", std::chrono::minutes(1)}; @@ -96,6 +101,13 @@ DEFAULT_TYPES IceCandidates::TYPE, TrustRequest::TYPE }}; +#else +const std::array<std::reference_wrapper<const ValueType>, 1> +DEFAULT_TYPES +{{ + ValueType::USER_DATA +}}; +#endif const std::array<std::reference_wrapper<const ValueType>, 1> DEFAULT_INSECURE_TYPES diff --git a/src/value.cpp b/src/value.cpp index 0750a530c71c3875b713156af5223634cf4ca280..61014b0006b9089d411cb4f508185ff025bda998 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -22,9 +22,12 @@ #endif #include "value.h" - #include "default_types.h" +#include "callbacks.h" + +#ifndef OPENDHT_LIGHT #include "securedht.h" // print certificate ID +#endif #ifdef OPENDHT_JSONCPP #include "base64.h" @@ -42,6 +45,46 @@ Value::Filter bindFilterRaw(FilterRaw raw_filter, void* user_data) { }; } +#ifndef OPENDHT_LIGHT +Value::Filter +Value::OwnerFilter(const crypto::PublicKey& pk) { + return OwnerFilter(pk.getId()); +} + + +Value::Filter +Value::OwnerFilter(const InfoHash& pkh) { + return [pkh](const Value& v) { + return v.owner and v.owner->getId() == pkh; + }; +} + +void +Value::sign(const crypto::PrivateKey& key) { + if (isEncrypted()) + throw DhtException("Can't sign encrypted data."); + owner = std::make_shared<const crypto::PublicKey>(key.getPublicKey()); + signature = key.sign(getToSign()); +} + +bool +Value::checkSignature() const { + return isSigned() and owner->checkSignature(getToSign(), signature); +} + +Value +Value::encrypt(const crypto::PrivateKey& from, const crypto::PublicKey& to) { + if (isEncrypted()) + throw DhtException("Data is already encrypted."); + setRecipient(to.getId()); + sign(from); + Value nv {id}; + nv.setCypher(to.encrypt(getToEncrypt())); + return nv; +} + +#endif + std::ostream& operator<< (std::ostream& s, const Value& v) { auto flags(s.flags()); @@ -56,7 +99,9 @@ std::ostream& operator<< (std::ostream& s, const Value& v) if (not v.isEncrypted()) { if (v.type == IpServiceAnnouncement::TYPE.id) { s << IpServiceAnnouncement(v.data); - } else if (v.type == CERTIFICATE_TYPE.id) { + } +#ifndef OPENDHT_LIGHT + else if (v.type == CERTIFICATE_TYPE.id) { s << "Certificate"; #ifdef OPENDHT_LOG_CRT_ID try { @@ -66,7 +111,9 @@ std::ostream& operator<< (std::ostream& s, const Value& v) s << " (invalid)"; } #endif - } else { + } +#endif + else { s << "Data (type: " << v.type << " ): "; s << std::hex; for (auto i : v.data) @@ -163,9 +210,12 @@ Value::msgpack_unpack_body(const msgpack::object& o) seq = rseq->as<decltype(seq)>(); else throw msgpack::type_error(); + +#ifndef OPENDHT_LIGHT crypto::PublicKey new_owner; new_owner.msgpack_unpack(*rowner); owner = std::make_shared<const crypto::PublicKey>(std::move(new_owner)); +#endif if (auto rrecipient = findMapValue(*rbody, "to")) { recipient = rrecipient->as<InfoHash>(); } @@ -194,11 +244,13 @@ Value::Value(Json::Value& json) } if (json.isMember("seq")) seq = json["seq"].asInt(); +#ifndef OPENDHT_LIGHT if (json.isMember("owner")) { auto ownerStr = json["owner"].asString(); auto ownerBlob = std::vector<unsigned char>(ownerStr.begin(), ownerStr.end()); owner = std::make_shared<const crypto::PublicKey>(ownerBlob); } +#endif if (json.isMember("to")) { auto toStr = json["to"].asString(); recipient = InfoHash(toStr); @@ -318,9 +370,11 @@ FieldValueIndex::FieldValueIndex(const Value& v, const Select& s) case Value::Field::ValueType: index[f] = {f, v.type}; break; +#ifndef OPENDHT_LIGHT case Value::Field::OwnerPk: index[f] = {f, v.owner ? v.owner->getId() : InfoHash() }; break; +#endif case Value::Field::SeqNum: index[f] = {f, v.seq}; break;