mirror of
https://github.com/telemt/telemt.git
synced 2026-05-13 23:31:44 +03:00
Merge pull request #770 from konstpic/feat/user-source-deny-list
feat(access): add per-user source IP deny list checks
This commit is contained in:
@@ -1893,6 +1893,12 @@ pub struct AccessConfig {
|
||||
#[serde(default)]
|
||||
pub cidr_rate_limits: HashMap<IpNetwork, RateLimitBps>,
|
||||
|
||||
/// Per-username client source IP/CIDR deny list. Checked after successful
|
||||
/// authentication; matching IPs get the same rejection path as invalid auth
|
||||
/// (handshake fails closed for that connection).
|
||||
#[serde(default)]
|
||||
pub user_source_deny: HashMap<String, Vec<IpNetwork>>,
|
||||
|
||||
#[serde(default)]
|
||||
pub user_max_unique_ips: HashMap<String, usize>,
|
||||
|
||||
@@ -1928,6 +1934,7 @@ impl Default for AccessConfig {
|
||||
user_data_quota: HashMap::new(),
|
||||
user_rate_limits: HashMap::new(),
|
||||
cidr_rate_limits: HashMap::new(),
|
||||
user_source_deny: HashMap::new(),
|
||||
user_max_unique_ips: HashMap::new(),
|
||||
user_max_unique_ips_global_each: default_user_max_unique_ips_global_each(),
|
||||
user_max_unique_ips_mode: UserMaxUniqueIpsMode::default(),
|
||||
@@ -1939,6 +1946,15 @@ impl Default for AccessConfig {
|
||||
}
|
||||
}
|
||||
|
||||
impl AccessConfig {
|
||||
/// Returns true if `ip` is contained in any CIDR listed for `username` under `user_source_deny`.
|
||||
pub fn is_user_source_ip_denied(&self, username: &str, ip: IpAddr) -> bool {
|
||||
self.user_source_deny
|
||||
.get(username)
|
||||
.is_some_and(|nets| nets.iter().any(|n| n.contains(ip)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct RateLimitBps {
|
||||
#[serde(default)]
|
||||
|
||||
@@ -1450,6 +1450,20 @@ where
|
||||
validated_secret.copy_from_slice(secret);
|
||||
}
|
||||
|
||||
if config
|
||||
.access
|
||||
.is_user_source_ip_denied(validated_user.as_str(), peer.ip())
|
||||
{
|
||||
auth_probe_record_failure_in(shared, peer.ip(), Instant::now());
|
||||
maybe_apply_server_hello_delay(config).await;
|
||||
warn!(
|
||||
peer = %peer,
|
||||
user = %validated_user,
|
||||
"TLS handshake rejected: client source IP on per-user deny list (access.user_source_deny)"
|
||||
);
|
||||
return HandshakeResult::BadClient { reader, writer };
|
||||
}
|
||||
|
||||
// Reject known replay digests before expensive cache/domain/ALPN policy work.
|
||||
let digest_half = &validation_digest[..tls::TLS_DIGEST_HALF_LEN];
|
||||
if replay_checker.check_tls_digest(digest_half) {
|
||||
@@ -1795,6 +1809,20 @@ where
|
||||
|
||||
let validation = matched_validation.expect("validation must exist when matched");
|
||||
|
||||
if config
|
||||
.access
|
||||
.is_user_source_ip_denied(matched_user.as_str(), peer.ip())
|
||||
{
|
||||
auth_probe_record_failure_in(shared, peer.ip(), Instant::now());
|
||||
maybe_apply_server_hello_delay(config).await;
|
||||
warn!(
|
||||
peer = %peer,
|
||||
user = %matched_user,
|
||||
"MTProto handshake rejected: client source IP on per-user deny list (access.user_source_deny)"
|
||||
);
|
||||
return HandshakeResult::BadClient { reader, writer };
|
||||
}
|
||||
|
||||
// Apply replay tracking only after successful authentication.
|
||||
//
|
||||
// This ordering prevents an attacker from producing invalid handshakes that
|
||||
@@ -1873,6 +1901,17 @@ where
|
||||
.auth_expensive_checks_total
|
||||
.fetch_add(validation_checks as u64, Ordering::Relaxed);
|
||||
|
||||
if config.access.is_user_source_ip_denied(user.as_str(), peer.ip()) {
|
||||
auth_probe_record_failure_in(shared, peer.ip(), Instant::now());
|
||||
maybe_apply_server_hello_delay(config).await;
|
||||
warn!(
|
||||
peer = %peer,
|
||||
user = %user,
|
||||
"MTProto handshake rejected: client source IP on per-user deny list (access.user_source_deny)"
|
||||
);
|
||||
return HandshakeResult::BadClient { reader, writer };
|
||||
}
|
||||
|
||||
// Apply replay tracking only after successful authentication.
|
||||
//
|
||||
// This ordering prevents an attacker from producing invalid handshakes that
|
||||
|
||||
Reference in New Issue
Block a user