config: minimum_ban_seconds, timeout_seconds

This commit is contained in:
Mike Dilger 2024-04-17 08:12:53 +12:00
parent a92049fb52
commit adc9e81068
6 changed files with 91 additions and 21 deletions

View File

@ -131,7 +131,7 @@ async fn main() -> Result<(), Error> {
};
// Possibly IP block
if ! GLOBALS.config.read().dont_ip_block {
if GLOBALS.config.read().enable_ip_blocking {
let ip_data = GLOBALS.store.get().unwrap().get_ip_data(hashed_peer.ip())?;
if ip_data.is_banned() {
log::debug!(target: "Client",
@ -394,9 +394,12 @@ async fn handle_http_request(
let old_num_websockets = GLOBALS.num_clients.fetch_sub(1, Ordering::SeqCst);
// Update ip data (including ban time)
// if GLOBALS.config.read().enable_ip_blocking {
let mut ban_seconds = 0;
let minimum_ban_seconds = GLOBALS.config.read().minimum_ban_seconds;
if let Ok(mut ip_data) = GLOBALS.store.get().unwrap().get_ip_data(peer.ip()) {
ban_seconds = ip_data.update_on_session_close(session_exit);
ban_seconds =
ip_data.update_on_session_close(session_exit, minimum_ban_seconds);
let _ = GLOBALS
.store
.get()
@ -460,7 +463,9 @@ impl WebSocketService {
let mut last_message_at = Instant::now();
let mut interval = tokio::time::interval(Duration::from_secs(5));
let timeout_seconds = GLOBALS.config.read().timeout_seconds;
let mut interval = tokio::time::interval(Duration::from_secs(1));
let _ = interval.tick().await; // consume the first tick
tokio::pin!(interval);
@ -469,8 +474,8 @@ impl WebSocketService {
instant = interval.tick() => {
// Drop them if they have no subscriptions
if self.subscriptions.is_empty() {
// And they are idle for 5 seconds with no subscriptions
if last_message_at + Duration::from_secs(5) < instant {
// And they are idle for timeout_seconds with no subscriptions
if last_message_at + Duration::from_secs(timeout_seconds) < instant {
self.websocket.send(Message::Close(None)).await?;
return Err(ChorusError::TimedOut.into());
}

View File

@ -30,7 +30,9 @@ pub struct FriendlyConfig {
pub server_log_level: String,
pub library_log_level: String,
pub client_log_level: String,
pub dont_ip_block: bool,
pub enable_ip_blocking: bool,
pub minimum_ban_seconds: u64,
pub timeout_seconds: u64,
}
impl Default for FriendlyConfig {
@ -59,7 +61,9 @@ impl Default for FriendlyConfig {
server_log_level: "Info".to_string(),
library_log_level: "Info".to_string(),
client_log_level: "Info".to_string(),
dont_ip_block: false,
enable_ip_blocking: true,
minimum_ban_seconds: 1,
timeout_seconds: 30,
}
}
}
@ -90,7 +94,9 @@ impl FriendlyConfig {
server_log_level,
library_log_level,
client_log_level,
dont_ip_block,
enable_ip_blocking,
minimum_ban_seconds,
timeout_seconds,
} = self;
let mut public_key: Option<Pubkey> = None;
@ -137,7 +143,9 @@ impl FriendlyConfig {
server_log_level,
library_log_level,
client_log_level,
dont_ip_block,
enable_ip_blocking,
minimum_ban_seconds,
timeout_seconds,
})
}
}
@ -168,7 +176,9 @@ pub struct Config {
pub server_log_level: log::LevelFilter,
pub library_log_level: log::LevelFilter,
pub client_log_level: log::LevelFilter,
pub dont_ip_block: bool,
pub enable_ip_blocking: bool,
pub minimum_ban_seconds: u64,
pub timeout_seconds: u64,
}
impl Default for Config {

View File

@ -123,13 +123,17 @@ pub struct IpData {
}
impl IpData {
pub fn update_on_session_close(&mut self, session_exit: SessionExit) -> u64 {
pub fn update_on_session_close(
&mut self,
session_exit: SessionExit,
minimum_ban_seconds: u64,
) -> u64 {
// Update reputation
self.reputation.update(session_exit);
// Compute ban_until
let mut until = Time::now();
let seconds = self.ban_seconds(session_exit);
let seconds = self.ban_seconds(session_exit, minimum_ban_seconds);
until.0 += seconds;
self.ban_until = Time(self.ban_until.0.max(until.0));
@ -141,14 +145,14 @@ impl IpData {
self.ban_until > Time::now()
}
fn ban_seconds(&self, session_exit: SessionExit) -> u64 {
fn ban_seconds(&self, session_exit: SessionExit, minimum_ban_seconds: u64) -> u64 {
let multiplier = self.reputation.ban_multiplier();
match session_exit {
SessionExit::Ok => 2,
SessionExit::ErrorExit => 2 + (2.0 * multiplier) as u64,
SessionExit::TooManyErrors => 2 + (5.0 * multiplier) as u64,
SessionExit::Timeout => 2 + (4.0 * multiplier) as u64,
SessionExit::Ok => minimum_ban_seconds,
SessionExit::ErrorExit => minimum_ban_seconds + (2.0 * multiplier) as u64,
SessionExit::TooManyErrors => minimum_ban_seconds + (5.0 * multiplier) as u64,
SessionExit::Timeout => minimum_ban_seconds + (1.0 * multiplier) as u64,
}
}
}

View File

@ -215,3 +215,33 @@ library_log_level = "Info"
# Default is Info
#
client_log_level = "Info"
# Whether to block incoming connections based on recent prior behavior
#
# Chorus normally blocks IP addresses for a short period preventing quick reconnections,
# and for a longer period if the previous connection ended in some error condition.
#
# By setting this variable to false, it will allow all connections, incluing poorly behaving
# clients that reconnect over and over in a tight loop.
#
# Default is true
#
enable_ip_blocking = true
# Number of seconds to ban an IP address after disconnection.
#
# Enforcing this minimum ban prevents clients from immediately reconnecting which can cause tight loops.
# Only relevant if enable_ip_blocking is true.
#
# Default is 1
#
minimum_ban_seconds = 1
# Number of seconds beyond which chorus times out a client that has no open subscriptions.
#
# Default is 30
#
timeout_seconds = 30

View File

@ -189,10 +189,28 @@ Possible values are: Trace, Debug, Info, Warn, Error
Default is Info
### dont_ip_block
### enable_ip_blocking
Whether to block incoming connections based on recent prior behavior
Chorus normally blocks IP addresses for a short period preventing quick reconnections, and for a longer period if the previous connection ended in some error condition.
By setting this variable to true, it will allow all connections.
By setting this variable to false, it will allow all connections, incluing poorly behaving clients that reconnect over and over in a tight loop.
Default is false.
Default is true
### minimum_ban_seconds
Number of seconds to ban an IP address after disconnection.
Enforcing this minimum ban prevents clients from immediately reconnecting which can cause tight loops.
Only relevant if enable_ip_blocking is true.
Default is 1
### timeout_seconds
Number of seconds beyond which chorus times out a client that has no open subscriptions.
Default is 30

View File

@ -22,4 +22,7 @@ serve_ephemeral = true
serve_relay_lists = true
server_log_level = "Info"
library_log_level = "Info"
client_log_level = "Warn"
client_log_level = "Warn"
enable_ip_blocking = true
minimum_ban_seconds = 1
timeout_seconds = 30