diff --git a/include/opendht/callbacks.h b/include/opendht/callbacks.h index 7f09eb3357309300a107c014e91a46f4f9a9ce36..5318c08c336385f584d15e484c5cc32a5c96ccca 100644 --- a/include/opendht/callbacks.h +++ b/include/opendht/callbacks.h @@ -30,23 +30,44 @@ namespace dht { struct Node; +/** + * Current status of a DHT node. + */ enum class NodeStatus { Disconnected, // 0 nodes Connecting, // 1+ nodes Connected // 1+ good nodes }; +/** + * Dht configuration. + */ struct Config { + /** DHT node ID */ InfoHash node_id; + + /** + * DHT network ID. A node will only talk with other nodes having + * the same network ID. + * Network ID 0 (default) represents the main public network. + */ + NetId network; + + /** For testing purposes only, enables bootstrap mode */ bool is_bootstrap; }; +/** + * SecureDht configuration. + */ struct SecureDhtConfig { Config node_config; crypto::Identity id; }; +static constexpr size_t DEFAULT_STORAGE_LIMIT {1024 * 1024 * 64}; + using ValuesExport = std::pair<InfoHash, Blob>; using GetCallback = std::function<bool(const std::vector<std::shared_ptr<Value>>& values)>; @@ -57,8 +78,6 @@ using CertificateStoreQuery = std::function<std::vector<std::shared_ptr<crypto:: typedef bool (*GetCallbackRaw)(std::shared_ptr<Value>, void *user_data); -static constexpr size_t DEFAULT_STORAGE_LIMIT {1024 * 1024 * 64}; - GetCallbackSimple bindGetCb(GetCallbackRaw raw_cb, void* user_data); GetCallback bindGetCb(GetCallbackSimple cb); diff --git a/include/opendht/dhtrunner.h b/include/opendht/dhtrunner.h index dc342bf9951c2e73a901ad1d02eddcd6f6543bda..6ee06ed0e224ead41ef776e60c824860e9d27d97 100644 --- a/include/opendht/dhtrunner.h +++ b/include/opendht/dhtrunner.h @@ -268,12 +268,13 @@ public: * @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(in_port_t port, const crypto::Identity identity, bool threaded = false, bool is_bootstrap = false) { + void run(in_port_t port, const crypto::Identity identity, bool threaded = false, NetId network = 0) { run(port, { /*.dht_config = */{ /*.node_config = */{ /*.node_id = */{}, - /*.is_bootstrap = */is_bootstrap + /*.network = */network, + /*.is_bootstrap = */false }, /*.id = */identity }, diff --git a/include/opendht/network_engine.h b/include/opendht/network_engine.h index 3a37354ee49707c76faeb80cb702ad7ac5000fba..3d336c354e3e04d76ce9e03d33d0e352eba16bf1 100644 --- a/include/opendht/network_engine.h +++ b/include/opendht/network_engine.h @@ -256,7 +256,7 @@ public: using RequestExpiredCb = std::function<void(const Request&, bool)>; NetworkEngine(Logger& log, Scheduler& scheduler) : myid(zeroes), DHT_LOG(log), scheduler(scheduler) {} - NetworkEngine(InfoHash& myid, int s, int s6, Logger& log, Scheduler& scheduler, + NetworkEngine(InfoHash& myid, NetId net, int s, int s6, Logger& log, Scheduler& scheduler, decltype(NetworkEngine::onError) onError, decltype(NetworkEngine::onNewNode) onNewNode, decltype(NetworkEngine::onReportedAddr) onReportedAddr, @@ -266,7 +266,7 @@ public: decltype(NetworkEngine::onListen) onListen, decltype(NetworkEngine::onAnnounce) onAnnounce) : onError(onError), onNewNode(onNewNode), onReportedAddr(onReportedAddr), onPing(onPing), onFindNode(onFindNode), - onGetValues(onGetValues), onListen(onListen), onAnnounce(onAnnounce), myid(myid), + onGetValues(onGetValues), onListen(onListen), onAnnounce(onAnnounce), myid(myid), network(net), dht_socket(s), dht_socket6(s6), DHT_LOG(log), scheduler(scheduler) { transaction_id = std::uniform_int_distribution<decltype(transaction_id)>{1}(rd_device); @@ -376,6 +376,7 @@ private: /* DHT info */ const InfoHash& myid; + const NetId network {0}; const int dht_socket {-1}; const int dht_socket6 {-1}; const Logger& DHT_LOG; diff --git a/include/opendht/routing_table.h b/include/opendht/routing_table.h index 5823999f42e1f12aa105c52d19ee517ed4998710..573d8680d7a8fb56d16feff20caffbe6c27f9e0a 100644 --- a/include/opendht/routing_table.h +++ b/include/opendht/routing_table.h @@ -23,6 +23,8 @@ namespace dht { +static constexpr unsigned TARGET_NODES {8}; + struct Bucket { Bucket() : cached() {} Bucket(sa_family_t af, const InfoHash& f = {}, time_point t = time_point::min()) diff --git a/include/opendht/utils.h b/include/opendht/utils.h index 2a0ca6861d88fec59d712af2b0f4b32507023490..a5f676c007b6d897ffc792dc32ed01426e17cf07 100644 --- a/include/opendht/utils.h +++ b/include/opendht/utils.h @@ -40,9 +40,8 @@ namespace dht { -static constexpr unsigned TARGET_NODES {8}; - using Address = std::pair<sockaddr_storage, socklen_t>; +using NetId = uint32_t; using want_t = int_fast8_t; std::string print_addr(const sockaddr* sa, socklen_t slen); diff --git a/src/dht.cpp b/src/dht.cpp index f38b365ee8ccbcfdfbe42310a89babc03e108e52..590bea804180f610b54b64d50782e3af0490963a 100644 --- a/src/dht.cpp +++ b/src/dht.cpp @@ -2102,7 +2102,7 @@ Dht::Dht() : store(), network_engine(DHT_LOG, scheduler) {} Dht::Dht(int s, int s6, Config config) : myid(config.node_id), is_bootstrap(config.is_bootstrap), store(), - network_engine(myid, s, s6, DHT_LOG, scheduler, + network_engine(myid, config.network, s, s6, DHT_LOG, scheduler, std::bind(&Dht::onError, this, _1, _2), std::bind(&Dht::onNewNode, this, _1, _2), std::bind(&Dht::onReportedAddr, this, _1, _2, _3), diff --git a/src/network_engine.cpp b/src/network_engine.cpp index e24a1ddfd7d4e667be7fa6930384170c6a9acb0f..15f2431c958d7dfbd6c2a95dc0f27aca89adef5d 100644 --- a/src/network_engine.cpp +++ b/src/network_engine.cpp @@ -49,6 +49,7 @@ static const uint8_t v4prefix[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; +constexpr unsigned SEND_NODES {8}; enum class MessageType { Error = 0, @@ -63,6 +64,7 @@ enum class MessageType { struct ParsedMessage { MessageType type; InfoHash id; /* the id of the sender */ + NetId network {0}; /* network id */ InfoHash info_hash; /* hash for which values are requested */ InfoHash target; /* target id around which to find nodes */ NetworkEngine::TransId tid; /* transaction id */ @@ -293,6 +295,11 @@ NetworkEngine::processMessage(const uint8_t *buf, size_t buflen, const sockaddr* return; } + if (msg.network != network) { + DHT_LOG.DEBUG("Received message from other network %u.", msg.network); + return; + } + if (msg.id == myid || msg.id == zeroes) { DHT_LOG.DEBUG("Received message from self."); return; @@ -451,9 +458,10 @@ packToken(msgpack::packer<msgpack::sbuffer>& pk, Blob token) } void -insertAddr(msgpack::packer<msgpack::sbuffer>& pk, const sockaddr *sa, socklen_t) +insertAddr(msgpack::packer<msgpack::sbuffer>& pk, const sockaddr *sa, socklen_t sa_len) { - size_t addr_len = (sa->sa_family == AF_INET) ? sizeof(in_addr) : sizeof(in6_addr); + size_t addr_len = std::min<size_t>(sa_len, + (sa->sa_family == AF_INET) ? sizeof(in_addr) : sizeof(in6_addr)); void* addr_ptr = (sa->sa_family == AF_INET) ? (void*)&((sockaddr_in*)sa)->sin_addr : (void*)&((sockaddr_in6*)sa)->sin6_addr; pk.pack("sa"); @@ -485,7 +493,7 @@ NetworkEngine::sendPing(std::shared_ptr<Node> node, RequestCb on_done, RequestEx auto tid = TransId {TransPrefix::PING, getNewTid()}; msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(5); + pk.pack_map(5+(network?1:0)); pk.pack(std::string("a")); pk.pack_map(1); pk.pack(std::string("id")); pk.pack(myid); @@ -495,6 +503,9 @@ NetworkEngine::sendPing(std::shared_ptr<Node> node, RequestCb on_done, RequestEx pk.pack_bin_body((const char*)tid.data(), tid.size()); pk.pack(std::string("y")); pk.pack(std::string("q")); pk.pack(std::string("v")); pk.pack(my_v); + if (network) { + pk.pack(std::string("n")); pk.pack(network); + } Blob b {buffer.data(), buffer.data() + buffer.size()}; std::shared_ptr<Request> req(new Request {tid.getTid(), node, std::move(b), @@ -519,7 +530,7 @@ void NetworkEngine::sendPong(const sockaddr* sa, socklen_t salen, TransId tid) { msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(4); + pk.pack_map(4+(network?1:0)); pk.pack(std::string("r")); pk.pack_map(2); pk.pack(std::string("id")); pk.pack(myid); @@ -529,6 +540,9 @@ NetworkEngine::sendPong(const sockaddr* sa, socklen_t salen, TransId tid) { pk.pack_bin_body((const char*)tid.data(), tid.size()); pk.pack(std::string("y")); pk.pack(std::string("r")); pk.pack(std::string("v")); pk.pack(my_v); + if (network) { + pk.pack(std::string("n")); pk.pack(network); + } send(buffer.data(), buffer.size(), 0, sa, salen); } @@ -539,7 +553,7 @@ NetworkEngine::sendFindNode(std::shared_ptr<Node> n, const InfoHash& target, wan auto tid = TransId {TransPrefix::FIND_NODE, getNewTid()}; msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(5); + pk.pack_map(5+(network?1:0)); pk.pack(std::string("a")); pk.pack_map(2 + (want>0?1:0)); pk.pack(std::string("id")); pk.pack(myid); @@ -556,7 +570,9 @@ NetworkEngine::sendFindNode(std::shared_ptr<Node> n, const InfoHash& target, wan pk.pack_bin_body((const char*)tid.data(), tid.size()); pk.pack(std::string("y")); pk.pack(std::string("q")); pk.pack(std::string("v")); pk.pack(my_v); - + if (network) { + pk.pack(std::string("n")); pk.pack(network); + } Blob b {buffer.data(), buffer.data() + buffer.size()}; std::shared_ptr<Request> req(new Request {tid.getTid(), n, std::move(b), @@ -583,7 +599,7 @@ NetworkEngine::sendGetValues(std::shared_ptr<Node> n, const InfoHash& info_hash, auto tid = TransId {TransPrefix::GET_VALUES, getNewTid()}; msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(5); + pk.pack_map(5+(network?1:0)); pk.pack(std::string("a")); pk.pack_map(2 + (want>0?1:0)); pk.pack(std::string("id")); pk.pack(myid); @@ -600,6 +616,9 @@ NetworkEngine::sendGetValues(std::shared_ptr<Node> n, const InfoHash& info_hash, pk.pack_bin_body((const char*)tid.data(), tid.size()); pk.pack(std::string("y")); pk.pack(std::string("q")); pk.pack(std::string("v")); pk.pack(my_v); + if (network) { + pk.pack(std::string("n")); pk.pack(network); + } Blob b {buffer.data(), buffer.data() + buffer.size()}; std::shared_ptr<Request> req(new Request {tid.getTid(), n, std::move(b), @@ -664,7 +683,7 @@ NetworkEngine::sendNodesValues(const sockaddr* sa, socklen_t salen, TransId tid, const std::vector<std::shared_ptr<Value>>& st, const Blob& token) { msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(4); + pk.pack_map(4+(network?1:0)); pk.pack(std::string("r")); pk.pack_map(2 + (not st.empty()?1:0) + (nodes.size()>0?1:0) + (nodes6.size()>0?1:0) + (not token.empty()?1:0)); @@ -715,6 +734,9 @@ NetworkEngine::sendNodesValues(const sockaddr* sa, socklen_t salen, TransId tid, pk.pack_bin_body((const char*)tid.data(), tid.size()); pk.pack(std::string("y")); pk.pack(std::string("r")); pk.pack(std::string("v")); pk.pack(my_v); + if (network) { + pk.pack(std::string("n")); pk.pack(network); + } send(buffer.data(), buffer.size(), 0, sa, salen); } @@ -725,7 +747,7 @@ NetworkEngine::bufferNodes(sa_family_t af, const InfoHash& id, std::vector<std:: std::sort(nodes.begin(), nodes.end(), [&](const std::shared_ptr<Node>& a, const std::shared_ptr<Node>& b){ return id.xorCmp(a->id, b->id) < 0; }); - size_t nnode = std::min<size_t>(TARGET_NODES, nodes.size()); + size_t nnode = std::min<size_t>(SEND_NODES, nodes.size()); Blob bnodes; if (af == AF_INET) { bnodes.resize(NODE4_INFO_BUF_LEN * nnode); @@ -777,7 +799,7 @@ NetworkEngine::sendListen(std::shared_ptr<Node> n, const InfoHash& infohash, con auto tid = TransId {TransPrefix::LISTEN, getNewTid()}; msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(5); + pk.pack_map(5+(network?1:0)); pk.pack(std::string("a")); pk.pack_map(3); pk.pack(std::string("id")); pk.pack(myid); @@ -789,7 +811,9 @@ NetworkEngine::sendListen(std::shared_ptr<Node> n, const InfoHash& infohash, con pk.pack_bin_body((const char*)tid.data(), tid.size()); pk.pack(std::string("y")); pk.pack(std::string("q")); pk.pack(std::string("v")); pk.pack(my_v); - + if (network) { + pk.pack(std::string("n")); pk.pack(network); + } Blob b {buffer.data(), buffer.data() + buffer.size()}; std::shared_ptr<Request> req(new Request {tid.getTid(), n, std::move(b), @@ -812,7 +836,7 @@ void NetworkEngine::sendListenConfirmation(const sockaddr* sa, socklen_t salen, TransId tid) { msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(4); + pk.pack_map(4+(network?1:0)); pk.pack(std::string("r")); pk.pack_map(2); pk.pack(std::string("id")); pk.pack(myid); @@ -822,6 +846,9 @@ NetworkEngine::sendListenConfirmation(const sockaddr* sa, socklen_t salen, Trans pk.pack_bin_body((const char*)tid.data(), tid.size()); pk.pack(std::string("y")); pk.pack(std::string("r")); pk.pack(std::string("v")); pk.pack(my_v); + if (network) { + pk.pack(std::string("n")); pk.pack(network); + } send(buffer.data(), buffer.size(), 0, sa, salen); } @@ -832,7 +859,7 @@ NetworkEngine::sendAnnounceValue(std::shared_ptr<Node> n, const InfoHash& infoha auto tid = TransId {TransPrefix::ANNOUNCE_VALUES, getNewTid()}; msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(5); + pk.pack_map(5+(network?1:0)); pk.pack(std::string("a")); pk.pack_map((created < scheduler.time() ? 5 : 4)); pk.pack(std::string("id")); pk.pack(myid); @@ -849,6 +876,9 @@ NetworkEngine::sendAnnounceValue(std::shared_ptr<Node> n, const InfoHash& infoha pk.pack_bin_body((const char*)tid.data(), tid.size()); pk.pack(std::string("y")); pk.pack(std::string("q")); pk.pack(std::string("v")); pk.pack(my_v); + if (network) { + pk.pack(std::string("n")); pk.pack(network); + } Blob b {buffer.data(), buffer.data() + buffer.size()}; std::shared_ptr<Request> req(new Request {tid.getTid(), n, std::move(b), @@ -878,7 +908,7 @@ void NetworkEngine::sendValueAnnounced(const sockaddr* sa, socklen_t salen, TransId tid, Value::Id vid) { msgpack::sbuffer buffer; msgpack::packer<msgpack::sbuffer> pk(&buffer); - pk.pack_map(4); + pk.pack_map(4+(network?1:0)); pk.pack(std::string("r")); pk.pack_map(3); pk.pack(std::string("id")); pk.pack(myid); @@ -889,6 +919,9 @@ NetworkEngine::sendValueAnnounced(const sockaddr* sa, socklen_t salen, TransId t pk.pack_bin_body((const char*)tid.data(), tid.size()); pk.pack(std::string("y")); pk.pack(std::string("r")); pk.pack(std::string("v")); pk.pack(my_v); + if (network) { + pk.pack(std::string("n")); pk.pack(network); + } send(buffer.data(), buffer.size(), 0, sa, salen); } @@ -917,6 +950,9 @@ NetworkEngine::sendError(const sockaddr* sa, pk.pack_bin_body((const char*)tid.data(), tid.size()); pk.pack(std::string("y")); pk.pack(std::string("e")); pk.pack(std::string("v")); pk.pack(my_v); + if (network) { + pk.pack(std::string("n")); pk.pack(network); + } send(buffer.data(), buffer.size(), 0, sa, salen); } @@ -960,6 +996,9 @@ ParsedMessage::msgpack_unpack(msgpack::object msg) error_code = e->via.array.ptr[0].as<uint16_t>(); } + if (auto netid = findMapValue(msg, "n")) + network = netid->as<NetId>(); + if (auto rid = findMapValue(req, "id")) id = {*rid}; diff --git a/tools/dhtchat.cpp b/tools/dhtchat.cpp index 359c0630a11122340cd16c4a2fe75659607d9868..981b551dda281b1b2715e17d906605f7ccb4189f 100644 --- a/tools/dhtchat.cpp +++ b/tools/dhtchat.cpp @@ -53,7 +53,7 @@ main(int argc, char **argv) throw std::runtime_error(std::string("Error initializing GnuTLS: ")+gnutls_strerror(rc)); DhtRunner dht; - dht.run(params.port, dht::crypto::generateIdentity("DHT Chat Node"), true); + dht.run(params.port, dht::crypto::generateIdentity("DHT Chat Node"), true, params.network); if (not params.bootstrap.first.empty()) dht.bootstrap(params.bootstrap.first.c_str(), params.bootstrap.second.c_str()); diff --git a/tools/dhtnode.cpp b/tools/dhtnode.cpp index f7acaa4af31fe550b0aa5aff69818171683c7d59..49ddef7ef03e19c18b1df6558c5045a40b06296c 100644 --- a/tools/dhtnode.cpp +++ b/tools/dhtnode.cpp @@ -256,7 +256,7 @@ main(int argc, char **argv) crt = dht::crypto::generateIdentity("DHT Node", ca_tmp); } - dht.run(params.port, crt, true, params.is_bootstrap_node); + dht.run(params.port, crt, true, params.network); if (params.log) { if (not params.logfile.empty()) diff --git a/tools/dhtscanner.cpp b/tools/dhtscanner.cpp index eb323781d203d39e3f17f709e48fadbda3e8c5ba..f93c31e7f17f2c76845a5bd3458a1bb481194f6b 100644 --- a/tools/dhtscanner.cpp +++ b/tools/dhtscanner.cpp @@ -80,7 +80,7 @@ main(int argc, char **argv) auto crt_tmp = dht::crypto::generateIdentity("Scanner node", ca_tmp); DhtRunner dht; - dht.run(params.port, crt_tmp, true, [](dht::NodeStatus /* ipv4 */, dht::NodeStatus /* ipv6 */) {}); + dht.run(params.port, crt_tmp, true, params.network); if (not params.bootstrap.first.empty()) dht.bootstrap(params.bootstrap.first.c_str(), params.bootstrap.second.c_str()); diff --git a/tools/tools_common.h b/tools/tools_common.h index 144bd521f394536cb9725f9b42f74f2902b8e614..84347082d9242956c38bac1fe31e86a48dbe0de0 100644 --- a/tools/tools_common.h +++ b/tools/tools_common.h @@ -142,6 +142,7 @@ struct dht_params { bool log {false}; std::string logfile {}; in_port_t port {0}; + dht::NetId network {0}; bool is_bootstrap_node {false}; bool generate_identity {false}; bool daemonize {false}; @@ -151,6 +152,7 @@ struct dht_params { static const constexpr struct option long_options[] = { {"help", no_argument, nullptr, 'h'}, {"port", required_argument, nullptr, 'p'}, + {"net", required_argument, nullptr, 'n'}, {"bootstrap", optional_argument, nullptr, 'b'}, {"identity", no_argument , nullptr, 'i'}, {"verbose", no_argument , nullptr, 'v'}, @@ -162,7 +164,7 @@ dht_params parseArgs(int argc, char **argv) { dht_params params; int opt; - while ((opt = getopt_long(argc, argv, ":hidv:p:b:", long_options, nullptr)) != -1) { + while ((opt = getopt_long(argc, argv, ":hidv:p:n:b:", long_options, nullptr)) != -1) { switch (opt) { case 'p': { int port_arg = atoi(optarg); @@ -172,6 +174,9 @@ parseArgs(int argc, char **argv) { std::cout << "Invalid port: " << port_arg << std::endl; } break; + case 'n': + params.network = strtoul(optarg, nullptr, 0); + break; case 'b': if (optarg) { params.bootstrap = splitPort((optarg[0] == '=') ? optarg+1 : optarg);