Skip to content

feat(listeners): add add_endpoint_with_filter for granular per-address L4 filtering - #941

Open
zsweiter wants to merge 1 commit into
cloudflare:mainfrom
zsweiter:feature/per-endpoint-connection-filter
Open

feat(listeners): add add_endpoint_with_filter for granular per-address L4 filtering#941
zsweiter wants to merge 1 commit into
cloudflare:mainfrom
zsweiter:feature/per-endpoint-connection-filter

Conversation

@zsweiter

Copy link
Copy Markdown

Description

This PR introduces add_endpoint_with_filter to the Listeners struct, allowing developers to configure specific ConnectionFilters on individual L4 transport stacks rather than enforcing a single global filter across all listeners.

Context / Rationale

Currently, the Listeners struct only exposes set_connection_filter, which eagerly iterates over all existing TransportStackBuilder entries and overwrites their local filter option.

However, TransportStackBuilder was already designed internally to hold an individual Option<Arc<dyn ConnectionFilter>>. The current public API layer forces all listening endpoints (e.g., port 80 and port 5050) to share the exact same L4 drop/accept logic, making it impossible to apply strict L4 firewalling to a management port while keeping the public service port uninhibited within the same Service.

By exposing add_endpoint_with_filter, we leverage Pingora's existing low-level architecture to support granular per-address filtering without breaking backward compatibility. The traditional add_endpoint simply defaults to passing None.

Example Usage

let mut listeners = Listeners::new();

// Port 8080: Public and completely open at L4
listeners.add_tcp("0.0.0.0:8080"); 

// Port 5050: Restricted administrative port with a dedicated L4 filter
listeners.add_endpoint_with_filter(
    ServerAddress::Tcp("0.0.0.0:5050".into(), None), 
    None, 
    Some(StrictAdminFilter)
);

Example Usage via endpoints()

This is particularly powerful when configuring a proxy service using the .endpoints() accessor to bind multiple network ports under a single server runtime:

use pingora::services::listening::Service;
use pingora::protocols::l4::listeners::ServerAddress;
use std::sync::Arc;

// 1. Create your proxy service
let mut my_proxy_service = http_proxy_service(&my_server.configuration, my_proxy_app);

// 2. Fetch the mutable Listeners collection from the service
let listeners = my_proxy_service.endpoints();

// 3. Port 8080: Public HTTP endpoint (completely open at L4)
listeners.add_tcp("0.0.0.0:8080"); 

// 4. Port 5050: Administrative endpoint (filtered immediately pre-TLS)
listeners.add_endpoint_with_filter(
    ServerAddress::Tcp("0.0.0.0:5050".into(), None), 
    None, 
    Some(Arc::new(StrictAdminL4Filter))
);

@drcaramelsyrup drcaramelsyrup added the enhancement New feature or request label Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants