v0.24.13
This commit is contained in:
1 parent
bd077754a9
commit
ed7e3377c1
40 files changed
+1764
-365
No files matched your search
@@ -267,6 +267,8 @@ fn finish_headers(
|
||||
request_id: &str,
|
||||
active: &[crate::vhost::Listener],
|
||||
) {
|
||||
// Global security headers form a baseline; explicitly set vhost values take precedence.
|
||||
snapshot.global_security.headers.apply(response.headers_mut(), tls);
|
||||
if let Some(frontend) = frontend {
|
||||
frontend.security.apply(response.headers_mut(), tls);
|
||||
}
|
||||
|
||||
+72
-15
@@ -106,13 +106,19 @@ async fn forward_request(
|
||||
} else {
|
||||
snapshot.frontend(&host, local.0, tls)
|
||||
};
|
||||
if snapshot.global_security.content_type_policy.blocks(request.headers()) {
|
||||
return error(
|
||||
StatusCode::FORBIDDEN,
|
||||
"RustProxy: request Content-Type denied by global policy\n",
|
||||
);
|
||||
}
|
||||
if frontend.is_some_and(|item| item.content_type_policy.blocks(request.headers())) {
|
||||
return error(
|
||||
StatusCode::FORBIDDEN,
|
||||
"RustProxy: request Content-Type denied by vhost policy\n",
|
||||
);
|
||||
}
|
||||
if snapshot.user_agent_blocking.blocks(request.headers())
|
||||
if snapshot.global_security.user_agent_blocking.blocks(request.headers())
|
||||
|| frontend.is_some_and(|frontend| frontend.user_agent_blocking.blocks(request.headers()))
|
||||
{
|
||||
return error(
|
||||
@@ -164,24 +170,16 @@ async fn forward_request(
|
||||
"RustProxy: RFC 9220 WebSocket transport is not enabled for this vhost\n",
|
||||
);
|
||||
}
|
||||
if let Some(response) = method_policy_denial(&snapshot.global_security.method_policy, request.method()) {
|
||||
return response;
|
||||
}
|
||||
if !cache_http_invalidation_method(request.method()) {
|
||||
if let Some(response) = frontend
|
||||
.and_then(|frontend| method_policy_denial(&frontend.method_policy, request.method()))
|
||||
{
|
||||
return response;
|
||||
}
|
||||
if let Some(response) = frontend.and_then(|frontend| {
|
||||
canonical_host_redirect(frontend, &host, tls, local.0.port(), request.uri())
|
||||
}) {
|
||||
return response;
|
||||
}
|
||||
if !tls {
|
||||
if let Some(response) =
|
||||
frontend.and_then(|frontend| force_ssl_redirect(frontend, &host, request.uri()))
|
||||
{
|
||||
return response;
|
||||
}
|
||||
}
|
||||
// Redirects are evaluated after global and per-vhost country/IP/rate checks below.
|
||||
}
|
||||
let mut context = match snapshot.forwarding.context_with_peer(
|
||||
request.headers(),
|
||||
@@ -226,13 +224,53 @@ async fn forward_request(
|
||||
let capture_country = state.logs.capture_country();
|
||||
let mut country_resolved = false;
|
||||
let mut country: Option<String> = None;
|
||||
if capture_country
|
||||
|| snapshot.global_security.country_access.needs_geoip()
|
||||
|| snapshot.global_security.rate_limit.needs_geoip()
|
||||
{
|
||||
country = cloudflare_country
|
||||
.clone()
|
||||
.or_else(|| state.geoip.load().country(context.client_ip));
|
||||
country_resolved = true;
|
||||
if capture_country {
|
||||
if let Some(exchange) = request.extensions().get::<Arc<Exchange>>() {
|
||||
*exchange.country.lock().unwrap_or_else(|e| e.into_inner()) = country.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Global rules are cumulative: an explicit IP allow cannot bypass a country deny/allowlist.
|
||||
if !snapshot.global_security.country_access.allows(country.as_deref())
|
||||
|| !snapshot.global_security.rate_limit.country_allowed(country.as_deref())
|
||||
|| snapshot.global_security.acl.as_ref().is_some_and(|acl| !acl.allows(context.client_ip))
|
||||
{
|
||||
return error(StatusCode::FORBIDDEN, "RustProxy: denied by global access policy\n");
|
||||
}
|
||||
if internal_dispatch.is_none() {
|
||||
if let Err(limited) = state.rate_limiter.check_with_user_agent(
|
||||
snapshot.envelope.revision,
|
||||
"\u{1f}rustproxy-global-security",
|
||||
context.client_ip,
|
||||
country.as_deref(),
|
||||
request.headers().get(http::header::USER_AGENT).and_then(|value| value.to_str().ok()),
|
||||
&snapshot.global_security.rate_limit,
|
||||
) {
|
||||
let mut response = error(
|
||||
StatusCode::TOO_MANY_REQUESTS,
|
||||
"RustProxy: global request rate limit exceeded\n",
|
||||
);
|
||||
if let Ok(value) = HeaderValue::from_str(&limited.retry_after_seconds.to_string()) {
|
||||
response.headers_mut().insert("retry-after", value);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
}
|
||||
if let Some(frontend) = frontend {
|
||||
if capture_country
|
||||
if !country_resolved && (capture_country
|
||||
|| frontend
|
||||
.profile_policies
|
||||
.iter()
|
||||
.any(|profile| profile.countries.needs_geoip())
|
||||
|| frontend.rate_limit.needs_geoip()
|
||||
|| frontend.rate_limit.needs_geoip())
|
||||
{
|
||||
country = cloudflare_country
|
||||
.clone()
|
||||
@@ -288,6 +326,23 @@ async fn forward_request(
|
||||
"RustProxy: denied by access policy\n",
|
||||
);
|
||||
}
|
||||
// Canonical / HTTPS redirects must not bypass global or per-vhost access policy.
|
||||
if !cache_http_invalidation_method(request.method()) {
|
||||
if let Some(mut response) = frontend.and_then(|frontend| {
|
||||
canonical_host_redirect(frontend, &host, tls, local.0.port(), request.uri())
|
||||
}) {
|
||||
snapshot.global_security.headers.apply(response.headers_mut(), tls);
|
||||
return response;
|
||||
}
|
||||
if !tls {
|
||||
if let Some(mut response) =
|
||||
frontend.and_then(|frontend| force_ssl_redirect(frontend, &host, request.uri()))
|
||||
{
|
||||
snapshot.global_security.headers.apply(response.headers_mut(), tls);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
if cache_http_invalidation_method(request.method()) {
|
||||
return cache_http_invalidation(
|
||||
&state,
|
||||
@@ -309,6 +364,7 @@ async fn forward_request(
|
||||
"RustProxy: redirect target could not be rendered\n",
|
||||
);
|
||||
};
|
||||
snapshot.global_security.headers.apply(response.headers_mut(), tls);
|
||||
response.extensions_mut().insert(RedirectResponse {
|
||||
http3_enabled: _redirect.http3_enabled,
|
||||
});
|
||||
@@ -316,6 +372,7 @@ async fn forward_request(
|
||||
}
|
||||
if let Some(item) = local_host {
|
||||
let mut response = item.page.serve(request.method(), StatusCode::NOT_FOUND);
|
||||
snapshot.global_security.headers.apply(response.headers_mut(), tls);
|
||||
response.extensions_mut().insert(LocalHostResponse {
|
||||
http3_enabled: item.http3_enabled,
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user