2023-06-21 08:28:20 +00:00
use crate ::error ::LemmyError ;
2023-02-16 04:05:14 +00:00
use actix_web ::dev ::{ ConnectionInfo , Service , ServiceRequest , ServiceResponse , Transform } ;
2023-06-21 08:28:20 +00:00
use enum_map ::enum_map ;
2020-12-21 23:27:42 +00:00
use futures ::future ::{ ok , Ready } ;
2023-06-21 08:28:20 +00:00
use rate_limiter ::{ InstantSecs , RateLimitStorage , RateLimitType } ;
2022-10-27 09:24:07 +00:00
use serde ::{ Deserialize , Serialize } ;
2020-05-16 14:04:08 +00:00
use std ::{
future ::Future ,
2023-06-21 08:28:20 +00:00
net ::{ IpAddr , Ipv4Addr , SocketAddr } ,
2020-05-16 14:04:08 +00:00
pin ::Pin ,
2022-03-25 15:41:38 +00:00
rc ::Rc ,
2023-06-21 08:28:20 +00:00
str ::FromStr ,
2022-07-11 17:12:12 +00:00
sync ::{ Arc , Mutex } ,
2020-05-16 14:04:08 +00:00
task ::{ Context , Poll } ,
2023-06-21 08:28:20 +00:00
time ::Duration ,
2020-05-16 14:04:08 +00:00
} ;
2022-11-16 19:06:22 +00:00
use tokio ::sync ::{ mpsc , mpsc ::Sender , OnceCell } ;
2022-10-27 09:24:07 +00:00
use typed_builder ::TypedBuilder ;
2020-04-19 22:08:25 +00:00
2020-05-16 14:04:08 +00:00
pub mod rate_limiter ;
2022-10-27 09:24:07 +00:00
#[ derive(Debug, Deserialize, Serialize, Clone, TypedBuilder) ]
pub struct RateLimitConfig {
#[ builder(default = 180) ]
/// Maximum number of messages created in interval
pub message : i32 ,
#[ builder(default = 60) ]
/// Interval length for message limit, in seconds
pub message_per_second : i32 ,
#[ builder(default = 6) ]
/// Maximum number of posts created in interval
pub post : i32 ,
#[ builder(default = 300) ]
/// Interval length for post limit, in seconds
pub post_per_second : i32 ,
#[ builder(default = 3) ]
/// Maximum number of registrations in interval
pub register : i32 ,
#[ builder(default = 3600) ]
/// Interval length for registration limit, in seconds
pub register_per_second : i32 ,
#[ builder(default = 6) ]
/// Maximum number of image uploads in interval
pub image : i32 ,
#[ builder(default = 3600) ]
/// Interval length for image uploads, in seconds
pub image_per_second : i32 ,
#[ builder(default = 6) ]
/// Maximum number of comments created in interval
pub comment : i32 ,
#[ builder(default = 600) ]
/// Interval length for comment limit, in seconds
pub comment_per_second : i32 ,
#[ builder(default = 60) ]
/// Maximum number of searches created in interval
pub search : i32 ,
#[ builder(default = 600) ]
/// Interval length for search limit, in seconds
pub search_per_second : i32 ,
}
2020-04-19 22:08:25 +00:00
#[ derive(Debug, Clone) ]
2022-11-16 19:06:22 +00:00
struct RateLimit {
pub rate_limiter : RateLimitStorage ,
2021-09-22 15:57:09 +00:00
pub rate_limit_config : RateLimitConfig ,
2020-04-20 17:51:42 +00:00
}
2020-04-20 03:59:07 +00:00
#[ derive(Debug, Clone) ]
2022-11-16 19:06:22 +00:00
pub struct RateLimitedGuard {
rate_limit : Arc < Mutex < RateLimit > > ,
2020-04-20 17:51:42 +00:00
type_ : RateLimitType ,
}
2020-04-20 03:59:07 +00:00
2022-11-16 19:06:22 +00:00
/// Single instance of rate limit config and buckets, which is shared across all threads.
#[ derive(Clone) ]
pub struct RateLimitCell {
tx : Sender < RateLimitConfig > ,
rate_limit : Arc < Mutex < RateLimit > > ,
2020-04-20 17:51:42 +00:00
}
2020-04-20 03:59:07 +00:00
2022-11-16 19:06:22 +00:00
impl RateLimitCell {
/// Initialize cell if it wasnt initialized yet. Otherwise returns the existing cell.
pub async fn new ( rate_limit_config : RateLimitConfig ) -> & 'static Self {
static LOCAL_INSTANCE : OnceCell < RateLimitCell > = OnceCell ::const_new ( ) ;
LOCAL_INSTANCE
. get_or_init ( | | async {
let ( tx , mut rx ) = mpsc ::channel ::< RateLimitConfig > ( 4 ) ;
let rate_limit = Arc ::new ( Mutex ::new ( RateLimit {
rate_limiter : Default ::default ( ) ,
rate_limit_config ,
} ) ) ;
let rate_limit2 = rate_limit . clone ( ) ;
tokio ::spawn ( async move {
while let Some ( r ) = rx . recv ( ) . await {
rate_limit2
. lock ( )
. expect ( " Failed to lock rate limit mutex for updating " )
. rate_limit_config = r ;
}
} ) ;
RateLimitCell { tx , rate_limit }
} )
. await
}
/// Call this when the config was updated, to update all in-memory cells.
pub async fn send ( & self , config : RateLimitConfig ) -> Result < ( ) , LemmyError > {
self . tx . send ( config ) . await ? ;
Ok ( ( ) )
}
2023-06-21 08:28:20 +00:00
/// Remove buckets older than the given duration
pub fn remove_older_than ( & self , mut duration : Duration ) {
let mut guard = self
. rate_limit
. lock ( )
. expect ( " Failed to lock rate limit mutex for reading " ) ;
let rate_limit = & guard . rate_limit_config ;
// If any rate limit interval is greater than `duration`, then the largest interval is used instead. This preserves buckets that would not pass the rate limit check.
let max_interval_secs = enum_map! {
RateLimitType ::Message = > rate_limit . message_per_second ,
RateLimitType ::Post = > rate_limit . post_per_second ,
RateLimitType ::Register = > rate_limit . register_per_second ,
RateLimitType ::Image = > rate_limit . image_per_second ,
RateLimitType ::Comment = > rate_limit . comment_per_second ,
RateLimitType ::Search = > rate_limit . search_per_second ,
}
. into_values ( )
. max ( )
. and_then ( | max | u64 ::try_from ( max ) . ok ( ) )
. unwrap_or ( 0 ) ;
duration = std ::cmp ::max ( duration , Duration ::from_secs ( max_interval_secs ) ) ;
guard
. rate_limiter
. remove_older_than ( duration , InstantSecs ::now ( ) )
}
2022-11-16 19:06:22 +00:00
pub fn message ( & self ) -> RateLimitedGuard {
2020-04-20 03:59:07 +00:00
self . kind ( RateLimitType ::Message )
}
2022-11-16 19:06:22 +00:00
pub fn post ( & self ) -> RateLimitedGuard {
2020-04-20 03:59:07 +00:00
self . kind ( RateLimitType ::Post )
}
2022-11-16 19:06:22 +00:00
pub fn register ( & self ) -> RateLimitedGuard {
2020-04-20 03:59:07 +00:00
self . kind ( RateLimitType ::Register )
}
2022-11-16 19:06:22 +00:00
pub fn image ( & self ) -> RateLimitedGuard {
2020-08-05 16:00:00 +00:00
self . kind ( RateLimitType ::Image )
}
2022-11-16 19:06:22 +00:00
pub fn comment ( & self ) -> RateLimitedGuard {
2021-11-11 20:40:25 +00:00
self . kind ( RateLimitType ::Comment )
}
2022-11-16 19:06:22 +00:00
pub fn search ( & self ) -> RateLimitedGuard {
2022-03-29 15:46:03 +00:00
self . kind ( RateLimitType ::Search )
}
2022-11-16 19:06:22 +00:00
fn kind ( & self , type_ : RateLimitType ) -> RateLimitedGuard {
RateLimitedGuard {
rate_limit : self . rate_limit . clone ( ) ,
2020-04-20 17:51:42 +00:00
type_ ,
}
2020-04-20 03:59:07 +00:00
}
}
2022-11-16 19:06:22 +00:00
pub struct RateLimitedMiddleware < S > {
rate_limited : RateLimitedGuard ,
service : Rc < S > ,
}
impl RateLimitedGuard {
2022-03-25 15:41:38 +00:00
/// Returns true if the request passed the rate limit, false if it failed and should be rejected.
2022-03-27 00:29:05 +00:00
pub fn check ( self , ip_addr : IpAddr ) -> bool {
2020-07-01 12:54:29 +00:00
// Does not need to be blocking because the RwLock in settings never held across await points,
// and the operation here locks only long enough to clone
2022-11-16 19:06:22 +00:00
let mut guard = self
. rate_limit
. lock ( )
. expect ( " Failed to lock rate limit mutex for reading " ) ;
let rate_limit = & guard . rate_limit_config ;
2020-04-20 03:59:07 +00:00
2022-03-25 15:41:38 +00:00
let ( kind , interval ) = match self . type_ {
RateLimitType ::Message = > ( rate_limit . message , rate_limit . message_per_second ) ,
RateLimitType ::Post = > ( rate_limit . post , rate_limit . post_per_second ) ,
RateLimitType ::Register = > ( rate_limit . register , rate_limit . register_per_second ) ,
RateLimitType ::Image = > ( rate_limit . image , rate_limit . image_per_second ) ,
RateLimitType ::Comment = > ( rate_limit . comment , rate_limit . comment_per_second ) ,
2022-03-29 15:46:03 +00:00
RateLimitType ::Search = > ( rate_limit . search , rate_limit . search_per_second ) ,
2022-03-25 15:41:38 +00:00
} ;
2022-11-16 19:06:22 +00:00
let limiter = & mut guard . rate_limiter ;
2022-03-27 00:29:05 +00:00
2023-06-21 08:28:20 +00:00
limiter . check_rate_limit_full ( self . type_ , ip_addr , kind , interval , InstantSecs ::now ( ) )
2020-04-20 03:59:07 +00:00
}
}
2022-11-16 19:06:22 +00:00
impl < S > Transform < S , ServiceRequest > for RateLimitedGuard
2020-04-20 03:59:07 +00:00
where
2022-03-25 15:41:38 +00:00
S : Service < ServiceRequest , Response = ServiceResponse , Error = actix_web ::Error > + 'static ,
2020-04-20 03:59:07 +00:00
S ::Future : 'static ,
{
type Response = S ::Response ;
type Error = actix_web ::Error ;
type InitError = ( ) ;
type Transform = RateLimitedMiddleware < S > ;
type Future = Ready < Result < Self ::Transform , Self ::InitError > > ;
fn new_transform ( & self , service : S ) -> Self ::Future {
2020-04-20 17:51:42 +00:00
ok ( RateLimitedMiddleware {
rate_limited : self . clone ( ) ,
2022-03-25 15:41:38 +00:00
service : Rc ::new ( service ) ,
2020-04-20 17:51:42 +00:00
} )
2020-04-20 03:59:07 +00:00
}
}
2020-04-20 04:43:30 +00:00
type FutResult < T , E > = dyn Future < Output = Result < T , E > > ;
2021-07-06 13:26:46 +00:00
impl < S > Service < ServiceRequest > for RateLimitedMiddleware < S >
2020-04-20 03:59:07 +00:00
where
2022-03-25 15:41:38 +00:00
S : Service < ServiceRequest , Response = ServiceResponse , Error = actix_web ::Error > + 'static ,
2020-04-20 03:59:07 +00:00
S ::Future : 'static ,
{
type Response = S ::Response ;
type Error = actix_web ::Error ;
2020-04-20 04:43:30 +00:00
type Future = Pin < Box < FutResult < Self ::Response , Self ::Error > > > ;
2020-04-20 03:59:07 +00:00
2021-07-06 13:26:46 +00:00
fn poll_ready ( & self , cx : & mut Context < '_ > ) -> Poll < Result < ( ) , Self ::Error > > {
2020-04-20 17:51:42 +00:00
self . service . poll_ready ( cx )
2020-04-20 03:59:07 +00:00
}
2021-07-06 13:26:46 +00:00
fn call ( & self , req : ServiceRequest ) -> Self ::Future {
2020-04-20 18:02:25 +00:00
let ip_addr = get_ip ( & req . connection_info ( ) ) ;
2020-04-20 03:59:07 +00:00
2022-03-25 15:41:38 +00:00
let rate_limited = self . rate_limited . clone ( ) ;
let service = self . service . clone ( ) ;
Box ::pin ( async move {
2022-03-27 00:29:05 +00:00
if rate_limited . check ( ip_addr ) {
2022-03-25 15:41:38 +00:00
service . call ( req ) . await
} else {
let ( http_req , _ ) = req . into_parts ( ) ;
2022-11-03 18:13:40 +00:00
Ok ( ServiceResponse ::from_err (
LemmyError ::from_message ( " rate_limit_error " ) ,
2022-03-25 15:41:38 +00:00
http_req ,
) )
}
} )
2020-04-20 03:59:07 +00:00
}
2020-04-19 22:08:25 +00:00
}
2023-02-16 04:05:14 +00:00
fn get_ip ( conn_info : & ConnectionInfo ) -> IpAddr {
2023-06-21 08:28:20 +00:00
conn_info
. realip_remote_addr ( )
. and_then ( parse_ip )
. unwrap_or ( IpAddr ::V4 ( Ipv4Addr ::new ( 127 , 0 , 0 , 1 ) ) )
}
fn parse_ip ( addr : & str ) -> Option < IpAddr > {
if let Some ( s ) = addr . strip_suffix ( ']' ) {
IpAddr ::from_str ( s . get ( 1 .. ) ? ) . ok ( )
} else if let Ok ( ip ) = IpAddr ::from_str ( addr ) {
Some ( ip )
} else if let Ok ( socket ) = SocketAddr ::from_str ( addr ) {
Some ( socket . ip ( ) )
} else {
None
}
}
#[ cfg(test) ]
mod tests {
#[ test ]
fn test_parse_ip ( ) {
let ip_addrs = [
" 1.2.3.4 " ,
" 1.2.3.4:8000 " ,
" 2001:db8:: " ,
" [2001:db8::] " ,
" [2001:db8::]:8000 " ,
] ;
for addr in ip_addrs {
assert! ( super ::parse_ip ( addr ) . is_some ( ) , " failed to parse {addr} " ) ;
}
}
2023-02-16 04:05:14 +00:00
}