Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43db0955de | ||
|
|
9d289f096e | ||
|
|
c95be6eb91 | ||
|
|
9a6254869d | ||
|
|
7a3850c7d3 | ||
|
|
4da80c8372 | ||
|
|
642f1ca477 | ||
|
|
b1f139f2ea | ||
|
|
88e1b75dd5 | ||
|
|
31d75606bc | ||
|
|
26463ae30f | ||
|
|
6580068112 | ||
|
|
88107def37 | ||
|
|
f4b9d8de40 | ||
|
|
b7210d167e | ||
|
|
f57692b7f2 | ||
|
|
6f8e0827a7 | ||
|
|
96b23abaf0 |
67
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
name: Bug Report / Сообщение об ошибке
|
||||
description: File a bug report / Сообщить об ошибке в программе
|
||||
labels: [ bug ]
|
||||
assignees: dovecoteescapee
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
### If you have trouble with specific websites or or can't configure the app, please use the [discussions section](https://github.com/dovecoteescapee/ByeDPIAndroid/discussions) to discuss it. This template is only for reporting bugs in the ByeDPI program.
|
||||
### Если у вас не работают какие-то сайты или не получается настроить приложение, используйте [раздел дискуссий](https://github.com/dovecoteescapee/ByeDPIAndroid/discussions) для обсуждения этого. Этот шаблон предназначен только для сообщений об ошибках в программе ByeDPI.
|
||||
- type: textarea
|
||||
id: bug
|
||||
attributes:
|
||||
label: Describe the bug / Описание ошибки
|
||||
description: A clear and concise description of what the bug is / Четкое и краткое описание ошибки
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduce
|
||||
attributes:
|
||||
label: To Reproduce / Как воспроизвести
|
||||
description: Steps to reproduce the behavior / Шаги для воспроизведения проблемы
|
||||
value: |
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: Expected behavior / Ожидаемое поведение
|
||||
description: A clear and concise description of what you expected to happen / Четкое и краткое описание ожидаемого поведения
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: screenshots
|
||||
attributes:
|
||||
label: Screenshots / Скриншоты
|
||||
description: If applicable, add screenshots to help explain your problem / При необходимости добавьте скриншоты, чтобы объяснить вашу проблему
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: Environment / Окружение
|
||||
description: Please complete the following information / Пожалуйста, заполните следующую информацию
|
||||
value: |
|
||||
**Smartphone / Смартфон:**
|
||||
- Device: [e.g. Pixel Fold, Samsung Galaxy S24]
|
||||
- Android version: [e.g. 10]
|
||||
- ByeDPI version: [e.g. 1.0.2]
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional context / Дополнительная информация
|
||||
description: Add any other context about the problem here / Добавьте любую другую информацию о проблеме здесь
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Before you submit / Прежде чем отправить
|
||||
options:
|
||||
- label: I have searched the open and closed issues for duplicates / Я искал(а) открытые и закрытые задачи на предмет дубликатов
|
||||
required: true
|
||||
- label: This is not a question, feature request, or general feedback / Это не вопрос, предложение новой функциональности или общий отзыв
|
||||
required: true
|
||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Questions about the program on Github / Вопросы по програме на Github
|
||||
url: https://github.com/dovecoteescapee/ByeDPIAndroid/discussions
|
||||
about: Please do not ask questions in the issue tracker / Пожалуйста, не задавайте вопросы в трекере задач
|
||||
- name: Questions about the program on NTC.party / Вопросы по програме на NTC.party
|
||||
url: https://ntc.party/c/community-software/byedpi/39
|
||||
about: Please do not ask questions in the issue tracker / Пожалуйста, не задавайте вопросы в трекере задач
|
||||
35
.github/ISSUE_TEMPLATE/feature.yml
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
name: Feature request / Предложить новую функциональность
|
||||
description: Suggest an idea for this project / Предложить идею для проекта
|
||||
labels: [ enhancement ]
|
||||
assignees: dovecoteescapee
|
||||
body:
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: What problem does your proposal solve? / Какую проблему решает ваше предложение?
|
||||
description: A clear and concise description of what the problem is / Четкое и краткое описание проблемы
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: solution
|
||||
attributes:
|
||||
label: Describe the solution you'd like / Опишите решение, которое вы предлагаете
|
||||
description: A clear and concise description of what you want to happen / Четкое и краткое описание того, что вы хотите, чтобы произошло
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Describe alternatives you've considered / Опишите альтернативные варианты, которые вы рассматривали
|
||||
description: A clear and concise description of any alternative solutions or features you've considered / Четкое и краткое описание любых альтернативных решений или функций, которые вы рассматривали
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: checklist
|
||||
attributes:
|
||||
label: Before you submit / Прежде чем отправить
|
||||
options:
|
||||
- label: I have searched the open and closed issues for duplicates / Я искал(а) открытые и закрытые задачи на предмет дубликатов
|
||||
required: true
|
||||
- label: I have verified that this feature does not already exist / Я убедился(ась), что эта функция еще не существует
|
||||
required: true
|
||||
1
.gitignore
vendored
@ -14,3 +14,4 @@
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
local.properties
|
||||
/app/src/main/jniLibs
|
||||
|
||||
8
.gitmodules
vendored
@ -1,6 +1,6 @@
|
||||
[submodule "app/libs/tun2socks"]
|
||||
path = app/libs/tun2socks
|
||||
url = https://github.com/dovecoteescapee/tun2socks.git
|
||||
[submodule "app/src/main/cpp/byedpi"]
|
||||
[submodule "hev-socks5-tunnel"]
|
||||
path = app/src/main/jni/hev-socks5-tunnel
|
||||
url = https://github.com/heiher/hev-socks5-tunnel.git
|
||||
[submodule "byedpi"]
|
||||
path = app/src/main/cpp/byedpi
|
||||
url = https://github.com/hufrea/byedpi.git
|
||||
|
||||
@ -2,7 +2,11 @@
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/libs/tun2socks" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/src/main/cpp/byedpi" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/src/main/jni/hev-socks5-tunnel" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/src/main/jni/hev-socks5-tunnel/src/core" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/src/main/jni/hev-socks5-tunnel/third-part/hev-task-system" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/src/main/jni/hev-socks5-tunnel/third-part/lwip" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/app/src/main/jni/hev-socks5-tunnel/third-part/yaml" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
53
README-ru.md
@ -3,44 +3,43 @@
|
||||
[English](README.md) | **Русский**
|
||||
|
||||
<div style="text-align: center;">
|
||||
<img src=".github/images/logo.svg" width="100%" height="200px">
|
||||
<img alt="Логотип ByeDPI" src=".github/images/logo.svg" width="100%" height="200px">
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
Приложение для Android, которое запускает локальный VPN-сервис для обхода DPI (Deep Packet Inspection) и цензуры.
|
||||
|
||||
Приложение локально запускает [ByeDPI](https://github.com/hufrea/byedpi) и перенаправляет весь трафик через него.
|
||||
Приложение локально запускает SOCKS5-прокси [ByeDPI](https://github.com/hufrea/byedpi) и перенаправляет весь трафик через него.
|
||||
|
||||
## Установка
|
||||
|
||||
[<img src="https://github.com/machiav3lli/oandbackupx/blob/034b226cea5c1b30eb4f6a6f313e4dadcbb0ece4/badge_github.png"
|
||||
alt="Скачать с GitHub"
|
||||
height="80">](https://github.com/dovecoteescapee/ByeDPIAndroid/releases)
|
||||
[<img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png"
|
||||
alt="Скачать с IzzyOnDroid"
|
||||
height="80">](https://apt.izzysoft.de/fdroid/index/apk/io.github.dovecoteescapee.byedpi)
|
||||
|
||||
### Или используйте Obtainium
|
||||
|
||||
1. Установите [Obtainium](https://github.com/ImranR98/Obtainium?tab=readme-ov-file#installation)
|
||||
1. Установите [Obtainium](https://github.com/ImranR98/Obtainium/blob/main/README.md#installation)
|
||||
2. Добавьте приложение по URL:
|
||||
`https://github.com/dovecoteescapee/ByeDPIAndroid`
|
||||
|
||||
## Настройки
|
||||
|
||||
Для обхода некоторых блокировок может потребоваться изменить настройки. Подробнее о различных настройках можно прочитать в [документации ByeDPI](https://github.com/hufrea/byedpi#readme-ov-file).
|
||||
Для обхода некоторых блокировок может потребоваться изменить настройки. Подробнее о различных настройках можно прочитать в [документации ByeDPI](https://github.com/hufrea/byedpi/blob/v0.13/README.md).
|
||||
|
||||
## FAQ
|
||||
|
||||
### Это вирус?
|
||||
|
||||
Нет. [Обсуждение проблемы](https://github.com/dovecoteescapee/ByeDPIAndroid/issues/61).
|
||||
|
||||
### У меня не получается настроить. Что делать?
|
||||
|
||||
Вы можете попросить помощи в [discussion](https://github.com/dovecoteescapee/ByeDPIAndroid/discussions).
|
||||
|
||||
### Как получать обновления?
|
||||
### Приложение требует root-права?
|
||||
|
||||
Используйте [Obtainium](#или-используйте-obtainium).
|
||||
Нет. Все функции приложения работают без root-прав.
|
||||
|
||||
### Это VPN?
|
||||
|
||||
@ -50,20 +49,30 @@
|
||||
|
||||
Никакие. Приложения не отправляет никакие данные на удаленный сервер. Весь трафик обрабатывается на устройстве.
|
||||
|
||||
### Как использовать ByeDPI вместе с AdGuard?
|
||||
|
||||
1. Запустите ByeDPI в режиме прокси.
|
||||
2. Добавьте ByeDPI в исключения AdGuard на вкладке "Управление приложениями".
|
||||
3. В настройках AdGuard укажите прокси:
|
||||
|
||||
```plaintext
|
||||
Тип прокси: SOCKS5
|
||||
Хост: 127.0.0.1
|
||||
Порт: 1080 (по умолчанию)
|
||||
```
|
||||
|
||||
### А есть для других платформ?
|
||||
|
||||
Для Windows существует [GoodByeDPI](https://github.com/ValdikSS/GoodbyeDPI), а для Linux и macOS [zapret](https://github.com/bol-van/zapret). Также, вы можете использовать оригинальный [ByeDPI](https://github.com/hufrea/byedpi) для запуска аналогичного прокси на Windows, Linux или macOS.
|
||||
|
||||
[Другие аналоги](https://github.com/ValdikSS/GoodbyeDPI?tab=readme-ov-file#similar-projects)
|
||||
[Список аналогов](https://github.com/ValdikSS/GoodbyeDPI/blob/master/README.md#similar-projects)
|
||||
|
||||
### Что такое DPI?
|
||||
|
||||
DPI (Deep Packet Inspection) - это технология для анализа и фильтрации трафика. Она используется провайдерами и государственными органами для блокировки сайтов и сервисов.
|
||||
DPI (Deep Packet Inspection) - это технология для анализа и фильтрации трафика. Она используется провайдерами и государственными органами для блокировки сайтов и сервисов.
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [ByeDPI](https://github.com/hufrea/byedpi)
|
||||
- [Tun2Socks](https://github.com/xjasonlyu/tun2socks)
|
||||
- [hev-socks5-tunnel](https://github.com/heiher/hev-socks5-tunnel)
|
||||
|
||||
## Сборка
|
||||
|
||||
@ -72,22 +81,16 @@ DPI (Deep Packet Inspection) - это технология для анализа
|
||||
1. JDK 8 или новее
|
||||
2. Android SDK
|
||||
3. Android NDK
|
||||
4. Go 1.22 или новее
|
||||
5. CMake 3.22.1 или новее
|
||||
4. CMake 3.22.1 или новее
|
||||
|
||||
Сборка приложения:
|
||||
|
||||
1. Установите gomobile:
|
||||
```bash
|
||||
go install golang.org/x/mobile/cmd/gomobile@latest
|
||||
gomobile init
|
||||
```
|
||||
2. Клонируйте репозиторий с подмодулями:
|
||||
1. Клонируйте репозиторий с подмодулями:
|
||||
```bash
|
||||
git clone --recurse-submodules
|
||||
```
|
||||
3. Запустите скрипт сборки из корня репозитория:
|
||||
2. Запустите скрипт сборки из корня репозитория:
|
||||
```bash
|
||||
./gradlew assembleRelease`
|
||||
```
|
||||
4. APK будет лежать в `app/build/outputs/apk/release/`
|
||||
3. APK будет лежать в `app/build/outputs/apk/release/`
|
||||
|
||||
52
README.md
@ -3,58 +3,68 @@
|
||||
**English** | [Русский](README-ru.md)
|
||||
|
||||
<div style="text-align: center;">
|
||||
<img src=".github/images/logo.svg" width="100%" height="200px">
|
||||
<img alt="ByeDPI logo" src=".github/images/logo.svg" width="100%" height="200px">
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
Android application that runs a local VPN service to bypass DPI (Deep Packet Inspection) and censorship.
|
||||
|
||||
The application locally runs [ByeDPI](https://github.com/hufrea/byedpi) and redirects all traffic through it.
|
||||
|
||||
This application runs a SOCKS5 proxy [ByeDPI](https://github.com/hufrea/byedpi) and redirects all traffic through it.
|
||||
|
||||
## Installation
|
||||
|
||||
[<img src="https://github.com/machiav3lli/oandbackupx/blob/034b226cea5c1b30eb4f6a6f313e4dadcbb0ece4/badge_github.png"
|
||||
alt="Get it on GitHub"
|
||||
height="80">](https://github.com/dovecoteescapee/ByeDPIAndroid/releases)
|
||||
[<img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png"
|
||||
alt="Get it on IzzyOnDroid"
|
||||
height="80">](https://apt.izzysoft.de/fdroid/index/apk/io.github.dovecoteescapee.byedpi)
|
||||
|
||||
### Or use Obtainium
|
||||
|
||||
1. Install [Obtainium](https://github.com/ImranR98/Obtainium?tab=readme-ov-file#installation)
|
||||
1. Install [Obtainium](https://github.com/ImranR98/Obtainium/blob/main/README.md#installation)
|
||||
2. Add the app by URL:
|
||||
`https://github.com/dovecoteescapee/ByeDPIAndroid`
|
||||
|
||||
## Settings
|
||||
|
||||
To bypass some blocks, you may need to change the settings. More about the various settings can be found in the [ByeDPI documentation](https://github.com/hufrea/byedpi#readme-ov-file).
|
||||
To bypass some blocks, you may need to change the settings. More about the various settings can be found in the [ByeDPI documentation](https://github.com/hufrea/byedpi/blob/v0.13/README.md).
|
||||
|
||||
## FAQ
|
||||
|
||||
### Is this a virus?
|
||||
|
||||
No. [Discussion of the problem](https://github.com/dovecoteescapee/ByeDPIAndroid/issues/61).
|
||||
|
||||
### I can't configure it. What to do?
|
||||
|
||||
You can ask for help in [discussion](https://github.com/dovecoteescapee/ByeDPIAndroid/discussions).
|
||||
|
||||
### How to get updates?
|
||||
### Does the application require root access?
|
||||
|
||||
Use [Obtainium](#or-use-obtainium).
|
||||
No. All application features work without root.
|
||||
|
||||
### Is this a VPN?
|
||||
|
||||
No. The application uses the VPN mode on Android to redirect traffic, but does not send anything to a remote server. It does not encrypt traffic and does not hide your IP address.
|
||||
|
||||
### How to use ByeDPI with AdGuard?
|
||||
|
||||
1. Run ByeDPI in proxy mode.
|
||||
2. Add ByeDPI to AdGuard exceptions on the "App management" tab.
|
||||
3. In AdGuard settings, specify the proxy:
|
||||
|
||||
```plaintext
|
||||
Proxy type: SOCKS5
|
||||
Proxy host: 127.0.0.1
|
||||
Proxy port: 1080 (default)
|
||||
```
|
||||
|
||||
### What data does the application collect?
|
||||
|
||||
None. The application does not send any data to a remote server. All traffic is processed on the device.
|
||||
|
||||
### Are there any for other platforms?
|
||||
|
||||
For Windows, there is [GoodByeDPI](https://github.com/ValdikSS/GoodbyeDPI), and for Linux and macOS [zapret](https://github.com/bol-van/zapret). Also, you can use the original [ByeDPI](https://github.com/hufrea/byedpi) to run a similar proxy on Windows, Linux, or macOS.
|
||||
|
||||
[Other similar projects](https://github.com/ValdikSS/GoodbyeDPI?tab=readme-ov-file#similar-projects)
|
||||
[Similar projects](https://github.com/ValdikSS/GoodbyeDPI/blob/master/README.md#similar-projects))
|
||||
|
||||
### What is DPI?
|
||||
|
||||
@ -63,7 +73,7 @@ DPI (Deep Packet Inspection) is a technology for analyzing and filtering traffic
|
||||
## Dependencies
|
||||
|
||||
- [ByeDPI](https://github.com/hufrea/byedpi)
|
||||
- [Tun2Socks](https://github.com/xjasonlyu/tun2socks)
|
||||
- [hev-socks5-tunnel](https://github.com/heiher/hev-socks5-tunnel)
|
||||
|
||||
## Building
|
||||
|
||||
@ -72,22 +82,16 @@ For building the application, you need:
|
||||
1. JDK 8 or later
|
||||
2. Android SDK
|
||||
3. Android NDK
|
||||
4. Go 1.22 or later
|
||||
5. CMake 3.22.1 or later
|
||||
4. CMake 3.22.1 or later
|
||||
|
||||
To build the application:
|
||||
|
||||
1. Install gomobile:
|
||||
```bash
|
||||
go install golang.org/x/mobile/cmd/gomobile@latest
|
||||
gomobile init
|
||||
```
|
||||
2. Clone the repository with submodules:
|
||||
1. Clone the repository with submodules:
|
||||
```bash
|
||||
git clone --recurse-submodules
|
||||
```
|
||||
3. Run the build script from the root of the repository:
|
||||
2. Run the build script from the root of the repository:
|
||||
```bash
|
||||
./gradlew assembleRelease
|
||||
```
|
||||
4. The APK will be in `app/build/outputs/apk/release/`
|
||||
3. The APK will be in `app/build/outputs/apk/release/`
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import com.android.build.gradle.internal.tasks.factory.dependsOn
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
@ -13,10 +11,17 @@ android {
|
||||
applicationId = "io.github.dovecoteescapee.byedpi"
|
||||
minSdk = 21
|
||||
targetSdk = 34
|
||||
versionCode = 7
|
||||
versionName = "1.0.2"
|
||||
versionCode = 10
|
||||
versionName = "1.2.0"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
ndk {
|
||||
abiFilters.add("armeabi-v7a")
|
||||
abiFilters.add("arm64-v8a")
|
||||
abiFilters.add("x86")
|
||||
abiFilters.add("x86_64")
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
@ -50,18 +55,23 @@ android {
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
}
|
||||
|
||||
// https://android.izzysoft.de/articles/named/iod-scan-apkchecks?lang=en#blobs
|
||||
dependenciesInfo {
|
||||
// Disables dependency metadata when building APKs.
|
||||
includeInApk = false
|
||||
// Disables dependency metadata when building Android App Bundles.
|
||||
includeInBundle = false
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(files("libs/tun2socks.aar"))
|
||||
|
||||
implementation("androidx.fragment:fragment-ktx:1.8.2")
|
||||
implementation("androidx.core:core-ktx:1.13.1")
|
||||
implementation("androidx.appcompat:appcompat:1.7.0")
|
||||
implementation("androidx.preference:preference-ktx:1.2.1")
|
||||
implementation("com.takisoft.preferencex:preferencex:1.1.0")
|
||||
implementation("com.google.android.material:material:1.12.0")
|
||||
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.4")
|
||||
implementation("androidx.lifecycle:lifecycle-service:2.8.4")
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
@ -69,75 +79,25 @@ dependencies {
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
|
||||
}
|
||||
|
||||
abstract class BaseTun2SocksTask : DefaultTask() {
|
||||
@get:InputDirectory
|
||||
val tun2socksDir: File
|
||||
get() = project.file("libs/tun2socks")
|
||||
|
||||
@get:OutputFile
|
||||
val tun2socksOutput: File
|
||||
get() = project.file("libs/tun2socks.aar")
|
||||
|
||||
@Internal
|
||||
protected fun isUpToDate(): Boolean {
|
||||
if (tun2socksOutput.exists()) {
|
||||
val lastModified = tun2socksOutput.lastModified()
|
||||
return !tun2socksDir.walkTopDown().any {
|
||||
it.isFile && it.lastModified() > lastModified
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
abstract class GetGomobileBind : BaseTun2SocksTask() {
|
||||
@TaskAction
|
||||
fun getBind() {
|
||||
if (isUpToDate()) {
|
||||
logger.lifecycle("No changes detected, skipping getBind.")
|
||||
return
|
||||
}
|
||||
|
||||
project.exec {
|
||||
workingDir = tun2socksDir
|
||||
|
||||
commandLine("go", "get", "golang.org/x/mobile/bind")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class BuildTun2Socks : BaseTun2SocksTask() {
|
||||
@TaskAction
|
||||
fun buildTun2Socks() {
|
||||
if (isUpToDate()) {
|
||||
logger.lifecycle("No changes detected, skipping buildTun2Socks.")
|
||||
return
|
||||
}
|
||||
|
||||
project.exec {
|
||||
workingDir = tun2socksDir
|
||||
|
||||
commandLine(
|
||||
"gomobile", "bind",
|
||||
"-target", "android",
|
||||
"-androidapi", "21",
|
||||
"-o", tun2socksOutput,
|
||||
"-trimpath",
|
||||
"./engine"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val getGomobileBind = tasks.register<GetGomobileBind>("getGomobileBind") {
|
||||
tasks.register<Exec>("runNdkBuild") {
|
||||
group = "build"
|
||||
description = "Get gomobile bind for compiling tun2socks"
|
||||
|
||||
val ndkDir = android.ndkDirectory
|
||||
executable = if (System.getProperty("os.name").startsWith("Windows", ignoreCase = true)) {
|
||||
"$ndkDir\\ndk-build.cmd"
|
||||
} else {
|
||||
"$ndkDir/ndk-build"
|
||||
}
|
||||
setArgs(listOf(
|
||||
"NDK_PROJECT_PATH=build/intermediates/ndkBuild",
|
||||
"NDK_LIBS_OUT=src/main/jniLibs",
|
||||
"APP_BUILD_SCRIPT=src/main/jni/Android.mk",
|
||||
"NDK_APPLICATION_MK=src/main/jni/Application.mk"
|
||||
))
|
||||
|
||||
println("Command: $commandLine")
|
||||
}
|
||||
|
||||
val buildTun2Socks = tasks.register<BuildTun2Socks>("buildTun2Socks") {
|
||||
group = "build"
|
||||
description = "Build tun2socks for Android"
|
||||
dependsOn(getGomobileBind)
|
||||
}
|
||||
|
||||
tasks.preBuild.dependsOn(buildTun2Socks)
|
||||
tasks.preBuild {
|
||||
dependsOn("runNdkBuild")
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
Subproject commit e083dafcf534d85e7fce86b3d48ee5c7a63c604e
|
||||
@ -6,12 +6,18 @@
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
|
||||
<uses-feature android:name="android.software.leanback"
|
||||
android:required="false" />
|
||||
<uses-feature android:name="android.hardware.touchscreen"
|
||||
android:required="false" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:banner="@mipmap/ic_launcher_foreground"
|
||||
android:logo="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
@ -25,6 +31,7 @@
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
|
||||
@ -1,53 +1,14 @@
|
||||
# For more information about using CMake with Android Studio, read the
|
||||
# documentation: https://d.android.com/studio/projects/add-native-code.html.
|
||||
# For more examples on how to use CMake, see https://github.com/android/ndk-samples.
|
||||
|
||||
# Sets the minimum CMake version required for this project.
|
||||
cmake_minimum_required(VERSION 3.22.1)
|
||||
|
||||
# Declares the project name. The project name can be accessed via ${ PROJECT_NAME},
|
||||
# Since this is the top level CMakeLists.txt, the project name is also accessible
|
||||
# with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level
|
||||
# build script scope).
|
||||
project("byedpi")
|
||||
project(byedpi_native)
|
||||
|
||||
# Creates and names a library, sets it as either STATIC
|
||||
# or SHARED, and provides the relative paths to its source code.
|
||||
# You can define multiple libraries, and CMake builds them for you.
|
||||
# Gradle automatically packages shared libraries with your APK.
|
||||
#
|
||||
# In this top level CMakeLists.txt, ${CMAKE_PROJECT_NAME} is used to define
|
||||
# the target library name; in the sub-module's CMakeLists.txt, ${PROJECT_NAME}
|
||||
# is preferred for the same purpose.
|
||||
#
|
||||
# In order to load a library into your app from Java/Kotlin, you must call
|
||||
# System.loadLibrary() and pass the name of the library defined here;
|
||||
# for GameActivity/NativeActivity derived applications, the same library name must be
|
||||
# used in the AndroidManifest.xml file.
|
||||
add_library(${CMAKE_PROJECT_NAME} SHARED
|
||||
# List C/C++ source files with relative paths to this CMakeLists.txt.
|
||||
byedpi/conev.c
|
||||
byedpi/desync.c
|
||||
byedpi/extend.c
|
||||
byedpi/packets.c
|
||||
byedpi/proxy.c
|
||||
byedpi/main.c
|
||||
byedpi/mpool.c
|
||||
native-lib.c
|
||||
utils.c
|
||||
)
|
||||
file(GLOB BYE_DPI_SRC byedpi/*.c)
|
||||
list(REMOVE_ITEM BYE_DPI_SRC ${CMAKE_CURRENT_SOURCE_DIR}/byedpi/win_service.c)
|
||||
|
||||
include_directories("byedpi")
|
||||
add_library(byedpi SHARED ${BYE_DPI_SRC} native-lib.c utils.c)
|
||||
target_include_directories(byedpi PRIVATE byedpi)
|
||||
|
||||
set(CMAKE_C_FLAGS "-std=c99 -O2 -D_XOPEN_SOURCE=500")
|
||||
target_compile_options(byedpi PRIVATE -std=c99 -O2 -D_XOPEN_SOURCE=500)
|
||||
target_compile_definitions(byedpi PRIVATE ANDROID_APP)
|
||||
|
||||
add_compile_definitions(ANDROID_APP)
|
||||
|
||||
# Specifies libraries CMake should link to your target library. You
|
||||
# can link libraries from various origins, such as libraries defined in this
|
||||
# build script, prebuilt third-party libraries, or Android system libraries.
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME}
|
||||
# List libraries link to the target library
|
||||
android
|
||||
log
|
||||
)
|
||||
target_link_libraries(byedpi PRIVATE android log)
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit dcf5ed727c996d0073a6cb95d5eec45a793d28a2
|
||||
Subproject commit 078842b084853bc30f33eaaec7acc510cf67e560
|
||||
@ -13,6 +13,11 @@ void clear_params(void);
|
||||
|
||||
char *ftob(const char *str, ssize_t *sl);
|
||||
|
||||
char *data_from_str(const char *str, ssize_t *size);
|
||||
|
||||
size_t parse_cform(char *buffer, size_t blen,
|
||||
const char *str, size_t slen);
|
||||
|
||||
struct mphdr *parse_hosts(char *buffer, size_t size);
|
||||
|
||||
int parse_offset(struct part *part, const char *str);
|
||||
|
||||
@ -12,11 +12,18 @@
|
||||
#include "utils.h"
|
||||
|
||||
const enum demode DESYNC_METHODS[] = {
|
||||
DESYNC_NONE,
|
||||
DESYNC_SPLIT,
|
||||
DESYNC_DISORDER,
|
||||
DESYNC_FAKE,
|
||||
DESYNC_OOB,
|
||||
DESYNC_NONE,
|
||||
DESYNC_SPLIT,
|
||||
DESYNC_DISORDER,
|
||||
DESYNC_FAKE,
|
||||
DESYNC_OOB,
|
||||
DESYNC_DISOOB,
|
||||
};
|
||||
|
||||
enum hosts_mode {
|
||||
HOSTS_DISABLE,
|
||||
HOSTS_BLACKLIST,
|
||||
HOSTS_WHITELIST,
|
||||
};
|
||||
|
||||
JNIEXPORT jint JNI_OnLoad(
|
||||
@ -75,14 +82,19 @@ Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniCreateSocket(
|
||||
jboolean split_at_host,
|
||||
jint fake_ttl,
|
||||
jstring fake_sni,
|
||||
jstring custom_oob_data,
|
||||
jbyte custom_oob_char,
|
||||
jboolean host_mixed_case,
|
||||
jboolean domain_mixed_case,
|
||||
jboolean host_remove_spaces,
|
||||
jboolean tls_record_split,
|
||||
jint tls_record_split_position,
|
||||
jboolean tls_record_split_at_sni) {
|
||||
|
||||
jboolean tls_record_split_at_sni,
|
||||
jint hosts_mode,
|
||||
jstring hosts,
|
||||
jboolean tfo,
|
||||
jint udp_fake_count,
|
||||
jboolean drop_sack,
|
||||
jint fake_offset) {
|
||||
struct sockaddr_ina s;
|
||||
|
||||
const char *address = (*env)->GetStringUTFChars(env, ip, 0);
|
||||
@ -98,6 +110,7 @@ Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniCreateSocket(
|
||||
params.max_open = max_connections;
|
||||
params.bfsize = buffer_size;
|
||||
params.resolve = !no_domain;
|
||||
params.tfo = tfo;
|
||||
|
||||
if (custom_ttl) {
|
||||
params.def_ttl = default_ttl;
|
||||
@ -112,6 +125,29 @@ Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniCreateSocket(
|
||||
}
|
||||
}
|
||||
|
||||
if (hosts_mode == HOSTS_WHITELIST) {
|
||||
struct desync_params *dp = add(
|
||||
(void *) ¶ms.dp,
|
||||
¶ms.dp_count,
|
||||
sizeof(struct desync_params)
|
||||
);
|
||||
if (!dp) {
|
||||
uniperror("add");
|
||||
reset_params();
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *str = (*env)->GetStringUTFChars(env, hosts, 0);
|
||||
dp->file_ptr = data_from_str(str, &dp->file_size);
|
||||
(*env)->ReleaseStringUTFChars(env, hosts, str);
|
||||
dp->hosts = parse_hosts(dp->file_ptr, dp->file_size);
|
||||
if (!dp->hosts) {
|
||||
perror("parse_hosts");
|
||||
clear_params();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
struct desync_params *dp = add(
|
||||
(void *) ¶ms.dp,
|
||||
¶ms.dp_count,
|
||||
@ -123,7 +159,21 @@ Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniCreateSocket(
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hosts_mode == HOSTS_BLACKLIST) {
|
||||
const char *str = (*env)->GetStringUTFChars(env, hosts, 0);
|
||||
dp->file_ptr = data_from_str(str, &dp->file_size);
|
||||
(*env)->ReleaseStringUTFChars(env, hosts, str);
|
||||
dp->hosts = parse_hosts(dp->file_ptr, dp->file_size);
|
||||
if (!dp->hosts) {
|
||||
perror("parse_hosts");
|
||||
clear_params();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
dp->ttl = fake_ttl;
|
||||
dp->udp_fake_count = udp_fake_count;
|
||||
dp->drop_sack = drop_sack;
|
||||
dp->proto =
|
||||
IS_HTTP * desync_http |
|
||||
IS_HTTPS * desync_https |
|
||||
@ -170,6 +220,8 @@ Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniCreateSocket(
|
||||
}
|
||||
|
||||
if (mode == DESYNC_FAKE) {
|
||||
dp->fake_offset = fake_offset;
|
||||
|
||||
const char *sni = (*env)->GetStringUTFChars(env, fake_sni, 0);
|
||||
LOG(LOG_S, "fake_sni: %s", sni);
|
||||
res = change_tls_sni(sni, fake_tls.data, fake_tls.size);
|
||||
@ -181,17 +233,8 @@ Java_io_github_dovecoteescapee_byedpi_core_ByeDpiProxy_jniCreateSocket(
|
||||
}
|
||||
|
||||
if (mode == DESYNC_OOB) {
|
||||
const char *oob = (*env)->GetStringUTFChars(env, custom_oob_data, 0);
|
||||
const size_t oob_len = strlen(oob);
|
||||
|
||||
oob_data.size = oob_len;
|
||||
oob_data.data = malloc(oob_len);
|
||||
if (oob_data.data == NULL) {
|
||||
uniperror("malloc");
|
||||
return -1;
|
||||
}
|
||||
memcpy(oob_data.data, oob, oob_len);
|
||||
(*env)->ReleaseStringUTFChars(env, custom_oob_data, oob);
|
||||
dp->oob_char[0] = custom_oob_char;
|
||||
dp->oob_char[1] = 1;
|
||||
}
|
||||
|
||||
if (dp->proto) {
|
||||
|
||||
@ -15,9 +15,10 @@ void reset_params(void) {
|
||||
params = default_params;
|
||||
}
|
||||
|
||||
extern const struct option options[35];
|
||||
extern const struct option options[38];
|
||||
|
||||
int parse_args(int argc, char **argv) {
|
||||
int parse_args(int argc, char **argv)
|
||||
{
|
||||
int optc = sizeof(options)/sizeof(*options);
|
||||
for (int i = 0, e = optc; i < e; i++)
|
||||
optc += options[i].has_arg;
|
||||
@ -50,8 +51,9 @@ int parse_args(int argc, char **argv) {
|
||||
|
||||
optind = optreset = 1;
|
||||
|
||||
while (!invalid && (rez = getopt_long_only(
|
||||
while (!invalid && (rez = getopt_long(
|
||||
argc, argv, opt, options, 0)) != -1) {
|
||||
|
||||
switch (rez) {
|
||||
|
||||
case 'N':
|
||||
@ -64,6 +66,15 @@ int parse_args(int argc, char **argv) {
|
||||
params.udp = 0;
|
||||
break;
|
||||
|
||||
// case 'h':
|
||||
// printf(help_text);
|
||||
// reset_params();
|
||||
// return 0;
|
||||
// case 'v':
|
||||
// printf("%s\n", VERSION);
|
||||
// reset_params();
|
||||
// return 0;
|
||||
|
||||
case 'i':
|
||||
if (get_addr(optarg,
|
||||
(struct sockaddr_ina *)¶ms.laddr) < 0)
|
||||
@ -119,10 +130,6 @@ int parse_args(int argc, char **argv) {
|
||||
reset_params();
|
||||
return -1;
|
||||
}
|
||||
if (!optarg) {
|
||||
dp->detect |= DETECT_TORST;
|
||||
break;
|
||||
}
|
||||
end = optarg;
|
||||
while (end && !invalid) {
|
||||
switch (*end) {
|
||||
@ -132,14 +139,9 @@ int parse_args(int argc, char **argv) {
|
||||
case 'r':
|
||||
dp->detect |= DETECT_HTTP_LOCAT;
|
||||
break;
|
||||
case 'c':
|
||||
dp->detect |= DETECT_HTTP_CLERR;
|
||||
break;
|
||||
case 's':
|
||||
dp->detect |= DETECT_TLS_INVSID;
|
||||
break;
|
||||
case 'a':
|
||||
dp->detect |= DETECT_TLS_ALERT;
|
||||
case 's':
|
||||
dp->detect |= DETECT_TLS_ERR;
|
||||
break;
|
||||
case 'n':
|
||||
break;
|
||||
@ -161,8 +163,12 @@ int parse_args(int argc, char **argv) {
|
||||
break;
|
||||
|
||||
case 'T':;
|
||||
#ifdef __linux__
|
||||
float f = strtof(optarg, &end);
|
||||
val = (long)(f * 1000);
|
||||
#else
|
||||
val = strtol(optarg, &end, 0);
|
||||
#endif
|
||||
if (val <= 0 || val > UINT_MAX || *end)
|
||||
invalid = 1;
|
||||
else
|
||||
@ -212,6 +218,7 @@ int parse_args(int argc, char **argv) {
|
||||
case 's':
|
||||
case 'd':
|
||||
case 'o':
|
||||
case 'q':
|
||||
case 'f':
|
||||
;
|
||||
struct part *part = add((void *)&dp->parts,
|
||||
@ -231,6 +238,8 @@ int parse_args(int argc, char **argv) {
|
||||
break;
|
||||
case 'o': part->m = DESYNC_OOB;
|
||||
break;
|
||||
case 'q': part->m = DESYNC_DISOOB;
|
||||
break;
|
||||
case 'f': part->m = DESYNC_FAKE;
|
||||
}
|
||||
break;
|
||||
@ -263,13 +272,21 @@ int parse_args(int argc, char **argv) {
|
||||
dp->md5sig = 1;
|
||||
break;
|
||||
|
||||
case 'O':
|
||||
val = strtol(optarg, &end, 0);
|
||||
if (val <= 0 || *end)
|
||||
invalid = 1;
|
||||
else
|
||||
dp->fake_offset = val;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
if (change_tls_sni(optarg, fake_tls.data, fake_tls.size)) {
|
||||
fprintf(stderr, "error chsni\n");
|
||||
perror("change_tls_sni");
|
||||
reset_params();
|
||||
return -1;
|
||||
}
|
||||
printf("sni: %s\n", optarg);
|
||||
LOG(LOG_S, "sni: %s", optarg);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
@ -284,14 +301,11 @@ int parse_args(int argc, char **argv) {
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
if (oob_data.data != oob_char) {
|
||||
continue;
|
||||
}
|
||||
oob_data.data = ftob(optarg, &oob_data.size);
|
||||
if (!oob_data.data) {
|
||||
uniperror("read/parse");
|
||||
val = parse_cform(dp->oob_char, 1, optarg, strlen(optarg));
|
||||
if (val != 1) {
|
||||
invalid = 1;
|
||||
}
|
||||
else dp->oob_char[1] = 1;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
@ -366,6 +380,10 @@ int parse_args(int argc, char **argv) {
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Y':
|
||||
dp->drop_sack = 1;
|
||||
break;
|
||||
|
||||
case 'w': //
|
||||
params.sfdelay = strtol(optarg, &end, 0);
|
||||
if (params.sfdelay < 0 || optarg == end
|
||||
@ -376,9 +394,11 @@ int parse_args(int argc, char **argv) {
|
||||
case 'W':
|
||||
params.wait_send = 0;
|
||||
break;
|
||||
#ifdef __linux__
|
||||
case 'P':
|
||||
params.protect_path = optarg;
|
||||
break;
|
||||
#endif
|
||||
case 0:
|
||||
break;
|
||||
|
||||
@ -387,13 +407,13 @@ int parse_args(int argc, char **argv) {
|
||||
return -1;
|
||||
|
||||
default:
|
||||
printf("?: %c\n", rez);
|
||||
LOG(LOG_S, "Unknown option: -%c", rez);
|
||||
reset_params();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (invalid) {
|
||||
fprintf(stderr, "invalid value: -%c %s\n", rez, optarg);
|
||||
LOG(LOG_S, "invalid value: -%c %s", rez, optarg);
|
||||
reset_params();
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ class MainActivity : AppCompatActivity() {
|
||||
private fun collectLogs(): String? =
|
||||
try {
|
||||
Runtime.getRuntime()
|
||||
.exec("logcat *:I -d")
|
||||
.exec("logcat *:D -d")
|
||||
.inputStream.bufferedReader()
|
||||
.use { it.readText() }
|
||||
} catch (e: Exception) {
|
||||
|
||||
@ -4,6 +4,7 @@ import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import io.github.dovecoteescapee.byedpi.R
|
||||
import io.github.dovecoteescapee.byedpi.fragments.MainSettingsFragment
|
||||
import io.github.dovecoteescapee.byedpi.utility.getPreferences
|
||||
@ -35,6 +36,7 @@ class SettingsActivity : AppCompatActivity() {
|
||||
R.id.action_reset_settings -> {
|
||||
getPreferences().edit().clear().apply()
|
||||
|
||||
supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(R.id.settings, MainSettingsFragment())
|
||||
|
||||
@ -69,13 +69,19 @@ class ByeDpiProxy {
|
||||
splitAtHost = preferences.splitAtHost,
|
||||
fakeTtl = preferences.fakeTtl,
|
||||
fakeSni = preferences.fakeSni,
|
||||
oobData = preferences.oobData,
|
||||
oobChar = preferences.oobChar,
|
||||
hostMixedCase = preferences.hostMixedCase,
|
||||
domainMixedCase = preferences.domainMixedCase,
|
||||
hostRemoveSpaces = preferences.hostRemoveSpaces,
|
||||
tlsRecordSplit = preferences.tlsRecordSplit,
|
||||
tlsRecordSplitPosition = preferences.tlsRecordSplitPosition,
|
||||
tlsRecordSplitAtSni = preferences.tlsRecordSplitAtSni,
|
||||
hostsMode = preferences.hostsMode.ordinal,
|
||||
hosts = preferences.hosts,
|
||||
tcpFastOpen = preferences.tcpFastOpen,
|
||||
udpFakeCount = preferences.udpFakeCount,
|
||||
dropSack = preferences.dropSack,
|
||||
fakeOffset = preferences.fakeOffset,
|
||||
)
|
||||
}
|
||||
|
||||
@ -97,13 +103,19 @@ class ByeDpiProxy {
|
||||
splitAtHost: Boolean,
|
||||
fakeTtl: Int,
|
||||
fakeSni: String,
|
||||
oobData: String,
|
||||
oobChar: Byte,
|
||||
hostMixedCase: Boolean,
|
||||
domainMixedCase: Boolean,
|
||||
hostRemoveSpaces: Boolean,
|
||||
tlsRecordSplit: Boolean,
|
||||
tlsRecordSplitPosition: Int,
|
||||
tlsRecordSplitAtSni: Boolean,
|
||||
hostsMode: Int,
|
||||
hosts: String?,
|
||||
tcpFastOpen: Boolean,
|
||||
udpFakeCount: Int,
|
||||
dropSack: Boolean,
|
||||
fakeOffset: Int,
|
||||
): Int
|
||||
|
||||
private external fun jniStartProxy(fd: Int): Int
|
||||
|
||||
@ -48,13 +48,19 @@ class ByeDpiProxyUIPreferences(
|
||||
splitAtHost: Boolean? = null,
|
||||
fakeTtl: Int? = null,
|
||||
fakeSni: String? = null,
|
||||
oobData: String? = null,
|
||||
oobChar: String? = null,
|
||||
hostMixedCase: Boolean? = null,
|
||||
domainMixedCase: Boolean? = null,
|
||||
hostRemoveSpaces: Boolean? = null,
|
||||
tlsRecordSplit: Boolean? = null,
|
||||
tlsRecordSplitPosition: Int? = null,
|
||||
tlsRecordSplitAtSni: Boolean? = null,
|
||||
hostsMode: HostsMode? = null,
|
||||
hosts: String? = null,
|
||||
tcpFastOpen: Boolean? = null,
|
||||
udpFakeCount: Int? = null,
|
||||
dropSack: Boolean? = null,
|
||||
byedpiFakeOffset: Int? = null,
|
||||
) : ByeDpiProxyPreferences {
|
||||
val ip: String = ip ?: "127.0.0.1"
|
||||
val port: Int = port ?: 1080
|
||||
@ -67,17 +73,27 @@ class ByeDpiProxyUIPreferences(
|
||||
val desyncHttps: Boolean = desyncHttps ?: true
|
||||
val desyncUdp: Boolean = desyncUdp ?: false
|
||||
val desyncMethod: DesyncMethod = desyncMethod ?: DesyncMethod.Disorder
|
||||
val splitPosition: Int = splitPosition ?: 3
|
||||
val splitPosition: Int = splitPosition ?: 1
|
||||
val splitAtHost: Boolean = splitAtHost ?: false
|
||||
val fakeTtl: Int = fakeTtl ?: 8
|
||||
val fakeSni: String = fakeSni ?: "www.iana.org"
|
||||
val oobData: String = oobData ?: "a"
|
||||
val oobChar: Byte = (oobChar ?: "a")[0].code.toByte()
|
||||
val hostMixedCase: Boolean = hostMixedCase ?: false
|
||||
val domainMixedCase: Boolean = domainMixedCase ?: false
|
||||
val hostRemoveSpaces: Boolean = hostRemoveSpaces ?: false
|
||||
val tlsRecordSplit: Boolean = tlsRecordSplit ?: false
|
||||
val tlsRecordSplitPosition: Int = tlsRecordSplitPosition ?: 0
|
||||
val tlsRecordSplitAtSni: Boolean = tlsRecordSplitAtSni ?: false
|
||||
val hostsMode: HostsMode =
|
||||
if (hosts?.isBlank() != false) HostsMode.Disable
|
||||
else hostsMode ?: HostsMode.Disable
|
||||
val hosts: String? =
|
||||
if (this.hostsMode == HostsMode.Disable) null
|
||||
else hosts?.trim()
|
||||
val tcpFastOpen: Boolean = tcpFastOpen ?: false
|
||||
val udpFakeCount: Int = udpFakeCount ?: 0
|
||||
val dropSack: Boolean = dropSack ?: false
|
||||
val fakeOffset: Int = byedpiFakeOffset ?: 0
|
||||
|
||||
constructor(preferences: SharedPreferences) : this(
|
||||
ip = preferences.getString("byedpi_proxy_ip", null),
|
||||
@ -95,7 +111,7 @@ class ByeDpiProxyUIPreferences(
|
||||
splitAtHost = preferences.getBoolean("byedpi_split_at_host", false),
|
||||
fakeTtl = preferences.getString("byedpi_fake_ttl", null)?.toIntOrNull(),
|
||||
fakeSni = preferences.getString("byedpi_fake_sni", null),
|
||||
oobData = preferences.getString("byedpi_oob_data", null),
|
||||
oobChar = preferences.getString("byedpi_oob_data", null),
|
||||
hostMixedCase = preferences.getBoolean("byedpi_host_mixed_case", false),
|
||||
domainMixedCase = preferences.getBoolean("byedpi_domain_mixed_case", false),
|
||||
hostRemoveSpaces = preferences.getBoolean("byedpi_host_remove_spaces", false),
|
||||
@ -103,6 +119,19 @@ class ByeDpiProxyUIPreferences(
|
||||
tlsRecordSplitPosition = preferences.getString("byedpi_tlsrec_position", null)
|
||||
?.toIntOrNull(),
|
||||
tlsRecordSplitAtSni = preferences.getBoolean("byedpi_tlsrec_at_sni", false),
|
||||
hostsMode = preferences.getString("byedpi_hosts_mode", null)
|
||||
?.let { HostsMode.fromName(it) },
|
||||
hosts = preferences.getString("byedpi_hosts_mode", null)?.let {
|
||||
when (HostsMode.fromName(it)) {
|
||||
HostsMode.Blacklist -> preferences.getString("byedpi_hosts_blacklist", null)
|
||||
HostsMode.Whitelist -> preferences.getString("byedpi_hosts_whitelist", null)
|
||||
else -> null
|
||||
}
|
||||
},
|
||||
tcpFastOpen = preferences.getBoolean("byedpi_tcp_fast_open", false),
|
||||
udpFakeCount = preferences.getString("byedpi_udp_fake_count", null)?.toIntOrNull(),
|
||||
dropSack = preferences.getBoolean("byedpi_drop_sack", false),
|
||||
byedpiFakeOffset = preferences.getString("byedpi_fake_offset", null)?.toIntOrNull(),
|
||||
)
|
||||
|
||||
enum class DesyncMethod {
|
||||
@ -110,7 +139,8 @@ class ByeDpiProxyUIPreferences(
|
||||
Split,
|
||||
Disorder,
|
||||
Fake,
|
||||
OOB;
|
||||
OOB,
|
||||
DISOOB;
|
||||
|
||||
companion object {
|
||||
fun fromName(name: String): DesyncMethod {
|
||||
@ -120,9 +150,27 @@ class ByeDpiProxyUIPreferences(
|
||||
"disorder" -> Disorder
|
||||
"fake" -> Fake
|
||||
"oob" -> OOB
|
||||
"disoob" -> DISOOB
|
||||
else -> throw IllegalArgumentException("Unknown desync method: $name")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class HostsMode {
|
||||
Disable,
|
||||
Blacklist,
|
||||
Whitelist;
|
||||
|
||||
companion object {
|
||||
fun fromName(name: String): HostsMode {
|
||||
return when (name) {
|
||||
"disable" -> Disable
|
||||
"blacklist" -> Blacklist
|
||||
"whitelist" -> Whitelist
|
||||
else -> throw IllegalArgumentException("Unknown hosts mode: $name")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
package io.github.dovecoteescapee.byedpi.core
|
||||
|
||||
object TProxyService {
|
||||
init {
|
||||
System.loadLibrary("hev-socks5-tunnel")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
external fun TProxyStartService(configPath: String, fd: Int)
|
||||
|
||||
@JvmStatic
|
||||
external fun TProxyStopService()
|
||||
|
||||
@JvmStatic
|
||||
@Suppress("unused")
|
||||
external fun TProxyGetStats(): LongArray
|
||||
}
|
||||
@ -6,6 +6,7 @@ import androidx.preference.*
|
||||
import io.github.dovecoteescapee.byedpi.R
|
||||
import io.github.dovecoteescapee.byedpi.core.ByeDpiProxyUIPreferences
|
||||
import io.github.dovecoteescapee.byedpi.core.ByeDpiProxyUIPreferences.DesyncMethod.*
|
||||
import io.github.dovecoteescapee.byedpi.core.ByeDpiProxyUIPreferences.HostsMode.*
|
||||
import io.github.dovecoteescapee.byedpi.utility.*
|
||||
|
||||
class ByeDpiUISettingsFragment : PreferenceFragmentCompat() {
|
||||
@ -65,7 +66,11 @@ class ByeDpiUISettingsFragment : PreferenceFragmentCompat() {
|
||||
val desyncMethod =
|
||||
findPreferenceNotNull<ListPreference>("byedpi_desync_method")
|
||||
.value.let { ByeDpiProxyUIPreferences.DesyncMethod.fromName(it) }
|
||||
val hostsMode = findPreferenceNotNull<ListPreference>("byedpi_hosts_mode")
|
||||
.value.let { ByeDpiProxyUIPreferences.HostsMode.fromName(it) }
|
||||
|
||||
val hostsBlacklist = findPreferenceNotNull<EditTextPreference>("byedpi_hosts_blacklist")
|
||||
val hostsWhitelist = findPreferenceNotNull<EditTextPreference>("byedpi_hosts_whitelist")
|
||||
val desyncHttp = findPreferenceNotNull<CheckBoxPreference>("byedpi_desync_http")
|
||||
val desyncHttps = findPreferenceNotNull<CheckBoxPreference>("byedpi_desync_https")
|
||||
val desyncUdp = findPreferenceNotNull<CheckBoxPreference>("byedpi_desync_udp")
|
||||
@ -73,7 +78,9 @@ class ByeDpiUISettingsFragment : PreferenceFragmentCompat() {
|
||||
val splitAtHost = findPreferenceNotNull<CheckBoxPreference>("byedpi_split_at_host")
|
||||
val ttlFake = findPreferenceNotNull<EditTextPreference>("byedpi_fake_ttl")
|
||||
val fakeSni = findPreferenceNotNull<EditTextPreference>("byedpi_fake_sni")
|
||||
val oobData = findPreferenceNotNull<EditTextPreference>("byedpi_oob_data")
|
||||
val fakeOffset = findPreferenceNotNull<EditTextPreference>("byedpi_fake_offset")
|
||||
val oobChar = findPreferenceNotNull<EditTextPreference>("byedpi_oob_data")
|
||||
val udpFakeCount = findPreferenceNotNull<EditTextPreference>("byedpi_udp_fake_count")
|
||||
val hostMixedCase = findPreferenceNotNull<CheckBoxPreference>("byedpi_host_mixed_case")
|
||||
val domainMixedCase = findPreferenceNotNull<CheckBoxPreference>("byedpi_domain_mixed_case")
|
||||
val hostRemoveSpaces =
|
||||
@ -83,64 +90,36 @@ class ByeDpiUISettingsFragment : PreferenceFragmentCompat() {
|
||||
findPreferenceNotNull<EditTextPreference>("byedpi_tlsrec_position")
|
||||
val splitTlsRecAtSni = findPreferenceNotNull<CheckBoxPreference>("byedpi_tlsrec_at_sni")
|
||||
|
||||
when (desyncMethod) {
|
||||
None -> {
|
||||
desyncHttp.isVisible = false
|
||||
desyncHttps.isVisible = false
|
||||
desyncUdp.isVisible = false
|
||||
splitPosition.isVisible = false
|
||||
splitAtHost.isVisible = false
|
||||
ttlFake.isVisible = false
|
||||
fakeSni.isVisible = false
|
||||
oobData.isVisible = false
|
||||
hostMixedCase.isVisible = false
|
||||
domainMixedCase.isVisible = false
|
||||
hostRemoveSpaces.isVisible = false
|
||||
}
|
||||
hostsBlacklist.isVisible = hostsMode == Blacklist
|
||||
hostsWhitelist.isVisible = hostsMode == Whitelist
|
||||
|
||||
else -> {
|
||||
desyncHttp.isVisible = true
|
||||
desyncHttps.isVisible = true
|
||||
desyncUdp.isVisible = true
|
||||
splitPosition.isVisible = true
|
||||
splitAtHost.isVisible = true
|
||||
val desyncEnabled = desyncMethod != None
|
||||
splitPosition.isVisible = desyncEnabled
|
||||
splitAtHost.isVisible = desyncEnabled
|
||||
|
||||
val desyncAllProtocols =
|
||||
!desyncHttp.isChecked && !desyncHttps.isChecked && !desyncUdp.isChecked
|
||||
val isFake = desyncMethod == Fake
|
||||
ttlFake.isVisible = isFake
|
||||
fakeSni.isVisible = isFake
|
||||
fakeOffset.isVisible = isFake
|
||||
|
||||
if (desyncAllProtocols || desyncHttp.isChecked) {
|
||||
hostMixedCase.isVisible = true
|
||||
domainMixedCase.isVisible = true
|
||||
hostRemoveSpaces.isVisible = true
|
||||
} else {
|
||||
hostMixedCase.isVisible = false
|
||||
domainMixedCase.isVisible = false
|
||||
hostRemoveSpaces.isVisible = false
|
||||
}
|
||||
val isOob = desyncMethod == OOB || desyncMethod == DISOOB
|
||||
oobChar.isVisible = isOob
|
||||
|
||||
when (desyncMethod) {
|
||||
Fake -> {
|
||||
ttlFake.isVisible = true
|
||||
fakeSni.isVisible = true
|
||||
oobData.isVisible = false
|
||||
}
|
||||
val desyncAllProtocols =
|
||||
!desyncHttp.isChecked && !desyncHttps.isChecked && !desyncUdp.isChecked
|
||||
|
||||
OOB -> {
|
||||
ttlFake.isVisible = false
|
||||
fakeSni.isVisible = false
|
||||
oobData.isVisible = true
|
||||
}
|
||||
val desyncHttpEnabled = desyncAllProtocols || desyncHttp.isChecked
|
||||
hostMixedCase.isEnabled = desyncHttpEnabled
|
||||
domainMixedCase.isEnabled = desyncHttpEnabled
|
||||
hostRemoveSpaces.isEnabled = desyncHttpEnabled
|
||||
|
||||
else -> {
|
||||
ttlFake.isVisible = false
|
||||
fakeSni.isVisible = false
|
||||
oobData.isVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val desyncUdpEnabled = desyncAllProtocols || desyncUdp.isChecked
|
||||
udpFakeCount.isEnabled = desyncUdpEnabled
|
||||
|
||||
splitTlsRecPosition.isVisible = splitTlsRec.isChecked
|
||||
splitTlsRecAtSni.isVisible = splitTlsRec.isChecked
|
||||
val desyncHttpsEnabled = desyncAllProtocols || desyncHttps.isChecked
|
||||
splitTlsRec.isEnabled = desyncHttpsEnabled
|
||||
val tlsRecEnabled = desyncHttpsEnabled && splitTlsRec.isChecked
|
||||
splitTlsRecPosition.isEnabled = tlsRecEnabled
|
||||
splitTlsRecAtSni.isEnabled = tlsRecEnabled
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +38,9 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.main_settings, rootKey)
|
||||
|
||||
setEditTextPreferenceListener("dns_ip") { checkIp(it) }
|
||||
setEditTextPreferenceListener("dns_ip") {
|
||||
it.isBlank() || checkNotLocalIp(it)
|
||||
}
|
||||
|
||||
findPreferenceNotNull<DropDownPreference>("app_theme")
|
||||
.setOnPreferenceChangeListener { _, newValue ->
|
||||
@ -83,10 +85,18 @@ class MainSettingsFragment : PreferenceFragmentCompat() {
|
||||
val mode = findPreferenceNotNull<ListPreference>("byedpi_mode")
|
||||
.value.let { Mode.fromString(it) }
|
||||
val dns = findPreferenceNotNull<EditTextPreference>("dns_ip")
|
||||
val ipv6 = findPreferenceNotNull<SwitchPreference>("ipv6_enable")
|
||||
|
||||
when (mode) {
|
||||
Mode.VPN -> dns.isVisible = true
|
||||
Mode.Proxy -> dns.isVisible = false
|
||||
Mode.VPN -> {
|
||||
dns.isVisible = true
|
||||
ipv6.isVisible = true
|
||||
}
|
||||
|
||||
Mode.Proxy -> {
|
||||
dns.isVisible = false
|
||||
ipv6.isVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,13 +8,11 @@ import android.os.Build
|
||||
import android.os.ParcelFileDescriptor
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import engine.Engine
|
||||
import engine.Key
|
||||
import io.github.dovecoteescapee.byedpi.BuildConfig
|
||||
import io.github.dovecoteescapee.byedpi.R
|
||||
import io.github.dovecoteescapee.byedpi.activities.MainActivity
|
||||
import io.github.dovecoteescapee.byedpi.core.ByeDpiProxy
|
||||
import io.github.dovecoteescapee.byedpi.core.ByeDpiProxyPreferences
|
||||
import io.github.dovecoteescapee.byedpi.core.TProxyService
|
||||
import io.github.dovecoteescapee.byedpi.data.*
|
||||
import io.github.dovecoteescapee.byedpi.utility.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -23,11 +21,12 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
|
||||
class ByeDpiVpnService : LifecycleVpnService() {
|
||||
private val proxy = ByeDpiProxy()
|
||||
private val byeDpiProxy = ByeDpiProxy()
|
||||
private var proxyJob: Job? = null
|
||||
private var vpn: ParcelFileDescriptor? = null
|
||||
private var tunFd: ParcelFileDescriptor? = null
|
||||
private val mutex = Mutex()
|
||||
private var stopping: Boolean = false
|
||||
|
||||
@ -138,7 +137,7 @@ class ByeDpiVpnService : LifecycleVpnService() {
|
||||
val preferences = getByeDpiPreferences()
|
||||
|
||||
proxyJob = lifecycleScope.launch(Dispatchers.IO) {
|
||||
val code = proxy.startProxy(preferences)
|
||||
val code = byeDpiProxy.startProxy(preferences)
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
if (code != 0) {
|
||||
@ -164,7 +163,7 @@ class ByeDpiVpnService : LifecycleVpnService() {
|
||||
return
|
||||
}
|
||||
|
||||
proxy.stopProxy()
|
||||
byeDpiProxy.stopProxy()
|
||||
proxyJob?.join() ?: throw IllegalStateException("ProxyJob field null")
|
||||
proxyJob = null
|
||||
|
||||
@ -174,30 +173,58 @@ class ByeDpiVpnService : LifecycleVpnService() {
|
||||
private fun startTun2Socks() {
|
||||
Log.i(TAG, "Starting tun2socks")
|
||||
|
||||
if (vpn != null) {
|
||||
if (tunFd != null) {
|
||||
throw IllegalStateException("VPN field not null")
|
||||
}
|
||||
|
||||
val sharedPreferences = getPreferences()
|
||||
val port = sharedPreferences.getString("byedpi_proxy_port", null)?.toInt() ?: 1080
|
||||
val dns = sharedPreferences.getStringNotNull("dns_ip", "1.1.1.1")
|
||||
val ipv6 = sharedPreferences.getBoolean("ipv6_enable", false)
|
||||
|
||||
val vpn = createBuilder(dns).establish()
|
||||
val tun2socksConfig = """
|
||||
| misc:
|
||||
| task-stack-size: 81920
|
||||
| socks5:
|
||||
| mtu: 8500
|
||||
| address: 127.0.0.1
|
||||
| port: $port
|
||||
| udp: udp
|
||||
""".trimMargin("| ")
|
||||
|
||||
val configPath = try {
|
||||
File.createTempFile("config", "tmp", cacheDir).apply {
|
||||
writeText(tun2socksConfig)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to create config file", e)
|
||||
throw e
|
||||
}
|
||||
|
||||
val fd = createBuilder(dns, ipv6).establish()
|
||||
?: throw IllegalStateException("VPN connection failed")
|
||||
|
||||
this.vpn = vpn
|
||||
// val fd = vpn.detachFd()
|
||||
Engine.insert(createKey(vpn.fd, port))
|
||||
Engine.start()
|
||||
this.tunFd = fd
|
||||
|
||||
TProxyService.TProxyStartService(configPath.absolutePath, fd.fd)
|
||||
|
||||
Log.i(TAG, "Tun2Socks started")
|
||||
}
|
||||
|
||||
private fun stopTun2Socks() {
|
||||
Log.i(TAG, "Stopping tun2socks")
|
||||
// Engine.stop() // sometimes crashes with fdsan
|
||||
vpn?.close() ?: Log.w(TAG, "VPN not running") // Is engine close sockets?
|
||||
vpn = null
|
||||
|
||||
TProxyService.TProxyStopService()
|
||||
|
||||
try {
|
||||
File(cacheDir, "config.tmp").delete()
|
||||
} catch (e: SecurityException) {
|
||||
Log.e(TAG, "Failed to delete config file", e)
|
||||
}
|
||||
|
||||
tunFd?.close() ?: Log.w(TAG, "VPN not running")
|
||||
tunFd = null
|
||||
|
||||
Log.i(TAG, "Tun2socks stopped")
|
||||
}
|
||||
|
||||
@ -212,6 +239,7 @@ class ByeDpiVpnService : LifecycleVpnService() {
|
||||
setStatus(
|
||||
when (newStatus) {
|
||||
ServiceStatus.Connected -> AppStatus.Running
|
||||
|
||||
ServiceStatus.Disconnected,
|
||||
ServiceStatus.Failed -> {
|
||||
proxyJob = null
|
||||
@ -241,7 +269,8 @@ class ByeDpiVpnService : LifecycleVpnService() {
|
||||
ByeDpiVpnService::class.java,
|
||||
)
|
||||
|
||||
private fun createBuilder(dns: String): Builder {
|
||||
private fun createBuilder(dns: String, ipv6: Boolean): Builder {
|
||||
Log.d(TAG, "DNS: $dns")
|
||||
val builder = Builder()
|
||||
builder.setSession("ByeDPI")
|
||||
builder.setConfigureIntent(
|
||||
@ -254,30 +283,22 @@ class ByeDpiVpnService : LifecycleVpnService() {
|
||||
)
|
||||
|
||||
builder.addAddress("10.10.10.10", 32)
|
||||
builder.addRoute("0.0.0.0", 0)
|
||||
builder.addRoute("0:0:0:0:0:0:0:0", 0)
|
||||
builder.addDnsServer(dns)
|
||||
.addRoute("0.0.0.0", 0)
|
||||
|
||||
if (ipv6) {
|
||||
builder.addAddress("fd00::1", 128)
|
||||
.addRoute("::", 0)
|
||||
}
|
||||
|
||||
if (dns.isNotBlank()) {
|
||||
builder.addDnsServer(dns)
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
builder.setMetered(false)
|
||||
}
|
||||
|
||||
builder.addDisallowedApplication("io.github.dovecoteescapee.byedpi")
|
||||
builder.addDisallowedApplication(applicationContext.packageName)
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
private fun createKey(fd: Int, port: Int): Key = Key().apply {
|
||||
mark = 0
|
||||
mtu = 0
|
||||
device = "fd://${fd}"
|
||||
|
||||
setInterface("")
|
||||
logLevel = if (BuildConfig.DEBUG) "debug" else "info"
|
||||
proxy = "socks5://127.0.0.1:$port"
|
||||
|
||||
restAPI = ""
|
||||
tcpSendBufferSize = ""
|
||||
tcpReceiveBufferSize = ""
|
||||
tcpModerateReceiveBuffer = false
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.ServiceLifecycleDispatcher
|
||||
|
||||
/**
|
||||
* Based on @link [androidx.lifecycle.LifecycleService]
|
||||
* Based on [androidx.lifecycle.LifecycleService]
|
||||
*/
|
||||
open class LifecycleVpnService : VpnService(), LifecycleOwner {
|
||||
@Suppress("LeakingThis")
|
||||
@ -28,10 +28,10 @@ open class LifecycleVpnService : VpnService(), LifecycleOwner {
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
@Suppress("DEPRECATION")
|
||||
@CallSuper
|
||||
override fun onStart(intent: Intent?, startId: Int) {
|
||||
dispatcher.onServicePreSuperOnStart()
|
||||
@Suppress("DEPRECATION")
|
||||
super.onStart(intent, startId)
|
||||
}
|
||||
|
||||
|
||||
@ -58,4 +58,4 @@ fun createConnectionNotification(
|
||||
PendingIntent.FLAG_IMMUTABLE,
|
||||
)
|
||||
)
|
||||
.build()
|
||||
.build()
|
||||
|
||||
@ -3,7 +3,6 @@ package io.github.dovecoteescapee.byedpi.utility
|
||||
import android.net.InetAddresses
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import android.util.Patterns
|
||||
import android.widget.Toast
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
@ -15,8 +14,21 @@ fun checkIp(ip: String): Boolean =
|
||||
InetAddresses.isNumericAddress(ip)
|
||||
} else {
|
||||
// This pattern doesn't not support IPv6
|
||||
@Suppress("DEPRECATION")
|
||||
Patterns.IP_ADDRESS.matcher(ip).matches()
|
||||
// @Suppress("DEPRECATION")
|
||||
// Patterns.IP_ADDRESS.matcher(ip).matches()
|
||||
true
|
||||
}
|
||||
|
||||
fun checkNotLocalIp(ip: String): Boolean =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
InetAddresses.isNumericAddress(ip) && InetAddresses.parseNumericAddress(ip).let {
|
||||
!it.isAnyLocalAddress && !it.isLoopbackAddress
|
||||
}
|
||||
} else {
|
||||
// This pattern doesn't not support IPv6
|
||||
// @Suppress("DEPRECATION")
|
||||
// Patterns.IP_ADDRESS.matcher(ip).matches()
|
||||
true
|
||||
}
|
||||
|
||||
fun PreferenceFragmentCompat.setEditTestPreferenceListenerPort(key: String) {
|
||||
|
||||
16
app/src/main/jni/Android.mk
Normal file
@ -0,0 +1,16 @@
|
||||
# Copyright (C) 2023 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
include $(call all-subdir-makefiles)
|
||||
21
app/src/main/jni/Application.mk
Normal file
@ -0,0 +1,21 @@
|
||||
# Copyright (C) 2023 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
APP_OPTIM := release
|
||||
APP_PLATFORM := android-21
|
||||
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
|
||||
APP_CFLAGS := -O3 -DPKGNAME=io/github/dovecoteescapee/byedpi/core
|
||||
APP_CPPFLAGS := -O3 -std=c++11
|
||||
NDK_TOOLCHAIN_VERSION := clang
|
||||
1
app/src/main/jni/hev-socks5-tunnel
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 677bb4530cfc867cd44d88d298960c8d8d9fbfad
|
||||
|
Before Width: | Height: | Size: 820 B |
|
Before Width: | Height: | Size: 486 B |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
24
app/src/main/res/drawable/ic_notification.xml
Normal file
@ -0,0 +1,24 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M14.74,16.866C17.473,15.885 17.893,13.832 17.869,12.884C17.835,11.487 16.792,10.113 16.751,9.354C16.714,8.676 16.967,8.174 18.106,8.338C18.002,8.039 17.763,7.536 17.479,7.178C17.112,6.714 16.629,6.356 15.858,6.357C14.554,6.359 14.124,7.537 13.826,8.296C13.528,9.056 13.837,9.36 13.026,10.509C13.149,11.895 13.097,11.909 12.882,12.771C12.362,14.851 10.511,17.307 9.567,18.641C8.623,19.975 7.843,20.663 8.685,21.329C9.526,21.997 9.927,21.032 10.234,20.477C10.542,19.923 10.871,19.205 11.014,19.246C11.158,19.287 11.199,19.153 10.819,20.303C10.44,21.452 10.532,21.955 11.353,22.017C12.174,22.078 12.328,21.575 12.389,20.713C12.451,19.852 12.564,19.379 12.677,19.379C12.79,19.379 12.821,19.236 12.903,20.323C12.985,21.411 13.016,22.15 14.063,21.781C15.109,21.412 14.791,20.816 14.535,20.242C14.278,19.667 14.207,19.092 14.319,19.041C14.432,18.99 14.566,19.257 14.976,19.893C15.387,20.529 15.613,21.289 16.485,20.704C17.697,19.89 16.043,18.477 15.304,17.543C13.991,18.015 13.324,18.015 13.313,17.543C13.303,17.071 13.875,17.176 14.74,16.866ZM16.057,7.078C16.282,7.078 16.465,7.261 16.465,7.486C16.465,7.71 16.282,7.893 16.057,7.893C15.833,7.893 15.65,7.71 15.65,7.486C15.65,7.261 15.833,7.078 16.057,7.078Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M12.323,10.724C12.328,12.132 12.098,13.609 10.721,15.484C9.624,15.608 8.689,15.672 8.468,15.227C8.209,14.706 8.769,14.613 9.399,14.153C9.399,14.153 10.449,13.531 10.239,13.298C10.029,13.064 8.995,13.788 8.497,13.974C7.999,14.161 7.027,14.632 6.506,13.71C6.272,13.298 6.568,13.088 7.478,12.901C8.388,12.715 8.932,12.458 8.777,12.256C8.621,12.054 7.206,12.566 6.086,12.575C4.966,12.582 4.616,12.085 4.616,11.68C4.616,11.276 4.966,11.338 5.946,11.276C6.926,11.214 7.552,11.307 7.532,10.926C7.517,10.623 6.101,10.856 5.246,10.724C4.39,10.592 3.13,10.359 3.13,9.448C3.13,9.06 3.355,8.943 4.047,9.168C4.74,9.394 6.606,9.728 6.606,9.308C6.606,8.888 4.18,9.121 2.849,7.877C1.519,6.633 2.391,5.972 2.655,5.972C3.06,5.972 3.375,6.62 5.548,7.317C6.59,7.651 9.2,7.899 9.958,8.266C10.908,8.725 12.323,10.724 12.323,10.724Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M15.828,5.51C16.435,4.323 16.575,4.112 16.837,3.281C17.099,2.449 17.249,1.729 17.696,1.762C18.302,1.806 18.524,2.519 18.273,3.392C17.982,4.402 17.146,5.458 16.94,5.776C16.605,5.468 15.828,5.51 15.828,5.51Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M17.31,5.903C18.106,5.041 18.208,4.344 18.605,4.337C19.001,4.33 19.22,4.813 19.142,5.238C19.065,5.664 18.542,6.428 18.194,6.796C17.774,6.357 17.536,6.085 17.31,5.903Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M18.47,7.222C18.552,7.004 19.051,6.733 19.283,6.946C19.573,7.212 19.602,8.025 19.036,8.586C18.852,7.943 18.61,7.396 18.47,7.222Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M18.378,11.31C18.712,11.059 19.35,10.323 19.239,9.844C19.128,9.366 19.046,9.308 18.378,9.22C17.71,9.133 17.497,9.061 17.531,9.298C17.566,9.535 18.363,11.121 18.378,11.31Z"
|
||||
android:fillColor="#ffffff"/>
|
||||
</vector>
|
||||
@ -1,9 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
tools:context=".activities.MainActivity">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
@ -11,42 +12,30 @@
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:paddingLeft="10pt"
|
||||
android:paddingTop="5pt"
|
||||
android:paddingRight="10pt"
|
||||
android:paddingBottom="5pt"
|
||||
android:textAllCaps="false"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/status_text"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
tools:text="@string/vpn_connect" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/status_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toTopOf="@+id/proxy_address"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/status_button"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
android:layout_below="@+id/status_button"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_centerHorizontal="true"
|
||||
tools:text="@string/vpn_disconnected" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/proxy_address"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/status_text"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
android:layout_below="@+id/status_text"
|
||||
android:layout_centerHorizontal="true"
|
||||
tools:text="127.0.0.1:1080" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
<item name="disorder">Disorder</item>
|
||||
<item name="fake">Fake</item>
|
||||
<item name="oob">Out-of-band</item>
|
||||
<item name="oob">Disordered out-of-band</item>
|
||||
</array>
|
||||
<array name="byedpi_desync_methods_entries">
|
||||
<item name="none">none</item>
|
||||
@ -33,5 +34,17 @@
|
||||
<item name="disorder">disorder</item>
|
||||
<item name="fake">fake</item>
|
||||
<item name="oob">oob</item>
|
||||
<item name="oob">disoob</item>
|
||||
</array>
|
||||
|
||||
<array name="byedpi_hosts_modes">
|
||||
<item name="disable">Disable</item>
|
||||
<item name="blacklist">Blacklist</item>
|
||||
<item name="whitelist">Whitelist</item>
|
||||
</array>
|
||||
<array name="byedpi_hosts_modes_entries">
|
||||
<item name="disable">disable</item>
|
||||
<item name="blacklist">blacklist</item>
|
||||
<item name="whitelist">whitelist</item>
|
||||
</array>
|
||||
</resources>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
<resources>
|
||||
<string name="byedpi_docs">https://github.com/hufrea/byedpi/blob/v0.13/README.md</string>
|
||||
<string name="app_name">ByeDPI</string>
|
||||
<string name="vpn_connect">Connect</string>
|
||||
<string name="vpn_disconnect">Disconnect</string>
|
||||
@ -57,4 +58,18 @@
|
||||
<string name="sni_of_fake_packet">SNI of fake packet</string>
|
||||
<string name="byedpi_proxy">Proxy</string>
|
||||
<string name="byedpi_desync">Desync</string>
|
||||
</resources>
|
||||
<string name="command_line_arguments">Command line arguments</string>
|
||||
<string name="byedpi_hosts_mode_setting">Hosts</string>
|
||||
<string name="byedpi_hosts_blacklist_setting">Hosts blacklist</string>
|
||||
<string name="byedpi_hosts_whitelist_setting">Hosts whitelist</string>
|
||||
<string name="byedpi_tcp_fast_open_setting">TCP Fast Open</string>
|
||||
<string name="byedpi_udp_fake_count">UDP fake count</string>
|
||||
<string name="ipv6_setting">IPv6</string>
|
||||
<string name="byedpi_fake_offset_setting">Fake offset</string>
|
||||
<string name="byedpi_drop_sack_setting">Drop SACK</string>
|
||||
<string name="desync_udp_category">UDP</string>
|
||||
<string name="desync_http_category">HTTP</string>
|
||||
<string name="desync_https_category">HTTPS</string>
|
||||
<string name="byedpi_protocols_category">Protocols</string>
|
||||
<string name="byedpi_protocols_hint">Uncheck all to desync all traffic</string>
|
||||
</resources>
|
||||
|
||||
@ -1,24 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:tag="byedpi_cmd_settings">
|
||||
|
||||
<Preference
|
||||
android:key="byedpi_readme"
|
||||
android:title="Documentation"
|
||||
android:textColor="?attr/textFillColor"
|
||||
android:icon="@drawable/ic_github_36">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="https://github.com/hufrea/byedpi/tree/main#readme-ov-file" />
|
||||
android:data="@string/byedpi_docs" />
|
||||
</Preference>
|
||||
|
||||
<androidx.preference.PreferenceCategory>
|
||||
|
||||
<com.takisoft.preferencex.EditTextPreference
|
||||
android:key="byedpi_cmd_args"
|
||||
android:title="Command line arguments"
|
||||
android:dialogTitle="Command line arguments"
|
||||
android:inputType="textMultiLine" />
|
||||
android:title="@string/command_line_arguments"
|
||||
android:dialogTitle="@string/command_line_arguments"
|
||||
android:inputType="textMultiLine"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
</androidx.preference.PreferenceCategory>
|
||||
|
||||
|
||||
@ -6,11 +6,10 @@
|
||||
<Preference
|
||||
android:key="byedpi_readme"
|
||||
android:title="@string/byedpi_readme_link"
|
||||
android:textColor="?attr/textFillColor"
|
||||
android:icon="@drawable/ic_github_36">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="https://github.com/hufrea/byedpi/tree/main#readme-ov-file" />
|
||||
android:data="@string/byedpi_docs" />
|
||||
</Preference>
|
||||
|
||||
<androidx.preference.PreferenceCategory
|
||||
@ -27,14 +26,14 @@
|
||||
android:title="@string/byedpi_proxy_port_setting"
|
||||
android:inputType="number"
|
||||
android:defaultValue="1080"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<com.takisoft.preferencex.EditTextPreference
|
||||
android:key="byedpi_max_connections"
|
||||
android:title="@string/byedpi_max_connections_setting"
|
||||
android:inputType="number"
|
||||
android:defaultValue="512"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<com.takisoft.preferencex.EditTextPreference
|
||||
android:key="byedpi_buffer_size"
|
||||
@ -48,11 +47,38 @@
|
||||
android:title="@string/byedpi_no_domain_setting"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="byedpi_tcp_fast_open"
|
||||
android:title="@string/byedpi_tcp_fast_open_setting"
|
||||
android:defaultValue="false" />
|
||||
|
||||
</androidx.preference.PreferenceCategory>
|
||||
|
||||
<androidx.preference.PreferenceCategory
|
||||
android:title="@string/byedpi_desync">
|
||||
|
||||
<DropDownPreference
|
||||
android:key="byedpi_hosts_mode"
|
||||
android:title="@string/byedpi_hosts_mode_setting"
|
||||
android:entries="@array/byedpi_hosts_modes"
|
||||
android:entryValues="@array/byedpi_hosts_modes_entries"
|
||||
android:defaultValue="disable"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<com.takisoft.preferencex.EditTextPreference
|
||||
android:key="byedpi_hosts_blacklist"
|
||||
android:title="@string/byedpi_hosts_blacklist_setting"
|
||||
android:dialogTitle="@string/byedpi_hosts_blacklist_setting"
|
||||
android:inputType="textMultiLine"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<com.takisoft.preferencex.EditTextPreference
|
||||
android:key="byedpi_hosts_whitelist"
|
||||
android:title="@string/byedpi_hosts_whitelist_setting"
|
||||
android:dialogTitle="@string/byedpi_hosts_whitelist_setting"
|
||||
android:inputType="textMultiLine"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<com.takisoft.preferencex.EditTextPreference
|
||||
android:key="byedpi_default_ttl"
|
||||
android:title="@string/byedpi_default_ttl_setting"
|
||||
@ -68,6 +94,55 @@
|
||||
android:defaultValue="disorder"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<com.takisoft.preferencex.EditTextPreference
|
||||
android:key="byedpi_split_position"
|
||||
android:title="@string/byedpi_split_position_setting"
|
||||
android:inputType="numberSigned"
|
||||
android:defaultValue="1"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="byedpi_split_at_host"
|
||||
android:title="@string/byedpi_split_at_host_setting"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="byedpi_drop_sack"
|
||||
android:title="@string/byedpi_drop_sack_setting"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<com.takisoft.preferencex.EditTextPreference
|
||||
android:key="byedpi_fake_ttl"
|
||||
android:title="@string/byedpi_fake_ttl_setting"
|
||||
android:inputType="number"
|
||||
android:defaultValue="8"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<com.takisoft.preferencex.EditTextPreference
|
||||
android:key="byedpi_fake_offset"
|
||||
android:title="@string/byedpi_fake_offset_setting"
|
||||
android:inputType="number"
|
||||
android:defaultValue="0"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<com.takisoft.preferencex.EditTextPreference
|
||||
android:key="byedpi_fake_sni"
|
||||
android:title="@string/sni_of_fake_packet"
|
||||
android:defaultValue="www.iana.org"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<com.takisoft.preferencex.EditTextPreference
|
||||
android:key="byedpi_oob_data"
|
||||
android:title="@string/oob_data"
|
||||
android:defaultValue="a"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
</androidx.preference.PreferenceCategory>
|
||||
|
||||
<androidx.preference.PreferenceCategory
|
||||
android:title="@string/byedpi_protocols_category"
|
||||
android:summary="@string/byedpi_protocols_hint">
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="byedpi_desync_http"
|
||||
android:title="@string/desync_http"
|
||||
@ -83,36 +158,10 @@
|
||||
android:title="@string/desync_udp"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<com.takisoft.preferencex.EditTextPreference
|
||||
android:key="byedpi_split_position"
|
||||
android:title="@string/byedpi_split_position_setting"
|
||||
android:inputType="numberSigned"
|
||||
android:defaultValue="3"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
</androidx.preference.PreferenceCategory>
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="byedpi_split_at_host"
|
||||
android:title="@string/byedpi_split_at_host_setting"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<com.takisoft.preferencex.EditTextPreference
|
||||
android:key="byedpi_fake_ttl"
|
||||
android:title="@string/byedpi_fake_ttl_setting"
|
||||
android:inputType="number"
|
||||
android:defaultValue="8"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<com.takisoft.preferencex.EditTextPreference
|
||||
android:key="byedpi_fake_sni"
|
||||
android:title="@string/sni_of_fake_packet"
|
||||
android:defaultValue="www.iana.org"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<com.takisoft.preferencex.EditTextPreference
|
||||
android:key="byedpi_oob_data"
|
||||
android:title="@string/oob_data"
|
||||
android:defaultValue="a"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
<androidx.preference.PreferenceCategory
|
||||
android:title="@string/desync_http_category">
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="byedpi_host_mixed_case"
|
||||
@ -129,6 +178,11 @@
|
||||
android:title="@string/byedpi_host_remove_spaces_setting"
|
||||
android:defaultValue="false"/>
|
||||
|
||||
</androidx.preference.PreferenceCategory>
|
||||
|
||||
<androidx.preference.PreferenceCategory
|
||||
android:title="@string/desync_https_category">
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="byedpi_tlsrec_enabled"
|
||||
android:title="@string/byedpi_tlsrec_enabled_setting"
|
||||
@ -148,4 +202,16 @@
|
||||
|
||||
</androidx.preference.PreferenceCategory>
|
||||
|
||||
<androidx.preference.PreferenceCategory
|
||||
android:title="@string/desync_udp_category">
|
||||
|
||||
<com.takisoft.preferencex.EditTextPreference
|
||||
android:key="byedpi_udp_fake_count"
|
||||
android:title="@string/byedpi_udp_fake_count"
|
||||
android:inputType="number"
|
||||
android:defaultValue="0"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
</androidx.preference.PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
@ -27,7 +27,12 @@
|
||||
android:key="dns_ip"
|
||||
android:title="@string/dbs_ip_setting"
|
||||
android:defaultValue="1.1.1.1"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="ipv6_enable"
|
||||
android:title="@string/ipv6_setting"
|
||||
android:defaultValue="false" />
|
||||
|
||||
</androidx.preference.PreferenceCategory>
|
||||
|
||||
|
||||
1
fastlane/metadata/android/en-US/full_description.txt
Normal file
@ -0,0 +1 @@
|
||||
<p><i>ByeDPI</i> runs a local VPN service to bypass DPI (Deep Packet Inspection) and censorship. It runs a SOCKS5 proxy <a href='https://github.com/hufrea/byedpi' target='_blank' rel='nofollow noopener'>ByeDPI</a> and redirects all traffic through it.</p><p>To bypass some blocks, you may need to change the settings. More about the various settings can be found in the <a href='https://github.com/hufrea/byedpi/blob/main/README.md' target='_blank' rel='nofollow noopener'>ByeDPI documentation</a>.</p><p>The application uses the VPN mode on Android to redirect traffic, but does not send anything to a remote server. It does not encrypt traffic and does not hide your IP address.</p>
|
||||
BIN
fastlane/metadata/android/en-US/images/icon.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 29 KiB |
1
fastlane/metadata/android/en-US/short_description.txt
Normal file
@ -0,0 +1 @@
|
||||
Bypass censorship on Android
|
||||
1
fastlane/metadata/android/ru-RU/full_description.txt
Normal file
@ -0,0 +1 @@
|
||||
<p><i>ByeDPI</i> запускает локальный VPN-сервис для обхода DPI (Deep Packet Inspection) и цензуры. Приложение локально запускает SOCKS5-прокси <a href='https://github.com/hufrea/byedpi' target='_blank' rel='nofollow noopener'>ByeDPI</a> и перенаправляет весь трафик через него.</p><p>Для обхода некоторых блокировок может потребоваться изменить настройки. Подробнее о различных настройках можно прочитать в <a href='https://github.com/hufrea/byedpi/blob/main/README.md' target='_blank' rel='nofollow noopener'>документации ByeDPI</a>.</p><p>Приложение использует VPN-режим на Android для перенаправления трафика, но не передает ничего на удаленный сервер. Оно не шифрует трафик и не скрывает ваш IP-адрес.</p>
|
||||
1
fastlane/metadata/android/ru-RU/short_description.txt
Normal file
@ -0,0 +1 @@
|
||||
Обход цензуры на Android
|
||||