mirror of
				https://github.com/stalwartlabs/mail-server.git
				synced 2025-10-31 06:45:56 +08:00 
			
		
		
		
	Added context to SMTP rate limiter keys
This commit is contained in:
		
							parent
							
								
									26e00b44a8
								
							
						
					
					
						commit
						3c7caddd98
					
				
					 7 changed files with 27 additions and 18 deletions
				
			
		|  | @ -74,7 +74,7 @@ pub const KV_RATE_LIMIT_RCPT: u8 = 2; | ||||||
| pub const KV_RATE_LIMIT_SCAN: u8 = 3; | pub const KV_RATE_LIMIT_SCAN: u8 = 3; | ||||||
| pub const KV_RATE_LIMIT_LOITER: u8 = 4; | pub const KV_RATE_LIMIT_LOITER: u8 = 4; | ||||||
| pub const KV_RATE_LIMIT_AUTH: u8 = 5; | pub const KV_RATE_LIMIT_AUTH: u8 = 5; | ||||||
| pub const KV_RATE_LIMIT_HASH: u8 = 6; | pub const KV_RATE_LIMIT_SMTP: u8 = 6; | ||||||
| pub const KV_RATE_LIMIT_CONTACT: u8 = 7; | pub const KV_RATE_LIMIT_CONTACT: u8 = 7; | ||||||
| pub const KV_RATE_LIMIT_HTTP_AUTHENTICATED: u8 = 8; | pub const KV_RATE_LIMIT_HTTP_AUTHENTICATED: u8 = 8; | ||||||
| pub const KV_RATE_LIMIT_HTTP_ANONYMOUS: u8 = 9; | pub const KV_RATE_LIMIT_HTTP_ANONYMOUS: u8 = 9; | ||||||
|  |  | ||||||
|  | @ -152,7 +152,7 @@ impl ManageStore for Server { | ||||||
|                     Some("rate-scan") => vec![KV_RATE_LIMIT_SCAN].into(), |                     Some("rate-scan") => vec![KV_RATE_LIMIT_SCAN].into(), | ||||||
|                     Some("rate-loiter") => vec![KV_RATE_LIMIT_LOITER].into(), |                     Some("rate-loiter") => vec![KV_RATE_LIMIT_LOITER].into(), | ||||||
|                     Some("rate-auth") => vec![KV_RATE_LIMIT_AUTH].into(), |                     Some("rate-auth") => vec![KV_RATE_LIMIT_AUTH].into(), | ||||||
|                     Some("rate-hash") => vec![KV_RATE_LIMIT_HASH].into(), |                     Some("rate-smtp") => vec![KV_RATE_LIMIT_SMTP].into(), | ||||||
|                     Some("rate-contact") => vec![KV_RATE_LIMIT_CONTACT].into(), |                     Some("rate-contact") => vec![KV_RATE_LIMIT_CONTACT].into(), | ||||||
|                     Some("rate-http-authenticated") => { |                     Some("rate-http-authenticated") => { | ||||||
|                         vec![KV_RATE_LIMIT_HTTP_AUTHENTICATED].into() |                         vec![KV_RATE_LIMIT_HTTP_AUTHENTICATED].into() | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ use common::{ | ||||||
|     config::smtp::*, |     config::smtp::*, | ||||||
|     expr::{functions::ResolveVariable, *}, |     expr::{functions::ResolveVariable, *}, | ||||||
|     listener::SessionStream, |     listener::SessionStream, | ||||||
|     ThrottleKey, KV_RATE_LIMIT_HASH, |     ThrottleKey, KV_RATE_LIMIT_SMTP, | ||||||
| }; | }; | ||||||
| use queue::QueueQuota; | use queue::QueueQuota; | ||||||
| use trc::SmtpEvent; | use trc::SmtpEvent; | ||||||
|  | @ -17,11 +17,11 @@ use utils::config::Rate; | ||||||
| use super::Session; | use super::Session; | ||||||
| 
 | 
 | ||||||
| pub trait NewKey: Sized { | pub trait NewKey: Sized { | ||||||
|     fn new_key(&self, e: &impl ResolveVariable) -> ThrottleKey; |     fn new_key(&self, e: &impl ResolveVariable, context: &str) -> ThrottleKey; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl NewKey for QueueQuota { | impl NewKey for QueueQuota { | ||||||
|     fn new_key(&self, e: &impl ResolveVariable) -> ThrottleKey { |     fn new_key(&self, e: &impl ResolveVariable, _: &str) -> ThrottleKey { | ||||||
|         let mut hasher = blake3::Hasher::new(); |         let mut hasher = blake3::Hasher::new(); | ||||||
| 
 | 
 | ||||||
|         if (self.keys & THROTTLE_RCPT) != 0 { |         if (self.keys & THROTTLE_RCPT) != 0 { | ||||||
|  | @ -72,7 +72,7 @@ impl NewKey for QueueQuota { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl NewKey for QueueRateLimiter { | impl NewKey for QueueRateLimiter { | ||||||
|     fn new_key(&self, e: &impl ResolveVariable) -> ThrottleKey { |     fn new_key(&self, e: &impl ResolveVariable, context: &str) -> ThrottleKey { | ||||||
|         let mut hasher = blake3::Hasher::new(); |         let mut hasher = blake3::Hasher::new(); | ||||||
| 
 | 
 | ||||||
|         if (self.keys & THROTTLE_RCPT) != 0 { |         if (self.keys & THROTTLE_RCPT) != 0 { | ||||||
|  | @ -129,8 +129,9 @@ impl NewKey for QueueRateLimiter { | ||||||
|         if (self.keys & THROTTLE_LOCAL_IP) != 0 { |         if (self.keys & THROTTLE_LOCAL_IP) != 0 { | ||||||
|             hasher.update(e.resolve_variable(V_LOCAL_IP).to_string().as_bytes()); |             hasher.update(e.resolve_variable(V_LOCAL_IP).to_string().as_bytes()); | ||||||
|         } |         } | ||||||
|         hasher.update(&self.rate.period.as_secs().to_ne_bytes()[..]); |         hasher.update(&self.rate.period.as_secs().to_be_bytes()[..]); | ||||||
|         hasher.update(&self.rate.requests.to_ne_bytes()[..]); |         hasher.update(&self.rate.requests.to_be_bytes()[..]); | ||||||
|  |         hasher.update(context.as_bytes()); | ||||||
| 
 | 
 | ||||||
|         ThrottleKey { |         ThrottleKey { | ||||||
|             hash: hasher.finalize().into(), |             hash: hasher.finalize().into(), | ||||||
|  | @ -170,7 +171,7 @@ impl<T: SessionStream> Session<T> { | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 // Build throttle key
 |                 // Build throttle key
 | ||||||
|                 let key = t.new_key(self); |                 let key = t.new_key(self, "inbound"); | ||||||
| 
 | 
 | ||||||
|                 // Check rate
 |                 // Check rate
 | ||||||
|                 match self |                 match self | ||||||
|  | @ -178,7 +179,7 @@ impl<T: SessionStream> Session<T> { | ||||||
|                     .core |                     .core | ||||||
|                     .storage |                     .storage | ||||||
|                     .lookup |                     .lookup | ||||||
|                     .is_rate_allowed(KV_RATE_LIMIT_HASH, key.hash.as_slice(), &t.rate, false) |                     .is_rate_allowed(KV_RATE_LIMIT_SMTP, key.hash.as_slice(), &t.rate, false) | ||||||
|                     .await |                     .await | ||||||
|                 { |                 { | ||||||
|                     Ok(Some(_)) => { |                     Ok(Some(_)) => { | ||||||
|  | @ -220,7 +221,7 @@ impl<T: SessionStream> Session<T> { | ||||||
|             .storage |             .storage | ||||||
|             .lookup |             .lookup | ||||||
|             .is_rate_allowed( |             .is_rate_allowed( | ||||||
|                 KV_RATE_LIMIT_HASH, |                 KV_RATE_LIMIT_SMTP, | ||||||
|                 hasher.finalize().as_bytes(), |                 hasher.finalize().as_bytes(), | ||||||
|                 rate, |                 rate, | ||||||
|                 false, |                 false, | ||||||
|  |  | ||||||
|  | @ -129,7 +129,7 @@ impl HasQueueQuota for Server { | ||||||
|                 .await |                 .await | ||||||
|                 .unwrap_or(false) |                 .unwrap_or(false) | ||||||
|         { |         { | ||||||
|             let key = quota.new_key(envelope); |             let key = quota.new_key(envelope, ""); | ||||||
|             if let Some(max_size) = quota.size { |             if let Some(max_size) = quota.size { | ||||||
|                 let used_size = self |                 let used_size = self | ||||||
|                     .core |                     .core | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ | ||||||
| use std::future::Future; | use std::future::Future; | ||||||
| 
 | 
 | ||||||
| use common::{ | use common::{ | ||||||
|     config::smtp::QueueRateLimiter, expr::functions::ResolveVariable, Server, KV_RATE_LIMIT_HASH, |     config::smtp::QueueRateLimiter, expr::functions::ResolveVariable, Server, KV_RATE_LIMIT_SMTP, | ||||||
| }; | }; | ||||||
| use store::write::now; | use store::write::now; | ||||||
| 
 | 
 | ||||||
|  | @ -37,13 +37,13 @@ impl IsAllowed for Server { | ||||||
|                 .await |                 .await | ||||||
|                 .unwrap_or(false) |                 .unwrap_or(false) | ||||||
|         { |         { | ||||||
|             let key = throttle.new_key(envelope); |             let key = throttle.new_key(envelope, "outbound"); | ||||||
| 
 | 
 | ||||||
|             match self |             match self | ||||||
|                 .core |                 .core | ||||||
|                 .storage |                 .storage | ||||||
|                 .lookup |                 .lookup | ||||||
|                 .is_rate_allowed(KV_RATE_LIMIT_HASH, key.as_ref(), &throttle.rate, false) |                 .is_rate_allowed(KV_RATE_LIMIT_SMTP, key.as_ref(), &throttle.rate, false) | ||||||
|                 .await |                 .await | ||||||
|             { |             { | ||||||
|                 Ok(Some(next_refill)) => { |                 Ok(Some(next_refill)) => { | ||||||
|  |  | ||||||
|  | @ -41,9 +41,19 @@ impl HttpStoreGet for Arc<HttpStore> { | ||||||
|     fn contains(&self, key: &str) -> bool { |     fn contains(&self, key: &str) -> bool { | ||||||
|         #[cfg(feature = "test_mode")] |         #[cfg(feature = "test_mode")] | ||||||
|         { |         { | ||||||
|             if key.contains("open") || key.contains("tank") { |             if self.config.url.contains("phishtank.com") | ||||||
|  |                 || self.config.url.contains("openphish.com") | ||||||
|  |             { | ||||||
|                 return (self.config.url.contains("open") && key.contains("open")) |                 return (self.config.url.contains("open") && key.contains("open")) | ||||||
|                     || (self.config.url.contains("tank") && key.contains("tank")); |                     || (self.config.url.contains("tank") && key.contains("tank")); | ||||||
|  |             } else if self.config.url.contains("disposable.github.io") { | ||||||
|  |                 return key.ends_with("guerrillamail.com") || key.ends_with("disposable.org"); | ||||||
|  |             } else if self.config.url.contains("free_email_provider_domains.txt") { | ||||||
|  |                 return key.ends_with("gmail.com") | ||||||
|  |                     || key.ends_with("googlemail.com") | ||||||
|  |                     || key.ends_with("yahoomail.com") | ||||||
|  |                     || key.ends_with("outlook.com") | ||||||
|  |                     || key.ends_with("freemail.org"); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -119,8 +119,6 @@ allow-invalid-certs = true | ||||||
| "url-redirectors" = {"bit.ly", "redirect.io", "redirect.me", "redirect.org", "redirect.com", "redirect.net", "t.ly", "tinyurl.com"} | "url-redirectors" = {"bit.ly", "redirect.io", "redirect.me", "redirect.org", "redirect.com", "redirect.net", "t.ly", "tinyurl.com"} | ||||||
| "spam-traps" = {"spamtrap@*"} | "spam-traps" = {"spamtrap@*"} | ||||||
| "trusted-domains" = {"stalw.art"} | "trusted-domains" = {"stalw.art"} | ||||||
| "freemail-providers" = {"gmail.com", "googlemail.com", "yahoomail.com", "outlook.com", "*freemail.org"} |  | ||||||
| "disposable-providers" = {"guerrillamail.com", "*disposable.org"} |  | ||||||
| "surbl-hashbl" = {"bit.ly", "drive.google.com", "lnkiy.in"} | "surbl-hashbl" = {"bit.ly", "drive.google.com", "lnkiy.in"} | ||||||
| "#;
 | "#;
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue