Research tool for studying DPI, TLS fingerprinting, and content-delivery protections via ClientHello splitting and parallel-strategy bypass. For educational and research purposes only.
Project description
NullGazeX — Research Tool for Network Filtering Analysis
Important: NullGazeX is a research and educational tool designed to study network filtering, Deep Packet Inspection (DPI), TLS fingerprinting, and content-delivery protection mechanisms. It is not intended for unauthorized access to protected content. The author assumes no liability for any misuse or for any consequences arising from its use. By using this software you agree that you are solely responsible for complying with all applicable laws and the terms of service of any website you interact with.
NullGazeX implements a multi-tier pipeline of bypass strategies — raced in parallel for terrifying speed — to retrieve content through ISP SNI filters, Cloudflare challenges, TLS fingerprint checks, and hotlinking protections.
What NullGazeX Does
| Capability | Description |
|---|---|
| Image Downloading | Download images through any firewall or anti-scraping protection. |
| Page Scraping | Retrieve full page HTML, text, titles, or JSON from any URL — undetected. |
| DPI Bypass | ClientHello packet splitting evades ISP SNI filters without external proxies or VPNs. |
| TLS Impersonation | Rotates curl_cffi browser fingerprints (Chrome, Safari, Firefox, Edge) so traffic looks like a real browser. |
| Parallel Strategy Racing | All bypass strategies launch concurrently — the fastest wins in fractions of a second. |
| Adaptive Anti-Blocking | Per-domain cooldown, jittered delays, session cycling, and fingerprint rotation prevent server-side rate-limiting. |
| Stealth Browser Fallback | Headless Chromium (via DrissionPage) with anti-detection flags for extreme JS challenges. |
How It Works
NullGazeX uses a local loopback proxy that intercepts the TLS ClientHello handshake packet and splits it into two TCP segments with an 8 ms gap between them. The SNI (Server Name Indication) field is thus broken across two packets. DPI firewalls inspect packets individually and do not reassemble them — so the SNI check never fires.
Combined with rotating TLS fingerprints (the curl_cffi library
impersonates Chrome 110–124, Safari 15–17, Firefox 116–117, and Edge
99–110), the traffic is indistinguishable from a real browser.
For more details see DPI_BYPASS_DOC.md.
Installation
Standard (image downloading + scraping)
pip install NullGazeX
With browser support (for extreme JS challenges)
pip install NullGazeX[browser]
Full installation (everything)
pip install NullGazeX[full]
Dependencies are resolved automatically:
| Extra | Includes |
|---|---|
| (none) | requests, curl_cffi |
browser |
DrissionPage (headless Chromium) |
scrape |
beautifulsoup4 (HTML parsing) |
full |
everything above |
Quick Start — Image Downloading
Single image
from nullgaze import download_image
download_image(
url="https://example.com/images/photo.jpg",
output_path="outputs/photo.jpg",
verbose=True
)
Batch download (concurrent)
from nullgaze import download_images
targets = [
("https://example.com/img1.jpg", "outputs/img1.jpg"),
("https://example.com/img2.jpg", "outputs/img2.jpg"),
("https://example.com/img3.jpg", "outputs/img3.jpg"),
]
results = download_images(targets, max_workers=10, verbose=True)
for i, res in enumerate(results):
if isinstance(res, Exception):
print(f"Failed {i+1}: {res}")
else:
print(f"Saved to: {res}")
Quick Start — Page Scraping
Scrape a page (raw HTML)
from nullgaze import scrape_page
html = scrape_page("https://example.com/article", verbose=True)
print(html[:500])
Scrape clean text
from nullgaze import scrape_text
text = scrape_text("https://example.com/article")
print(text)
Get page title
from nullgaze import scrape_title
title = scrape_title("https://example.com/article")
print(f"Title: {title}")
Scrape a JSON API
from nullgaze import scrape_json
data = scrape_json("https://api.example.com/data")
print(data)
Scrape multiple URLs in parallel
from nullgaze import scrape_bulk
urls = [
"https://example.com/page1",
"https://example.com/page2",
"https://example.com/page3",
]
results = scrape_bulk(urls, max_workers=10, verbose=True)
for i, res in enumerate(results):
if isinstance(res, Exception):
print(f"Failed {urls[i]}: {res}")
else:
print(f"Success: {len(res)} chars")
Object-Oriented API
Image Downloader
from nullgaze import ImageDownloader
downloader = ImageDownloader(verbose=True)
custom_headers = {
"Referer": "https://custom-referer.com/",
"Cookie": "session=abc123",
}
downloader.download(
url="https://example.com/protected/image.png",
output_path="outputs/image.png",
headers=custom_headers,
race_timeout=3.0, # give up after 3s
)
Page Scraper
from nullgaze import PageScraper
scraper = PageScraper(verbose=True)
# All strategies race in parallel
html = scraper.scrape("https://example.com", race_timeout=5.0)
# Get just the title
title = scraper.scrape_title("https://example.com")
# Get clean text
text = scraper.scrape_text("https://example.com")
Strategy Pipeline
NullGazeX races these strategies in parallel — the first to succeed wins, the rest are cancelled:
| Tier | Strategy | Speed | Best For |
|---|---|---|---|
| 1 | Direct HTTP | ⚡⚡⚡ ~0.3s | Unrestricted servers |
| 2 | DPI-Bypass + TLS Impersonation | ⚡⚡ ~0.5s | ISP SNI blocks, fingerprint checks |
| 3 | Stealth Browser (Chromium) | 🐢 ~3s | Cloudflare Turnstile, JS challenges |
| 4 | Weserv Proxy (images only) | ⚡⚡ ~1s | General fallback |
The library caches the successful strategy per domain so subsequent requests to the same domain skip the race and go straight to the winning strategy.
Anti-Blocking Features
| Mechanism | How It Works |
|---|---|
| Fingerprint rotation | Each request picks a random TLS fingerprint (Chrome 110–124, Safari 15–17, Firefox 116–117, Edge 99–110). |
| Header rotation | User-Agent, Accept, Accept-Language, and Sec-Fetch-* headers are randomized per request. |
| Jittered delays | 50–200 ms random delay between bulk dispatches to avoid burst detection. |
| Adaptive cooldown | When a server returns 429/503, the domain is cooled down with exponential backoff (2s → 4s → 8s → capped at 30s). |
| Session cycling | curl_cffi sessions are cycled every 25 requests to rotate TLS session state. |
| Domain strategy cache | Caches which strategy works per domain — avoids re-discovering on every request. |
Error Handling
from nullgaze import (
download_image,
DownloadFailedError,
InvalidURLError,
ScrapeError,
BlockedError,
)
# Image errors
try:
download_image("https://example.com/img.jpg", "output.jpg")
except InvalidURLError:
print("Bad URL")
except DownloadFailedError as e:
print(f"All strategies failed: {e}")
# Scraping errors
from nullgaze import scrape_page
try:
html = scrape_page("https://example.com")
except BlockedError:
print("Server explicitly blocked us (403/429/503)")
except ScrapeError as e:
print(f"Scraping failed: {e}")
Pre-Warming for Maximum Speed
Call engine_prewarm() at startup to pre-launch the DPI-bypass proxy
and open a trial connection. The first real request will hit a hot path
in under 100 ms:
from nullgaze import engine_prewarm, download_image
engine_prewarm() # proxy ready, connections hot
# Now every request starts at full speed
download_image("https://example.com/img.jpg", "output.jpg")
License
MIT License. See LICENSE.
Disclaimer
This library is provided as a research and educational tool for studying network filtering, DPI, TLS fingerprinting, and web scraping techniques. The author is not responsible for how you use it. You are solely responsible for ensuring your use complies with all applicable laws, regulations, and the terms of service of any website you interact with. By using this software you acknowledge these terms.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nullgazex-2.1.0.tar.gz.
File metadata
- Download URL: nullgazex-2.1.0.tar.gz
- Upload date:
- Size: 17.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c577dccdff30d6d5eed5d73c589fb47b2295a66e64d55178d428116c8d59b839
|
|
| MD5 |
7ae2d8a04a0c730ea7ce54b9c0dd3504
|
|
| BLAKE2b-256 |
24520e1e3202150c0c44a405c5f3ff5dde3e847d923ba393fad2a9b4babbcce5
|
File details
Details for the file nullgazex-2.1.0-py3-none-any.whl.
File metadata
- Download URL: nullgazex-2.1.0-py3-none-any.whl
- Upload date:
- Size: 19.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9ea169c596daba59e80d5aa5be5b6ef1c42e5ecf83c8aa028b04e2cc67403b25
|
|
| MD5 |
e9b824753a149778fccc8255cf992a84
|
|
| BLAKE2b-256 |
a370ac56f688cf17bd525ba02b03189946863c421b68639a3d374c177babc870
|