When dealing with SSL/TLS traffic (port 443), the encryption presents unique challenges for transparent inspection that don't exist with HTTP (port 80). The core issue lies in the SSL handshake process where the client expects to communicate directly with the destination server, not an intermediate proxy.
The reason your initial approach with Charles failed is that SSL/TLS requires the proxy to:
1. Terminate the client's SSL connection
2. Initiate a new SSL connection to the destination
3. Present a valid certificate to the client
A raw port redirect breaks this chain because Charles receives encrypted traffic without context about the original destination hostname (SNI).
Here's a working configuration that preserves destination information:
# iptables rules
*nat
-A PREROUTING -i eth1 -p tcp --dport 80 -j REDIRECT --to-port 1337
-A PREROUTING -i eth1 -p tcp --dport 443 -j REDIRECT --to-port 1338
-A POSTROUTING -s 192.168.2.0/24 -o eth0 -j MASQUERADE
# Enable TPROXY for SSL
*mangle
-A PREROUTING -i eth1 -p tcp -m socket --transparent -j MARK --set-mark 1
-A PREROUTING -i eth1 -p tcp --dport 443 -j TPROXY --tproxy-mark 0x1/0x1 --on-port 1338
For the proxy to work with SSL:
- Enable "Transparent HTTP proxying" in Proxy Settings
- Install Charles root certificate on all clients
- Configure SSL Proxying for target domains (*.* for all)
For enterprise-grade solutions, consider Squid with SSL bump:
# squid.conf snippet
http_port 3128 intercept
https_port 3130 cert=/etc/squid/ssl/cert.pem key=/etc/squid/ssl/key.pem intercept ssl-bump
ssl_bump stare all
ssl_bump bump all
When destination hosts appear stripped:
- Verify TPROXY kernel support (CONFIG_NETFILTER_TPROXY)
- Check Charles' access log for X-Forwarded-For headers
- Test with
curl -v --insecure https://example.com
for handshake errors
Remember that transparent SSL inspection:
- May violate privacy laws in some jurisdictions
- Requires explicit user consent in corporate environments
- Should be clearly documented in security policies
- Needs proper certificate management
When implementing a transparent proxy for HTTPS traffic (port 443), we encounter fundamental differences from HTTP traffic handling. The main obstacles are:
- Client-server encryption before proxy interaction occurs
- SNI (Server Name Indication) stripping during redirection
- Certificate trust chain requirements
Your basic setup works for HTTP because plaintext protocols allow easy interception. Here's the working port 80 configuration:
nat
-A PREROUTING -i eth1 -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.168.2.1:1337
-A PREROUTING -i eth1 -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 1337
-A POSTROUTING -s 192.168.2.0/24 -o eth0 -j MASQUERADE
When you added similar rules for 443, you discovered the destination host information gets lost. This happens because:
- The TLS handshake occurs before the HTTP Host header appears
- iptables REDIRECT/DNAT doesn't preserve SNI information
- The proxy needs to know the target host to generate valid certificates
To make this work properly, we need a three-component solution:
1. iptables traffic redirection
2. SNI proxy to preserve host information
3. SSL-intercepting proxy (Charles in this case)
Here's the full implementation using sni-proxy
as an intermediate component:
# Install required components
apt-get install build-essential libevent-dev
git clone https://github.com/dlundquist/sniproxy.git
cd sniproxy
./autogen.sh && ./configure && make && make install
# iptables rules
iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80 -j REDIRECT --to-port 1337
iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 443 -j REDIRECT --to-port 443
# sniproxy configuration (/etc/sniproxy.conf)
user daemon
pidfile /var/run/sniproxy.pid
listen 443 {
proto tcp
table https_hosts
access_log {
filename /var/log/sniproxy/https_access.log
priority notice
}
}
table https_hosts {
.* *:1338
}
Configure Charles with these specific settings:
- Enable "Transparent HTTP proxying"
- Enable "Support HTTP/2" in SSL proxying settings
- Set up reverse proxy mapping: 1338 → destination:port
- Install Charles CA certificate on all client devices
Use this cURL command to verify proper SNI preservation:
curl -v --resolve example.com:443:192.168.2.1 https://example.com
Key things to check:
- The certificate chain shows Charles as the issuer
- The original hostname appears in Charles logs
- No SSL warnings appear in client applications
For more advanced scenarios, consider these options:
1. Squid with SSL bumping
2. mitmproxy in transparent mode
3. Nginx stream module for SNI routing
Important factors for real-world deployment:
- Performance impact of SSL decryption
- Legal compliance for traffic inspection
- Certificate management across client devices
- Logging and audit requirements