-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Description
What is the problem your feature solves, or the need it fulfills?
Currently, Pingora has no mechanism to filter or drop connections at the TCP level before the TLS handshake occurs. All connection filtering must happen after TLS negotiation completes (in early_request_filter
or later), which means:
- Unwanted connections consume resources completing expensive TLS handshakes
- Malicious IPs can overwhelm the server with TLS negotiation attempts
- Geoblocking and IP filtering happen too late in the connection lifecycle
This affects anyone who needs to:
- Implement IP-based access control
- Block connections from specific geographic regions
- Protect against DDoS attacks at the connection level
- Enforce security policies before TLS negotiation
Describe the solution you'd like
Add a ConnectionFilter
trait that allows users to implement custom connection filtering logic, similar to how the ProxyHttp
trait works:
// In pingora-core
#[async_trait]
pub trait ConnectionFilter: Send + Sync {
/// Called when a new TCP connection is accepted, before TLS handshake
/// Return true to accept the connection, false to drop it
async fn should_accept(&self, addr: &SocketAddr) -> bool {
true // Default: accept all
}
}
// Default implementation that accepts everything
pub struct AcceptAllFilter;
impl ConnectionFilter for AcceptAllFilter {
// Uses default implementation
}
The trait would be called in the connection accept loop:
let (socket, addr) = listener.accept().await?;
// Apply connection filter
if !self.connection_filter.should_accept(&addr).await {
// Log, update metrics, etc.
drop(socket);
continue;
}
// Proceed with TLS handshake...
This approach:
- Keeps Pingora unopinionated about specific filtering implementations
- Allows async operations for complex filtering logic (database lookups, etc.)
- Follows existing Pingora patterns
- Minimal performance impact (one trait call per connection)
Describe alternatives you've considered
-
Built-in IP filtering (as suggested in Implement TCP Connection IP allowlist/blocklist in Pingora #297): This would add IP allowlist/blocklist directly to Pingora. However, this is too opinionated and doesn't cover all use cases (e.g., geoblocking, rate limiting).
-
Infrastructure-level filtering (iptables, cloud WAF): Works but requires external configuration and doesn't integrate with application logic or metrics.
-
Existing
early_request_filter
: Already available but runs after TLS handshake, wasting resources on unwanted connections. -
Synchronous trait: Simpler but would block the accept loop for database lookups or other I/O operations.
The proposed async trait solution provides maximum flexibility while maintaining Pingora's philosophy of being an unopinionated framework.
Additional context
- Related to issue Implement TCP Connection IP allowlist/blocklist in Pingora #297 which requests IP filtering functionality
- Similar pattern already exists in Pingora with the
ProxyHttp
trait for HTTP request handling - This would enable fixing issues like geoblocking happening after TLS handshake (which wastes resources)
- Performance impact should be minimal as it's a single trait call before expensive TLS operations
I'm willing to implement this feature if the approach is approved.