Skip to content

Instantly share code, notes, and snippets.

@thedtvn
Created January 3, 2026 21:56
Show Gist options
  • Select an option

  • Save thedtvn/bf774b889dfd232c131875cd1054deda to your computer and use it in GitHub Desktop.

Select an option

Save thedtvn/bf774b889dfd232c131875cd1054deda to your computer and use it in GitHub Desktop.

SNI Bypass Script for mitmproxy

A mitmproxy script that bypasses Deep Packet Inspection (DPI) SNI filtering and handles SSL certificate pinning gracefully.

Overview

This script intercepts TLS connections and modifies the Server Name Indication (SNI) to bypass government or ISP-level censorship that blocks specific domains. It also intelligently handles certificate pinning to avoid breaking apps and websites that implement it.

How It Works

1. SNI Obfuscation

When a blocked domain is detected, the script generates a fake SNI by adding a random subdomain:

  • Original: example.com → Modified: a1b2c3d4.example.com
  • The DPI filter doesn't recognize the modified SNI pattern
  • The server still accepts the connection as it resolves to the same domain

2. Automatic Blocking Detection

  • On TLS connection failure, automatically adds domain to block list
  • Next connection attempt uses fake SNI bypass
  • Connection is killed and retried automatically by the browser

3. Certificate Pinning Protection

  • Detects certificate verification failures
  • Adds domain to skip list to prevent future MITM attempts
  • Preserves connections for apps with SSL pinning (banking apps, security software)

Requirements

pip install -r requirements.txt

Usage

Basic Usage ( Http base )

mitmdump -s .\bypass_dpi.py --set block_global=false

Local Mode (recommended for current machine use with out config proxy)

mitmdump -s .\bypass_dpi.py --mode local --set block_global=false

Known limitation

  • It will slow when that sni is block and wait for connection timeout to add to block list
  • This is just Edu example and not a Long-term soulution
Made by The DT for internet freedom.
from mitmproxy import tls, connection
from mitmproxy.script import concurrent
from tldextract import extract
import secrets
block_domain = set()
skip_domain = set()
modify_sni = {}
def _generate_fake_sni(original_sni: str) -> str:
"""
Well this work by send random subdomain to bypass DPI SNI filtering
example if original_sni is example.com
it will return ab12cd34.example.com wich skip check by DPI
work as well for subdomain like a.b.example.com
it will return ef56gh78.example.com
"""
registered_domain = extract(original_sni).registered_domain
return f"{secrets.token_hex(4)}.{registered_domain}"
@concurrent
def tls_clienthello(data: tls.ClientHelloData):
"""
Check if the SNI is in the skip_domain list to ignore the connection
this will prevent mitm tampering with the connection
this help web or app that check certificate pinning to work properly
"""
if data.client_hello.sni is None or data.client_hello.sni in skip_domain:
data.ignore_connection = True
return
@concurrent
def tls_start_server(data: tls.TlsData):
"""
This is modify the SNI to bypass DPI filtering
if the SNI is in the block_domain list
"""
if data.context.client.sni not in block_domain:
return
if data.context.client.sni in modify_sni:
new_sni = modify_sni[data.context.client.sni]
else:
new_sni = _generate_fake_sni(data.context.client.sni)
data.context.server.sni = new_sni
modify_sni[data.context.client.sni] = new_sni
print(f"Modified SNI from {data.context.client.sni} to {new_sni}")
@concurrent
def tls_failed_server(data: tls.TlsData):
"""
Handle TLS failures from the server side
If the failure is due to certificate verification, add the domain to skip_domain
This to avoid future attempts to mitm try to tamper with the connection
and keep connections preserved
"""
print(f"TLS failed server for SNI: {data.context.server.sni}")
# Add to block domain for future connections
block_domain.add(data.context.client.sni)
if data.conn.error.startswith("Certificate verify failed"):
skip_domain.add(data.context.client.sni)
data.context.server.state = connection.ConnectionState.CLOSED
data.context.client.state = connection.ConnectionState.CLOSED
print(
f"Added {data.context.client.sni} to skip_domain due to certificate verification failure"
)
return
print(f"Reason Error Server: {data.conn.error}")
print(f"Added {data.context.client.sni} to block_domain for SNI bypass")
data.context.server.state = connection.ConnectionState.CLOSED
data.context.client.state = connection.ConnectionState.CLOSED
@concurrent
def tls_failed_client(data: tls.TlsData):
"""
Handle TLS failures from the client side this use to add domain to skip_domain
to avoid future attempts to mitm tamper with the connection that ssl pinning apps or website use
Then kill the connection to make reconnection with no mitm tampering
"""
print(f"TLS failed client for SNI: {data.context.client.sni}")
if data.context.client.sni in block_domain:
return
print(f"Reason Error Client: {data.conn.error}")
skip_domain.add(data.context.client.sni)
print(f"Added {data.context.client.sni} to skip_domain to avoid future attempts")
data.context.server.state = connection.ConnectionState.CLOSED
data.context.client.state = connection.ConnectionState.CLOSED
@concurrent
def tls_established_server(data: tls.TlsData):
"""
Clean up the modify_sni mapping after a successful TLS handshake
This prevents the mapping from growing indefinitely
"""
if data.context.client.sni in modify_sni:
original_sni = data.context.client.sni
new_sni = modify_sni[original_sni]
print(
f"SNI bypass successful for {original_sni}, using modified SNI: {new_sni}"
)
# Clean up the mapping after successful connection
del modify_sni[original_sni]
mitmproxy
tldextract
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment