mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-26 08:11:39 +00:00
protocols/autonat: optionally use only global IPs (#2618)
Optionally only perform dial-backs on peers that are observed at a global ip-address. This is relevant when multiple peers are in the same local network, in which case a peer could incorrectly assume themself to be public because a peer in the same local network was able to dial them. Thus servers should reject dial-back requests from clients with a non-global IP address, and at the same time clients should only pick connected peers as servers if they are global. Behind a config flag (enabled by default) to also allow use-cases where AutoNAT is needed within a private network.
This commit is contained in:
@ -6,6 +6,11 @@
|
|||||||
|
|
||||||
- Update to `libp2p-request-response` `v0.18.0`.
|
- Update to `libp2p-request-response` `v0.18.0`.
|
||||||
|
|
||||||
|
- Add `Config::only_global_ips` to skip peers that are observed at a private IP-address
|
||||||
|
(see [PR 2618]).
|
||||||
|
|
||||||
|
[PR 2618]: https://github.com/libp2p/rust-libp2p/pull/2618
|
||||||
|
|
||||||
# 0.3.0
|
# 0.3.0
|
||||||
|
|
||||||
- Update to `libp2p-swarm` `v0.35.0`.
|
- Update to `libp2p-swarm` `v0.35.0`.
|
||||||
|
@ -30,6 +30,7 @@ use futures_timer::Delay;
|
|||||||
use instant::Instant;
|
use instant::Instant;
|
||||||
use libp2p_core::{
|
use libp2p_core::{
|
||||||
connection::{ConnectionId, ListenerId},
|
connection::{ConnectionId, ListenerId},
|
||||||
|
multiaddr::Protocol,
|
||||||
ConnectedPoint, Endpoint, Multiaddr, PeerId,
|
ConnectedPoint, Endpoint, Multiaddr, PeerId,
|
||||||
};
|
};
|
||||||
use libp2p_request_response::{
|
use libp2p_request_response::{
|
||||||
@ -77,6 +78,11 @@ pub struct Config {
|
|||||||
pub throttle_clients_peer_max: usize,
|
pub throttle_clients_peer_max: usize,
|
||||||
/// Period for throttling clients requests.
|
/// Period for throttling clients requests.
|
||||||
pub throttle_clients_period: Duration,
|
pub throttle_clients_period: Duration,
|
||||||
|
/// As a server reject probes for clients that are observed at a non-global ip address.
|
||||||
|
/// Correspondingly as a client only pick peers as server that are not observed at a
|
||||||
|
/// private ip address. Note that this does not apply for servers that are added via
|
||||||
|
/// [`Behaviour::add_server`].
|
||||||
|
pub only_global_ips: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
@ -93,6 +99,7 @@ impl Default for Config {
|
|||||||
throttle_clients_global_max: 30,
|
throttle_clients_global_max: 30,
|
||||||
throttle_clients_peer_max: 3,
|
throttle_clients_peer_max: 3,
|
||||||
throttle_clients_period: Duration::from_secs(1),
|
throttle_clients_period: Duration::from_secs(1),
|
||||||
|
only_global_ips: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,7 +195,8 @@ pub struct Behaviour {
|
|||||||
ongoing_outbound: HashMap<RequestId, ProbeId>,
|
ongoing_outbound: HashMap<RequestId, ProbeId>,
|
||||||
|
|
||||||
// Connected peers with the observed address of each connection.
|
// Connected peers with the observed address of each connection.
|
||||||
// If the endpoint of a connection is relayed, the observed address is `None`.
|
// If the endpoint of a connection is relayed or not global (in case of Config::only_global_ips),
|
||||||
|
// the observed address is `None`.
|
||||||
connected: HashMap<PeerId, HashMap<ConnectionId, Option<Multiaddr>>>,
|
connected: HashMap<PeerId, HashMap<ConnectionId, Option<Multiaddr>>>,
|
||||||
|
|
||||||
// Used servers in recent outbound probes that are throttled through Config::throttle_server_period.
|
// Used servers in recent outbound probes that are throttled through Config::throttle_server_period.
|
||||||
@ -313,12 +321,14 @@ impl NetworkBehaviour for Behaviour {
|
|||||||
other_established,
|
other_established,
|
||||||
);
|
);
|
||||||
let connections = self.connected.entry(*peer).or_default();
|
let connections = self.connected.entry(*peer).or_default();
|
||||||
let addr = if endpoint.is_relayed() {
|
let addr = endpoint.get_remote_address();
|
||||||
None
|
let observed_addr =
|
||||||
|
if !endpoint.is_relayed() && (!self.config.only_global_ips || addr.is_global_ip()) {
|
||||||
|
Some(addr.clone())
|
||||||
} else {
|
} else {
|
||||||
Some(endpoint.get_remote_address().clone())
|
None
|
||||||
};
|
};
|
||||||
connections.insert(*conn, addr);
|
connections.insert(*conn, observed_addr);
|
||||||
|
|
||||||
match endpoint {
|
match endpoint {
|
||||||
ConnectedPoint::Dialer {
|
ConnectedPoint::Dialer {
|
||||||
@ -386,12 +396,14 @@ impl NetworkBehaviour for Behaviour {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let connections = self.connected.get_mut(peer).expect("Peer is connected.");
|
let connections = self.connected.get_mut(peer).expect("Peer is connected.");
|
||||||
let addr = if new.is_relayed() {
|
let addr = new.get_remote_address();
|
||||||
None
|
let observed_addr =
|
||||||
|
if !new.is_relayed() && (!self.config.only_global_ips || addr.is_global_ip()) {
|
||||||
|
Some(addr.clone())
|
||||||
} else {
|
} else {
|
||||||
Some(new.get_remote_address().clone())
|
None
|
||||||
};
|
};
|
||||||
connections.insert(*conn, addr);
|
connections.insert(*conn, observed_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inject_new_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) {
|
fn inject_new_listen_addr(&mut self, id: ListenerId, addr: &Multiaddr) {
|
||||||
@ -512,3 +524,119 @@ trait HandleInnerEvent {
|
|||||||
event: RequestResponseEvent<DialRequest, DialResponse>,
|
event: RequestResponseEvent<DialRequest, DialResponse>,
|
||||||
) -> (VecDeque<Event>, Option<Action>);
|
) -> (VecDeque<Event>, Option<Action>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait GlobalIp {
|
||||||
|
fn is_global_ip(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GlobalIp for Multiaddr {
|
||||||
|
fn is_global_ip(&self) -> bool {
|
||||||
|
match self.iter().next() {
|
||||||
|
Some(Protocol::Ip4(a)) => a.is_global_ip(),
|
||||||
|
Some(Protocol::Ip6(a)) => a.is_global_ip(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GlobalIp for std::net::Ipv4Addr {
|
||||||
|
// NOTE: The below logic is copied from `std::net::Ipv4Addr::is_global`, which is at the time of
|
||||||
|
// writing behind the unstable `ip` feature.
|
||||||
|
// See https://github.com/rust-lang/rust/issues/27709 for more info.
|
||||||
|
fn is_global_ip(&self) -> bool {
|
||||||
|
// Check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two
|
||||||
|
// globally routable addresses in the 192.0.0.0/24 range.
|
||||||
|
if u32::from_be_bytes(self.octets()) == 0xc0000009
|
||||||
|
|| u32::from_be_bytes(self.octets()) == 0xc000000a
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copied from the unstable method `std::net::Ipv4Addr::is_shared`.
|
||||||
|
fn is_shared(addr: &std::net::Ipv4Addr) -> bool {
|
||||||
|
addr.octets()[0] == 100 && (addr.octets()[1] & 0b1100_0000 == 0b0100_0000)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copied from the unstable method `std::net::Ipv4Addr::is_reserved`.
|
||||||
|
//
|
||||||
|
// **Warning**: As IANA assigns new addresses, this logic will be
|
||||||
|
// updated. This may result in non-reserved addresses being
|
||||||
|
// treated as reserved in code that relies on an outdated version
|
||||||
|
// of this method.
|
||||||
|
fn is_reserved(addr: &std::net::Ipv4Addr) -> bool {
|
||||||
|
addr.octets()[0] & 240 == 240 && !addr.is_broadcast()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copied from the unstable method `std::net::Ipv4Addr::is_benchmarking`.
|
||||||
|
fn is_benchmarking(addr: &std::net::Ipv4Addr) -> bool {
|
||||||
|
addr.octets()[0] == 198 && (addr.octets()[1] & 0xfe) == 18
|
||||||
|
}
|
||||||
|
|
||||||
|
!self.is_private()
|
||||||
|
&& !self.is_loopback()
|
||||||
|
&& !self.is_link_local()
|
||||||
|
&& !self.is_broadcast()
|
||||||
|
&& !self.is_documentation()
|
||||||
|
&& !is_shared(self)
|
||||||
|
// addresses reserved for future protocols (`192.0.0.0/24`)
|
||||||
|
&& !(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0)
|
||||||
|
&& !is_reserved(self)
|
||||||
|
&& !is_benchmarking(self)
|
||||||
|
// Make sure the address is not in 0.0.0.0/8
|
||||||
|
&& self.octets()[0] != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GlobalIp for std::net::Ipv6Addr {
|
||||||
|
// NOTE: The below logic is copied from `std::net::Ipv6Addr::is_global`, which is at the time of
|
||||||
|
// writing behind the unstable `ip` feature.
|
||||||
|
// See https://github.com/rust-lang/rust/issues/27709 for more info.
|
||||||
|
//
|
||||||
|
// Note that contrary to `Ipv4Addr::is_global_ip` this currently checks for global scope
|
||||||
|
// rather than global reachability.
|
||||||
|
fn is_global_ip(&self) -> bool {
|
||||||
|
// Copied from the unstable method `std::net::Ipv6Addr::is_unicast`.
|
||||||
|
fn is_unicast(addr: &std::net::Ipv6Addr) -> bool {
|
||||||
|
!addr.is_multicast()
|
||||||
|
}
|
||||||
|
// Copied from the unstable method `std::net::Ipv6Addr::is_unicast_link_local`.
|
||||||
|
fn is_unicast_link_local(addr: &std::net::Ipv6Addr) -> bool {
|
||||||
|
(addr.segments()[0] & 0xffc0) == 0xfe80
|
||||||
|
}
|
||||||
|
// Copied from the unstable method `std::net::Ipv6Addr::is_unique_local`.
|
||||||
|
fn is_unique_local(addr: &std::net::Ipv6Addr) -> bool {
|
||||||
|
(addr.segments()[0] & 0xfe00) == 0xfc00
|
||||||
|
}
|
||||||
|
// Copied from the unstable method `std::net::Ipv6Addr::is_documentation`.
|
||||||
|
fn is_documentation(addr: &std::net::Ipv6Addr) -> bool {
|
||||||
|
(addr.segments()[0] == 0x2001) && (addr.segments()[1] == 0xdb8)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copied from the unstable method `std::net::Ipv6Addr::is_unicast_global`.
|
||||||
|
fn is_unicast_global(addr: &std::net::Ipv6Addr) -> bool {
|
||||||
|
is_unicast(addr)
|
||||||
|
&& !addr.is_loopback()
|
||||||
|
&& !is_unicast_link_local(addr)
|
||||||
|
&& !is_unique_local(addr)
|
||||||
|
&& !addr.is_unspecified()
|
||||||
|
&& !is_documentation(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variation of unstable method [`std::net::Ipv6Addr::multicast_scope`] that instead of the
|
||||||
|
// `Ipv6MulticastScope` just returns if the scope is global or not.
|
||||||
|
// Equivalent to `Ipv6Addr::multicast_scope(..).map(|scope| matches!(scope, Ipv6MulticastScope::Global))`.
|
||||||
|
fn is_multicast_scope_global(addr: &std::net::Ipv6Addr) -> Option<bool> {
|
||||||
|
match addr.segments()[0] & 0x000f {
|
||||||
|
14 => Some(true), // Global multicast scope.
|
||||||
|
1..=5 | 8 => Some(false), // Local multicast scope.
|
||||||
|
_ => None, // Unknown multicast scope.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match is_multicast_scope_global(self) {
|
||||||
|
Some(true) => true,
|
||||||
|
None => is_unicast_global(self),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -262,7 +262,12 @@ impl<'a> AsClient<'a> {
|
|||||||
let mut servers: Vec<&PeerId> = self.servers.iter().collect();
|
let mut servers: Vec<&PeerId> = self.servers.iter().collect();
|
||||||
|
|
||||||
if self.config.use_connected {
|
if self.config.use_connected {
|
||||||
servers.extend(self.connected.iter().map(|(id, _)| id));
|
servers.extend(self.connected.iter().filter_map(|(id, addrs)| {
|
||||||
|
// Filter servers for which no qualified address is known.
|
||||||
|
// This is the case if the connection is relayed or the address is
|
||||||
|
// not global (in case of Config::only_global_ips).
|
||||||
|
addrs.values().any(|a| a.is_some()).then(|| id)
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
servers.retain(|s| !self.throttled_servers.iter().any(|(id, _)| s == &id));
|
servers.retain(|s| !self.throttled_servers.iter().any(|(id, _)| s == &id));
|
||||||
|
@ -295,8 +295,8 @@ impl<'a> AsServer<'a> {
|
|||||||
.values()
|
.values()
|
||||||
.find_map(|a| a.as_ref())
|
.find_map(|a| a.as_ref())
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
let status_text = "no dial-request over relayed connections".to_string();
|
let status_text = "refusing to dial peer with blocked observed address".to_string();
|
||||||
(status_text, ResponseError::DialError)
|
(status_text, ResponseError::DialRefused)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let mut addrs = Self::filter_valid_addrs(sender, request.addresses, observed_addr);
|
let mut addrs = Self::filter_valid_addrs(sender, request.addresses, observed_addr);
|
||||||
@ -304,7 +304,7 @@ impl<'a> AsServer<'a> {
|
|||||||
|
|
||||||
if addrs.is_empty() {
|
if addrs.is_empty() {
|
||||||
let status_text = "no dialable addresses".to_string();
|
let status_text = "no dialable addresses".to_string();
|
||||||
return Err((status_text, ResponseError::DialError));
|
return Err((status_text, ResponseError::DialRefused));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(addrs)
|
Ok(addrs)
|
||||||
@ -316,10 +316,6 @@ impl<'a> AsServer<'a> {
|
|||||||
demanded: Vec<Multiaddr>,
|
demanded: Vec<Multiaddr>,
|
||||||
observed_remote_at: &Multiaddr,
|
observed_remote_at: &Multiaddr,
|
||||||
) -> Vec<Multiaddr> {
|
) -> Vec<Multiaddr> {
|
||||||
// Skip if the observed address is a relay address.
|
|
||||||
if observed_remote_at.iter().any(|p| p == Protocol::P2pCircuit) {
|
|
||||||
return Vec::new();
|
|
||||||
}
|
|
||||||
let observed_ip = match observed_remote_at
|
let observed_ip = match observed_remote_at
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.find(|p| matches!(p, Protocol::Ip4(_) | Protocol::Ip6(_)))
|
.find(|p| matches!(p, Protocol::Ip4(_) | Protocol::Ip6(_)))
|
||||||
@ -417,23 +413,4 @@ mod test {
|
|||||||
.with(Protocol::P2p(peer_id.into()));
|
.with(Protocol::P2p(peer_id.into()));
|
||||||
assert_eq!(filtered, vec![expected_1, expected_2]);
|
assert_eq!(filtered, vec![expected_1, expected_2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn skip_relayed_addr() {
|
|
||||||
let peer_id = PeerId::random();
|
|
||||||
let observed_ip = random_ip();
|
|
||||||
// Observed address is relayed.
|
|
||||||
let observed_addr = Multiaddr::empty()
|
|
||||||
.with(observed_ip.clone())
|
|
||||||
.with(random_port())
|
|
||||||
.with(Protocol::P2p(PeerId::random().into()))
|
|
||||||
.with(Protocol::P2pCircuit)
|
|
||||||
.with(Protocol::P2p(peer_id.into()));
|
|
||||||
let demanded = Multiaddr::empty()
|
|
||||||
.with(random_ip())
|
|
||||||
.with(random_port())
|
|
||||||
.with(Protocol::P2p(peer_id.into()));
|
|
||||||
let filtered = AsServer::filter_valid_addrs(peer_id, vec![demanded], &observed_addr);
|
|
||||||
assert!(filtered.is_empty());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,7 @@ async fn spawn_server(kill: oneshot::Receiver<()>) -> (PeerId, Multiaddr) {
|
|||||||
let mut server = init_swarm(Config {
|
let mut server = init_swarm(Config {
|
||||||
boot_delay: Duration::from_secs(60),
|
boot_delay: Duration::from_secs(60),
|
||||||
throttle_clients_peer_max: usize::MAX,
|
throttle_clients_peer_max: usize::MAX,
|
||||||
|
only_global_ips: false,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
@ -100,6 +101,7 @@ async fn test_auto_probe() {
|
|||||||
retry_interval: TEST_RETRY_INTERVAL,
|
retry_interval: TEST_RETRY_INTERVAL,
|
||||||
refresh_interval: TEST_REFRESH_INTERVAL,
|
refresh_interval: TEST_REFRESH_INTERVAL,
|
||||||
confidence_max: MAX_CONFIDENCE,
|
confidence_max: MAX_CONFIDENCE,
|
||||||
|
only_global_ips: false,
|
||||||
throttle_server_period: Duration::ZERO,
|
throttle_server_period: Duration::ZERO,
|
||||||
boot_delay: Duration::ZERO,
|
boot_delay: Duration::ZERO,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -237,8 +239,6 @@ async fn test_auto_probe() {
|
|||||||
assert_eq!(client.behaviour().confidence(), 0);
|
assert_eq!(client.behaviour().confidence(), 0);
|
||||||
assert!(client.behaviour().nat_status().is_public());
|
assert!(client.behaviour().nat_status().is_public());
|
||||||
assert!(client.behaviour().public_address().is_some());
|
assert!(client.behaviour().public_address().is_some());
|
||||||
|
|
||||||
drop(_handle);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
run_test_with_timeout(test).await;
|
run_test_with_timeout(test).await;
|
||||||
@ -251,6 +251,7 @@ async fn test_confidence() {
|
|||||||
retry_interval: TEST_RETRY_INTERVAL,
|
retry_interval: TEST_RETRY_INTERVAL,
|
||||||
refresh_interval: TEST_REFRESH_INTERVAL,
|
refresh_interval: TEST_REFRESH_INTERVAL,
|
||||||
confidence_max: MAX_CONFIDENCE,
|
confidence_max: MAX_CONFIDENCE,
|
||||||
|
only_global_ips: false,
|
||||||
throttle_server_period: Duration::ZERO,
|
throttle_server_period: Duration::ZERO,
|
||||||
boot_delay: Duration::from_millis(100),
|
boot_delay: Duration::from_millis(100),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -332,8 +333,6 @@ async fn test_confidence() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(_handle);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
run_test_with_timeout(test).await;
|
run_test_with_timeout(test).await;
|
||||||
@ -346,6 +345,7 @@ async fn test_throttle_server_period() {
|
|||||||
retry_interval: TEST_RETRY_INTERVAL,
|
retry_interval: TEST_RETRY_INTERVAL,
|
||||||
refresh_interval: TEST_REFRESH_INTERVAL,
|
refresh_interval: TEST_REFRESH_INTERVAL,
|
||||||
confidence_max: MAX_CONFIDENCE,
|
confidence_max: MAX_CONFIDENCE,
|
||||||
|
only_global_ips: false,
|
||||||
// Throttle servers so they can not be re-used for dial request.
|
// Throttle servers so they can not be re-used for dial request.
|
||||||
throttle_server_period: Duration::from_secs(1000),
|
throttle_server_period: Duration::from_secs(1000),
|
||||||
boot_delay: Duration::from_millis(100),
|
boot_delay: Duration::from_millis(100),
|
||||||
@ -393,8 +393,6 @@ async fn test_throttle_server_period() {
|
|||||||
other => panic!("Unexpected behaviour event: {:?}.", other),
|
other => panic!("Unexpected behaviour event: {:?}.", other),
|
||||||
}
|
}
|
||||||
assert_eq!(client.behaviour().confidence(), 0);
|
assert_eq!(client.behaviour().confidence(), 0);
|
||||||
|
|
||||||
drop(_handle)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
run_test_with_timeout(test).await;
|
run_test_with_timeout(test).await;
|
||||||
@ -407,6 +405,7 @@ async fn test_use_connected_as_server() {
|
|||||||
retry_interval: TEST_RETRY_INTERVAL,
|
retry_interval: TEST_RETRY_INTERVAL,
|
||||||
refresh_interval: TEST_REFRESH_INTERVAL,
|
refresh_interval: TEST_REFRESH_INTERVAL,
|
||||||
confidence_max: MAX_CONFIDENCE,
|
confidence_max: MAX_CONFIDENCE,
|
||||||
|
only_global_ips: false,
|
||||||
throttle_server_period: Duration::ZERO,
|
throttle_server_period: Duration::ZERO,
|
||||||
boot_delay: Duration::from_millis(100),
|
boot_delay: Duration::from_millis(100),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -445,8 +444,6 @@ async fn test_use_connected_as_server() {
|
|||||||
}
|
}
|
||||||
other => panic!("Unexpected behaviour event: {:?}.", other),
|
other => panic!("Unexpected behaviour event: {:?}.", other),
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(_handle);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
run_test_with_timeout(test).await;
|
run_test_with_timeout(test).await;
|
||||||
@ -461,6 +458,7 @@ async fn test_outbound_failure() {
|
|||||||
retry_interval: TEST_RETRY_INTERVAL,
|
retry_interval: TEST_RETRY_INTERVAL,
|
||||||
refresh_interval: TEST_REFRESH_INTERVAL,
|
refresh_interval: TEST_REFRESH_INTERVAL,
|
||||||
confidence_max: MAX_CONFIDENCE,
|
confidence_max: MAX_CONFIDENCE,
|
||||||
|
only_global_ips: false,
|
||||||
throttle_server_period: Duration::ZERO,
|
throttle_server_period: Duration::ZERO,
|
||||||
boot_delay: Duration::from_millis(100),
|
boot_delay: Duration::from_millis(100),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -524,3 +522,55 @@ async fn test_outbound_failure() {
|
|||||||
|
|
||||||
run_test_with_timeout(test).await;
|
run_test_with_timeout(test).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_global_ips_config() {
|
||||||
|
let test = async {
|
||||||
|
let mut client = init_swarm(Config {
|
||||||
|
retry_interval: TEST_RETRY_INTERVAL,
|
||||||
|
refresh_interval: TEST_REFRESH_INTERVAL,
|
||||||
|
confidence_max: MAX_CONFIDENCE,
|
||||||
|
// Enforce that only peers outside of the local network are used as servers.
|
||||||
|
only_global_ips: true,
|
||||||
|
boot_delay: Duration::from_millis(100),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
client
|
||||||
|
.listen_on("/ip4/0.0.0.0/tcp/0".parse().unwrap())
|
||||||
|
.unwrap();
|
||||||
|
loop {
|
||||||
|
match client.select_next_some().await {
|
||||||
|
SwarmEvent::NewListenAddr { .. } => break,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let (_handle, rx) = oneshot::channel();
|
||||||
|
let (server_id, addr) = spawn_server(rx).await;
|
||||||
|
|
||||||
|
// Dial server instead of adding it via `Behaviour::add_server` because the
|
||||||
|
// `only_global_ips` restriction does not apply for manually added servers.
|
||||||
|
client.dial(addr).unwrap();
|
||||||
|
loop {
|
||||||
|
if let SwarmEvent::ConnectionEstablished { peer_id, .. } =
|
||||||
|
client.select_next_some().await
|
||||||
|
{
|
||||||
|
assert_eq!(peer_id, server_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expect that the server is not qualified for dial-back because it is observed
|
||||||
|
// at a local IP.
|
||||||
|
match next_event(&mut client).await {
|
||||||
|
Event::OutboundProbe(OutboundProbeEvent::Error { error, .. }) => {
|
||||||
|
assert!(matches!(error, OutboundProbeError::NoServer))
|
||||||
|
}
|
||||||
|
other => panic!("Unexpected behaviour event: {:?}.", other),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
run_test_with_timeout(test).await;
|
||||||
|
}
|
||||||
|
@ -43,7 +43,10 @@ async fn init_swarm(config: Config) -> Swarm<Behaviour> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn init_server(config: Option<Config>) -> (Swarm<Behaviour>, PeerId, Multiaddr) {
|
async fn init_server(config: Option<Config>) -> (Swarm<Behaviour>, PeerId, Multiaddr) {
|
||||||
let mut config = config.unwrap_or_default();
|
let mut config = config.unwrap_or_else(|| Config {
|
||||||
|
only_global_ips: false,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
// Don't do any outbound probes.
|
// Don't do any outbound probes.
|
||||||
config.boot_delay = Duration::from_secs(60);
|
config.boot_delay = Duration::from_secs(60);
|
||||||
|
|
||||||
@ -74,6 +77,7 @@ async fn spawn_client(
|
|||||||
boot_delay: Duration::from_secs(1),
|
boot_delay: Duration::from_secs(1),
|
||||||
retry_interval: Duration::from_secs(1),
|
retry_interval: Duration::from_secs(1),
|
||||||
throttle_server_period: Duration::ZERO,
|
throttle_server_period: Duration::ZERO,
|
||||||
|
only_global_ips: false,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
@ -224,8 +228,6 @@ async fn test_dial_back() {
|
|||||||
}
|
}
|
||||||
other => panic!("Unexpected behaviour event: {:?}.", other),
|
other => panic!("Unexpected behaviour event: {:?}.", other),
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(_handle);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
run_test_with_timeout(test).await;
|
run_test_with_timeout(test).await;
|
||||||
@ -270,8 +272,6 @@ async fn test_dial_error() {
|
|||||||
}
|
}
|
||||||
other => panic!("Unexpected behaviour event: {:?}.", other),
|
other => panic!("Unexpected behaviour event: {:?}.", other),
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(_handle);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
run_test_with_timeout(test).await;
|
run_test_with_timeout(test).await;
|
||||||
@ -283,6 +283,7 @@ async fn test_throttle_global_max() {
|
|||||||
let (mut server, server_id, server_addr) = init_server(Some(Config {
|
let (mut server, server_id, server_addr) = init_server(Some(Config {
|
||||||
throttle_clients_global_max: 1,
|
throttle_clients_global_max: 1,
|
||||||
throttle_clients_period: Duration::from_secs(60),
|
throttle_clients_period: Duration::from_secs(60),
|
||||||
|
only_global_ips: false,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}))
|
}))
|
||||||
.await;
|
.await;
|
||||||
@ -318,8 +319,6 @@ async fn test_throttle_global_max() {
|
|||||||
other => panic!("Unexpected behaviour event: {:?}.", other),
|
other => panic!("Unexpected behaviour event: {:?}.", other),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(_handles);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
run_test_with_timeout(test).await;
|
run_test_with_timeout(test).await;
|
||||||
@ -331,6 +330,7 @@ async fn test_throttle_peer_max() {
|
|||||||
let (mut server, server_id, server_addr) = init_server(Some(Config {
|
let (mut server, server_id, server_addr) = init_server(Some(Config {
|
||||||
throttle_clients_peer_max: 1,
|
throttle_clients_peer_max: 1,
|
||||||
throttle_clients_period: Duration::from_secs(60),
|
throttle_clients_period: Duration::from_secs(60),
|
||||||
|
only_global_ips: false,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}))
|
}))
|
||||||
.await;
|
.await;
|
||||||
@ -369,8 +369,6 @@ async fn test_throttle_peer_max() {
|
|||||||
}
|
}
|
||||||
other => panic!("Unexpected behaviour event: {:?}.", other),
|
other => panic!("Unexpected behaviour event: {:?}.", other),
|
||||||
};
|
};
|
||||||
|
|
||||||
drop(_handle);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
run_test_with_timeout(test).await;
|
run_test_with_timeout(test).await;
|
||||||
@ -382,6 +380,7 @@ async fn test_dial_multiple_addr() {
|
|||||||
let (mut server, server_id, server_addr) = init_server(Some(Config {
|
let (mut server, server_id, server_addr) = init_server(Some(Config {
|
||||||
throttle_clients_peer_max: 1,
|
throttle_clients_peer_max: 1,
|
||||||
throttle_clients_period: Duration::from_secs(60),
|
throttle_clients_period: Duration::from_secs(60),
|
||||||
|
only_global_ips: false,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}))
|
}))
|
||||||
.await;
|
.await;
|
||||||
@ -428,3 +427,29 @@ async fn test_dial_multiple_addr() {
|
|||||||
|
|
||||||
run_test_with_timeout(test).await;
|
run_test_with_timeout(test).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_global_ips_config() {
|
||||||
|
let test = async {
|
||||||
|
let (mut server, server_id, server_addr) = init_server(Some(Config {
|
||||||
|
// Enforce that only clients outside of the local network are qualified for dial-backs.
|
||||||
|
only_global_ips: true,
|
||||||
|
..Default::default()
|
||||||
|
}))
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let (_handle, rx) = oneshot::channel();
|
||||||
|
spawn_client(true, false, server_id, server_addr.clone(), rx).await;
|
||||||
|
|
||||||
|
// Expect the probe to be refused as both peers run on the same machine and thus in the same local network.
|
||||||
|
match next_event(&mut server).await {
|
||||||
|
Event::InboundProbe(InboundProbeEvent::Error { error, .. }) => assert!(matches!(
|
||||||
|
error,
|
||||||
|
InboundProbeError::Response(ResponseError::DialRefused)
|
||||||
|
)),
|
||||||
|
other => panic!("Unexpected behaviour event: {:?}.", other),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
run_test_with_timeout(test).await;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user