ip whitelist

This commit is contained in:
2026-08-11 02:02:39 +08:00
parent 6e0b0c92d1
commit b62c74b883
10 changed files with 270 additions and 13 deletions
+91 -7
View File
@@ -1,5 +1,5 @@
use crate::{
auth::{client_ip::ClientIpPolicy, AuthorizationService},
auth::{client_ip::ClientIpPolicy, ip_whitelist, AuthorizationService},
config::Config,
logs::{follower::LiveMessage, index::HistoryStore},
};
@@ -142,17 +142,101 @@ async fn authorize(
peer: SocketAddr,
headers: &HeaderMap,
) -> Result<IpAddr, Response> {
validate_origin(&state.config.public_origin, headers)
.map_err(|_| error(StatusCode::FORBIDDEN, "origin_denied"))?;
validate_origin(&state.config.public_origin, headers).map_err(|_| {
tracing::debug!(
event = "authorization_decision",
result = "denied",
reason = "origin_denied",
peer_ip = %peer.ip()
);
error(StatusCode::FORBIDDEN, "origin_denied")
})?;
let ip = state
.ip_policy
.extract(peer.ip(), headers)
.map_err(|_| error(StatusCode::BAD_REQUEST, "invalid_client_ip"))?;
.map_err(|extract_error| {
tracing::debug!(
event = "authorization_decision",
result = "denied",
reason = "invalid_client_ip",
peer_ip = %peer.ip(),
error = %extract_error
);
error(StatusCode::BAD_REQUEST, "invalid_client_ip")
})?;
if state.auth.is_allowed(ip).await {
Ok(ip)
} else {
Err(error(StatusCode::FORBIDDEN, "access_denied"))
let allowed_player_ips = state.auth.allowed_ips().await;
tracing::debug!(
event = "authorization_decision",
result = "allowed",
source = "player_join",
client_ip = %ip,
peer_ip = %peer.ip(),
?allowed_player_ips
);
return Ok(ip);
}
let allowed_player_ips = state.auth.allowed_ips().await;
if let Some(path) = state.config.ip_whitelist_file.clone() {
let log_path = path.clone();
let result = tokio::task::spawn_blocking(move || ip_whitelist::check(&path, ip)).await;
match result {
Ok(Ok(check)) if check.matched => {
tracing::debug!(
event = "authorization_decision",
result = "allowed",
source = "ip_whitelist_file",
client_ip = %ip,
peer_ip = %peer.ip(),
path = %log_path.display(),
allowed_override_networks = ?check.entries,
?allowed_player_ips
);
return Ok(ip);
}
Ok(Ok(check)) => tracing::debug!(
event = "ip_whitelist_checked",
result = "no_match",
client_ip = %ip,
path = %log_path.display(),
allowed_override_networks = ?check.entries,
?allowed_player_ips
),
Ok(Err(error)) => tracing::warn!(
event = "ip_whitelist_read_failed",
client_ip = %ip,
path = %log_path.display(),
?allowed_player_ips,
%error
),
Err(error) => tracing::warn!(
event = "ip_whitelist_check_failed",
client_ip = %ip,
path = %log_path.display(),
?allowed_player_ips,
%error
),
}
} else {
tracing::debug!(
event = "ip_whitelist_disabled",
client_ip = %ip,
?allowed_player_ips
);
}
tracing::debug!(
event = "authorization_decision",
result = "denied",
reason = "no_authorization_match",
client_ip = %ip,
peer_ip = %peer.ip(),
?allowed_player_ips
);
Err((
StatusCode::FORBIDDEN,
Json(serde_json::json!({"error":"access_denied", "client_ip":ip})),
)
.into_response())
}
fn validate_origin(expected: &str, headers: &HeaderMap) -> Result<(), ()> {
if let Some(origin) = headers.get(header::ORIGIN) {