When dealing with modern encrypted traffic, traditional transparent proxy approaches hit a fundamental limitation: you can't inspect/modify SSL/TLS traffic without performing MITM (Man-in-the-Middle) decryption. However, for domain-based filtering without content inspection, we have alternative approaches.
The primary obstacles in implementing SSL transparent proxying are:
- SNI (Server Name Indication) extraction requires packet inspection
- TCP connection splicing must maintain encryption integrity
- IPVS/NAT complications with encrypted payloads
Here are three operational approaches:
# Method 1: iptables + SNI inspection
iptables -t mangle -A PREROUTING -p tcp --dport 443 -j TPROXY \
--on-port 3128 --tproxy-mark 1/1
# Requires proxy supporting TPROXY and SNI extraction:
# Example with haproxy configuration
frontend https-in
bind :3128 transparent
mode tcp
tcp-request inspect-delay 5s
tcp-request content capture req.ssl_sni len 100
use_backend %[req.ssl_sni,lower]
For domain whitelisting/blacklisting, consider this Python pseudocode:
def handle_sni(sni):
with open('/etc/proxy/domains.list') as f:
blocked_domains = set(line.strip() for line in f)
if sni in blocked_domains:
reset_connection()
else:
forward_traffic()
To prevent bypass attempts:
# Block direct HTTPS access except from proxy
iptables -A OUTPUT -p tcp --dport 443 -m owner ! --uid-owner proxyuser -j REJECT
# Alternative: Network-level enforcement
iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 3128
Tool | SNI Support | Transparent Mode |
---|---|---|
HAProxy | Yes | Yes (TPROXY) |
Nginx | Yes (1.11.5+) | Limited |
Privoxy | No | No |
Here's a complete configuration for domain filtering using HAProxy:
global
tune.ssl.default-dh-param 2048
frontend https
bind :3128 transparent
mode tcp
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
acl valid_domain req_ssl_sni -f /etc/haproxy/allowed_domains.lst
tcp-request content reject if !valid_domain
use_backend upstream_%[req_ssl_sni]
backend upstream_example.com
mode tcp
server example 93.184.216.34:443
Note that this approach maintains full encryption while still providing domain-level access control.
Setting up a transparent proxy for SSL traffic (port 443) presents unique technical hurdles because:
- HTTPS encrypts both the request and response, including the domain name in the initial TLS handshake (SNI)
- Traditional transparent proxies work at layer 4 (TCP) while domain filtering requires layer 7 visibility
- Any MITM approach would require certificate installation on clients
One working solution without breaking encryption is using DNS filtering combined with iptables:
# Example iptables rules for DNS redirection
iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-port 53
iptables -t nat -A PREROUTING -p tcp --dport 53 -j REDIRECT --to-port 53
# Block direct HTTPS access if not via proxy
iptables -A FORWARD -p tcp --dport 443 -m state --state NEW -j DROP
This requires running a DNS server (like dnsmasq) with domain blacklists:
# dnsmasq.conf example
address=/bad-domain.com/127.0.0.1
address=/another-bad-site.com/0.0.0.0
server=/good-domain.com/8.8.8.8
Modern solutions can inspect Server Name Indication (SNI) in TLS handshakes:
# nftables example for SNI filtering
table inet filter {
chain output {
type filter hook output priority 0; policy accept;
tcp dport 443 tls_sni "blacklisted.com" counter drop
}
}
Tools like:
- sniproxy - Lightweight SNI-based proxy
- tlsproxy - MITM-capable proxy with optional decryption
- Pound - Reverse proxy with SNI awareness
For corporate environments, consider these architectural approaches:
- Transparent proxy at gateway level using PF_SENSE/OPNSense
- Endpoint-based solutions using authenticated proxies
- Cloud-based secure web gateways
Example enterprise deployment:
# Enterprise firewall rules example
# Allow only proxy server to initiate HTTPS
iptables -A FORWARD -p tcp --dport 443 -s ! $PROXY_IP -j DROP
# Redirect all HTTP to proxy
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to $PROXY_IP:3128