librats 0.9.1 → 1.0.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/native-src/CMakeLists.txt +14 -0
- package/native-src/src/dht.cpp +3 -32
- package/native-src/src/dht.h +9 -1
- package/native-src/src/librats.cpp +42 -12
- package/native-src/src/librats.h +146 -2
- package/native-src/src/librats_discovery.cpp +22 -3
- package/native-src/src/librats_persistence.cpp +12 -2
- package/native-src/src/librats_portmap.cpp +419 -0
- package/native-src/src/natpmp.cpp +416 -0
- package/native-src/src/natpmp.h +140 -0
- package/native-src/src/network_monitor.cpp +367 -0
- package/native-src/src/network_monitor.h +104 -0
- package/native-src/src/network_utils.cpp +183 -2
- package/native-src/src/network_utils.h +27 -0
- package/native-src/src/port_mapping.h +78 -0
- package/native-src/src/socket.cpp +26 -6
- package/native-src/src/socket.h +6 -2
- package/native-src/src/upnp.cpp +635 -0
- package/native-src/src/upnp.h +163 -0
- package/native-src/src/wakeup_pipe.h +60 -0
- package/package.json +1 -1
|
@@ -41,11 +41,38 @@ bool is_valid_ipv6(const std::string& ip_str);
|
|
|
41
41
|
*/
|
|
42
42
|
bool is_hostname(const std::string& str);
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Check whether an IP address is publicly routable (not a private/reserved range).
|
|
46
|
+
*
|
|
47
|
+
* Returns false for RFC1918 (10/8, 172.16/12, 192.168/16), CGNAT (100.64/10),
|
|
48
|
+
* loopback, link-local (169.254/16, fe80::/10), unspecified, multicast/reserved,
|
|
49
|
+
* and IPv6 unique-local (fc00::/7). A non-IP / unparseable string yields false.
|
|
50
|
+
*
|
|
51
|
+
* Used both by the DHT (BEP 42 external-IP voting) and by automatic port
|
|
52
|
+
* forwarding to detect a double-NAT gateway whose reported "external" IP is itself
|
|
53
|
+
* private and therefore not a usable public endpoint.
|
|
54
|
+
*/
|
|
55
|
+
bool is_public_ip(const std::string& ip);
|
|
56
|
+
|
|
44
57
|
/**
|
|
45
58
|
* Get all local network interface addresses (IPv4 and IPv6)
|
|
46
59
|
* @return Vector of local IP addresses from all network interfaces
|
|
47
60
|
*/
|
|
48
61
|
std::vector<std::string> get_local_interface_addresses();
|
|
49
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Get the default IPv4 gateway address(es) of the host.
|
|
65
|
+
*
|
|
66
|
+
* Used for NAT port forwarding (NAT-PMP talks to the gateway directly, and UPnP
|
|
67
|
+
* can use it to restrict discovery to the local router). The OS routing table is
|
|
68
|
+
* consulted where available (Windows iphlpapi, Linux /proc/net/route). When the
|
|
69
|
+
* platform routing table cannot be read, a best-effort heuristic derived from the
|
|
70
|
+
* local IPv4 addresses (network .1) is appended so callers still have a candidate
|
|
71
|
+
* to try.
|
|
72
|
+
*
|
|
73
|
+
* @return Vector of gateway IPv4 addresses, most specific first. May be empty.
|
|
74
|
+
*/
|
|
75
|
+
std::vector<std::string> get_default_gateways();
|
|
76
|
+
|
|
50
77
|
} // namespace network_utils
|
|
51
78
|
} // namespace librats
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file port_mapping.h
|
|
5
|
+
* @brief Shared types for automatic NAT port forwarding (UPnP IGD + NAT-PMP)
|
|
6
|
+
*
|
|
7
|
+
* Both the UPnP (@ref UpnpClient) and NAT-PMP (@ref NatPmpClient) backends ask a
|
|
8
|
+
* home router to forward an external (WAN) port to a local (LAN) port so that
|
|
9
|
+
* inbound peer connections can reach a host behind NAT. They share the small set
|
|
10
|
+
* of vocabulary types defined here: the transport protocol of the mapping, which
|
|
11
|
+
* backend produced a result, and the result/callback shape RatsClient consumes.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
#include <cstdint>
|
|
15
|
+
#include <string>
|
|
16
|
+
#include <functional>
|
|
17
|
+
|
|
18
|
+
namespace librats {
|
|
19
|
+
|
|
20
|
+
/// Transport protocol of a port mapping.
|
|
21
|
+
enum class PortMapProtocol : uint8_t {
|
|
22
|
+
TCP,
|
|
23
|
+
UDP
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/// Which NAT traversal backend produced a result.
|
|
27
|
+
enum class PortMapTransport : uint8_t {
|
|
28
|
+
UPnP,
|
|
29
|
+
NatPMP
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/// Human readable protocol name ("TCP"/"UDP").
|
|
33
|
+
inline const char* to_string(PortMapProtocol p) {
|
|
34
|
+
return p == PortMapProtocol::TCP ? "TCP" : "UDP";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/// Human readable transport name ("UPnP"/"NAT-PMP").
|
|
38
|
+
inline const char* to_string(PortMapTransport t) {
|
|
39
|
+
return t == PortMapTransport::UPnP ? "UPnP" : "NAT-PMP";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Result of a port mapping attempt.
|
|
44
|
+
*
|
|
45
|
+
* On success @ref external_port holds the public port the router assigned (which
|
|
46
|
+
* may differ from the requested one) and, when the backend can report it,
|
|
47
|
+
* @ref external_ip holds the discovered public IP address.
|
|
48
|
+
*/
|
|
49
|
+
struct PortMapResult {
|
|
50
|
+
PortMapTransport transport; ///< Backend that produced this result
|
|
51
|
+
PortMapProtocol protocol; ///< Protocol of the mapping
|
|
52
|
+
bool success = false; ///< Whether the mapping is currently active
|
|
53
|
+
uint16_t internal_port = 0; ///< Local (LAN) port that was mapped
|
|
54
|
+
uint16_t external_port = 0; ///< Public (WAN) port assigned by the router
|
|
55
|
+
std::string external_ip; ///< Discovered public IP (may be empty)
|
|
56
|
+
std::string error; ///< Human readable error when !success
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Callback invoked whenever a mapping is established, refreshed, removed or fails.
|
|
61
|
+
* Always called from the backend's own worker thread.
|
|
62
|
+
*/
|
|
63
|
+
using PortMapCallback = std::function<void(const PortMapResult&)>;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Configuration for RatsClient's automatic port forwarding.
|
|
67
|
+
*
|
|
68
|
+
* Both backends run in parallel by default; whichever the router supports
|
|
69
|
+
* succeeds. Disabling one (or all) of them is a matter of flipping a flag.
|
|
70
|
+
*/
|
|
71
|
+
struct PortMappingConfig {
|
|
72
|
+
bool enabled = true; ///< Master switch for automatic port forwarding
|
|
73
|
+
bool enable_upnp = true; ///< Use the UPnP IGD backend
|
|
74
|
+
bool enable_natpmp = true; ///< Use the NAT-PMP backend
|
|
75
|
+
uint32_t lease_duration_seconds = 3600; ///< Requested lease duration
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
} // namespace librats
|
|
@@ -844,18 +844,29 @@ int send_udp_data(socket_t socket, const std::vector<uint8_t>& data,
|
|
|
844
844
|
}
|
|
845
845
|
|
|
846
846
|
std::vector<uint8_t> receive_udp_data(socket_t socket, size_t buffer_size, Peer& sender_peer,
|
|
847
|
-
int timeout_ms) {
|
|
848
|
-
// Handle timeout using select
|
|
849
|
-
|
|
847
|
+
int timeout_ms, socket_t interrupt_fd) {
|
|
848
|
+
// Handle timeout (and optional interrupt socket) using select. When no interrupt
|
|
849
|
+
// fd is supplied this path is identical to the plain timeout behavior.
|
|
850
|
+
const bool have_interrupt = is_valid_socket(interrupt_fd);
|
|
851
|
+
if (timeout_ms >= 0 || have_interrupt) {
|
|
850
852
|
fd_set read_fds;
|
|
851
853
|
FD_ZERO(&read_fds);
|
|
852
854
|
FD_SET(socket, &read_fds);
|
|
855
|
+
socket_t maxfd = socket;
|
|
856
|
+
if (have_interrupt) {
|
|
857
|
+
FD_SET(interrupt_fd, &read_fds);
|
|
858
|
+
if (interrupt_fd > maxfd) maxfd = interrupt_fd;
|
|
859
|
+
}
|
|
853
860
|
|
|
854
861
|
struct timeval timeout;
|
|
855
|
-
|
|
856
|
-
|
|
862
|
+
struct timeval* ptimeout = nullptr; // timeout_ms < 0 => block until readable
|
|
863
|
+
if (timeout_ms >= 0) {
|
|
864
|
+
timeout.tv_sec = timeout_ms / 1000;
|
|
865
|
+
timeout.tv_usec = (timeout_ms % 1000) * 1000;
|
|
866
|
+
ptimeout = &timeout;
|
|
867
|
+
}
|
|
857
868
|
|
|
858
|
-
int result = select(
|
|
869
|
+
int result = select(static_cast<int>(maxfd) + 1, &read_fds, nullptr, nullptr, ptimeout);
|
|
859
870
|
if (result == 0) {
|
|
860
871
|
LOG_SOCKET_DEBUG("UDP receive timeout (" << timeout_ms << "ms)");
|
|
861
872
|
return {};
|
|
@@ -863,6 +874,15 @@ std::vector<uint8_t> receive_udp_data(socket_t socket, size_t buffer_size, Peer&
|
|
|
863
874
|
LOG_SOCKET_ERROR("Select error while waiting for UDP data");
|
|
864
875
|
return {};
|
|
865
876
|
}
|
|
877
|
+
// Woken by the interrupt socket (e.g. stop requested): leave the data socket
|
|
878
|
+
// untouched and report no data so the caller can re-check its stop flag.
|
|
879
|
+
if (have_interrupt && FD_ISSET(interrupt_fd, &read_fds)) {
|
|
880
|
+
return {};
|
|
881
|
+
}
|
|
882
|
+
// Guard against calling recvfrom on a data socket that isn't actually ready.
|
|
883
|
+
if (!FD_ISSET(socket, &read_fds)) {
|
|
884
|
+
return {};
|
|
885
|
+
}
|
|
866
886
|
}
|
|
867
887
|
|
|
868
888
|
std::vector<uint8_t> buffer(buffer_size);
|
package/native-src/src/socket.h
CHANGED
|
@@ -170,10 +170,14 @@ int send_udp_data(socket_t socket, const std::vector<uint8_t>& data, const std::
|
|
|
170
170
|
* @param buffer_size Maximum number of bytes to receive
|
|
171
171
|
* @param sender_peer Output parameter for the sender's peer info
|
|
172
172
|
* @param timeout_ms Timeout in milliseconds (-1 for blocking, 0 for non-blocking, >0 for timeout)
|
|
173
|
-
* @
|
|
173
|
+
* @param interrupt_fd Optional second socket to watch; when it becomes readable the
|
|
174
|
+
* call returns immediately with an empty vector (used to wake a
|
|
175
|
+
* blocking receive on shutdown). INVALID_SOCKET_VALUE disables it.
|
|
176
|
+
* @return Received data, empty vector on timeout, error or interrupt
|
|
174
177
|
*/
|
|
175
178
|
std::vector<uint8_t> receive_udp_data(socket_t socket, size_t buffer_size, Peer& sender_peer,
|
|
176
|
-
int timeout_ms = -1
|
|
179
|
+
int timeout_ms = -1,
|
|
180
|
+
socket_t interrupt_fd = INVALID_SOCKET_VALUE);
|
|
177
181
|
|
|
178
182
|
// Common Socket Functions
|
|
179
183
|
/**
|