Skip to main content

Python proxy that implements DPI evasion mechanisms (TLS record fragmentation, TCP segmentation, encrypted DNS, HTTP)

Project description

DPYProxy

DPYProxy is a python proxy that implements DPI evasion mechanisms. To circumvent TLS censorship, TLS record fragmentation and TCP segmentation are implemented. To circumvent DNS censorship, DPYProxy uses encrypted DNS and TCP segmentation. All DPI evasion mechanisms can be enabled separately.

DPYProxy comes with a TLS and DNS module circumventing TLS and DNS censorship respectively. Both modules are enabled by default:

DNS Module

You can run the DNS module of DPYProxy locally or on a separate machine. It functions as a DNS resolver that circumvents DNS censorship. In a typical setup, DPYProxy runs locally replacing your previous DNS resolver in your system setup.

The DNS module automatically determines a working circumvention method and DNS resolver. You can also specify a circumvention method and resolver manually (see Usage).

The DNS module saves working circumvention methods and resolvers to a file working_resolvers.json. This file is loaded on startup to speed up the determination of a working circumvention method. You can force re-determination using the --dns_skip_working_file flag.

TLS Module

You can run the TLS Module of DPYProxy locally or on a separate machine. It functions like an HTTP CONNECT/SOCKSv4/SOCKSv5 proxy. I.e., you can specify it as your Firefox/Chrome/System Proxy.

In a typical setup, DPYProxy runs locally replacing your previous proxy in your browser or system setup. You can specify your previous proxy as a forward proxy for DPYProxy. This can be helpful if you need DPYProxy for DPI evasion and a separate proxy for IP censorship circumvention.

The TLS module does not automatically determine a working circumvention method. You need to specify the circumvention method manually (see Usage). However, by default, the TLS module uses the DNS module to resolve DNS queries. Thus, if you run both modules, the DNS module automatically determines a working circumvention method for DNS queries used by the TLS module.

HTTP Module

You can run the HTTP module of DPYProxy locally or on a separate machine. It functions like an HTTP CONNECT/SOCKSv4/SOCKSv5 proxy. I.e., you can specify it as your Firefox/Chrome/System Proxy.

In a typical setup, DPYProxy runs locally replacing your previous proxy in your browser or system setup. You can specify your previous proxy as a forward proxy for DPYProxy. This can be helpful if you need DPYProxy for DPI evasion and a separate proxy for IP censorship circumvention.

The HTTP module does not automatically determine a working circumvention method. You need to specify the circumvention method manually (see Usage). Simple HTTP request alterations (e.g., lowercase request) and HTTP Request Smuggling strategies are implemented. A list of all implemented strategies can be found in: modules/http/HttpStrategies. Be careful: HTTP request smuggling is a network attack against benign hosts and its implementation is experimental. Plain HTTP traffic is also visible to any party that can read your traffic (such as your ISP). Use HTTPS (HTTP over TLS) instead

The HTTP module is disabled by default. Enable by providing --disabled-modules ""

HTTP request smuggling can be dangerous: https://portswigger.net/web-security/request-smuggling. Only enable if you know what you are doing and only use it against servers you have permission access via request smuggling. HttpStrategies 100-129 are HTTP request smuggling strategies.

Requirements

You can run DPYProxy with Python or Docker. The requirements for both options are listed below.

  • python3 (if you want to run DPYPRoxy with Python)
    • sudo apt install python3
    • pip3 install . to run as module with python3 main.py or python3 -m dpyproxy
    • OR install hatch and run using hatch run dpyproxy
  • docker (if you want to run DPYProxy in a container)

Quick Start

Start DPYProxy with Docker:

docker-compose up

Alternatively, start DPYProxy with Python:

python3 main.py --tls_record_frag --tls_tcp_frag --tls_frag_size 20 --tls_port 4433 --dns_port 5533

After automatically determining a circumvention method, the expected output looks like this:

INFO:root:DNS Module and TLS module found. Setting DNS server for TLS Module
INFO:root:Determining working circumvention method / resolver!
### Started TCP proxy on localhost:4433 ###
INFO:root:Found working circumvention method / resolver UDP - 1.0.0.3:53! Checking if consistently reachable!
INFO:root:UDP - 1.0.0.3:53 consistently reachable, keeping!
INFO:root:Finding consistent mode and starting resolvers took 0.0792999267578125 seconds in total.
### Started UDP DNS server on 127.0.0.1:5533 ###
### Started TCP DNS server on 127.0.0.1:5533 ###

DPYProxy now resolves all DNS requests to port 5533. You can send a DNS request to the DNS server using dig:

dig wikipedia.org @127.0.0.1 -p 5533

You can also configure the DNS resolver 127.0.0.1:5533 in any application that supports custom DNS resolvers, e.g., in your browser or system settings.

