node: Add connection limits

The limits are roughly modeled after the Bitcoin network.
This commit is contained in:
Alexis Sellier 2024-03-04 10:59:15 +01:00 committed by cloudhead
parent 5bdc2ad1fb
commit 786ce40f95
No known key found for this signature in database
4 changed files with 52 additions and 1 deletions

View File

@ -43,6 +43,10 @@ $ rad config
"fillRate": 1.0,
"capacity": 64
}
},
"connection": {
"inbound": 128,
"outbound": 16
}
},
"policy": "block",

View File

@ -105,6 +105,10 @@ mod routes {
"fillRate": 1.0,
"capacity": 64
}
},
"connection": {
"inbound": 128,
"outbound": 16
}
},
"policy": "block",

View File

@ -1059,10 +1059,15 @@ where
/// Inbound connection attempt.
pub fn accepted(&mut self, addr: Address) -> bool {
// Always accept trusted connections.
// Always accept trusted connections, even if we already reached
// our inbound connection limit.
if addr.is_trusted() {
return true;
}
// Check for inbound connection limit.
if self.sessions.inbound().count() >= self.config.limits.connection.inbound {
return false;
}
let host: HostName = addr.into();
if self
@ -1912,6 +1917,10 @@ where
error!(target: "service", "Attempted connection to self");
return false;
}
if self.sessions.outbound().count() >= self.config.limits.connection.outbound {
error!(target: "service", "Outbound connection limit reached when attempting {nid} ({addr})");
return false;
}
let persistent = self.config.is_persistent(&nid);
let time = self.time();
@ -2345,6 +2354,16 @@ impl Sessions {
})
}
/// Iterator over connected inbound peers.
pub fn inbound(&self) -> impl Iterator<Item = (&NodeId, &Session)> + Clone {
self.connected().filter(|(_, s)| s.link.is_inbound())
}
/// Iterator over outbound peers.
pub fn outbound(&self) -> impl Iterator<Item = (&NodeId, &Session)> + Clone {
self.connected().filter(|(_, s)| s.link.is_outbound())
}
/// Iterator over mutable fully connected peers.
pub fn connected_mut(&mut self) -> impl Iterator<Item = (&NodeId, &mut Session)> {
self.0.iter_mut().filter(move |(_, s)| s.is_connected())

View File

@ -93,6 +93,9 @@ pub struct Limits {
/// Rate limitter settings.
#[serde(default)]
pub rate: RateLimits,
/// Connection limits.
#[serde(default)]
pub connection: ConnectionLimits,
}
impl Default for Limits {
@ -104,6 +107,27 @@ impl Default for Limits {
fetch_concurrency: 1,
max_open_files: 4096,
rate: RateLimits::default(),
connection: ConnectionLimits::default(),
}
}
}
/// Connection limits.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ConnectionLimits {
/// Max inbound connections.
pub inbound: usize,
/// Max outbound connections. Note that this is higher than the *target* number
/// in [`TARGET_OUTBOUND_PEERS`].
pub outbound: usize,
}
impl Default for ConnectionLimits {
fn default() -> Self {
Self {
inbound: 128,
outbound: 16,
}
}
}