TLS SNI Router & Filter (tls_sni)
The TLS SNI Plugin extracts the Server Name Indication (SNI) extension from raw TLS ClientHello packets at Layer 4 without decrypting or terminating TLS certificates. This enables operators to enforce domain allowlists/blocklists, prevent malware command-and-control access, and route encrypted traffic to backends with zero cryptographic overhead and zero access to private keys.
Capabilities & Threat Defense
| Threat / Attack Vector | Defense Mechanism | Action Taken |
|---|---|---|
| Unauthorized Domain Probing | Inspects TLS ClientHello SNI extension | Connection dropped before TLS handshake completes |
| Malicious Outbound / C2 Connections | Filters SNI against blocked_domains | Connection terminated immediately |
| Unencrypted Traffic on TLS Port | Validates TLS record header (0x16 0x03) | Non-TLS traffic immediately rejected |
| Private Key Exposure | Pure zero-decryption Layer 4 inspection | Never requires certificates or private keys |
Installation
Install the plugin via CLI or declaratively:
# Install using short nametcp-warden plugins install tls_sni# Or install via Git repository URLtcp-warden plugins install https://github.com/routewarden/plugins/tls_sniConfiguration Reference
Add a TLS SNI guard service to tcp-warden.yaml:
services: tls_proxy: listen: ":8443" upstream: "127.0.0.1:443" protocol: "tls" rate_limit: connections_per_minute: 120 burst: 20 plugin_config: allowed_domains: - "*.routewarden.io" - "routewarden.io" - "api.internal" blocked_domains: - "*.malware.example" - "c2.threat.org"Configuration Options
| Field | Type | Default | Description |
|---|---|---|---|
listen | string | ":8443" | Local proxy listen address and port. |
upstream | string | "127.0.0.1:443" | Target TLS service or downstream reverse proxy. |
protocol | string | "tls" | Must be set to "tls", "tls-sni", or "sni". |
plugin_config.allowed_domains | []string | [] | List of allowed domain patterns (supports wildcards *.domain.com). If empty, all unblocked domains are allowed. |
plugin_config.blocked_domains | []string | [] | List of explicitly blocked domain patterns. |
Network & Deployment Architecture
Option A: Kernel Firewall Redirection (nftables / iptables)
Redirect incoming external HTTPS/TLS traffic on port 443 to RouteWarden port 8443:
# Redirect incoming external HTTPS/TLS traffic on port 443 to RouteWarden port 8443sudo nft add rule ip routewarden_nat prerouting iifname "eth0" tcp dport 443 redirect to :8443Option B: Docker Compose Network Isolation
Route encrypted TLS traffic to an internal TLS-terminating container without exposing the backend directly:
services: routewarden: image: ghcr.io/routewarden/tcp-warden:latest ports: - "443:8443" # Map host HTTPS/TLS port 443 to RouteWarden - "9091:9091" # Management API volumes: - ./tcp-warden.yaml:/etc/routewarden/tcp-warden.yaml:ro depends_on: - web-tls web-tls: image: caddy:alpine # Do NOT publish host ports; RouteWarden transparently routes TLS SNI upstreamTesting & Verification
Verify allowed domains, test blocked domains, and verify immediate drop of non-TLS connections:
# Test allowed domain through SNI proxycurl -vk --resolve routewarden.io:8443:127.0.0.1 https://routewarden.io:8443/