You can test the TLS circumventions using curl

curl -p -x localhost:4433 https://www.wikipedia.org

Detailed usage of DPYPRoxy-DNS and the original TLS module can be found below.

Usage

usage: main.py [options]

Proxy for circumventing DPI-based censorship.

TLS Module:
  --tls_disabled_modes {HTTP,HTTPS,SNI,SOCKSv4,SOCKSv4a,SOCKSv5}
                        List of proxy modes to ignore. By default, all none are disabled. Hence, all are enabled
  --tls_timeout TLS_TIMEOUT
                        Connection timeout in seconds
  --tls_host TLS_HOST   Address the proxy server runs on
  --tls_port TLS_PORT   Port the proxy server runs on
  --tls_record_frag, --no-tls_record_frag
                        Whether to use record fragmentation to forwarded TLS handshake messages (default: True)
  --tls_tcp_frag, --no-tls_tcp_frag
                        Whether to use TCP fragmentation to forwarded messages. (default: True)
  --tls_frag_size TLS_FRAG_SIZE
                        Bytes in each TCP/TLS record fragment
  --tls_dns_server_ip TLS_DNS_SERVER_IP
                        DNS server IP for all DNS queries of the TLS module. If not given, the DNS server started by the DNS module us used. If DNS module is not used, the OS default DNS server is used.
  --tls_dns_server_port TLS_DNS_SERVER_PORT
                        DNS server port for all DNS queries. Only set if a DNS server IP is given. If not given, the default port 53 is used.
  --tls_forward_proxy_host TLS_FORWARD_PROXY_HOST
                        Host of the forward proxy if any is present
  --tls_forward_proxy_port TLS_FORWARD_PROXY_PORT
                        Port the forward proxy server runs on
  --tls_forward_proxy_mode {HTTP,HTTPS,SNI,SOCKSv4,SOCKSv4a,SOCKSv5}
                        The proxy type of the forward proxy
  --tls_forward_proxy_resolve_address, --no-tls_forward_proxy_resolve_address
                        Whether to resolve domains before including them in the HTTP CONNECT request to the second proxy (default: False)

DNS Module:
  --dns_mode DNS_MODE   Mode that the DNS proxy operates in. Default AUTO. If not set to AUTO, still attempts to automatically determine a resolver for the configured mode. To pre-define the used DNS mode and server set this flag and the dns_resolver_host and optionally the dns_resolver_port flags.
  --dns_timeout DNS_TIMEOUT
                        Connection timeout in seconds. For the LAST_RESPONSE mode this timeout will always be reached. Set this timeout and the timeout of calling application accordingly.
  --dns_host DNS_HOST   Address the proxy server runs on
  --dns_port DNS_PORT   Port the proxy server runs on
  --dns_resolver_host DNS_RESOLVER_HOST
                        DNS resolver IP. If set, must correspond to the selected dns_mode.
  --dns_resolver_port DNS_RESOLVER_PORT
                        DNS resolver port. If set, must correspond to the selected dns_mode. If unset, port is chosen based on the chosen or determined mode's standard port
  --dns_censored_domain DNS_CENSORED_DOMAIN
                        A domain name censored in your location. Used to determine working circumventions methods. Specify together with --dns_censored_domain_ip
  --dns_compare_ip_ranges DNS_COMPARE_IP_RANGES
                        A list of IP ranges the resolved IP of the censored domain lies in. The censored domain is specifiable in --dns_censored_domain.
  --dns_block_page_ips DNS_BLOCK_PAGE_IPS
                        Whether the given IP ranges to compare are block page IPs or not. Default is False.
  --dns_add_sni DNS_ADD_SNI
                        Whether or not to include the SNI for encrypted DNS modes. Defaults to True.
  --dns_skip_working_file DNS_SKIP_WORKING_FILE
                        Whether taking the stored working resolver from a file should be skipped. Defaults to False.

HTTP Module:
  --http_timeout HTTP_TIMEOUT
                        Connection timeout in seconds
  --http_host HTTP_HOST
                        Address the proxy server runs on
  --http_port HTTP_PORT
                        Port the proxy server runs on
  --http_strategy HTTP_STRATEGY
                        Number of which specific http manipulation strategy to apply. None: no manipulation, [1..70]: basic manipulations, [101, 129]: Smuggling.See HttpStrategies for meaning.
  --http_smuggling_uncensored_url HTTP_SMUGGLING_UNCENSORED_URL
                        Uncensored url to use for http smuggling.

Standard options:
  -h, --help            Show this help message and exit
  --debug, --no-debug   Turns on debugging (default: False)
  --disabled_modules DISABLED_MODULES
                        List of proxy modules to disable. By default, all none are disabled. Hence, all are enabled

Examples

