librats 0.7.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -4
- package/lib/index.d.ts +9 -22
- package/native-src/CMakeLists.txt +132 -50
- package/native-src/cmake/ratsConfig.cmake.in +8 -0
- package/native-src/src/bt_network.cpp +296 -183
- package/native-src/src/bt_network.h +25 -5
- package/native-src/src/crypto/sha256.c +1 -1
- package/native-src/src/dht.cpp +297 -47
- package/native-src/src/dht.h +70 -6
- package/native-src/src/file_transfer.cpp +1185 -1578
- package/native-src/src/file_transfer.h +240 -521
- package/native-src/src/io_poller.cpp +917 -0
- package/native-src/src/io_poller.h +138 -0
- package/native-src/src/krpc.cpp +161 -96
- package/native-src/src/krpc.h +18 -4
- package/native-src/src/librats.cpp +812 -1236
- package/native-src/src/librats.h +207 -208
- package/native-src/src/librats_bittorrent.cpp +1 -5
- package/native-src/src/librats_c.cpp +22 -39
- package/native-src/src/librats_discovery.cpp +377 -0
- package/native-src/src/librats_encryption.cpp +130 -283
- package/native-src/src/librats_file_transfer.cpp +27 -109
- package/native-src/src/librats_gossipsub.cpp +1 -5
- package/native-src/src/librats_ice.cpp +5 -1
- package/native-src/src/librats_log_macros.h +36 -0
- package/native-src/src/librats_logging.cpp +1 -7
- package/native-src/src/librats_mdns.cpp +1 -11
- package/native-src/src/librats_persistence.cpp +1 -11
- package/native-src/src/librats_reconnection.cpp +2 -13
- package/native-src/src/librats_statistic.cpp +105 -0
- package/native-src/src/socket.cpp +15 -3
- package/package.json +1 -1
- package/scripts/build-librats.js +3 -0
- package/scripts/prepare-package.js +10 -0
- package/src/librats_node.cpp +53 -64
package/native-src/src/dht.h
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
#include <atomic>
|
|
14
14
|
#include <chrono>
|
|
15
15
|
#include <memory>
|
|
16
|
+
#include <random>
|
|
16
17
|
#include <condition_variable>
|
|
17
18
|
|
|
18
19
|
// Hash specialization for Peer and NodeId (must be defined before use in unordered_map/set)
|
|
@@ -165,8 +166,12 @@ public:
|
|
|
165
166
|
* Constructor
|
|
166
167
|
* @param port The UDP port to bind to (default: 6881)
|
|
167
168
|
* @param bind_address The interface IP address to bind to (empty for all interfaces)
|
|
169
|
+
* @param data_directory Directory for routing-table persistence
|
|
170
|
+
* @param address_family Address family this node operates on. IPv4 and IPv6 form
|
|
171
|
+
* separate Kademlia networks (BEP 32), so each family needs its own DhtClient.
|
|
168
172
|
*/
|
|
169
|
-
DhtClient(int port = DHT_PORT, const std::string& bind_address = "", const std::string& data_directory = ""
|
|
173
|
+
DhtClient(int port = DHT_PORT, const std::string& bind_address = "", const std::string& data_directory = "",
|
|
174
|
+
AddressFamily address_family = AddressFamily::IPv4);
|
|
170
175
|
|
|
171
176
|
/**
|
|
172
177
|
* Destructor
|
|
@@ -222,9 +227,33 @@ public:
|
|
|
222
227
|
|
|
223
228
|
/**
|
|
224
229
|
* Get our node ID
|
|
225
|
-
* @return The node ID
|
|
230
|
+
* @return The node ID (returned by value; the ID may be regenerated at runtime
|
|
231
|
+
* when our external IP is learned, see set_external_ip)
|
|
226
232
|
*/
|
|
227
|
-
|
|
233
|
+
NodeId get_node_id() const { return node_id_; }
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Set our external (public) IP address and regenerate the node ID from it per BEP 42.
|
|
237
|
+
* IPv4/IPv6 node IDs must be derived from the matching-family external address, so this
|
|
238
|
+
* is a no-op if the address family does not match this instance. Safe to call at runtime;
|
|
239
|
+
* the routing table is re-bucketed against the new ID. Non-public/invalid addresses are ignored.
|
|
240
|
+
* @param ip External IP address as seen by the network (e.g. from STUN or DHT "ip" voting)
|
|
241
|
+
*/
|
|
242
|
+
void set_external_ip(const std::string& ip);
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Get the external address currently used to derive our node ID ("" if none/random).
|
|
246
|
+
*/
|
|
247
|
+
std::string get_external_address() const;
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* BEP 42 helpers (public for testing / explicit use).
|
|
251
|
+
* generate_node_id_from_ip: build an IP-derived node ID (random where BEP 42 allows).
|
|
252
|
+
* verify_node_id_for_ip: check whether a node ID is valid for the given source IP
|
|
253
|
+
* (always true for non-public IPs, which cannot be verified).
|
|
254
|
+
*/
|
|
255
|
+
static bool generate_node_id_from_ip(const std::string& ip, NodeId& out, std::mt19937& gen);
|
|
256
|
+
static bool verify_node_id_for_ip(const NodeId& id, const std::string& ip);
|
|
228
257
|
|
|
229
258
|
/**
|
|
230
259
|
* Get number of nodes in routing table
|
|
@@ -337,11 +366,26 @@ public:
|
|
|
337
366
|
#endif // RATS_SEARCH_FEATURES
|
|
338
367
|
|
|
339
368
|
/**
|
|
340
|
-
* Get default BitTorrent DHT bootstrap nodes
|
|
369
|
+
* Get default BitTorrent DHT bootstrap nodes.
|
|
370
|
+
* Hostnames are resolved per-family at send time, so the same list serves both
|
|
371
|
+
* IPv4 and IPv6 (nodes without an AAAA record are simply skipped on IPv6).
|
|
341
372
|
* @return Vector of bootstrap nodes
|
|
342
373
|
*/
|
|
343
374
|
static std::vector<Peer> get_default_bootstrap_nodes();
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Address family this DHT node operates on.
|
|
378
|
+
*/
|
|
379
|
+
AddressFamily address_family() const { return address_family_; }
|
|
380
|
+
bool is_ipv6() const { return address_family_ == AddressFamily::IPv6; }
|
|
344
381
|
|
|
382
|
+
/**
|
|
383
|
+
* Compute the routing-table persistence file path for this instance.
|
|
384
|
+
* Includes the address family so the IPv4 and IPv6 nodes (which may share a port)
|
|
385
|
+
* never overwrite each other's saved state.
|
|
386
|
+
*/
|
|
387
|
+
std::string routing_table_file_path() const;
|
|
388
|
+
|
|
345
389
|
/**
|
|
346
390
|
* Save routing table to disk
|
|
347
391
|
* @return true if successful, false otherwise
|
|
@@ -364,10 +408,23 @@ private:
|
|
|
364
408
|
int port_;
|
|
365
409
|
std::string bind_address_;
|
|
366
410
|
std::string data_directory_;
|
|
367
|
-
|
|
411
|
+
AddressFamily address_family_; // IPv4 or IPv6 (this node's Kademlia network)
|
|
412
|
+
NodeId node_id_; // protected by routing_table_mutex_ for writes; lock-free reads are benign
|
|
368
413
|
socket_t socket_;
|
|
369
414
|
std::atomic<bool> running_;
|
|
370
|
-
|
|
415
|
+
|
|
416
|
+
// BEP 42: external-IP-derived node ID.
|
|
417
|
+
// We learn our external address from the top-level "ip" field other nodes echo back in
|
|
418
|
+
// their responses, and vote across distinct responders before trusting it (so a single
|
|
419
|
+
// malicious node cannot poison our node ID). external_address_/voting are guarded by
|
|
420
|
+
// external_ip_mutex_, which is NEVER held while acquiring any other DHT mutex.
|
|
421
|
+
std::string external_address_; // IP currently used to derive node_id_ ("" = random)
|
|
422
|
+
std::unordered_map<std::string, int> external_ip_votes_;// reported external IP -> vote count
|
|
423
|
+
std::unordered_set<std::string> external_ip_voters_; // responder IPs already counted (dedup)
|
|
424
|
+
mutable std::mutex external_ip_mutex_; // Lock order: independent (never nested with others)
|
|
425
|
+
static constexpr int EXTERNAL_IP_VOTE_THRESHOLD = 5; // distinct responders that must agree
|
|
426
|
+
static constexpr size_t MAX_EXTERNAL_IP_VOTERS = 1000; // cap voter set to bound memory
|
|
427
|
+
|
|
371
428
|
// ============================================================================
|
|
372
429
|
// MUTEX LOCK ORDER - CRITICAL: Always acquire mutexes in this order to avoid deadlocks
|
|
373
430
|
// ============================================================================
|
|
@@ -507,6 +564,9 @@ private:
|
|
|
507
564
|
// Used to decide whether to respond with neighbor_id (spider contact) or real node_id (organic DHT)
|
|
508
565
|
std::unordered_set<std::string> spider_contacted_ips_;
|
|
509
566
|
|
|
567
|
+
// Rate-limit re-bootstrapping in spider_walk to avoid DDOSing bootstrap nodes
|
|
568
|
+
std::chrono::steady_clock::time_point last_spider_bootstrap_{}; // epoch = never bootstrapped
|
|
569
|
+
|
|
510
570
|
// Spider helper methods
|
|
511
571
|
void add_spider_node(const DhtNode& node);
|
|
512
572
|
void add_spider_nodes(const std::vector<DhtNode>& nodes);
|
|
@@ -549,6 +609,10 @@ private:
|
|
|
549
609
|
int get_bucket_index(const NodeId& id);
|
|
550
610
|
|
|
551
611
|
NodeId generate_node_id();
|
|
612
|
+
// BEP 42 internals
|
|
613
|
+
static bool is_public_address(const std::string& ip);
|
|
614
|
+
void rebuild_routing_table_unlocked(); // re-bucket all nodes after node_id_ changed (routing_table_mutex_ held)
|
|
615
|
+
void maybe_update_external_ip(const std::string& reported_ip, const Peer& responder);
|
|
552
616
|
NodeId xor_distance(const NodeId& a, const NodeId& b);
|
|
553
617
|
bool is_closer(const NodeId& a, const NodeId& b, const NodeId& target);
|
|
554
618
|
|