mirror of
https://github.com/ValdikSS/GoodbyeDPI.git
synced 2025-12-17 12:54:36 +03:00
Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
754ff6ff06 | ||
|
|
3114036d09 | ||
|
|
ae7398035a | ||
|
|
ee009cf107 | ||
|
|
810aef6aed | ||
|
|
c0f43a293e | ||
|
|
03cb084f10 | ||
|
|
abd2e77ca4 | ||
|
|
d2265d3167 | ||
|
|
4fbfeb8956 | ||
|
|
207a2f7004 | ||
|
|
311b26e744 | ||
|
|
e344f5711c | ||
|
|
14fb025468 | ||
|
|
a95fe3ebff | ||
|
|
8a0bef08bf | ||
|
|
cb9cc82fde | ||
|
|
c2784dd79e | ||
|
|
bc95b6f598 | ||
|
|
985a09c73d | ||
|
|
15793fb84f | ||
|
|
f0d42129aa | ||
|
|
83af8cc541 | ||
|
|
62f2953515 | ||
|
|
7b66094f56 | ||
|
|
a6c7169033 | ||
|
|
c8c596f37e | ||
|
|
fb552640b6 | ||
|
|
ed210cdf44 | ||
|
|
dcff8389b3 | ||
|
|
9bb1bc5682 | ||
|
|
16f2a8fb81 | ||
|
|
c517169e94 | ||
|
|
e9ac13bcda | ||
|
|
78ae517871 | ||
|
|
ed45c42c9e | ||
|
|
aab7842a76 | ||
|
|
79bda5c482 | ||
|
|
68bc67685f | ||
|
|
e463f4b4e5 | ||
|
|
1a867ddf9c | ||
|
|
7e43110f74 | ||
|
|
abcca5ea84 | ||
|
|
74822fca16 | ||
|
|
8401dfcc1a | ||
|
|
c4bbd0b8e2 | ||
|
|
6b2f3cfa74 | ||
|
|
d9bf7c3ccd | ||
|
|
ad18fb9854 | ||
|
|
bc82203364 | ||
|
|
9bfce3156e | ||
|
|
f7362094d3 | ||
|
|
f1aece75ae | ||
|
|
60dd3cb004 | ||
|
|
d031ae65bf | ||
|
|
a1fb62ff82 | ||
|
|
46e6c8f2db | ||
|
|
905d3c98a6 | ||
|
|
b08836de50 | ||
|
|
cf1f2a8674 | ||
|
|
16464646a9 | ||
|
|
ba015cf44e | ||
|
|
3837635f2c | ||
|
|
95c5ca81b2 | ||
|
|
bbb7e4cea8 | ||
|
|
15eb10ac68 | ||
|
|
4c846c712d | ||
|
|
4a82fd442d | ||
|
|
b3c9ff8419 | ||
|
|
fc6fd98a62 | ||
|
|
6304328548 | ||
|
|
86867fe678 | ||
|
|
54349a1c31 | ||
|
|
54f810b6b0 |
26
.github/ISSUE_TEMPLATE/bug.yml
vendored
26
.github/ISSUE_TEMPLATE/bug.yml
vendored
@@ -1,11 +1,17 @@
|
||||
name: Bug Report / Сообщение об ошибке
|
||||
name: The program crashes, hangs, certain function does not work / Программа падает, зависает, отдельная функция не работает
|
||||
description: File a bug report / Сообщить об ошибке в программе
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**USE THIS FORM ONLY FOR BUGS**
|
||||
### Carefully read all the text IN FULL. Take this seriously.
|
||||
### Use this form only for software bug reports! The website does not open? That's likely NOT a bug, do NOT report it here! You have a question regarding the program? That's not a bug either!
|
||||
#### If in doubt, [use NTC.party forum](https://ntc.party/c/community-software/goodbyedpi).
|
||||
### Внимательно прочитайте ВЕСЬ текст ниже. Отнеситесь к этому со всей ответственностью.
|
||||
### Используйте эту форму только для сообщений об ошибках в программе! Неоткрывающиеся сайты таковыми не являются, вопросы по программе к ошибкам не относятся.
|
||||
#### Если у вас есть сомнения, [воспользуйтесь форумом NTC.party](https://ntc.party/c/community-software/goodbyedpi).
|
||||
|
||||
GoodbyeDPI does not guarantee to work with your ISP for every blocked website or at all. If GoodbyeDPI can't unblock some or any websites, this is most likely not a software bug, and you should not report it here.
|
||||
|
||||
Please only report software bugs, such as:
|
||||
@@ -13,12 +19,13 @@ body:
|
||||
* incorrect network packet handling
|
||||
* antivirus incompatibility
|
||||
* DNS redirection problems
|
||||
* other software
|
||||
* memory leaks
|
||||
* other software issues
|
||||
|
||||
Please make sure to check other opened and closed issues, it could be your bug has been reported already.
|
||||
For questions, or if in doubt, [use NTC.party forum](https://ntc.party/c/community-software/goodbyedpi).
|
||||
|
||||
**ИСПОЛЬЗУЙТЕ ЭТУ ФОРМУ ТОЛЬКО ДЛЯ БАГОВ**
|
||||
### ИСПОЛЬЗУЙТЕ ЭТУ ФОРМУ ТОЛЬКО ДЛЯ БАГОВ! Веб-сайт не открывается? Это, скорее всего, не баг, не сообщайте сюда!
|
||||
GoodbyeDPI не гарантирует ни 100% работу с вашим провайдером, ни работу с каждым заблокированным сайтом. Если GoodbyeDPI не разблокирует доступ к некоторым или всем веб-сайтам, вероятнее всего, это не программная ошибка, и не стоит о ней сообщать здесь.
|
||||
|
||||
Пожалуйста, сообщайте только об ошибках в программе, таких как:
|
||||
@@ -26,10 +33,21 @@ body:
|
||||
* некорректная обработка сетевых пакетов
|
||||
* несовместимость с антивирусами
|
||||
* проблемы с перенаправлением DNS
|
||||
* утечки памяти
|
||||
* другие ошибки в программе
|
||||
|
||||
Также посмотрите другие открытые и закрытые баги. Возможно, ошибка уже обсуждалась или исправлена.
|
||||
Для вопросов, а также в случае сомнений в определении бага, обращайтесь [на форум NTC.party](https://ntc.party/c/community-software/goodbyedpi).
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: CAPTCHA
|
||||
description: Confirm that you have read the text above / Подтвердите, что вы прочитали текст выше
|
||||
options:
|
||||
- label: I understand I could be banned from the repository if I misusing issue section not for posting bugs, but for question or 'broken website' report. / Я понимаю, что меня могут заблокировать в репозитории, если я буду использовать раздел issue не для сообщений об ошибках, а для вопросов или сообщении о «неработающем веб-сайте».
|
||||
required: true
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: os
|
||||
attributes:
|
||||
|
||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
8
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,5 +1,13 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: The program worked yesterday but not today / Программа работала вчера, но перестала работать сегодня
|
||||
url: https://ntc.party/c/community-software/goodbyedpi/8
|
||||
about: Visit support community forum, people will certainly help you! / Посетите форум поддержки, где сообщество вам поможет!
|
||||
|
||||
- name: Сertain website is still unreachable / Отдельный веб-сайт всё ещё недоступен
|
||||
url: https://ntc.party/c/community-software/goodbyedpi/8
|
||||
about: That could be solved with community support! / Проблема будет решена силами сообщества!
|
||||
|
||||
- name: Questions about the program / Вопросы по програме
|
||||
url: https://ntc.party/c/community-software/goodbyedpi/8
|
||||
about: Please ask and answer questions on forum / Пожалуйста, задавайте вопросы только на форуме
|
||||
|
||||
13
.github/ISSUE_TEMPLATE/feature.yml
vendored
13
.github/ISSUE_TEMPLATE/feature.yml
vendored
@@ -1,12 +1,19 @@
|
||||
name: Feature request / Предложить новую функциональность
|
||||
name: Feature request / Предложить новую функциональность
|
||||
description: Suggest an idea or function for this project / Предложить новую идею или функциональность в программе
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
If you think of a great function or circumvention method which is missing from the program, go ahead and suggest it here.
|
||||
Если вы придумали новую функцию или метод обхода, которого еще нет в программе, напишите о нем подробнее здесь.
|
||||
If you think of a great function or circumvention method which is missing from the program, go ahead and suggest it here. But first make sure to search exiting tickets.
|
||||
Если вы придумали новую функцию или метод обхода, которого еще нет в программе, напишите о нем подробнее здесь. Но сначала убедитесь с помощью поиска, что такого запроса еще не было.
|
||||
- type: checkboxes
|
||||
id: ensure
|
||||
attributes:
|
||||
label: I've made sure there's no existing feature request / Я убедился, что такой функциональности еще никто не предлагал
|
||||
options:
|
||||
- label: I've made sure there's no existing feature request / Я убедился, что такой функциональности еще никто не предлагал
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
|
||||
23
.github/workflows/build.yml
vendored
23
.github/workflows/build.yml
vendored
@@ -4,24 +4,27 @@ on:
|
||||
push:
|
||||
paths:
|
||||
- 'src/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'src/**'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
WINDIVERT_URL: https://www.reqrypt.org/download/WinDivert-2.2.0-A.zip
|
||||
WINDIVERT_NAME: WinDivert-2.2.0-A.zip
|
||||
WINDIVERT_BASENAME: WinDivert-2.2.0-A
|
||||
WINDIVERT_SHA256: 2a7630aac0914746fbc565ac862fa096e3e54233883ac52d17c83107496b7a7f
|
||||
WINDIVERT_URL: https://reqrypt.org/download/WinDivert-2.2.0-D.zip
|
||||
WINDIVERT_NAME: WinDivert-2.2.0-D.zip
|
||||
WINDIVERT_BASENAME: WinDivert-2.2.0-D
|
||||
WINDIVERT_SHA256: 1d461cfdfa7ba88ebcfbb3603b71b703e9f72aba8aeff99a75ce293e6f89d2ba
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Declare short commit variable
|
||||
id: vars
|
||||
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
|
||||
run: >
|
||||
@@ -31,7 +34,7 @@ jobs:
|
||||
|
||||
- name: Download WinDivert from cache
|
||||
id: windivert-cache
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env. WINDIVERT_NAME }}
|
||||
key: ${{ env. WINDIVERT_SHA256 }}
|
||||
@@ -49,14 +52,14 @@ jobs:
|
||||
run: >
|
||||
cd src && make clean &&
|
||||
make CPREFIX=x86_64-w64-mingw32- BIT64=1 WINDIVERTHEADERS=../${{ env.WINDIVERT_BASENAME }}/include WINDIVERTLIBS=../${{ env.WINDIVERT_BASENAME }}/x64 -j4
|
||||
|
||||
|
||||
- name: Prepare x86_64 directory
|
||||
run: |
|
||||
mkdir 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
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: goodbyedpi_x86_64_${{ steps.vars.outputs.sha_short }}
|
||||
path: goodbyedpi_x86_64_${{ steps.vars.outputs.sha_short }}
|
||||
@@ -72,7 +75,7 @@ jobs:
|
||||
cp src/goodbyedpi.exe ${{ env.WINDIVERT_BASENAME }}/x86/*.{dll,sys} goodbyedpi_x86_${{ steps.vars.outputs.sha_short }}
|
||||
|
||||
- name: Upload output file x86
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: goodbyedpi_x86_${{ steps.vars.outputs.sha_short }}
|
||||
path: goodbyedpi_x86_${{ steps.vars.outputs.sha_short }}
|
||||
|
||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.o
|
||||
*.exe
|
||||
43
README.md
43
README.md
@@ -19,9 +19,12 @@ If it works — congratulations! You can use it as-is or configure further.
|
||||
|
||||
Download [latest version from Releases page](https://github.com/ValdikSS/GoodbyeDPI/releases) and run.
|
||||
|
||||
## Supported arguments
|
||||
To get relevant information about your version of the program, use the -h (--help) argument at startup.
|
||||
```
|
||||
Usage: goodbyedpi.exe [OPTION...]
|
||||
-p block passive DPI
|
||||
-q block QUIC/HTTP3
|
||||
-r replace Host with hoSt
|
||||
-s remove space between host header and its value
|
||||
-m mix Host header case (test.com -> tEsT.cOm)
|
||||
@@ -43,6 +46,7 @@ Usage: goodbyedpi.exe [OPTION...]
|
||||
supplied text file (HTTP Host/TLS SNI).
|
||||
This option can be supplied multiple times.
|
||||
--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.
|
||||
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
|
||||
@@ -62,6 +66,17 @@ Usage: goodbyedpi.exe [OPTION...]
|
||||
--reverse-frag fragment (split) the packets just as --native-frag, but send them in the
|
||||
reversed order. Works with the websites which could not handle segmented
|
||||
HTTPS TLS ClientHello (because they receive the TCP flow "combined").
|
||||
--fake-from-hex <value> Load fake packets for Fake Request Mode from HEX values (like 1234abcDEF).
|
||||
This option can be supplied multiple times, in this case each fake packet
|
||||
would be sent on every request in the command line argument order.
|
||||
--fake-with-sni <value> Generate fake packets for Fake Request Mode with given SNI domain name.
|
||||
The packets mimic Mozilla Firefox 130 TLS ClientHello packet
|
||||
(with random generated fake SessionID, key shares and ECH grease).
|
||||
Can be supplied multiple times for multiple fake packets.
|
||||
--fake-gen <value> Generate random-filled fake packets for Fake Request Mode, value of them
|
||||
(up to 30).
|
||||
--fake-resend <value> Send each fake packet value number of times.
|
||||
Default: 1 (send each packet once).
|
||||
--max-payload [value] packets with TCP payload data more than [value] won't be processed.
|
||||
Use this option to reduce CPU usage by skipping huge amount of data
|
||||
(like file transfers) in already established sessions.
|
||||
@@ -76,10 +91,15 @@ LEGACY modesets:
|
||||
-4 -p -r -s (best speed)
|
||||
|
||||
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
|
||||
```
|
||||
-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.
|
||||
```
|
||||
## How to check
|
||||
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.
|
||||
|
||||
* **Chrome**: Settings → [Privacy and security](chrome://settings/security) → Use secure DNS → With: NextDNS
|
||||
@@ -87,7 +107,7 @@ To check if your ISP's DPI could be circumvented, first make sure that your prov
|
||||
|
||||
Then run the `goodbyedpi.exe` executable without any options. If it works — congratulations! You can use it as-is or configure further, for example by using `--blacklist` option if the list of blocked websites is known and available for your country.
|
||||
|
||||
If your provider intercepts DNS requests, you may want to use `--dns-addr` option to a public DNS resover running on non-standard port (such as Yandex DNS `77.88.8.8:1253`) or configure DNS over HTTPS/TLS using third-party applications.
|
||||
If your provider intercepts DNS requests, you may want to use `--dns-addr` option to a public DNS resolver running on non-standard port (such as Yandex DNS `77.88.8.8:1253`) or configure DNS over HTTPS/TLS using third-party applications.
|
||||
|
||||
Check the .cmd scripts and modify it according to your preference and network conditions.
|
||||
|
||||
@@ -134,18 +154,25 @@ Modify them according to your own needs.
|
||||
# Known issues
|
||||
|
||||
* Horribly outdated Windows 7 installations are not able to load WinDivert driver due to missing support for SHA256 digital signatures. Install KB3033929 [x86](https://www.microsoft.com/en-us/download/details.aspx?id=46078)/[x64](https://www.microsoft.com/en-us/download/details.aspx?id=46148), or better, update the whole system using Windows Update.
|
||||
* Intel/Qualcomm Killer network cards: `Advanced Stream Detect` in Killer Control Center is incompatible with GoodbyeDPI, [disable it](https://github.com/ValdikSS/GoodbyeDPI/issues/541#issuecomment-2296038239).
|
||||
* QUIK trading software [may interfere with GoodbyeDPI](https://github.com/ValdikSS/GoodbyeDPI/issues/677#issuecomment-2390595606). First start QUIK, then GoodbyeDPI.
|
||||
* ~~Some SSL/TLS stacks unable to process fragmented ClientHello packets, and HTTPS websites won't open. Bug: [#4](https://github.com/ValdikSS/GoodbyeDPI/issues/4), [#64](https://github.com/ValdikSS/GoodbyeDPI/issues/64).~~ Fragmentation issues are fixed in v0.1.7.
|
||||
* ~~ESET Antivirus is incompatible with WinDivert driver [#91](https://github.com/ValdikSS/GoodbyeDPI/issues/91). This is most probably antivirus bug, not WinDivert.~~
|
||||
|
||||
|
||||
# Similar projects
|
||||
|
||||
- **[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).
|
||||
- **[DPITunnel](https://github.com/zhenyolka/DPITunnel)** by @zhenyolka (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).
|
||||
- **[zapret](https://github.com/bol-van/zapret)** by @bol-van (for MacOS, Linux and Windows)
|
||||
- **[Green Tunnel](https://github.com/SadeghHayeri/GreenTunnel)** by @SadeghHayeri (for MacOS, Linux and Windows)
|
||||
- **[DPI Tunnel CLI](https://github.com/nomoresat/DPITunnel-cli)** by @zhenyolka (for Linux and routers)
|
||||
- **[DPI Tunnel for Android](https://github.com/nomoresat/DPITunnel-android)** by @zhenyolka (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-Platform](https://github.com/r3pr3ss10n/SpoofDPI-Platform)** by @r3pr3ss10n (for Android, macOS, Windows)
|
||||
- **[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/)** / **[ByeByeDPI](https://github.com/romanvht/ByeByeDPI/)** for Android (no root)
|
||||
- **[youtubeUnblock](https://github.com/Waujito/youtubeUnblock/)** by @Waujito (for OpenWRT/Entware routers and Linux)
|
||||
|
||||
# Kudos
|
||||
|
||||
|
||||
@@ -11,7 +11,12 @@ TARGET = goodbyedpi.exe
|
||||
#LIBS = -L$(WINDIVERTLIBS) -Wl,-Bstatic -lssp -Wl,-Bdynamic -lWinDivert -lws2_32
|
||||
LIBS = -L$(WINDIVERTLIBS) -lWinDivert -lws2_32 -l:libssp.a
|
||||
CC = $(CPREFIX)gcc
|
||||
|
||||
CCWINDRES = $(CPREFIX)windres
|
||||
ifeq (, $(shell which $(CPREFIX)windres))
|
||||
CCWINDRES = windres
|
||||
endif
|
||||
|
||||
CFLAGS = -std=c99 -pie -fPIE -pipe -I$(WINDIVERTHEADERS) -L$(WINDIVERTLIBS) \
|
||||
-O2 -D_FORTIFY_SOURCE=2 -fstack-protector \
|
||||
-Wall -Wextra -Wpedantic -Wformat=2 -Wformat-overflow=2 -Wformat-truncation=2 \
|
||||
@@ -19,10 +24,10 @@ CFLAGS = -std=c99 -pie -fPIE -pipe -I$(WINDIVERTHEADERS) -L$(WINDIVERTLIBS) \
|
||||
-Wnull-dereference -Warray-bounds=2 -Wimplicit-fallthrough=3 \
|
||||
-Wstringop-overflow=4 \
|
||||
-Wformat-signedness -Wstrict-overflow=2 -Wcast-align=strict \
|
||||
-Wfloat-equal -Wcast-align -Wsign-conversion -Wno-stringop-overflow -Wno-stringop-overread \
|
||||
-Wfloat-equal -Wcast-align -Wsign-conversion \
|
||||
#-fstack-protector-strong
|
||||
LDFLAGS = -fstack-protector -Wl,-O1,-pie,--dynamicbase,--nxcompat,--sort-common,--as-needed \
|
||||
-Wl,--image-base,0x140000000 -Wl,--disable-auto-image-base
|
||||
-Wl,--disable-auto-image-base
|
||||
|
||||
ifdef BIT64
|
||||
LDFLAGS += -Wl,--high-entropy-va -Wl,--pic-executable,-e,mainCRTStartup
|
||||
|
||||
@@ -70,8 +70,8 @@ int blackwhitelist_load_list(const char *filename) {
|
||||
line);
|
||||
continue;
|
||||
}
|
||||
if (strlen(line) < 3) {
|
||||
printf("WARNING: host %s is less than 3 bytes, skipping\n", line);
|
||||
if (strlen(line) < 2) {
|
||||
printf("WARNING: host %s is less than 2 characters, skipping\n", line);
|
||||
continue;
|
||||
}
|
||||
if (add_hostname(line))
|
||||
@@ -99,8 +99,7 @@ int blackwhitelist_check_hostname(const char *host_addr, size_t host_len) {
|
||||
|
||||
tokenized_host = strchr(current_host, '.');
|
||||
while (tokenized_host != NULL && tokenized_host < (current_host + HOST_MAXLEN)) {
|
||||
/* Search hostname only if there is next token */
|
||||
if (strchr(tokenized_host + 1, '.') && check_get_hostname(tokenized_host + 1))
|
||||
if (check_get_hostname(tokenized_host + 1))
|
||||
return TRUE;
|
||||
tokenized_host = strchr(tokenized_host + 1, '.');
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#define _CRT_RAND_S
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <in6addr.h>
|
||||
@@ -7,6 +9,15 @@
|
||||
#include "windivert.h"
|
||||
#include "goodbyedpi.h"
|
||||
|
||||
struct fake_t {
|
||||
const unsigned char* data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static struct fake_t *fakes[30] = {0};
|
||||
int fakes_count = 0;
|
||||
int fakes_resend = 1;
|
||||
|
||||
static const unsigned char fake_http_request[] = "GET / HTTP/1.1\r\nHost: www.w3.org\r\n"
|
||||
"User-Agent: curl/7.65.3\r\nAccept: */*\r\n"
|
||||
"Accept-Encoding: deflate, gzip, br\r\n\r\n";
|
||||
@@ -46,6 +57,91 @@ static const unsigned char fake_https_request[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
// Captured from Firefox 130.0.1
|
||||
static const unsigned char fake_clienthello_part0[] = { // 116 bytes
|
||||
// TLS 1.2 ClientHello header (DD for length placeholder)
|
||||
0x16, 0x03, 0x01, 0xDD, 0xDD, 0x01, 0x00, 0xDD, 0xDD, 0x03, 0x03,
|
||||
// Random bytes (AA for placeholder)
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
// Random Session ID
|
||||
0x20,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
// Cipher Suites
|
||||
0x00, 0x22, 0x13, 0x01, 0x13, 0x03, 0x13, 0x02, 0xC0, 0x2B, 0xC0, 0x2F, 0xCC, 0xA9, 0xCC, 0xA8,
|
||||
0xC0, 0x2C, 0xC0, 0x30, 0xC0, 0x0A, 0xC0, 0x09, 0xC0, 0x13, 0xC0, 0x14, 0x00, 0x9C, 0x00, 0x9D,
|
||||
0x00, 0x2F, 0x00, 0x35,
|
||||
// Compression Methods
|
||||
0x01, 0x00,
|
||||
// Extensions Length
|
||||
0xDD, 0xDD,
|
||||
};
|
||||
// SNI: 00 00 L1 L1 L2 L2 00 L3 L3 (sni)
|
||||
// L1 = L+5, L2 = L+3, L3 = L // 9 + L bytes
|
||||
static const unsigned char fake_clienthello_part1[] = { // 523 bytes
|
||||
// extended_master_secret
|
||||
0x00, 0x17, 0x00, 0x00,
|
||||
// renegotiation_info
|
||||
0xFF, 0x01, 0x00, 0x01, 0x00,
|
||||
// supported_groups
|
||||
0x00, 0x0A, 0x00, 0x0E,
|
||||
0x00, 0x0C, 0x00, 0x1D, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, 0x01, 0x00, 0x01, 0x01,
|
||||
// ex_point_formats
|
||||
0x00, 0x0B, 0x00, 0x02, 0x01, 0x00,
|
||||
// session_ticket
|
||||
0x00, 0x23, 0x00, 0x00,
|
||||
// ALPN
|
||||
0x00, 0x10, 0x00, 0x0E,
|
||||
0x00, 0x0C, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2F, 0x31, 0x2E, 0x31,
|
||||
// status_request
|
||||
0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
// delegated_credentials
|
||||
0x00, 0x22, 0x00, 0x0A, 0x00, 0x08, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, 0x03,
|
||||
// key_share
|
||||
0x00, 0x33, 0x00, 0x6B, 0x00, 0x69, 0x00, 0x1D, 0x00, 0x20,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0x00, 0x17, 0x00, 0x41, 0x04,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
// supported_versions
|
||||
0x00, 0x2B, 0x00, 0x05, 0x04, 0x03, 0x04, 0x03, 0x03,
|
||||
// signature_algorithms
|
||||
0x00, 0x0D, 0x00, 0x18, 0x00, 0x16, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x08, 0x04, 0x08, 0x05,
|
||||
0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x02, 0x03, 0x02, 0x01,
|
||||
// psk_key_exchange_modes
|
||||
0x00, 0x2D, 0x00, 0x02, 0x01, 0x01,
|
||||
// record_size_limit
|
||||
0x00, 0x1C, 0x00, 0x02, 0x40, 0x01,
|
||||
// encrypted_client_hello
|
||||
0xFE, 0x0D, 0x01, 0x19, 0x00, 0x00, 0x01, 0x00, 0x01, 0xAA, 0x00, 0x20,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0x00, 0xEF,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA
|
||||
};
|
||||
// JA4: t13d1715h2_5b57614c22b0_5c2c66f702b0
|
||||
// JA4_r: t13d1715h2_002f,0035,009c,009d,1301,1302,1303,c009,c00a,c013,c014,c02b,c02c,c02f,c030,cca8,cca9_0005,000a,000b,000d,0017,001c,0022,0023,002b,002d,0033,fe0d,ff01_0403,0503,0603,0804,0805,0806,0401,0501,0601,0203,0201
|
||||
// JA3 Fullstring: 771,4865-4867-4866-49195-49199-52393-52392-49196-49200-49162-49161-49171-49172-156-157-47-53,0-23-65281-10-11-35-16-5-34-51-43-13-45-28-65037,29-23-24-25-256-257,0
|
||||
// JA3: b5001237acdf006056b409cc433726b0
|
||||
|
||||
static int send_fake_data(const HANDLE w_filter,
|
||||
const PWINDIVERT_ADDRESS addr,
|
||||
const char *pkt,
|
||||
@@ -54,7 +150,8 @@ static int send_fake_data(const HANDLE w_filter,
|
||||
const BOOL is_https,
|
||||
const BYTE set_ttl,
|
||||
const BYTE set_checksum,
|
||||
const BYTE set_seq
|
||||
const BYTE set_seq,
|
||||
const struct fake_t *fake_data
|
||||
) {
|
||||
char packet_fake[MAX_PACKET_SIZE];
|
||||
WINDIVERT_ADDRESS addr_new;
|
||||
@@ -66,6 +163,10 @@ static int send_fake_data(const HANDLE w_filter,
|
||||
PWINDIVERT_TCPHDR ppTcpHdr;
|
||||
unsigned const char *fake_request_data = is_https ? fake_https_request : fake_http_request;
|
||||
UINT fake_request_size = is_https ? sizeof(fake_https_request) : sizeof(fake_http_request) - 1;
|
||||
if (fake_data) {
|
||||
fake_request_data = fake_data->data;
|
||||
fake_request_size = fake_data->size;
|
||||
}
|
||||
|
||||
memcpy(&addr_new, addr, sizeof(WINDIVERT_ADDRESS));
|
||||
memcpy(packet_fake, pkt, packetLen);
|
||||
@@ -148,22 +249,26 @@ static int send_fake_request(const HANDLE w_filter,
|
||||
const BOOL is_https,
|
||||
const BYTE set_ttl,
|
||||
const BYTE set_checksum,
|
||||
const BYTE set_seq
|
||||
const BYTE set_seq,
|
||||
const struct fake_t *fake_data
|
||||
) {
|
||||
if (set_ttl) {
|
||||
send_fake_data(w_filter, addr, pkt, packetLen,
|
||||
is_ipv6, is_https,
|
||||
set_ttl, FALSE, FALSE);
|
||||
set_ttl, FALSE, FALSE,
|
||||
fake_data);
|
||||
}
|
||||
if (set_checksum) {
|
||||
send_fake_data(w_filter, addr, pkt, packetLen,
|
||||
is_ipv6, is_https,
|
||||
FALSE, set_checksum, FALSE);
|
||||
FALSE, set_checksum, FALSE,
|
||||
fake_data);
|
||||
}
|
||||
if (set_seq) {
|
||||
send_fake_data(w_filter, addr, pkt, packetLen,
|
||||
is_ipv6, is_https,
|
||||
FALSE, FALSE, set_seq);
|
||||
FALSE, FALSE, set_seq,
|
||||
fake_data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -177,9 +282,18 @@ int send_fake_http_request(const HANDLE w_filter,
|
||||
const BYTE set_checksum,
|
||||
const BYTE set_seq
|
||||
) {
|
||||
return send_fake_request(w_filter, addr, pkt, packetLen,
|
||||
is_ipv6, FALSE,
|
||||
set_ttl, set_checksum, set_seq);
|
||||
int ret = 0;
|
||||
for (int i=0; i<fakes_count || i == 0; i++) {
|
||||
for (int j=0; j<fakes_resend; j++)
|
||||
if (send_fake_request(w_filter, addr, pkt, packetLen,
|
||||
is_ipv6, FALSE,
|
||||
set_ttl, set_checksum, set_seq,
|
||||
fakes[i]))
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int send_fake_https_request(const HANDLE w_filter,
|
||||
@@ -191,7 +305,137 @@ int send_fake_https_request(const HANDLE w_filter,
|
||||
const BYTE set_checksum,
|
||||
const BYTE set_seq
|
||||
) {
|
||||
return send_fake_request(w_filter, addr, pkt, packetLen,
|
||||
int ret = 0;
|
||||
for (int i=0; i<fakes_count || i == 0; i++) {
|
||||
for (int j=0; j<fakes_resend; j++)
|
||||
if (send_fake_request(w_filter, addr, pkt, packetLen,
|
||||
is_ipv6, TRUE,
|
||||
set_ttl, set_checksum, set_seq);
|
||||
set_ttl, set_checksum, set_seq,
|
||||
fakes[i]))
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fake_add(const unsigned char *data, size_t size) {
|
||||
struct fake_t *fake = malloc(sizeof(struct fake_t));
|
||||
fake->size = size;
|
||||
fake->data = data;
|
||||
|
||||
for (size_t k = 0; k <= sizeof(fakes) / sizeof(*fakes); k++) {
|
||||
if (!fakes[k]) {
|
||||
fakes[k] = fake;
|
||||
fakes_count++;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
int fake_load_from_hex(const char *data) {
|
||||
size_t len = strlen(data);
|
||||
if (len < 2 || len % 2 || len > (1420 * 2))
|
||||
return 1;
|
||||
|
||||
unsigned char *finaldata = calloc((len + 2) / 2, 1);
|
||||
|
||||
for (size_t i = 0; i<len - 1; i+=2) {
|
||||
char num1 = data[i];
|
||||
char num2 = data[i+1];
|
||||
debug("Current num1: %X, num2: %X\n", num1, num2);
|
||||
unsigned char finalchar = 0;
|
||||
char curchar = num1;
|
||||
|
||||
for (int j=0; j<=1; j++) {
|
||||
if (curchar >= '0' && curchar <= '9')
|
||||
curchar -= '0';
|
||||
else if (curchar >= 'a' && curchar <= 'f')
|
||||
curchar -= 'a' - 0xA;
|
||||
else if (curchar >= 'A' && curchar <= 'F')
|
||||
curchar -= 'A' - 0xA;
|
||||
else
|
||||
return 2; // incorrect character, not a hex data
|
||||
|
||||
if (!j) {
|
||||
num1 = curchar;
|
||||
curchar = num2;
|
||||
continue;
|
||||
}
|
||||
num2 = curchar;
|
||||
}
|
||||
debug("Processed num1: %X, num2: %X\n", num1, num2);
|
||||
finalchar = (num1 << 4) | num2;
|
||||
debug("Final char: %X\n", finalchar);
|
||||
finaldata[i/2] = finalchar;
|
||||
}
|
||||
|
||||
return fake_add(finaldata, len / 2);
|
||||
}
|
||||
|
||||
int fake_load_random(unsigned int count, unsigned int maxsize) {
|
||||
if (count < 1 || count > sizeof(fakes) / sizeof(*fakes))
|
||||
return 1;
|
||||
|
||||
unsigned int random = 0;
|
||||
|
||||
for (unsigned int i=0; i<count; i++) {
|
||||
unsigned int len = 0;
|
||||
if (rand_s(&len))
|
||||
return 1;
|
||||
len = 8 + (len % maxsize);
|
||||
|
||||
unsigned char *data = calloc(len, 1);
|
||||
for (unsigned int j=0; j<len; j++) {
|
||||
rand_s(&random);
|
||||
data[j] = random % 0xFF;
|
||||
}
|
||||
if (fake_add(data, len))
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void set_uint16be(unsigned char *buffer, int offset, int value) {
|
||||
buffer[offset] = (value >> 8) & 0xFF;
|
||||
buffer[offset + 1] = value & 0xFF;
|
||||
}
|
||||
|
||||
int fake_load_from_sni(const char *domain_name) {
|
||||
if (!domain_name) {
|
||||
return 1; // just extra safeguard against NPE
|
||||
}
|
||||
// calculate sizes
|
||||
const int name_size = strlen(domain_name);
|
||||
const int part0_size = sizeof(fake_clienthello_part0);
|
||||
const int part1_size = sizeof(fake_clienthello_part1);
|
||||
const int sni_head_size = 9;
|
||||
const int packet_size = part0_size + part1_size + sni_head_size + name_size;
|
||||
// allocate memory
|
||||
unsigned char *packet = malloc(packet_size);
|
||||
// copy major parts of packet
|
||||
memcpy(packet, fake_clienthello_part0, part0_size);
|
||||
memcpy(&packet[part0_size + sni_head_size + name_size], fake_clienthello_part1, part1_size);
|
||||
// replace placeholders with random generated values
|
||||
unsigned int random = 0;
|
||||
for (int i = 0; i < packet_size; i++) {
|
||||
if (packet[i] == 0xAA) {
|
||||
rand_s(&random);
|
||||
packet[i] = random & 0xFF;
|
||||
}
|
||||
}
|
||||
// write size fields into packet
|
||||
set_uint16be(packet, 0x0003, packet_size - 5);
|
||||
set_uint16be(packet, 0x0007, packet_size - 9);
|
||||
set_uint16be(packet, 0x0072, packet_size - 116);
|
||||
// write SNI extension
|
||||
set_uint16be(packet, part0_size + 0, 0x0000);
|
||||
set_uint16be(packet, part0_size + 2, name_size + 5);
|
||||
set_uint16be(packet, part0_size + 4, name_size + 3);
|
||||
packet[part0_size + 6] = 0x00;
|
||||
set_uint16be(packet, part0_size + 7, name_size);
|
||||
memcpy(&packet[part0_size + sni_head_size], domain_name, name_size);
|
||||
// add packet to fakes
|
||||
return fake_add(packet, packet_size);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
extern int fakes_count;
|
||||
extern int fakes_resend;
|
||||
int send_fake_http_request(const HANDLE w_filter,
|
||||
const PWINDIVERT_ADDRESS addr,
|
||||
const char *pkt,
|
||||
@@ -16,3 +18,6 @@ int send_fake_https_request(const HANDLE w_filter,
|
||||
const BYTE set_checksum,
|
||||
const BYTE set_seq
|
||||
);
|
||||
int fake_load_from_hex(const char *data);
|
||||
int fake_load_from_sni(const char *domain_name);
|
||||
int fake_load_random(unsigned int count, unsigned int maxsize);
|
||||
|
||||
289
src/goodbyedpi.c
289
src/goodbyedpi.c
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
@@ -23,7 +24,7 @@
|
||||
// My mingw installation does not load inet_pton definition for some reason
|
||||
WINSOCK_API_LINKAGE INT WSAAPI inet_pton(INT Family, LPCSTR pStringBuf, PVOID pAddr);
|
||||
|
||||
#define GOODBYEDPI_VERSION "v0.2.2"
|
||||
#define GOODBYEDPI_VERSION "v0.2.3rc3"
|
||||
|
||||
#define die() do { sleep(20); exit(EXIT_FAILURE); } while (0)
|
||||
|
||||
@@ -78,9 +79,12 @@ WINSOCK_API_LINKAGE INT WSAAPI inet_pton(INT Family, LPCSTR pStringBuf, PVOID pA
|
||||
"(tcp.DstPort == 80 or tcp.DstPort == 443) and tcp.Ack and " \
|
||||
"(" 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 " \
|
||||
"!impostor and !loopback and " \
|
||||
"((ip.Id <= 0xF and ip.Id >= 0x0) " IPID_TEMPLATE ") and " \
|
||||
"(true " IPID_TEMPLATE ") and " \
|
||||
"(tcp.SrcPort == 443 or tcp.SrcPort == 80) and tcp.Rst and " \
|
||||
DIVERT_NO_LOCALNETSv4_SRC
|
||||
|
||||
@@ -131,6 +135,18 @@ WINSOCK_API_LINKAGE INT WSAAPI inet_pton(INT Family, LPCSTR pStringBuf, PVOID pA
|
||||
ttl_of_fake_packet, do_wrong_chksum, do_wrong_seq); \
|
||||
} while (0)
|
||||
|
||||
enum ERROR_CODE{
|
||||
ERROR_DEFAULT = 1,
|
||||
ERROR_PORT_BOUNDS,
|
||||
ERROR_DNS_V4_ADDR,
|
||||
ERROR_DNS_V6_ADDR,
|
||||
ERROR_DNS_V4_PORT,
|
||||
ERROR_DNS_V6_PORT,
|
||||
ERROR_BLACKLIST_LOAD,
|
||||
ERROR_AUTOTTL,
|
||||
ERROR_ATOUSI,
|
||||
ERROR_AUTOB
|
||||
};
|
||||
|
||||
static int running_from_service = 0;
|
||||
static int exiting = 0;
|
||||
@@ -162,6 +178,7 @@ static struct option long_options[] = {
|
||||
{"dns-verb", no_argument, 0, 'v' },
|
||||
{"blacklist", required_argument, 0, 'b' },
|
||||
{"allow-no-sni",no_argument, 0, ']' },
|
||||
{"frag-by-sni", no_argument, 0, '>' },
|
||||
{"ip-id", required_argument, 0, 'i' },
|
||||
{"set-ttl", required_argument, 0, '$' },
|
||||
{"min-ttl", required_argument, 0, '[' },
|
||||
@@ -171,7 +188,11 @@ static struct option long_options[] = {
|
||||
{"native-frag", no_argument, 0, '*' },
|
||||
{"reverse-frag",no_argument, 0, '(' },
|
||||
{"max-payload", optional_argument, 0, '|' },
|
||||
{"openvpn", no_argument, 0, '#' },
|
||||
{"fake-from-hex", required_argument, 0, 'u' },
|
||||
{"fake-with-sni", required_argument, 0, '}' },
|
||||
{"fake-gen", required_argument, 0, 'j' },
|
||||
{"fake-resend", required_argument, 0, 't' },
|
||||
{"debug-exit", optional_argument, 0, 'x' },
|
||||
{0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -218,7 +239,10 @@ static void add_ip_id_str(int id) {
|
||||
static void add_maxpayloadsize_str(unsigned short maxpayload) {
|
||||
char *newstr;
|
||||
/* 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 : true)";
|
||||
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);
|
||||
|
||||
sprintf(addfilter, maxpayloadsize_str, maxpayload);
|
||||
@@ -264,7 +288,7 @@ unsigned short int atousi(const char *str, const char *msg) {
|
||||
|
||||
if(res > limitValue) {
|
||||
puts(msg);
|
||||
exit(EXIT_FAILURE);
|
||||
exit(ERROR_ATOUSI);
|
||||
}
|
||||
return (unsigned short int)res;
|
||||
}
|
||||
@@ -277,7 +301,7 @@ BYTE atoub(const char *str, const char *msg) {
|
||||
|
||||
if(res > limitValue) {
|
||||
puts(msg);
|
||||
exit(EXIT_FAILURE);
|
||||
exit(ERROR_AUTOB);
|
||||
}
|
||||
return (BYTE)res;
|
||||
}
|
||||
@@ -294,10 +318,27 @@ static HANDLE init(char *filter, UINT64 flags) {
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, errorcode, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&errormessage, 0, NULL);
|
||||
printf("Error opening filter: %s", errormessage);
|
||||
printf("Error opening filter: %d %s\n", errorcode, errormessage);
|
||||
LocalFree(errormessage);
|
||||
if (errorcode == 577)
|
||||
printf("Windows Server 2016 systems must have secure boot disabled to be "
|
||||
if (errorcode == 2)
|
||||
printf("The driver files WinDivert32.sys or WinDivert64.sys were not found.\n");
|
||||
else if (errorcode == 654)
|
||||
printf("An incompatible version of the WinDivert driver is currently loaded.\n"
|
||||
"Please unload it with the following commands ran as administrator:\n\n"
|
||||
"sc stop windivert\n"
|
||||
"sc delete windivert\n"
|
||||
"sc stop windivert14\n"
|
||||
"sc delete windivert14\n");
|
||||
else if (errorcode == 1275)
|
||||
printf("This error occurs for various reasons, including:\n"
|
||||
"the WinDivert driver is blocked by security software; or\n"
|
||||
"you are using a virtualization environment that does not support drivers.\n");
|
||||
else if (errorcode == 1753)
|
||||
printf("This error occurs when the Base Filtering Engine service has been disabled.\n"
|
||||
"Enable Base Filtering Engine service.\n");
|
||||
else if (errorcode == 577)
|
||||
printf("Could not load driver due to invalid digital signature.\n"
|
||||
"Windows Server 2016 systems must have secure boot disabled to be \n"
|
||||
"able to load WinDivert driver.\n"
|
||||
"Windows 7 systems must be up-to-date or at least have KB3033929 installed.\n"
|
||||
"https://www.microsoft.com/en-us/download/details.aspx?id=46078\n\n"
|
||||
@@ -434,16 +475,6 @@ static int extract_sni(const char *pktdata, unsigned int pktlen,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static inline int is_openvpn_handshake(const char *pktdata, unsigned int pktlen) {
|
||||
/*
|
||||
* 0x38 is P_CONTROL_HARD_RESET_CLIENT_V2 + peer_id(0),
|
||||
* 0x50 is P_CONTROL_HARD_RESET_CLIENT_V3 + peer_id(0)
|
||||
*/
|
||||
return pktlen >= 16
|
||||
&& ntohs(((uint16_t*)pktdata)[0]) == pktlen - 2
|
||||
&& (pktdata[2] == '\x38' || pktdata[2] == '\x50');
|
||||
}
|
||||
|
||||
static inline void change_window_size(const PWINDIVERT_TCPHDR ppTcpHdr, unsigned int size) {
|
||||
if (size >= 1 && size <= 0xFFFFu) {
|
||||
ppTcpHdr->Window = htons((u_short)size);
|
||||
@@ -485,7 +516,7 @@ static void send_native_fragment(HANDLE w_filter, WINDIVERT_ADDRESS addr,
|
||||
PWINDIVERT_TCPHDR ppTcpHdr,
|
||||
unsigned int fragment_size, int step) {
|
||||
char packet_bak[MAX_PACKET_SIZE];
|
||||
memcpy(&packet_bak, packet, packetLen);
|
||||
memcpy(packet_bak, packet, packetLen);
|
||||
UINT orig_packetLen = packetLen;
|
||||
|
||||
if (fragment_size >= packet_dataLen) {
|
||||
@@ -542,7 +573,7 @@ static void send_native_fragment(HANDLE w_filter, WINDIVERT_ADDRESS addr,
|
||||
packetLen,
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -552,9 +583,9 @@ int main(int argc, char *argv[]) {
|
||||
ipv4_tcp, ipv4_tcp_data, ipv4_udp_data,
|
||||
ipv6_tcp, ipv6_tcp_data, ipv6_udp_data
|
||||
} packet_type;
|
||||
bool debug_exit = false;
|
||||
int i, should_reinject, should_recalc_checksum = 0;
|
||||
int sni_ok = 0;
|
||||
int openvpn_handshake = 0;
|
||||
int opt;
|
||||
int packet_v4, packet_v6;
|
||||
HANDLE w_filter = NULL;
|
||||
@@ -570,7 +601,8 @@ int main(int argc, char *argv[]) {
|
||||
conntrack_info_t dns_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_nowait = 0,
|
||||
do_fragment_https = 0, do_host = 0,
|
||||
@@ -580,8 +612,8 @@ int main(int argc, char *argv[]) {
|
||||
do_dnsv4_redirect = 0, do_dnsv6_redirect = 0,
|
||||
do_dns_verb = 0, do_tcp_verb = 0, do_blacklist = 0,
|
||||
do_allow_no_sni = 0,
|
||||
do_fragment_by_sni = 0,
|
||||
do_fake_packet = 0,
|
||||
do_openvpn = 0,
|
||||
do_auto_ttl = 0,
|
||||
do_wrong_chksum = 0,
|
||||
do_wrong_seq = 0,
|
||||
@@ -642,17 +674,19 @@ int main(int argc, char *argv[]) {
|
||||
);
|
||||
|
||||
if (argc == 1) {
|
||||
/* enable mode -5 by default */
|
||||
/* enable mode -9 by default */
|
||||
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_auto_ttl = 1;
|
||||
do_wrong_chksum = 1;
|
||||
do_wrong_seq = 1;
|
||||
do_block_quic = 1;
|
||||
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) {
|
||||
case '1':
|
||||
do_passivedpi = do_host = do_host_removespace \
|
||||
@@ -693,9 +727,27 @@ int main(int argc, char *argv[]) {
|
||||
do_wrong_seq = 1;
|
||||
max_payload_size = 1200;
|
||||
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':
|
||||
do_passivedpi = 1;
|
||||
break;
|
||||
case 'q':
|
||||
do_block_quic = 1;
|
||||
break;
|
||||
case 'r':
|
||||
do_host = 1;
|
||||
break;
|
||||
@@ -735,7 +787,7 @@ int main(int argc, char *argv[]) {
|
||||
i = atoi(optarg);
|
||||
if (i <= 0 || i > 65535) {
|
||||
printf("Port parameter error!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
exit(ERROR_PORT_BOUNDS);
|
||||
}
|
||||
if (i != 80 && i != 443)
|
||||
add_filter_str(IPPROTO_TCP, i);
|
||||
@@ -754,14 +806,14 @@ int main(int argc, char *argv[]) {
|
||||
do_dnsv4_redirect = 1;
|
||||
if (inet_pton(AF_INET, optarg, &dnsv4_addr) != 1) {
|
||||
puts("DNS address parameter error!");
|
||||
exit(EXIT_FAILURE);
|
||||
exit(ERROR_DNS_V4_ADDR);
|
||||
}
|
||||
add_filter_str(IPPROTO_UDP, 53);
|
||||
flush_dns_cache();
|
||||
break;
|
||||
}
|
||||
puts("DNS address parameter error!");
|
||||
exit(EXIT_FAILURE);
|
||||
exit(ERROR_DNS_V4_ADDR);
|
||||
break;
|
||||
case '!': // --dnsv6-addr
|
||||
if ((inet_pton(AF_INET6, optarg, dns_temp_addr.s6_addr) == 1) &&
|
||||
@@ -770,21 +822,21 @@ int main(int argc, char *argv[]) {
|
||||
do_dnsv6_redirect = 1;
|
||||
if (inet_pton(AF_INET6, optarg, dnsv6_addr.s6_addr) != 1) {
|
||||
puts("DNS address parameter error!");
|
||||
exit(EXIT_FAILURE);
|
||||
exit(ERROR_DNS_V6_ADDR);
|
||||
}
|
||||
add_filter_str(IPPROTO_UDP, 53);
|
||||
flush_dns_cache();
|
||||
break;
|
||||
}
|
||||
puts("DNS address parameter error!");
|
||||
exit(EXIT_FAILURE);
|
||||
exit(ERROR_DNS_V6_ADDR);
|
||||
break;
|
||||
case 'g': // --dns-port
|
||||
if (!do_dnsv4_redirect) {
|
||||
puts("--dns-port should be used with --dns-addr!\n"
|
||||
"Make sure you use --dns-addr and pass it before "
|
||||
"--dns-port");
|
||||
exit(EXIT_FAILURE);
|
||||
exit(ERROR_DNS_V4_PORT);
|
||||
}
|
||||
dnsv4_port = atousi(optarg, "DNS port parameter error!");
|
||||
if (dnsv4_port != 53) {
|
||||
@@ -797,7 +849,7 @@ int main(int argc, char *argv[]) {
|
||||
puts("--dnsv6-port should be used with --dnsv6-addr!\n"
|
||||
"Make sure you use --dnsv6-addr and pass it before "
|
||||
"--dnsv6-port");
|
||||
exit(EXIT_FAILURE);
|
||||
exit(ERROR_DNS_V6_PORT);
|
||||
}
|
||||
dnsv6_port = atousi(optarg, "DNS port parameter error!");
|
||||
if (dnsv6_port != 53) {
|
||||
@@ -813,12 +865,15 @@ int main(int argc, char *argv[]) {
|
||||
do_blacklist = 1;
|
||||
if (!blackwhitelist_load_list(optarg)) {
|
||||
printf("Can't load blacklist from file!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
exit(ERROR_BLACKLIST_LOAD);
|
||||
}
|
||||
break;
|
||||
case ']': // --allow-no-sni
|
||||
do_allow_no_sni = 1;
|
||||
break;
|
||||
case '>': // --frag-by-sni
|
||||
do_fragment_by_sni = 1;
|
||||
break;
|
||||
case '$': // --set-ttl
|
||||
do_auto_ttl = auto_ttl_1 = auto_ttl_2 = auto_ttl_max = 0;
|
||||
do_fake_packet = 1;
|
||||
@@ -844,13 +899,13 @@ int main(int argc, char *argv[]) {
|
||||
autottl_current = strtok(NULL, "-");
|
||||
if (!autottl_current) {
|
||||
puts("Set Auto TTL parameter error!");
|
||||
exit(EXIT_FAILURE);
|
||||
exit(ERROR_AUTOTTL);
|
||||
}
|
||||
auto_ttl_2 = atoub(autottl_current, "Set Auto TTL parameter error!");
|
||||
autottl_current = strtok(NULL, "-");
|
||||
if (!autottl_current) {
|
||||
puts("Set Auto TTL parameter error!");
|
||||
exit(EXIT_FAILURE);
|
||||
exit(ERROR_AUTOTTL);
|
||||
}
|
||||
auto_ttl_max = atoub(autottl_current, "Set Auto TTL parameter error!");
|
||||
}
|
||||
@@ -862,9 +917,6 @@ int main(int argc, char *argv[]) {
|
||||
free(autottl_copy);
|
||||
}
|
||||
break;
|
||||
case '#': // --openvpn
|
||||
do_openvpn = 1;
|
||||
break;
|
||||
case '%': // --wrong-chksum
|
||||
do_fake_packet = 1;
|
||||
do_wrong_chksum = 1;
|
||||
@@ -892,9 +944,37 @@ int main(int argc, char *argv[]) {
|
||||
else
|
||||
max_payload_size = 1200;
|
||||
break;
|
||||
case 'u': // --fake-from-hex
|
||||
if (fake_load_from_hex(optarg)) {
|
||||
printf("WARNING: bad fake HEX value %s\n", optarg);
|
||||
}
|
||||
break;
|
||||
case '}': // --fake-with-sni
|
||||
if (fake_load_from_sni(optarg)) {
|
||||
printf("WARNING: bad domain name for SNI: %s\n", optarg);
|
||||
}
|
||||
break;
|
||||
case 'j': // --fake-gen
|
||||
if (fake_load_random(atoub(optarg, "Fake generator parameter error!"), 200)) {
|
||||
puts("WARNING: fake generator has failed!");
|
||||
}
|
||||
break;
|
||||
case 't': // --fake-resend
|
||||
fakes_resend = atoub(optarg, "Fake resend parameter error!");
|
||||
if (fakes_resend == 1)
|
||||
puts("WARNING: fake-resend is 1, no resending is in place!");
|
||||
else if (!fakes_resend)
|
||||
puts("WARNING: fake-resend is 0, fake packet mode is disabled!");
|
||||
else if (fakes_resend > 100)
|
||||
puts("WARNING: fake-resend value is a little too high, don't you think?");
|
||||
break;
|
||||
case 'x': // --debug-exit
|
||||
debug_exit = true;
|
||||
break;
|
||||
default:
|
||||
puts("Usage: goodbyedpi.exe [OPTION...]\n"
|
||||
" -p block passive DPI\n"
|
||||
" -q block QUIC/HTTP3\n"
|
||||
" -r replace Host with hoSt\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"
|
||||
@@ -915,6 +995,7 @@ int main(int argc, char *argv[]) {
|
||||
" supplied text file (HTTP Host/TLS SNI).\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"
|
||||
" --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"
|
||||
" 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"
|
||||
@@ -935,12 +1016,22 @@ int main(int argc, char *argv[]) {
|
||||
" --reverse-frag fragment (split) the packets just as --native-frag, but send them in the\n"
|
||||
" reversed order. Works with the websites which could not handle segmented\n"
|
||||
" HTTPS TLS ClientHello (because they receive the TCP flow \"combined\").\n"
|
||||
" --fake-from-hex <value> Load fake packets for Fake Request Mode from HEX values (like 1234abcDEF).\n"
|
||||
" This option can be supplied multiple times, in this case each fake packet\n"
|
||||
" would be sent on every request in the command line argument order.\n"
|
||||
" --fake-with-sni <value> Generate fake packets for Fake Request Mode with given SNI domain name.\n"
|
||||
" The packets mimic Mozilla Firefox 130 TLS ClientHello packet\n"
|
||||
" (with random generated fake SessionID, key shares and ECH grease).\n"
|
||||
" Can be supplied multiple times for multiple fake packets.\n"
|
||||
" --fake-gen <value> Generate random-filled fake packets for Fake Request Mode, value of them\n"
|
||||
" (up to 30).\n"
|
||||
" --fake-resend <value> Send each fake packet value number of times.\n"
|
||||
" Default: 1 (send each packet once).\n"
|
||||
" --max-payload [value] packets with TCP payload data more than [value] won't be processed.\n"
|
||||
" Use this option to reduce CPU usage by skipping huge amount of data\n"
|
||||
" (like file transfers) in already established sessions.\n"
|
||||
" May skip some huge HTTP requests from being processed.\n"
|
||||
" Default (if set): --max-payload 1200.\n"
|
||||
" --openvpn Detect OpenVPN TCP and fragment/send fake packet.\n"
|
||||
"\n");
|
||||
puts("LEGACY modesets:\n"
|
||||
" -1 -p -r -s -f 2 -k 2 -n -e 2 (most compatible mode)\n"
|
||||
@@ -949,9 +1040,14 @@ int main(int argc, char *argv[]) {
|
||||
" -4 -p -r -s (best speed)"
|
||||
"\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"
|
||||
" -6 -f 2 -e 2 --wrong-seq --reverse-frag --max-payload\n");
|
||||
exit(EXIT_FAILURE);
|
||||
" -5 -f 2 -e 2 --auto-ttl --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(ERROR_DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -971,47 +1067,52 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
printf("Block passive: %d\n" /* 1 */
|
||||
"Block QUIC/HTTP3: %d\n" /* 1 */
|
||||
"Fragment HTTP: %u\n" /* 2 */
|
||||
"Fragment persistent HTTP: %u\n" /* 3 */
|
||||
"Fragment HTTPS: %u\n" /* 4 */
|
||||
"Native fragmentation (splitting): %d\n" /* 5 */
|
||||
"Fragments sending in reverse: %d\n" /* 6 */
|
||||
"hoSt: %d\n" /* 7 */
|
||||
"Host no space: %d\n" /* 8 */
|
||||
"Additional space: %d\n" /* 9 */
|
||||
"Mix Host: %d\n" /* 10 */
|
||||
"HTTP AllPorts: %d\n" /* 11 */
|
||||
"HTTP Persistent Nowait: %d\n" /* 12 */
|
||||
"DNS redirect: %d\n" /* 13 */
|
||||
"DNSv6 redirect: %d\n" /* 14 */
|
||||
"Allow missing SNI: %d\n" /* 15 */
|
||||
"Fake requests, TTL: %s (fixed: %hu, auto: %hu-%hu-%hu, min distance: %hu)\n" /* 16 */
|
||||
"Fake requests, wrong checksum: %d\n" /* 17 */
|
||||
"Fake requests, wrong SEQ/ACK: %d\n" /* 18 */
|
||||
"Max payload size: %hu\n" /* 19 */
|
||||
"OpenVPN: %d\n", /* 20 */
|
||||
do_passivedpi, /* 1 */
|
||||
"Fragment by SNI: %u\n" /* 5 */
|
||||
"Native fragmentation (splitting): %d\n" /* 6 */
|
||||
"Fragments sending in reverse: %d\n" /* 7 */
|
||||
"hoSt: %d\n" /* 8 */
|
||||
"Host no space: %d\n" /* 9 */
|
||||
"Additional space: %d\n" /* 10 */
|
||||
"Mix Host: %d\n" /* 11 */
|
||||
"HTTP AllPorts: %d\n" /* 12 */
|
||||
"HTTP Persistent Nowait: %d\n" /* 13 */
|
||||
"DNS redirect: %d\n" /* 14 */
|
||||
"DNSv6 redirect: %d\n" /* 15 */
|
||||
"Allow missing SNI: %d\n" /* 16 */
|
||||
"Fake requests, TTL: %s (fixed: %hu, auto: %hu-%hu-%hu, min distance: %hu)\n" /* 17 */
|
||||
"Fake requests, wrong checksum: %d\n" /* 18 */
|
||||
"Fake requests, wrong SEQ/ACK: %d\n" /* 19 */
|
||||
"Fake requests, custom payloads: %d\n" /* 20 */
|
||||
"Fake requests, resend: %d\n" /* 21 */
|
||||
"Max payload size: %hu\n", /* 22 */
|
||||
do_passivedpi, do_block_quic, /* 1 */
|
||||
(do_fragment_http ? http_fragment_size : 0), /* 2 */
|
||||
(do_fragment_http_persistent ? http_fragment_size : 0),/* 3 */
|
||||
(do_fragment_https ? https_fragment_size : 0), /* 4 */
|
||||
do_native_frag, /* 5 */
|
||||
do_reverse_frag, /* 6 */
|
||||
do_host, /* 7 */
|
||||
do_host_removespace, /* 8 */
|
||||
do_additional_space, /* 9 */
|
||||
do_host_mixedcase, /* 10 */
|
||||
do_http_allports, /* 11 */
|
||||
do_fragment_http_persistent_nowait, /* 12 */
|
||||
do_dnsv4_redirect, /* 13 */
|
||||
do_dnsv6_redirect, /* 14 */
|
||||
do_allow_no_sni, /* 15 */
|
||||
do_auto_ttl ? "auto" : (do_fake_packet ? "fixed" : "disabled"), /* 16 */
|
||||
do_fragment_by_sni, /* 5 */
|
||||
do_native_frag, /* 6 */
|
||||
do_reverse_frag, /* 7 */
|
||||
do_host, /* 8 */
|
||||
do_host_removespace, /* 9 */
|
||||
do_additional_space, /* 10 */
|
||||
do_host_mixedcase, /* 11 */
|
||||
do_http_allports, /* 12 */
|
||||
do_fragment_http_persistent_nowait, /* 13 */
|
||||
do_dnsv4_redirect, /* 14 */
|
||||
do_dnsv6_redirect, /* 15 */
|
||||
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,
|
||||
do_auto_ttl ? auto_ttl_max : 0, ttl_min_nhops,
|
||||
do_wrong_chksum, /* 17 */
|
||||
do_wrong_seq, /* 18 */
|
||||
max_payload_size, /* 19 */
|
||||
do_openvpn /* 20 */
|
||||
do_wrong_chksum, /* 18 */
|
||||
do_wrong_seq, /* 19 */
|
||||
fakes_count, /* 20 */
|
||||
fakes_resend, /* 21 */
|
||||
max_payload_size /* 22 */
|
||||
);
|
||||
|
||||
if (do_fragment_http && http_fragment_size > 2 && !do_native_frag) {
|
||||
@@ -1042,6 +1143,15 @@ int main(int argc, char *argv[]) {
|
||||
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
|
||||
* active DPI circumvention
|
||||
@@ -1055,7 +1165,10 @@ int main(int argc, char *argv[]) {
|
||||
if (filters[i] == NULL)
|
||||
die();
|
||||
}
|
||||
|
||||
if (debug_exit) {
|
||||
printf("Debug Exit\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
printf("Filter activated, GoodbyeDPI is now running!\n");
|
||||
signal(SIGINT, sigint_handler);
|
||||
|
||||
@@ -1065,6 +1178,7 @@ int main(int argc, char *argv[]) {
|
||||
packetLen);
|
||||
should_reinject = 1;
|
||||
should_recalc_checksum = 0;
|
||||
sni_ok = 0;
|
||||
|
||||
ppIpHdr = (PWINDIVERT_IPHDR)NULL;
|
||||
ppIpV6Hdr = (PWINDIVERT_IPV6HDR)NULL;
|
||||
@@ -1138,7 +1252,7 @@ int main(int argc, char *argv[]) {
|
||||
*/
|
||||
else if (addr.Outbound &&
|
||||
((do_fragment_https ? packet_dataLen == https_fragment_size : 0) ||
|
||||
packet_dataLen >= 16) &&
|
||||
packet_dataLen > 16) &&
|
||||
ppTcpHdr->DstPort != htons(80) &&
|
||||
(do_fake_packet || do_native_frag)
|
||||
)
|
||||
@@ -1148,11 +1262,9 @@ int main(int argc, char *argv[]) {
|
||||
* But if the packet is more than 2 bytes, check ClientHello byte.
|
||||
*/
|
||||
if ((packet_dataLen == 2 && memcmp(packet_data, "\x16\x03", 2) == 0) ||
|
||||
(packet_dataLen >= 3 && memcmp(packet_data, "\x16\x03\x01", 3) == 0) ||
|
||||
(do_openvpn && (openvpn_handshake = is_openvpn_handshake(packet_data, packet_dataLen)))
|
||||
)
|
||||
(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,
|
||||
&host_addr, &host_len);
|
||||
}
|
||||
@@ -1161,7 +1273,6 @@ int main(int argc, char *argv[]) {
|
||||
blackwhitelist_check_hostname(host_addr, host_len)
|
||||
) ||
|
||||
(do_blacklist && !sni_ok && do_allow_no_sni) ||
|
||||
(do_openvpn && openvpn_handshake) ||
|
||||
(!do_blacklist)
|
||||
)
|
||||
{
|
||||
@@ -1169,7 +1280,7 @@ int main(int argc, char *argv[]) {
|
||||
char lsni[HOST_MAXLEN + 1] = {0};
|
||||
extract_sni(packet_data, packet_dataLen,
|
||||
&host_addr, &host_len);
|
||||
memcpy(&lsni, host_addr, host_len);
|
||||
memcpy(lsni, host_addr, host_len);
|
||||
printf("Blocked HTTPS website SNI: %s\n", lsni);
|
||||
#endif
|
||||
if (do_fake_packet) {
|
||||
@@ -1204,7 +1315,7 @@ int main(int argc, char *argv[]) {
|
||||
host_len = hdr_value_len;
|
||||
#ifdef DEBUG
|
||||
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);
|
||||
#endif
|
||||
|
||||
@@ -1306,7 +1417,11 @@ int main(int argc, char *argv[]) {
|
||||
current_fragment_size = http_fragment_size;
|
||||
}
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user