python3 main.py --disabled_modules TLS launches DPYProxy with just the DNS module enabled. The TLS module is disabled and not used at all. The DNS module starts in its auto mode by default.

python3 main.py --tls_record_frag --no-tls_tcp_frag launches DPYProxy with TLS record fragmentation enabled. TCP fragmentation is turned off. The DNS module is also enabled with its default auto mode to determine a working circumvention. Using this circumvention, a resolver is started that can be used on the system in general and is used by the TLS module by default.

python3 main.py --tls_frag_size 100 launches DPYProxy with both TLS record and TCP fragmentation and sets the fragment size to 100 bytes. The TLS record will be of size 100 while the encompassing TCP segments will be just large enough to contain the fragmented TLS record. The DNS module is also enabled with its default auto mode to determine a working circumvention. Using this circumvention, a resolver is started that can be used on the system in general and is used by the TLS module by default.

python3 main.py --http_smuggling 23 --http_smuggling_uncensored_url 2 launches DPYProxy with HTTP Request Smuggling strategy number 23 enabled, using the second of three incorporated urls that are found to be uncensored (in china). This specific strategy includes the Content-Length Header to set the bounds before the hidden request and the Transfer-Encoding Header to set them after the body to hide the second request. Additionally the Transfer-Encoding Header gets modified to include a second Colon (Transfer-Encoding:: chunked). A list of all implemented smuggling strategies (and direct manipulations) can be found in: modules/http/HttpStrategies. There you will also find the three uncensored urls.

python3 main.py --record_frag --forward_proxy_address 192.168.0.1 --forward_proxy_port 8080 --forward_proxy_mode HTTPS --forward_proxy_resolve_address launches DPYProxy with TLS record fragmentation and a forward proxy. The forward proxy is specified by its address and port. While DPYProxy accepts HTTP GET, HTTP CONNECT and TLS ClientHello messages for proxying, it connects to the forward proxy using HTTP CONNECT. The DNS module is also enabled with its default auto mode to determine a working circumvention. Using this circumvention, a resolver is started that can be used on the system in general and is used by the TLS module by default.

Testing

Setup DPYProxy using

python3 main.py --tls_record_frag --tls_tcp_frag --tls_frag_size 20 --tls_port 4433 --dns_port 5533

You can test the TLS circumventions using curl

curl -p -x localhost:4433 https://www.wikipedia.org

Using some kind of capturing tool like Wireshark, you can inspect the fragmented TLS records and TCP segments.

You can test the DNS circumventions using dig

dig wikipedia.org @127.0.0.1 -p 5533

Using some kind of capturing tool like Wireshark, you can inspect the made DNS requests for the selected circumvention strategy.

Docker

You can run DPYProxy in a Docker container. A standard setting is provided in the docker-compose.yml file. You can also build the image yourself using the provided Dockerfile or change the parameters in the docker-compose.yml file.

Start the container with:

docker-compose up

Roadmap

We developed DPYProxy when writing a blogpost in which we circumvented the GFW with TLS record fragmentation. Thus, the functionality of DPYProxy is currently limited. Below, I gathered some potential avenues for the future.

Implemented

  • HTTP Connect Proxy
  • SNI Proxy
  • DNS Resolver
  • Socksv4/Sockv5 proxy
  • TLS record fragmentation
  • TCP Fragmentation
  • HTTP Circumventions

Todo

  • unit tests...
  • IPv6

Maintainance

  • Run ruff check --fix to fix the auto fixable lint issues.
  • Run ruff format . to pretty the code. Few could need a manual effort.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dpyproxy-2.2.0.tar.gz (48.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dpyproxy-2.2.0-py3-none-any.whl (63.3 kB view details)

Uploaded Python 3

File details

Details for the file dpyproxy-2.2.0.tar.gz.

File metadata

  • Download URL: dpyproxy-2.2.0.tar.gz
  • Upload date:
  • Size: 48.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for dpyproxy-2.2.0.tar.gz
Algorithm Hash digest
SHA256 7eea04d58656fcb5c949a37167a53359ca61158487e42a99700c7f885ac0c6b4
MD5 bde36ef83b14c7fdc669d5f040c01abf
BLAKE2b-256 e60db3f5097fa893188eaab980752ecac41fe3c72cb2ed0906d2bb75cd87b21c

See more details on using hashes here.

File details

Details for the file dpyproxy-2.2.0-py3-none-any.whl.

File metadata

  • Download URL: dpyproxy-2.2.0-py3-none-any.whl
  • Upload date:
  • Size: 63.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for dpyproxy-2.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 87d5e71c8f799257d95f036c47618c14cd4fc9a10578a903fd27e2f1a3a90f0b
MD5 58815861b31b0c34f712e8751498c972
BLAKE2b-256 580bb7b3a385424d5820594251867938f76829ab2dabc042171a7faf0f3793b7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page