29 Commits

Author SHA1 Message Date
ValdikSS
9bfce3156e Make mode -9 the default, instead of -5
Auto-ttl gives many false positives in TTL detection, which breaks non-blocked websites.
Use the combination of wrong-seq and wrong-chksum and hope to the best.
Also block QUIC to workaround possible throttling, as right now it is not dissected.
2024-07-31 14:49:15 +03:00
ValdikSS
f7362094d3 New modes: -8 and -9
-8 is -7 with added --wrong-seq, it sends two subsequent fake packets, one with
incorrect sequence, and another one with incorrect checksum.

-9 is -8 with QUIC block.
2024-07-31 14:49:15 +03:00
ValdikSS
f1aece75ae New mode: -7 - As -6 but with wrong chksum 2024-07-31 14:49:15 +03:00
ValdikSS
60dd3cb004 Make ClientHello ignore --max-payload limits
Receive TLS ClientHello despite max-payload limit set, to get all
the benefits of the option (decreased CPU consumption) but still
handle all TLS connections, including Kyber.
2024-07-31 14:49:15 +03:00
ValdikSS
d031ae65bf New option: -q - block QUIC/HTTP3
Only Initial packet in Long Header Packets are blocked.
The packet should be at least 1200 bytes in size.
2024-07-31 14:49:10 +03:00
ValdikSS
905d3c98a6 Revert "Add Unicorn HTTPS for iOS": doesn't do anything
This reverts commit 95c5ca81b2.
2024-07-26 03:44:16 +03:00
ValdikSS
b08836de50 Use WinDivert 2.2.0-D for Windows 7 compatibility 2024-07-25 00:51:47 +03:00
ValdikSS
cf1f2a8674 Actions: use $GITHUB_OUTPUT instead of ::set-output 2024-07-23 07:14:35 +03:00
ValdikSS
16464646a9 Use WinDivert 2.2.2 2024-07-23 07:11:47 +03:00
ValdikSS
ba015cf44e Update Github Actions "actions" to newest versions 2024-07-23 07:11:18 +03:00
ValdikSS
3837635f2c Use non-prefixed windres for msys2. #372 2024-07-23 07:04:08 +03:00
ValdikSS
95c5ca81b2 Add Unicorn HTTPS for iOS 2024-05-31 03:18:56 +03:00
ValdikSS
bbb7e4cea8 Add ByeDPI 2024-05-30 22:41:46 +03:00
ValdikSS
15eb10ac68 Fragment packet by the beginning of SNI value. #357
It has been reported that the DPI systems in Saudi Arabia and
United Arab Emirates are started to search for the beginning of
SNI extension header and its value, without parsing the TLS ClientHello
packet, in any part of TCP session.

Workaround the issue by splitting the packet right after the end
of extension headers and before its value.

https://ntc.party/t/goodbyedpi-in-saudi-arabia/7884
https://ntc.party/t/goodbyedpi-in-uae/7914
2024-05-30 22:16:14 +03:00
ValdikSS
4c846c712d Handle TLSv1.2 record version handshakes (16 03 03). #353 2024-05-30 21:02:16 +03:00
ValdikSS
4a82fd442d Add manual Github Action trigger 2023-03-29 13:38:48 +03:00
ValdikSS
b3c9ff8419 Merge pull request #270 from mohadangKim/master
fix memcpy usage
2022-08-06 15:06:14 +03:00
ValdikSS
fc6fd98a62 Merge branch 'VladWinner-master' 2022-08-06 14:52:15 +03:00
ValdikSS
6304328548 Merge branch 'master' of https://github.com/VladWinner/GoodbyeDPI into VladWinner-master 2022-08-06 14:52:02 +03:00
ValdikSS
86867fe678 Add GhosTCP by macronut to the list of alternative projects 2022-08-06 14:46:00 +03:00
mohadangKim
54349a1c31 fix memcpy usage 2022-07-01 22:12:55 +09:00
ValdikSS
4f18a73239 Print correct set-ttl/auto-ttl mode in the status 2022-03-31 12:15:40 +03:00
ValdikSS
67629fb6ef Disable auto-ttl if set-ttl has been used after auto-ttl 2022-03-31 12:14:03 +03:00
ValdikSS
27a6d256f0 Handle HTTP GET and POST in packets larger than --max-payload
If --max-payload 1200 is used and there's HTTP request with lots of cookies
which exceed 1200 bytes in size, this packet would have been skipped as
'too large', and the circumvention won't be applied.
Fix this by checking for "GET " or "POST" in the beginning of the packet
regardless of its size.
2022-03-21 15:17:27 +03:00
ValdikSS
938dce7333 Merge branch 'windivert2' 2022-03-21 15:06:15 +03:00
Vlad
54f810b6b0 Update README.md 2022-03-14 20:26:29 +03:00
ValdikSS
68a68aede9 Use WinDivert 2.2.0 for Github Actions building 2022-01-04 15:13:57 +03:00
ValdikSS
4a8f7ac4fb Call WinDivertShutdown on shutdown 2022-01-04 03:14:47 +03:00
ValdikSS
ee4ce8893c Initial support for WinDivert 2.0+
This patch adds WinDivert 2.0+ support in a backward-incompatible way.
WinDivert 1.4 won't work after this commit anymore.
2022-01-03 21:23:40 +03:00
5 changed files with 175 additions and 97 deletions

View File

