Skip to content

TCP Proxy

The PowerDNS Platform Filter TCP Proxy (pdns-pf-proxy-tcp) routes HTTP and HTTPS connections through Platform Filter's per-subscriber policy. It reads just enough of the initial client bytes to find the target host, asks the simulator for an allow or block decision, and then tunnels the rest of the connection at the TCP level without looking further.

Because the proxy works at the TCP level and never terminates TLS, the upstream server receives the exact bytes the browser sent. It is a single static binary that can replace the OpenResty HTTP and HTTPS proxy in many deployments.

What it does

  • Inspects the first HTTP request or TLS ClientHello to determine the target host.
  • Calls the simulator once per connection for an allow or block decision.
  • Resolves the host and proxies raw TCP bytes in both directions.
  • Tracks each connection and logs a summary, plus periodic activity stats.
  • Accepts a runtime command to pause and unpause a subscriber's traffic.

Filtering is per connection, not per request. The proxy does not parse HTTP request paths.

Protocols

The proxy inspects connections differently depending on the listener protocol.

  • HTTPS — extracts the SNI from the TLS ClientHello. TLS is not terminated, so a blocked connection is simply closed with no block page.
  • HTTP — parses the first request headers to read the Host header. A blocked request gets an HTML error page with a proper status code.
  • SOCKS5 — accepts a CONNECT to port 80 or 443 and then routes on the later HTTP Host or TLS SNI rather than the SOCKS destination. Useful for routing a client through the filter without per-host network configuration. Restrict who can reach it — see the SOCKS5 listener warning.

HTTP and HTTPS listeners can optionally require an HAProxy PROXY protocol v1 header on a separate bind address, which preserves the client source IP across an upstream load balancer.

Where it fits in Platform Filter

Traffic only reaches the proxy because the DNS layer sends it there. When the filter engine in the DNS server decides a client should not connect directly to a host, it answers the DNS query with the proxy's IP instead of the real one, so the client opens its connection to the proxy. The proxy then inspects the host, consults the simulator (over NATS or over the simulator's HTTP API) for the policy decision, and forwards allowed connections to the real upstream host:

client  →  pdns-pf-proxy-tcp  →  upstream host
                  └─ allow / block ─  simulator

Redirecting through the proxy buys two things DNS filtering alone cannot: a subscriber can be blocked or unblocked immediately without waiting for a DNS TTL to expire (see Pause control), and a blocked HTTP request can be answered with a proper block page.

See Architecture for how the decision backends and the connection lifecycle fit together.

Who this documentation is for

This site is for operators running a deployed instance — the service has already been installed by Ansible (or equivalent tooling), and you need to understand how it behaves and what the configuration knobs do. There is no installation walkthrough here.

Next steps

  • Architecture: the connection lifecycle, the decision backends, and the core vocabulary.
  • Configuration: full YAML reference, one section at a time.
  • Operations: systemd, CLI flags, logging, and connection stats.
  • Pause control: pausing and unpausing a subscriber's traffic at runtime over NATS.