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