@@ -4,22 +4,24 @@ on:
push: push:
paths: paths:
- 'src/**' - 'src/**'
workflow_dispatch:
env: env:
WINDIVERT_URL: https://www.reqrypt.org/download/WinDivert-1.4.3-A.zip WINDIVERT_URL: https://reqrypt.org/download/WinDivert-2.2.0-D.zip
WINDIVERT_NAME: WinDivert-1.4.3-A.zip WINDIVERT_NAME: WinDivert-2.2.0-D.zip
WINDIVERT_SHA256: 4084bc3931f31546d375ed89e3f842776efa46f321ed0adcd32d3972a7d02566 WINDIVERT_BASENAME: WinDivert-2.2.0-D
WINDIVERT_SHA256: 1d461cfdfa7ba88ebcfbb3603b71b703e9f72aba8aeff99a75ce293e6f89d2ba
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v4
- name: Declare short commit variable - name: Declare short commit variable
id: vars id: vars
run: | run: |
echo "::set-output name=sha_short::$(git rev-parse --short HEAD)" echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Install MinGW-w64 - name: Install MinGW-w64
run: > run: >
@@ -29,7 +31,7 @@ jobs:
- name: Download WinDivert from cache - name: Download WinDivert from cache
id: windivert-cache id: windivert-cache
uses: actions/cache@v2 uses: actions/cache@v4
with: with:
path: ${{ env. WINDIVERT_NAME }} path: ${{ env. WINDIVERT_NAME }}
key: ${{ env. WINDIVERT_SHA256 }} key: ${{ env. WINDIVERT_SHA256 }}
@@ -46,15 +48,15 @@ jobs:
- name: Compile x86_64 - name: Compile x86_64
run: > run: >
cd src && make clean && cd src && make clean &&
make CPREFIX=x86_64-w64-mingw32- BIT64=1 WINDIVERTHEADERS=../WinDivert-1.4.3-A/include WINDIVERTLIBS=../WinDivert-1.4.3-A/x86_64 -j4 make CPREFIX=x86_64-w64-mingw32- BIT64=1 WINDIVERTHEADERS=../${{ env.WINDIVERT_BASENAME }}/include WINDIVERTLIBS=../${{ env.WINDIVERT_BASENAME }}/x64 -j4
- name: Prepare x86_64 directory - name: Prepare x86_64 directory
run: | run: |
mkdir goodbyedpi_x86_64_${{ steps.vars.outputs.sha_short }} mkdir goodbyedpi_x86_64_${{ steps.vars.outputs.sha_short }}
cp src/goodbyedpi.exe WinDivert-1.4.3-A/x86_64/*.{dll,sys} goodbyedpi_x86_64_${{ steps.vars.outputs.sha_short }} cp src/goodbyedpi.exe ${{ env.WINDIVERT_BASENAME }}/x64/*.{dll,sys} goodbyedpi_x86_64_${{ steps.vars.outputs.sha_short }}
- name: Upload output file x86_64 (64 bit) - name: Upload output file x86_64
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v4
with: with:
name: goodbyedpi_x86_64_${{ steps.vars.outputs.sha_short }} name: goodbyedpi_x86_64_${{ steps.vars.outputs.sha_short }}
path: goodbyedpi_x86_64_${{ steps.vars.outputs.sha_short }} path: goodbyedpi_x86_64_${{ steps.vars.outputs.sha_short }}
@@ -62,15 +64,15 @@ jobs:
- name: Compile i686 - name: Compile i686
run: > run: >
cd src && make clean && cd src && make clean &&
make CPREFIX=i686-w64-mingw32- WINDIVERTHEADERS=../WinDivert-1.4.3-A/include WINDIVERTLIBS=../WinDivert-1.4.3-A/x86 -j4 make CPREFIX=i686-w64-mingw32- WINDIVERTHEADERS=../${{ env.WINDIVERT_BASENAME }}/include WINDIVERTLIBS=../${{ env.WINDIVERT_BASENAME }}/x86 -j4
- name: Prepare x86 directory - name: Prepare x86 directory
run: | run: |
mkdir goodbyedpi_x86_${{ steps.vars.outputs.sha_short }} mkdir goodbyedpi_x86_${{ steps.vars.outputs.sha_short }}
cp src/goodbyedpi.exe WinDivert-1.4.3-A/x86/*.{dll,sys} goodbyedpi_x86_${{ steps.vars.outputs.sha_short }} cp src/goodbyedpi.exe ${{ env.WINDIVERT_BASENAME }}/x86/*.{dll,sys} goodbyedpi_x86_${{ steps.vars.outputs.sha_short }}
- name: Upload output file x86 - name: Upload output file x86
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v4
with: with:
name: goodbyedpi_x86_${{ steps.vars.outputs.sha_short }} name: goodbyedpi_x86_${{ steps.vars.outputs.sha_short }}
path: goodbyedpi_x86_${{ steps.vars.outputs.sha_short }} path: goodbyedpi_x86_${{ steps.vars.outputs.sha_short }}

View File

@@ -22,6 +22,7 @@ Download [latest version from Releases page](https://github.com/ValdikSS/Goodbye
``` ```
Usage: goodbyedpi.exe [OPTION...] Usage: goodbyedpi.exe [OPTION...]
-p block passive DPI -p block passive DPI
-q block QUIC/HTTP3
-r replace Host with hoSt -r replace Host with hoSt
-s remove space between host header and its value -s remove space between host header and its value
-m mix Host header case (test.com -> tEsT.cOm) -m mix Host header case (test.com -> tEsT.cOm)
@@ -43,6 +44,7 @@ Usage: goodbyedpi.exe [OPTION...]
supplied text file (HTTP Host/TLS SNI). supplied text file (HTTP Host/TLS SNI).
This option can be supplied multiple times. This option can be supplied multiple times.
--allow-no-sni perform circumvention if TLS SNI can't be detected with --blacklist enabled. --allow-no-sni perform circumvention if TLS SNI can't be detected with --blacklist enabled.
--frag-by-sni if SNI is detected in TLS packet, fragment the packet right before SNI value.
--set-ttl <value> activate Fake Request Mode and send it with supplied TTL value. --set-ttl <value> activate Fake Request Mode and send it with supplied TTL value.
DANGEROUS! May break websites in unexpected ways. Use with care (or --blacklist). DANGEROUS! May break websites in unexpected ways. Use with care (or --blacklist).
--auto-ttl [a1-a2-m] activate Fake Request Mode, automatically detect TTL and decrease --auto-ttl [a1-a2-m] activate Fake Request Mode, automatically detect TTL and decrease
@@ -76,8 +78,13 @@ LEGACY modesets:
-4 -p -r -s (best speed) -4 -p -r -s (best speed)
Modern modesets (more stable, more compatible, faster): Modern modesets (more stable, more compatible, faster):
-5 -f 2 -e 2 --auto-ttl --reverse-frag --max-payload (this is the default) -5 -f 2 -e 2 --auto-ttl --reverse-frag --max-payload
-6 -f 2 -e 2 --wrong-seq --reverse-frag --max-payload -6 -f 2 -e 2 --wrong-seq --reverse-frag --max-payload
-7 -f 2 -e 2 --wrong-chksum --reverse-frag --max-payload
-8 -f 2 -e 2 --wrong-seq --wrong-chksum --reverse-frag --max-payload
-9 -f 2 -e 2 --wrong-seq --wrong-chksum --reverse-frag --max-payload -q (this is the default)
Note: combination of --wrong-seq and --wrong-chksum generates two different fake packets.
``` ```
To check if your ISP's DPI could be circumvented, first make sure that your provider does not poison DNS answers by enabling "Secure DNS (DNS over HTTPS)" option in your browser. To check if your ISP's DPI could be circumvented, first make sure that your provider does not poison DNS answers by enabling "Secure DNS (DNS over HTTPS)" option in your browser.
@@ -140,12 +147,15 @@ Modify them according to your own needs.
# Similar projects # Similar projects
- **[zapret](https://github.com/bol-van/zapret)** by @bol-van (for Linux). - **[zapret](https://github.com/bol-van/zapret)** by @bol-van (for Linux)
- **[Green Tunnel](https://github.com/SadeghHayeri/GreenTunnel)** by @SadeghHayeri (for MacOS, Linux and Windows). - **[Green Tunnel](https://github.com/SadeghHayeri/GreenTunnel)** by @SadeghHayeri (for MacOS, Linux and Windows)
- **[DPITunnel](https://github.com/zhenyolka/DPITunnel)** by @zhenyolka (for Android). - **[DPI Tunnel CLI](https://github.com/zhenyolka/DPITunnel-cli)** by @zhenyolka (for Linux and routers)
- **[PowerTunnel](https://github.com/krlvm/PowerTunnel)** by @krlvm (for Windows, MacOS and Linux). - **[DPI Tunnel for Android](https://github.com/zhenyolka/DPITunnel-android)** by @zhenyolka (for Android)
- **[PowerTunnel for Android](https://github.com/krlvm/PowerTunnel-Android)** by @krlvm (for Android). - **[PowerTunnel](https://github.com/krlvm/PowerTunnel)** by @krlvm (for Windows, MacOS and Linux)
- **[PowerTunnel for Android](https://github.com/krlvm/PowerTunnel-Android)** by @krlvm (for Android)
- **[SpoofDPI](https://github.com/xvzc/SpoofDPI)** by @xvzc (for macOS and Linux) - **[SpoofDPI](https://github.com/xvzc/SpoofDPI)** by @xvzc (for macOS and Linux)
- **[GhosTCP](https://github.com/macronut/ghostcp)** by @macronut (for Windows)
- **[ByeDPI](https://github.com/hufrea/byedpi)** for Linux/Windows + **[ByeDPIAndroid](https://github.com/dovecoteescapee/ByeDPIAndroid/)** for Android (no root)
# Kudos # Kudos

View File

@@ -11,7 +11,12 @@ TARGET = goodbyedpi.exe
#LIBS = -L$(WINDIVERTLIBS) -Wl,-Bstatic -lssp -Wl,-Bdynamic -lWinDivert -lws2_32 #LIBS = -L$(WINDIVERTLIBS) -Wl,-Bstatic -lssp -Wl,-Bdynamic -lWinDivert -lws2_32
LIBS = -L$(WINDIVERTLIBS) -lWinDivert -lws2_32 -l:libssp.a LIBS = -L$(WINDIVERTLIBS) -lWinDivert -lws2_32 -l:libssp.a
CC = $(CPREFIX)gcc CC = $(CPREFIX)gcc
CCWINDRES = $(CPREFIX)windres CCWINDRES = $(CPREFIX)windres
ifeq (, $(shell which $(CPREFIX)windres))
CCWINDRES = windres
endif
CFLAGS = -std=c99 -pie -fPIE -pipe -I$(WINDIVERTHEADERS) -L$(WINDIVERTLIBS) \ CFLAGS = -std=c99 -pie -fPIE -pipe -I$(WINDIVERTHEADERS) -L$(WINDIVERTLIBS) \
-O2 -D_FORTIFY_SOURCE=2 -fstack-protector \ -O2 -D_FORTIFY_SOURCE=2 -fstack-protector \
-Wall -Wextra -Wpedantic -Wformat=2 -Wformat-overflow=2 -Wformat-truncation=2 \ -Wall -Wextra -Wpedantic -Wformat=2 -Wformat-overflow=2 -Wformat-truncation=2 \

View File

@@ -70,19 +70,21 @@ static int send_fake_data(const HANDLE w_filter,
memcpy(&addr_new, addr, sizeof(WINDIVERT_ADDRESS)); memcpy(&addr_new, addr, sizeof(WINDIVERT_ADDRESS));
memcpy(packet_fake, pkt, packetLen); memcpy(packet_fake, pkt, packetLen);
addr_new.PseudoTCPChecksum = 0; addr_new.TCPChecksum = 0;
addr_new.PseudoIPChecksum = 0; addr_new.IPChecksum = 0;
if (!is_ipv6) { if (!is_ipv6) {
// IPv4 TCP Data packet // IPv4 TCP Data packet
if (!WinDivertHelperParsePacket(packet_fake, packetLen, &ppIpHdr, if (!WinDivertHelperParsePacket(packet_fake, packetLen, &ppIpHdr,
NULL, NULL, NULL, &ppTcpHdr, NULL, &packet_data, &packet_dataLen)) NULL, NULL, NULL, NULL, &ppTcpHdr, NULL, &packet_data, &packet_dataLen,
NULL, NULL))
return 1; return 1;
} }
else { else {
// IPv6 TCP Data packet // IPv6 TCP Data packet
if (!WinDivertHelperParsePacket(packet_fake, packetLen, NULL, if (!WinDivertHelperParsePacket(packet_fake, packetLen, NULL,
&ppIpV6Hdr, NULL, NULL, &ppTcpHdr, NULL, &packet_data, &packet_dataLen)) &ppIpV6Hdr, NULL, NULL, NULL, &ppTcpHdr, NULL, &packet_data, &packet_dataLen,
NULL, NULL))
return 1; return 1;
} }
@@ -126,12 +128,12 @@ static int send_fake_data(const HANDLE w_filter,
// ...and damage it // ...and damage it
ppTcpHdr->Checksum = htons(ntohs(ppTcpHdr->Checksum) - 1); ppTcpHdr->Checksum = htons(ntohs(ppTcpHdr->Checksum) - 1);
} }
//printf("Pseudo checksum: %d\n", addr_new.PseudoTCPChecksum); //printf("Pseudo checksum: %d\n", addr_new.TCPChecksum);
WinDivertSend( WinDivertSend(
w_filter, packet_fake, w_filter, packet_fake,
packetLen_new, packetLen_new,
&addr_new, NULL NULL, &addr_new
); );
debug("Fake packet: OK"); debug("Fake packet: OK");

View File

@@ -78,6 +78,9 @@ WINSOCK_API_LINKAGE INT WSAAPI inet_pton(INT Family, LPCSTR pStringBuf, PVOID pA
"(tcp.DstPort == 80 or tcp.DstPort == 443) and tcp.Ack and " \ "(tcp.DstPort == 80 or tcp.DstPort == 443) and tcp.Ack and " \
"(" DIVERT_NO_LOCALNETSv4_DST " or " DIVERT_NO_LOCALNETSv6_DST "))" \ "(" DIVERT_NO_LOCALNETSv4_DST " or " DIVERT_NO_LOCALNETSv6_DST "))" \
"))" "))"
#define FILTER_PASSIVE_BLOCK_QUIC "outbound and !impostor and !loopback and udp " \
"and udp.DstPort == 443 and udp.PayloadLength >= 1200 " \
"and udp.Payload[0] >= 0xC0 and udp.Payload32[1b] == 0x01"
#define FILTER_PASSIVE_STRING_TEMPLATE "inbound and ip and tcp and " \ #define FILTER_PASSIVE_STRING_TEMPLATE "inbound and ip and tcp and " \
"!impostor and !loopback and " \ "!impostor and !loopback and " \
"((ip.Id <= 0xF and ip.Id >= 0x0) " IPID_TEMPLATE ") and " \ "((ip.Id <= 0xF and ip.Id >= 0x0) " IPID_TEMPLATE ") and " \
@@ -162,6 +165,7 @@ static struct option long_options[] = {
{"dns-verb", no_argument, 0, 'v' }, {"dns-verb", no_argument, 0, 'v' },
{"blacklist", required_argument, 0, 'b' }, {"blacklist", required_argument, 0, 'b' },
{"allow-no-sni",no_argument, 0, ']' }, {"allow-no-sni",no_argument, 0, ']' },
{"frag-by-sni", no_argument, 0, '>' },
{"ip-id", required_argument, 0, 'i' }, {"ip-id", required_argument, 0, 'i' },
{"set-ttl", required_argument, 0, '$' }, {"set-ttl", required_argument, 0, '$' },
{"min-ttl", required_argument, 0, '[' }, {"min-ttl", required_argument, 0, '[' },
@@ -216,7 +220,11 @@ static void add_ip_id_str(int id) {
static void add_maxpayloadsize_str(unsigned short maxpayload) { static void add_maxpayloadsize_str(unsigned short maxpayload) {
char *newstr; char *newstr;
const char *maxpayloadsize_str = "and (tcp.PayloadLength ? tcp.PayloadLength < %hu : true)"; /* 0x47455420 is "GET ", 0x504F5354 is "POST", big endian. */
const char *maxpayloadsize_str =
"and (tcp.PayloadLength ? tcp.PayloadLength < %hu " \
"or tcp.Payload32[0] == 0x47455420 or tcp.Payload32[0] == 0x504F5354 " \
"or (tcp.Payload[0] == 0x16 and tcp.Payload[1] == 0x03 and tcp.Payload[2] <= 0x03): true)";
char *addfilter = malloc(strlen(maxpayloadsize_str) + 16); char *addfilter = malloc(strlen(maxpayloadsize_str) + 16);
sprintf(addfilter, maxpayloadsize_str, maxpayload); sprintf(addfilter, maxpayloadsize_str, maxpayload);
@@ -309,6 +317,7 @@ static HANDLE init(char *filter, UINT64 flags) {
static int deinit(HANDLE handle) { static int deinit(HANDLE handle) {
if (handle) { if (handle) {
WinDivertShutdown(handle, WINDIVERT_SHUTDOWN_BOTH);
WinDivertClose(handle); WinDivertClose(handle);
return TRUE; return TRUE;
} }
@@ -472,7 +481,7 @@ static void send_native_fragment(HANDLE w_filter, WINDIVERT_ADDRESS addr,
PWINDIVERT_TCPHDR ppTcpHdr, PWINDIVERT_TCPHDR ppTcpHdr,
unsigned int fragment_size, int step) { unsigned int fragment_size, int step) {
char packet_bak[MAX_PACKET_SIZE]; char packet_bak[MAX_PACKET_SIZE];
memcpy(&packet_bak, packet, packetLen); memcpy(packet_bak, packet, packetLen);
UINT orig_packetLen = packetLen; UINT orig_packetLen = packetLen;
if (fragment_size >= packet_dataLen) { if (fragment_size >= packet_dataLen) {
@@ -518,8 +527,8 @@ static void send_native_fragment(HANDLE w_filter, WINDIVERT_ADDRESS addr,
ppTcpHdr->SeqNum = htonl(ntohl(ppTcpHdr->SeqNum) + fragment_size); ppTcpHdr->SeqNum = htonl(ntohl(ppTcpHdr->SeqNum) + fragment_size);
} }
addr.PseudoIPChecksum = 0; addr.IPChecksum = 0;
addr.PseudoTCPChecksum = 0; addr.TCPChecksum = 0;
WinDivertHelperCalcChecksums( WinDivertHelperCalcChecksums(
packet, packetLen, &addr, 0 packet, packetLen, &addr, 0
@@ -527,9 +536,9 @@ static void send_native_fragment(HANDLE w_filter, WINDIVERT_ADDRESS addr,
WinDivertSend( WinDivertSend(
w_filter, packet, w_filter, packet,
packetLen, packetLen,
&addr, NULL NULL, &addr
); );
memcpy(packet, &packet_bak, orig_packetLen); memcpy(packet, packet_bak, orig_packetLen);
//printf("Sent native fragment of %d size (step%d)\n", packetLen, step); //printf("Sent native fragment of %d size (step%d)\n", packetLen, step);
} }
@@ -556,7 +565,8 @@ int main(int argc, char *argv[]) {
conntrack_info_t dns_conn_info; conntrack_info_t dns_conn_info;
tcp_conntrack_info_t tcp_conn_info; tcp_conntrack_info_t tcp_conn_info;
int do_passivedpi = 0, do_fragment_http = 0, int do_passivedpi = 0, do_block_quic = 0,
do_fragment_http = 0,
do_fragment_http_persistent = 0, do_fragment_http_persistent = 0,
do_fragment_http_persistent_nowait = 0, do_fragment_http_persistent_nowait = 0,
do_fragment_https = 0, do_host = 0, do_fragment_https = 0, do_host = 0,
@@ -566,6 +576,7 @@ int main(int argc, char *argv[]) {
do_dnsv4_redirect = 0, do_dnsv6_redirect = 0, do_dnsv4_redirect = 0, do_dnsv6_redirect = 0,
do_dns_verb = 0, do_tcp_verb = 0, do_blacklist = 0, do_dns_verb = 0, do_tcp_verb = 0, do_blacklist = 0,
do_allow_no_sni = 0, do_allow_no_sni = 0,
do_fragment_by_sni = 0,
do_fake_packet = 0, do_fake_packet = 0,
do_auto_ttl = 0, do_auto_ttl = 0,
do_wrong_chksum = 0, do_wrong_chksum = 0,
@@ -627,17 +638,19 @@ int main(int argc, char *argv[]) {
); );
if (argc == 1) { if (argc == 1) {
/* enable mode -5 by default */ /* enable mode -9 by default */
do_fragment_http = do_fragment_https = 1; do_fragment_http = do_fragment_https = 1;
do_reverse_frag = do_native_frag = 1; do_reverse_frag = do_native_frag = 1;
http_fragment_size = https_fragment_size = 2; http_fragment_size = https_fragment_size = 2;
do_fragment_http_persistent = do_fragment_http_persistent_nowait = 1; do_fragment_http_persistent = do_fragment_http_persistent_nowait = 1;
do_fake_packet = 1; do_fake_packet = 1;
do_auto_ttl = 1; do_wrong_chksum = 1;
do_wrong_seq = 1;
do_block_quic = 1;
max_payload_size = 1200; max_payload_size = 1200;
} }
while ((opt = getopt_long(argc, argv, "123456prsaf:e:mwk:n", long_options, NULL)) != -1) { while ((opt = getopt_long(argc, argv, "123456789pqrsaf:e:mwk:n", long_options, NULL)) != -1) {
switch (opt) { switch (opt) {
case '1': case '1':
do_passivedpi = do_host = do_host_removespace \ do_passivedpi = do_host = do_host_removespace \
@@ -678,9 +691,27 @@ int main(int argc, char *argv[]) {
do_wrong_seq = 1; do_wrong_seq = 1;
max_payload_size = 1200; max_payload_size = 1200;
break; break;
case '9': // +7+8
do_block_quic = 1;
// fall through
case '8': // +7
do_wrong_seq = 1;
// fall through
case '7':
do_fragment_http = do_fragment_https = 1;
do_reverse_frag = do_native_frag = 1;
http_fragment_size = https_fragment_size = 2;
do_fragment_http_persistent = do_fragment_http_persistent_nowait = 1;
do_fake_packet = 1;
do_wrong_chksum = 1;
max_payload_size = 1200;
break;
case 'p': case 'p':
do_passivedpi = 1; do_passivedpi = 1;
break; break;
case 'q':
do_block_quic = 1;
break;
case 'r': case 'r':
do_host = 1; do_host = 1;
break; break;
@@ -804,7 +835,11 @@ int main(int argc, char *argv[]) {
case ']': // --allow-no-sni case ']': // --allow-no-sni
do_allow_no_sni = 1; do_allow_no_sni = 1;
break; break;
case '>': // --frag-by-sni
do_fragment_by_sni = 1;
break;
case '$': // --set-ttl case '$': // --set-ttl
do_auto_ttl = auto_ttl_1 = auto_ttl_2 = auto_ttl_max = 0;
do_fake_packet = 1; do_fake_packet = 1;
ttl_of_fake_packet = atoub(optarg, "Set TTL parameter error!"); ttl_of_fake_packet = atoub(optarg, "Set TTL parameter error!");
break; break;
@@ -876,6 +911,7 @@ int main(int argc, char *argv[]) {
default: default:
puts("Usage: goodbyedpi.exe [OPTION...]\n" puts("Usage: goodbyedpi.exe [OPTION...]\n"
" -p block passive DPI\n" " -p block passive DPI\n"
" -q block QUIC/HTTP3\n"
" -r replace Host with hoSt\n" " -r replace Host with hoSt\n"
" -s remove space between host header and its value\n" " -s remove space between host header and its value\n"
" -a additional space between Method and Request-URI (enables -s, may break sites)\n" " -a additional space between Method and Request-URI (enables -s, may break sites)\n"
@@ -896,6 +932,7 @@ int main(int argc, char *argv[]) {
" supplied text file (HTTP Host/TLS SNI).\n" " supplied text file (HTTP Host/TLS SNI).\n"
" This option can be supplied multiple times.\n" " This option can be supplied multiple times.\n"
" --allow-no-sni perform circumvention if TLS SNI can't be detected with --blacklist enabled.\n" " --allow-no-sni perform circumvention if TLS SNI can't be detected with --blacklist enabled.\n"
" --frag-by-sni if SNI is detected in TLS packet, fragment the packet right before SNI value.\n"
" --set-ttl <value> activate Fake Request Mode and send it with supplied TTL value.\n" " --set-ttl <value> activate Fake Request Mode and send it with supplied TTL value.\n"
" DANGEROUS! May break websites in unexpected ways. Use with care (or --blacklist).\n" " DANGEROUS! May break websites in unexpected ways. Use with care (or --blacklist).\n"
" --auto-ttl [a1-a2-m] activate Fake Request Mode, automatically detect TTL and decrease\n" " --auto-ttl [a1-a2-m] activate Fake Request Mode, automatically detect TTL and decrease\n"
@@ -929,8 +966,13 @@ int main(int argc, char *argv[]) {
" -4 -p -r -s (best speed)" " -4 -p -r -s (best speed)"
"\n" "\n"
"Modern modesets (more stable, more compatible, faster):\n" "Modern modesets (more stable, more compatible, faster):\n"
" -5 -f 2 -e 2 --auto-ttl --reverse-frag --max-payload (this is the default)\n" " -5 -f 2 -e 2 --auto-ttl --reverse-frag --max-payload\n"
" -6 -f 2 -e 2 --wrong-seq --reverse-frag --max-payload\n"); " -6 -f 2 -e 2 --wrong-seq --reverse-frag --max-payload\n"
" -7 -f 2 -e 2 --wrong-chksum --reverse-frag --max-payload\n"
" -8 -f 2 -e 2 --wrong-seq --wrong-chksum --reverse-frag --max-payload\n"
" -9 -f 2 -e 2 --wrong-seq --wrong-chksum --reverse-frag --max-payload -q (this is the default)\n\n"
"Note: combination of --wrong-seq and --wrong-chksum generates two different fake packets.\n"
);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
@@ -951,9 +993,11 @@ int main(int argc, char *argv[]) {
} }
printf("Block passive: %d\n" /* 1 */ printf("Block passive: %d\n" /* 1 */
"Block QUIC/HTTP3: %d\n" /* 1 */
"Fragment HTTP: %u\n" /* 2 */ "Fragment HTTP: %u\n" /* 2 */
"Fragment persistent HTTP: %u\n" /* 3 */ "Fragment persistent HTTP: %u\n" /* 3 */
"Fragment HTTPS: %u\n" /* 4 */ "Fragment HTTPS: %u\n" /* 4 */
"Fragment by SNI: %u\n" /* 5 */
"Native fragmentation (splitting): %d\n" /* 5 */ "Native fragmentation (splitting): %d\n" /* 5 */
"Fragments sending in reverse: %d\n" /* 6 */ "Fragments sending in reverse: %d\n" /* 6 */
"hoSt: %d\n" /* 7 */ "hoSt: %d\n" /* 7 */
@@ -969,27 +1013,28 @@ int main(int argc, char *argv[]) {
"Fake requests, wrong checksum: %d\n" /* 17 */ "Fake requests, wrong checksum: %d\n" /* 17 */
"Fake requests, wrong SEQ/ACK: %d\n" /* 18 */ "Fake requests, wrong SEQ/ACK: %d\n" /* 18 */
"Max payload size: %hu\n", /* 19 */ "Max payload size: %hu\n", /* 19 */
do_passivedpi, /* 1 */ do_passivedpi, do_block_quic, /* 1 */
(do_fragment_http ? http_fragment_size : 0), /* 2 */ (do_fragment_http ? http_fragment_size : 0), /* 2 */
(do_fragment_http_persistent ? http_fragment_size : 0),/* 3 */ (do_fragment_http_persistent ? http_fragment_size : 0),/* 3 */
(do_fragment_https ? https_fragment_size : 0), /* 4 */ (do_fragment_https ? https_fragment_size : 0), /* 4 */
do_native_frag, /* 5 */ do_fragment_by_sni, /* 5 */
do_reverse_frag, /* 6 */ do_native_frag, /* 6 */
do_host, /* 7 */ do_reverse_frag, /* 7 */
do_host_removespace, /* 8 */ do_host, /* 8 */
do_additional_space, /* 9 */ do_host_removespace, /* 9 */
do_host_mixedcase, /* 10 */ do_additional_space, /* 10 */
do_http_allports, /* 11 */ do_host_mixedcase, /* 11 */
do_fragment_http_persistent_nowait, /* 12 */ do_http_allports, /* 12 */
do_dnsv4_redirect, /* 13 */ do_fragment_http_persistent_nowait, /* 13 */
do_dnsv6_redirect, /* 14 */ do_dnsv4_redirect, /* 14 */
do_allow_no_sni, /* 15 */ do_dnsv6_redirect, /* 15 */
ttl_of_fake_packet ? "fixed" : (do_auto_ttl ? "auto" : "disabled"), /* 16 */ do_allow_no_sni, /* 16 */
do_auto_ttl ? "auto" : (do_fake_packet ? "fixed" : "disabled"), /* 17 */
ttl_of_fake_packet, do_auto_ttl ? auto_ttl_1 : 0, do_auto_ttl ? auto_ttl_2 : 0, ttl_of_fake_packet, do_auto_ttl ? auto_ttl_1 : 0, do_auto_ttl ? auto_ttl_2 : 0,
do_auto_ttl ? auto_ttl_max : 0, ttl_min_nhops, do_auto_ttl ? auto_ttl_max : 0, ttl_min_nhops,
do_wrong_chksum, /* 17 */ do_wrong_chksum, /* 18 */
do_wrong_seq, /* 18 */ do_wrong_seq, /* 19 */
max_payload_size /* 19 */ max_payload_size /* 20 */
); );
if (do_fragment_http && http_fragment_size > 2 && !do_native_frag) { if (do_fragment_http && http_fragment_size > 2 && !do_native_frag) {
@@ -1001,7 +1046,7 @@ int main(int argc, char *argv[]) {
if (do_native_frag && !(do_fragment_http || do_fragment_https)) { if (do_native_frag && !(do_fragment_http || do_fragment_https)) {
puts("\nERROR: Native fragmentation is enabled but fragment sizes are not set.\n" puts("\nERROR: Native fragmentation is enabled but fragment sizes are not set.\n"
"Fragmentation has no effect."); "Fragmentation has no effect.");
exit(EXIT_FAILURE); die();
} }
if (max_payload_size) if (max_payload_size)
@@ -1020,6 +1065,15 @@ int main(int argc, char *argv[]) {
filter_num++; filter_num++;
} }
if (do_block_quic) {
filters[filter_num] = init(
FILTER_PASSIVE_BLOCK_QUIC,
WINDIVERT_FLAG_DROP);
if (filters[filter_num] == NULL)
die();
filter_num++;
}
/* /*
* IPv4 & IPv6 filter for inbound HTTP redirection packets and * IPv4 & IPv6 filter for inbound HTTP redirection packets and
* active DPI circumvention * active DPI circumvention
@@ -1038,11 +1092,12 @@ int main(int argc, char *argv[]) {
signal(SIGINT, sigint_handler); signal(SIGINT, sigint_handler);
while (1) { while (1) {
if (WinDivertRecv(w_filter, packet, sizeof(packet), &addr, &packetLen)) { if (WinDivertRecv(w_filter, packet, sizeof(packet), &packetLen, &addr)) {
debug("Got %s packet, len=%d!\n", addr.Direction ? "inbound" : "outbound", debug("Got %s packet, len=%d!\n", addr.Outbound ? "outbound" : "inbound",
packetLen); packetLen);
should_reinject = 1; should_reinject = 1;
should_recalc_checksum = 0; should_recalc_checksum = 0;
sni_ok = 0;
ppIpHdr = (PWINDIVERT_IPHDR)NULL; ppIpHdr = (PWINDIVERT_IPHDR)NULL;
ppIpV6Hdr = (PWINDIVERT_IPV6HDR)NULL; ppIpV6Hdr = (PWINDIVERT_IPV6HDR)NULL;
@@ -1052,35 +1107,35 @@ int main(int argc, char *argv[]) {
packet_type = unknown; packet_type = unknown;
// Parse network packet and set it's type // Parse network packet and set it's type
if ((packet_v4 = WinDivertHelperParsePacket(packet, packetLen, &ppIpHdr, if (WinDivertHelperParsePacket(packet, packetLen, &ppIpHdr,
NULL, NULL, NULL, &ppTcpHdr, NULL, &packet_data, &packet_dataLen))) &ppIpV6Hdr, NULL, NULL, NULL, &ppTcpHdr, &ppUdpHdr, &packet_data, &packet_dataLen,
NULL, NULL))
{ {
packet_type = ipv4_tcp_data; if (ppIpHdr) {
} packet_v4 = 1;
else if ((packet_v6 = WinDivertHelperParsePacket(packet, packetLen, NULL, if (ppTcpHdr) {
&ppIpV6Hdr, NULL, NULL, &ppTcpHdr, NULL, &packet_data, &packet_dataLen))) packet_type = ipv4_tcp;
{ if (packet_data) {
packet_type = ipv6_tcp_data; packet_type = ipv4_tcp_data;
} }
else if ((packet_v4 = WinDivertHelperParsePacket(packet, packetLen, &ppIpHdr, }
NULL, NULL, NULL, &ppTcpHdr, NULL, NULL, NULL))) else if (ppUdpHdr && packet_data) {
{ packet_type = ipv4_udp_data;
packet_type = ipv4_tcp; }
} }
else if ((packet_v6 = WinDivertHelperParsePacket(packet, packetLen, NULL,
&ppIpV6Hdr, NULL, NULL, &ppTcpHdr, NULL, NULL, NULL))) else if (ppIpV6Hdr) {
{ packet_v6 = 1;
packet_type = ipv6_tcp; if (ppTcpHdr) {
} packet_type = ipv6_tcp;
else if ((packet_v4 = WinDivertHelperParsePacket(packet, packetLen, &ppIpHdr, if (packet_data) {
NULL, NULL, NULL, NULL, &ppUdpHdr, &packet_data, &packet_dataLen))) packet_type = ipv6_tcp_data;
{ }
packet_type = ipv4_udp_data; }
} else if (ppUdpHdr && packet_data) {
else if ((packet_v6 = WinDivertHelperParsePacket(packet, packetLen, NULL, packet_type = ipv6_udp_data;
&ppIpV6Hdr, NULL, NULL, NULL, &ppUdpHdr, &packet_data, &packet_dataLen))) }
{ }
packet_type = ipv6_udp_data;
} }
debug("packet_type: %d, packet_v4: %d, packet_v6: %d\n", packet_type, packet_v4, packet_v6); debug("packet_type: %d, packet_v4: %d, packet_v6: %d\n", packet_type, packet_v4, packet_v6);
@@ -1090,7 +1145,7 @@ int main(int argc, char *argv[]) {
/* Got a TCP packet WITH DATA */ /* Got a TCP packet WITH DATA */
/* Handle INBOUND packet with data and find HTTP REDIRECT in there */ /* Handle INBOUND packet with data and find HTTP REDIRECT in there */
if (addr.Direction == WINDIVERT_DIRECTION_INBOUND && packet_dataLen > 16) { if (!addr.Outbound && packet_dataLen > 16) {
/* If INBOUND packet with DATA (tcp.Ack) */ /* If INBOUND packet with DATA (tcp.Ack) */
/* Drop packets from filter with HTTP 30x Redirect */ /* Drop packets from filter with HTTP 30x Redirect */
@@ -1114,7 +1169,7 @@ int main(int argc, char *argv[]) {
/* Handle OUTBOUND packet on port 443, search for something that resembles /* Handle OUTBOUND packet on port 443, search for something that resembles
* TLS handshake, send fake request. * TLS handshake, send fake request.
*/ */
else if (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND && else if (addr.Outbound &&
((do_fragment_https ? packet_dataLen == https_fragment_size : 0) || ((do_fragment_https ? packet_dataLen == https_fragment_size : 0) ||
packet_dataLen > 16) && packet_dataLen > 16) &&
ppTcpHdr->DstPort != htons(80) && ppTcpHdr->DstPort != htons(80) &&
@@ -1126,9 +1181,9 @@ int main(int argc, char *argv[]) {
* But if the packet is more than 2 bytes, check ClientHello byte. * But if the packet is more than 2 bytes, check ClientHello byte.
*/ */
if ((packet_dataLen == 2 && memcmp(packet_data, "\x16\x03", 2) == 0) || if ((packet_dataLen == 2 && memcmp(packet_data, "\x16\x03", 2) == 0) ||
(packet_dataLen >= 3 && memcmp(packet_data, "\x16\x03\x01", 3) == 0)) (packet_dataLen >= 3 && ( memcmp(packet_data, "\x16\x03\x01", 3) == 0 || memcmp(packet_data, "\x16\x03\x03", 3) == 0 )))
{ {
if (do_blacklist) { if (do_blacklist || do_fragment_by_sni) {
sni_ok = extract_sni(packet_data, packet_dataLen, sni_ok = extract_sni(packet_data, packet_dataLen,
&host_addr, &host_len); &host_addr, &host_len);
} }
@@ -1144,7 +1199,7 @@ int main(int argc, char *argv[]) {
char lsni[HOST_MAXLEN + 1] = {0}; char lsni[HOST_MAXLEN + 1] = {0};
extract_sni(packet_data, packet_dataLen, extract_sni(packet_data, packet_dataLen,
&host_addr, &host_len); &host_addr, &host_len);
memcpy(&lsni, host_addr, host_len); memcpy(lsni, host_addr, host_len);
printf("Blocked HTTPS website SNI: %s\n", lsni); printf("Blocked HTTPS website SNI: %s\n", lsni);
#endif #endif
if (do_fake_packet) { if (do_fake_packet) {
@@ -1158,7 +1213,7 @@ int main(int argc, char *argv[]) {
} }
} }
/* Handle OUTBOUND packet on port 80, search for Host header */ /* Handle OUTBOUND packet on port 80, search for Host header */
else if (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND && else if (addr.Outbound &&
packet_dataLen > 16 && packet_dataLen > 16 &&
(do_http_allports ? 1 : (ppTcpHdr->DstPort == htons(80))) && (do_http_allports ? 1 : (ppTcpHdr->DstPort == htons(80))) &&
find_http_method_end(packet_data, find_http_method_end(packet_data,
@@ -1179,7 +1234,7 @@ int main(int argc, char *argv[]) {
host_len = hdr_value_len; host_len = hdr_value_len;
#ifdef DEBUG #ifdef DEBUG
char lhost[HOST_MAXLEN + 1] = {0}; char lhost[HOST_MAXLEN + 1] = {0};
memcpy(&lhost, host_addr, host_len); memcpy(lhost, host_addr, host_len);
printf("Blocked HTTP website Host: %s\n", lhost); printf("Blocked HTTP website Host: %s\n", lhost);
#endif #endif
@@ -1281,7 +1336,11 @@ int main(int argc, char *argv[]) {
current_fragment_size = http_fragment_size; current_fragment_size = http_fragment_size;
} }
else if (do_fragment_https && ppTcpHdr->DstPort != htons(80)) { else if (do_fragment_https && ppTcpHdr->DstPort != htons(80)) {
current_fragment_size = https_fragment_size; if (do_fragment_by_sni && sni_ok) {
current_fragment_size = (void*)host_addr - packet_data;
} else {
current_fragment_size = https_fragment_size;
}
} }
if (current_fragment_size) { if (current_fragment_size) {
@@ -1302,7 +1361,7 @@ int main(int argc, char *argv[]) {
/* Else if we got TCP packet without data */ /* Else if we got TCP packet without data */
else if (packet_type == ipv4_tcp || packet_type == ipv6_tcp) { else if (packet_type == ipv4_tcp || packet_type == ipv6_tcp) {
/* If we got INBOUND SYN+ACK packet */ /* If we got INBOUND SYN+ACK packet */
if (addr.Direction == WINDIVERT_DIRECTION_INBOUND && if (!addr.Outbound &&
ppTcpHdr->Syn == 1 && ppTcpHdr->Ack == 1) { ppTcpHdr->Syn == 1 && ppTcpHdr->Ack == 1) {
//printf("Changing Window Size!\n"); //printf("Changing Window Size!\n");
/* /*
@@ -1342,7 +1401,7 @@ int main(int argc, char *argv[]) {
else if ((do_dnsv4_redirect && (packet_type == ipv4_udp_data)) || else if ((do_dnsv4_redirect && (packet_type == ipv4_udp_data)) ||
(do_dnsv6_redirect && (packet_type == ipv6_udp_data))) (do_dnsv6_redirect && (packet_type == ipv6_udp_data)))
{ {
if (addr.Direction == WINDIVERT_DIRECTION_INBOUND) { if (!addr.Outbound) {
if ((packet_v4 && dns_handle_incoming(&ppIpHdr->DstAddr, ppUdpHdr->DstPort, if ((packet_v4 && dns_handle_incoming(&ppIpHdr->DstAddr, ppUdpHdr->DstPort,
packet_data, packet_dataLen, packet_data, packet_dataLen,
&dns_conn_info, 0)) &dns_conn_info, 0))
@@ -1372,7 +1431,7 @@ int main(int argc, char *argv[]) {
} }
} }
else if (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND) { else if (addr.Outbound) {
if ((packet_v4 && dns_handle_outgoing(&ppIpHdr->SrcAddr, ppUdpHdr->SrcPort, if ((packet_v4 && dns_handle_outgoing(&ppIpHdr->SrcAddr, ppUdpHdr->SrcPort,
&ppIpHdr->DstAddr, ppUdpHdr->DstPort, &ppIpHdr->DstAddr, ppUdpHdr->DstPort,
packet_data, packet_dataLen, 0)) packet_data, packet_dataLen, 0))
@@ -1410,7 +1469,7 @@ int main(int argc, char *argv[]) {
if (should_recalc_checksum) { if (should_recalc_checksum) {
WinDivertHelperCalcChecksums(packet, packetLen, &addr, (UINT64)0LL); WinDivertHelperCalcChecksums(packet, packetLen, &addr, (UINT64)0LL);
} }
WinDivertSend(w_filter, packet, packetLen, &addr, NULL); WinDivertSend(w_filter, packet, packetLen, NULL, &addr);
} }
} }
else { else {