Initial commit of SSH Proxy VPN Android app.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
commit
46fcf18bed
37
.gitignore
vendored
Normal file
37
.gitignore
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# Gradle / Android
|
||||||
|
.gradle/
|
||||||
|
**/build/
|
||||||
|
**/.cxx/
|
||||||
|
local.properties
|
||||||
|
*.apk
|
||||||
|
*.aab
|
||||||
|
*.ap_
|
||||||
|
*.dex
|
||||||
|
captures/
|
||||||
|
.externalNativeBuild/
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# Native duplicate (used copy lives in app/src/main/cpp)
|
||||||
|
/hev-socks5-tunnel/
|
||||||
|
|
||||||
|
# Logs / crash dumps
|
||||||
|
*.log
|
||||||
|
hs_err_pid*.log
|
||||||
|
replay_pid*.log
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Secrets / keys
|
||||||
|
*.jks
|
||||||
|
*.keystore
|
||||||
|
id_rsa
|
||||||
|
id_ed25519
|
||||||
|
*.pem
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
104
README.md
Normal file
104
README.md
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
# SSH Proxy VPN (Android)
|
||||||
|
|
||||||
|
Приложение поднимает **SSH-туннель по ключу**, внутри него — **SOCKS5** (`ssh -D`), и через **VpnService** направляет **весь трафик Android** в локальный SOCKS.
|
||||||
|
|
||||||
|
## Схема
|
||||||
|
|
||||||
|
```
|
||||||
|
Приложения Android
|
||||||
|
↓
|
||||||
|
VpnService (TUN 10.8.0.2)
|
||||||
|
↓
|
||||||
|
tun2socks (native)
|
||||||
|
↓
|
||||||
|
SOCKS5 127.0.0.1:10808 ← SSH dynamic forward (-D)
|
||||||
|
↓
|
||||||
|
SSH-сервер
|
||||||
|
↓
|
||||||
|
Интернет
|
||||||
|
```
|
||||||
|
|
||||||
|
## Сборка
|
||||||
|
|
||||||
|
1. Откройте папку `D:\SshProxyVpn` в **Android Studio** (Hedgehog+).
|
||||||
|
2. Подключите native-модуль **hev-socks5-tunnel** (обязательно для реальной маршрутизации):
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cd D:\SshProxyVpn
|
||||||
|
.\setup-native.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
Или вручную:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd D:/SshProxyVpn/app/src/main/cpp
|
||||||
|
git clone --recursive https://github.com/heiher/hev-socks5-tunnel.git
|
||||||
|
cd ../../..
|
||||||
|
powershell -ExecutionPolicy Bypass -File fix-symlinks.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Windows:** Git часто не создаёт symlink-заголовки (`../src/...`). Скрипт `fix-symlinks.ps1` заменяет их на реальные `.h` файлы. Без этого сборка падает с ошибкой `hev-memory-allocator-api.h`.
|
||||||
|
|
||||||
|
3. Соберите проект: **Build → Make Project**.
|
||||||
|
4. Установите APK на телефон (minSdk 26).
|
||||||
|
|
||||||
|
> Без `hev-socks5-tunnel` SSH подключится, но VPN не пропустит трафик — приложение покажет ошибку native-модуля.
|
||||||
|
|
||||||
|
## Настройка
|
||||||
|
|
||||||
|
| Поле | Пример |
|
||||||
|
|------|--------|
|
||||||
|
| SSH хост | `203.0.113.10` |
|
||||||
|
| Порт | `22` |
|
||||||
|
| Пользователь | `ubuntu` |
|
||||||
|
| Ключ | OpenSSH private key (`id_ed25519`, `id_rsa`) |
|
||||||
|
| Passphrase | если ключ защищён |
|
||||||
|
| SOCKS порт | `10808` (локальный) |
|
||||||
|
|
||||||
|
На сервере в `~/.ssh/authorized_keys` должен быть ваш **публичный** ключ.
|
||||||
|
|
||||||
|
## Как работает код
|
||||||
|
|
||||||
|
| Компонент | Файл |
|
||||||
|
|-----------|------|
|
||||||
|
| UI и сохранение настроек | `MainActivity.kt` |
|
||||||
|
| SSH + SOCKS (локальный SOCKS5 через SSH direct-tcpip) | `ssh/SshTunnelManager.kt`, `ssh/LocalSocks5Proxy.kt` |
|
||||||
|
| Foreground-сервис оркестрации | `service/TunnelService.kt` |
|
||||||
|
| VPN-интерфейс | `vpn/ProxyVpnService.kt` |
|
||||||
|
| TUN → SOCKS | `vpn/Tun2Socks.kt` + `cpp/tun2socks_jni.cpp` |
|
||||||
|
|
||||||
|
**Важно:** перед включением VPN вызывается `VpnService.protect()` для SSH-сокета, иначе SSH уйдёт в собственный туннель и соединение оборвётся.
|
||||||
|
|
||||||
|
## Разрешения
|
||||||
|
|
||||||
|
- `INTERNET` — SSH
|
||||||
|
- `FOREGROUND_SERVICE` — фоновый туннель
|
||||||
|
- **VPN** — системный запрос при первом подключении
|
||||||
|
|
||||||
|
## Ограничения
|
||||||
|
|
||||||
|
- Нужен **NDK** для сборки native-части.
|
||||||
|
- Производительность ниже, чем у WireGuard/OpenVPN.
|
||||||
|
- Некоторые приложения с certificate pinning могут не работать через прокси.
|
||||||
|
- Для production добавьте проверку **host key** SSH (сейчас есть опция «принимать неизвестный ключ»).
|
||||||
|
|
||||||
|
## Тест SSH без VPN
|
||||||
|
|
||||||
|
На ПК с тем же ключом:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh -i id_ed25519 -D 10808 user@server
|
||||||
|
curl --socks5 127.0.0.1:10808 https://ifconfig.me
|
||||||
|
```
|
||||||
|
|
||||||
|
На Android SOCKS доступен только внутри приложения на `127.0.0.1:10808` после подключения SSH.
|
||||||
|
|
||||||
|
## Структура проекта
|
||||||
|
|
||||||
|
```
|
||||||
|
SshProxyVpn/
|
||||||
|
app/src/main/java/com/sshproxy/vpn/
|
||||||
|
app/src/main/cpp/
|
||||||
|
tun2socks_jni.cpp
|
||||||
|
hev-socks5-tunnel/ ← клонировать вручную
|
||||||
|
```
|
||||||
75
app/build.gradle.kts
Normal file
75
app/build.gradle.kts
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
plugins {
|
||||||
|
id("com.android.application")
|
||||||
|
id("org.jetbrains.kotlin.android")
|
||||||
|
id("org.jetbrains.kotlin.plugin.parcelize")
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "com.sshproxy.vpn"
|
||||||
|
compileSdk = 34
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
applicationId = "com.sshproxy.vpn"
|
||||||
|
minSdk = 26
|
||||||
|
targetSdk = 34
|
||||||
|
versionCode = 1
|
||||||
|
versionName = "1.0.0"
|
||||||
|
|
||||||
|
ndk {
|
||||||
|
abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
|
||||||
|
}
|
||||||
|
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
cppFlags += "-std=c++17"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
isMinifyEnabled = false
|
||||||
|
proguardFiles(
|
||||||
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
|
"proguard-rules.pro"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "17"
|
||||||
|
}
|
||||||
|
|
||||||
|
buildFeatures {
|
||||||
|
viewBinding = true
|
||||||
|
}
|
||||||
|
|
||||||
|
packaging {
|
||||||
|
jniLibs {
|
||||||
|
useLegacyPackaging = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
path = file("src/main/cpp/CMakeLists.txt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation("androidx.core:core-ktx:1.13.1")
|
||||||
|
implementation("androidx.appcompat:appcompat:1.7.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")
|
||||||
|
implementation("androidx.recyclerview:recyclerview:1.3.2")
|
||||||
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1")
|
||||||
|
implementation("com.github.mwiede:jsch:0.2.20")
|
||||||
|
}
|
||||||
0
app/proguard-rules.pro
vendored
Normal file
0
app/proguard-rules.pro
vendored
Normal file
71
app/src/main/AndroidManifest.xml
Normal file
71
app/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
|
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
|
||||||
|
tools:ignore="QueryAllPackagesPermission" />
|
||||||
|
|
||||||
|
<queries>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent>
|
||||||
|
</queries>
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:name=".TunnelApplication"
|
||||||
|
android:allowBackup="false"
|
||||||
|
android:extractNativeLibs="true"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:supportsRtl="true"
|
||||||
|
android:theme="@style/Theme.SshProxyVpn">
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".MainActivity"
|
||||||
|
android:exported="true"
|
||||||
|
android:launchMode="singleTop"
|
||||||
|
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".AppExclusionActivity"
|
||||||
|
android:exported="false"
|
||||||
|
android:parentActivityName=".MainActivity" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".TunnelSettingsActivity"
|
||||||
|
android:exported="false"
|
||||||
|
android:parentActivityName=".MainActivity" />
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".service.TunnelService"
|
||||||
|
android:exported="false"
|
||||||
|
android:stopWithTask="false"
|
||||||
|
android:foregroundServiceType="specialUse">
|
||||||
|
<property
|
||||||
|
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
||||||
|
android:value="SSH VPN tunnel" />
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".vpn.ProxyVpnService"
|
||||||
|
android:exported="false"
|
||||||
|
android:stopWithTask="false"
|
||||||
|
android:permission="android.permission.BIND_VPN_SERVICE">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.net.VpnService" />
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
</application>
|
||||||
|
</manifest>
|
||||||
92
app/src/main/cpp/CMakeLists.txt
Normal file
92
app/src/main/cpp/CMakeLists.txt
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.22.1)
|
||||||
|
project(tun2socks_jni)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
enable_language(ASM)
|
||||||
|
|
||||||
|
set(HEV_DIR ${CMAKE_CURRENT_SOURCE_DIR}/hev-socks5-tunnel)
|
||||||
|
|
||||||
|
find_library(log-lib log)
|
||||||
|
|
||||||
|
if(EXISTS ${HEV_DIR}/src/hev-main.c)
|
||||||
|
message(STATUS "Building with hev-socks5-tunnel")
|
||||||
|
|
||||||
|
# --- yaml ---
|
||||||
|
file(GLOB YAML_SOURCES ${HEV_DIR}/third-part/yaml/src/*.c)
|
||||||
|
add_library(hev_yaml STATIC ${YAML_SOURCES})
|
||||||
|
target_include_directories(hev_yaml PUBLIC ${HEV_DIR}/third-part/yaml/src)
|
||||||
|
target_compile_definitions(hev_yaml PRIVATE
|
||||||
|
YAML_VERSION_MAJOR=0
|
||||||
|
YAML_VERSION_MINOR=2
|
||||||
|
YAML_VERSION_PATCH=5
|
||||||
|
YAML_VERSION_STRING=\"0.2.5\"
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- lwip ---
|
||||||
|
file(GLOB_RECURSE LWIP_SOURCES ${HEV_DIR}/third-part/lwip/src/*.c)
|
||||||
|
add_library(hev_lwip STATIC ${LWIP_SOURCES})
|
||||||
|
target_include_directories(hev_lwip PUBLIC
|
||||||
|
${HEV_DIR}/third-part/lwip/src/include
|
||||||
|
${HEV_DIR}/third-part/lwip/src/ports/include
|
||||||
|
)
|
||||||
|
target_compile_definitions(hev_lwip PRIVATE FD_SET_DEFINED SOCKLEN_T_DEFINED)
|
||||||
|
|
||||||
|
# --- hev-task-system ---
|
||||||
|
file(GLOB_RECURSE TASK_SOURCES ${HEV_DIR}/third-part/hev-task-system/src/*.c)
|
||||||
|
set(TASK_ASM ${HEV_DIR}/third-part/hev-task-system/src/kern/task/hev-task-execute.S)
|
||||||
|
add_library(hev_task STATIC ${TASK_SOURCES} ${TASK_ASM})
|
||||||
|
target_include_directories(hev_task PUBLIC
|
||||||
|
${HEV_DIR}/third-part/hev-task-system/include
|
||||||
|
${HEV_DIR}/third-part/hev-task-system/src
|
||||||
|
)
|
||||||
|
set_source_files_properties(${TASK_ASM} PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp")
|
||||||
|
target_compile_definitions(hev_task PRIVATE
|
||||||
|
ENABLE_STACK_OVERFLOW_DETECTION=1
|
||||||
|
ENABLE_MEMALLOC_SLICE=1
|
||||||
|
ENABLE_IO_SPLICE_SYSCALL=1
|
||||||
|
CONFIG_STACK_BACKEND=STACK_MMAP
|
||||||
|
CONFIG_STACK_OVERFLOW_DETECTION=1
|
||||||
|
CONFIG_MEMALLOC_SLICE_ALIGN=16
|
||||||
|
CONFIG_MEMALLOC_SLICE_MAX_SIZE=4096
|
||||||
|
CONFIG_MEMALLOC_SLICE_MAX_COUNT=1000
|
||||||
|
CONFIG_SCHED_CLOCK=CLOCK_NONE
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- hev-socks5-tunnel (без hev-jni.c — свой JNI) ---
|
||||||
|
file(GLOB HEV_MAIN_SOURCES ${HEV_DIR}/src/*.c)
|
||||||
|
file(GLOB_RECURSE HEV_CORE_SOURCES ${HEV_DIR}/src/core/src/*.c)
|
||||||
|
file(GLOB HEV_MISC_SOURCES ${HEV_DIR}/src/misc/*.c)
|
||||||
|
list(FILTER HEV_MAIN_SOURCES EXCLUDE REGEX ".*/hev-jni\\.c$")
|
||||||
|
|
||||||
|
add_library(hev_socks5 STATIC
|
||||||
|
${HEV_MAIN_SOURCES}
|
||||||
|
${HEV_CORE_SOURCES}
|
||||||
|
${HEV_MISC_SOURCES}
|
||||||
|
)
|
||||||
|
target_include_directories(hev_socks5 PUBLIC
|
||||||
|
${HEV_DIR}/src
|
||||||
|
${HEV_DIR}/src/core/include
|
||||||
|
${HEV_DIR}/src/misc
|
||||||
|
${HEV_DIR}/third-part/yaml/include
|
||||||
|
${HEV_DIR}/third-part/lwip/src/include
|
||||||
|
${HEV_DIR}/third-part/lwip/src/ports/include
|
||||||
|
${HEV_DIR}/third-part/hev-task-system/include
|
||||||
|
)
|
||||||
|
target_compile_definitions(hev_socks5 PRIVATE
|
||||||
|
ENABLE_LIBRARY=1
|
||||||
|
FD_SET_DEFINED=1
|
||||||
|
SOCKLEN_T_DEFINED=1
|
||||||
|
COMMIT_ID=\"embedded\"
|
||||||
|
)
|
||||||
|
target_link_libraries(hev_socks5 PUBLIC hev_yaml hev_lwip hev_task)
|
||||||
|
|
||||||
|
add_library(tun2socks_jni SHARED tun2socks_jni.cpp)
|
||||||
|
target_compile_definitions(tun2socks_jni PRIVATE USE_HEV_TUN2SOCKS=1)
|
||||||
|
target_include_directories(tun2socks_jni PRIVATE ${HEV_DIR}/src)
|
||||||
|
target_link_libraries(tun2socks_jni hev_socks5 ${log-lib} atomic)
|
||||||
|
else()
|
||||||
|
message(WARNING "hev-socks5-tunnel not found — clone into app/src/main/cpp/hev-socks5-tunnel")
|
||||||
|
add_library(tun2socks_jni SHARED tun2socks_jni.cpp)
|
||||||
|
target_link_libraries(tun2socks_jni ${log-lib})
|
||||||
|
endif()
|
||||||
115
app/src/main/cpp/hev-socks5-tunnel/.clang-format
Normal file
115
app/src/main/cpp/hev-socks5-tunnel/.clang-format
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: TopLevel
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: MultiLine
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BraceWrapping:
|
||||||
|
AfterClass: true
|
||||||
|
AfterControlStatement: false
|
||||||
|
AfterEnum: true
|
||||||
|
AfterFunction: true
|
||||||
|
AfterNamespace: true
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: true
|
||||||
|
AfterUnion: true
|
||||||
|
AfterExternBlock: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: true
|
||||||
|
SplitEmptyRecord: true
|
||||||
|
SplitEmptyNamespace: true
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BreakBeforeInheritanceComma: false
|
||||||
|
BreakInheritanceList: BeforeColon
|
||||||
|
BreakBeforeTernaryOperators: false
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakStringLiterals: false
|
||||||
|
ColumnLimit: 80
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: false
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
FixNamespaceComments: false
|
||||||
|
ForEachMacros:
|
||||||
|
- foreach
|
||||||
|
- Q_FOREACH
|
||||||
|
- BOOST_FOREACH
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 1
|
||||||
|
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||||
|
Priority: 3
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 1
|
||||||
|
IncludeIsMainRegex: '(Test)?$'
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentWidth: 4
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: Inner
|
||||||
|
ObjCBinPackProtocolList: Auto
|
||||||
|
ObjCBlockIndentWidth: 4
|
||||||
|
ObjCSpaceAfterProperty: true
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PenaltyBreakAssignment: 10
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 30
|
||||||
|
PenaltyBreakComment: 10
|
||||||
|
PenaltyBreakFirstLessLess: 0
|
||||||
|
PenaltyBreakString: 10
|
||||||
|
PenaltyBreakTemplateDeclaration: 10
|
||||||
|
PenaltyExcessCharacter: 100
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 60
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReflowComments: false
|
||||||
|
SortIncludes: false
|
||||||
|
SortUsingDeclarations: false
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterTemplateKeyword: true
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: Always
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Cpp03
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
||||||
|
...
|
||||||
11
app/src/main/cpp/hev-socks5-tunnel/.dockerignore
Normal file
11
app/src/main/cpp/hev-socks5-tunnel/.dockerignore
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/.idea/
|
||||||
|
/.vscode/
|
||||||
|
|
||||||
|
/.git/
|
||||||
|
/.github/
|
||||||
|
/README.md
|
||||||
|
/License
|
||||||
|
|
||||||
|
/Dockerfile
|
||||||
|
|
||||||
|
/conf/
|
||||||
408
app/src/main/cpp/hev-socks5-tunnel/.github/workflows/build.yaml
vendored
Normal file
408
app/src/main/cpp/hev-socks5-tunnel/.github/workflows/build.yaml
vendored
Normal file
@ -0,0 +1,408 @@
|
|||||||
|
name: "Build"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
release:
|
||||||
|
types:
|
||||||
|
- published
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
source:
|
||||||
|
name: Source
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
BRANCH_NAME: ${{ github.base_ref || github.ref_name }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
submodules: true
|
||||||
|
- name: Gen Source
|
||||||
|
run: |
|
||||||
|
REV_ID=$(git rev-parse --short HEAD)
|
||||||
|
mkdir -p hev-socks5-tunnel-${{ env.BRANCH_NAME }}
|
||||||
|
git ls-files --recurse-submodules | tar c -O -T- | tar x -C hev-socks5-tunnel-${{ env.BRANCH_NAME }}
|
||||||
|
echo ${REV_ID} > hev-socks5-tunnel-${{ env.BRANCH_NAME }}/.rev-id
|
||||||
|
tar cJf hev-socks5-tunnel-${{ env.BRANCH_NAME }}.tar.xz hev-socks5-tunnel-${{ env.BRANCH_NAME }}
|
||||||
|
- name: Upload source
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: hev-socks5-tunnel-${{ env.BRANCH_NAME }}.tar.xz
|
||||||
|
path: hev-socks5-tunnel-${{ env.BRANCH_NAME }}.tar.xz
|
||||||
|
if-no-files-found: error
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
linux:
|
||||||
|
name: Linux
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- name: arm64
|
||||||
|
tool: aarch64-unknown-linux-musl
|
||||||
|
- name: arm32
|
||||||
|
tool: arm-unknown-linux-musleabi
|
||||||
|
- name: arm32hf
|
||||||
|
tool: arm-unknown-linux-musleabihf
|
||||||
|
- name: arm32v7
|
||||||
|
tool: armv7-unknown-linux-musleabi
|
||||||
|
- name: arm32v7hf
|
||||||
|
tool: armv7-unknown-linux-musleabihf
|
||||||
|
- name: i586
|
||||||
|
tool: i586-unknown-linux-musl
|
||||||
|
- name: i686
|
||||||
|
tool: i686-unknown-linux-musl
|
||||||
|
- name: loong64
|
||||||
|
tool: loongarch64-unknown-linux-musl
|
||||||
|
- name: m68k
|
||||||
|
tool: m68k-unknown-linux-musl
|
||||||
|
- name: microblazeel
|
||||||
|
tool: microblazeel-xilinx-linux-musl
|
||||||
|
- name: microblaze
|
||||||
|
tool: microblaze-xilinx-linux-musl
|
||||||
|
- name: mips64el
|
||||||
|
tool: mips64el-unknown-linux-musl
|
||||||
|
- name: mips64
|
||||||
|
tool: mips64-unknown-linux-musl
|
||||||
|
- name: mips32el
|
||||||
|
tool: mipsel-unknown-linux-musl
|
||||||
|
- name: mips32elsf
|
||||||
|
tool: mipsel-unknown-linux-muslsf
|
||||||
|
- name: mips32
|
||||||
|
tool: mips-unknown-linux-musl
|
||||||
|
- name: mips32sf
|
||||||
|
tool: mips-unknown-linux-muslsf
|
||||||
|
- name: or1k
|
||||||
|
tool: or1k-unknown-linux-musl
|
||||||
|
- name: powerpc64le
|
||||||
|
tool: powerpc64le-unknown-linux-musl
|
||||||
|
- name: powerpc64
|
||||||
|
tool: powerpc64-unknown-linux-musl
|
||||||
|
- name: powerpcle
|
||||||
|
tool: powerpcle-unknown-linux-musl
|
||||||
|
- name: powerpc
|
||||||
|
tool: powerpc-unknown-linux-musl
|
||||||
|
- name: riscv32
|
||||||
|
tool: riscv32-unknown-linux-musl
|
||||||
|
- name: riscv64
|
||||||
|
tool: riscv64-unknown-linux-musl
|
||||||
|
- name: s390x
|
||||||
|
tool: s390x-ibm-linux-musl
|
||||||
|
- name: sh4
|
||||||
|
tool: sh4-multilib-linux-musl
|
||||||
|
- name: x86_64
|
||||||
|
tool: x86_64-unknown-linux-musl
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
submodules: true
|
||||||
|
- name: Build ${{ matrix.name }}
|
||||||
|
run: |
|
||||||
|
sudo mkdir -p /opt/x-tools
|
||||||
|
wget https://github.com/cross-tools/musl-cross/releases/download/20260515/${{ matrix.tool }}.tar.xz
|
||||||
|
sudo tar xf ${{ matrix.tool }}.tar.xz -C /opt/x-tools
|
||||||
|
make CROSS_PREFIX=/opt/x-tools/${{ matrix.tool }}/bin/${{ matrix.tool }}- CFLAGS=${{ matrix.env.CFLAGS }} ENABLE_STATIC=1 -j`nproc`
|
||||||
|
cp bin/hev-socks5-tunnel hev-socks5-tunnel-linux-${{ matrix.name }}
|
||||||
|
- name: Upload ${{ matrix.name }}
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: hev-socks5-tunnel-linux-${{ matrix.name }}
|
||||||
|
path: hev-socks5-tunnel-linux-${{ matrix.name }}
|
||||||
|
if-no-files-found: error
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
macos:
|
||||||
|
name: macOS
|
||||||
|
runs-on: macos-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- name: arm64
|
||||||
|
flags: -arch arm64 -mmacosx-version-min=11.0
|
||||||
|
- name: x86_64
|
||||||
|
flags: -arch x86_64 -mmacosx-version-min=10.6
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
submodules: true
|
||||||
|
- name: Build ${{ matrix.name }}
|
||||||
|
run: |
|
||||||
|
make CC=clang CFLAGS="${{ matrix.flags }}" LFLAGS="${{ matrix.flags }}" -j $(sysctl -n hw.logicalcpu)
|
||||||
|
cp bin/hev-socks5-tunnel hev-socks5-tunnel-darwin-${{ matrix.name }}
|
||||||
|
- name: Upload ${{ matrix.name }}
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: hev-socks5-tunnel-darwin-${{ matrix.name }}
|
||||||
|
path: hev-socks5-tunnel-darwin-${{ matrix.name }}
|
||||||
|
if-no-files-found: error
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
freebsd:
|
||||||
|
name: FreeBSD
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
submodules: true
|
||||||
|
- name: Build
|
||||||
|
uses: vmactions/freebsd-vm@v1
|
||||||
|
with:
|
||||||
|
usesh: true
|
||||||
|
prepare: |
|
||||||
|
pkg install -y gmake gcc
|
||||||
|
run: |
|
||||||
|
gmake
|
||||||
|
cp bin/hev-socks5-tunnel hev-socks5-tunnel-freebsd-x86_64
|
||||||
|
- name: Upload
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: hev-socks5-tunnel-freebsd-x86_64
|
||||||
|
path: hev-socks5-tunnel-freebsd-x86_64
|
||||||
|
if-no-files-found: error
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
windows:
|
||||||
|
name: Windows
|
||||||
|
runs-on: windows-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: cmd
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
submodules: true
|
||||||
|
- name: Setup MSYS2
|
||||||
|
uses: msys2/setup-msys2@v2
|
||||||
|
with:
|
||||||
|
msystem: MSYS
|
||||||
|
location: D:\msys2
|
||||||
|
update: true
|
||||||
|
install: >-
|
||||||
|
gcc
|
||||||
|
git
|
||||||
|
make
|
||||||
|
wget
|
||||||
|
zip
|
||||||
|
- name: Build
|
||||||
|
shell: msys2 {0}
|
||||||
|
run: |
|
||||||
|
export MSYS=winsymlinks:native
|
||||||
|
git clone --depth=1 --recursive file://`pwd` work; cd work
|
||||||
|
make -j`nproc`
|
||||||
|
mkdir hev-socks5-tunnel
|
||||||
|
cp bin/hev-socks5-tunnel* hev-socks5-tunnel
|
||||||
|
cp third-part/wintun/bin/wintun.dll hev-socks5-tunnel
|
||||||
|
wget -P hev-socks5-tunnel https://github.com/heiher/msys2/releases/latest/download/msys-2.0.dll
|
||||||
|
zip -r ../hev-socks5-tunnel-win64.zip hev-socks5-tunnel
|
||||||
|
- name: Upload ${{ matrix.name }}
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: hev-socks5-tunnel-win64.zip
|
||||||
|
path: hev-socks5-tunnel-win64.zip
|
||||||
|
if-no-files-found: error
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
release:
|
||||||
|
name: Release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs:
|
||||||
|
- source
|
||||||
|
- linux
|
||||||
|
- macos
|
||||||
|
- freebsd
|
||||||
|
- windows
|
||||||
|
if: github.event_name == 'release'
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
- name: Download artifacts
|
||||||
|
uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
path: release
|
||||||
|
pattern: "hev-*"
|
||||||
|
merge-multiple: true
|
||||||
|
- name: Upload artifacts
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
for i in release/hev-*; do
|
||||||
|
gh release upload ${{ github.event.release.tag_name }} $i
|
||||||
|
done
|
||||||
|
|
||||||
|
apple:
|
||||||
|
name: Apple
|
||||||
|
runs-on: macos-latest
|
||||||
|
if: github.event_name != 'release'
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
submodules: true
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
./build-apple.sh
|
||||||
|
|
||||||
|
android:
|
||||||
|
name: Android
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name != 'release'
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
submodules: true
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
wget https://dl.google.com/android/repository/android-ndk-r27d-linux.zip
|
||||||
|
unzip android-ndk-r27d-linux.zip
|
||||||
|
ln -sf . jni
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
./android-ndk-r27d/ndk-build
|
||||||
|
|
||||||
|
llvm:
|
||||||
|
name: LLVM
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name != 'release'
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
submodules: true
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
sudo apt install -y clang
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
make CC=clang ENABLE_STATIC=1 -j`nproc`
|
||||||
|
|
||||||
|
docker:
|
||||||
|
name: Build Docker Image
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
platform:
|
||||||
|
- linux/amd64
|
||||||
|
- linux/386
|
||||||
|
- linux/arm64/v8
|
||||||
|
- linux/arm/v7
|
||||||
|
- linux/arm/v6
|
||||||
|
- linux/riscv64
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
submodules: true
|
||||||
|
- name: Prepare QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
- name: Prepare Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
- name: Prepare Repo Name
|
||||||
|
id: repo
|
||||||
|
run: |
|
||||||
|
echo "repository=${GITHUB_REPOSITORY@L}" >> $GITHUB_OUTPUT
|
||||||
|
- name: Prepare Digest
|
||||||
|
run: |
|
||||||
|
platform=${{ matrix.platform }}
|
||||||
|
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||||
|
- name: Login GitHub Packages Docker Image Repository
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Build and Push Docker Image
|
||||||
|
id: build
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile
|
||||||
|
platforms: ${{ matrix.platform }}
|
||||||
|
provenance: false
|
||||||
|
outputs: type=image,name=ghcr.io/${{ steps.repo.outputs.repository }},push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }}
|
||||||
|
cache-from: type=gha,scope=${{ matrix.platform }}
|
||||||
|
cache-to: type=gha,mode=max,scope=${{ matrix.platform }}
|
||||||
|
- name: Export Digest
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
run: |
|
||||||
|
mkdir -p /tmp/digests
|
||||||
|
digest="${{ steps.build.outputs.digest }}"
|
||||||
|
touch "/tmp/digests/${digest#sha256:}"
|
||||||
|
- name: Upload Digest
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
with:
|
||||||
|
name: digests-${{ env.PLATFORM_PAIR }}
|
||||||
|
path: /tmp/digests/*
|
||||||
|
if-no-files-found: error
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
docker-merge:
|
||||||
|
name: Merge Docker Image Tags
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
needs:
|
||||||
|
- docker
|
||||||
|
permissions:
|
||||||
|
packages: write
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- name: Download Digests
|
||||||
|
uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
path: /tmp/digests
|
||||||
|
pattern: digests-*
|
||||||
|
merge-multiple: true
|
||||||
|
- name: Prepare Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
- name: Prepare Repo Name
|
||||||
|
id: repo
|
||||||
|
run: |
|
||||||
|
echo "repository=${GITHUB_REPOSITORY@L}" >> $GITHUB_OUTPUT
|
||||||
|
- name: Login GitHub Packages Docker Image Repository
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Format Docker Image Meta
|
||||||
|
uses: docker/metadata-action@v5
|
||||||
|
id: docker_meta
|
||||||
|
with:
|
||||||
|
images: ghcr.io/${{ steps.repo.outputs.repository }}
|
||||||
|
tags: |
|
||||||
|
type=ref,event=branch
|
||||||
|
type=ref,event=pr
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
|
type=raw,value=nightly,enable={{is_default_branch}}
|
||||||
|
- name: Create Manifest List and Push
|
||||||
|
working-directory: /tmp/digests
|
||||||
|
run: |
|
||||||
|
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
||||||
|
$(printf 'ghcr.io/${{ steps.repo.outputs.repository }}@sha256:%s ' *)
|
||||||
|
- name: Inspect image
|
||||||
|
run: |
|
||||||
|
docker buildx imagetools inspect ghcr.io/${{ steps.repo.outputs.repository }}:${{ steps.docker_meta.outputs.version }}
|
||||||
26
app/src/main/cpp/hev-socks5-tunnel/.github/workflows/code-format.yaml
vendored
Normal file
26
app/src/main/cpp/hev-socks5-tunnel/.github/workflows/code-format.yaml
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
name: "Check code formatting"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
checker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
sudo apt install -y clang-format
|
||||||
|
- name: Format
|
||||||
|
run: |
|
||||||
|
find src -iname "*.[h,c]" -exec clang-format -i {} \;
|
||||||
|
- name: Check
|
||||||
|
run: |
|
||||||
|
git status
|
||||||
|
git diff --quiet
|
||||||
5
app/src/main/cpp/hev-socks5-tunnel/.gitignore
vendored
Normal file
5
app/src/main/cpp/hev-socks5-tunnel/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
bin
|
||||||
|
build
|
||||||
|
HevSocks5Tunnel.xcframework
|
||||||
|
obj
|
||||||
|
libs
|
||||||
12
app/src/main/cpp/hev-socks5-tunnel/.gitmodules
vendored
Normal file
12
app/src/main/cpp/hev-socks5-tunnel/.gitmodules
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[submodule "third-part/hev-task-system"]
|
||||||
|
path = third-part/hev-task-system
|
||||||
|
url = https://github.com/heiher/hev-task-system
|
||||||
|
[submodule "third-part/yaml"]
|
||||||
|
path = third-part/yaml
|
||||||
|
url = https://github.com/heiher/yaml
|
||||||
|
[submodule "third-part/lwip"]
|
||||||
|
path = third-part/lwip
|
||||||
|
url = https://github.com/heiher/lwip
|
||||||
|
[submodule "src/core"]
|
||||||
|
path = src/core
|
||||||
|
url = https://github.com/heiher/hev-socks5-core
|
||||||
51
app/src/main/cpp/hev-socks5-tunnel/Android.mk
Normal file
51
app/src/main/cpp/hev-socks5-tunnel/Android.mk
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# Copyright (C) 2021 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
TOP_PATH := $(call my-dir)
|
||||||
|
|
||||||
|
ifeq ($(filter $(modules-get-list),yaml),)
|
||||||
|
include $(TOP_PATH)/third-part/yaml/Android.mk
|
||||||
|
endif
|
||||||
|
ifeq ($(filter $(modules-get-list),lwip),)
|
||||||
|
include $(TOP_PATH)/third-part/lwip/Android.mk
|
||||||
|
endif
|
||||||
|
ifeq ($(filter $(modules-get-list),hev-task-system),)
|
||||||
|
include $(TOP_PATH)/third-part/hev-task-system/Android.mk
|
||||||
|
endif
|
||||||
|
|
||||||
|
LOCAL_PATH = $(TOP_PATH)
|
||||||
|
SRCDIR := $(LOCAL_PATH)/src
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
include $(LOCAL_PATH)/build.mk
|
||||||
|
LOCAL_MODULE := hev-socks5-tunnel
|
||||||
|
LOCAL_SRC_FILES := $(patsubst $(SRCDIR)/%,src/%,$(SRCFILES))
|
||||||
|
LOCAL_C_INCLUDES := \
|
||||||
|
$(LOCAL_PATH)/src \
|
||||||
|
$(LOCAL_PATH)/src/misc \
|
||||||
|
$(LOCAL_PATH)/src/core/include \
|
||||||
|
$(LOCAL_PATH)/third-part/yaml/include \
|
||||||
|
$(LOCAL_PATH)/third-part/lwip/src/include \
|
||||||
|
$(LOCAL_PATH)/third-part/lwip/src/ports/include \
|
||||||
|
$(LOCAL_PATH)/third-part/hev-task-system/include
|
||||||
|
LOCAL_CFLAGS += -DFD_SET_DEFINED -DSOCKLEN_T_DEFINED -DENABLE_LIBRARY
|
||||||
|
LOCAL_CFLAGS += $(VERSION_CFLAGS)
|
||||||
|
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||||
|
LOCAL_CFLAGS += -mfpu=neon
|
||||||
|
endif
|
||||||
|
LOCAL_STATIC_LIBRARIES := yaml lwip hev-task-system
|
||||||
|
LOCAL_LDFLAGS += -Wl,-z,max-page-size=16384
|
||||||
|
LOCAL_LDFLAGS += -Wl,-z,common-page-size=16384
|
||||||
|
include $(BUILD_SHARED_LIBRARY)
|
||||||
21
app/src/main/cpp/hev-socks5-tunnel/Application.mk
Normal file
21
app/src/main/cpp/hev-socks5-tunnel/Application.mk
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Copyright (C) 2013 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-29
|
||||||
|
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
|
||||||
|
APP_CFLAGS := -O3
|
||||||
|
APP_SUPPORT_FLEXIBLE_PAGE_SIZES := true
|
||||||
|
NDK_TOOLCHAIN_VERSION := clang
|
||||||
43
app/src/main/cpp/hev-socks5-tunnel/Dockerfile
Normal file
43
app/src/main/cpp/hev-socks5-tunnel/Dockerfile
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
FROM alpine:latest AS builder
|
||||||
|
|
||||||
|
RUN apk add --update --no-cache \
|
||||||
|
make \
|
||||||
|
git \
|
||||||
|
gcc \
|
||||||
|
linux-headers \
|
||||||
|
musl-dev
|
||||||
|
|
||||||
|
WORKDIR /src
|
||||||
|
COPY . /src
|
||||||
|
|
||||||
|
RUN make clean && make
|
||||||
|
|
||||||
|
FROM alpine:latest
|
||||||
|
LABEL org.opencontainers.image.source="https://github.com/heiher/hev-socks5-tunnel"
|
||||||
|
|
||||||
|
RUN apk add --update --no-cache \
|
||||||
|
iproute2
|
||||||
|
|
||||||
|
ENV TUN=tun0 \
|
||||||
|
MTU=8500 \
|
||||||
|
IPV4=198.18.0.1 \
|
||||||
|
IPV6='' \
|
||||||
|
TABLE=20 \
|
||||||
|
MARK=438 \
|
||||||
|
SOCKS5_ADDR=172.17.0.1 \
|
||||||
|
SOCKS5_PORT=1080 \
|
||||||
|
SOCKS5_USERNAME='' \
|
||||||
|
SOCKS5_PASSWORD='' \
|
||||||
|
SOCKS5_UDP_MODE=udp \
|
||||||
|
SOCKS5_UDP_ADDR='' \
|
||||||
|
CONFIG_ROUTES=1 \
|
||||||
|
IPV4_INCLUDED_ROUTES=0.0.0.0/0 \
|
||||||
|
IPV4_EXCLUDED_ROUTES='' \
|
||||||
|
LOG_LEVEL=warn
|
||||||
|
|
||||||
|
HEALTHCHECK --start-period=5s --interval=5s --timeout=2s --retries=3 CMD ["test", "-f", "/success"]
|
||||||
|
|
||||||
|
COPY --chmod=755 docker/entrypoint.sh /entrypoint.sh
|
||||||
|
COPY --from=builder /src/bin/hev-socks5-tunnel /usr/bin/hev-socks5-tunnel
|
||||||
|
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
19
app/src/main/cpp/hev-socks5-tunnel/LICENSE
Normal file
19
app/src/main/cpp/hev-socks5-tunnel/LICENSE
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2022 hev
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
146
app/src/main/cpp/hev-socks5-tunnel/Makefile
Normal file
146
app/src/main/cpp/hev-socks5-tunnel/Makefile
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
# Makefile for hev-socks5-tunnel
|
||||||
|
|
||||||
|
PROJECT=hev-socks5-tunnel
|
||||||
|
|
||||||
|
CROSS_PREFIX :=
|
||||||
|
PP=$(CROSS_PREFIX)cpp
|
||||||
|
CC=$(CROSS_PREFIX)gcc
|
||||||
|
AR=$(CROSS_PREFIX)ar
|
||||||
|
STRIP=$(CROSS_PREFIX)strip
|
||||||
|
CCFLAGS=-O3 -pipe -Wall -Werror $(CFLAGS) \
|
||||||
|
-I$(SRCDIR) \
|
||||||
|
-I$(SRCDIR)/misc \
|
||||||
|
-I$(SRCDIR)/core/include \
|
||||||
|
-I$(THIRDPARTDIR)/yaml/include \
|
||||||
|
-I$(THIRDPARTDIR)/wintun/include \
|
||||||
|
-I$(THIRDPARTDIR)/lwip/src/include \
|
||||||
|
-I$(THIRDPARTDIR)/lwip/src/ports/include \
|
||||||
|
-I$(THIRDPARTDIR)/hev-task-system/include
|
||||||
|
LDFLAGS=-L$(THIRDPARTDIR)/yaml/bin -lyaml \
|
||||||
|
-L$(THIRDPARTDIR)/lwip/bin -llwip \
|
||||||
|
-L$(THIRDPARTDIR)/hev-task-system/bin -lhev-task-system \
|
||||||
|
-lpthread $(LFLAGS)
|
||||||
|
|
||||||
|
SRCDIR=src
|
||||||
|
BINDIR=bin
|
||||||
|
CONFDIR=conf
|
||||||
|
BUILDDIR=build
|
||||||
|
INSTDIR=/usr/local
|
||||||
|
THIRDPARTDIR=third-part
|
||||||
|
|
||||||
|
CONFIG=$(CONFDIR)/main.yml
|
||||||
|
EXEC_TARGET=$(BINDIR)/hev-socks5-tunnel
|
||||||
|
STATIC_TARGET=$(BINDIR)/lib$(PROJECT).a
|
||||||
|
SHARED_TARGET=$(BINDIR)/lib$(PROJECT).so
|
||||||
|
THIRDPARTS=$(THIRDPARTDIR)/yaml \
|
||||||
|
$(THIRDPARTDIR)/lwip \
|
||||||
|
$(THIRDPARTDIR)/hev-task-system
|
||||||
|
|
||||||
|
$(STATIC_TARGET) : CCFLAGS+=-DENABLE_LIBRARY
|
||||||
|
$(SHARED_TARGET) : CCFLAGS+=-DENABLE_LIBRARY -fPIC
|
||||||
|
$(SHARED_TARGET) : LDFLAGS+=-shared -pthread
|
||||||
|
|
||||||
|
-include build.mk
|
||||||
|
CCFLAGS+=$(VERSION_CFLAGS)
|
||||||
|
CCSRCS=$(filter %.c,$(SRCFILES))
|
||||||
|
ASSRCS=$(filter %.S,$(SRCFILES))
|
||||||
|
LDOBJS=$(patsubst $(SRCDIR)/%.c,$(BUILDDIR)/%.o,$(CCSRCS)) \
|
||||||
|
$(patsubst $(SRCDIR)/%.S,$(BUILDDIR)/%.o,$(ASSRCS))
|
||||||
|
DEPEND=$(LDOBJS:.o=.dep)
|
||||||
|
|
||||||
|
BUILDMSG="\e[1;31mBUILD\e[0m %s\n"
|
||||||
|
LINKMSG="\e[1;34mLINK\e[0m \e[1;32m%s\e[0m\n"
|
||||||
|
STRIPMSG="\e[1;34mSTRIP\e[0m \e[1;32m%s\e[0m\n"
|
||||||
|
CLEANMSG="\e[1;34mCLEAN\e[0m %s\n"
|
||||||
|
INSTMSG="\e[1;34mINST\e[0m %s -> %s\n"
|
||||||
|
UNINSMSG="\e[1;34mUNINS\e[0m %s\n"
|
||||||
|
|
||||||
|
ENABLE_DEBUG :=
|
||||||
|
ifeq ($(ENABLE_DEBUG),1)
|
||||||
|
CCFLAGS+=-g -O0 -DENABLE_DEBUG
|
||||||
|
STRIP=true
|
||||||
|
endif
|
||||||
|
|
||||||
|
ENABLE_STATIC :=
|
||||||
|
ifeq ($(ENABLE_STATIC),1)
|
||||||
|
CCFLAGS+=-static
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(MSYSTEM),MSYS)
|
||||||
|
LDFLAGS+=-lmsys-2.0 -lws2_32 -lIphlpapi
|
||||||
|
endif
|
||||||
|
|
||||||
|
V :=
|
||||||
|
ECHO_PREFIX := @
|
||||||
|
ifeq ($(V),1)
|
||||||
|
undefine ECHO_PREFIX
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: exec static shared clean install uninstall tp-static tp-shared tp-clean
|
||||||
|
|
||||||
|
exec : $(EXEC_TARGET)
|
||||||
|
|
||||||
|
static : $(STATIC_TARGET)
|
||||||
|
|
||||||
|
shared : $(SHARED_TARGET)
|
||||||
|
|
||||||
|
tp-static : $(THIRDPARTS)
|
||||||
|
@$(foreach dir,$^,$(MAKE) --no-print-directory -C $(dir) static;)
|
||||||
|
|
||||||
|
tp-shared : $(THIRDPARTS)
|
||||||
|
@$(foreach dir,$^,$(MAKE) --no-print-directory -C $(dir) shared;)
|
||||||
|
|
||||||
|
tp-clean : $(THIRDPARTS)
|
||||||
|
@$(foreach dir,$^,$(MAKE) --no-print-directory -C $(dir) clean;)
|
||||||
|
|
||||||
|
clean : tp-clean
|
||||||
|
$(ECHO_PREFIX) $(RM) -rf $(BINDIR) $(BUILDDIR)
|
||||||
|
@printf $(CLEANMSG) $(PROJECT)
|
||||||
|
|
||||||
|
install : $(INSTDIR)/bin/$(PROJECT) $(INSTDIR)/etc/$(PROJECT).yml
|
||||||
|
|
||||||
|
uninstall :
|
||||||
|
$(ECHO_PREFIX) $(RM) -rf $(INSTDIR)/bin/$(PROJECT)
|
||||||
|
@printf $(UNINSMSG) $(INSTDIR)/bin/$(PROJECT)
|
||||||
|
$(ECHO_PREFIX) $(RM) -rf $(INSTDIR)/etc/$(PROJECT).yml
|
||||||
|
@printf $(UNINSMSG) $(INSTDIR)/etc/$(PROJECT).yml
|
||||||
|
|
||||||
|
$(INSTDIR)/bin/$(PROJECT) : $(EXEC_TARGET)
|
||||||
|
$(ECHO_PREFIX) install -d -m 0755 $(dir $@)
|
||||||
|
$(ECHO_PREFIX) install -m 0755 $< $@
|
||||||
|
@printf $(INSTMSG) $< $@
|
||||||
|
|
||||||
|
$(INSTDIR)/etc/$(PROJECT).yml : $(CONFIG)
|
||||||
|
$(ECHO_PREFIX) install -d -m 0755 $(dir $@)
|
||||||
|
$(ECHO_PREFIX) install -m 0644 $< $@
|
||||||
|
@printf $(INSTMSG) $< $@
|
||||||
|
|
||||||
|
$(EXEC_TARGET) : $(LDOBJS) tp-static
|
||||||
|
$(ECHO_PREFIX) mkdir -p $(dir $@)
|
||||||
|
$(ECHO_PREFIX) $(CC) $(CCFLAGS) -o $@ $(LDOBJS) $(LDFLAGS)
|
||||||
|
@printf $(LINKMSG) $@
|
||||||
|
$(ECHO_PREFIX) $(STRIP) $@
|
||||||
|
@printf $(STRIPMSG) $@
|
||||||
|
|
||||||
|
$(STATIC_TARGET) : $(LDOBJS) tp-static
|
||||||
|
$(ECHO_PREFIX) mkdir -p $(dir $@)
|
||||||
|
$(ECHO_PREFIX) $(AR) csq $@ $(LDOBJS)
|
||||||
|
@printf $(LINKMSG) $@
|
||||||
|
|
||||||
|
$(SHARED_TARGET) : $(LDOBJS) tp-shared
|
||||||
|
$(ECHO_PREFIX) mkdir -p $(dir $@)
|
||||||
|
$(ECHO_PREFIX) $(CC) $(CCFLAGS) -o $@ $(LDOBJS) $(LDFLAGS)
|
||||||
|
@printf $(LINKMSG) $@
|
||||||
|
|
||||||
|
$(BUILDDIR)/%.dep : $(SRCDIR)/%.c
|
||||||
|
$(ECHO_PREFIX) mkdir -p $(dir $@)
|
||||||
|
$(ECHO_PREFIX) $(PP) $(CCFLAGS) -MM -MT$(@:.dep=.o) -MF$@ $< 2>/dev/null
|
||||||
|
|
||||||
|
$(BUILDDIR)/%.o : $(SRCDIR)/%.c
|
||||||
|
$(ECHO_PREFIX) mkdir -p $(dir $@)
|
||||||
|
$(ECHO_PREFIX) $(CC) $(CCFLAGS) -c -o $@ $<
|
||||||
|
@printf $(BUILDMSG) $<
|
||||||
|
|
||||||
|
ifneq ($(MAKECMDGOALS),clean)
|
||||||
|
-include $(DEPEND)
|
||||||
|
endif
|
||||||
398
app/src/main/cpp/hev-socks5-tunnel/README.md
Normal file
398
app/src/main/cpp/hev-socks5-tunnel/README.md
Normal file
@ -0,0 +1,398 @@
|
|||||||
|
# HevSocks5Tunnel
|
||||||
|
|
||||||
|
[](https://github.com/heiher/hev-socks5-tunnel)
|
||||||
|
|
||||||
|
A simple, lightweight tunnel over Socks5 proxy (tun2socks).
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
* IPv4/IPv6. (dual stack)
|
||||||
|
* Redirect TCP connections.
|
||||||
|
* Redirect UDP packets. (Fullcone NAT, UDP-in-UDP and UDP-in-TCP [^1])
|
||||||
|
* Linux/Android/FreeBSD/macOS/iOS/Windows.
|
||||||
|
|
||||||
|
## Benchmarks
|
||||||
|
|
||||||
|
See [here](https://github.com/heiher/hev-socks5-tunnel/wiki/Benchmarks) for more details.
|
||||||
|
|
||||||
|
### Speed
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
### CPU usage
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
### Memory usage
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
## How to Build
|
||||||
|
|
||||||
|
### Unix
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone --recursive https://github.com/heiher/hev-socks5-tunnel
|
||||||
|
cd hev-socks5-tunnel
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
### Android
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir hev-socks5-tunnel
|
||||||
|
cd hev-socks5-tunnel
|
||||||
|
git clone --recursive https://github.com/heiher/hev-socks5-tunnel jni
|
||||||
|
ndk-build
|
||||||
|
```
|
||||||
|
|
||||||
|
### iOS and macOS
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone --recursive https://github.com/heiher/hev-socks5-tunnel
|
||||||
|
cd hev-socks5-tunnel
|
||||||
|
# will generate HevSocks5Tunnel.xcframework
|
||||||
|
./build-apple.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows (MSYS2)
|
||||||
|
```bash
|
||||||
|
export MSYS=winsymlinks:native
|
||||||
|
git clone --recursive https://github.com/heiher/hev-socks5-tunnel
|
||||||
|
cd hev-socks5-tunnel
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
### Library
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone --recursive https://github.com/heiher/hev-socks5-tunnel
|
||||||
|
cd hev-socks5-tunnel
|
||||||
|
|
||||||
|
# Static library
|
||||||
|
make static
|
||||||
|
|
||||||
|
# Shared library
|
||||||
|
make shared
|
||||||
|
```
|
||||||
|
|
||||||
|
## How to Use
|
||||||
|
|
||||||
|
### Config
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
tunnel:
|
||||||
|
# Interface name
|
||||||
|
name: tun0
|
||||||
|
# Interface MTU
|
||||||
|
mtu: 8500
|
||||||
|
# Multi-queue
|
||||||
|
multi-queue: false
|
||||||
|
# IPv4 address
|
||||||
|
ipv4: 198.18.0.1
|
||||||
|
# IPv6 address
|
||||||
|
ipv6: 'fc00::1'
|
||||||
|
# Post up script
|
||||||
|
# post-up-script: up.sh
|
||||||
|
# Pre down script
|
||||||
|
# pre-down-script: down.sh
|
||||||
|
|
||||||
|
socks5:
|
||||||
|
# Socks5 server port
|
||||||
|
port: 1080
|
||||||
|
# Socks5 server address (ipv4/ipv6)
|
||||||
|
address: 127.0.0.1
|
||||||
|
# Socks5 UDP relay mode (tcp|udp)
|
||||||
|
udp: 'udp'
|
||||||
|
# Override the UDP address provided by the Socks5 server (ipv4/ipv6)
|
||||||
|
# udp-address: ''
|
||||||
|
# Socks5 handshake using pipeline mode
|
||||||
|
# pipeline: false
|
||||||
|
# Socks5 server username
|
||||||
|
# username: 'username'
|
||||||
|
# Socks5 server password
|
||||||
|
# password: 'password'
|
||||||
|
# Socket mark
|
||||||
|
# mark: 0
|
||||||
|
# TCP fastopen
|
||||||
|
# tcp-fastopen: false
|
||||||
|
|
||||||
|
#mapdns:
|
||||||
|
# Mapped DNS address
|
||||||
|
# address: 198.18.0.2
|
||||||
|
# Mapped DNS port
|
||||||
|
# port: 53
|
||||||
|
# Mapped IP network base
|
||||||
|
# network: 100.64.0.0
|
||||||
|
# Mapped IP network mask
|
||||||
|
# netmask: 255.192.0.0
|
||||||
|
# Mapped DNS cache size
|
||||||
|
# cache-size: 10000
|
||||||
|
|
||||||
|
#misc:
|
||||||
|
# task stack size (bytes)
|
||||||
|
# task-stack-size: 86016
|
||||||
|
# tcp buffer size (bytes)
|
||||||
|
# tcp-buffer-size: 65536
|
||||||
|
# udp socket recv buffer (SO_RCVBUF) size (bytes)
|
||||||
|
# udp-recv-buffer-size: 524288
|
||||||
|
# number of udp buffers in splice, 1500 bytes per buffer.
|
||||||
|
# udp-copy-buffer-nums: 10
|
||||||
|
# maximum session count (0: unlimited)
|
||||||
|
# max-session-count: 0
|
||||||
|
# connect timeout (ms)
|
||||||
|
# connect-timeout: 10000
|
||||||
|
# TCP read-write timeout (ms)
|
||||||
|
# tcp-read-write-timeout: 300000
|
||||||
|
# UDP read-write timeout (ms)
|
||||||
|
# udp-read-write-timeout: 60000
|
||||||
|
# stdout, stderr or file-path
|
||||||
|
# log-file: stderr
|
||||||
|
# debug, info, warn or error
|
||||||
|
# log-level: warn
|
||||||
|
# If present, run as a daemon with this pid file
|
||||||
|
# pid-file: /run/hev-socks5-tunnel.pid
|
||||||
|
# If present, set rlimit nofile; else use default value
|
||||||
|
# limit-nofile: 65535
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run
|
||||||
|
|
||||||
|
#### Linux
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Set socks5.mark = 438
|
||||||
|
bin/hev-socks5-tunnel conf/main.yml
|
||||||
|
|
||||||
|
# Disable reverse path filter
|
||||||
|
sudo sysctl -w net.ipv4.conf.all.rp_filter=0
|
||||||
|
sudo sysctl -w net.ipv4.conf.tun0.rp_filter=0
|
||||||
|
|
||||||
|
# Bypass upstream socks5 server
|
||||||
|
sudo ip rule add fwmark 438 lookup main pref 10
|
||||||
|
sudo ip -6 rule add fwmark 438 lookup main pref 10
|
||||||
|
|
||||||
|
# Route others
|
||||||
|
sudo ip route add default dev tun0 table 20
|
||||||
|
sudo ip rule add lookup 20 pref 20
|
||||||
|
sudo ip -6 route add default dev tun0 table 20
|
||||||
|
sudo ip -6 rule add lookup 20 pref 20
|
||||||
|
```
|
||||||
|
|
||||||
|
#### FreeBSD/macOS
|
||||||
|
|
||||||
|
```zsh
|
||||||
|
# Bypass upstream socks5 server
|
||||||
|
# 10.0.0.1: socks5 server
|
||||||
|
# 10.0.2.2: default gateway
|
||||||
|
sudo route add -net 10.0.0.1/32 10.0.2.2
|
||||||
|
|
||||||
|
# Route others
|
||||||
|
sudo route change -inet default -interface tun0
|
||||||
|
sudo route change -inet6 default -interface tun0
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Windows
|
||||||
|
|
||||||
|
```zsh
|
||||||
|
# Bypass upstream socks5 server
|
||||||
|
# 10.0.0.1: socks5 server
|
||||||
|
# 10.0.2.2: default gateway
|
||||||
|
route add 10.0.0.1/32 10.0.2.2
|
||||||
|
|
||||||
|
# Route others
|
||||||
|
route change 0.0.0.0/0 0.0.0.0 if tun-index
|
||||||
|
route change ::/0 :: if tun-index
|
||||||
|
```
|
||||||
|
|
||||||
|
#### OpenWrt 24.10+
|
||||||
|
|
||||||
|
Repo: https://github.com/openwrt/packages/tree/master/net/hev-socks5-tunnel
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Install package
|
||||||
|
opkg install hev-socks5-tunnel
|
||||||
|
|
||||||
|
# Edit /etc/config/hev-socks5-tunnel
|
||||||
|
|
||||||
|
# Restart service
|
||||||
|
/etc/init.d/hev-socks5-tunnel restart
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Low memory usage
|
||||||
|
|
||||||
|
On low-memory systems like iOS, reducing the size of the TCP buffer and
|
||||||
|
task stack, as well as limiting the maximum session count, can help prevent
|
||||||
|
out-of-memory issues.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
misc:
|
||||||
|
# task stack size (bytes)
|
||||||
|
task-stack-size: 24576 # 20480 + tcp-buffer-size
|
||||||
|
# tcp buffer size (bytes)
|
||||||
|
tcp-buffer-size: 4096
|
||||||
|
# maximum session count
|
||||||
|
max-session-count: 1200
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Docker Compose
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
client:
|
||||||
|
image: alpine:latest # just for network testing
|
||||||
|
tty: true # you can test network in terminal
|
||||||
|
depends_on:
|
||||||
|
tun:
|
||||||
|
condition: service_healthy
|
||||||
|
network_mode: "service:tun"
|
||||||
|
|
||||||
|
tun:
|
||||||
|
image: ghcr.io/heiher/hev-socks5-tunnel:latest # `latest` for the latest published version; `nightly` for the latest source build; `vX.Y.Z` for the specific version
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN # needed
|
||||||
|
devices:
|
||||||
|
- /dev/net/tun:/dev/net/tun # needed
|
||||||
|
environment:
|
||||||
|
TUN: tun0 # optional, tun interface name, default `tun0`
|
||||||
|
MTU: 8500 # optional, MTU is MTU, default `8500`
|
||||||
|
IPV4: 198.18.0.1 # optional, tun interface ip, default `198.18.0.1`
|
||||||
|
TABLE: 20 # optional, ip route table id, default `20`
|
||||||
|
MARK: 438 # optional, ip route rule mark, dec or hex format, default `438`
|
||||||
|
SOCKS5_ADDR: a.b.c.d # socks5 proxy server address
|
||||||
|
SOCKS5_PORT: 1080 # socks5 proxy server port
|
||||||
|
SOCKS5_USERNAME: user # optional, socks5 proxy username, only set when need to auth
|
||||||
|
SOCKS5_PASSWORD: pass # optional, socks5 proxy password, only set when need to auth
|
||||||
|
SOCKS5_UDP_MODE: udp # optional, UDP relay mode, default `udp`, other option `tcp`
|
||||||
|
SOCKS5_UDP_ADDR: a.b.c.d # optional, override the UDP address provided by the Socks5 server
|
||||||
|
CONFIG_ROUTES: 1 # optional, set 0 to ignore TABLE, IPV4_INCLUDED_ROUTES and IPV4_EXCLUDED_ROUTES, with MARK defaults to 0
|
||||||
|
IPV4_INCLUDED_ROUTES: 0.0.0.0/0 # optional, demo means proxy all traffic. for multiple network segments, join with `,` or `\n`
|
||||||
|
IPV4_EXCLUDED_ROUTES: a.b.c.d # optional, demo means exclude traffic from the proxy itself. for multiple network segments, join with `,` or `\n`
|
||||||
|
LOG_LEVEL: warn # optional, default `warn`, other option `debug`/`info`/`error`
|
||||||
|
dns:
|
||||||
|
- 8.8.8.8
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also set the route rules with multiple network segments like:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
environment:
|
||||||
|
IPV4_INCLUDED_ROUTES: 10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
|
||||||
|
IPV4_EXCLUDED_ROUTES: |-
|
||||||
|
a.b.c.d/24
|
||||||
|
a.b.c.f/24
|
||||||
|
```
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* hev_socks5_tunnel_main:
|
||||||
|
* @config_path: config file path
|
||||||
|
* @tun_fd: tunnel file descriptor
|
||||||
|
*
|
||||||
|
* Start and run the socks5 tunnel, this function will blocks until the
|
||||||
|
* hev_socks5_tunnel_quit is called or an error occurs.
|
||||||
|
*
|
||||||
|
* Alias of hev_socks5_tunnel_main_from_file
|
||||||
|
*
|
||||||
|
* Returns: returns zero on successful, otherwise returns -1.
|
||||||
|
*
|
||||||
|
* Since: 2.4.6
|
||||||
|
*/
|
||||||
|
int hev_socks5_tunnel_main (const char *config_path, int tun_fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hev_socks5_tunnel_main_from_file:
|
||||||
|
* @config_path: config file path
|
||||||
|
* @tun_fd: tunnel file descriptor
|
||||||
|
*
|
||||||
|
* Start and run the socks5 tunnel, this function will blocks until the
|
||||||
|
* hev_socks5_tunnel_quit is called or an error occurs.
|
||||||
|
*
|
||||||
|
* Returns: returns zero on successful, otherwise returns -1.
|
||||||
|
*
|
||||||
|
* Since: 2.6.7
|
||||||
|
*/
|
||||||
|
int hev_socks5_tunnel_main_from_file (const char *config_path, int tun_fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hev_socks5_tunnel_main_from_str:
|
||||||
|
* @config_str: string config
|
||||||
|
* @config_len: the byte length of string config
|
||||||
|
* @tun_fd: tunnel file descriptor
|
||||||
|
*
|
||||||
|
* Start and run the socks5 tunnel, this function will blocks until the
|
||||||
|
* hev_socks5_tunnel_quit is called or an error occurs.
|
||||||
|
*
|
||||||
|
* Returns: returns zero on successful, otherwise returns -1.
|
||||||
|
*
|
||||||
|
* Since: 2.6.7
|
||||||
|
*/
|
||||||
|
int hev_socks5_tunnel_main_from_str (const unsigned char *config_str,
|
||||||
|
unsigned int config_len, int tun_fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hev_socks5_tunnel_quit:
|
||||||
|
*
|
||||||
|
* Stop the socks5 tunnel.
|
||||||
|
*
|
||||||
|
* Since: 2.4.6
|
||||||
|
*/
|
||||||
|
void hev_socks5_tunnel_quit (void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hev_socks5_tunnel_stats:
|
||||||
|
* @tx_packets (out): transmitted packets
|
||||||
|
* @tx_bytes (out): transmitted bytes
|
||||||
|
* @rx_packets (out): received packets
|
||||||
|
* @rx_bytes (out): received bytes
|
||||||
|
*
|
||||||
|
* Retrieve tunnel interface traffic statistics.
|
||||||
|
*
|
||||||
|
* Since: 2.6.5
|
||||||
|
*/
|
||||||
|
void hev_socks5_tunnel_stats (size_t *tx_packets, size_t *tx_bytes,
|
||||||
|
size_t *rx_packets, size_t *rx_bytes);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Use Cases
|
||||||
|
|
||||||
|
### Android VPN
|
||||||
|
|
||||||
|
* [SocksTun](https://github.com/heiher/sockstun)
|
||||||
|
|
||||||
|
### iOS
|
||||||
|
|
||||||
|
* [Tun2SocksKit](https://github.com/EbrahimTahernejad/Tun2SocksKit)
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
|
||||||
|
* **arror** - https://github.com/arror
|
||||||
|
* **bazuchan** - https://github.com/bazuchan
|
||||||
|
* **codewithtamim** - https://github.com/codewithtamim
|
||||||
|
* **dovecoteescapee** - https://github.com/dovecoteescapee
|
||||||
|
* **ebrahimtahernejad** - https://github.com/ebrahimtahernejad
|
||||||
|
* **heiby** - https://github.com/heiby
|
||||||
|
* **hev** - https://hev.cc
|
||||||
|
* **katana** - https://github.com/officialkatana
|
||||||
|
* **pronebird** - https://github.com/pronebird
|
||||||
|
* **saeeddev94** - https://github.com/saeeddev94
|
||||||
|
* **sskaje** - https://github.com/sskaje
|
||||||
|
* **wankkoree** - https://github.com/wankkoree
|
||||||
|
* **xiguagua** - https://github.com/xiguagua
|
||||||
|
* **xz-dev** - https://github.com/xz-dev
|
||||||
|
* **yiguous** - https://github.com/yiguous
|
||||||
|
* **yujinpan** - https://github.com/yujinpan
|
||||||
|
* **zheshinicheng** - https://github.com/zheshinicheng
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
|
|
||||||
|
[^1]: See [protocol specification](https://github.com/heiher/hev-socks5-core/tree/main?tab=readme-ov-file#udp-in-tcp). The [hev-socks5-server](https://github.com/heiher/hev-socks5-server) supports UDP relay over TCP.
|
||||||
76
app/src/main/cpp/hev-socks5-tunnel/build-apple.sh
Normal file
76
app/src/main/cpp/hev-socks5-tunnel/build-apple.sh
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
XCFRAMEWORK_DIR="./apple_xcframework"
|
||||||
|
LIB_NAME="HevSocks5Tunnel"
|
||||||
|
|
||||||
|
# buildStatic iphoneos -mios-version-min=15.0 arm64
|
||||||
|
buildStatic()
|
||||||
|
{
|
||||||
|
echo "build for $1, $2, min version $3"
|
||||||
|
|
||||||
|
local MIN_VERSION="-m$1-version-min=$3"
|
||||||
|
make PP="xcrun --sdk $1 --toolchain $1 clang" \
|
||||||
|
CC="xcrun --sdk $1 --toolchain $1 clang" \
|
||||||
|
CFLAGS="-arch $2 $MIN_VERSION" \
|
||||||
|
LFLAGS="-arch $2 $MIN_VERSION -Wl,-Bsymbolic-functions" static
|
||||||
|
|
||||||
|
local OUTPUT_DIR="$XCFRAMEWORK_DIR/$1-$2"
|
||||||
|
mkdir -p $OUTPUT_DIR
|
||||||
|
local OUTPUT_ARCH_FILE="$OUTPUT_DIR/libhev-socks5-tunnel.a"
|
||||||
|
|
||||||
|
libtool -static -o $OUTPUT_ARCH_FILE \
|
||||||
|
bin/libhev-socks5-tunnel.a \
|
||||||
|
third-part/lwip/bin/liblwip.a \
|
||||||
|
third-part/yaml/bin/libyaml.a \
|
||||||
|
third-part/hev-task-system/bin/libhev-task-system.a
|
||||||
|
make clean
|
||||||
|
}
|
||||||
|
|
||||||
|
mergeStatic()
|
||||||
|
{
|
||||||
|
echo "merge for $1, $2, $3"
|
||||||
|
local FIRST_LIB_FILE="$XCFRAMEWORK_DIR/$1-$2/libhev-socks5-tunnel.a"
|
||||||
|
local SECOND_LIB_FILE="$XCFRAMEWORK_DIR/$1-$3/libhev-socks5-tunnel.a"
|
||||||
|
local OUTPUT_DIR="$XCFRAMEWORK_DIR/$1-$2-$3"
|
||||||
|
mkdir -p $OUTPUT_DIR
|
||||||
|
local OUTPUT_ARCH_FILE="$OUTPUT_DIR/libhev-socks5-tunnel.a"
|
||||||
|
lipo -create \
|
||||||
|
-arch $2 $FIRST_LIB_FILE \
|
||||||
|
-arch $3 $SECOND_LIB_FILE \
|
||||||
|
-output $OUTPUT_ARCH_FILE
|
||||||
|
}
|
||||||
|
|
||||||
|
rm -rf $XCFRAMEWORK_DIR
|
||||||
|
rm -rf HevSocks5Tunnel.xcframework
|
||||||
|
mkdir $XCFRAMEWORK_DIR
|
||||||
|
|
||||||
|
buildStatic iphoneos arm64 15.0
|
||||||
|
buildStatic iphonesimulator x86_64 15.0
|
||||||
|
buildStatic iphonesimulator arm64 15.0
|
||||||
|
mergeStatic iphonesimulator x86_64 arm64
|
||||||
|
|
||||||
|
# keep same with flutter
|
||||||
|
buildStatic macosx x86_64 10.14
|
||||||
|
buildStatic macosx arm64 10.14
|
||||||
|
mergeStatic macosx x86_64 arm64
|
||||||
|
|
||||||
|
buildStatic appletvos arm64 17.0
|
||||||
|
buildStatic appletvsimulator x86_64 17.0
|
||||||
|
buildStatic appletvsimulator arm64 17.0
|
||||||
|
mergeStatic appletvsimulator x86_64 arm64
|
||||||
|
|
||||||
|
INCLUDE_DIR="$XCFRAMEWORK_DIR/include"
|
||||||
|
mkdir -p $INCLUDE_DIR/$LIB_NAME
|
||||||
|
cp ./src/hev-main.h $INCLUDE_DIR/$LIB_NAME
|
||||||
|
cp ./module.modulemap $INCLUDE_DIR/$LIB_NAME
|
||||||
|
xcodebuild -create-xcframework \
|
||||||
|
-library ./apple_xcframework/iphoneos-arm64/libhev-socks5-tunnel.a -headers $INCLUDE_DIR \
|
||||||
|
-library ./apple_xcframework/iphonesimulator-x86_64-arm64/libhev-socks5-tunnel.a -headers $INCLUDE_DIR \
|
||||||
|
-library ./apple_xcframework/macosx-x86_64-arm64/libhev-socks5-tunnel.a -headers $INCLUDE_DIR \
|
||||||
|
-library ./apple_xcframework/appletvos-arm64/libhev-socks5-tunnel.a -headers $INCLUDE_DIR \
|
||||||
|
-library ./apple_xcframework/appletvsimulator-x86_64-arm64/libhev-socks5-tunnel.a -headers $INCLUDE_DIR \
|
||||||
|
-output ./HevSocks5Tunnel.xcframework
|
||||||
|
|
||||||
|
rm -rf ./apple_xcframework
|
||||||
20
app/src/main/cpp/hev-socks5-tunnel/build.mk
Normal file
20
app/src/main/cpp/hev-socks5-tunnel/build.mk
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Build
|
||||||
|
|
||||||
|
rwildcard=$(foreach d,$(wildcard $1*), \
|
||||||
|
$(call rwildcard,$d/,$2) \
|
||||||
|
$(filter $(subst *,%,$2),$d))
|
||||||
|
|
||||||
|
SRCFILES=$(call rwildcard,$(SRCDIR)/,*.c *.S)
|
||||||
|
|
||||||
|
ifeq ($(REV_ID),)
|
||||||
|
ifneq (,$(wildcard .rev-id))
|
||||||
|
REV_ID=$(shell cat .rev-id)
|
||||||
|
endif
|
||||||
|
ifeq ($(REV_ID),)
|
||||||
|
REV_ID=$(shell git -C $(SRCDIR) rev-parse --short HEAD)
|
||||||
|
endif
|
||||||
|
ifeq ($(REV_ID),)
|
||||||
|
REV_ID=unknown
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
VERSION_CFLAGS=-DCOMMIT_ID=\"$(REV_ID)\"
|
||||||
75
app/src/main/cpp/hev-socks5-tunnel/conf/main.yml
Normal file
75
app/src/main/cpp/hev-socks5-tunnel/conf/main.yml
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
# Main configuration for hev-socks5-tunnel
|
||||||
|
|
||||||
|
tunnel:
|
||||||
|
# Interface name
|
||||||
|
name: tun0
|
||||||
|
# Interface MTU
|
||||||
|
mtu: 8500
|
||||||
|
# Multi-queue
|
||||||
|
multi-queue: false
|
||||||
|
# IPv4 address
|
||||||
|
ipv4: 198.18.0.1
|
||||||
|
# IPv6 address
|
||||||
|
ipv6: 'fc00::1'
|
||||||
|
# Post up script
|
||||||
|
# post-up-script: up.sh
|
||||||
|
# Pre down script
|
||||||
|
# pre-down-script: down.sh
|
||||||
|
|
||||||
|
socks5:
|
||||||
|
# Socks5 server port
|
||||||
|
port: 1080
|
||||||
|
# Socks5 server address (ipv4/ipv6)
|
||||||
|
address: 127.0.0.1
|
||||||
|
# Socks5 UDP relay mode (tcp|udp)
|
||||||
|
udp: 'udp'
|
||||||
|
# Override the UDP address provided by the Socks5 server (ipv4/ipv6)
|
||||||
|
# udp-address: ''
|
||||||
|
# Socks5 handshake using pipeline mode
|
||||||
|
# pipeline: false
|
||||||
|
# Socks5 server username
|
||||||
|
# username: 'username'
|
||||||
|
# Socks5 server password
|
||||||
|
# password: 'password'
|
||||||
|
# Socket mark
|
||||||
|
# mark: 0
|
||||||
|
# TCP fastopen
|
||||||
|
# tcp-fastopen: false
|
||||||
|
|
||||||
|
#mapdns:
|
||||||
|
# Mapped DNS address
|
||||||
|
# address: 198.18.0.2
|
||||||
|
# Mapped DNS port
|
||||||
|
# port: 53
|
||||||
|
# Mapped IP network base
|
||||||
|
# network: 100.64.0.0
|
||||||
|
# Mapped IP network mask
|
||||||
|
# netmask: 255.192.0.0
|
||||||
|
# Mapped DNS cache size
|
||||||
|
# cache-size: 10000
|
||||||
|
|
||||||
|
#misc:
|
||||||
|
# task stack size (bytes)
|
||||||
|
# task-stack-size: 86016
|
||||||
|
# tcp buffer size (bytes)
|
||||||
|
# tcp-buffer-size: 65536
|
||||||
|
# udp socket recv buffer (SO_RCVBUF) size (bytes)
|
||||||
|
# udp-recv-buffer-size: 524288
|
||||||
|
# number of udp buffers in splice, 1500 bytes per buffer.
|
||||||
|
# udp-copy-buffer-nums: 10
|
||||||
|
# maximum session count (0: unlimited)
|
||||||
|
# max-session-count: 0
|
||||||
|
# connect timeout (ms)
|
||||||
|
# connect-timeout: 10000
|
||||||
|
# TCP read-write timeout (ms)
|
||||||
|
# tcp-read-write-timeout: 300000
|
||||||
|
# UDP read-write timeout (ms)
|
||||||
|
# udp-read-write-timeout: 60000
|
||||||
|
# stdout, stderr or file-path
|
||||||
|
# log-file: stderr
|
||||||
|
# debug, info, warn or error
|
||||||
|
# log-level: warn
|
||||||
|
# If present, run as a daemon with this pid file
|
||||||
|
# pid-file: /run/hev-socks5-tunnel.pid
|
||||||
|
# If present, set rlimit nofile; else use default value
|
||||||
|
# limit-nofile: 65535
|
||||||
89
app/src/main/cpp/hev-socks5-tunnel/docker/entrypoint.sh
Normal file
89
app/src/main/cpp/hev-socks5-tunnel/docker/entrypoint.sh
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
TUN="${TUN:-tun0}"
|
||||||
|
MTU="${MTU:-8500}"
|
||||||
|
IPV4="${IPV4:-198.18.0.1}"
|
||||||
|
IPV6="${IPV6:-}"
|
||||||
|
|
||||||
|
CONFIG_ROUTES="${CONFIG_ROUTES:-1}"
|
||||||
|
|
||||||
|
TABLE="${TABLE:-20}"
|
||||||
|
if [ "${CONFIG_ROUTES}" == "0" ]; then
|
||||||
|
MARK="${MARK:-0}"
|
||||||
|
else
|
||||||
|
MARK="${MARK:-438}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
SOCKS5_ADDR="${SOCKS5_ADDR:-172.17.0.1}"
|
||||||
|
SOCKS5_PORT="${SOCKS5_PORT:-1080}"
|
||||||
|
SOCKS5_USERNAME="${SOCKS5_USERNAME:-}"
|
||||||
|
SOCKS5_PASSWORD="${SOCKS5_PASSWORD:-}"
|
||||||
|
SOCKS5_UDP_MODE="${SOCKS5_UDP_MODE:-udp}"
|
||||||
|
SOCKS5_UDP_ADDR="${SOCKS5_UDP_ADDR:-}"
|
||||||
|
|
||||||
|
IPV4_INCLUDED_ROUTES="${IPV4_INCLUDED_ROUTES:-0.0.0.0/0}"
|
||||||
|
IPV4_EXCLUDED_ROUTES="${IPV4_EXCLUDED_ROUTES:-}"
|
||||||
|
|
||||||
|
LOG_LEVEL="${LOG_LEVEL:-warn}"
|
||||||
|
|
||||||
|
config_file() {
|
||||||
|
cat > /hs5t.yml << EOF
|
||||||
|
misc:
|
||||||
|
log-level: '${LOG_LEVEL}'
|
||||||
|
tunnel:
|
||||||
|
name: '${TUN}'
|
||||||
|
mtu: ${MTU}
|
||||||
|
ipv4: '${IPV4}'
|
||||||
|
ipv6: '${IPV6}'
|
||||||
|
post-up-script: '/route.sh'
|
||||||
|
socks5:
|
||||||
|
address: '${SOCKS5_ADDR}'
|
||||||
|
port: ${SOCKS5_PORT}
|
||||||
|
udp: '${SOCKS5_UDP_MODE}'
|
||||||
|
mark: ${MARK}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
if [ -n "${SOCKS5_USERNAME}" ]; then
|
||||||
|
echo " username: '${SOCKS5_USERNAME}'" >> /hs5t.yml
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "${SOCKS5_PASSWORD}" ]; then
|
||||||
|
echo " password: '${SOCKS5_PASSWORD}'" >> /hs5t.yml
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "${SOCKS5_UDP_ADDR}" ]; then
|
||||||
|
echo " udp-address: '${SOCKS5_UDP_ADDR}'" >> /hs5t.yml
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
config_route() {
|
||||||
|
echo "#!/bin/sh" > /route.sh
|
||||||
|
chmod +x /route.sh
|
||||||
|
|
||||||
|
if [ "${CONFIG_ROUTES}" == "0" ]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "ip route add default dev ${TUN} table ${TABLE}" >> /route.sh
|
||||||
|
|
||||||
|
for addr in $(echo ${IPV4_INCLUDED_ROUTES} | tr ',' '\n'); do
|
||||||
|
echo "ip rule add to ${addr} table ${TABLE}" >> /route.sh
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "ip rule add to $(ip -o -f inet address show eth0 | awk '/scope global/ {print $4}') table main" >> /route.sh
|
||||||
|
|
||||||
|
for addr in $(echo ${IPV4_EXCLUDED_ROUTES} | tr ',' '\n'); do
|
||||||
|
echo "ip rule add to ${addr} table main" >> /route.sh
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "ip rule add fwmark ${MARK} table main pref 1" >> /route.sh
|
||||||
|
}
|
||||||
|
|
||||||
|
run() {
|
||||||
|
config_file
|
||||||
|
config_route
|
||||||
|
echo "echo 1 > /success" >> /route.sh
|
||||||
|
hev-socks5-tunnel /hs5t.yml
|
||||||
|
}
|
||||||
|
|
||||||
|
run || exit 1
|
||||||
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-main.h
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2019 - 2023 hev
|
||||||
|
Description : Main
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_MAIN_H__
|
||||||
|
#define __HEV_MAIN_H__
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hev_socks5_tunnel_main:
|
||||||
|
* @config_path: config file path
|
||||||
|
* @tun_fd: tunnel file descriptor
|
||||||
|
*
|
||||||
|
* Start and run the socks5 tunnel, this function will blocks until the
|
||||||
|
* hev_socks5_tunnel_quit is called or an error occurs.
|
||||||
|
*
|
||||||
|
* Returns: returns zero on successful, otherwise returns -1.
|
||||||
|
*
|
||||||
|
* Since: 2.4.6
|
||||||
|
*/
|
||||||
|
int hev_socks5_tunnel_main (const char *config_path, int tun_fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hev_socks5_tunnel_main_from_file:
|
||||||
|
* @config_path: config file path
|
||||||
|
* @tun_fd: tunnel file descriptor
|
||||||
|
*
|
||||||
|
* Start and run the socks5 tunnel, this function will blocks until the
|
||||||
|
* hev_socks5_tunnel_quit is called or an error occurs.
|
||||||
|
*
|
||||||
|
* Returns: returns zero on successful, otherwise returns -1.
|
||||||
|
*
|
||||||
|
* Since: 2.6.7
|
||||||
|
*/
|
||||||
|
int hev_socks5_tunnel_main_from_file (const char *config_path, int tun_fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hev_socks5_tunnel_main_from_str:
|
||||||
|
* @config_str: string config
|
||||||
|
* @config_len: the byte length of string config
|
||||||
|
* @tun_fd: tunnel file descriptor
|
||||||
|
*
|
||||||
|
* Start and run the socks5 tunnel, this function will blocks until the
|
||||||
|
* hev_socks5_tunnel_quit is called or an error occurs.
|
||||||
|
*
|
||||||
|
* Returns: returns zero on successful, otherwise returns -1.
|
||||||
|
*
|
||||||
|
* Since: 2.6.7
|
||||||
|
*/
|
||||||
|
int hev_socks5_tunnel_main_from_str (const unsigned char *config_str,
|
||||||
|
unsigned int config_len, int tun_fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hev_socks5_tunnel_quit:
|
||||||
|
*
|
||||||
|
* Stop the socks5 tunnel.
|
||||||
|
*
|
||||||
|
* Since: 2.4.6
|
||||||
|
*/
|
||||||
|
void hev_socks5_tunnel_quit (void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hev_socks5_tunnel_stats:
|
||||||
|
* @tx_packets (out): transmitted packets
|
||||||
|
* @tx_bytes (out): transmitted bytes
|
||||||
|
* @rx_packets (out): received packets
|
||||||
|
* @rx_bytes (out): received bytes
|
||||||
|
*
|
||||||
|
* Retrieve tunnel interface traffic statistics.
|
||||||
|
*
|
||||||
|
* Since: 2.6.5
|
||||||
|
*/
|
||||||
|
void hev_socks5_tunnel_stats (size_t *tx_packets, size_t *tx_bytes,
|
||||||
|
size_t *rx_packets, size_t *rx_bytes);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_MAIN_H__ */
|
||||||
4
app/src/main/cpp/hev-socks5-tunnel/module.modulemap
Normal file
4
app/src/main/cpp/hev-socks5-tunnel/module.modulemap
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
module HevSocks5Tunnel {
|
||||||
|
umbrella header "hev-main.h"
|
||||||
|
export *
|
||||||
|
}
|
||||||
115
app/src/main/cpp/hev-socks5-tunnel/src/core/.clang-format
Normal file
115
app/src/main/cpp/hev-socks5-tunnel/src/core/.clang-format
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: TopLevel
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: MultiLine
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BraceWrapping:
|
||||||
|
AfterClass: true
|
||||||
|
AfterControlStatement: false
|
||||||
|
AfterEnum: true
|
||||||
|
AfterFunction: true
|
||||||
|
AfterNamespace: true
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: true
|
||||||
|
AfterUnion: true
|
||||||
|
AfterExternBlock: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: true
|
||||||
|
SplitEmptyRecord: true
|
||||||
|
SplitEmptyNamespace: true
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BreakBeforeInheritanceComma: false
|
||||||
|
BreakInheritanceList: BeforeColon
|
||||||
|
BreakBeforeTernaryOperators: false
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakStringLiterals: false
|
||||||
|
ColumnLimit: 80
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: false
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
FixNamespaceComments: false
|
||||||
|
ForEachMacros:
|
||||||
|
- foreach
|
||||||
|
- Q_FOREACH
|
||||||
|
- BOOST_FOREACH
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 1
|
||||||
|
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||||
|
Priority: 3
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 1
|
||||||
|
IncludeIsMainRegex: '(Test)?$'
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentWidth: 4
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: Inner
|
||||||
|
ObjCBinPackProtocolList: Auto
|
||||||
|
ObjCBlockIndentWidth: 4
|
||||||
|
ObjCSpaceAfterProperty: true
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PenaltyBreakAssignment: 10
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 30
|
||||||
|
PenaltyBreakComment: 10
|
||||||
|
PenaltyBreakFirstLessLess: 0
|
||||||
|
PenaltyBreakString: 10
|
||||||
|
PenaltyBreakTemplateDeclaration: 10
|
||||||
|
PenaltyExcessCharacter: 100
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 60
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReflowComments: false
|
||||||
|
SortIncludes: false
|
||||||
|
SortUsingDeclarations: false
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterTemplateKeyword: true
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: Always
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Cpp03
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
||||||
|
...
|
||||||
26
app/src/main/cpp/hev-socks5-tunnel/src/core/.github/workflows/code-format.yaml
vendored
Normal file
26
app/src/main/cpp/hev-socks5-tunnel/src/core/.github/workflows/code-format.yaml
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
name: "Check code formatting"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
checker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
sudo apt install -y clang-format
|
||||||
|
- name: Format
|
||||||
|
run: |
|
||||||
|
find src -iname "*.[h,c]" -exec clang-format -i {} \;
|
||||||
|
- name: Check
|
||||||
|
run: |
|
||||||
|
git status
|
||||||
|
git diff --quiet
|
||||||
19
app/src/main/cpp/hev-socks5-tunnel/src/core/LICENSE
Normal file
19
app/src/main/cpp/hev-socks5-tunnel/src/core/LICENSE
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2022 hev
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
204
app/src/main/cpp/hev-socks5-tunnel/src/core/README.md
Normal file
204
app/src/main/cpp/hev-socks5-tunnel/src/core/README.md
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
# HevSocks5Core
|
||||||
|
|
||||||
|
HevSocks5Core is a simple, lightweight socks5 library.
|
||||||
|
|
||||||
|
**Features**
|
||||||
|
* IPv4/IPv6. (dual stack)
|
||||||
|
* Standard `CONNECT` command.
|
||||||
|
* Standard `UDP ASSOCIATE` command.
|
||||||
|
* Extended `FWD UDP` command. (UDP in TCP)
|
||||||
|
* Multiple username/password authentication.
|
||||||
|
|
||||||
|
**Dependencies**
|
||||||
|
* HevTaskSystem - https://github.com/heiher/hev-task-system
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Server
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
#include <hev-task-io.h>
|
||||||
|
#include <hev-task-io-socket.h>
|
||||||
|
#include <hev-task-dns.h>
|
||||||
|
#include <hev-task-system.h>
|
||||||
|
|
||||||
|
#include <hev-socks5-server.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
server_entry (void *data)
|
||||||
|
{
|
||||||
|
HevSocks5Server *server = data;
|
||||||
|
hev_socks5_server_run (server);
|
||||||
|
hev_object_unref (HEV_OBJECT (server));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
listener_entry (void *data)
|
||||||
|
{
|
||||||
|
struct addrinfo hints = { 0 };
|
||||||
|
struct addrinfo *result;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
hints.ai_family = AF_INET6;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_flags = AI_PASSIVE;
|
||||||
|
|
||||||
|
hev_task_dns_getaddrinfo (NULL, "1080", &hints, &result);
|
||||||
|
fd = hev_task_io_socket_socket (AF_INET6, SOCK_STREAM, 0);
|
||||||
|
bind (fd, result->ai_addr, result->ai_addrlen);
|
||||||
|
freeaddrinfo (result);
|
||||||
|
listen (fd, 5);
|
||||||
|
|
||||||
|
hev_task_add_fd (hev_task_self (), fd, POLLIN);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
HevSocks5Server *server;
|
||||||
|
HevTask *task;
|
||||||
|
int nfd;
|
||||||
|
|
||||||
|
nfd = hev_task_io_socket_accept (fd, NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
task = hev_task_new (-1);
|
||||||
|
server = hev_socks5_server_new (nfd);
|
||||||
|
hev_task_run (task, server_entry, server);
|
||||||
|
}
|
||||||
|
|
||||||
|
close (fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
HevTask *task;
|
||||||
|
|
||||||
|
hev_task_system_init ();
|
||||||
|
|
||||||
|
task = hev_task_new (-1);
|
||||||
|
hev_task_run (task, listener_entry, NULL);
|
||||||
|
|
||||||
|
hev_task_system_run ();
|
||||||
|
|
||||||
|
hev_task_system_fini ();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Client
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
#include <hev-task-system.h>
|
||||||
|
#include <hev-socks5-client-tcp.h>
|
||||||
|
#include <hev-socks5-client-udp.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
tcp_client_entry (void *data)
|
||||||
|
{
|
||||||
|
HevSocks5ClientTCP *tcp;
|
||||||
|
|
||||||
|
tcp = hev_socks5_client_tcp_new_name ("www.google.com", 443);
|
||||||
|
hev_socks5_client_connect (HEV_SOCKS5_CLIENT (tcp), "127.0.0.1", 1080);
|
||||||
|
hev_socks5_client_handshake (HEV_SOCKS5_CLIENT (tcp));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* splice data to/from a socket fd:
|
||||||
|
* hev_socks5_tcp_splice (HEV_SOCKS5_TCP (tcp), fd);
|
||||||
|
*/
|
||||||
|
|
||||||
|
hev_object_unref (HEV_OBJECT (tcp));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
udp_client_entry (void *data)
|
||||||
|
{
|
||||||
|
HevSocks5ClientUDP *udp;
|
||||||
|
|
||||||
|
udp = hev_socks5_client_udp_new (HEV_SOCKS5_TYPE_UDP_IN_TCP);
|
||||||
|
hev_socks5_client_connect (HEV_SOCKS5_CLIENT (udp), "127.0.0.1", 1080);
|
||||||
|
hev_socks5_client_handshake (HEV_SOCKS5_CLIENT (udp));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HevSocks5UDPMsg msgv[num];
|
||||||
|
*
|
||||||
|
* send udp packets:
|
||||||
|
* hev_socks5_udp_sendmmsg (HEV_SOCKS5_UDP (udp), msgv, num);
|
||||||
|
*
|
||||||
|
* recv udp packets:
|
||||||
|
* hev_socks5_udp_recvmmsg (HEV_SOCKS5_UDP (udp), msgv, num, 0);
|
||||||
|
*/
|
||||||
|
|
||||||
|
hev_object_unref (HEV_OBJECT (udp));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
HevTask *task;
|
||||||
|
|
||||||
|
hev_task_system_init ();
|
||||||
|
|
||||||
|
task = hev_task_new (-1);
|
||||||
|
hev_task_run (task, tcp_client_entry, NULL);
|
||||||
|
|
||||||
|
task = hev_task_new (-1);
|
||||||
|
hev_task_run (task, udp_client_entry, NULL);
|
||||||
|
|
||||||
|
hev_task_system_run ();
|
||||||
|
|
||||||
|
hev_task_system_fini ();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## UDP in TCP
|
||||||
|
|
||||||
|
UDP-in-TCP mode is a proprietary extension based on RFC 1928, designed to
|
||||||
|
forward UDP packets within the primary SOCKS5 TCP stream. The protocol is
|
||||||
|
defined as follows:
|
||||||
|
|
||||||
|
### SOCKS5 Requests
|
||||||
|
|
||||||
|
```
|
||||||
|
+----+-----+-------+------+----------+----------+
|
||||||
|
|VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
|
||||||
|
+----+-----+-------+------+----------+----------+
|
||||||
|
| 1 | 1 | X'00' | 1 | Variable | 2 |
|
||||||
|
+----+-----+-------+------+----------+----------+
|
||||||
|
```
|
||||||
|
|
||||||
|
* CMD
|
||||||
|
* UDP IN TCP: X'05'
|
||||||
|
|
||||||
|
### UDP Relays
|
||||||
|
|
||||||
|
```
|
||||||
|
+--------+--------+------+----------+----------+----------+
|
||||||
|
| MSGLEN | HDRLEN | ATYP | DST.ADDR | DST.PORT | DATA |
|
||||||
|
+--------+--------+------+----------+----------+----------+
|
||||||
|
| 2 | 1 | 1 | Variable | 2 | Variable |
|
||||||
|
+--------+--------+------+----------+----------+----------+
|
||||||
|
```
|
||||||
|
|
||||||
|
- MSGLEN: The total length of the UDP relay message. `[MSGLEN, DATA]`
|
||||||
|
- HDRLEN: The header length of the UDP relay message. `[MSGLEN, DST.PORT]`
|
||||||
|
- ATYPE/DST.ADDR/DST.PORT: Fields follow the definitions specified in RFC 1928.
|
||||||
|
|
||||||
|
## Users
|
||||||
|
|
||||||
|
* **HevSocks5Server** - https://github.com/heiher/hev-socks5-server
|
||||||
|
* **HevSocks5TProxy** - https://github.com/heiher/hev-socks5-tproxy
|
||||||
|
* **HevSocks5Tunnel** - https://github.com/heiher/hev-socks5-tunnel
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
* **hev** - https://hev.cc
|
||||||
|
* **spider84** - https://github.com/spider84
|
||||||
|
|
||||||
|
## License
|
||||||
|
MIT
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-rbtree.h
|
||||||
|
Authors : Andrea Arcangeli <andrea@suse.de>
|
||||||
|
David Woodhouse <dwmw2@infradead.org>
|
||||||
|
Michel Lespinasse <walken@google.com>
|
||||||
|
Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2018 everyone.
|
||||||
|
Description : RedBlack Tree
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_RBTREE_H__
|
||||||
|
#define __HEV_RBTREE_H__
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef struct _HevRBTree HevRBTree;
|
||||||
|
typedef struct _HevRBTreeNode HevRBTreeNode;
|
||||||
|
|
||||||
|
struct _HevRBTree
|
||||||
|
{
|
||||||
|
HevRBTreeNode *root;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevRBTreeNode
|
||||||
|
{
|
||||||
|
unsigned long __parent_color;
|
||||||
|
HevRBTreeNode *right;
|
||||||
|
HevRBTreeNode *left;
|
||||||
|
} __attribute__ ((aligned (sizeof (long))));
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hev_rbtree_node_empty (HevRBTreeNode *node)
|
||||||
|
{
|
||||||
|
return node->__parent_color == (unsigned long)node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline HevRBTreeNode *
|
||||||
|
hev_rbtree_node_parent (HevRBTreeNode *node)
|
||||||
|
{
|
||||||
|
return (HevRBTreeNode *)(node->__parent_color & ~3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
hev_rbtree_node_link (HevRBTreeNode *node, HevRBTreeNode *parent,
|
||||||
|
HevRBTreeNode **link)
|
||||||
|
{
|
||||||
|
node->__parent_color = (unsigned long)parent;
|
||||||
|
node->left = node->right = NULL;
|
||||||
|
|
||||||
|
*link = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
HevRBTreeNode *hev_rbtree_node_prev (HevRBTreeNode *node);
|
||||||
|
HevRBTreeNode *hev_rbtree_node_next (HevRBTreeNode *node);
|
||||||
|
|
||||||
|
HevRBTreeNode *hev_rbtree_first (HevRBTree *self);
|
||||||
|
HevRBTreeNode *hev_rbtree_last (HevRBTree *self);
|
||||||
|
|
||||||
|
void hev_rbtree_insert_color (HevRBTree *self, HevRBTreeNode *node);
|
||||||
|
|
||||||
|
void hev_rbtree_replace (HevRBTree *self, HevRBTreeNode *victim,
|
||||||
|
HevRBTreeNode *new);
|
||||||
|
|
||||||
|
void hev_rbtree_erase (HevRBTree *self, HevRBTreeNode *node);
|
||||||
|
|
||||||
|
#endif /* __HEV_RBTREE_H__ */
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-authenticator.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2023 hev
|
||||||
|
Description : Socks5 Authenticator
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_AUTHENTICATOR_H__
|
||||||
|
#define __HEV_SOCKS5_AUTHENTICATOR_H__
|
||||||
|
|
||||||
|
#include <hev-object-atomic.h>
|
||||||
|
|
||||||
|
#include "hev-rbtree.h"
|
||||||
|
#include "hev-socks5-user.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HEV_SOCKS5_AUTHENTICATOR(p) ((HevSocks5Authenticator *)p)
|
||||||
|
#define HEV_SOCKS5_AUTHENTICATOR_CLASS(p) ((HevSocks5AuthenticatorClass *)p)
|
||||||
|
#define HEV_SOCKS5_AUTHENTICATOR_TYPE (hev_socks5_authenticator_class ())
|
||||||
|
|
||||||
|
typedef struct _HevSocks5Authenticator HevSocks5Authenticator;
|
||||||
|
typedef struct _HevSocks5AuthenticatorClass HevSocks5AuthenticatorClass;
|
||||||
|
typedef enum _HevSocks5AuthenticatorType HevSocks5AuthenticatorType;
|
||||||
|
|
||||||
|
struct _HevSocks5Authenticator
|
||||||
|
{
|
||||||
|
HevObjectAtomic base;
|
||||||
|
|
||||||
|
HevRBTree tree;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5AuthenticatorClass
|
||||||
|
{
|
||||||
|
HevObjectAtomicClass base;
|
||||||
|
};
|
||||||
|
|
||||||
|
HevObjectClass *hev_socks5_authenticator_class (void);
|
||||||
|
|
||||||
|
int hev_socks5_authenticator_construct (HevSocks5Authenticator *self);
|
||||||
|
|
||||||
|
HevSocks5Authenticator *hev_socks5_authenticator_new (void);
|
||||||
|
|
||||||
|
int hev_socks5_authenticator_add (HevSocks5Authenticator *self,
|
||||||
|
HevSocks5User *user);
|
||||||
|
|
||||||
|
int hev_socks5_authenticator_del (HevSocks5Authenticator *self,
|
||||||
|
const char *name, unsigned int name_len);
|
||||||
|
|
||||||
|
HevSocks5User *hev_socks5_authenticator_get (HevSocks5Authenticator *self,
|
||||||
|
const char *name,
|
||||||
|
unsigned int name_len);
|
||||||
|
|
||||||
|
void hev_socks5_authenticator_clear (HevSocks5Authenticator *self);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_AUTHENTICATOR_H__ */
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-client-tcp.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2025 hev
|
||||||
|
Description : Socks5 Client TCP
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_CLIENT_TCP_H__
|
||||||
|
#define __HEV_SOCKS5_CLIENT_TCP_H__
|
||||||
|
|
||||||
|
#include "hev-socks5-tcp.h"
|
||||||
|
#include "hev-socks5-proto.h"
|
||||||
|
|
||||||
|
#include "hev-socks5-client.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HEV_SOCKS5_CLIENT_TCP(p) ((HevSocks5ClientTCP *)p)
|
||||||
|
#define HEV_SOCKS5_CLIENT_TCP_CLASS(p) ((HevSocks5ClientTCPClass *)p)
|
||||||
|
#define HEV_SOCKS5_CLIENT_TCP_TYPE (hev_socks5_client_tcp_class ())
|
||||||
|
|
||||||
|
typedef struct _HevSocks5ClientTCP HevSocks5ClientTCP;
|
||||||
|
typedef struct _HevSocks5ClientTCPClass HevSocks5ClientTCPClass;
|
||||||
|
|
||||||
|
struct _HevSocks5ClientTCP
|
||||||
|
{
|
||||||
|
HevSocks5Client base;
|
||||||
|
|
||||||
|
HevSocks5Addr *addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5ClientTCPClass
|
||||||
|
{
|
||||||
|
HevSocks5ClientClass base;
|
||||||
|
|
||||||
|
HevSocks5TCPIface tcp;
|
||||||
|
};
|
||||||
|
|
||||||
|
HevObjectClass *hev_socks5_client_tcp_class (void);
|
||||||
|
|
||||||
|
int hev_socks5_client_tcp_construct (HevSocks5ClientTCP *self,
|
||||||
|
const HevSocks5Addr *addr);
|
||||||
|
|
||||||
|
HevSocks5ClientTCP *hev_socks5_client_tcp_new_name (const char *name, int port);
|
||||||
|
HevSocks5ClientTCP *hev_socks5_client_tcp_new_ipv4 (const void *ipv4, int port);
|
||||||
|
HevSocks5ClientTCP *hev_socks5_client_tcp_new_ipv6 (const void *ipv6, int port);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_CLIENT_TCP_H__ */
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-client-udp.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2023 hev
|
||||||
|
Description : Socks5 Client UDP
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_CLIENT_UDP_H__
|
||||||
|
#define __HEV_SOCKS5_CLIENT_UDP_H__
|
||||||
|
|
||||||
|
#include "hev-socks5-udp.h"
|
||||||
|
|
||||||
|
#include "hev-socks5-client.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HEV_SOCKS5_CLIENT_UDP(p) ((HevSocks5ClientUDP *)p)
|
||||||
|
#define HEV_SOCKS5_CLIENT_UDP_CLASS(p) ((HevSocks5ClientUDPClass *)p)
|
||||||
|
#define HEV_SOCKS5_CLIENT_UDP_TYPE (hev_socks5_client_udp_class ())
|
||||||
|
|
||||||
|
typedef struct _HevSocks5ClientUDP HevSocks5ClientUDP;
|
||||||
|
typedef struct _HevSocks5ClientUDPClass HevSocks5ClientUDPClass;
|
||||||
|
|
||||||
|
struct _HevSocks5ClientUDP
|
||||||
|
{
|
||||||
|
HevSocks5Client base;
|
||||||
|
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5ClientUDPClass
|
||||||
|
{
|
||||||
|
HevSocks5ClientClass base;
|
||||||
|
|
||||||
|
HevSocks5UDPIface udp;
|
||||||
|
};
|
||||||
|
|
||||||
|
HevObjectClass *hev_socks5_client_udp_class (void);
|
||||||
|
|
||||||
|
int hev_socks5_client_udp_construct (HevSocks5ClientUDP *self,
|
||||||
|
HevSocks5Type type);
|
||||||
|
|
||||||
|
HevSocks5ClientUDP *hev_socks5_client_udp_new (HevSocks5Type type);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_CLIENT_UDP_H__ */
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-client.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2024 hev
|
||||||
|
Description : Socks5 Client
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_CLIENT_H__
|
||||||
|
#define __HEV_SOCKS5_CLIENT_H__
|
||||||
|
|
||||||
|
#include "hev-socks5.h"
|
||||||
|
#include "hev-socks5-proto.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HEV_SOCKS5_CLIENT(p) ((HevSocks5Client *)p)
|
||||||
|
#define HEV_SOCKS5_CLIENT_CLASS(p) ((HevSocks5ClientClass *)p)
|
||||||
|
#define HEV_SOCKS5_CLIENT_TYPE (hev_socks5_client_class ())
|
||||||
|
|
||||||
|
typedef struct _HevSocks5Client HevSocks5Client;
|
||||||
|
typedef struct _HevSocks5ClientClass HevSocks5ClientClass;
|
||||||
|
|
||||||
|
struct _HevSocks5Client
|
||||||
|
{
|
||||||
|
HevSocks5 base;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
const char *user;
|
||||||
|
const char *pass;
|
||||||
|
} auth;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5ClientClass
|
||||||
|
{
|
||||||
|
HevSocks5Class base;
|
||||||
|
|
||||||
|
HevSocks5Addr *(*get_upstream_addr) (HevSocks5Client *self);
|
||||||
|
int (*set_upstream_addr) (HevSocks5Client *self, HevSocks5Addr *addr);
|
||||||
|
};
|
||||||
|
|
||||||
|
HevObjectClass *hev_socks5_client_class (void);
|
||||||
|
|
||||||
|
int hev_socks5_client_construct (HevSocks5Client *self, HevSocks5Type type);
|
||||||
|
|
||||||
|
int hev_socks5_client_connect (HevSocks5Client *self, const char *addr,
|
||||||
|
int port);
|
||||||
|
|
||||||
|
int hev_socks5_client_handshake (HevSocks5Client *self, int pipeline);
|
||||||
|
|
||||||
|
void hev_socks5_client_set_auth (HevSocks5Client *self, const char *user,
|
||||||
|
const char *pass);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_CLIENT_H__ */
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-logger.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 hev
|
||||||
|
Description : Socks5 Logger
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_LOGGER_H__
|
||||||
|
#define __HEV_SOCKS5_LOGGER_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum _HevSocks5LoggerLevel HevSocks5LoggerLevel;
|
||||||
|
|
||||||
|
enum _HevSocks5LoggerLevel
|
||||||
|
{
|
||||||
|
HEV_SOCKS5_LOGGER_DEBUG,
|
||||||
|
HEV_SOCKS5_LOGGER_INFO,
|
||||||
|
HEV_SOCKS5_LOGGER_WARN,
|
||||||
|
HEV_SOCKS5_LOGGER_ERROR,
|
||||||
|
HEV_SOCKS5_LOGGER_UNSET,
|
||||||
|
};
|
||||||
|
|
||||||
|
int hev_socks5_logger_init (HevSocks5LoggerLevel level, const char *path);
|
||||||
|
void hev_socks5_logger_fini (void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_LOGGER_H__ */
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-misc.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2025 hev
|
||||||
|
Description : Socks5 Misc
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_MISC_H__
|
||||||
|
#define __HEV_SOCKS5_MISC_H__
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
|
||||||
|
#include "hev-socks5-proto.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int hev_socks5_task_io_yielder (HevTaskYieldType type, void *data);
|
||||||
|
|
||||||
|
void hev_socks5_set_connect_timeout (int timeout);
|
||||||
|
void hev_socks5_set_tcp_timeout (int timeout);
|
||||||
|
void hev_socks5_set_udp_timeout (int timeout);
|
||||||
|
|
||||||
|
void hev_socks5_set_task_stack_size (int stack_size);
|
||||||
|
void hev_socks5_set_udp_recv_buffer_size (int buffer_size);
|
||||||
|
void hev_socks5_set_udp_copy_buffer_nums (int nums);
|
||||||
|
|
||||||
|
int hev_socks5_addr_len (const HevSocks5Addr *addr);
|
||||||
|
int hev_socks5_addr_from_name (HevSocks5Addr *addr, const char *name, int port);
|
||||||
|
int hev_socks5_addr_from_ipv4 (HevSocks5Addr *addr, const void *ipv4, int port);
|
||||||
|
int hev_socks5_addr_from_ipv6 (HevSocks5Addr *addr, const void *ipv6, int port);
|
||||||
|
int hev_socks5_addr_from_sockaddr6 (HevSocks5Addr *addr,
|
||||||
|
struct sockaddr_in6 *saddr);
|
||||||
|
int hev_socks5_addr_into_sockaddr6 (const HevSocks5Addr *addr,
|
||||||
|
struct sockaddr_in6 *saddr, int *family);
|
||||||
|
int hev_socks5_name_into_sockaddr6 (const char *host, int port,
|
||||||
|
struct sockaddr_in6 *saddr, int *family);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_MISC_H__ */
|
||||||
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-proto.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2023 hev
|
||||||
|
Description : Socks5 Proto
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_PROTO_H__
|
||||||
|
#define __HEV_SOCKS5_PROTO_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum _HevSocks5Version HevSocks5Version;
|
||||||
|
typedef enum _HevSocks5AuthMethod HevSocks5AuthMethod;
|
||||||
|
typedef enum _HevSocks5AuthVersion HevSocks5AuthVersion;
|
||||||
|
typedef enum _HevSocks5ReqCmd HevSocks5ReqCmd;
|
||||||
|
typedef enum _HevSocks5ResRep HevSocks5ResRep;
|
||||||
|
typedef enum _HevSocks5AddrType HevSocks5AddrType;
|
||||||
|
|
||||||
|
typedef struct _HevSocks5Auth HevSocks5Auth;
|
||||||
|
typedef struct _HevSocks5Addr HevSocks5Addr;
|
||||||
|
typedef struct _HevSocks5ReqRes HevSocks5ReqRes;
|
||||||
|
typedef struct _HevSocks5UDPHdr HevSocks5UDPHdr;
|
||||||
|
|
||||||
|
enum _HevSocks5Version
|
||||||
|
{
|
||||||
|
HEV_SOCKS5_VERSION_5 = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum _HevSocks5AuthMethod
|
||||||
|
{
|
||||||
|
HEV_SOCKS5_AUTH_METHOD_NONE = 0,
|
||||||
|
HEV_SOCKS5_AUTH_METHOD_USER = 2,
|
||||||
|
HEV_SOCKS5_AUTH_METHOD_DENY = 255,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum _HevSocks5AuthVersion
|
||||||
|
{
|
||||||
|
HEV_SOCKS5_AUTH_VERSION_1 = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum _HevSocks5ReqCmd
|
||||||
|
{
|
||||||
|
HEV_SOCKS5_REQ_CMD_CONNECT = 1,
|
||||||
|
HEV_SOCKS5_REQ_CMD_UDP_ASC = 3,
|
||||||
|
HEV_SOCKS5_REQ_CMD_FWD_UDP = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum _HevSocks5ResRep
|
||||||
|
{
|
||||||
|
HEV_SOCKS5_RES_REP_SUCC = 0,
|
||||||
|
HEV_SOCKS5_RES_REP_FAIL = 1,
|
||||||
|
HEV_SOCKS5_RES_REP_HOST = 4,
|
||||||
|
HEV_SOCKS5_RES_REP_IMPL = 7,
|
||||||
|
HEV_SOCKS5_RES_REP_ADDR = 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum _HevSocks5AddrType
|
||||||
|
{
|
||||||
|
HEV_SOCKS5_ADDR_TYPE_IPV4 = 1,
|
||||||
|
HEV_SOCKS5_ADDR_TYPE_IPV6 = 4,
|
||||||
|
HEV_SOCKS5_ADDR_TYPE_NAME = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5Auth
|
||||||
|
{
|
||||||
|
uint8_t ver;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint8_t method;
|
||||||
|
uint8_t method_len;
|
||||||
|
};
|
||||||
|
uint8_t methods[256];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct _HevSocks5Addr
|
||||||
|
{
|
||||||
|
uint8_t atype;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t addr[4];
|
||||||
|
uint16_t port;
|
||||||
|
} ipv4 __attribute__ ((packed));
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t addr[16];
|
||||||
|
uint16_t port;
|
||||||
|
} ipv6 __attribute__ ((packed));
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t len;
|
||||||
|
uint8_t addr[256 + 2];
|
||||||
|
} domain;
|
||||||
|
};
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct _HevSocks5ReqRes
|
||||||
|
{
|
||||||
|
uint8_t ver;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint8_t cmd;
|
||||||
|
uint8_t rep;
|
||||||
|
};
|
||||||
|
uint8_t rsv;
|
||||||
|
HevSocks5Addr addr;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct _HevSocks5UDPHdr
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint8_t rsv[3];
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint16_t datlen;
|
||||||
|
uint8_t hdrlen;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
};
|
||||||
|
HevSocks5Addr addr;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_PROTO_H__ */
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-server.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2023 hev
|
||||||
|
Description : Socks5 Server
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_SERVER_H__
|
||||||
|
#define __HEV_SOCKS5_SERVER_H__
|
||||||
|
|
||||||
|
#include <hev-object.h>
|
||||||
|
|
||||||
|
#include "hev-socks5.h"
|
||||||
|
#include "hev-socks5-tcp.h"
|
||||||
|
#include "hev-socks5-udp.h"
|
||||||
|
#include "hev-socks5-user.h"
|
||||||
|
#include "hev-socks5-authenticator.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HEV_SOCKS5_SERVER(p) ((HevSocks5Server *)p)
|
||||||
|
#define HEV_SOCKS5_SERVER_CLASS(p) ((HevSocks5ServerClass *)p)
|
||||||
|
#define HEV_SOCKS5_SERVER_TYPE (hev_socks5_server_class ())
|
||||||
|
|
||||||
|
typedef struct _HevSocks5Server HevSocks5Server;
|
||||||
|
typedef struct _HevSocks5ServerClass HevSocks5ServerClass;
|
||||||
|
|
||||||
|
struct _HevSocks5Server
|
||||||
|
{
|
||||||
|
HevSocks5 base;
|
||||||
|
|
||||||
|
int fds[2];
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
HevObject *obj;
|
||||||
|
HevSocks5User *user;
|
||||||
|
HevSocks5Authenticator *auth;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5ServerClass
|
||||||
|
{
|
||||||
|
HevSocks5Class base;
|
||||||
|
|
||||||
|
int (*binder) (HevSocks5Server *self, int sock, struct sockaddr_in6 *src);
|
||||||
|
|
||||||
|
HevSocks5TCPIface tcp;
|
||||||
|
HevSocks5UDPIface udp;
|
||||||
|
};
|
||||||
|
|
||||||
|
HevObjectClass *hev_socks5_server_class (void);
|
||||||
|
|
||||||
|
int hev_socks5_server_construct (HevSocks5Server *self, int fd);
|
||||||
|
|
||||||
|
HevSocks5Server *hev_socks5_server_new (int fd);
|
||||||
|
|
||||||
|
void hev_socks5_server_set_auth (HevSocks5Server *self,
|
||||||
|
HevSocks5Authenticator *auth);
|
||||||
|
|
||||||
|
int hev_socks5_server_run (HevSocks5Server *self);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_SERVER_H__ */
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-tcp.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 hev
|
||||||
|
Description : Socks5 TCP
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_TCP_H__
|
||||||
|
#define __HEV_SOCKS5_TCP_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HEV_SOCKS5_TCP(p) ((HevSocks5TCP *)p)
|
||||||
|
#define HEV_SOCKS5_TCP_IFACE(p) ((HevSocks5TCPIface *)p)
|
||||||
|
#define HEV_SOCKS5_TCP_TYPE (hev_socks5_tcp_iface ())
|
||||||
|
|
||||||
|
typedef void HevSocks5TCP;
|
||||||
|
typedef struct _HevSocks5TCPIface HevSocks5TCPIface;
|
||||||
|
|
||||||
|
struct _HevSocks5TCPIface
|
||||||
|
{
|
||||||
|
int (*splicer) (HevSocks5TCP *self, int fd);
|
||||||
|
};
|
||||||
|
|
||||||
|
void *hev_socks5_tcp_iface (void);
|
||||||
|
|
||||||
|
int hev_socks5_tcp_splice (HevSocks5TCP *self, int fd);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_TCP_H__ */
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-udp.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2025 hev
|
||||||
|
Description : Socks5 UDP
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_UDP_H__
|
||||||
|
#define __HEV_SOCKS5_UDP_H__
|
||||||
|
|
||||||
|
#include "hev-socks5-proto.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HEV_SOCKS5_UDP(p) ((HevSocks5UDP *)p)
|
||||||
|
#define HEV_SOCKS5_UDP_IFACE(p) ((HevSocks5UDPIface *)p)
|
||||||
|
#define HEV_SOCKS5_UDP_TYPE (hev_socks5_udp_iface ())
|
||||||
|
|
||||||
|
typedef void HevSocks5UDP;
|
||||||
|
typedef struct _HevSocks5UDPMsg HevSocks5UDPMsg;
|
||||||
|
typedef struct _HevSocks5UDPIface HevSocks5UDPIface;
|
||||||
|
|
||||||
|
struct _HevSocks5UDPMsg
|
||||||
|
{
|
||||||
|
HevSocks5Addr *addr;
|
||||||
|
void *buf;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5UDPIface
|
||||||
|
{
|
||||||
|
int (*get_fd) (HevSocks5UDP *self);
|
||||||
|
int (*splicer) (HevSocks5UDP *self, int fd);
|
||||||
|
};
|
||||||
|
|
||||||
|
void *hev_socks5_udp_iface (void);
|
||||||
|
|
||||||
|
int hev_socks5_udp_get_fd (HevSocks5UDP *self);
|
||||||
|
|
||||||
|
int hev_socks5_udp_sendmmsg (HevSocks5UDP *self, HevSocks5UDPMsg *msgv,
|
||||||
|
unsigned int num);
|
||||||
|
int hev_socks5_udp_recvmmsg (HevSocks5UDP *self, HevSocks5UDPMsg *msgv,
|
||||||
|
unsigned int num, int nonblock);
|
||||||
|
|
||||||
|
int hev_socks5_udp_splice (HevSocks5UDP *self, int fd);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_UDP_H__ */
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-user.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2023 hev
|
||||||
|
Description : Socks5 User
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_USER_H__
|
||||||
|
#define __HEV_SOCKS5_USER_H__
|
||||||
|
|
||||||
|
#include <hev-object-atomic.h>
|
||||||
|
|
||||||
|
#include "hev-rbtree.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HEV_SOCKS5_USER(p) ((HevSocks5User *)p)
|
||||||
|
#define HEV_SOCKS5_USER_CLASS(p) ((HevSocks5UserClass *)p)
|
||||||
|
#define HEV_SOCKS5_USER_TYPE (hev_socks5_user_class ())
|
||||||
|
|
||||||
|
typedef struct _HevSocks5User HevSocks5User;
|
||||||
|
typedef struct _HevSocks5UserClass HevSocks5UserClass;
|
||||||
|
|
||||||
|
struct _HevSocks5User
|
||||||
|
{
|
||||||
|
HevObjectAtomic base;
|
||||||
|
|
||||||
|
HevRBTreeNode node;
|
||||||
|
|
||||||
|
char *name;
|
||||||
|
char *pass;
|
||||||
|
unsigned int name_len;
|
||||||
|
unsigned int pass_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5UserClass
|
||||||
|
{
|
||||||
|
HevObjectAtomicClass base;
|
||||||
|
|
||||||
|
int (*checker) (HevSocks5User *self, const char *pass,
|
||||||
|
unsigned int pass_len);
|
||||||
|
};
|
||||||
|
|
||||||
|
HevObjectClass *hev_socks5_user_class (void);
|
||||||
|
|
||||||
|
int hev_socks5_user_construct (HevSocks5User *self, const char *name,
|
||||||
|
unsigned int name_len, const char *pass,
|
||||||
|
unsigned int pass_len);
|
||||||
|
|
||||||
|
HevSocks5User *hev_socks5_user_new (const char *name, unsigned int name_len,
|
||||||
|
const char *pass, unsigned int pass_len);
|
||||||
|
|
||||||
|
int hev_socks5_user_check (HevSocks5User *self, const char *pass,
|
||||||
|
unsigned int pass_len);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_USER_H__ */
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2023 hev
|
||||||
|
Description : Socks5
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_H__
|
||||||
|
#define __HEV_SOCKS5_H__
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include <hev-object.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HEV_SOCKS5(p) ((HevSocks5 *)p)
|
||||||
|
#define HEV_SOCKS5_CLASS(p) ((HevSocks5Class *)p)
|
||||||
|
#define HEV_SOCKS5_TYPE (hev_socks5_class ())
|
||||||
|
|
||||||
|
typedef struct _HevSocks5 HevSocks5;
|
||||||
|
typedef struct _HevSocks5Class HevSocks5Class;
|
||||||
|
typedef enum _HevSocks5Type HevSocks5Type;
|
||||||
|
typedef enum _HevSocks5AddrFamily HevSocks5AddrFamily;
|
||||||
|
|
||||||
|
enum _HevSocks5Type
|
||||||
|
{
|
||||||
|
HEV_SOCKS5_TYPE_NONE,
|
||||||
|
HEV_SOCKS5_TYPE_TCP,
|
||||||
|
HEV_SOCKS5_TYPE_UDP_IN_TCP,
|
||||||
|
HEV_SOCKS5_TYPE_UDP_IN_UDP,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum _HevSocks5AddrFamily
|
||||||
|
{
|
||||||
|
HEV_SOCKS5_ADDR_FAMILY_IPV4 = AF_INET,
|
||||||
|
HEV_SOCKS5_ADDR_FAMILY_IPV6 = AF_INET6,
|
||||||
|
HEV_SOCKS5_ADDR_FAMILY_UNSPEC = AF_UNSPEC,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5
|
||||||
|
{
|
||||||
|
HevObject base;
|
||||||
|
|
||||||
|
int fd;
|
||||||
|
int timeout;
|
||||||
|
int udp_associated;
|
||||||
|
HevSocks5Type type;
|
||||||
|
HevSocks5AddrFamily addr_family;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5Class
|
||||||
|
{
|
||||||
|
HevObjectClass base;
|
||||||
|
|
||||||
|
int (*binder) (HevSocks5 *self, int sock, const struct sockaddr *dest);
|
||||||
|
};
|
||||||
|
|
||||||
|
HevObjectClass *hev_socks5_class (void);
|
||||||
|
|
||||||
|
int hev_socks5_construct (HevSocks5 *self, HevSocks5Type type);
|
||||||
|
|
||||||
|
int hev_socks5_get_timeout (HevSocks5 *self);
|
||||||
|
void hev_socks5_set_timeout (HevSocks5 *self, int timeout);
|
||||||
|
|
||||||
|
HevSocks5AddrFamily hev_socks5_get_addr_family (HevSocks5 *self);
|
||||||
|
void hev_socks5_set_addr_family (HevSocks5 *self, HevSocks5AddrFamily family);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_H__ */
|
||||||
106
app/src/main/cpp/hev-socks5-tunnel/src/core/src/hev-compiler.h
Normal file
106
app/src/main/cpp/hev-socks5-tunnel/src/core/src/hev-compiler.h
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-compiler.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2019 everyone.
|
||||||
|
Description : Compiler
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_COMPILER_H__
|
||||||
|
#define __HEV_COMPILER_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ALIGN_UP(addr, align) \
|
||||||
|
((addr + (typeof (addr))align - 1) & ~((typeof (addr))align - 1))
|
||||||
|
|
||||||
|
#define ALIGN_DOWN(addr, align) ((addr) & ~((typeof (addr))align - 1))
|
||||||
|
|
||||||
|
#ifndef ARRAY_SIZE
|
||||||
|
#define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef EXPORT_SYMBOL
|
||||||
|
#define EXPORT_SYMBOL __attribute__ ((visibility ("default")))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define barrier() __asm__ __volatile__ ("" : : : "memory")
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
__read_once_size (void *dst, const volatile void *src, int size)
|
||||||
|
{
|
||||||
|
switch (size) {
|
||||||
|
case sizeof (char):
|
||||||
|
*(char *)dst = *(volatile char *)src;
|
||||||
|
break;
|
||||||
|
case sizeof (short):
|
||||||
|
*(short *)dst = *(volatile short *)src;
|
||||||
|
break;
|
||||||
|
case sizeof (int):
|
||||||
|
*(int *)dst = *(volatile int *)src;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
barrier ();
|
||||||
|
__builtin_memcpy ((void *)dst, (const void *)src, size);
|
||||||
|
barrier ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
__write_once_size (volatile void *dst, const void *src, int size)
|
||||||
|
{
|
||||||
|
switch (size) {
|
||||||
|
case sizeof (char):
|
||||||
|
*(volatile char *)dst = *(char *)src;
|
||||||
|
break;
|
||||||
|
case sizeof (short):
|
||||||
|
*(volatile short *)dst = *(short *)src;
|
||||||
|
break;
|
||||||
|
case sizeof (int):
|
||||||
|
*(volatile int *)dst = *(int *)src;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
barrier ();
|
||||||
|
__builtin_memcpy ((void *)dst, (const void *)src, size);
|
||||||
|
barrier ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define READ_ONCE(x) \
|
||||||
|
({ \
|
||||||
|
union \
|
||||||
|
{ \
|
||||||
|
typeof (x) __val; \
|
||||||
|
char __c[1]; \
|
||||||
|
} __u; \
|
||||||
|
__read_once_size (__u.__c, &(x), sizeof (x)); \
|
||||||
|
__u.__val; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define WRITE_ONCE(x, val) \
|
||||||
|
({ \
|
||||||
|
union \
|
||||||
|
{ \
|
||||||
|
typeof (x) __val; \
|
||||||
|
char __c[1]; \
|
||||||
|
} __u = { .__val = (typeof (x))(val) }; \
|
||||||
|
__write_once_size (&(x), __u.__c, sizeof (x)); \
|
||||||
|
__u.__val; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#ifndef container_of
|
||||||
|
#define container_of(ptr, type, member) \
|
||||||
|
({ \
|
||||||
|
void *__mptr = (void *)(ptr); \
|
||||||
|
((type *)(__mptr - offsetof (type, member))); \
|
||||||
|
})
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_COMPILER_H__ */
|
||||||
635
app/src/main/cpp/hev-socks5-tunnel/src/core/src/hev-rbtree.c
Normal file
635
app/src/main/cpp/hev-socks5-tunnel/src/core/src/hev-rbtree.c
Normal file
@ -0,0 +1,635 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-rbtree.c
|
||||||
|
Authors : Andrea Arcangeli <andrea@suse.de>
|
||||||
|
David Woodhouse <dwmw2@infradead.org>
|
||||||
|
Michel Lespinasse <walken@google.com>
|
||||||
|
Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2018 everyone.
|
||||||
|
Description : RedBlack Tree
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hev-rbtree.h"
|
||||||
|
|
||||||
|
typedef enum _HevRBTreeColor HevRBTreeColor;
|
||||||
|
|
||||||
|
enum _HevRBTreeColor
|
||||||
|
{
|
||||||
|
HEV_RBTREE_RED = 0,
|
||||||
|
HEV_RBTREE_BLACK,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hev_rbtree_node_color (HevRBTreeNode *node)
|
||||||
|
{
|
||||||
|
return node->__parent_color & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hev_rbtree_node_is_red (HevRBTreeNode *node)
|
||||||
|
{
|
||||||
|
return !(hev_rbtree_node_color (node) & HEV_RBTREE_BLACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hev_rbtree_node_is_black (HevRBTreeNode *node)
|
||||||
|
{
|
||||||
|
return hev_rbtree_node_color (node) & HEV_RBTREE_BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
_hev_rbtree_node_is_black (unsigned long pc)
|
||||||
|
{
|
||||||
|
return pc & HEV_RBTREE_BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline HevRBTreeNode *
|
||||||
|
_hev_rbtree_node_parent (unsigned long pc)
|
||||||
|
{
|
||||||
|
return ((HevRBTreeNode *)(pc & ~3));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline HevRBTreeNode *
|
||||||
|
hev_rbtree_node_red_parent (HevRBTreeNode *node)
|
||||||
|
{
|
||||||
|
return (HevRBTreeNode *)node->__parent_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
hev_rbtree_node_set_black (HevRBTreeNode *node)
|
||||||
|
{
|
||||||
|
node->__parent_color |= HEV_RBTREE_BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
hev_rbtree_node_set_parent (HevRBTreeNode *node, HevRBTreeNode *parent)
|
||||||
|
{
|
||||||
|
node->__parent_color = hev_rbtree_node_color (node) | (unsigned long)parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
hev_rbtree_node_set_parent_color (HevRBTreeNode *node, HevRBTreeNode *parent,
|
||||||
|
int color)
|
||||||
|
{
|
||||||
|
node->__parent_color = (unsigned long)parent | color;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
hev_rbtree_change_child (HevRBTree *self, HevRBTreeNode *old,
|
||||||
|
HevRBTreeNode *new, HevRBTreeNode *parent)
|
||||||
|
{
|
||||||
|
if (parent) {
|
||||||
|
if (parent->left == old)
|
||||||
|
parent->left = new;
|
||||||
|
else
|
||||||
|
parent->right = new;
|
||||||
|
} else {
|
||||||
|
self->root = new;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper function for rotations:
|
||||||
|
* - old's parent and color get assigned to new
|
||||||
|
* - old gets assigned new as a parent and 'color' as a color.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
hev_rbtree_rotate_set_parents (HevRBTree *self, HevRBTreeNode *old,
|
||||||
|
HevRBTreeNode *new, int color)
|
||||||
|
{
|
||||||
|
HevRBTreeNode *parent = hev_rbtree_node_parent (old);
|
||||||
|
new->__parent_color = old->__parent_color;
|
||||||
|
hev_rbtree_node_set_parent_color (old, new, color);
|
||||||
|
hev_rbtree_change_child (self, old, new, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
HevRBTreeNode *
|
||||||
|
hev_rbtree_node_prev (HevRBTreeNode *node)
|
||||||
|
{
|
||||||
|
HevRBTreeNode *parent;
|
||||||
|
|
||||||
|
if (hev_rbtree_node_empty (node))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have a left-hand child, go down and then right as far
|
||||||
|
* as we can.
|
||||||
|
*/
|
||||||
|
if (node->left) {
|
||||||
|
node = node->left;
|
||||||
|
while (node->right)
|
||||||
|
node = node->right;
|
||||||
|
return (HevRBTreeNode *)node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* No left-hand children. Go up till we find an ancestor which
|
||||||
|
* is a right-hand child of its parent.
|
||||||
|
*/
|
||||||
|
while ((parent = hev_rbtree_node_parent (node)) && node == parent->left)
|
||||||
|
node = parent;
|
||||||
|
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
HevRBTreeNode *
|
||||||
|
hev_rbtree_node_next (HevRBTreeNode *node)
|
||||||
|
{
|
||||||
|
HevRBTreeNode *parent;
|
||||||
|
|
||||||
|
if (hev_rbtree_node_empty (node))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have a right-hand child, go down and then left as far
|
||||||
|
* as we can.
|
||||||
|
*/
|
||||||
|
if (node->right) {
|
||||||
|
node = node->right;
|
||||||
|
while (node->left)
|
||||||
|
node = node->left;
|
||||||
|
return (HevRBTreeNode *)node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* No right-hand children. Everything down and left is smaller than us,
|
||||||
|
* so any 'next' node must be in the general direction of our parent.
|
||||||
|
* Go up the tree; any time the ancestor is a right-hand child of its
|
||||||
|
* parent, keep going up. First time it's a left-hand child of its
|
||||||
|
* parent, said parent is our 'next' node.
|
||||||
|
*/
|
||||||
|
while ((parent = hev_rbtree_node_parent (node)) && node == parent->right)
|
||||||
|
node = parent;
|
||||||
|
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
HevRBTreeNode *
|
||||||
|
hev_rbtree_first (HevRBTree *self)
|
||||||
|
{
|
||||||
|
HevRBTreeNode *n;
|
||||||
|
|
||||||
|
n = self->root;
|
||||||
|
if (!n)
|
||||||
|
return NULL;
|
||||||
|
while (n->left)
|
||||||
|
n = n->left;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
HevRBTreeNode *
|
||||||
|
hev_rbtree_last (HevRBTree *self)
|
||||||
|
{
|
||||||
|
HevRBTreeNode *n;
|
||||||
|
|
||||||
|
n = self->root;
|
||||||
|
if (!n)
|
||||||
|
return NULL;
|
||||||
|
while (n->right)
|
||||||
|
n = n->right;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_rbtree_insert_color (HevRBTree *self, HevRBTreeNode *node)
|
||||||
|
{
|
||||||
|
HevRBTreeNode *parent = hev_rbtree_node_red_parent (node), *gparent, *tmp;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
/*
|
||||||
|
* Loop invariant: node is red.
|
||||||
|
*/
|
||||||
|
if (!parent) {
|
||||||
|
/*
|
||||||
|
* The inserted node is root. Either this is the
|
||||||
|
* first node, or we recursed at Case 1 below and
|
||||||
|
* are no longer violating 4).
|
||||||
|
*/
|
||||||
|
hev_rbtree_node_set_parent_color (node, NULL, HEV_RBTREE_BLACK);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there is a black parent, we are done.
|
||||||
|
* Otherwise, take some corrective action as,
|
||||||
|
* per 4), we don't want a red root or two
|
||||||
|
* consecutive red nodes.
|
||||||
|
*/
|
||||||
|
if (hev_rbtree_node_is_black (parent))
|
||||||
|
break;
|
||||||
|
|
||||||
|
gparent = hev_rbtree_node_red_parent (parent);
|
||||||
|
|
||||||
|
tmp = gparent->right;
|
||||||
|
if (parent != tmp) { /* parent == gparent->left */
|
||||||
|
if (tmp && hev_rbtree_node_is_red (tmp)) {
|
||||||
|
/*
|
||||||
|
* Case 1 - node's uncle is red (color flips).
|
||||||
|
*
|
||||||
|
* G g
|
||||||
|
* / \ / \
|
||||||
|
* p u --> P U
|
||||||
|
* / /
|
||||||
|
* n n
|
||||||
|
*
|
||||||
|
* However, since g's parent might be red, and
|
||||||
|
* 4) does not allow this, we need to recurse
|
||||||
|
* at g.
|
||||||
|
*/
|
||||||
|
hev_rbtree_node_set_parent_color (tmp, gparent,
|
||||||
|
HEV_RBTREE_BLACK);
|
||||||
|
hev_rbtree_node_set_parent_color (parent, gparent,
|
||||||
|
HEV_RBTREE_BLACK);
|
||||||
|
node = gparent;
|
||||||
|
parent = hev_rbtree_node_parent (node);
|
||||||
|
hev_rbtree_node_set_parent_color (node, parent, HEV_RBTREE_RED);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = parent->right;
|
||||||
|
if (node == tmp) {
|
||||||
|
/*
|
||||||
|
* Case 2 - node's uncle is black and node is
|
||||||
|
* the parent's right child (left rotate at parent).
|
||||||
|
*
|
||||||
|
* G G
|
||||||
|
* / \ / \
|
||||||
|
* p U --> n U
|
||||||
|
* \ /
|
||||||
|
* n p
|
||||||
|
*
|
||||||
|
* This still leaves us in violation of 4), the
|
||||||
|
* continuation into Case 3 will fix that.
|
||||||
|
*/
|
||||||
|
tmp = node->left;
|
||||||
|
parent->right = tmp;
|
||||||
|
node->left = parent;
|
||||||
|
if (tmp)
|
||||||
|
hev_rbtree_node_set_parent_color (tmp, parent,
|
||||||
|
HEV_RBTREE_BLACK);
|
||||||
|
hev_rbtree_node_set_parent_color (parent, node, HEV_RBTREE_RED);
|
||||||
|
parent = node;
|
||||||
|
tmp = node->right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Case 3 - node's uncle is black and node is
|
||||||
|
* the parent's left child (right rotate at gparent).
|
||||||
|
*
|
||||||
|
* G P
|
||||||
|
* / \ / \
|
||||||
|
* p U --> n g
|
||||||
|
* / \
|
||||||
|
* n U
|
||||||
|
*/
|
||||||
|
gparent->left = tmp; /* == parent->right */
|
||||||
|
parent->right = gparent;
|
||||||
|
if (tmp)
|
||||||
|
hev_rbtree_node_set_parent_color (tmp, gparent,
|
||||||
|
HEV_RBTREE_BLACK);
|
||||||
|
hev_rbtree_rotate_set_parents (self, gparent, parent,
|
||||||
|
HEV_RBTREE_RED);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
tmp = gparent->left;
|
||||||
|
if (tmp && hev_rbtree_node_is_red (tmp)) {
|
||||||
|
/* Case 1 - color flips */
|
||||||
|
hev_rbtree_node_set_parent_color (tmp, gparent,
|
||||||
|
HEV_RBTREE_BLACK);
|
||||||
|
hev_rbtree_node_set_parent_color (parent, gparent,
|
||||||
|
HEV_RBTREE_BLACK);
|
||||||
|
node = gparent;
|
||||||
|
parent = hev_rbtree_node_parent (node);
|
||||||
|
hev_rbtree_node_set_parent_color (node, parent, HEV_RBTREE_RED);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = parent->left;
|
||||||
|
if (node == tmp) {
|
||||||
|
/* Case 2 - right rotate at parent */
|
||||||
|
tmp = node->right;
|
||||||
|
parent->left = tmp;
|
||||||
|
node->right = parent;
|
||||||
|
if (tmp)
|
||||||
|
hev_rbtree_node_set_parent_color (tmp, parent,
|
||||||
|
HEV_RBTREE_BLACK);
|
||||||
|
hev_rbtree_node_set_parent_color (parent, node, HEV_RBTREE_RED);
|
||||||
|
parent = node;
|
||||||
|
tmp = node->left;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Case 3 - left rotate at gparent */
|
||||||
|
gparent->right = tmp; /* == parent->left */
|
||||||
|
parent->left = gparent;
|
||||||
|
if (tmp)
|
||||||
|
hev_rbtree_node_set_parent_color (tmp, gparent,
|
||||||
|
HEV_RBTREE_BLACK);
|
||||||
|
hev_rbtree_rotate_set_parents (self, gparent, parent,
|
||||||
|
HEV_RBTREE_RED);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_rbtree_replace (HevRBTree *self, HevRBTreeNode *victim, HevRBTreeNode *new)
|
||||||
|
{
|
||||||
|
HevRBTreeNode *parent = hev_rbtree_node_parent (victim);
|
||||||
|
|
||||||
|
/* Copy the pointers/colour from the victim to the replacement */
|
||||||
|
*new = *victim;
|
||||||
|
|
||||||
|
/* Set the surrounding nodes to point to the replacement */
|
||||||
|
if (victim->left)
|
||||||
|
hev_rbtree_node_set_parent (victim->left, new);
|
||||||
|
if (victim->right)
|
||||||
|
hev_rbtree_node_set_parent (victim->right, new);
|
||||||
|
hev_rbtree_change_child (self, victim, new, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline HevRBTreeNode *
|
||||||
|
_hev_rbtree_erase (HevRBTree *self, HevRBTreeNode *node)
|
||||||
|
{
|
||||||
|
HevRBTreeNode *child = node->right;
|
||||||
|
HevRBTreeNode *tmp = node->left;
|
||||||
|
HevRBTreeNode *parent, *rebalance;
|
||||||
|
unsigned long pc;
|
||||||
|
|
||||||
|
if (!tmp) {
|
||||||
|
/*
|
||||||
|
* Case 1: node to erase has no more than 1 child (easy!)
|
||||||
|
*
|
||||||
|
* Note that if there is one child it must be red due to 5)
|
||||||
|
* and node must be black due to 4). We adjust colors locally
|
||||||
|
* so as to bypass _hev_rbtree_erase_color() later on.
|
||||||
|
*/
|
||||||
|
pc = node->__parent_color;
|
||||||
|
parent = _hev_rbtree_node_parent (pc);
|
||||||
|
hev_rbtree_change_child (self, node, child, parent);
|
||||||
|
if (child) {
|
||||||
|
child->__parent_color = pc;
|
||||||
|
rebalance = NULL;
|
||||||
|
} else
|
||||||
|
rebalance = _hev_rbtree_node_is_black (pc) ? parent : NULL;
|
||||||
|
tmp = parent;
|
||||||
|
} else if (!child) {
|
||||||
|
/* Still case 1, but this time the child is node->left */
|
||||||
|
tmp->__parent_color = pc = node->__parent_color;
|
||||||
|
parent = _hev_rbtree_node_parent (pc);
|
||||||
|
hev_rbtree_change_child (self, node, tmp, parent);
|
||||||
|
rebalance = NULL;
|
||||||
|
tmp = parent;
|
||||||
|
} else {
|
||||||
|
HevRBTreeNode *successor = child, *child2;
|
||||||
|
|
||||||
|
tmp = child->left;
|
||||||
|
if (!tmp) {
|
||||||
|
/*
|
||||||
|
* Case 2: node's successor is its right child
|
||||||
|
*
|
||||||
|
* (n) (s)
|
||||||
|
* / \ / \
|
||||||
|
* (x) (s) -> (x) (c)
|
||||||
|
* \
|
||||||
|
* (c)
|
||||||
|
*/
|
||||||
|
parent = successor;
|
||||||
|
child2 = successor->right;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Case 3: node's successor is leftmost under
|
||||||
|
* node's right child subtree
|
||||||
|
*
|
||||||
|
* (n) (s)
|
||||||
|
* / \ / \
|
||||||
|
* (x) (y) -> (x) (y)
|
||||||
|
* / /
|
||||||
|
* (p) (p)
|
||||||
|
* / /
|
||||||
|
* (s) (c)
|
||||||
|
* \
|
||||||
|
* (c)
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
parent = successor;
|
||||||
|
successor = tmp;
|
||||||
|
tmp = tmp->left;
|
||||||
|
} while (tmp);
|
||||||
|
child2 = successor->right;
|
||||||
|
parent->left = child2;
|
||||||
|
successor->right = child;
|
||||||
|
hev_rbtree_node_set_parent (child, successor);
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = node->left;
|
||||||
|
successor->left = tmp;
|
||||||
|
hev_rbtree_node_set_parent (tmp, successor);
|
||||||
|
|
||||||
|
pc = node->__parent_color;
|
||||||
|
tmp = _hev_rbtree_node_parent (pc);
|
||||||
|
hev_rbtree_change_child (self, node, successor, tmp);
|
||||||
|
|
||||||
|
if (child2) {
|
||||||
|
hev_rbtree_node_set_parent_color (child2, parent, HEV_RBTREE_BLACK);
|
||||||
|
rebalance = NULL;
|
||||||
|
} else {
|
||||||
|
rebalance = hev_rbtree_node_is_black (successor) ? parent : NULL;
|
||||||
|
}
|
||||||
|
successor->__parent_color = pc;
|
||||||
|
tmp = successor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rebalance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inline version for hev_rbtree_erase() use - we want to be able to inline
|
||||||
|
* and eliminate the dummy_rotate callback there
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
_hev_rbtree_erase_color (HevRBTree *self, HevRBTreeNode *parent)
|
||||||
|
{
|
||||||
|
HevRBTreeNode *node = NULL, *sibling, *tmp1, *tmp2;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
/*
|
||||||
|
* Loop invariants:
|
||||||
|
* - node is black (or NULL on first iteration)
|
||||||
|
* - node is not the root (parent is not NULL)
|
||||||
|
* - All leaf paths going through parent and node have a
|
||||||
|
* black node count that is 1 lower than other leaf paths.
|
||||||
|
*/
|
||||||
|
sibling = parent->right;
|
||||||
|
if (node != sibling) { /* node == parent->left */
|
||||||
|
if (hev_rbtree_node_is_red (sibling)) {
|
||||||
|
/*
|
||||||
|
* Case 1 - left rotate at parent
|
||||||
|
*
|
||||||
|
* P S
|
||||||
|
* / \ / \
|
||||||
|
* N s --> p Sr
|
||||||
|
* / \ / \
|
||||||
|
* Sl Sr N Sl
|
||||||
|
*/
|
||||||
|
tmp1 = sibling->left;
|
||||||
|
parent->right = tmp1;
|
||||||
|
sibling->left = parent;
|
||||||
|
hev_rbtree_node_set_parent_color (tmp1, parent,
|
||||||
|
HEV_RBTREE_BLACK);
|
||||||
|
hev_rbtree_rotate_set_parents (self, parent, sibling,
|
||||||
|
HEV_RBTREE_RED);
|
||||||
|
sibling = tmp1;
|
||||||
|
}
|
||||||
|
tmp1 = sibling->right;
|
||||||
|
if (!tmp1 || hev_rbtree_node_is_black (tmp1)) {
|
||||||
|
tmp2 = sibling->left;
|
||||||
|
if (!tmp2 || hev_rbtree_node_is_black (tmp2)) {
|
||||||
|
/*
|
||||||
|
* Case 2 - sibling color flip
|
||||||
|
* (p could be either color here)
|
||||||
|
*
|
||||||
|
* (p) (p)
|
||||||
|
* / \ / \
|
||||||
|
* N S --> N s
|
||||||
|
* / \ / \
|
||||||
|
* Sl Sr Sl Sr
|
||||||
|
*
|
||||||
|
* This leaves us violating 5) which
|
||||||
|
* can be fixed by flipping p to black
|
||||||
|
* if it was red, or by recursing at p.
|
||||||
|
* p is red when coming from Case 1.
|
||||||
|
*/
|
||||||
|
hev_rbtree_node_set_parent_color (sibling, parent,
|
||||||
|
HEV_RBTREE_RED);
|
||||||
|
if (hev_rbtree_node_is_red (parent))
|
||||||
|
hev_rbtree_node_set_black (parent);
|
||||||
|
else {
|
||||||
|
node = parent;
|
||||||
|
parent = hev_rbtree_node_parent (node);
|
||||||
|
if (parent)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Case 3 - right rotate at sibling
|
||||||
|
* (p could be either color here)
|
||||||
|
*
|
||||||
|
* (p) (p)
|
||||||
|
* / \ / \
|
||||||
|
* N S --> N sl
|
||||||
|
* / \ \
|
||||||
|
* sl Sr S
|
||||||
|
* \
|
||||||
|
* Sr
|
||||||
|
*
|
||||||
|
* Note: p might be red, and then both
|
||||||
|
* p and sl are red after rotation(which
|
||||||
|
* breaks property 4). This is fixed in
|
||||||
|
* Case 4 (in hev_rbtree_rotate_set_parents()
|
||||||
|
* which set sl the color of p
|
||||||
|
* and set p HEV_RBTREE_BLACK)
|
||||||
|
*
|
||||||
|
* (p) (sl)
|
||||||
|
* / \ / \
|
||||||
|
* N sl --> P S
|
||||||
|
* \ / \
|
||||||
|
* S N Sr
|
||||||
|
* \
|
||||||
|
* Sr
|
||||||
|
*/
|
||||||
|
tmp1 = tmp2->right;
|
||||||
|
sibling->left = tmp1;
|
||||||
|
tmp2->right = sibling;
|
||||||
|
parent->right = tmp2;
|
||||||
|
if (tmp1)
|
||||||
|
hev_rbtree_node_set_parent_color (tmp1, sibling,
|
||||||
|
HEV_RBTREE_BLACK);
|
||||||
|
tmp1 = sibling;
|
||||||
|
sibling = tmp2;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Case 4 - left rotate at parent + color flips
|
||||||
|
* (p and sl could be either color here.
|
||||||
|
* After rotation, p becomes black, s acquires
|
||||||
|
* p's color, and sl keeps its color)
|
||||||
|
*
|
||||||
|
* (p) (s)
|
||||||
|
* / \ / \
|
||||||
|
* N S --> P Sr
|
||||||
|
* / \ / \
|
||||||
|
* (sl) sr N (sl)
|
||||||
|
*/
|
||||||
|
tmp2 = sibling->left;
|
||||||
|
parent->right = tmp2;
|
||||||
|
sibling->left = parent;
|
||||||
|
hev_rbtree_node_set_parent_color (tmp1, sibling, HEV_RBTREE_BLACK);
|
||||||
|
if (tmp2)
|
||||||
|
hev_rbtree_node_set_parent (tmp2, parent);
|
||||||
|
hev_rbtree_rotate_set_parents (self, parent, sibling,
|
||||||
|
HEV_RBTREE_BLACK);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
sibling = parent->left;
|
||||||
|
if (hev_rbtree_node_is_red (sibling)) {
|
||||||
|
/* Case 1 - right rotate at parent */
|
||||||
|
tmp1 = sibling->right;
|
||||||
|
parent->left = tmp1;
|
||||||
|
sibling->right = parent;
|
||||||
|
hev_rbtree_node_set_parent_color (tmp1, parent,
|
||||||
|
HEV_RBTREE_BLACK);
|
||||||
|
hev_rbtree_rotate_set_parents (self, parent, sibling,
|
||||||
|
HEV_RBTREE_RED);
|
||||||
|
sibling = tmp1;
|
||||||
|
}
|
||||||
|
tmp1 = sibling->left;
|
||||||
|
if (!tmp1 || hev_rbtree_node_is_black (tmp1)) {
|
||||||
|
tmp2 = sibling->right;
|
||||||
|
if (!tmp2 || hev_rbtree_node_is_black (tmp2)) {
|
||||||
|
/* Case 2 - sibling color flip */
|
||||||
|
hev_rbtree_node_set_parent_color (sibling, parent,
|
||||||
|
HEV_RBTREE_RED);
|
||||||
|
if (hev_rbtree_node_is_red (parent))
|
||||||
|
hev_rbtree_node_set_black (parent);
|
||||||
|
else {
|
||||||
|
node = parent;
|
||||||
|
parent = hev_rbtree_node_parent (node);
|
||||||
|
if (parent)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Case 3 - left rotate at sibling */
|
||||||
|
tmp1 = tmp2->left;
|
||||||
|
sibling->right = tmp1;
|
||||||
|
tmp2->left = sibling;
|
||||||
|
parent->left = tmp2;
|
||||||
|
if (tmp1)
|
||||||
|
hev_rbtree_node_set_parent_color (tmp1, sibling,
|
||||||
|
HEV_RBTREE_BLACK);
|
||||||
|
tmp1 = sibling;
|
||||||
|
sibling = tmp2;
|
||||||
|
}
|
||||||
|
/* Case 4 - right rotate at parent + color flips */
|
||||||
|
tmp2 = sibling->right;
|
||||||
|
parent->left = tmp2;
|
||||||
|
sibling->right = parent;
|
||||||
|
hev_rbtree_node_set_parent_color (tmp1, sibling, HEV_RBTREE_BLACK);
|
||||||
|
if (tmp2)
|
||||||
|
hev_rbtree_node_set_parent (tmp2, parent);
|
||||||
|
hev_rbtree_rotate_set_parents (self, parent, sibling,
|
||||||
|
HEV_RBTREE_BLACK);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_rbtree_erase (HevRBTree *self, HevRBTreeNode *node)
|
||||||
|
{
|
||||||
|
HevRBTreeNode *rebalance;
|
||||||
|
rebalance = _hev_rbtree_erase (self, node);
|
||||||
|
if (rebalance)
|
||||||
|
_hev_rbtree_erase_color (self, rebalance);
|
||||||
|
}
|
||||||
68
app/src/main/cpp/hev-socks5-tunnel/src/core/src/hev-rbtree.h
Normal file
68
app/src/main/cpp/hev-socks5-tunnel/src/core/src/hev-rbtree.h
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-rbtree.h
|
||||||
|
Authors : Andrea Arcangeli <andrea@suse.de>
|
||||||
|
David Woodhouse <dwmw2@infradead.org>
|
||||||
|
Michel Lespinasse <walken@google.com>
|
||||||
|
Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2018 everyone.
|
||||||
|
Description : RedBlack Tree
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_RBTREE_H__
|
||||||
|
#define __HEV_RBTREE_H__
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef struct _HevRBTree HevRBTree;
|
||||||
|
typedef struct _HevRBTreeNode HevRBTreeNode;
|
||||||
|
|
||||||
|
struct _HevRBTree
|
||||||
|
{
|
||||||
|
HevRBTreeNode *root;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevRBTreeNode
|
||||||
|
{
|
||||||
|
unsigned long __parent_color;
|
||||||
|
HevRBTreeNode *right;
|
||||||
|
HevRBTreeNode *left;
|
||||||
|
} __attribute__ ((aligned (sizeof (long))));
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
hev_rbtree_node_empty (HevRBTreeNode *node)
|
||||||
|
{
|
||||||
|
return node->__parent_color == (unsigned long)node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline HevRBTreeNode *
|
||||||
|
hev_rbtree_node_parent (HevRBTreeNode *node)
|
||||||
|
{
|
||||||
|
return (HevRBTreeNode *)(node->__parent_color & ~3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
hev_rbtree_node_link (HevRBTreeNode *node, HevRBTreeNode *parent,
|
||||||
|
HevRBTreeNode **link)
|
||||||
|
{
|
||||||
|
node->__parent_color = (unsigned long)parent;
|
||||||
|
node->left = node->right = NULL;
|
||||||
|
|
||||||
|
*link = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
HevRBTreeNode *hev_rbtree_node_prev (HevRBTreeNode *node);
|
||||||
|
HevRBTreeNode *hev_rbtree_node_next (HevRBTreeNode *node);
|
||||||
|
|
||||||
|
HevRBTreeNode *hev_rbtree_first (HevRBTree *self);
|
||||||
|
HevRBTreeNode *hev_rbtree_last (HevRBTree *self);
|
||||||
|
|
||||||
|
void hev_rbtree_insert_color (HevRBTree *self, HevRBTreeNode *node);
|
||||||
|
|
||||||
|
void hev_rbtree_replace (HevRBTree *self, HevRBTreeNode *victim,
|
||||||
|
HevRBTreeNode *new);
|
||||||
|
|
||||||
|
void hev_rbtree_erase (HevRBTree *self, HevRBTreeNode *node);
|
||||||
|
|
||||||
|
#endif /* __HEV_RBTREE_H__ */
|
||||||
@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-authenticator.c
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2023 hev
|
||||||
|
Description : Socks5 Authenticator
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "hev-compiler.h"
|
||||||
|
#include "hev-socks5-logger-priv.h"
|
||||||
|
|
||||||
|
#include "hev-socks5-authenticator.h"
|
||||||
|
|
||||||
|
HevSocks5Authenticator *
|
||||||
|
hev_socks5_authenticator_new (void)
|
||||||
|
{
|
||||||
|
HevSocks5Authenticator *self;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
self = calloc (1, sizeof (HevSocks5Authenticator));
|
||||||
|
if (!self)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
res = hev_socks5_authenticator_construct (self);
|
||||||
|
if (res < 0) {
|
||||||
|
free (self);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 authenticator new", self);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_authenticator_add (HevSocks5Authenticator *self, HevSocks5User *user)
|
||||||
|
{
|
||||||
|
HevRBTreeNode **new = &self->tree.root, *parent = NULL;
|
||||||
|
|
||||||
|
while (*new) {
|
||||||
|
HevSocks5User *this;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
this = container_of (*new, HevSocks5User, node);
|
||||||
|
|
||||||
|
if (this->name_len < user->name_len)
|
||||||
|
res = -1;
|
||||||
|
else if (this->name_len > user->name_len)
|
||||||
|
res = 1;
|
||||||
|
else
|
||||||
|
res = memcmp (this->name, user->name, this->name_len);
|
||||||
|
|
||||||
|
parent = *new;
|
||||||
|
if (res < 0)
|
||||||
|
new = &((*new)->left);
|
||||||
|
else if (res > 0)
|
||||||
|
new = &((*new)->right);
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
hev_rbtree_node_link (&user->node, parent, new);
|
||||||
|
hev_rbtree_insert_color (&self->tree, &user->node);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_authenticator_del (HevSocks5Authenticator *self, const char *name,
|
||||||
|
unsigned int name_len)
|
||||||
|
{
|
||||||
|
HevRBTreeNode *node = self->tree.root;
|
||||||
|
|
||||||
|
while (node) {
|
||||||
|
HevSocks5User *this;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
this = container_of (node, HevSocks5User, node);
|
||||||
|
if (this->name_len < name_len)
|
||||||
|
res = -1;
|
||||||
|
else if (this->name_len > name_len)
|
||||||
|
res = 1;
|
||||||
|
else
|
||||||
|
res = memcmp (this->name, name, name_len);
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
node = node->left;
|
||||||
|
} else if (res > 0) {
|
||||||
|
node = node->right;
|
||||||
|
} else {
|
||||||
|
hev_rbtree_erase (&self->tree, node);
|
||||||
|
hev_object_unref (HEV_OBJECT (this));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HevSocks5User *
|
||||||
|
hev_socks5_authenticator_get (HevSocks5Authenticator *self, const char *name,
|
||||||
|
unsigned int name_len)
|
||||||
|
{
|
||||||
|
HevRBTreeNode *node = self->tree.root;
|
||||||
|
|
||||||
|
while (node) {
|
||||||
|
HevSocks5User *this;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
this = container_of (node, HevSocks5User, node);
|
||||||
|
if (this->name_len < name_len)
|
||||||
|
res = -1;
|
||||||
|
else if (this->name_len > name_len)
|
||||||
|
res = 1;
|
||||||
|
else
|
||||||
|
res = memcmp (this->name, name, name_len);
|
||||||
|
|
||||||
|
if (res < 0)
|
||||||
|
node = node->left;
|
||||||
|
else if (res > 0)
|
||||||
|
node = node->right;
|
||||||
|
else
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_authenticator_clear (HevSocks5Authenticator *self)
|
||||||
|
{
|
||||||
|
HevRBTreeNode *n;
|
||||||
|
|
||||||
|
while ((n = hev_rbtree_first (&self->tree))) {
|
||||||
|
HevSocks5User *t;
|
||||||
|
|
||||||
|
t = container_of (n, HevSocks5User, node);
|
||||||
|
hev_rbtree_erase (&self->tree, n);
|
||||||
|
hev_object_unref (HEV_OBJECT (t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_authenticator_construct (HevSocks5Authenticator *self)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = hev_object_atomic_construct (&self->base);
|
||||||
|
if (res < 0)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 authenticator construct", self);
|
||||||
|
|
||||||
|
HEV_OBJECT (self)->klass = HEV_SOCKS5_AUTHENTICATOR_TYPE;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hev_socks5_authenticator_destruct (HevObject *base)
|
||||||
|
{
|
||||||
|
HevSocks5Authenticator *self = HEV_SOCKS5_AUTHENTICATOR (base);
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 authenticator destruct", self);
|
||||||
|
|
||||||
|
hev_socks5_authenticator_clear (self);
|
||||||
|
|
||||||
|
HEV_OBJECT_ATOMIC_TYPE->destruct (base);
|
||||||
|
free (base);
|
||||||
|
}
|
||||||
|
|
||||||
|
HevObjectClass *
|
||||||
|
hev_socks5_authenticator_class (void)
|
||||||
|
{
|
||||||
|
static HevSocks5AuthenticatorClass klass;
|
||||||
|
HevSocks5AuthenticatorClass *kptr = &klass;
|
||||||
|
HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr);
|
||||||
|
|
||||||
|
if (!okptr->name) {
|
||||||
|
memcpy (kptr, HEV_OBJECT_ATOMIC_TYPE, sizeof (HevObjectAtomicClass));
|
||||||
|
|
||||||
|
okptr->name = "HevSocks5Authenticator";
|
||||||
|
okptr->destruct = hev_socks5_authenticator_destruct;
|
||||||
|
}
|
||||||
|
|
||||||
|
return okptr;
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-authenticator.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2023 hev
|
||||||
|
Description : Socks5 Authenticator
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_AUTHENTICATOR_H__
|
||||||
|
#define __HEV_SOCKS5_AUTHENTICATOR_H__
|
||||||
|
|
||||||
|
#include <hev-object-atomic.h>
|
||||||
|
|
||||||
|
#include "hev-rbtree.h"
|
||||||
|
#include "hev-socks5-user.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HEV_SOCKS5_AUTHENTICATOR(p) ((HevSocks5Authenticator *)p)
|
||||||
|
#define HEV_SOCKS5_AUTHENTICATOR_CLASS(p) ((HevSocks5AuthenticatorClass *)p)
|
||||||
|
#define HEV_SOCKS5_AUTHENTICATOR_TYPE (hev_socks5_authenticator_class ())
|
||||||
|
|
||||||
|
typedef struct _HevSocks5Authenticator HevSocks5Authenticator;
|
||||||
|
typedef struct _HevSocks5AuthenticatorClass HevSocks5AuthenticatorClass;
|
||||||
|
typedef enum _HevSocks5AuthenticatorType HevSocks5AuthenticatorType;
|
||||||
|
|
||||||
|
struct _HevSocks5Authenticator
|
||||||
|
{
|
||||||
|
HevObjectAtomic base;
|
||||||
|
|
||||||
|
HevRBTree tree;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5AuthenticatorClass
|
||||||
|
{
|
||||||
|
HevObjectAtomicClass base;
|
||||||
|
};
|
||||||
|
|
||||||
|
HevObjectClass *hev_socks5_authenticator_class (void);
|
||||||
|
|
||||||
|
int hev_socks5_authenticator_construct (HevSocks5Authenticator *self);
|
||||||
|
|
||||||
|
HevSocks5Authenticator *hev_socks5_authenticator_new (void);
|
||||||
|
|
||||||
|
int hev_socks5_authenticator_add (HevSocks5Authenticator *self,
|
||||||
|
HevSocks5User *user);
|
||||||
|
|
||||||
|
int hev_socks5_authenticator_del (HevSocks5Authenticator *self,
|
||||||
|
const char *name, unsigned int name_len);
|
||||||
|
|
||||||
|
HevSocks5User *hev_socks5_authenticator_get (HevSocks5Authenticator *self,
|
||||||
|
const char *name,
|
||||||
|
unsigned int name_len);
|
||||||
|
|
||||||
|
void hev_socks5_authenticator_clear (HevSocks5Authenticator *self);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_AUTHENTICATOR_H__ */
|
||||||
@ -0,0 +1,185 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-client-tcp.c
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2025 hev
|
||||||
|
Description : Socks5 Client TCP
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <hev-memory-allocator.h>
|
||||||
|
|
||||||
|
#include "hev-socks5-misc-priv.h"
|
||||||
|
#include "hev-socks5-logger-priv.h"
|
||||||
|
|
||||||
|
#include "hev-socks5-client-tcp.h"
|
||||||
|
|
||||||
|
HevSocks5ClientTCP *
|
||||||
|
hev_socks5_client_tcp_new_name (const char *name, int port)
|
||||||
|
{
|
||||||
|
HevSocks5ClientTCP *self;
|
||||||
|
HevSocks5Addr addr;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
self = hev_malloc0 (sizeof (HevSocks5ClientTCP));
|
||||||
|
if (!self)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
hev_socks5_addr_from_name (&addr, name, port);
|
||||||
|
res = hev_socks5_client_tcp_construct (self, &addr);
|
||||||
|
if (res < 0) {
|
||||||
|
hev_free (self);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 client tcp new name", self);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
HevSocks5ClientTCP *
|
||||||
|
hev_socks5_client_tcp_new_ipv4 (const void *ipv4, int port)
|
||||||
|
{
|
||||||
|
HevSocks5ClientTCP *self;
|
||||||
|
HevSocks5Addr addr;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
self = hev_malloc0 (sizeof (HevSocks5ClientTCP));
|
||||||
|
if (!self)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
hev_socks5_addr_from_ipv4 (&addr, ipv4, port);
|
||||||
|
res = hev_socks5_client_tcp_construct (self, &addr);
|
||||||
|
if (res < 0) {
|
||||||
|
hev_free (self);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 client tcp new ipv4", self);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
HevSocks5ClientTCP *
|
||||||
|
hev_socks5_client_tcp_new_ipv6 (const void *ipv6, int port)
|
||||||
|
{
|
||||||
|
HevSocks5ClientTCP *self;
|
||||||
|
HevSocks5Addr addr;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
self = hev_malloc0 (sizeof (HevSocks5ClientTCP));
|
||||||
|
if (!self)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
hev_socks5_addr_from_ipv6 (&addr, ipv6, port);
|
||||||
|
res = hev_socks5_client_tcp_construct (self, &addr);
|
||||||
|
if (res < 0) {
|
||||||
|
hev_free (self);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 client tcp new ipv6", self);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HevSocks5Addr *
|
||||||
|
hev_socks5_client_tcp_get_upstream_addr (HevSocks5Client *base)
|
||||||
|
{
|
||||||
|
HevSocks5ClientTCP *self = HEV_SOCKS5_CLIENT_TCP (base);
|
||||||
|
HevSocks5Addr *addr;
|
||||||
|
|
||||||
|
addr = self->addr;
|
||||||
|
self->addr = NULL;
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_client_tcp_set_upstream_addr (HevSocks5Client *base,
|
||||||
|
HevSocks5Addr *addr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_client_tcp_construct (HevSocks5ClientTCP *self,
|
||||||
|
const HevSocks5Addr *addr)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = hev_socks5_client_construct (&self->base, HEV_SOCKS5_TYPE_TCP);
|
||||||
|
if (res < 0)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 client tcp construct", self);
|
||||||
|
|
||||||
|
HEV_OBJECT (self)->klass = HEV_SOCKS5_CLIENT_TCP_TYPE;
|
||||||
|
|
||||||
|
res = hev_socks5_addr_len (addr);
|
||||||
|
self->addr = hev_malloc (res);
|
||||||
|
if (!self->addr)
|
||||||
|
return -1;
|
||||||
|
memcpy (self->addr, addr, res);
|
||||||
|
|
||||||
|
if (LOG_ON ()) {
|
||||||
|
const char *str;
|
||||||
|
char buf[272];
|
||||||
|
|
||||||
|
str = hev_socks5_addr_into_str (self->addr, buf, sizeof (buf));
|
||||||
|
LOG_I ("%p socks5 client tcp -> %s", self, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hev_socks5_client_tcp_destruct (HevObject *base)
|
||||||
|
{
|
||||||
|
HevSocks5ClientTCP *self = HEV_SOCKS5_CLIENT_TCP (base);
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 client tcp destruct", self);
|
||||||
|
|
||||||
|
if (self->addr)
|
||||||
|
hev_free (self->addr);
|
||||||
|
|
||||||
|
HEV_SOCKS5_CLIENT_TYPE->destruct (base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
hev_socks5_client_tcp_iface (HevObject *base, void *type)
|
||||||
|
{
|
||||||
|
HevSocks5ClientTCPClass *klass = HEV_OBJECT_GET_CLASS (base);
|
||||||
|
|
||||||
|
return &klass->tcp;
|
||||||
|
}
|
||||||
|
|
||||||
|
HevObjectClass *
|
||||||
|
hev_socks5_client_tcp_class (void)
|
||||||
|
{
|
||||||
|
static HevSocks5ClientTCPClass klass;
|
||||||
|
HevSocks5ClientTCPClass *kptr = &klass;
|
||||||
|
HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr);
|
||||||
|
|
||||||
|
if (!okptr->name) {
|
||||||
|
HevSocks5ClientClass *ckptr;
|
||||||
|
HevSocks5TCPIface *tiptr;
|
||||||
|
|
||||||
|
memcpy (kptr, HEV_SOCKS5_CLIENT_TYPE, sizeof (HevSocks5ClientClass));
|
||||||
|
|
||||||
|
okptr->name = "HevSocks5ClientTCP";
|
||||||
|
okptr->destruct = hev_socks5_client_tcp_destruct;
|
||||||
|
okptr->iface = hev_socks5_client_tcp_iface;
|
||||||
|
|
||||||
|
ckptr = HEV_SOCKS5_CLIENT_CLASS (kptr);
|
||||||
|
ckptr->get_upstream_addr = hev_socks5_client_tcp_get_upstream_addr;
|
||||||
|
ckptr->set_upstream_addr = hev_socks5_client_tcp_set_upstream_addr;
|
||||||
|
|
||||||
|
tiptr = &kptr->tcp;
|
||||||
|
memcpy (tiptr, HEV_SOCKS5_TCP_TYPE, sizeof (HevSocks5TCPIface));
|
||||||
|
}
|
||||||
|
|
||||||
|
return okptr;
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-client-tcp.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2025 hev
|
||||||
|
Description : Socks5 Client TCP
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_CLIENT_TCP_H__
|
||||||
|
#define __HEV_SOCKS5_CLIENT_TCP_H__
|
||||||
|
|
||||||
|
#include "hev-socks5-tcp.h"
|
||||||
|
#include "hev-socks5-proto.h"
|
||||||
|
|
||||||
|
#include "hev-socks5-client.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HEV_SOCKS5_CLIENT_TCP(p) ((HevSocks5ClientTCP *)p)
|
||||||
|
#define HEV_SOCKS5_CLIENT_TCP_CLASS(p) ((HevSocks5ClientTCPClass *)p)
|
||||||
|
#define HEV_SOCKS5_CLIENT_TCP_TYPE (hev_socks5_client_tcp_class ())
|
||||||
|
|
||||||
|
typedef struct _HevSocks5ClientTCP HevSocks5ClientTCP;
|
||||||
|
typedef struct _HevSocks5ClientTCPClass HevSocks5ClientTCPClass;
|
||||||
|
|
||||||
|
struct _HevSocks5ClientTCP
|
||||||
|
{
|
||||||
|
HevSocks5Client base;
|
||||||
|
|
||||||
|
HevSocks5Addr *addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5ClientTCPClass
|
||||||
|
{
|
||||||
|
HevSocks5ClientClass base;
|
||||||
|
|
||||||
|
HevSocks5TCPIface tcp;
|
||||||
|
};
|
||||||
|
|
||||||
|
HevObjectClass *hev_socks5_client_tcp_class (void);
|
||||||
|
|
||||||
|
int hev_socks5_client_tcp_construct (HevSocks5ClientTCP *self,
|
||||||
|
const HevSocks5Addr *addr);
|
||||||
|
|
||||||
|
HevSocks5ClientTCP *hev_socks5_client_tcp_new_name (const char *name, int port);
|
||||||
|
HevSocks5ClientTCP *hev_socks5_client_tcp_new_ipv4 (const void *ipv4, int port);
|
||||||
|
HevSocks5ClientTCP *hev_socks5_client_tcp_new_ipv6 (const void *ipv6, int port);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_CLIENT_TCP_H__ */
|
||||||
@ -0,0 +1,213 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-client-udp.c
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2025 hev
|
||||||
|
Description : Socks5 Client UDP
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
#include <hev-task-io.h>
|
||||||
|
#include <hev-task-io-socket.h>
|
||||||
|
#include <hev-memory-allocator.h>
|
||||||
|
|
||||||
|
#include "hev-socks5-misc-priv.h"
|
||||||
|
#include "hev-socks5-logger-priv.h"
|
||||||
|
|
||||||
|
#include "hev-socks5-client-udp.h"
|
||||||
|
|
||||||
|
#define task_io_yielder hev_socks5_task_io_yielder
|
||||||
|
|
||||||
|
HevSocks5ClientUDP *
|
||||||
|
hev_socks5_client_udp_new (HevSocks5Type type)
|
||||||
|
{
|
||||||
|
HevSocks5ClientUDP *self;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
self = hev_malloc0 (sizeof (HevSocks5ClientUDP));
|
||||||
|
if (!self)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
res = hev_socks5_client_udp_construct (self, type);
|
||||||
|
if (res < 0) {
|
||||||
|
hev_free (self);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 client udp new", self);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HevSocks5Addr *
|
||||||
|
hev_socks5_client_udp_get_upstream_addr (HevSocks5Client *base)
|
||||||
|
{
|
||||||
|
HevSocks5AddrFamily family;
|
||||||
|
HevSocks5Addr *addr;
|
||||||
|
|
||||||
|
family = hev_socks5_get_addr_family (HEV_SOCKS5 (base));
|
||||||
|
|
||||||
|
switch (family) {
|
||||||
|
case HEV_SOCKS5_ADDR_FAMILY_IPV4:
|
||||||
|
addr = hev_malloc0 (7);
|
||||||
|
if (addr)
|
||||||
|
addr->atype = HEV_SOCKS5_ADDR_TYPE_IPV4;
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_ADDR_FAMILY_IPV6:
|
||||||
|
addr = hev_malloc0 (19);
|
||||||
|
if (addr)
|
||||||
|
addr->atype = HEV_SOCKS5_ADDR_TYPE_IPV6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
addr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_client_udp_set_upstream_addr (HevSocks5Client *base,
|
||||||
|
HevSocks5Addr *addr)
|
||||||
|
{
|
||||||
|
HevSocks5ClientUDP *self = HEV_SOCKS5_CLIENT_UDP (base);
|
||||||
|
struct sockaddr_in6 saddr;
|
||||||
|
struct sockaddr *sadp;
|
||||||
|
HevSocks5Class *klass;
|
||||||
|
int addr_family;
|
||||||
|
int res;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (HEV_SOCKS5 (base)->type != HEV_SOCKS5_TYPE_UDP_IN_UDP)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memset (&saddr, 0, sizeof (saddr));
|
||||||
|
addr_family = hev_socks5_get_addr_family (HEV_SOCKS5 (self));
|
||||||
|
res = hev_socks5_addr_into_sockaddr6 (addr, &saddr, &addr_family);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_W ("%p socks5 client udp addr", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = hev_socks5_socket (SOCK_DGRAM);
|
||||||
|
if (fd < 0) {
|
||||||
|
LOG_E ("%p socks5 client udp socket", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sadp = (struct sockaddr *)&saddr;
|
||||||
|
klass = HEV_OBJECT_GET_CLASS (self);
|
||||||
|
res = klass->binder (HEV_SOCKS5 (self), fd, sadp);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_W ("%p socks5 client udp bind", self);
|
||||||
|
hev_task_del_fd (hev_task_self (), fd);
|
||||||
|
close (fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_task_io_socket_connect (fd, sadp, sizeof (saddr), task_io_yielder,
|
||||||
|
self);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_I ("%p socks5 client udp connect", self);
|
||||||
|
hev_task_del_fd (hev_task_self (), fd);
|
||||||
|
close (fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HEV_SOCKS5 (self)->udp_associated = 1;
|
||||||
|
self->fd = fd;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_client_udp_get_fd (HevSocks5UDP *self)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
switch (HEV_SOCKS5 (self)->type) {
|
||||||
|
case HEV_SOCKS5_TYPE_UDP_IN_TCP:
|
||||||
|
fd = HEV_SOCKS5 (self)->fd;
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_TYPE_UDP_IN_UDP:
|
||||||
|
fd = HEV_SOCKS5_CLIENT_UDP (self)->fd;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_client_udp_construct (HevSocks5ClientUDP *self, HevSocks5Type type)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = hev_socks5_client_construct (&self->base, type);
|
||||||
|
if (res < 0)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
LOG_I ("%p socks5 client udp construct", self);
|
||||||
|
|
||||||
|
HEV_OBJECT (self)->klass = HEV_SOCKS5_CLIENT_UDP_TYPE;
|
||||||
|
|
||||||
|
self->fd = -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hev_socks5_client_udp_destruct (HevObject *base)
|
||||||
|
{
|
||||||
|
HevSocks5ClientUDP *self = HEV_SOCKS5_CLIENT_UDP (base);
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 client udp destruct", self);
|
||||||
|
|
||||||
|
if (self->fd >= 0) {
|
||||||
|
hev_task_del_fd (hev_task_self (), self->fd);
|
||||||
|
close (self->fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
HEV_SOCKS5_CLIENT_TYPE->destruct (base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
hev_socks5_client_udp_iface (HevObject *base, void *type)
|
||||||
|
{
|
||||||
|
HevSocks5ClientUDPClass *klass = HEV_OBJECT_GET_CLASS (base);
|
||||||
|
|
||||||
|
return &klass->udp;
|
||||||
|
}
|
||||||
|
|
||||||
|
HevObjectClass *
|
||||||
|
hev_socks5_client_udp_class (void)
|
||||||
|
{
|
||||||
|
static HevSocks5ClientUDPClass klass;
|
||||||
|
HevSocks5ClientUDPClass *kptr = &klass;
|
||||||
|
HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr);
|
||||||
|
|
||||||
|
if (!okptr->name) {
|
||||||
|
HevSocks5ClientClass *ckptr;
|
||||||
|
HevSocks5UDPIface *uiptr;
|
||||||
|
|
||||||
|
memcpy (kptr, HEV_SOCKS5_CLIENT_TYPE, sizeof (HevSocks5ClientClass));
|
||||||
|
|
||||||
|
okptr->name = "HevSocks5ClientUDP";
|
||||||
|
okptr->destruct = hev_socks5_client_udp_destruct;
|
||||||
|
okptr->iface = hev_socks5_client_udp_iface;
|
||||||
|
|
||||||
|
ckptr = HEV_SOCKS5_CLIENT_CLASS (kptr);
|
||||||
|
ckptr->get_upstream_addr = hev_socks5_client_udp_get_upstream_addr;
|
||||||
|
ckptr->set_upstream_addr = hev_socks5_client_udp_set_upstream_addr;
|
||||||
|
|
||||||
|
uiptr = &kptr->udp;
|
||||||
|
memcpy (uiptr, HEV_SOCKS5_UDP_TYPE, sizeof (HevSocks5UDPIface));
|
||||||
|
uiptr->get_fd = hev_socks5_client_udp_get_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
return okptr;
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-client-udp.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2023 hev
|
||||||
|
Description : Socks5 Client UDP
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_CLIENT_UDP_H__
|
||||||
|
#define __HEV_SOCKS5_CLIENT_UDP_H__
|
||||||
|
|
||||||
|
#include "hev-socks5-udp.h"
|
||||||
|
|
||||||
|
#include "hev-socks5-client.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HEV_SOCKS5_CLIENT_UDP(p) ((HevSocks5ClientUDP *)p)
|
||||||
|
#define HEV_SOCKS5_CLIENT_UDP_CLASS(p) ((HevSocks5ClientUDPClass *)p)
|
||||||
|
#define HEV_SOCKS5_CLIENT_UDP_TYPE (hev_socks5_client_udp_class ())
|
||||||
|
|
||||||
|
typedef struct _HevSocks5ClientUDP HevSocks5ClientUDP;
|
||||||
|
typedef struct _HevSocks5ClientUDPClass HevSocks5ClientUDPClass;
|
||||||
|
|
||||||
|
struct _HevSocks5ClientUDP
|
||||||
|
{
|
||||||
|
HevSocks5Client base;
|
||||||
|
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5ClientUDPClass
|
||||||
|
{
|
||||||
|
HevSocks5ClientClass base;
|
||||||
|
|
||||||
|
HevSocks5UDPIface udp;
|
||||||
|
};
|
||||||
|
|
||||||
|
HevObjectClass *hev_socks5_client_udp_class (void);
|
||||||
|
|
||||||
|
int hev_socks5_client_udp_construct (HevSocks5ClientUDP *self,
|
||||||
|
HevSocks5Type type);
|
||||||
|
|
||||||
|
HevSocks5ClientUDP *hev_socks5_client_udp_new (HevSocks5Type type);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_CLIENT_UDP_H__ */
|
||||||
@ -0,0 +1,475 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-client.c
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2025 hev
|
||||||
|
Description : Socks5 Client
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
#include <hev-task-io.h>
|
||||||
|
#include <hev-task-io-socket.h>
|
||||||
|
#include <hev-memory-allocator.h>
|
||||||
|
|
||||||
|
#include "hev-socks5-misc-priv.h"
|
||||||
|
#include "hev-socks5-logger-priv.h"
|
||||||
|
|
||||||
|
#include "hev-socks5-client.h"
|
||||||
|
|
||||||
|
#define task_io_yielder hev_socks5_task_io_yielder
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_client_write_auth_methods (HevSocks5Client *self)
|
||||||
|
{
|
||||||
|
HevSocks5Auth auth;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 client write auth methods", self);
|
||||||
|
|
||||||
|
auth.ver = HEV_SOCKS5_VERSION_5;
|
||||||
|
auth.method_len = 1;
|
||||||
|
if (!self->auth.user || !self->auth.pass)
|
||||||
|
auth.methods[0] = HEV_SOCKS5_AUTH_METHOD_NONE;
|
||||||
|
else
|
||||||
|
auth.methods[0] = HEV_SOCKS5_AUTH_METHOD_USER;
|
||||||
|
|
||||||
|
res = hev_task_io_socket_send (HEV_SOCKS5 (self)->fd, &auth, 3, MSG_WAITALL,
|
||||||
|
task_io_yielder, self);
|
||||||
|
if (res <= 0) {
|
||||||
|
LOG_I ("%p socks5 client write auth methods", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_client_write_auth_creds (HevSocks5Client *self)
|
||||||
|
{
|
||||||
|
struct msghdr mh = { 0 };
|
||||||
|
struct iovec iov[4];
|
||||||
|
unsigned char ub[3];
|
||||||
|
int res;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 client write auth creds", self);
|
||||||
|
|
||||||
|
if (!self->auth.user || !self->auth.pass)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ub[0] = HEV_SOCKS5_AUTH_VERSION_1;
|
||||||
|
ub[1] = strlen (self->auth.user);
|
||||||
|
ub[2] = strlen (self->auth.pass);
|
||||||
|
iov[0].iov_base = &ub[0];
|
||||||
|
iov[0].iov_len = 2;
|
||||||
|
iov[1].iov_base = (void *)self->auth.user;
|
||||||
|
iov[1].iov_len = ub[1];
|
||||||
|
iov[2].iov_base = &ub[2];
|
||||||
|
iov[2].iov_len = 1;
|
||||||
|
iov[3].iov_base = (void *)self->auth.pass;
|
||||||
|
iov[3].iov_len = ub[2];
|
||||||
|
|
||||||
|
mh.msg_iov = iov;
|
||||||
|
mh.msg_iovlen = 4;
|
||||||
|
res = hev_task_io_socket_sendmsg (HEV_SOCKS5 (self)->fd, &mh, MSG_WAITALL,
|
||||||
|
task_io_yielder, self);
|
||||||
|
if (res <= 0) {
|
||||||
|
LOG_I ("%p socks5 client write auth creds", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_client_write_request (HevSocks5Client *self)
|
||||||
|
{
|
||||||
|
HevSocks5ClientClass *klass;
|
||||||
|
struct msghdr mh = { 0 };
|
||||||
|
struct iovec iov[2];
|
||||||
|
HevSocks5Addr *addr;
|
||||||
|
HevSocks5ReqRes req;
|
||||||
|
int addrlen;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 client write request", self);
|
||||||
|
|
||||||
|
req.ver = HEV_SOCKS5_VERSION_5;
|
||||||
|
req.rsv = 0;
|
||||||
|
|
||||||
|
switch (HEV_SOCKS5 (self)->type) {
|
||||||
|
case HEV_SOCKS5_TYPE_TCP:
|
||||||
|
req.cmd = HEV_SOCKS5_REQ_CMD_CONNECT;
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_TYPE_UDP_IN_TCP:
|
||||||
|
req.cmd = HEV_SOCKS5_REQ_CMD_FWD_UDP;
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_TYPE_UDP_IN_UDP:
|
||||||
|
req.cmd = HEV_SOCKS5_REQ_CMD_UDP_ASC;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iov[0].iov_base = &req;
|
||||||
|
iov[0].iov_len = 3;
|
||||||
|
|
||||||
|
klass = HEV_OBJECT_GET_CLASS (self);
|
||||||
|
addr = klass->get_upstream_addr (self);
|
||||||
|
|
||||||
|
switch (addr->atype) {
|
||||||
|
case HEV_SOCKS5_ADDR_TYPE_IPV4:
|
||||||
|
addrlen = 7;
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_ADDR_TYPE_IPV6:
|
||||||
|
addrlen = 19;
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_ADDR_TYPE_NAME:
|
||||||
|
addrlen = 4 + addr->domain.len;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_I ("%p socks5 client req.atype %u", self, addr->atype);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iov[1].iov_base = addr;
|
||||||
|
iov[1].iov_len = addrlen;
|
||||||
|
|
||||||
|
mh.msg_iov = iov;
|
||||||
|
mh.msg_iovlen = 2;
|
||||||
|
ret = hev_task_io_socket_sendmsg (HEV_SOCKS5 (self)->fd, &mh, MSG_WAITALL,
|
||||||
|
task_io_yielder, self);
|
||||||
|
if (ret <= 0) {
|
||||||
|
LOG_I ("%p socks5 client write request", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
hev_free (addr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_client_read_auth_method (HevSocks5Client *self)
|
||||||
|
{
|
||||||
|
HevSocks5Auth auth;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 client read auth method", self);
|
||||||
|
|
||||||
|
res = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, &auth, 2, MSG_WAITALL,
|
||||||
|
task_io_yielder, self);
|
||||||
|
if (res != 2) {
|
||||||
|
LOG_I ("%p socks5 client read auth", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auth.ver != HEV_SOCKS5_VERSION_5) {
|
||||||
|
LOG_I ("%p socks5 client auth.ver %u", self, auth.ver);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return auth.method;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_client_read_auth_creds (HevSocks5Client *self)
|
||||||
|
{
|
||||||
|
HevSocks5ReqRes res;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 client read auth creds", self);
|
||||||
|
|
||||||
|
ret = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, &res, 2, MSG_WAITALL,
|
||||||
|
task_io_yielder, self);
|
||||||
|
if (ret != 2) {
|
||||||
|
LOG_I ("%p socks5 client read auth creds", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.ver != HEV_SOCKS5_AUTH_VERSION_1) {
|
||||||
|
LOG_I ("%p socks5 client auth.res.ver %u", self, res.ver);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.rep != HEV_SOCKS5_RES_REP_SUCC) {
|
||||||
|
LOG_I ("%p socks5 client auth.res.rep %u", self, res.rep);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 client auth done", self);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_client_read_response (HevSocks5Client *self)
|
||||||
|
{
|
||||||
|
HevSocks5ClientClass *klass;
|
||||||
|
HevSocks5ReqRes res;
|
||||||
|
int addrlen;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 client read response", self);
|
||||||
|
|
||||||
|
ret = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, &res, 4, MSG_WAITALL,
|
||||||
|
task_io_yielder, self);
|
||||||
|
if (ret != 4) {
|
||||||
|
LOG_I ("%p socks5 client read response", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.ver != HEV_SOCKS5_VERSION_5) {
|
||||||
|
LOG_I ("%p socks5 client res.ver %u", self, res.ver);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.rep != HEV_SOCKS5_RES_REP_SUCC) {
|
||||||
|
LOG_I ("%p socks5 client res.rep %u", self, res.rep);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (res.addr.atype) {
|
||||||
|
case HEV_SOCKS5_ADDR_TYPE_IPV4:
|
||||||
|
addrlen = 6;
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_ADDR_TYPE_IPV6:
|
||||||
|
addrlen = 18;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_I ("%p socks5 client res.atype %u", self, res.addr.atype);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, &res.addr.ipv4,
|
||||||
|
addrlen, MSG_WAITALL, task_io_yielder, self);
|
||||||
|
if (ret != addrlen) {
|
||||||
|
LOG_I ("%p socks5 client read addr", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
klass = HEV_OBJECT_GET_CLASS (self);
|
||||||
|
ret = klass->set_upstream_addr (self, &res.addr);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_W ("%p socks5 client set upstream addr", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_client_connect (HevSocks5Client *self, const char *addr, int port)
|
||||||
|
{
|
||||||
|
HevSocks5Class *klass;
|
||||||
|
struct sockaddr_in6 saddr;
|
||||||
|
struct sockaddr *sap;
|
||||||
|
int addr_family;
|
||||||
|
int timeout;
|
||||||
|
int fd, res;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 client connect [%s]:%d", self, addr, port);
|
||||||
|
|
||||||
|
timeout = hev_socks5_get_connect_timeout ();
|
||||||
|
hev_socks5_set_timeout (HEV_SOCKS5 (self), timeout);
|
||||||
|
|
||||||
|
memset (&saddr, 0, sizeof (saddr));
|
||||||
|
addr_family = hev_socks5_get_addr_family (HEV_SOCKS5 (self));
|
||||||
|
res = hev_socks5_name_into_sockaddr6 (addr, port, &saddr, &addr_family);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_I ("%p socks5 client resolve [%s]:%d", self, addr, port);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = hev_socks5_socket (SOCK_STREAM);
|
||||||
|
if (fd < 0) {
|
||||||
|
LOG_E ("%p socks5 client socket", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sap = (struct sockaddr *)&saddr;
|
||||||
|
klass = HEV_OBJECT_GET_CLASS (self);
|
||||||
|
res = klass->binder (HEV_SOCKS5 (self), fd, sap);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_W ("%p socks5 client bind", self);
|
||||||
|
hev_task_del_fd (hev_task_self (), fd);
|
||||||
|
close (fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_task_io_socket_connect (fd, sap, sizeof (saddr), task_io_yielder,
|
||||||
|
self);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_I ("%p socks5 client connect", self);
|
||||||
|
hev_task_del_fd (hev_task_self (), fd);
|
||||||
|
close (fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HEV_SOCKS5 (self)->fd = fd;
|
||||||
|
hev_socks5_set_addr_family (HEV_SOCKS5 (self), addr_family);
|
||||||
|
LOG_D ("%p socks5 client connect server fd %d", self, fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_client_handshake_standard (HevSocks5Client *self)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 client handshake standard", self);
|
||||||
|
|
||||||
|
res = hev_socks5_client_write_auth_methods (self);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
res = hev_socks5_client_read_auth_method (self);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (res == HEV_SOCKS5_AUTH_METHOD_USER) {
|
||||||
|
res = hev_socks5_client_write_auth_creds (self);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
res = hev_socks5_client_read_auth_creds (self);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
} else if (res != HEV_SOCKS5_AUTH_METHOD_NONE) {
|
||||||
|
LOG_I ("%p socks5 client auth method %d", self, res);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_socks5_client_write_request (self);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
res = hev_socks5_client_read_response (self);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_client_handshake_pipeline (HevSocks5Client *self)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 client handshake pipeline", self);
|
||||||
|
|
||||||
|
res = hev_socks5_client_write_auth_methods (self);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
res = hev_socks5_client_write_auth_creds (self);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
res = hev_socks5_client_write_request (self);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
res = hev_socks5_client_read_auth_method (self);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (res == HEV_SOCKS5_AUTH_METHOD_USER) {
|
||||||
|
res = hev_socks5_client_read_auth_creds (self);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
} else if (res != HEV_SOCKS5_AUTH_METHOD_NONE) {
|
||||||
|
LOG_I ("%p socks5 client auth method %d", self, res);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_socks5_client_read_response (self);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_client_handshake (HevSocks5Client *self, int pipeline)
|
||||||
|
{
|
||||||
|
int timeout;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
timeout = hev_socks5_get_tcp_timeout ();
|
||||||
|
hev_socks5_set_timeout (HEV_SOCKS5 (self), timeout);
|
||||||
|
|
||||||
|
if (pipeline)
|
||||||
|
res = hev_socks5_client_handshake_pipeline (self);
|
||||||
|
else
|
||||||
|
res = hev_socks5_client_handshake_standard (self);
|
||||||
|
|
||||||
|
switch (HEV_SOCKS5 (self)->type) {
|
||||||
|
case HEV_SOCKS5_TYPE_UDP_IN_TCP:
|
||||||
|
case HEV_SOCKS5_TYPE_UDP_IN_UDP:
|
||||||
|
timeout = hev_socks5_get_udp_timeout ();
|
||||||
|
hev_socks5_set_timeout (HEV_SOCKS5 (self), timeout);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_client_set_auth (HevSocks5Client *self, const char *user,
|
||||||
|
const char *pass)
|
||||||
|
{
|
||||||
|
LOG_D ("%p socks5 client set auth", self);
|
||||||
|
|
||||||
|
self->auth.user = user;
|
||||||
|
self->auth.pass = pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_client_construct (HevSocks5Client *self, HevSocks5Type type)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = hev_socks5_construct (&self->base, type);
|
||||||
|
if (res < 0)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 client construct", self);
|
||||||
|
|
||||||
|
HEV_OBJECT (self)->klass = HEV_SOCKS5_CLIENT_TYPE;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hev_socks5_client_destruct (HevObject *base)
|
||||||
|
{
|
||||||
|
HevSocks5Client *self = HEV_SOCKS5_CLIENT (base);
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 client destruct", self);
|
||||||
|
|
||||||
|
HEV_SOCKS5_TYPE->destruct (base);
|
||||||
|
}
|
||||||
|
|
||||||
|
HevObjectClass *
|
||||||
|
hev_socks5_client_class (void)
|
||||||
|
{
|
||||||
|
static HevSocks5ClientClass klass;
|
||||||
|
HevSocks5ClientClass *kptr = &klass;
|
||||||
|
HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr);
|
||||||
|
|
||||||
|
if (!okptr->name) {
|
||||||
|
memcpy (kptr, HEV_SOCKS5_TYPE, sizeof (HevSocks5Class));
|
||||||
|
|
||||||
|
okptr->name = "HevSocks5Client";
|
||||||
|
okptr->destruct = hev_socks5_client_destruct;
|
||||||
|
}
|
||||||
|
|
||||||
|
return okptr;
|
||||||
|
}
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-client.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2024 hev
|
||||||
|
Description : Socks5 Client
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_CLIENT_H__
|
||||||
|
#define __HEV_SOCKS5_CLIENT_H__
|
||||||
|
|
||||||
|
#include "hev-socks5.h"
|
||||||
|
#include "hev-socks5-proto.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HEV_SOCKS5_CLIENT(p) ((HevSocks5Client *)p)
|
||||||
|
#define HEV_SOCKS5_CLIENT_CLASS(p) ((HevSocks5ClientClass *)p)
|
||||||
|
#define HEV_SOCKS5_CLIENT_TYPE (hev_socks5_client_class ())
|
||||||
|
|
||||||
|
typedef struct _HevSocks5Client HevSocks5Client;
|
||||||
|
typedef struct _HevSocks5ClientClass HevSocks5ClientClass;
|
||||||
|
|
||||||
|
struct _HevSocks5Client
|
||||||
|
{
|
||||||
|
HevSocks5 base;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
const char *user;
|
||||||
|
const char *pass;
|
||||||
|
} auth;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5ClientClass
|
||||||
|
{
|
||||||
|
HevSocks5Class base;
|
||||||
|
|
||||||
|
HevSocks5Addr *(*get_upstream_addr) (HevSocks5Client *self);
|
||||||
|
int (*set_upstream_addr) (HevSocks5Client *self, HevSocks5Addr *addr);
|
||||||
|
};
|
||||||
|
|
||||||
|
HevObjectClass *hev_socks5_client_class (void);
|
||||||
|
|
||||||
|
int hev_socks5_client_construct (HevSocks5Client *self, HevSocks5Type type);
|
||||||
|
|
||||||
|
int hev_socks5_client_connect (HevSocks5Client *self, const char *addr,
|
||||||
|
int port);
|
||||||
|
|
||||||
|
int hev_socks5_client_handshake (HevSocks5Client *self, int pipeline);
|
||||||
|
|
||||||
|
void hev_socks5_client_set_auth (HevSocks5Client *self, const char *user,
|
||||||
|
const char *pass);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_CLIENT_H__ */
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-logger-priv.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 hev
|
||||||
|
Description : Socks5 Logger Private
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_LOGGER_PRIV_H__
|
||||||
|
#define __HEV_SOCKS5_LOGGER_PRIV_H__
|
||||||
|
|
||||||
|
#include "hev-socks5-logger.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LOG_D(fmt...) hev_socks5_logger_log (HEV_SOCKS5_LOGGER_DEBUG, fmt)
|
||||||
|
#define LOG_I(fmt...) hev_socks5_logger_log (HEV_SOCKS5_LOGGER_INFO, fmt)
|
||||||
|
#define LOG_W(fmt...) hev_socks5_logger_log (HEV_SOCKS5_LOGGER_WARN, fmt)
|
||||||
|
#define LOG_E(fmt...) hev_socks5_logger_log (HEV_SOCKS5_LOGGER_ERROR, fmt)
|
||||||
|
|
||||||
|
#define LOG_ON() hev_socks5_logger_enabled (HEV_SOCKS5_LOGGER_UNSET)
|
||||||
|
#define LOG_ON_D() hev_socks5_logger_enabled (HEV_SOCKS5_LOGGER_DEBUG)
|
||||||
|
#define LOG_ON_I() hev_socks5_logger_enabled (HEV_SOCKS5_LOGGER_INFO)
|
||||||
|
#define LOG_ON_W() hev_socks5_logger_enabled (HEV_SOCKS5_LOGGER_WARN)
|
||||||
|
#define LOG_ON_E() hev_socks5_logger_enabled (HEV_SOCKS5_LOGGER_ERROR)
|
||||||
|
|
||||||
|
int hev_socks5_logger_enabled (HevSocks5LoggerLevel level);
|
||||||
|
void hev_socks5_logger_log (HevSocks5LoggerLevel level, const char *fmt, ...);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_LOGGER_PRIV_H__ */
|
||||||
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-logger.c
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 hev
|
||||||
|
Description : Socks5 Logger
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "hev-socks5-logger.h"
|
||||||
|
#include "hev-socks5-logger-priv.h"
|
||||||
|
|
||||||
|
static int fd = -1;
|
||||||
|
static HevSocks5LoggerLevel req_level;
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_logger_init (HevSocks5LoggerLevel level, const char *path)
|
||||||
|
{
|
||||||
|
req_level = level;
|
||||||
|
|
||||||
|
if (0 == strcmp (path, "stdout"))
|
||||||
|
fd = dup (1);
|
||||||
|
else if (0 == strcmp (path, "stderr"))
|
||||||
|
fd = dup (2);
|
||||||
|
else
|
||||||
|
fd = open (path, O_WRONLY | O_APPEND | O_CREAT, 0640);
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_logger_fini (void)
|
||||||
|
{
|
||||||
|
close (fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_logger_enabled (HevSocks5LoggerLevel level)
|
||||||
|
{
|
||||||
|
if (level >= req_level && fd >= 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_logger_log (HevSocks5LoggerLevel level, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
struct iovec iov[4];
|
||||||
|
const char *ts_fmt;
|
||||||
|
char msg[1024];
|
||||||
|
struct tm *ti;
|
||||||
|
char ts[32];
|
||||||
|
time_t now;
|
||||||
|
va_list ap;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (level < req_level || fd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
time (&now);
|
||||||
|
ti = localtime (&now);
|
||||||
|
|
||||||
|
ts_fmt = "[%04u-%02u-%02u %02u:%02u:%02u] ";
|
||||||
|
len = snprintf (ts, sizeof (ts), ts_fmt, 1900 + ti->tm_year, 1 + ti->tm_mon,
|
||||||
|
ti->tm_mday, ti->tm_hour, ti->tm_min, ti->tm_sec);
|
||||||
|
|
||||||
|
iov[0].iov_base = ts;
|
||||||
|
iov[0].iov_len = len;
|
||||||
|
|
||||||
|
switch (level) {
|
||||||
|
case HEV_SOCKS5_LOGGER_DEBUG:
|
||||||
|
iov[1].iov_base = "[D] ";
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_LOGGER_INFO:
|
||||||
|
iov[1].iov_base = "[I] ";
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_LOGGER_WARN:
|
||||||
|
iov[1].iov_base = "[W] ";
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_LOGGER_ERROR:
|
||||||
|
iov[1].iov_base = "[E] ";
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_LOGGER_UNSET:
|
||||||
|
iov[1].iov_base = "[?] ";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
iov[1].iov_len = 4;
|
||||||
|
|
||||||
|
va_start (ap, fmt);
|
||||||
|
iov[2].iov_base = msg;
|
||||||
|
iov[2].iov_len = vsnprintf (msg, 1024, fmt, ap);
|
||||||
|
va_end (ap);
|
||||||
|
|
||||||
|
iov[3].iov_base = "\n";
|
||||||
|
iov[3].iov_len = 1;
|
||||||
|
|
||||||
|
if (writev (fd, iov, 4)) {
|
||||||
|
/* ignore return value */
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-logger.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 hev
|
||||||
|
Description : Socks5 Logger
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_LOGGER_H__
|
||||||
|
#define __HEV_SOCKS5_LOGGER_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum _HevSocks5LoggerLevel HevSocks5LoggerLevel;
|
||||||
|
|
||||||
|
enum _HevSocks5LoggerLevel
|
||||||
|
{
|
||||||
|
HEV_SOCKS5_LOGGER_DEBUG,
|
||||||
|
HEV_SOCKS5_LOGGER_INFO,
|
||||||
|
HEV_SOCKS5_LOGGER_WARN,
|
||||||
|
HEV_SOCKS5_LOGGER_ERROR,
|
||||||
|
HEV_SOCKS5_LOGGER_UNSET,
|
||||||
|
};
|
||||||
|
|
||||||
|
int hev_socks5_logger_init (HevSocks5LoggerLevel level, const char *path);
|
||||||
|
void hev_socks5_logger_fini (void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_LOGGER_H__ */
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-misc-priv.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2025 hev
|
||||||
|
Description : Socks5 Misc Private
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_MISC_PRIV_H__
|
||||||
|
#define __HEV_SOCKS5_MISC_PRIV_H__
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
#include <hev-task-io.h>
|
||||||
|
|
||||||
|
#include "hev-socks5-misc.h"
|
||||||
|
#include "hev-socks5-proto.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int hev_socks5_socket (int type);
|
||||||
|
|
||||||
|
const char *hev_socks5_addr_into_str (const HevSocks5Addr *addr, char *buf,
|
||||||
|
int len);
|
||||||
|
|
||||||
|
int hev_socks5_get_connect_timeout (void);
|
||||||
|
int hev_socks5_get_tcp_timeout (void);
|
||||||
|
int hev_socks5_get_udp_timeout (void);
|
||||||
|
|
||||||
|
int hev_socks5_get_task_stack_size (void);
|
||||||
|
int hev_socks5_get_udp_copy_buffer_nums (void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_MISC_PRIV_H__ */
|
||||||
@ -0,0 +1,385 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-misc.c
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2025 hev
|
||||||
|
Description : Socks5 Misc
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
#include <hev-task-io.h>
|
||||||
|
#include <hev-task-io-socket.h>
|
||||||
|
#include <hev-task-dns.h>
|
||||||
|
#include <hev-memory-allocator.h>
|
||||||
|
|
||||||
|
#include "hev-socks5.h"
|
||||||
|
#include "hev-socks5-logger-priv.h"
|
||||||
|
|
||||||
|
#include "hev-socks5-misc.h"
|
||||||
|
#include "hev-socks5-misc-priv.h"
|
||||||
|
|
||||||
|
static int connect_timeout = 10000;
|
||||||
|
static int tcp_timeout = 300000;
|
||||||
|
static int udp_timeout = 60000;
|
||||||
|
|
||||||
|
static int task_stack_size = 8192;
|
||||||
|
static int udp_recv_buffer_size = 512 * 1024;
|
||||||
|
static int udp_copy_buffer_nums = 10;
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_task_io_yielder (HevTaskYieldType type, void *data)
|
||||||
|
{
|
||||||
|
HevSocks5 *self = data;
|
||||||
|
|
||||||
|
if (type == HEV_TASK_YIELD) {
|
||||||
|
hev_task_yield (HEV_TASK_YIELD);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->timeout < 0) {
|
||||||
|
hev_task_yield (HEV_TASK_WAITIO);
|
||||||
|
} else {
|
||||||
|
int timeout = self->timeout;
|
||||||
|
timeout = hev_task_sleep (timeout);
|
||||||
|
if (timeout <= 0) {
|
||||||
|
LOG_I ("%p io timeout", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_socket (int type)
|
||||||
|
{
|
||||||
|
HevTask *task = hev_task_self ();
|
||||||
|
int fd, res, zero = 0;
|
||||||
|
|
||||||
|
fd = hev_task_io_socket_socket (AF_INET6, type, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
res = setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof (zero));
|
||||||
|
if (res < 0) {
|
||||||
|
close (fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_task_add_fd (task, fd, POLLIN | POLLOUT);
|
||||||
|
if (res < 0)
|
||||||
|
hev_task_mod_fd (task, fd, POLLIN | POLLOUT);
|
||||||
|
|
||||||
|
if (type == SOCK_DGRAM) {
|
||||||
|
res = udp_recv_buffer_size;
|
||||||
|
setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &res, sizeof (res));
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
hev_socks5_addr_into_str (const HevSocks5Addr *addr, char *buf, int len)
|
||||||
|
{
|
||||||
|
const char *res = buf;
|
||||||
|
uint16_t port;
|
||||||
|
char sa[256];
|
||||||
|
|
||||||
|
switch (addr->atype) {
|
||||||
|
case HEV_SOCKS5_ADDR_TYPE_IPV4:
|
||||||
|
port = ntohs (addr->ipv4.port);
|
||||||
|
inet_ntop (AF_INET, addr->ipv4.addr, sa, sizeof (sa));
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_ADDR_TYPE_IPV6:
|
||||||
|
port = ntohs (addr->ipv6.port);
|
||||||
|
inet_ntop (AF_INET6, addr->ipv6.addr, sa, sizeof (sa));
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_ADDR_TYPE_NAME:
|
||||||
|
memcpy (sa, addr->domain.addr, addr->domain.len);
|
||||||
|
sa[addr->domain.len] = '\0';
|
||||||
|
memcpy (&port, addr->domain.addr + addr->domain.len, 2);
|
||||||
|
port = ntohs (port);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf (buf, len, "[%s]:%u", sa, port);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_addr_len (const HevSocks5Addr *addr)
|
||||||
|
{
|
||||||
|
switch (addr->atype) {
|
||||||
|
case HEV_SOCKS5_ADDR_TYPE_IPV4:
|
||||||
|
return 7;
|
||||||
|
case HEV_SOCKS5_ADDR_TYPE_IPV6:
|
||||||
|
return 19;
|
||||||
|
case HEV_SOCKS5_ADDR_TYPE_NAME:
|
||||||
|
return 4 + addr->domain.len;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_addr_from_name (HevSocks5Addr *addr, const char *name, int _port)
|
||||||
|
{
|
||||||
|
uint16_t port = _port;
|
||||||
|
addr->atype = HEV_SOCKS5_ADDR_TYPE_NAME;
|
||||||
|
strncpy ((char *)addr->domain.addr, name, 256);
|
||||||
|
addr->domain.len = strlen ((char *)addr->domain.addr);
|
||||||
|
memcpy ((char *)addr->domain.addr + addr->domain.len, &port, 2);
|
||||||
|
return 4 + addr->domain.len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_addr_from_ipv4 (HevSocks5Addr *addr, const void *ipv4, int port)
|
||||||
|
{
|
||||||
|
addr->atype = HEV_SOCKS5_ADDR_TYPE_IPV4;
|
||||||
|
memcpy (addr->ipv4.addr, ipv4, sizeof (addr->ipv4.addr));
|
||||||
|
addr->ipv4.port = port;
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_addr_from_ipv6 (HevSocks5Addr *addr, const void *ipv6, int port)
|
||||||
|
{
|
||||||
|
addr->atype = HEV_SOCKS5_ADDR_TYPE_IPV6;
|
||||||
|
memcpy (addr->ipv6.addr, ipv6, sizeof (addr->ipv6.addr));
|
||||||
|
addr->ipv6.port = port;
|
||||||
|
return 19;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_addr_from_sockaddr6 (HevSocks5Addr *addr, struct sockaddr_in6 *saddr)
|
||||||
|
{
|
||||||
|
if (IN6_IS_ADDR_V4MAPPED (&saddr->sin6_addr)) {
|
||||||
|
addr->atype = HEV_SOCKS5_ADDR_TYPE_IPV4;
|
||||||
|
addr->ipv4.port = saddr->sin6_port;
|
||||||
|
memcpy (addr->ipv4.addr, &saddr->sin6_addr.s6_addr[12], 4);
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr->atype = HEV_SOCKS5_ADDR_TYPE_IPV6;
|
||||||
|
addr->ipv6.port = saddr->sin6_port;
|
||||||
|
memcpy (addr->ipv6.addr, &saddr->sin6_addr, 16);
|
||||||
|
return 19;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hev_socks5_ipv4_into_sockaddr6 (const HevSocks5Addr *addr,
|
||||||
|
struct sockaddr_in6 *saddr)
|
||||||
|
{
|
||||||
|
saddr->sin6_family = AF_INET6;
|
||||||
|
saddr->sin6_port = addr->ipv4.port;
|
||||||
|
memset (&saddr->sin6_addr, 0, 10);
|
||||||
|
saddr->sin6_addr.s6_addr[10] = 0xff;
|
||||||
|
saddr->sin6_addr.s6_addr[11] = 0xff;
|
||||||
|
memcpy (&saddr->sin6_addr.s6_addr[12], addr->ipv4.addr, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hev_socks5_ipv6_into_sockaddr6 (const HevSocks5Addr *addr,
|
||||||
|
struct sockaddr_in6 *saddr)
|
||||||
|
{
|
||||||
|
saddr->sin6_family = AF_INET6;
|
||||||
|
saddr->sin6_port = addr->ipv6.port;
|
||||||
|
memcpy (&saddr->sin6_addr, addr->ipv6.addr, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_addr_into_sockaddr6 (const HevSocks5Addr *addr,
|
||||||
|
struct sockaddr_in6 *saddr, int *family)
|
||||||
|
{
|
||||||
|
switch (addr->atype) {
|
||||||
|
case HEV_SOCKS5_ADDR_TYPE_IPV4: {
|
||||||
|
hev_socks5_ipv4_into_sockaddr6 (addr, saddr);
|
||||||
|
*family = HEV_SOCKS5_ADDR_FAMILY_IPV4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HEV_SOCKS5_ADDR_TYPE_IPV6: {
|
||||||
|
hev_socks5_ipv6_into_sockaddr6 (addr, saddr);
|
||||||
|
*family = HEV_SOCKS5_ADDR_FAMILY_IPV6;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case HEV_SOCKS5_ADDR_TYPE_NAME: {
|
||||||
|
char name[256];
|
||||||
|
uint16_t port;
|
||||||
|
memcpy (name, addr->domain.addr, addr->domain.len);
|
||||||
|
name[addr->domain.len] = '\0';
|
||||||
|
memcpy (&port, addr->domain.addr + addr->domain.len, 2);
|
||||||
|
return hev_socks5_name_into_sockaddr6 (name, ntohs (port), saddr,
|
||||||
|
family);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_name_resolve_ipv4 (const char *name, struct sockaddr_in6 *saddr)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
memset (&saddr->sin6_addr, 0, 10);
|
||||||
|
res = inet_pton (AF_INET, name, &saddr->sin6_addr.s6_addr[12]);
|
||||||
|
if (res == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
saddr->sin6_addr.s6_addr[10] = 0xff;
|
||||||
|
saddr->sin6_addr.s6_addr[11] = 0xff;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_name_resolve_ipv6 (const char *name, struct sockaddr_in6 *saddr)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = inet_pton (AF_INET6, name, &saddr->sin6_addr);
|
||||||
|
if (res == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_name_resolve_name (const char *name, struct sockaddr_in6 *saddr,
|
||||||
|
int *family)
|
||||||
|
{
|
||||||
|
struct addrinfo *result = NULL;
|
||||||
|
struct addrinfo hints = { 0 };
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
hints.ai_family = *family;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
|
||||||
|
hev_task_dns_getaddrinfo (name, NULL, &hints, &result);
|
||||||
|
if (!result)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
switch (result->ai_family) {
|
||||||
|
case AF_INET: {
|
||||||
|
struct sockaddr_in *sa = (struct sockaddr_in *)result->ai_addr;
|
||||||
|
memset (&saddr->sin6_addr, 0, 10);
|
||||||
|
saddr->sin6_addr.s6_addr[10] = 0xff;
|
||||||
|
saddr->sin6_addr.s6_addr[11] = 0xff;
|
||||||
|
memcpy (&saddr->sin6_addr.s6_addr[12], &sa->sin_addr, 4);
|
||||||
|
*family = HEV_SOCKS5_ADDR_FAMILY_IPV4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AF_INET6: {
|
||||||
|
struct sockaddr_in6 *sa = (struct sockaddr_in6 *)result->ai_addr;
|
||||||
|
memcpy (&saddr->sin6_addr, &sa->sin6_addr, 16);
|
||||||
|
*family = HEV_SOCKS5_ADDR_FAMILY_IPV6;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
res = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo (result);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_name_into_sockaddr6 (const char *name, int port,
|
||||||
|
struct sockaddr_in6 *saddr, int *family)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
saddr->sin6_family = AF_INET6;
|
||||||
|
saddr->sin6_port = htons (port);
|
||||||
|
|
||||||
|
res = hev_socks5_name_resolve_ipv4 (name, saddr);
|
||||||
|
if (res == 0) {
|
||||||
|
*family = HEV_SOCKS5_ADDR_FAMILY_IPV4;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_socks5_name_resolve_ipv6 (name, saddr);
|
||||||
|
if (res == 0) {
|
||||||
|
*family = HEV_SOCKS5_ADDR_FAMILY_IPV6;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_socks5_name_resolve_name (name, saddr, family);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_set_connect_timeout (int timeout)
|
||||||
|
{
|
||||||
|
connect_timeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_get_connect_timeout (void)
|
||||||
|
{
|
||||||
|
return connect_timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_set_tcp_timeout (int timeout)
|
||||||
|
{
|
||||||
|
tcp_timeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_get_tcp_timeout (void)
|
||||||
|
{
|
||||||
|
return tcp_timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_set_udp_timeout (int timeout)
|
||||||
|
{
|
||||||
|
udp_timeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_get_udp_timeout (void)
|
||||||
|
{
|
||||||
|
return udp_timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_set_task_stack_size (int stack_size)
|
||||||
|
{
|
||||||
|
task_stack_size = stack_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_get_task_stack_size (void)
|
||||||
|
{
|
||||||
|
return task_stack_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_set_udp_recv_buffer_size (int buffer_size)
|
||||||
|
{
|
||||||
|
udp_recv_buffer_size = buffer_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_set_udp_copy_buffer_nums (int nums)
|
||||||
|
{
|
||||||
|
udp_copy_buffer_nums = nums;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_get_udp_copy_buffer_nums (void)
|
||||||
|
{
|
||||||
|
return udp_copy_buffer_nums;
|
||||||
|
}
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-misc.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2025 hev
|
||||||
|
Description : Socks5 Misc
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_MISC_H__
|
||||||
|
#define __HEV_SOCKS5_MISC_H__
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
|
||||||
|
#include "hev-socks5-proto.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int hev_socks5_task_io_yielder (HevTaskYieldType type, void *data);
|
||||||
|
|
||||||
|
void hev_socks5_set_connect_timeout (int timeout);
|
||||||
|
void hev_socks5_set_tcp_timeout (int timeout);
|
||||||
|
void hev_socks5_set_udp_timeout (int timeout);
|
||||||
|
|
||||||
|
void hev_socks5_set_task_stack_size (int stack_size);
|
||||||
|
void hev_socks5_set_udp_recv_buffer_size (int buffer_size);
|
||||||
|
void hev_socks5_set_udp_copy_buffer_nums (int nums);
|
||||||
|
|
||||||
|
int hev_socks5_addr_len (const HevSocks5Addr *addr);
|
||||||
|
int hev_socks5_addr_from_name (HevSocks5Addr *addr, const char *name, int port);
|
||||||
|
int hev_socks5_addr_from_ipv4 (HevSocks5Addr *addr, const void *ipv4, int port);
|
||||||
|
int hev_socks5_addr_from_ipv6 (HevSocks5Addr *addr, const void *ipv6, int port);
|
||||||
|
int hev_socks5_addr_from_sockaddr6 (HevSocks5Addr *addr,
|
||||||
|
struct sockaddr_in6 *saddr);
|
||||||
|
int hev_socks5_addr_into_sockaddr6 (const HevSocks5Addr *addr,
|
||||||
|
struct sockaddr_in6 *saddr, int *family);
|
||||||
|
int hev_socks5_name_into_sockaddr6 (const char *host, int port,
|
||||||
|
struct sockaddr_in6 *saddr, int *family);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_MISC_H__ */
|
||||||
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-proto.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2023 hev
|
||||||
|
Description : Socks5 Proto
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_PROTO_H__
|
||||||
|
#define __HEV_SOCKS5_PROTO_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum _HevSocks5Version HevSocks5Version;
|
||||||
|
typedef enum _HevSocks5AuthMethod HevSocks5AuthMethod;
|
||||||
|
typedef enum _HevSocks5AuthVersion HevSocks5AuthVersion;
|
||||||
|
typedef enum _HevSocks5ReqCmd HevSocks5ReqCmd;
|
||||||
|
typedef enum _HevSocks5ResRep HevSocks5ResRep;
|
||||||
|
typedef enum _HevSocks5AddrType HevSocks5AddrType;
|
||||||
|
|
||||||
|
typedef struct _HevSocks5Auth HevSocks5Auth;
|
||||||
|
typedef struct _HevSocks5Addr HevSocks5Addr;
|
||||||
|
typedef struct _HevSocks5ReqRes HevSocks5ReqRes;
|
||||||
|
typedef struct _HevSocks5UDPHdr HevSocks5UDPHdr;
|
||||||
|
|
||||||
|
enum _HevSocks5Version
|
||||||
|
{
|
||||||
|
HEV_SOCKS5_VERSION_5 = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum _HevSocks5AuthMethod
|
||||||
|
{
|
||||||
|
HEV_SOCKS5_AUTH_METHOD_NONE = 0,
|
||||||
|
HEV_SOCKS5_AUTH_METHOD_USER = 2,
|
||||||
|
HEV_SOCKS5_AUTH_METHOD_DENY = 255,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum _HevSocks5AuthVersion
|
||||||
|
{
|
||||||
|
HEV_SOCKS5_AUTH_VERSION_1 = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum _HevSocks5ReqCmd
|
||||||
|
{
|
||||||
|
HEV_SOCKS5_REQ_CMD_CONNECT = 1,
|
||||||
|
HEV_SOCKS5_REQ_CMD_UDP_ASC = 3,
|
||||||
|
HEV_SOCKS5_REQ_CMD_FWD_UDP = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum _HevSocks5ResRep
|
||||||
|
{
|
||||||
|
HEV_SOCKS5_RES_REP_SUCC = 0,
|
||||||
|
HEV_SOCKS5_RES_REP_FAIL = 1,
|
||||||
|
HEV_SOCKS5_RES_REP_HOST = 4,
|
||||||
|
HEV_SOCKS5_RES_REP_IMPL = 7,
|
||||||
|
HEV_SOCKS5_RES_REP_ADDR = 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum _HevSocks5AddrType
|
||||||
|
{
|
||||||
|
HEV_SOCKS5_ADDR_TYPE_IPV4 = 1,
|
||||||
|
HEV_SOCKS5_ADDR_TYPE_IPV6 = 4,
|
||||||
|
HEV_SOCKS5_ADDR_TYPE_NAME = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5Auth
|
||||||
|
{
|
||||||
|
uint8_t ver;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint8_t method;
|
||||||
|
uint8_t method_len;
|
||||||
|
};
|
||||||
|
uint8_t methods[256];
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct _HevSocks5Addr
|
||||||
|
{
|
||||||
|
uint8_t atype;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t addr[4];
|
||||||
|
uint16_t port;
|
||||||
|
} ipv4 __attribute__ ((packed));
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t addr[16];
|
||||||
|
uint16_t port;
|
||||||
|
} ipv6 __attribute__ ((packed));
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t len;
|
||||||
|
uint8_t addr[256 + 2];
|
||||||
|
} domain;
|
||||||
|
};
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct _HevSocks5ReqRes
|
||||||
|
{
|
||||||
|
uint8_t ver;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint8_t cmd;
|
||||||
|
uint8_t rep;
|
||||||
|
};
|
||||||
|
uint8_t rsv;
|
||||||
|
HevSocks5Addr addr;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct _HevSocks5UDPHdr
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint8_t rsv[3];
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint16_t datlen;
|
||||||
|
uint8_t hdrlen;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
};
|
||||||
|
HevSocks5Addr addr;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_PROTO_H__ */
|
||||||
@ -0,0 +1,684 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-server.c
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2025 hev
|
||||||
|
Description : Socks5 Server
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
#include <hev-task-io.h>
|
||||||
|
#include <hev-task-io-socket.h>
|
||||||
|
#include <hev-memory-allocator.h>
|
||||||
|
|
||||||
|
#include "hev-socks5-proto.h"
|
||||||
|
#include "hev-socks5-misc-priv.h"
|
||||||
|
#include "hev-socks5-logger-priv.h"
|
||||||
|
|
||||||
|
#include "hev-socks5-server.h"
|
||||||
|
|
||||||
|
#define task_io_yielder hev_socks5_task_io_yielder
|
||||||
|
|
||||||
|
HevSocks5Server *
|
||||||
|
hev_socks5_server_new (int fd)
|
||||||
|
{
|
||||||
|
HevSocks5Server *self;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
self = hev_malloc0 (sizeof (HevSocks5Server));
|
||||||
|
if (!self)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
res = hev_socks5_server_construct (self, fd);
|
||||||
|
if (res < 0) {
|
||||||
|
hev_free (self);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 server new", self);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_server_set_auth (HevSocks5Server *self, HevSocks5Authenticator *auth)
|
||||||
|
{
|
||||||
|
if (self->auth)
|
||||||
|
hev_object_unref (HEV_OBJECT (self->auth));
|
||||||
|
|
||||||
|
hev_object_ref (HEV_OBJECT (auth));
|
||||||
|
self->auth = auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_server_read_auth_method (HevSocks5Server *self)
|
||||||
|
{
|
||||||
|
HevSocks5Auth auth;
|
||||||
|
HevSocks5AuthMethod method;
|
||||||
|
int res;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 server read auth method", self);
|
||||||
|
|
||||||
|
res = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, &auth, 2, MSG_WAITALL,
|
||||||
|
task_io_yielder, self);
|
||||||
|
if (res != 2) {
|
||||||
|
LOG_I ("%p socks5 server read auth method", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auth.ver != HEV_SOCKS5_VERSION_5) {
|
||||||
|
LOG_I ("%p socks5 server auth.ver %u", self, auth.ver);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, &auth.methods,
|
||||||
|
auth.method_len, MSG_WAITALL,
|
||||||
|
task_io_yielder, self);
|
||||||
|
if (res != auth.method_len) {
|
||||||
|
LOG_I ("%p socks5 server read auth methods", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->auth)
|
||||||
|
method = HEV_SOCKS5_AUTH_METHOD_USER;
|
||||||
|
else
|
||||||
|
method = HEV_SOCKS5_AUTH_METHOD_NONE;
|
||||||
|
|
||||||
|
res = -1;
|
||||||
|
for (i = 0; i < auth.method_len; i++) {
|
||||||
|
if (auth.methods[i] == method) {
|
||||||
|
res = method;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_server_write_auth_method (HevSocks5Server *self, int auth_method)
|
||||||
|
{
|
||||||
|
HevSocks5Auth auth;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 server write auth method", self);
|
||||||
|
|
||||||
|
auth.ver = HEV_SOCKS5_VERSION_5;
|
||||||
|
auth.method = auth_method;
|
||||||
|
|
||||||
|
res = hev_task_io_socket_send (HEV_SOCKS5 (self)->fd, &auth, 2, MSG_WAITALL,
|
||||||
|
task_io_yielder, self);
|
||||||
|
if (res <= 0) {
|
||||||
|
LOG_I ("%p socks5 server write auth method", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_server_read_auth_user (HevSocks5Server *self)
|
||||||
|
{
|
||||||
|
HevSocks5User *user;
|
||||||
|
uint8_t nlen, plen;
|
||||||
|
uint8_t name[257];
|
||||||
|
uint8_t pass[257];
|
||||||
|
uint8_t head[2];
|
||||||
|
int res;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 server read auth user", self);
|
||||||
|
|
||||||
|
res = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, head, 2, MSG_WAITALL,
|
||||||
|
task_io_yielder, self);
|
||||||
|
if (res != 2) {
|
||||||
|
LOG_I ("%p socks5 server read auth user.ver", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (head[0] != 1) {
|
||||||
|
LOG_I ("%p socks5 server auth user.ver %u", self, head[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlen = head[1];
|
||||||
|
if (nlen == 0) {
|
||||||
|
LOG_I ("%p socks5 server auth user.nlen %u", self, nlen);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, name, nlen + 1,
|
||||||
|
MSG_WAITALL, task_io_yielder, self);
|
||||||
|
if (res != (nlen + 1)) {
|
||||||
|
LOG_I ("%p socks5 server read auth user.name", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
plen = name[nlen];
|
||||||
|
if (plen == 0) {
|
||||||
|
LOG_I ("%p socks5 server auth user.plen %u", self, plen);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, pass, plen,
|
||||||
|
MSG_WAITALL, task_io_yielder, self);
|
||||||
|
if (res != plen) {
|
||||||
|
LOG_I ("%p socks5 server read auth user.pass", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
user = hev_socks5_authenticator_get (self->auth, (char *)name, nlen);
|
||||||
|
if (!user) {
|
||||||
|
LOG_I ("%p socks5 server auth user: %s pass: %s", self, name, pass);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_socks5_user_check (user, (char *)pass, plen);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_I ("%p socks5 server auth user: %s pass: %s", self, name, pass);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
hev_object_ref (HEV_OBJECT (user));
|
||||||
|
hev_object_unref (HEV_OBJECT (self->auth));
|
||||||
|
self->user = user;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_server_write_auth_user (HevSocks5Server *self, int auth_res)
|
||||||
|
{
|
||||||
|
uint8_t buf[2];
|
||||||
|
int res;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 server write auth user", self);
|
||||||
|
|
||||||
|
buf[0] = 1;
|
||||||
|
buf[1] = auth_res;
|
||||||
|
|
||||||
|
res = hev_task_io_socket_send (HEV_SOCKS5 (self)->fd, buf, 2, MSG_WAITALL,
|
||||||
|
task_io_yielder, self);
|
||||||
|
if (res <= 0) {
|
||||||
|
LOG_I ("%p socks5 server write auth user", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_server_auth (HevSocks5Server *self)
|
||||||
|
{
|
||||||
|
int method;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
method = hev_socks5_server_read_auth_method (self);
|
||||||
|
res = hev_socks5_server_write_auth_method (self, method);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
switch (method) {
|
||||||
|
case HEV_SOCKS5_AUTH_METHOD_NONE:
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_AUTH_METHOD_USER:
|
||||||
|
res = hev_socks5_server_read_auth_user (self);
|
||||||
|
res |= hev_socks5_server_write_auth_user (self, res);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_server_read_request (HevSocks5Server *self, int *cmd, int *rep,
|
||||||
|
struct sockaddr_in6 *addr)
|
||||||
|
{
|
||||||
|
HevSocks5ReqRes req;
|
||||||
|
int addr_family;
|
||||||
|
int addrlen;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 server read request", self);
|
||||||
|
|
||||||
|
res = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, &req, 5, MSG_WAITALL,
|
||||||
|
task_io_yielder, self);
|
||||||
|
if (res != 5) {
|
||||||
|
LOG_I ("%p socks5 server read request", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.ver != HEV_SOCKS5_VERSION_5) {
|
||||||
|
*rep = HEV_SOCKS5_RES_REP_FAIL;
|
||||||
|
LOG_I ("%p socks5 server req.ver %u", self, req.ver);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (req.addr.atype) {
|
||||||
|
case HEV_SOCKS5_ADDR_TYPE_IPV4:
|
||||||
|
addrlen = 5;
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_ADDR_TYPE_IPV6:
|
||||||
|
addrlen = 17;
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_ADDR_TYPE_NAME:
|
||||||
|
addrlen = 2 + req.addr.domain.len;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*rep = HEV_SOCKS5_RES_REP_ADDR;
|
||||||
|
LOG_I ("%p socks5 server req.atype %u", self, req.addr.atype);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, req.addr.domain.addr,
|
||||||
|
addrlen, MSG_WAITALL, task_io_yielder, self);
|
||||||
|
if (res != addrlen) {
|
||||||
|
*rep = HEV_SOCKS5_RES_REP_ADDR;
|
||||||
|
LOG_I ("%p socks5 server read addr", self);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr_family = hev_socks5_get_addr_family (HEV_SOCKS5 (self));
|
||||||
|
res = hev_socks5_addr_into_sockaddr6 (&req.addr, addr, &addr_family);
|
||||||
|
if (res < 0) {
|
||||||
|
*rep = HEV_SOCKS5_RES_REP_ADDR;
|
||||||
|
LOG_I ("%p socks5 server resolve addr", self);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
hev_socks5_set_addr_family (HEV_SOCKS5 (self), addr_family);
|
||||||
|
|
||||||
|
if (LOG_ON ()) {
|
||||||
|
const char *type;
|
||||||
|
const char *str;
|
||||||
|
char buf[272];
|
||||||
|
|
||||||
|
switch (req.cmd) {
|
||||||
|
case HEV_SOCKS5_REQ_CMD_CONNECT:
|
||||||
|
type = "tcp";
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_REQ_CMD_UDP_ASC:
|
||||||
|
case HEV_SOCKS5_REQ_CMD_FWD_UDP:
|
||||||
|
type = "udp";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
type = "unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = hev_socks5_addr_into_str (&req.addr, buf, sizeof (buf));
|
||||||
|
LOG_I ("%p socks5 server %s %s", self, type, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
*cmd = req.cmd;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_server_write_response (HevSocks5Server *self, int rep,
|
||||||
|
struct sockaddr_in6 *addr)
|
||||||
|
{
|
||||||
|
HevSocks5ReqRes res;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 server write response", self);
|
||||||
|
|
||||||
|
res.ver = HEV_SOCKS5_VERSION_5;
|
||||||
|
res.rep = rep;
|
||||||
|
res.rsv = 0;
|
||||||
|
|
||||||
|
ret = hev_socks5_addr_from_sockaddr6 (&res.addr, addr);
|
||||||
|
ret = hev_task_io_socket_send (HEV_SOCKS5 (self)->fd, &res, 3 + ret,
|
||||||
|
MSG_WAITALL, task_io_yielder, self);
|
||||||
|
if (ret <= 0) {
|
||||||
|
LOG_I ("%p socks5 server write response", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_server_connect (HevSocks5Server *self, struct sockaddr_in6 *addr)
|
||||||
|
{
|
||||||
|
HevSocks5Class *klass;
|
||||||
|
int timeout;
|
||||||
|
int res;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 server connect", self);
|
||||||
|
|
||||||
|
fd = hev_socks5_socket (SOCK_STREAM);
|
||||||
|
if (fd < 0) {
|
||||||
|
LOG_E ("%p socks5 server socket stream", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
klass = HEV_OBJECT_GET_CLASS (self);
|
||||||
|
res = klass->binder (HEV_SOCKS5 (self), fd, (struct sockaddr *)addr);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_W ("%p socks5 server bind", self);
|
||||||
|
hev_task_del_fd (hev_task_self (), fd);
|
||||||
|
close (fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout = hev_socks5_get_connect_timeout ();
|
||||||
|
hev_socks5_set_timeout (HEV_SOCKS5 (self), timeout);
|
||||||
|
|
||||||
|
res = hev_task_io_socket_connect (fd, (struct sockaddr *)addr,
|
||||||
|
sizeof (*addr), task_io_yielder, self);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_I ("%p socks5 server connect", self);
|
||||||
|
hev_task_del_fd (hev_task_self (), fd);
|
||||||
|
close (fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout = hev_socks5_get_tcp_timeout ();
|
||||||
|
hev_socks5_set_timeout (HEV_SOCKS5 (self), timeout);
|
||||||
|
|
||||||
|
self->fds[0] = fd;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_server_bind (HevSocks5Server *self, struct sockaddr_in6 *addr)
|
||||||
|
{
|
||||||
|
HevSocks5ServerClass *sskptr = HEV_OBJECT_GET_CLASS (self);
|
||||||
|
int one = 1;
|
||||||
|
int res;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 server bind", self);
|
||||||
|
|
||||||
|
fd = hev_socks5_socket (SOCK_DGRAM);
|
||||||
|
if (fd < 0) {
|
||||||
|
LOG_E ("%p socks5 server socket dgram", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->fds[0] = fd;
|
||||||
|
|
||||||
|
if (!addr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fd = hev_socks5_socket (SOCK_DGRAM);
|
||||||
|
if (fd < 0) {
|
||||||
|
LOG_E ("%p socks5 server socket dgram", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof (one));
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_W ("%p socks5 server socket reuse", self);
|
||||||
|
hev_task_del_fd (hev_task_self (), fd);
|
||||||
|
close (fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = sskptr->binder (self, fd, addr);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_W ("%p socks5 server bind", self);
|
||||||
|
hev_task_del_fd (hev_task_self (), fd);
|
||||||
|
close (fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->fds[1] = fd;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_server_udp_bind (HevSocks5Server *self, int sock,
|
||||||
|
struct sockaddr_in6 *src)
|
||||||
|
{
|
||||||
|
socklen_t alen;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 server udp bind", self);
|
||||||
|
|
||||||
|
alen = sizeof (struct sockaddr_in6);
|
||||||
|
res = getsockname (HEV_SOCKS5 (self)->fd, (struct sockaddr *)src, &alen);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_W ("%p socks5 server tcp socket name", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
src->sin6_port = 0;
|
||||||
|
res = bind (sock, (struct sockaddr *)src, alen);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_W ("%p socks5 server socket bind", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = getsockname (sock, (struct sockaddr *)src, &alen);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_W ("%p socks5 server udp socket name", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_server_handshake (HevSocks5Server *self)
|
||||||
|
{
|
||||||
|
struct sockaddr_in6 addr;
|
||||||
|
int timeout;
|
||||||
|
int cmd;
|
||||||
|
int rep;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 server handshake", self);
|
||||||
|
|
||||||
|
timeout = hev_socks5_get_tcp_timeout ();
|
||||||
|
hev_socks5_set_timeout (HEV_SOCKS5 (self), timeout);
|
||||||
|
|
||||||
|
res = hev_socks5_server_auth (self);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
rep = HEV_SOCKS5_RES_REP_SUCC;
|
||||||
|
res = hev_socks5_server_read_request (self, &cmd, &rep, &addr);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (rep == HEV_SOCKS5_RES_REP_SUCC) {
|
||||||
|
switch (cmd) {
|
||||||
|
case HEV_SOCKS5_REQ_CMD_CONNECT:
|
||||||
|
res = hev_socks5_server_connect (self, &addr);
|
||||||
|
if (res < 0)
|
||||||
|
rep = HEV_SOCKS5_RES_REP_HOST;
|
||||||
|
HEV_SOCKS5 (self)->type = HEV_SOCKS5_TYPE_TCP;
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_REQ_CMD_UDP_ASC:
|
||||||
|
res = hev_socks5_server_bind (self, &addr);
|
||||||
|
if (res < 0)
|
||||||
|
rep = HEV_SOCKS5_RES_REP_FAIL;
|
||||||
|
HEV_SOCKS5 (self)->type = HEV_SOCKS5_TYPE_UDP_IN_UDP;
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_REQ_CMD_FWD_UDP:
|
||||||
|
res = hev_socks5_server_bind (self, NULL);
|
||||||
|
if (res < 0)
|
||||||
|
rep = HEV_SOCKS5_RES_REP_FAIL;
|
||||||
|
HEV_SOCKS5 (self)->type = HEV_SOCKS5_TYPE_UDP_IN_TCP;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rep = HEV_SOCKS5_RES_REP_IMPL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_socks5_server_write_response (self, rep, &addr);
|
||||||
|
if ((res < 0) || (rep != HEV_SOCKS5_RES_REP_SUCC))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_server_service (HevSocks5Server *self)
|
||||||
|
{
|
||||||
|
int timeout;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 server service", self);
|
||||||
|
|
||||||
|
switch (HEV_SOCKS5 (self)->type) {
|
||||||
|
case HEV_SOCKS5_TYPE_TCP:
|
||||||
|
hev_socks5_tcp_splice (HEV_SOCKS5_TCP (self), self->fds[0]);
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_TYPE_UDP_IN_UDP:
|
||||||
|
case HEV_SOCKS5_TYPE_UDP_IN_TCP:
|
||||||
|
timeout = hev_socks5_get_udp_timeout ();
|
||||||
|
hev_socks5_set_timeout (HEV_SOCKS5 (self), timeout);
|
||||||
|
hev_socks5_udp_splice (HEV_SOCKS5_UDP (self), self->fds[0]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_server_run (HevSocks5Server *self)
|
||||||
|
{
|
||||||
|
HevTask *task = hev_task_self ();
|
||||||
|
int res;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 server run", self);
|
||||||
|
|
||||||
|
fd = HEV_SOCKS5 (self)->fd;
|
||||||
|
res = hev_task_add_fd (task, fd, POLLIN | POLLOUT);
|
||||||
|
if (res < 0)
|
||||||
|
hev_task_mod_fd (task, fd, POLLIN | POLLOUT);
|
||||||
|
|
||||||
|
res = hev_socks5_server_handshake (self);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
res = hev_socks5_server_service (self);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_server_get_fd (HevSocks5UDP *self)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
switch (HEV_SOCKS5 (self)->type) {
|
||||||
|
case HEV_SOCKS5_TYPE_UDP_IN_TCP:
|
||||||
|
fd = HEV_SOCKS5 (self)->fd;
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_TYPE_UDP_IN_UDP:
|
||||||
|
fd = HEV_SOCKS5_SERVER (self)->fds[1];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_server_construct (HevSocks5Server *self, int fd)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = hev_socks5_construct (&self->base, HEV_SOCKS5_TYPE_NONE);
|
||||||
|
if (res < 0)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 server construct", self);
|
||||||
|
|
||||||
|
HEV_OBJECT (self)->klass = HEV_SOCKS5_SERVER_TYPE;
|
||||||
|
|
||||||
|
HEV_SOCKS5 (self)->fd = fd;
|
||||||
|
|
||||||
|
self->fds[0] = -1;
|
||||||
|
self->fds[1] = -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hev_socks5_server_destruct (HevObject *base)
|
||||||
|
{
|
||||||
|
HevSocks5Server *self = HEV_SOCKS5_SERVER (base);
|
||||||
|
HevTask *task = hev_task_self ();
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 server destruct", self);
|
||||||
|
|
||||||
|
if (self->fds[0] >= 0) {
|
||||||
|
hev_task_del_fd (task, self->fds[0]);
|
||||||
|
close (self->fds[0]);
|
||||||
|
}
|
||||||
|
if (self->fds[1] >= 0) {
|
||||||
|
hev_task_del_fd (task, self->fds[1]);
|
||||||
|
close (self->fds[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->obj)
|
||||||
|
hev_object_unref (self->obj);
|
||||||
|
|
||||||
|
HEV_SOCKS5_TYPE->destruct (base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
hev_socks5_server_iface (HevObject *base, void *type)
|
||||||
|
{
|
||||||
|
HevSocks5ServerClass *klass = HEV_OBJECT_GET_CLASS (base);
|
||||||
|
|
||||||
|
if (type == HEV_SOCKS5_TCP_TYPE)
|
||||||
|
return &klass->tcp;
|
||||||
|
|
||||||
|
if (type == HEV_SOCKS5_UDP_TYPE)
|
||||||
|
return &klass->udp;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
HevObjectClass *
|
||||||
|
hev_socks5_server_class (void)
|
||||||
|
{
|
||||||
|
static HevSocks5ServerClass klass;
|
||||||
|
HevSocks5ServerClass *kptr = &klass;
|
||||||
|
HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr);
|
||||||
|
|
||||||
|
if (!okptr->name) {
|
||||||
|
HevSocks5TCPIface *tiptr;
|
||||||
|
HevSocks5UDPIface *uiptr;
|
||||||
|
|
||||||
|
memcpy (kptr, HEV_SOCKS5_TYPE, sizeof (HevSocks5Class));
|
||||||
|
|
||||||
|
okptr->name = "HevSocks5Server";
|
||||||
|
okptr->destruct = hev_socks5_server_destruct;
|
||||||
|
okptr->iface = hev_socks5_server_iface;
|
||||||
|
|
||||||
|
kptr->binder = hev_socks5_server_udp_bind;
|
||||||
|
|
||||||
|
tiptr = &kptr->tcp;
|
||||||
|
memcpy (tiptr, HEV_SOCKS5_TCP_TYPE, sizeof (HevSocks5TCPIface));
|
||||||
|
|
||||||
|
uiptr = &kptr->udp;
|
||||||
|
memcpy (uiptr, HEV_SOCKS5_UDP_TYPE, sizeof (HevSocks5UDPIface));
|
||||||
|
uiptr->get_fd = hev_socks5_server_get_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
return okptr;
|
||||||
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-server.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2023 hev
|
||||||
|
Description : Socks5 Server
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_SERVER_H__
|
||||||
|
#define __HEV_SOCKS5_SERVER_H__
|
||||||
|
|
||||||
|
#include <hev-object.h>
|
||||||
|
|
||||||
|
#include "hev-socks5.h"
|
||||||
|
#include "hev-socks5-tcp.h"
|
||||||
|
#include "hev-socks5-udp.h"
|
||||||
|
#include "hev-socks5-user.h"
|
||||||
|
#include "hev-socks5-authenticator.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HEV_SOCKS5_SERVER(p) ((HevSocks5Server *)p)
|
||||||
|
#define HEV_SOCKS5_SERVER_CLASS(p) ((HevSocks5ServerClass *)p)
|
||||||
|
#define HEV_SOCKS5_SERVER_TYPE (hev_socks5_server_class ())
|
||||||
|
|
||||||
|
typedef struct _HevSocks5Server HevSocks5Server;
|
||||||
|
typedef struct _HevSocks5ServerClass HevSocks5ServerClass;
|
||||||
|
|
||||||
|
struct _HevSocks5Server
|
||||||
|
{
|
||||||
|
HevSocks5 base;
|
||||||
|
|
||||||
|
int fds[2];
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
HevObject *obj;
|
||||||
|
HevSocks5User *user;
|
||||||
|
HevSocks5Authenticator *auth;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5ServerClass
|
||||||
|
{
|
||||||
|
HevSocks5Class base;
|
||||||
|
|
||||||
|
int (*binder) (HevSocks5Server *self, int sock, struct sockaddr_in6 *src);
|
||||||
|
|
||||||
|
HevSocks5TCPIface tcp;
|
||||||
|
HevSocks5UDPIface udp;
|
||||||
|
};
|
||||||
|
|
||||||
|
HevObjectClass *hev_socks5_server_class (void);
|
||||||
|
|
||||||
|
int hev_socks5_server_construct (HevSocks5Server *self, int fd);
|
||||||
|
|
||||||
|
HevSocks5Server *hev_socks5_server_new (int fd);
|
||||||
|
|
||||||
|
void hev_socks5_server_set_auth (HevSocks5Server *self,
|
||||||
|
HevSocks5Authenticator *auth);
|
||||||
|
|
||||||
|
int hev_socks5_server_run (HevSocks5Server *self);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_SERVER_H__ */
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-tcp.c
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 hev
|
||||||
|
Description : Socks5 TCP
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hev-socks5.h"
|
||||||
|
#include "hev-socks5-misc-priv.h"
|
||||||
|
#include "hev-socks5-logger-priv.h"
|
||||||
|
|
||||||
|
#include "hev-socks5-tcp.h"
|
||||||
|
|
||||||
|
#define task_io_yielder hev_socks5_task_io_yielder
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_tcp_splicer (HevSocks5TCP *self, int fd)
|
||||||
|
{
|
||||||
|
HevTask *task = hev_task_self ();
|
||||||
|
int cfd;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 tcp splicer", self);
|
||||||
|
|
||||||
|
cfd = HEV_SOCKS5 (self)->fd;
|
||||||
|
if (cfd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
res = hev_task_add_fd (task, fd, POLLIN | POLLOUT);
|
||||||
|
if (res < 0)
|
||||||
|
hev_task_mod_fd (task, fd, POLLIN | POLLOUT);
|
||||||
|
|
||||||
|
hev_task_io_splice (cfd, cfd, fd, fd, 8192, task_io_yielder, self);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_tcp_splice (HevSocks5TCP *self, int fd)
|
||||||
|
{
|
||||||
|
HevSocks5TCPIface *iface;
|
||||||
|
|
||||||
|
iface = HEV_OBJECT_GET_IFACE (self, HEV_SOCKS5_TCP_TYPE);
|
||||||
|
return iface->splicer (self, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
hev_socks5_tcp_iface (void)
|
||||||
|
{
|
||||||
|
static HevSocks5TCPIface type = {
|
||||||
|
.splicer = hev_socks5_tcp_splicer,
|
||||||
|
};
|
||||||
|
|
||||||
|
return &type;
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-tcp.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 hev
|
||||||
|
Description : Socks5 TCP
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_TCP_H__
|
||||||
|
#define __HEV_SOCKS5_TCP_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HEV_SOCKS5_TCP(p) ((HevSocks5TCP *)p)
|
||||||
|
#define HEV_SOCKS5_TCP_IFACE(p) ((HevSocks5TCPIface *)p)
|
||||||
|
#define HEV_SOCKS5_TCP_TYPE (hev_socks5_tcp_iface ())
|
||||||
|
|
||||||
|
typedef void HevSocks5TCP;
|
||||||
|
typedef struct _HevSocks5TCPIface HevSocks5TCPIface;
|
||||||
|
|
||||||
|
struct _HevSocks5TCPIface
|
||||||
|
{
|
||||||
|
int (*splicer) (HevSocks5TCP *self, int fd);
|
||||||
|
};
|
||||||
|
|
||||||
|
void *hev_socks5_tcp_iface (void);
|
||||||
|
|
||||||
|
int hev_socks5_tcp_splice (HevSocks5TCP *self, int fd);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_TCP_H__ */
|
||||||
508
app/src/main/cpp/hev-socks5-tunnel/src/core/src/hev-socks5-udp.c
Normal file
508
app/src/main/cpp/hev-socks5-tunnel/src/core/src/hev-socks5-udp.c
Normal file
@ -0,0 +1,508 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-udp.c
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2025 hev
|
||||||
|
Description : Socks5 UDP
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
#include <hev-task-io.h>
|
||||||
|
#include <hev-task-io-socket.h>
|
||||||
|
#include <hev-memory-allocator.h>
|
||||||
|
|
||||||
|
#include "hev-socks5.h"
|
||||||
|
#include "hev-socks5-misc-priv.h"
|
||||||
|
#include "hev-socks5-logger-priv.h"
|
||||||
|
|
||||||
|
#include "hev-socks5-udp.h"
|
||||||
|
|
||||||
|
#define UDP_BUF_SIZE 1500
|
||||||
|
|
||||||
|
static int
|
||||||
|
task_io_yielder (HevTaskYieldType type, void *data)
|
||||||
|
{
|
||||||
|
HevSocks5 *self = data;
|
||||||
|
|
||||||
|
if (self->type == HEV_SOCKS5_TYPE_UDP_IN_UDP) {
|
||||||
|
ssize_t res;
|
||||||
|
char buf;
|
||||||
|
|
||||||
|
res = recv (self->fd, &buf, sizeof (buf), 0);
|
||||||
|
if ((res == 0) || ((res < 0) && (errno != EAGAIN))) {
|
||||||
|
hev_socks5_set_timeout (self, 0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hev_socks5_task_io_yielder (type, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_udp_get_fd (HevSocks5UDP *self)
|
||||||
|
{
|
||||||
|
HevSocks5UDPIface *iface;
|
||||||
|
|
||||||
|
iface = HEV_OBJECT_GET_IFACE (self, HEV_SOCKS5_UDP_TYPE);
|
||||||
|
return iface->get_fd (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_udp_sendmmsg_tcp (HevSocks5UDP *self, HevSocks5UDPMsg *msgv,
|
||||||
|
unsigned int num)
|
||||||
|
{
|
||||||
|
struct iovec iov[num * 3];
|
||||||
|
HevSocks5UDPHdr udp[num];
|
||||||
|
struct msghdr mh;
|
||||||
|
int i, res;
|
||||||
|
|
||||||
|
mh.msg_name = NULL;
|
||||||
|
mh.msg_namelen = 0;
|
||||||
|
mh.msg_control = NULL;
|
||||||
|
mh.msg_controllen = 0;
|
||||||
|
mh.msg_iov = iov;
|
||||||
|
mh.msg_iovlen = num * 3;
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
int addrlen;
|
||||||
|
|
||||||
|
addrlen = hev_socks5_addr_len (msgv[i].addr);
|
||||||
|
if (addrlen <= 0) {
|
||||||
|
LOG_D ("%p socks5 udp addr", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
udp[i].datlen = htons (msgv[i].len);
|
||||||
|
udp[i].hdrlen = 3 + addrlen;
|
||||||
|
|
||||||
|
iov[i * 3].iov_base = &udp[i];
|
||||||
|
iov[i * 3].iov_len = 3;
|
||||||
|
iov[i * 3 + 1].iov_base = msgv[i].addr;
|
||||||
|
iov[i * 3 + 1].iov_len = addrlen;
|
||||||
|
iov[i * 3 + 2].iov_base = msgv[i].buf;
|
||||||
|
iov[i * 3 + 2].iov_len = msgv[i].len;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_task_io_socket_sendmsg (hev_socks5_udp_get_fd (self), &mh,
|
||||||
|
MSG_WAITALL, task_io_yielder, self);
|
||||||
|
if (res <= 0) {
|
||||||
|
LOG_D ("%p socks5 udp write tcp", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_udp_sendmmsg_udp (HevSocks5UDP *self, HevSocks5UDPMsg *msgv,
|
||||||
|
unsigned int num)
|
||||||
|
{
|
||||||
|
struct iovec iov[num * 3];
|
||||||
|
struct mmsghdr mvec[num];
|
||||||
|
HevSocks5UDPHdr udp[num];
|
||||||
|
int i, res;
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
int addrlen;
|
||||||
|
|
||||||
|
addrlen = hev_socks5_addr_len (msgv[i].addr);
|
||||||
|
if (addrlen <= 0) {
|
||||||
|
LOG_D ("%p socks5 udp addr", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
udp[i].datlen = 0;
|
||||||
|
udp[i].hdrlen = 0;
|
||||||
|
|
||||||
|
iov[i * 3].iov_base = &udp[i];
|
||||||
|
iov[i * 3].iov_len = 3;
|
||||||
|
iov[i * 3 + 1].iov_base = msgv[i].addr;
|
||||||
|
iov[i * 3 + 1].iov_len = addrlen;
|
||||||
|
iov[i * 3 + 2].iov_base = msgv[i].buf;
|
||||||
|
iov[i * 3 + 2].iov_len = msgv[i].len;
|
||||||
|
|
||||||
|
mvec[i].msg_hdr.msg_name = NULL;
|
||||||
|
mvec[i].msg_hdr.msg_namelen = 0;
|
||||||
|
mvec[i].msg_hdr.msg_control = NULL;
|
||||||
|
mvec[i].msg_hdr.msg_controllen = 0;
|
||||||
|
mvec[i].msg_hdr.msg_iov = &iov[i * 3];
|
||||||
|
mvec[i].msg_hdr.msg_iovlen = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_task_io_socket_sendmmsg (hev_socks5_udp_get_fd (self), mvec, num,
|
||||||
|
MSG_WAITALL, task_io_yielder, self);
|
||||||
|
if (res <= 0)
|
||||||
|
LOG_D ("%p socks5 udp write udp", self);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_udp_sendmmsg (HevSocks5UDP *self, HevSocks5UDPMsg *msgv,
|
||||||
|
unsigned int num)
|
||||||
|
{
|
||||||
|
switch (HEV_SOCKS5 (self)->type) {
|
||||||
|
case HEV_SOCKS5_TYPE_UDP_IN_TCP:
|
||||||
|
return hev_socks5_udp_sendmmsg_tcp (self, msgv, num);
|
||||||
|
case HEV_SOCKS5_TYPE_UDP_IN_UDP:
|
||||||
|
return hev_socks5_udp_sendmmsg_udp (self, msgv, num);
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_udp_recvmmsg_tcp (HevSocks5UDP *self, HevSocks5UDPMsg *msgv,
|
||||||
|
unsigned int num, int nonblock)
|
||||||
|
{
|
||||||
|
int i, fd, rlen = 0;
|
||||||
|
|
||||||
|
fd = hev_socks5_udp_get_fd (self);
|
||||||
|
|
||||||
|
if (nonblock)
|
||||||
|
nonblock = MSG_DONTWAIT;
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
HevSocks5UDPHdr udp;
|
||||||
|
struct iovec iov[2];
|
||||||
|
struct msghdr mh;
|
||||||
|
int addrlen;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = hev_task_io_socket_recv (fd, &udp, 5, nonblock, task_io_yielder,
|
||||||
|
self);
|
||||||
|
if (res > 0 && res < 5)
|
||||||
|
res += hev_task_io_socket_recv (fd, (void *)&udp + res, 5 - res,
|
||||||
|
MSG_WAITALL, task_io_yielder, self);
|
||||||
|
if (res != 5) {
|
||||||
|
if (rlen > 0)
|
||||||
|
break;
|
||||||
|
if (res != -1 || errno != EAGAIN)
|
||||||
|
LOG_D ("%p socks5 udp read udp head", self);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (udp.hdrlen < 5) {
|
||||||
|
LOG_D ("%p socks5 udp head len", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
addrlen = udp.hdrlen - 3;
|
||||||
|
udp.datlen = ntohs (udp.datlen);
|
||||||
|
if (udp.datlen > (msgv[i].len - addrlen)) {
|
||||||
|
LOG_D ("%p socks5 udp data len", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mh.msg_name = NULL;
|
||||||
|
mh.msg_namelen = 0;
|
||||||
|
mh.msg_control = NULL;
|
||||||
|
mh.msg_controllen = 0;
|
||||||
|
mh.msg_iov = iov;
|
||||||
|
mh.msg_iovlen = 2;
|
||||||
|
|
||||||
|
iov[0].iov_base = msgv[i].buf + 2;
|
||||||
|
iov[0].iov_len = addrlen - 2;
|
||||||
|
iov[1].iov_base = msgv[i].buf + addrlen;
|
||||||
|
iov[1].iov_len = udp.datlen;
|
||||||
|
|
||||||
|
res = hev_task_io_socket_recvmsg (fd, &mh, MSG_WAITALL, task_io_yielder,
|
||||||
|
self);
|
||||||
|
if (res != (addrlen - 2 + udp.datlen)) {
|
||||||
|
LOG_D ("%p socks5 udp read udp data", self);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
msgv[i].addr = msgv[i].buf;
|
||||||
|
msgv[i].buf = iov[1].iov_base;
|
||||||
|
msgv[i].len = udp.datlen;
|
||||||
|
msgv[i].addr->atype = udp.addr.atype;
|
||||||
|
msgv[i].addr->domain.len = udp.addr.domain.len;
|
||||||
|
|
||||||
|
rlen++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_udp_recvmmsg_udp (HevSocks5UDP *self, HevSocks5UDPMsg *msgv,
|
||||||
|
unsigned int num, int nonblock)
|
||||||
|
{
|
||||||
|
struct sockaddr_in6 taddr;
|
||||||
|
struct mmsghdr mvec[num];
|
||||||
|
struct iovec iov[num];
|
||||||
|
int i, fd, res;
|
||||||
|
|
||||||
|
fd = hev_socks5_udp_get_fd (self);
|
||||||
|
|
||||||
|
if (nonblock)
|
||||||
|
nonblock = MSG_DONTWAIT;
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
mvec[i].msg_hdr.msg_name = NULL;
|
||||||
|
mvec[i].msg_hdr.msg_namelen = 0;
|
||||||
|
mvec[i].msg_hdr.msg_control = NULL;
|
||||||
|
mvec[i].msg_hdr.msg_controllen = 0;
|
||||||
|
mvec[i].msg_hdr.msg_iov = &iov[i];
|
||||||
|
mvec[i].msg_hdr.msg_iovlen = 1;
|
||||||
|
|
||||||
|
iov[i].iov_base = msgv[i].buf;
|
||||||
|
iov[i].iov_len = msgv[i].len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!HEV_SOCKS5 (self)->udp_associated) {
|
||||||
|
mvec[0].msg_hdr.msg_name = &taddr;
|
||||||
|
mvec[0].msg_hdr.msg_namelen = sizeof (taddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_task_io_socket_recvmmsg (fd, mvec, num, nonblock, task_io_yielder,
|
||||||
|
self);
|
||||||
|
if (res <= 0) {
|
||||||
|
if (res != -1 || errno != EAGAIN)
|
||||||
|
LOG_D ("%p socks5 udp read udp", self);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!HEV_SOCKS5 (self)->udp_associated) {
|
||||||
|
struct sockaddr *saddr = mvec[0].msg_hdr.msg_name;
|
||||||
|
socklen_t alen = mvec[0].msg_hdr.msg_namelen;
|
||||||
|
if (connect (fd, saddr, alen) < 0)
|
||||||
|
return -1;
|
||||||
|
HEV_SOCKS5 (self)->udp_associated = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < res; i++) {
|
||||||
|
HevSocks5UDPHdr *udp = msgv[i].buf;
|
||||||
|
int addrlen = hev_socks5_addr_len (&udp->addr);
|
||||||
|
int doff;
|
||||||
|
|
||||||
|
msgv[i].len = mvec[i].msg_len;
|
||||||
|
if (msgv[i].len < 4) {
|
||||||
|
msgv[i].addr = NULL;
|
||||||
|
msgv[i].len = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addrlen <= 0) {
|
||||||
|
LOG_D ("%p socks5 udp addr", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
doff = 3 + addrlen;
|
||||||
|
if (doff > msgv[i].len) {
|
||||||
|
LOG_D ("%p socks5 udp data len", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
msgv[i].addr = &udp->addr;
|
||||||
|
msgv[i].buf += doff;
|
||||||
|
msgv[i].len -= doff;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_udp_recvmmsg (HevSocks5UDP *self, HevSocks5UDPMsg *msgv,
|
||||||
|
unsigned int num, int nonblock)
|
||||||
|
{
|
||||||
|
switch (HEV_SOCKS5 (self)->type) {
|
||||||
|
case HEV_SOCKS5_TYPE_UDP_IN_TCP:
|
||||||
|
return hev_socks5_udp_recvmmsg_tcp (self, msgv, num, nonblock);
|
||||||
|
case HEV_SOCKS5_TYPE_UDP_IN_UDP:
|
||||||
|
return hev_socks5_udp_recvmmsg_udp (self, msgv, num, nonblock);
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_udp_fwd_f (HevSocks5UDP *self, int fd, void *buf, unsigned int num,
|
||||||
|
int *bind)
|
||||||
|
{
|
||||||
|
HevSocks5UDPMsg svec[num];
|
||||||
|
int i, res;
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
svec[i].buf = buf + UDP_BUF_SIZE * i;
|
||||||
|
svec[i].len = UDP_BUF_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_socks5_udp_recvmmsg (self, svec, num, 1);
|
||||||
|
if (res > 0) {
|
||||||
|
struct sockaddr_in6 addr[res];
|
||||||
|
struct mmsghdr dvec[res];
|
||||||
|
struct iovec iov[res];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
for (i = 0; i < res; i++) {
|
||||||
|
int family;
|
||||||
|
|
||||||
|
if (!svec[i].len || !svec[i].addr) {
|
||||||
|
LOG_D ("%p socks5 udp invalid", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
family = hev_socks5_get_addr_family (HEV_SOCKS5 (self));
|
||||||
|
ret = hev_socks5_addr_into_sockaddr6 (svec[i].addr, &addr[i],
|
||||||
|
&family);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_D ("%p socks5 udp sockaddr", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dvec[i].msg_hdr.msg_name = (struct sockaddr *)&addr[i];
|
||||||
|
dvec[i].msg_hdr.msg_namelen = sizeof (struct sockaddr_in6);
|
||||||
|
dvec[i].msg_hdr.msg_control = NULL;
|
||||||
|
dvec[i].msg_hdr.msg_controllen = 0;
|
||||||
|
dvec[i].msg_hdr.msg_iov = &iov[i];
|
||||||
|
dvec[i].msg_hdr.msg_iovlen = 1;
|
||||||
|
iov[i].iov_base = svec[i].buf;
|
||||||
|
iov[i].iov_len = svec[i].len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*bind) {
|
||||||
|
HevSocks5Class *skptr = HEV_OBJECT_GET_CLASS (self);
|
||||||
|
struct sockaddr *addr = dvec[0].msg_hdr.msg_name;
|
||||||
|
ret = skptr->binder (HEV_SOCKS5 (self), fd, addr);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_W ("%p socks5 udp bind", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*bind = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_task_io_socket_sendmmsg (fd, dvec, res, MSG_WAITALL,
|
||||||
|
task_io_yielder, self);
|
||||||
|
}
|
||||||
|
if (res <= 0) {
|
||||||
|
if (res == -1 && errno == EAGAIN)
|
||||||
|
return 0;
|
||||||
|
LOG_D ("%p socks5 udp fwd f recv send", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_udp_fwd_b (HevSocks5UDP *self, int fd, struct mmsghdr *svec,
|
||||||
|
unsigned int num)
|
||||||
|
{
|
||||||
|
int i, res;
|
||||||
|
|
||||||
|
res = hev_task_io_socket_recvmmsg (fd, svec, num, MSG_DONTWAIT,
|
||||||
|
task_io_yielder, self);
|
||||||
|
if (res > 0) {
|
||||||
|
HevSocks5UDPMsg dvec[res];
|
||||||
|
char saddr[res][19];
|
||||||
|
|
||||||
|
for (i = 0; i < res; i++) {
|
||||||
|
dvec[i].buf = svec[i].msg_hdr.msg_iov->iov_base;
|
||||||
|
dvec[i].len = svec[i].msg_len;
|
||||||
|
dvec[i].addr = (HevSocks5Addr *)&saddr[i];
|
||||||
|
hev_socks5_addr_from_sockaddr6 (dvec[i].addr,
|
||||||
|
svec[i].msg_hdr.msg_name);
|
||||||
|
}
|
||||||
|
res = hev_socks5_udp_sendmmsg (self, dvec, res);
|
||||||
|
}
|
||||||
|
if (res <= 0) {
|
||||||
|
if (res == -1 && errno == EAGAIN)
|
||||||
|
return 0;
|
||||||
|
LOG_D ("%p socks5 udp fwd b recv send", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_udp_splicer (HevSocks5UDP *self, int fd_b)
|
||||||
|
{
|
||||||
|
HevTask *task = hev_task_self ();
|
||||||
|
int res_f = 1, res_b = 1;
|
||||||
|
int bind = 0;
|
||||||
|
void *buf;
|
||||||
|
int fd_a;
|
||||||
|
int num;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 udp splicer", self);
|
||||||
|
|
||||||
|
num = hev_socks5_get_udp_copy_buffer_nums ();
|
||||||
|
buf = hev_malloc (UDP_BUF_SIZE * num * 2);
|
||||||
|
if (!buf)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
fd_a = hev_socks5_udp_get_fd (self);
|
||||||
|
if (hev_task_mod_fd (task, fd_a, POLLIN | POLLOUT) < 0)
|
||||||
|
hev_task_add_fd (task, fd_a, POLLIN | POLLOUT);
|
||||||
|
if (hev_task_add_fd (task, fd_b, POLLIN | POLLOUT) < 0)
|
||||||
|
hev_task_mod_fd (task, fd_b, POLLIN | POLLOUT);
|
||||||
|
|
||||||
|
{
|
||||||
|
struct mmsghdr vec[num];
|
||||||
|
struct sockaddr_in6 addr[num];
|
||||||
|
struct iovec iov[num];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
vec[i].msg_hdr.msg_name = (struct sockaddr *)&addr[i];
|
||||||
|
vec[i].msg_hdr.msg_namelen = sizeof (struct sockaddr_in6);
|
||||||
|
vec[i].msg_hdr.msg_control = NULL;
|
||||||
|
vec[i].msg_hdr.msg_controllen = 0;
|
||||||
|
vec[i].msg_hdr.msg_iov = &iov[i];
|
||||||
|
vec[i].msg_hdr.msg_iovlen = 1;
|
||||||
|
iov[i].iov_base = buf + UDP_BUF_SIZE * (num + i);
|
||||||
|
iov[i].iov_len = UDP_BUF_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
HevTaskYieldType type;
|
||||||
|
|
||||||
|
if (res_f >= 0)
|
||||||
|
res_f = hev_socks5_udp_fwd_f (self, fd_b, buf, num, &bind);
|
||||||
|
if (res_b >= 0)
|
||||||
|
res_b = hev_socks5_udp_fwd_b (self, fd_b, vec, num);
|
||||||
|
|
||||||
|
if (res_f > 0 || res_b > 0)
|
||||||
|
type = HEV_TASK_YIELD;
|
||||||
|
else if ((res_f & res_b) == 0)
|
||||||
|
type = HEV_TASK_WAITIO;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (task_io_yielder (type, self))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hev_free (buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_udp_splice (HevSocks5UDP *self, int fd)
|
||||||
|
{
|
||||||
|
HevSocks5UDPIface *iface;
|
||||||
|
|
||||||
|
iface = HEV_OBJECT_GET_IFACE (self, HEV_SOCKS5_UDP_TYPE);
|
||||||
|
return iface->splicer (self, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
hev_socks5_udp_iface (void)
|
||||||
|
{
|
||||||
|
static HevSocks5UDPIface type = {
|
||||||
|
.splicer = hev_socks5_udp_splicer,
|
||||||
|
};
|
||||||
|
|
||||||
|
return &type;
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-udp.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2025 hev
|
||||||
|
Description : Socks5 UDP
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_UDP_H__
|
||||||
|
#define __HEV_SOCKS5_UDP_H__
|
||||||
|
|
||||||
|
#include "hev-socks5-proto.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HEV_SOCKS5_UDP(p) ((HevSocks5UDP *)p)
|
||||||
|
#define HEV_SOCKS5_UDP_IFACE(p) ((HevSocks5UDPIface *)p)
|
||||||
|
#define HEV_SOCKS5_UDP_TYPE (hev_socks5_udp_iface ())
|
||||||
|
|
||||||
|
typedef void HevSocks5UDP;
|
||||||
|
typedef struct _HevSocks5UDPMsg HevSocks5UDPMsg;
|
||||||
|
typedef struct _HevSocks5UDPIface HevSocks5UDPIface;
|
||||||
|
|
||||||
|
struct _HevSocks5UDPMsg
|
||||||
|
{
|
||||||
|
HevSocks5Addr *addr;
|
||||||
|
void *buf;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5UDPIface
|
||||||
|
{
|
||||||
|
int (*get_fd) (HevSocks5UDP *self);
|
||||||
|
int (*splicer) (HevSocks5UDP *self, int fd);
|
||||||
|
};
|
||||||
|
|
||||||
|
void *hev_socks5_udp_iface (void);
|
||||||
|
|
||||||
|
int hev_socks5_udp_get_fd (HevSocks5UDP *self);
|
||||||
|
|
||||||
|
int hev_socks5_udp_sendmmsg (HevSocks5UDP *self, HevSocks5UDPMsg *msgv,
|
||||||
|
unsigned int num);
|
||||||
|
int hev_socks5_udp_recvmmsg (HevSocks5UDP *self, HevSocks5UDPMsg *msgv,
|
||||||
|
unsigned int num, int nonblock);
|
||||||
|
|
||||||
|
int hev_socks5_udp_splice (HevSocks5UDP *self, int fd);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_UDP_H__ */
|
||||||
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-user.c
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2023 hev
|
||||||
|
Description : Socks5 User
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "hev-socks5-logger-priv.h"
|
||||||
|
|
||||||
|
#include "hev-socks5-user.h"
|
||||||
|
|
||||||
|
HevSocks5User *
|
||||||
|
hev_socks5_user_new (const char *name, unsigned int name_len, const char *pass,
|
||||||
|
unsigned int pass_len)
|
||||||
|
{
|
||||||
|
HevSocks5User *self;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
self = calloc (1, sizeof (HevSocks5User));
|
||||||
|
if (!self)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
res = hev_socks5_user_construct (self, name, name_len, pass, pass_len);
|
||||||
|
if (res < 0) {
|
||||||
|
free (self);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 user new", self);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_user_check (HevSocks5User *self, const char *pass,
|
||||||
|
unsigned int pass_len)
|
||||||
|
{
|
||||||
|
HevSocks5UserClass *klass = HEV_OBJECT_GET_CLASS (self);
|
||||||
|
|
||||||
|
return klass->checker (self, pass, pass_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_user_checker (HevSocks5User *self, const char *pass,
|
||||||
|
unsigned int pass_len)
|
||||||
|
{
|
||||||
|
LOG_D ("%p socks5 user checker", self);
|
||||||
|
|
||||||
|
if (self->pass_len != pass_len)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (memcmp (self->pass, pass, pass_len) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_user_construct (HevSocks5User *self, const char *name,
|
||||||
|
unsigned int name_len, const char *pass,
|
||||||
|
unsigned int pass_len)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = hev_object_atomic_construct (&self->base);
|
||||||
|
if (res < 0)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 user construct", self);
|
||||||
|
|
||||||
|
HEV_OBJECT (self)->klass = HEV_SOCKS5_USER_TYPE;
|
||||||
|
|
||||||
|
self->name = malloc (name_len);
|
||||||
|
self->name_len = name_len;
|
||||||
|
memcpy (self->name, name, name_len);
|
||||||
|
|
||||||
|
self->pass = malloc (pass_len);
|
||||||
|
self->pass_len = pass_len;
|
||||||
|
memcpy (self->pass, pass, pass_len);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hev_socks5_user_destruct (HevObject *base)
|
||||||
|
{
|
||||||
|
HevSocks5User *self = HEV_SOCKS5_USER (base);
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 user destruct", self);
|
||||||
|
|
||||||
|
free (self->name);
|
||||||
|
free (self->pass);
|
||||||
|
|
||||||
|
HEV_OBJECT_ATOMIC_TYPE->destruct (base);
|
||||||
|
free (base);
|
||||||
|
}
|
||||||
|
|
||||||
|
HevObjectClass *
|
||||||
|
hev_socks5_user_class (void)
|
||||||
|
{
|
||||||
|
static HevSocks5UserClass klass;
|
||||||
|
HevSocks5UserClass *kptr = &klass;
|
||||||
|
HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr);
|
||||||
|
|
||||||
|
if (!okptr->name) {
|
||||||
|
memcpy (kptr, HEV_OBJECT_ATOMIC_TYPE, sizeof (HevObjectAtomicClass));
|
||||||
|
|
||||||
|
okptr->name = "HevSocks5User";
|
||||||
|
okptr->destruct = hev_socks5_user_destruct;
|
||||||
|
|
||||||
|
kptr->checker = hev_socks5_user_checker;
|
||||||
|
}
|
||||||
|
|
||||||
|
return okptr;
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-user.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2023 hev
|
||||||
|
Description : Socks5 User
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_USER_H__
|
||||||
|
#define __HEV_SOCKS5_USER_H__
|
||||||
|
|
||||||
|
#include <hev-object-atomic.h>
|
||||||
|
|
||||||
|
#include "hev-rbtree.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HEV_SOCKS5_USER(p) ((HevSocks5User *)p)
|
||||||
|
#define HEV_SOCKS5_USER_CLASS(p) ((HevSocks5UserClass *)p)
|
||||||
|
#define HEV_SOCKS5_USER_TYPE (hev_socks5_user_class ())
|
||||||
|
|
||||||
|
typedef struct _HevSocks5User HevSocks5User;
|
||||||
|
typedef struct _HevSocks5UserClass HevSocks5UserClass;
|
||||||
|
|
||||||
|
struct _HevSocks5User
|
||||||
|
{
|
||||||
|
HevObjectAtomic base;
|
||||||
|
|
||||||
|
HevRBTreeNode node;
|
||||||
|
|
||||||
|
char *name;
|
||||||
|
char *pass;
|
||||||
|
unsigned int name_len;
|
||||||
|
unsigned int pass_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5UserClass
|
||||||
|
{
|
||||||
|
HevObjectAtomicClass base;
|
||||||
|
|
||||||
|
int (*checker) (HevSocks5User *self, const char *pass,
|
||||||
|
unsigned int pass_len);
|
||||||
|
};
|
||||||
|
|
||||||
|
HevObjectClass *hev_socks5_user_class (void);
|
||||||
|
|
||||||
|
int hev_socks5_user_construct (HevSocks5User *self, const char *name,
|
||||||
|
unsigned int name_len, const char *pass,
|
||||||
|
unsigned int pass_len);
|
||||||
|
|
||||||
|
HevSocks5User *hev_socks5_user_new (const char *name, unsigned int name_len,
|
||||||
|
const char *pass, unsigned int pass_len);
|
||||||
|
|
||||||
|
int hev_socks5_user_check (HevSocks5User *self, const char *pass,
|
||||||
|
unsigned int pass_len);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_USER_H__ */
|
||||||
109
app/src/main/cpp/hev-socks5-tunnel/src/core/src/hev-socks5.c
Normal file
109
app/src/main/cpp/hev-socks5-tunnel/src/core/src/hev-socks5.c
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5.c
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2023 hev
|
||||||
|
Description : Socks5
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
#include <hev-task-io.h>
|
||||||
|
#include <hev-task-io-socket.h>
|
||||||
|
#include <hev-task-dns.h>
|
||||||
|
#include <hev-memory-allocator.h>
|
||||||
|
|
||||||
|
#include "hev-socks5-logger-priv.h"
|
||||||
|
|
||||||
|
#include "hev-socks5.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_get_timeout (HevSocks5 *self)
|
||||||
|
{
|
||||||
|
return self->timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_set_timeout (HevSocks5 *self, int timeout)
|
||||||
|
{
|
||||||
|
self->timeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
HevSocks5AddrFamily
|
||||||
|
hev_socks5_get_addr_family (HevSocks5 *self)
|
||||||
|
{
|
||||||
|
return self->addr_family;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_set_addr_family (HevSocks5 *self, HevSocks5AddrFamily family)
|
||||||
|
{
|
||||||
|
self->addr_family = family;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_bind (HevSocks5 *self, int sock, const struct sockaddr *dest)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_construct (HevSocks5 *self, HevSocks5Type type)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = hev_object_construct (&self->base);
|
||||||
|
if (res < 0)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 construct", self);
|
||||||
|
|
||||||
|
HEV_OBJECT (self)->klass = HEV_SOCKS5_TYPE;
|
||||||
|
|
||||||
|
self->fd = -1;
|
||||||
|
self->timeout = -1;
|
||||||
|
self->type = type;
|
||||||
|
self->addr_family = HEV_SOCKS5_ADDR_FAMILY_UNSPEC;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hev_socks5_destruct (HevObject *base)
|
||||||
|
{
|
||||||
|
HevSocks5 *self = HEV_SOCKS5 (base);
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 destruct", self);
|
||||||
|
|
||||||
|
if (self->fd >= 0) {
|
||||||
|
hev_task_del_fd (hev_task_self (), self->fd);
|
||||||
|
close (self->fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
HEV_OBJECT_TYPE->destruct (base);
|
||||||
|
hev_free (base);
|
||||||
|
}
|
||||||
|
|
||||||
|
HevObjectClass *
|
||||||
|
hev_socks5_class (void)
|
||||||
|
{
|
||||||
|
static HevSocks5Class klass;
|
||||||
|
HevSocks5Class *kptr = &klass;
|
||||||
|
HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr);
|
||||||
|
|
||||||
|
if (!okptr->name) {
|
||||||
|
memcpy (kptr, HEV_OBJECT_TYPE, sizeof (HevObjectClass));
|
||||||
|
|
||||||
|
okptr->name = "HevSocks5";
|
||||||
|
okptr->destruct = hev_socks5_destruct;
|
||||||
|
|
||||||
|
kptr->binder = hev_socks5_bind;
|
||||||
|
}
|
||||||
|
|
||||||
|
return okptr;
|
||||||
|
}
|
||||||
78
app/src/main/cpp/hev-socks5-tunnel/src/core/src/hev-socks5.h
Normal file
78
app/src/main/cpp/hev-socks5-tunnel/src/core/src/hev-socks5.h
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5.h
|
||||||
|
Author : Heiher <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2021 - 2023 hev
|
||||||
|
Description : Socks5
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_H__
|
||||||
|
#define __HEV_SOCKS5_H__
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include <hev-object.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HEV_SOCKS5(p) ((HevSocks5 *)p)
|
||||||
|
#define HEV_SOCKS5_CLASS(p) ((HevSocks5Class *)p)
|
||||||
|
#define HEV_SOCKS5_TYPE (hev_socks5_class ())
|
||||||
|
|
||||||
|
typedef struct _HevSocks5 HevSocks5;
|
||||||
|
typedef struct _HevSocks5Class HevSocks5Class;
|
||||||
|
typedef enum _HevSocks5Type HevSocks5Type;
|
||||||
|
typedef enum _HevSocks5AddrFamily HevSocks5AddrFamily;
|
||||||
|
|
||||||
|
enum _HevSocks5Type
|
||||||
|
{
|
||||||
|
HEV_SOCKS5_TYPE_NONE,
|
||||||
|
HEV_SOCKS5_TYPE_TCP,
|
||||||
|
HEV_SOCKS5_TYPE_UDP_IN_TCP,
|
||||||
|
HEV_SOCKS5_TYPE_UDP_IN_UDP,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum _HevSocks5AddrFamily
|
||||||
|
{
|
||||||
|
HEV_SOCKS5_ADDR_FAMILY_IPV4 = AF_INET,
|
||||||
|
HEV_SOCKS5_ADDR_FAMILY_IPV6 = AF_INET6,
|
||||||
|
HEV_SOCKS5_ADDR_FAMILY_UNSPEC = AF_UNSPEC,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5
|
||||||
|
{
|
||||||
|
HevObject base;
|
||||||
|
|
||||||
|
int fd;
|
||||||
|
int timeout;
|
||||||
|
int udp_associated;
|
||||||
|
HevSocks5Type type;
|
||||||
|
HevSocks5AddrFamily addr_family;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5Class
|
||||||
|
{
|
||||||
|
HevObjectClass base;
|
||||||
|
|
||||||
|
int (*binder) (HevSocks5 *self, int sock, const struct sockaddr *dest);
|
||||||
|
};
|
||||||
|
|
||||||
|
HevObjectClass *hev_socks5_class (void);
|
||||||
|
|
||||||
|
int hev_socks5_construct (HevSocks5 *self, HevSocks5Type type);
|
||||||
|
|
||||||
|
int hev_socks5_get_timeout (HevSocks5 *self);
|
||||||
|
void hev_socks5_set_timeout (HevSocks5 *self, int timeout);
|
||||||
|
|
||||||
|
HevSocks5AddrFamily hev_socks5_get_addr_family (HevSocks5 *self);
|
||||||
|
void hev_socks5_set_addr_family (HevSocks5 *self, HevSocks5AddrFamily family);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_H__ */
|
||||||
21
app/src/main/cpp/hev-socks5-tunnel/src/hev-config-const.h
Normal file
21
app/src/main/cpp/hev-socks5-tunnel/src/hev-config-const.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-config-const.h
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2019 - 2024 hev
|
||||||
|
Description : Config Constants
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_CONFIG_CONST_H__
|
||||||
|
#define __HEV_CONFIG_CONST_H__
|
||||||
|
|
||||||
|
#define MAJOR_VERSION (2)
|
||||||
|
#define MINOR_VERSION (15)
|
||||||
|
#define MICRO_VERSION (0)
|
||||||
|
|
||||||
|
static const int UDP_BUF_SIZE = 1500;
|
||||||
|
static const int UDP_POOL_SIZE = 512;
|
||||||
|
static const int TASK_STACK_SIZE = 20480;
|
||||||
|
|
||||||
|
#endif /* __HEV_CONFIG_CONST_H__ */
|
||||||
688
app/src/main/cpp/hev-socks5-tunnel/src/hev-config.c
Normal file
688
app/src/main/cpp/hev-socks5-tunnel/src/hev-config.c
Normal file
@ -0,0 +1,688 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-config.c
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2019 - 2024 hev
|
||||||
|
Description : Config
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <lwip/tcp.h>
|
||||||
|
#include <yaml.h>
|
||||||
|
|
||||||
|
#include "hev-logger.h"
|
||||||
|
#include "hev-config.h"
|
||||||
|
#include "hev-config-const.h"
|
||||||
|
|
||||||
|
static char tun_name[64];
|
||||||
|
static unsigned int tun_mtu = 8500;
|
||||||
|
static int multi_queue;
|
||||||
|
|
||||||
|
static char tun_ipv4_address[16];
|
||||||
|
static char tun_ipv6_address[64];
|
||||||
|
|
||||||
|
static char tun_post_up_script[1024];
|
||||||
|
static char tun_pre_down_script[1024];
|
||||||
|
|
||||||
|
static HevConfigServer srv;
|
||||||
|
|
||||||
|
static int mapdns_address;
|
||||||
|
static int mapdns_port;
|
||||||
|
static int mapdns_network;
|
||||||
|
static int mapdns_netmask;
|
||||||
|
static int mapdns_cache_size;
|
||||||
|
|
||||||
|
static char log_file[1024];
|
||||||
|
static char pid_file[1024];
|
||||||
|
static int max_session_count;
|
||||||
|
static int task_stack_size = 86016;
|
||||||
|
static int tcp_buffer_size = 65536;
|
||||||
|
static int udp_recv_buffer_size = 524288;
|
||||||
|
static int udp_copy_buffer_nums = 10;
|
||||||
|
static int connect_timeout = 10000;
|
||||||
|
static int tcp_read_write_timeout = 300000;
|
||||||
|
static int udp_read_write_timeout = 60000;
|
||||||
|
static int limit_nofile = 65535;
|
||||||
|
static int log_level = HEV_LOGGER_WARN;
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_config_parse_tunnel_ipv4 (yaml_document_t *doc, yaml_node_t *base)
|
||||||
|
{
|
||||||
|
yaml_node_pair_t *pair;
|
||||||
|
|
||||||
|
if (!base || YAML_MAPPING_NODE != base->type)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (pair = base->data.mapping.pairs.start;
|
||||||
|
pair < base->data.mapping.pairs.top; pair++) {
|
||||||
|
yaml_node_t *node;
|
||||||
|
const char *key, *value;
|
||||||
|
|
||||||
|
if (!pair->key || !pair->value)
|
||||||
|
break;
|
||||||
|
|
||||||
|
node = yaml_document_get_node (doc, pair->key);
|
||||||
|
if (!node || YAML_SCALAR_NODE != node->type)
|
||||||
|
break;
|
||||||
|
key = (const char *)node->data.scalar.value;
|
||||||
|
|
||||||
|
node = yaml_document_get_node (doc, pair->value);
|
||||||
|
if (!node || YAML_SCALAR_NODE != node->type)
|
||||||
|
break;
|
||||||
|
value = (const char *)node->data.scalar.value;
|
||||||
|
|
||||||
|
if (0 == strcmp (key, "address"))
|
||||||
|
strncpy (tun_ipv4_address, value, 16 - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_config_parse_tunnel_ipv6 (yaml_document_t *doc, yaml_node_t *base)
|
||||||
|
{
|
||||||
|
yaml_node_pair_t *pair;
|
||||||
|
|
||||||
|
if (!base || YAML_MAPPING_NODE != base->type)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (pair = base->data.mapping.pairs.start;
|
||||||
|
pair < base->data.mapping.pairs.top; pair++) {
|
||||||
|
yaml_node_t *node;
|
||||||
|
const char *key, *value;
|
||||||
|
|
||||||
|
if (!pair->key || !pair->value)
|
||||||
|
break;
|
||||||
|
|
||||||
|
node = yaml_document_get_node (doc, pair->key);
|
||||||
|
if (!node || YAML_SCALAR_NODE != node->type)
|
||||||
|
break;
|
||||||
|
key = (const char *)node->data.scalar.value;
|
||||||
|
|
||||||
|
node = yaml_document_get_node (doc, pair->value);
|
||||||
|
if (!node || YAML_SCALAR_NODE != node->type)
|
||||||
|
break;
|
||||||
|
value = (const char *)node->data.scalar.value;
|
||||||
|
|
||||||
|
if (0 == strcmp (key, "address"))
|
||||||
|
strncpy (tun_ipv6_address, value, 64 - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_config_parse_tunnel (yaml_document_t *doc, yaml_node_t *base)
|
||||||
|
{
|
||||||
|
yaml_node_pair_t *pair;
|
||||||
|
|
||||||
|
if (!base || YAML_MAPPING_NODE != base->type)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (pair = base->data.mapping.pairs.start;
|
||||||
|
pair < base->data.mapping.pairs.top; pair++) {
|
||||||
|
yaml_node_t *node;
|
||||||
|
const char *key;
|
||||||
|
|
||||||
|
if (!pair->key || !pair->value)
|
||||||
|
break;
|
||||||
|
|
||||||
|
node = yaml_document_get_node (doc, pair->key);
|
||||||
|
if (!node || YAML_SCALAR_NODE != node->type)
|
||||||
|
break;
|
||||||
|
key = (const char *)node->data.scalar.value;
|
||||||
|
|
||||||
|
node = yaml_document_get_node (doc, pair->value);
|
||||||
|
if (!node)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (YAML_SCALAR_NODE == node->type) {
|
||||||
|
const char *value = (const char *)node->data.scalar.value;
|
||||||
|
|
||||||
|
if (0 == strcmp (key, "name"))
|
||||||
|
strncpy (tun_name, value, 64 - 1);
|
||||||
|
else if (0 == strcmp (key, "mtu"))
|
||||||
|
tun_mtu = strtoul (value, NULL, 10);
|
||||||
|
else if (0 == strcmp (key, "multi-queue"))
|
||||||
|
multi_queue = strcasecmp (value, "false");
|
||||||
|
else if (0 == strcmp (key, "ipv4"))
|
||||||
|
strncpy (tun_ipv4_address, value, 16 - 1);
|
||||||
|
else if (0 == strcmp (key, "ipv6"))
|
||||||
|
strncpy (tun_ipv6_address, value, 64 - 1);
|
||||||
|
else if (0 == strcmp (key, "post-up-script"))
|
||||||
|
strncpy (tun_post_up_script, value, 64 - 1);
|
||||||
|
else if (0 == strcmp (key, "pre-down-script"))
|
||||||
|
strncpy (tun_pre_down_script, value, 64 - 1);
|
||||||
|
} else {
|
||||||
|
if (0 == strcmp (key, "ipv4"))
|
||||||
|
hev_config_parse_tunnel_ipv4 (doc, node);
|
||||||
|
else if (0 == strcmp (key, "ipv6"))
|
||||||
|
hev_config_parse_tunnel_ipv6 (doc, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_config_parse_socks5 (yaml_document_t *doc, yaml_node_t *base)
|
||||||
|
{
|
||||||
|
yaml_node_pair_t *pair;
|
||||||
|
static char _user[256];
|
||||||
|
static char _pass[256];
|
||||||
|
const char *addr = NULL;
|
||||||
|
const char *port = NULL;
|
||||||
|
const char *udpm = NULL;
|
||||||
|
const char *udpa = NULL;
|
||||||
|
const char *user = NULL;
|
||||||
|
const char *pass = NULL;
|
||||||
|
const char *mark = NULL;
|
||||||
|
const char *pipe = NULL;
|
||||||
|
const char *tfso = NULL;
|
||||||
|
|
||||||
|
if (!base || YAML_MAPPING_NODE != base->type)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (pair = base->data.mapping.pairs.start;
|
||||||
|
pair < base->data.mapping.pairs.top; pair++) {
|
||||||
|
yaml_node_t *node;
|
||||||
|
const char *key, *value;
|
||||||
|
|
||||||
|
if (!pair->key || !pair->value)
|
||||||
|
break;
|
||||||
|
|
||||||
|
node = yaml_document_get_node (doc, pair->key);
|
||||||
|
if (!node || YAML_SCALAR_NODE != node->type)
|
||||||
|
break;
|
||||||
|
key = (const char *)node->data.scalar.value;
|
||||||
|
|
||||||
|
node = yaml_document_get_node (doc, pair->value);
|
||||||
|
if (!node || YAML_SCALAR_NODE != node->type)
|
||||||
|
break;
|
||||||
|
value = (const char *)node->data.scalar.value;
|
||||||
|
|
||||||
|
if (0 == strcmp (key, "port"))
|
||||||
|
port = value;
|
||||||
|
else if (0 == strcmp (key, "address"))
|
||||||
|
addr = value;
|
||||||
|
else if (0 == strcmp (key, "udp"))
|
||||||
|
udpm = value;
|
||||||
|
else if (0 == strcmp (key, "udp-address"))
|
||||||
|
udpa = value;
|
||||||
|
else if (0 == strcmp (key, "pipeline"))
|
||||||
|
pipe = value;
|
||||||
|
else if (0 == strcmp (key, "username"))
|
||||||
|
user = value;
|
||||||
|
else if (0 == strcmp (key, "password"))
|
||||||
|
pass = value;
|
||||||
|
else if (0 == strcmp (key, "mark"))
|
||||||
|
mark = value;
|
||||||
|
else if (0 == strcmp (key, "tcp-fastopen"))
|
||||||
|
tfso = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!port) {
|
||||||
|
fprintf (stderr, "Can't found socks5.port!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!addr) {
|
||||||
|
fprintf (stderr, "Can't found socks5.address!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((user && !pass) || (!user && pass)) {
|
||||||
|
fprintf (stderr, "Must be set both socks5 username and password!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy (srv.addr, addr, 256 - 1);
|
||||||
|
srv.port = strtoul (port, NULL, 10);
|
||||||
|
|
||||||
|
if (pipe && (strcasecmp (pipe, "true") == 0))
|
||||||
|
srv.pipeline = 1;
|
||||||
|
|
||||||
|
if (udpm && (strcasecmp (udpm, "udp") == 0))
|
||||||
|
srv.udp_in_udp = 1;
|
||||||
|
|
||||||
|
if (udpa)
|
||||||
|
strncpy (srv.udp_addr, udpa, 256 - 1);
|
||||||
|
|
||||||
|
if (user && pass) {
|
||||||
|
strncpy (_user, user, 256 - 1);
|
||||||
|
strncpy (_pass, pass, 256 - 1);
|
||||||
|
srv.user = _user;
|
||||||
|
srv.pass = _pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mark)
|
||||||
|
srv.mark = strtoul (mark, NULL, 0);
|
||||||
|
|
||||||
|
if (tfso)
|
||||||
|
srv.fastopen = (0 == strcasecmp (tfso, "true")) ? 1 : 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_config_parse_mapdns (yaml_document_t *doc, yaml_node_t *base)
|
||||||
|
{
|
||||||
|
yaml_node_pair_t *pair;
|
||||||
|
|
||||||
|
if (!base || YAML_MAPPING_NODE != base->type)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (pair = base->data.mapping.pairs.start;
|
||||||
|
pair < base->data.mapping.pairs.top; pair++) {
|
||||||
|
yaml_node_t *node;
|
||||||
|
const char *key, *value;
|
||||||
|
|
||||||
|
if (!pair->key || !pair->value)
|
||||||
|
break;
|
||||||
|
|
||||||
|
node = yaml_document_get_node (doc, pair->key);
|
||||||
|
if (!node || YAML_SCALAR_NODE != node->type)
|
||||||
|
break;
|
||||||
|
key = (const char *)node->data.scalar.value;
|
||||||
|
|
||||||
|
node = yaml_document_get_node (doc, pair->value);
|
||||||
|
if (!node || YAML_SCALAR_NODE != node->type)
|
||||||
|
break;
|
||||||
|
value = (const char *)node->data.scalar.value;
|
||||||
|
|
||||||
|
if (0 == strcmp (key, "address"))
|
||||||
|
inet_pton (AF_INET, value, &mapdns_address);
|
||||||
|
else if (0 == strcmp (key, "port"))
|
||||||
|
mapdns_port = strtoul (value, NULL, 10);
|
||||||
|
else if (0 == strcmp (key, "network"))
|
||||||
|
inet_pton (AF_INET, value, &mapdns_network);
|
||||||
|
else if (0 == strcmp (key, "netmask"))
|
||||||
|
inet_pton (AF_INET, value, &mapdns_netmask);
|
||||||
|
else if (0 == strcmp (key, "cache-size"))
|
||||||
|
mapdns_cache_size = strtoul (value, NULL, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
mapdns_network = ntohl (mapdns_network);
|
||||||
|
mapdns_netmask = ntohl (mapdns_netmask);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_config_parse_log_level (const char *value)
|
||||||
|
{
|
||||||
|
if (0 == strcmp (value, "debug"))
|
||||||
|
return HEV_LOGGER_DEBUG;
|
||||||
|
else if (0 == strcmp (value, "info"))
|
||||||
|
return HEV_LOGGER_INFO;
|
||||||
|
else if (0 == strcmp (value, "error"))
|
||||||
|
return HEV_LOGGER_ERROR;
|
||||||
|
|
||||||
|
return HEV_LOGGER_WARN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_config_parse_misc (yaml_document_t *doc, yaml_node_t *base)
|
||||||
|
{
|
||||||
|
yaml_node_pair_t *pair;
|
||||||
|
int tcp_rw_timeout = -1;
|
||||||
|
int udp_rw_timeout = -1;
|
||||||
|
int rw_timeout = -1;
|
||||||
|
|
||||||
|
if (!base || YAML_MAPPING_NODE != base->type)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (pair = base->data.mapping.pairs.start;
|
||||||
|
pair < base->data.mapping.pairs.top; pair++) {
|
||||||
|
yaml_node_t *node;
|
||||||
|
const char *key, *value;
|
||||||
|
|
||||||
|
if (!pair->key || !pair->value)
|
||||||
|
break;
|
||||||
|
|
||||||
|
node = yaml_document_get_node (doc, pair->key);
|
||||||
|
if (!node || YAML_SCALAR_NODE != node->type)
|
||||||
|
break;
|
||||||
|
key = (const char *)node->data.scalar.value;
|
||||||
|
|
||||||
|
node = yaml_document_get_node (doc, pair->value);
|
||||||
|
if (!node || YAML_SCALAR_NODE != node->type)
|
||||||
|
break;
|
||||||
|
value = (const char *)node->data.scalar.value;
|
||||||
|
|
||||||
|
if (0 == strcmp (key, "task-stack-size"))
|
||||||
|
task_stack_size = strtoul (value, NULL, 10);
|
||||||
|
else if (0 == strcmp (key, "tcp-buffer-size"))
|
||||||
|
tcp_buffer_size = strtoul (value, NULL, 10);
|
||||||
|
else if (0 == strcmp (key, "udp-recv-buffer-size"))
|
||||||
|
udp_recv_buffer_size = strtoul (value, NULL, 10);
|
||||||
|
else if (0 == strcmp (key, "udp-copy-buffer-nums"))
|
||||||
|
udp_copy_buffer_nums = strtoul (value, NULL, 10);
|
||||||
|
else if (0 == strcmp (key, "max-session-count"))
|
||||||
|
max_session_count = strtoul (value, NULL, 10);
|
||||||
|
else if (0 == strcmp (key, "connect-timeout"))
|
||||||
|
connect_timeout = strtoul (value, NULL, 10);
|
||||||
|
else if (0 == strcmp (key, "read-write-timeout"))
|
||||||
|
rw_timeout = strtoul (value, NULL, 10);
|
||||||
|
else if (0 == strcmp (key, "tcp-read-write-timeout"))
|
||||||
|
tcp_rw_timeout = strtoul (value, NULL, 10);
|
||||||
|
else if (0 == strcmp (key, "udp-read-write-timeout"))
|
||||||
|
udp_rw_timeout = strtoul (value, NULL, 10);
|
||||||
|
else if (0 == strcmp (key, "pid-file"))
|
||||||
|
strncpy (pid_file, value, 1024 - 1);
|
||||||
|
else if (0 == strcmp (key, "log-file"))
|
||||||
|
strncpy (log_file, value, 1024 - 1);
|
||||||
|
else if (0 == strcmp (key, "log-level"))
|
||||||
|
log_level = hev_config_parse_log_level (value);
|
||||||
|
else if (0 == strcmp (key, "limit-nofile"))
|
||||||
|
limit_nofile = strtol (value, NULL, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tcp_rw_timeout <= 0)
|
||||||
|
tcp_rw_timeout = rw_timeout;
|
||||||
|
if (udp_rw_timeout <= 0)
|
||||||
|
udp_rw_timeout = rw_timeout;
|
||||||
|
|
||||||
|
if (tcp_rw_timeout > 0)
|
||||||
|
tcp_read_write_timeout = tcp_rw_timeout;
|
||||||
|
if (udp_rw_timeout > 0)
|
||||||
|
udp_read_write_timeout = udp_rw_timeout;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_config_parse_doc (yaml_document_t *doc)
|
||||||
|
{
|
||||||
|
yaml_node_t *root;
|
||||||
|
yaml_node_pair_t *pair;
|
||||||
|
int min_task_stack_size;
|
||||||
|
int udp_buffer_size;
|
||||||
|
|
||||||
|
root = yaml_document_get_root_node (doc);
|
||||||
|
if (!root || YAML_MAPPING_NODE != root->type)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (pair = root->data.mapping.pairs.start;
|
||||||
|
pair < root->data.mapping.pairs.top; pair++) {
|
||||||
|
yaml_node_t *node;
|
||||||
|
const char *key;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
if (!pair->key || !pair->value)
|
||||||
|
break;
|
||||||
|
|
||||||
|
node = yaml_document_get_node (doc, pair->key);
|
||||||
|
if (!node || YAML_SCALAR_NODE != node->type)
|
||||||
|
break;
|
||||||
|
|
||||||
|
key = (const char *)node->data.scalar.value;
|
||||||
|
node = yaml_document_get_node (doc, pair->value);
|
||||||
|
|
||||||
|
if (0 == strcmp (key, "tunnel"))
|
||||||
|
res = hev_config_parse_tunnel (doc, node);
|
||||||
|
else if (0 == strcmp (key, "socks5"))
|
||||||
|
res = hev_config_parse_socks5 (doc, node);
|
||||||
|
else if (0 == strcmp (key, "mapdns"))
|
||||||
|
res = hev_config_parse_mapdns (doc, node);
|
||||||
|
else if (0 == strcmp (key, "misc"))
|
||||||
|
res = hev_config_parse_misc (doc, node);
|
||||||
|
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tcp_buffer_size > TCP_SND_BUF)
|
||||||
|
tcp_buffer_size = TCP_SND_BUF;
|
||||||
|
|
||||||
|
udp_buffer_size = UDP_BUF_SIZE * udp_copy_buffer_nums;
|
||||||
|
|
||||||
|
if (tcp_buffer_size > udp_buffer_size)
|
||||||
|
min_task_stack_size = TASK_STACK_SIZE + tcp_buffer_size;
|
||||||
|
else
|
||||||
|
min_task_stack_size = TASK_STACK_SIZE + udp_buffer_size;
|
||||||
|
|
||||||
|
if (task_stack_size < min_task_stack_size)
|
||||||
|
task_stack_size = min_task_stack_size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_config_init_from_file (const char *config_path)
|
||||||
|
{
|
||||||
|
yaml_parser_t parser;
|
||||||
|
yaml_document_t doc;
|
||||||
|
FILE *fp;
|
||||||
|
int res = -1;
|
||||||
|
|
||||||
|
if (!yaml_parser_initialize (&parser))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
fp = fopen (config_path, "r");
|
||||||
|
if (!fp) {
|
||||||
|
fprintf (stderr, "Open %s failed!\n", config_path);
|
||||||
|
goto exit_free_parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
yaml_parser_set_input_file (&parser, fp);
|
||||||
|
if (!yaml_parser_load (&parser, &doc)) {
|
||||||
|
fprintf (stderr, "Parse %s failed!\n", config_path);
|
||||||
|
goto exit_close_fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_config_parse_doc (&doc);
|
||||||
|
yaml_document_delete (&doc);
|
||||||
|
|
||||||
|
exit_close_fp:
|
||||||
|
fclose (fp);
|
||||||
|
exit_free_parser:
|
||||||
|
yaml_parser_delete (&parser);
|
||||||
|
exit:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_config_init_from_str (const unsigned char *config_str,
|
||||||
|
unsigned int config_len)
|
||||||
|
{
|
||||||
|
yaml_parser_t parser;
|
||||||
|
yaml_document_t doc;
|
||||||
|
int res = -1;
|
||||||
|
|
||||||
|
if (!yaml_parser_initialize (&parser))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
yaml_parser_set_input_string (&parser, config_str, config_len);
|
||||||
|
if (!yaml_parser_load (&parser, &doc)) {
|
||||||
|
fprintf (stderr, "Failed to parse config.");
|
||||||
|
goto exit_free_parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_config_parse_doc (&doc);
|
||||||
|
yaml_document_delete (&doc);
|
||||||
|
|
||||||
|
exit_free_parser:
|
||||||
|
yaml_parser_delete (&parser);
|
||||||
|
exit:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_config_fini (void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
hev_config_get_tunnel_name (void)
|
||||||
|
{
|
||||||
|
if (!tun_name[0])
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return tun_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
hev_config_get_tunnel_mtu (void)
|
||||||
|
{
|
||||||
|
return tun_mtu;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_config_get_tunnel_multi_queue (void)
|
||||||
|
{
|
||||||
|
return multi_queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
hev_config_get_tunnel_ipv4_address (void)
|
||||||
|
{
|
||||||
|
if (!tun_ipv4_address[0])
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return tun_ipv4_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
hev_config_get_tunnel_ipv6_address (void)
|
||||||
|
{
|
||||||
|
if (!tun_ipv6_address[0])
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return tun_ipv6_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
hev_config_get_tunnel_post_up_script (void)
|
||||||
|
{
|
||||||
|
if (!tun_post_up_script[0])
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return tun_post_up_script;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
hev_config_get_tunnel_pre_down_script (void)
|
||||||
|
{
|
||||||
|
if (!tun_pre_down_script[0])
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return tun_pre_down_script;
|
||||||
|
}
|
||||||
|
|
||||||
|
HevConfigServer *
|
||||||
|
hev_config_get_socks5_server (void)
|
||||||
|
{
|
||||||
|
return &srv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_config_get_mapdns_address (void)
|
||||||
|
{
|
||||||
|
return mapdns_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_config_get_mapdns_port (void)
|
||||||
|
{
|
||||||
|
return mapdns_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_config_get_mapdns_network (void)
|
||||||
|
{
|
||||||
|
return mapdns_network;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_config_get_mapdns_netmask (void)
|
||||||
|
{
|
||||||
|
return mapdns_netmask;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_config_get_mapdns_cache_size (void)
|
||||||
|
{
|
||||||
|
return mapdns_cache_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_config_get_misc_task_stack_size (void)
|
||||||
|
{
|
||||||
|
return task_stack_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_config_get_misc_tcp_buffer_size (void)
|
||||||
|
{
|
||||||
|
return tcp_buffer_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_config_get_misc_udp_recv_buffer_size (void)
|
||||||
|
{
|
||||||
|
return udp_recv_buffer_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_config_get_misc_udp_copy_buffer_nums (void)
|
||||||
|
{
|
||||||
|
return udp_copy_buffer_nums;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_config_get_misc_max_session_count (void)
|
||||||
|
{
|
||||||
|
return max_session_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_config_get_misc_connect_timeout (void)
|
||||||
|
{
|
||||||
|
return connect_timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_config_get_misc_tcp_read_write_timeout (void)
|
||||||
|
{
|
||||||
|
return tcp_read_write_timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_config_get_misc_udp_read_write_timeout (void)
|
||||||
|
{
|
||||||
|
return udp_read_write_timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_config_get_misc_limit_nofile (void)
|
||||||
|
{
|
||||||
|
return limit_nofile;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
hev_config_get_misc_pid_file (void)
|
||||||
|
{
|
||||||
|
if (!pid_file[0])
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return pid_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
hev_config_get_misc_log_file (void)
|
||||||
|
{
|
||||||
|
if (!log_file[0])
|
||||||
|
return "stderr";
|
||||||
|
|
||||||
|
return log_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_config_get_misc_log_level (void)
|
||||||
|
{
|
||||||
|
return log_level;
|
||||||
|
}
|
||||||
64
app/src/main/cpp/hev-socks5-tunnel/src/hev-config.h
Normal file
64
app/src/main/cpp/hev-socks5-tunnel/src/hev-config.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-config.h
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2019 - 2023 hev
|
||||||
|
Description : Config
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_CONFIG_H__
|
||||||
|
#define __HEV_CONFIG_H__
|
||||||
|
|
||||||
|
typedef struct _HevConfigServer HevConfigServer;
|
||||||
|
|
||||||
|
struct _HevConfigServer
|
||||||
|
{
|
||||||
|
const char *user;
|
||||||
|
const char *pass;
|
||||||
|
unsigned int mark;
|
||||||
|
short udp_in_udp;
|
||||||
|
unsigned short port;
|
||||||
|
unsigned char pipeline;
|
||||||
|
unsigned char fastopen;
|
||||||
|
char udp_addr[256];
|
||||||
|
char addr[256];
|
||||||
|
};
|
||||||
|
|
||||||
|
int hev_config_init_from_file (const char *config_path);
|
||||||
|
int hev_config_init_from_str (const unsigned char *config_str,
|
||||||
|
unsigned int config_len);
|
||||||
|
void hev_config_fini (void);
|
||||||
|
|
||||||
|
const char *hev_config_get_tunnel_name (void);
|
||||||
|
unsigned int hev_config_get_tunnel_mtu (void);
|
||||||
|
int hev_config_get_tunnel_multi_queue (void);
|
||||||
|
|
||||||
|
const char *hev_config_get_tunnel_ipv4_address (void);
|
||||||
|
const char *hev_config_get_tunnel_ipv6_address (void);
|
||||||
|
|
||||||
|
const char *hev_config_get_tunnel_post_up_script (void);
|
||||||
|
const char *hev_config_get_tunnel_pre_down_script (void);
|
||||||
|
|
||||||
|
HevConfigServer *hev_config_get_socks5_server (void);
|
||||||
|
|
||||||
|
int hev_config_get_mapdns_address (void);
|
||||||
|
int hev_config_get_mapdns_port (void);
|
||||||
|
int hev_config_get_mapdns_network (void);
|
||||||
|
int hev_config_get_mapdns_netmask (void);
|
||||||
|
int hev_config_get_mapdns_cache_size (void);
|
||||||
|
|
||||||
|
int hev_config_get_misc_task_stack_size (void);
|
||||||
|
int hev_config_get_misc_tcp_buffer_size (void);
|
||||||
|
int hev_config_get_misc_udp_recv_buffer_size (void);
|
||||||
|
int hev_config_get_misc_udp_copy_buffer_nums (void);
|
||||||
|
int hev_config_get_misc_max_session_count (void);
|
||||||
|
int hev_config_get_misc_connect_timeout (void);
|
||||||
|
int hev_config_get_misc_tcp_read_write_timeout (void);
|
||||||
|
int hev_config_get_misc_udp_read_write_timeout (void);
|
||||||
|
int hev_config_get_misc_limit_nofile (void);
|
||||||
|
const char *hev_config_get_misc_pid_file (void);
|
||||||
|
const char *hev_config_get_misc_log_file (void);
|
||||||
|
int hev_config_get_misc_log_level (void);
|
||||||
|
|
||||||
|
#endif /* __HEV_CONFIG_H__ */
|
||||||
170
app/src/main/cpp/hev-socks5-tunnel/src/hev-jni.c
Normal file
170
app/src/main/cpp/hev-socks5-tunnel/src/hev-jni.c
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-jni.c
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2019 - 2023 hev
|
||||||
|
Description : Jave Native Interface
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef ANDROID
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "hev-main.h"
|
||||||
|
|
||||||
|
#include "hev-jni.h"
|
||||||
|
|
||||||
|
/* clang-format off */
|
||||||
|
#ifndef PKGNAME
|
||||||
|
#define PKGNAME hev/htproxy
|
||||||
|
#endif
|
||||||
|
#ifndef CLSNAME
|
||||||
|
#define CLSNAME TProxyService
|
||||||
|
#endif
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
|
#define STR(s) STR_ARG (s)
|
||||||
|
#define STR_ARG(c) #c
|
||||||
|
#define N_ELEMENTS(arr) (sizeof (arr) / sizeof ((arr)[0]))
|
||||||
|
|
||||||
|
typedef struct _ThreadData ThreadData;
|
||||||
|
|
||||||
|
struct _ThreadData
|
||||||
|
{
|
||||||
|
char *path;
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int is_working;
|
||||||
|
static JavaVM *java_vm;
|
||||||
|
static pthread_t work_thread;
|
||||||
|
static pthread_mutex_t mutex;
|
||||||
|
static pthread_key_t current_jni_env;
|
||||||
|
|
||||||
|
static void native_start_service (JNIEnv *env, jobject thiz, jstring conig_path,
|
||||||
|
jint fd);
|
||||||
|
static void native_stop_service (JNIEnv *env, jobject thiz);
|
||||||
|
static jlongArray native_get_stats (JNIEnv *env, jobject thiz);
|
||||||
|
|
||||||
|
static JNINativeMethod native_methods[] = {
|
||||||
|
{ "TProxyStartService", "(Ljava/lang/String;I)V",
|
||||||
|
(void *)native_start_service },
|
||||||
|
{ "TProxyStopService", "()V", (void *)native_stop_service },
|
||||||
|
{ "TProxyGetStats", "()[J", (void *)native_get_stats },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
detach_current_thread (void *env)
|
||||||
|
{
|
||||||
|
(*java_vm)->DetachCurrentThread (java_vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
jint
|
||||||
|
JNI_OnLoad (JavaVM *vm, void *reserved)
|
||||||
|
{
|
||||||
|
JNIEnv *env = NULL;
|
||||||
|
jclass klass;
|
||||||
|
|
||||||
|
java_vm = vm;
|
||||||
|
if (JNI_OK != (*vm)->GetEnv (vm, (void **)&env, JNI_VERSION_1_4)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
klass = (*env)->FindClass (env, STR (PKGNAME) "/" STR (CLSNAME));
|
||||||
|
(*env)->RegisterNatives (env, klass, native_methods,
|
||||||
|
N_ELEMENTS (native_methods));
|
||||||
|
(*env)->DeleteLocalRef (env, klass);
|
||||||
|
|
||||||
|
pthread_key_create (¤t_jni_env, detach_current_thread);
|
||||||
|
pthread_mutex_init (&mutex, NULL);
|
||||||
|
|
||||||
|
return JNI_VERSION_1_4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
thread_handler (void *data)
|
||||||
|
{
|
||||||
|
ThreadData *tdata = data;
|
||||||
|
|
||||||
|
hev_socks5_tunnel_main (tdata->path, tdata->fd);
|
||||||
|
|
||||||
|
free (tdata->path);
|
||||||
|
free (tdata);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
native_start_service (JNIEnv *env, jobject thiz, jstring config_path, jint fd)
|
||||||
|
{
|
||||||
|
const jbyte *bytes;
|
||||||
|
ThreadData *tdata;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
pthread_mutex_lock (&mutex);
|
||||||
|
|
||||||
|
if (is_working)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
tdata = malloc (sizeof (ThreadData));
|
||||||
|
tdata->fd = fd;
|
||||||
|
|
||||||
|
bytes = (const jbyte *)(*env)->GetStringUTFChars (env, config_path, NULL);
|
||||||
|
tdata->path = strdup ((const char *)bytes);
|
||||||
|
(*env)->ReleaseStringUTFChars (env, config_path, (const char *)bytes);
|
||||||
|
|
||||||
|
res = pthread_create (&work_thread, NULL, thread_handler, tdata);
|
||||||
|
if (res != 0) {
|
||||||
|
free (tdata->path);
|
||||||
|
free (tdata);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_working = 1;
|
||||||
|
exit:
|
||||||
|
pthread_mutex_unlock (&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
native_stop_service (JNIEnv *env, jobject thiz)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock (&mutex);
|
||||||
|
|
||||||
|
if (!is_working)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
hev_socks5_tunnel_quit ();
|
||||||
|
pthread_join (work_thread, NULL);
|
||||||
|
|
||||||
|
is_working = 0;
|
||||||
|
exit:
|
||||||
|
pthread_mutex_unlock (&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static jlongArray
|
||||||
|
native_get_stats (JNIEnv *env, jobject thiz)
|
||||||
|
{
|
||||||
|
size_t tx_packets, rx_packets, tx_bytes, rx_bytes;
|
||||||
|
jlongArray res;
|
||||||
|
jlong array[4];
|
||||||
|
|
||||||
|
hev_socks5_tunnel_stats (&tx_packets, &tx_bytes, &rx_packets, &rx_bytes);
|
||||||
|
array[0] = tx_packets;
|
||||||
|
array[1] = tx_bytes;
|
||||||
|
array[2] = rx_packets;
|
||||||
|
array[3] = rx_bytes;
|
||||||
|
|
||||||
|
res = (*env)->NewLongArray (env, 4);
|
||||||
|
(*env)->SetLongArrayRegion (env, res, 0, 4, array);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ANDROID */
|
||||||
13
app/src/main/cpp/hev-socks5-tunnel/src/hev-jni.h
Normal file
13
app/src/main/cpp/hev-socks5-tunnel/src/hev-jni.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-jni.h
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2019 - 2023 hev
|
||||||
|
Description : Java Native Interface
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_JNI_H__
|
||||||
|
#define __HEV_JNI_H__
|
||||||
|
|
||||||
|
#endif /* __HEV_JNI_H__ */
|
||||||
155
app/src/main/cpp/hev-socks5-tunnel/src/hev-main.c
Normal file
155
app/src/main/cpp/hev-socks5-tunnel/src/hev-main.c
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-main.c
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2019 - 2023 hev
|
||||||
|
Description : Main
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <lwip/init.h>
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
#include <hev-task-system.h>
|
||||||
|
#include <hev-socks5-misc.h>
|
||||||
|
|
||||||
|
#include "hev-utils.h"
|
||||||
|
#include "hev-config.h"
|
||||||
|
#include "hev-config-const.h"
|
||||||
|
#include "hev-logger.h"
|
||||||
|
#include "hev-socks5-logger.h"
|
||||||
|
#include "hev-socks5-tunnel.h"
|
||||||
|
|
||||||
|
#include "hev-main.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_tunnel_main_inner (int tun_fd)
|
||||||
|
{
|
||||||
|
const char *pid_file;
|
||||||
|
const char *log_file;
|
||||||
|
int log_level;
|
||||||
|
int nofile;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
log_file = hev_config_get_misc_log_file ();
|
||||||
|
log_level = hev_config_get_misc_log_level ();
|
||||||
|
|
||||||
|
res = hev_config_get_misc_connect_timeout ();
|
||||||
|
hev_socks5_set_connect_timeout (res);
|
||||||
|
res = hev_config_get_misc_tcp_read_write_timeout ();
|
||||||
|
hev_socks5_set_tcp_timeout (res);
|
||||||
|
res = hev_config_get_misc_udp_read_write_timeout ();
|
||||||
|
hev_socks5_set_udp_timeout (res);
|
||||||
|
|
||||||
|
res = hev_config_get_misc_udp_recv_buffer_size ();
|
||||||
|
hev_socks5_set_udp_recv_buffer_size (res);
|
||||||
|
|
||||||
|
res = hev_logger_init (log_level, log_file);
|
||||||
|
if (res < 0)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
res = hev_socks5_logger_init (log_level, log_file);
|
||||||
|
if (res < 0)
|
||||||
|
return -3;
|
||||||
|
|
||||||
|
nofile = hev_config_get_misc_limit_nofile ();
|
||||||
|
res = set_limit_nofile (nofile);
|
||||||
|
if (res < 0)
|
||||||
|
LOG_I ("set limit nofile");
|
||||||
|
|
||||||
|
pid_file = hev_config_get_misc_pid_file ();
|
||||||
|
if (pid_file)
|
||||||
|
run_as_daemon (pid_file);
|
||||||
|
|
||||||
|
res = hev_task_system_init ();
|
||||||
|
if (res < 0)
|
||||||
|
return -4;
|
||||||
|
|
||||||
|
lwip_init ();
|
||||||
|
|
||||||
|
res = hev_socks5_tunnel_init (tun_fd);
|
||||||
|
if (res < 0)
|
||||||
|
return -5;
|
||||||
|
|
||||||
|
hev_socks5_tunnel_run ();
|
||||||
|
|
||||||
|
hev_socks5_tunnel_fini ();
|
||||||
|
hev_socks5_logger_fini ();
|
||||||
|
hev_logger_fini ();
|
||||||
|
hev_config_fini ();
|
||||||
|
hev_task_system_fini ();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_tunnel_main_from_file (const char *config_path, int tun_fd)
|
||||||
|
{
|
||||||
|
int res = hev_config_init_from_file (config_path);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return hev_socks5_tunnel_main_inner (tun_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_tunnel_main_from_str (const unsigned char *config_str,
|
||||||
|
unsigned int config_len, int tun_fd)
|
||||||
|
{
|
||||||
|
int res = hev_config_init_from_str (config_str, config_len);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return hev_socks5_tunnel_main_inner (tun_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_tunnel_main (const char *config_path, int tun_fd)
|
||||||
|
{
|
||||||
|
return hev_socks5_tunnel_main_from_file (config_path, tun_fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_tunnel_quit (void)
|
||||||
|
{
|
||||||
|
hev_socks5_tunnel_stop ();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef ENABLE_LIBRARY
|
||||||
|
static void
|
||||||
|
show_help (const char *self_path)
|
||||||
|
{
|
||||||
|
printf ("%s CONFIG_PATH\n", self_path);
|
||||||
|
printf ("Version: %u.%u.%u %s\n", MAJOR_VERSION, MINOR_VERSION,
|
||||||
|
MICRO_VERSION, COMMIT_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sigint_handler (int signum)
|
||||||
|
{
|
||||||
|
hev_socks5_tunnel_stop ();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (argc < 2 || strcmp (argv[1], "--version") == 0) {
|
||||||
|
show_help (argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
signal (SIGINT, sigint_handler);
|
||||||
|
|
||||||
|
res = hev_socks5_tunnel_main (argv[1], -1);
|
||||||
|
if (res < 0)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* ENABLE_LIBRARY */
|
||||||
90
app/src/main/cpp/hev-socks5-tunnel/src/hev-main.h
Normal file
90
app/src/main/cpp/hev-socks5-tunnel/src/hev-main.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-main.h
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2019 - 2023 hev
|
||||||
|
Description : Main
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_MAIN_H__
|
||||||
|
#define __HEV_MAIN_H__
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hev_socks5_tunnel_main:
|
||||||
|
* @config_path: config file path
|
||||||
|
* @tun_fd: tunnel file descriptor
|
||||||
|
*
|
||||||
|
* Start and run the socks5 tunnel, this function will blocks until the
|
||||||
|
* hev_socks5_tunnel_quit is called or an error occurs.
|
||||||
|
*
|
||||||
|
* Returns: returns zero on successful, otherwise returns -1.
|
||||||
|
*
|
||||||
|
* Since: 2.4.6
|
||||||
|
*/
|
||||||
|
int hev_socks5_tunnel_main (const char *config_path, int tun_fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hev_socks5_tunnel_main_from_file:
|
||||||
|
* @config_path: config file path
|
||||||
|
* @tun_fd: tunnel file descriptor
|
||||||
|
*
|
||||||
|
* Start and run the socks5 tunnel, this function will blocks until the
|
||||||
|
* hev_socks5_tunnel_quit is called or an error occurs.
|
||||||
|
*
|
||||||
|
* Returns: returns zero on successful, otherwise returns -1.
|
||||||
|
*
|
||||||
|
* Since: 2.6.7
|
||||||
|
*/
|
||||||
|
int hev_socks5_tunnel_main_from_file (const char *config_path, int tun_fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hev_socks5_tunnel_main_from_str:
|
||||||
|
* @config_str: string config
|
||||||
|
* @config_len: the byte length of string config
|
||||||
|
* @tun_fd: tunnel file descriptor
|
||||||
|
*
|
||||||
|
* Start and run the socks5 tunnel, this function will blocks until the
|
||||||
|
* hev_socks5_tunnel_quit is called or an error occurs.
|
||||||
|
*
|
||||||
|
* Returns: returns zero on successful, otherwise returns -1.
|
||||||
|
*
|
||||||
|
* Since: 2.6.7
|
||||||
|
*/
|
||||||
|
int hev_socks5_tunnel_main_from_str (const unsigned char *config_str,
|
||||||
|
unsigned int config_len, int tun_fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hev_socks5_tunnel_quit:
|
||||||
|
*
|
||||||
|
* Stop the socks5 tunnel.
|
||||||
|
*
|
||||||
|
* Since: 2.4.6
|
||||||
|
*/
|
||||||
|
void hev_socks5_tunnel_quit (void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hev_socks5_tunnel_stats:
|
||||||
|
* @tx_packets (out): transmitted packets
|
||||||
|
* @tx_bytes (out): transmitted bytes
|
||||||
|
* @rx_packets (out): received packets
|
||||||
|
* @rx_bytes (out): received bytes
|
||||||
|
*
|
||||||
|
* Retrieve tunnel interface traffic statistics.
|
||||||
|
*
|
||||||
|
* Since: 2.6.5
|
||||||
|
*/
|
||||||
|
void hev_socks5_tunnel_stats (size_t *tx_packets, size_t *tx_bytes,
|
||||||
|
size_t *rx_packets, size_t *rx_bytes);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_MAIN_H__ */
|
||||||
332
app/src/main/cpp/hev-socks5-tunnel/src/hev-mapped-dns.c
Normal file
332
app/src/main/cpp/hev-socks5-tunnel/src/hev-mapped-dns.c
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-mapped-dns.c
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2025 hev
|
||||||
|
Description : Mapped DNS
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include <hev-compiler.h>
|
||||||
|
#include <hev-memory-allocator.h>
|
||||||
|
|
||||||
|
#include "hev-logger.h"
|
||||||
|
|
||||||
|
#include "hev-mapped-dns.h"
|
||||||
|
|
||||||
|
static HevMappedDNS *singleton;
|
||||||
|
|
||||||
|
typedef struct _DNSHdr DNSHdr;
|
||||||
|
|
||||||
|
struct _DNSHdr
|
||||||
|
{
|
||||||
|
uint16_t id;
|
||||||
|
uint16_t fl;
|
||||||
|
uint16_t qd;
|
||||||
|
uint16_t an;
|
||||||
|
uint16_t ns;
|
||||||
|
uint16_t ar;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevMappedDNSNode
|
||||||
|
{
|
||||||
|
HevRBTreeNode tree;
|
||||||
|
HevListNode list;
|
||||||
|
char *name;
|
||||||
|
int idx;
|
||||||
|
};
|
||||||
|
|
||||||
|
HevMappedDNS *
|
||||||
|
hev_mapped_dns_new (int net, int mask, int max)
|
||||||
|
{
|
||||||
|
HevMappedDNS *self;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
self = hev_malloc0 (sizeof (HevMappedDNS) + sizeof (void *) * max);
|
||||||
|
if (!self)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
res = hev_mapped_dns_construct (self, net, mask, max);
|
||||||
|
if (res < 0) {
|
||||||
|
hev_free (self);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_D ("%p mapped dns new", self);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
HevMappedDNS *
|
||||||
|
hev_mapped_dns_get (void)
|
||||||
|
{
|
||||||
|
return singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_mapped_dns_put (HevMappedDNS *self)
|
||||||
|
{
|
||||||
|
singleton = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HevMappedDNSNode *
|
||||||
|
hev_mapped_dns_node_alloc (const char *name)
|
||||||
|
{
|
||||||
|
HevMappedDNSNode *node;
|
||||||
|
|
||||||
|
node = hev_malloc0 (sizeof (HevMappedDNSNode));
|
||||||
|
if (!node)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
node->name = strdup (name);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hev_mapped_dns_node_free (HevMappedDNSNode *node)
|
||||||
|
{
|
||||||
|
free (node->name);
|
||||||
|
hev_free (node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_mapped_dns_find (HevMappedDNS *self, const char *name)
|
||||||
|
{
|
||||||
|
HevRBTreeNode **new = &self->tree.root, *parent = NULL;
|
||||||
|
HevMappedDNSNode *node;
|
||||||
|
int idx = self->use;
|
||||||
|
|
||||||
|
while (*new) {
|
||||||
|
int res;
|
||||||
|
|
||||||
|
node = container_of (*new, HevMappedDNSNode, tree);
|
||||||
|
res = strcmp (node->name, name);
|
||||||
|
parent = *new;
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
new = &((*new)->left);
|
||||||
|
} else if (res > 0) {
|
||||||
|
new = &((*new)->right);
|
||||||
|
} else {
|
||||||
|
hev_list_del (&self->list, &node->list);
|
||||||
|
hev_list_add_tail (&self->list, &node->list);
|
||||||
|
return node->idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node = hev_mapped_dns_node_alloc (name);
|
||||||
|
if (!node)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
hev_rbtree_node_link (&node->tree, parent, new);
|
||||||
|
hev_rbtree_insert_color (&self->tree, &node->tree);
|
||||||
|
hev_list_add_tail (&self->list, &node->list);
|
||||||
|
|
||||||
|
if (self->use < self->max) {
|
||||||
|
self->use++;
|
||||||
|
} else {
|
||||||
|
HevMappedDNSNode *nf;
|
||||||
|
HevListNode *nl;
|
||||||
|
|
||||||
|
nl = hev_list_first (&self->list);
|
||||||
|
nf = container_of (nl, HevMappedDNSNode, list);
|
||||||
|
|
||||||
|
idx = nf->idx;
|
||||||
|
hev_rbtree_erase (&self->tree, &nf->tree);
|
||||||
|
hev_list_del (&self->list, &nf->list);
|
||||||
|
hev_mapped_dns_node_free (nf);
|
||||||
|
}
|
||||||
|
|
||||||
|
self->records[idx] = node;
|
||||||
|
node->idx = idx;
|
||||||
|
|
||||||
|
return node->idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint16_t
|
||||||
|
read_u16 (const uint8_t *p)
|
||||||
|
{
|
||||||
|
return ((uint16_t)p[0] << 8) | p[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
write_u16 (uint8_t *p, uint16_t v)
|
||||||
|
{
|
||||||
|
p[0] = v >> 8;
|
||||||
|
p[1] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
write_u32 (uint8_t *p, uint32_t v)
|
||||||
|
{
|
||||||
|
p[0] = v >> 24;
|
||||||
|
p[1] = v >> 16;
|
||||||
|
p[2] = v >> 8;
|
||||||
|
p[3] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_mapped_dns_handle (HevMappedDNS *self, void *req, int qlen, void *res,
|
||||||
|
int slen)
|
||||||
|
{
|
||||||
|
DNSHdr *qhdr = req;
|
||||||
|
DNSHdr *shdr = res;
|
||||||
|
uint8_t *rb = req;
|
||||||
|
uint8_t *sb = res;
|
||||||
|
int ips[32];
|
||||||
|
int ipo[32];
|
||||||
|
int ipn = 0;
|
||||||
|
int off;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (slen < qlen)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memcpy (res, req, qlen);
|
||||||
|
qhdr->qd = ntohs (qhdr->qd);
|
||||||
|
shdr->fl = ntohs (shdr->fl);
|
||||||
|
shdr->ns = 0;
|
||||||
|
shdr->an = 0;
|
||||||
|
shdr->ar = 0;
|
||||||
|
|
||||||
|
if (qhdr->qd > 32)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
off = sizeof (DNSHdr);
|
||||||
|
for (i = 0; i < qhdr->qd; i++) {
|
||||||
|
ipo[ipn] = off;
|
||||||
|
|
||||||
|
while (rb[off]) {
|
||||||
|
int poff = off;
|
||||||
|
|
||||||
|
off += 1 + rb[off];
|
||||||
|
if (off >= qlen)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
rb[poff] = '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
off++;
|
||||||
|
if ((off + 3) >= qlen)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((read_u16 (&rb[off + 0]) == 1) && (read_u16 (&rb[off + 2]) == 1)) {
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
idx = hev_mapped_dns_find (self, (char *)&rb[ipo[ipn] + 1]);
|
||||||
|
if (idx >= 0) {
|
||||||
|
ips[ipn] = self->net | idx;
|
||||||
|
ipn++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
off += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ipn; i++) {
|
||||||
|
if ((off + 15) >= slen)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
sb[off + 0] = 0xc0;
|
||||||
|
sb[off + 1] = ipo[i];
|
||||||
|
write_u16 (&sb[off + 2], 1);
|
||||||
|
write_u16 (&sb[off + 4], 1);
|
||||||
|
write_u32 (&sb[off + 6], 1);
|
||||||
|
write_u16 (&sb[off + 10], 4);
|
||||||
|
write_u32 (&sb[off + 12], ips[i]);
|
||||||
|
|
||||||
|
off += 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
shdr->fl = htons (shdr->fl | 0x8000 | ((shdr->fl & 0x100) >> 1));
|
||||||
|
shdr->an = htons (ipn);
|
||||||
|
|
||||||
|
return off;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
hev_mapped_dns_lookup (HevMappedDNS *self, int ip)
|
||||||
|
{
|
||||||
|
HevMappedDNSNode *node;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
idx = ip & ~self->mask;
|
||||||
|
if (idx >= self->max)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
node = self->records[idx];
|
||||||
|
if (!node)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
hev_list_del (&self->list, &node->list);
|
||||||
|
hev_list_add_tail (&self->list, &node->list);
|
||||||
|
|
||||||
|
return node->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_mapped_dns_construct (HevMappedDNS *self, int net, int mask, int max)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = hev_object_construct (&self->base);
|
||||||
|
if (res < 0)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
LOG_D ("%p mapped dns construct", self);
|
||||||
|
|
||||||
|
HEV_OBJECT (self)->klass = HEV_MAPPED_DNS_TYPE;
|
||||||
|
|
||||||
|
if (max > ~mask)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
self->max = max;
|
||||||
|
self->net = net;
|
||||||
|
self->mask = mask;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hev_mapped_dns_destruct (HevObject *base)
|
||||||
|
{
|
||||||
|
HevMappedDNS *self = HEV_MAPPED_DNS (base);
|
||||||
|
HevListNode *n;
|
||||||
|
|
||||||
|
LOG_D ("%p mapped dns destruct", self);
|
||||||
|
|
||||||
|
n = hev_list_first (&self->list);
|
||||||
|
while (n) {
|
||||||
|
HevMappedDNSNode *t;
|
||||||
|
|
||||||
|
t = container_of (n, HevMappedDNSNode, list);
|
||||||
|
n = hev_list_node_next (n);
|
||||||
|
hev_mapped_dns_node_free (t);
|
||||||
|
}
|
||||||
|
|
||||||
|
HEV_OBJECT_TYPE->destruct (base);
|
||||||
|
hev_free (base);
|
||||||
|
}
|
||||||
|
|
||||||
|
HevObjectClass *
|
||||||
|
hev_mapped_dns_class (void)
|
||||||
|
{
|
||||||
|
static HevMappedDNSClass klass;
|
||||||
|
HevMappedDNSClass *kptr = &klass;
|
||||||
|
HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr);
|
||||||
|
|
||||||
|
if (!okptr->name) {
|
||||||
|
memcpy (kptr, HEV_OBJECT_TYPE, sizeof (HevObjectClass));
|
||||||
|
|
||||||
|
okptr->name = "HevMappedDNS";
|
||||||
|
okptr->destruct = hev_mapped_dns_destruct;
|
||||||
|
}
|
||||||
|
|
||||||
|
return okptr;
|
||||||
|
}
|
||||||
65
app/src/main/cpp/hev-socks5-tunnel/src/hev-mapped-dns.h
Normal file
65
app/src/main/cpp/hev-socks5-tunnel/src/hev-mapped-dns.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-mapped-dns.h
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2025 hev
|
||||||
|
Description : Mapped DNS
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_MAPPED_DNS_H__
|
||||||
|
#define __HEV_MAPPED_DNS_H__
|
||||||
|
|
||||||
|
#include <hev-list.h>
|
||||||
|
#include <hev-rbtree.h>
|
||||||
|
#include <hev-object.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HEV_MAPPED_DNS(p) ((HevMappedDNS *)p)
|
||||||
|
#define HEV_MAPPED_DNS_CLASS(p) ((HevMappedDNSClass *)p)
|
||||||
|
#define HEV_MAPPED_DNS_TYPE (hev_mapped_dns_class ())
|
||||||
|
|
||||||
|
typedef struct _HevMappedDNS HevMappedDNS;
|
||||||
|
typedef struct _HevMappedDNSClass HevMappedDNSClass;
|
||||||
|
typedef struct _HevMappedDNSNode HevMappedDNSNode;
|
||||||
|
|
||||||
|
struct _HevMappedDNS
|
||||||
|
{
|
||||||
|
HevObject base;
|
||||||
|
|
||||||
|
int use;
|
||||||
|
int max;
|
||||||
|
int net;
|
||||||
|
int mask;
|
||||||
|
|
||||||
|
HevList list;
|
||||||
|
HevRBTree tree;
|
||||||
|
HevMappedDNSNode *records[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevMappedDNSClass
|
||||||
|
{
|
||||||
|
HevObjectClass base;
|
||||||
|
};
|
||||||
|
|
||||||
|
HevObjectClass *hev_mapped_dns_class (void);
|
||||||
|
|
||||||
|
int hev_mapped_dns_construct (HevMappedDNS *self, int net, int mask, int max);
|
||||||
|
|
||||||
|
HevMappedDNS *hev_mapped_dns_new (int net, int mask, int max);
|
||||||
|
|
||||||
|
HevMappedDNS *hev_mapped_dns_get (void);
|
||||||
|
void hev_mapped_dns_put (HevMappedDNS *self);
|
||||||
|
|
||||||
|
int hev_mapped_dns_handle (HevMappedDNS *self, void *req, int qlen, void *res,
|
||||||
|
int slen);
|
||||||
|
const char *hev_mapped_dns_lookup (HevMappedDNS *self, int ip);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_MAPPED_DNS_H__ */
|
||||||
359
app/src/main/cpp/hev-socks5-tunnel/src/hev-socks5-session-tcp.c
Normal file
359
app/src/main/cpp/hev-socks5-tunnel/src/hev-socks5-session-tcp.c
Normal file
@ -0,0 +1,359 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-session-tcp.c
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2017 - 2023 hev
|
||||||
|
Description : Socks5 Session TCP
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <lwip/tcp.h>
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
#include <hev-task-io.h>
|
||||||
|
#include <hev-task-io-socket.h>
|
||||||
|
#include <hev-task-mutex.h>
|
||||||
|
#include <hev-memory-allocator.h>
|
||||||
|
#include <hev-socks5-misc.h>
|
||||||
|
|
||||||
|
#include "hev-utils.h"
|
||||||
|
#include "hev-config.h"
|
||||||
|
#include "hev-logger.h"
|
||||||
|
#include "hev-config-const.h"
|
||||||
|
#include "hev-socks5-tunnel.h"
|
||||||
|
|
||||||
|
#include "hev-socks5-session-tcp.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
task_io_yielder (HevTaskYieldType type, void *data)
|
||||||
|
{
|
||||||
|
HevSocks5Session *self = data;
|
||||||
|
HevListNode *node;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = hev_socks5_task_io_yielder (type, data);
|
||||||
|
node = hev_socks5_session_get_node (self);
|
||||||
|
hev_socks5_tunnel_update_session (node);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
tcp_splice_f (HevSocks5SessionTCP *self)
|
||||||
|
{
|
||||||
|
struct iovec iov[64];
|
||||||
|
struct pbuf *p;
|
||||||
|
int iovc = 0;
|
||||||
|
int res = 1;
|
||||||
|
|
||||||
|
if (self->queue) {
|
||||||
|
for (p = self->queue; p && (iovc < 64); p = p->next, iovc++) {
|
||||||
|
iov[iovc].iov_base = p->payload;
|
||||||
|
iov[iovc].iov_len = p->len;
|
||||||
|
}
|
||||||
|
} else if (self->pcb_eof) {
|
||||||
|
res = -1;
|
||||||
|
} else {
|
||||||
|
res = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iovc) {
|
||||||
|
ssize_t s = writev (HEV_SOCKS5 (self)->fd, iov, iovc);
|
||||||
|
if (0 >= s) {
|
||||||
|
if ((0 > s) && (EAGAIN == errno))
|
||||||
|
res = 0;
|
||||||
|
else
|
||||||
|
res = -1;
|
||||||
|
} else {
|
||||||
|
hev_task_mutex_lock (self->mutex);
|
||||||
|
self->queue = pbuf_free_header (self->queue, s);
|
||||||
|
if (self->pcb)
|
||||||
|
tcp_recved (self->pcb, s);
|
||||||
|
hev_task_mutex_unlock (self->mutex);
|
||||||
|
res = 1;
|
||||||
|
}
|
||||||
|
} else if (res < 0) {
|
||||||
|
shutdown (HEV_SOCKS5 (self)->fd, SHUT_WR);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
tcp_splice_b (HevSocks5SessionTCP *self)
|
||||||
|
{
|
||||||
|
struct iovec iov[2];
|
||||||
|
err_t err = ERR_OK;
|
||||||
|
int res = 1, iovc;
|
||||||
|
|
||||||
|
iovc = hev_ring_buffer_writing (self->buffer, iov);
|
||||||
|
if (iovc) {
|
||||||
|
ssize_t s = readv (HEV_SOCKS5 (self)->fd, iov, iovc);
|
||||||
|
if (0 >= s) {
|
||||||
|
if ((0 > s) && (EAGAIN == errno))
|
||||||
|
res = 0;
|
||||||
|
else
|
||||||
|
res = -1;
|
||||||
|
} else {
|
||||||
|
hev_ring_buffer_write_finish (self->buffer, s);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hev_task_mutex_lock (self->mutex);
|
||||||
|
if (self->pcb) {
|
||||||
|
iovc = hev_ring_buffer_reading (self->buffer, iov);
|
||||||
|
if (iovc) {
|
||||||
|
ssize_t s = 0;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < iovc; i++) {
|
||||||
|
void *ptr = iov[i].iov_base;
|
||||||
|
size_t len = iov[i].iov_len;
|
||||||
|
err |= tcp_write (self->pcb, ptr, len, 0);
|
||||||
|
s += len;
|
||||||
|
}
|
||||||
|
hev_ring_buffer_read_finish (self->buffer, s);
|
||||||
|
err |= tcp_output (self->pcb);
|
||||||
|
res = 1;
|
||||||
|
} else if (res < 0) {
|
||||||
|
tcp_shutdown (self->pcb, 0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hev_task_mutex_unlock (self->mutex);
|
||||||
|
if (!self->pcb || (err != ERR_OK))
|
||||||
|
res = -1;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static err_t
|
||||||
|
tcp_recv_handler (void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
|
||||||
|
{
|
||||||
|
HevSocks5SessionTCP *self = arg;
|
||||||
|
|
||||||
|
if (p) {
|
||||||
|
if (!self->queue) {
|
||||||
|
self->queue = p;
|
||||||
|
} else {
|
||||||
|
if (self->queue->tot_len > TCP_WND_MAX (pcb))
|
||||||
|
return ERR_WOULDBLOCK;
|
||||||
|
pbuf_cat (self->queue, p);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self->pcb_eof = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
hev_task_wakeup (self->data.task);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static err_t
|
||||||
|
tcp_sent_handler (void *arg, struct tcp_pcb *pcb, u16_t len)
|
||||||
|
{
|
||||||
|
HevSocks5SessionTCP *self = arg;
|
||||||
|
|
||||||
|
hev_ring_buffer_read_release (self->buffer, len);
|
||||||
|
hev_task_wakeup (self->data.task);
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
tcp_err_handler (void *arg, err_t err)
|
||||||
|
{
|
||||||
|
HevSocks5SessionTCP *self = arg;
|
||||||
|
|
||||||
|
self->pcb = NULL;
|
||||||
|
hev_socks5_session_terminate (HEV_SOCKS5_SESSION (self));
|
||||||
|
}
|
||||||
|
|
||||||
|
HevSocks5SessionTCP *
|
||||||
|
hev_socks5_session_tcp_new (struct tcp_pcb *pcb, HevTaskMutex *mutex)
|
||||||
|
{
|
||||||
|
HevSocks5SessionTCP *self;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
self = hev_malloc0 (sizeof (HevSocks5SessionTCP));
|
||||||
|
if (!self)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
res = hev_socks5_session_tcp_construct (self, pcb, mutex);
|
||||||
|
if (res < 0) {
|
||||||
|
hev_free (self);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 session tcp new", self);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hev_socks5_session_tcp_splice (HevSocks5Session *base)
|
||||||
|
{
|
||||||
|
HevSocks5SessionTCP *self = HEV_SOCKS5_SESSION_TCP (base);
|
||||||
|
int tcp_buffer_size;
|
||||||
|
int res_f = 1;
|
||||||
|
int res_b = 1;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 session tcp splice", self);
|
||||||
|
|
||||||
|
if (!self->pcb)
|
||||||
|
return;
|
||||||
|
|
||||||
|
tcp_buffer_size = hev_config_get_misc_tcp_buffer_size ();
|
||||||
|
self->buffer = hev_ring_buffer_alloca (tcp_buffer_size);
|
||||||
|
if (!self->buffer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
HevTaskYieldType type;
|
||||||
|
|
||||||
|
if (res_f >= 0)
|
||||||
|
res_f = tcp_splice_f (self);
|
||||||
|
if (res_b >= 0)
|
||||||
|
res_b = tcp_splice_b (self);
|
||||||
|
|
||||||
|
if (res_f > 0 || res_b > 0)
|
||||||
|
type = HEV_TASK_YIELD;
|
||||||
|
else if ((res_f & res_b) == 0)
|
||||||
|
type = HEV_TASK_WAITIO;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (task_io_yielder (type, base) < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (self->pcb) {
|
||||||
|
if (hev_ring_buffer_get_use_size (self->buffer) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (task_io_yielder (HEV_TASK_WAITIO, base) < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static HevTask *
|
||||||
|
hev_socks5_session_tcp_get_task (HevSocks5Session *base)
|
||||||
|
{
|
||||||
|
HevSocks5SessionTCP *self = HEV_SOCKS5_SESSION_TCP (base);
|
||||||
|
|
||||||
|
return self->data.task;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hev_socks5_session_tcp_set_task (HevSocks5Session *base, HevTask *task)
|
||||||
|
{
|
||||||
|
HevSocks5SessionTCP *self = HEV_SOCKS5_SESSION_TCP (base);
|
||||||
|
|
||||||
|
self->data.task = task;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HevListNode *
|
||||||
|
hev_socks5_session_tcp_get_node (HevSocks5Session *base)
|
||||||
|
{
|
||||||
|
HevSocks5SessionTCP *self = HEV_SOCKS5_SESSION_TCP (base);
|
||||||
|
|
||||||
|
return &self->data.node;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_session_tcp_construct (HevSocks5SessionTCP *self,
|
||||||
|
struct tcp_pcb *pcb, HevTaskMutex *mutex)
|
||||||
|
{
|
||||||
|
HevSocks5Addr addr;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = hev_socks5_addr_from_lwip (&addr, &pcb->local_ip, pcb->local_port);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
res = hev_socks5_client_tcp_construct (&self->base, &addr);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 session tcp construct", self);
|
||||||
|
|
||||||
|
HEV_OBJECT (self)->klass = HEV_SOCKS5_SESSION_TCP_TYPE;
|
||||||
|
|
||||||
|
tcp_arg (pcb, self);
|
||||||
|
tcp_recv (pcb, tcp_recv_handler);
|
||||||
|
tcp_sent (pcb, tcp_sent_handler);
|
||||||
|
tcp_err (pcb, tcp_err_handler);
|
||||||
|
|
||||||
|
self->pcb = pcb;
|
||||||
|
self->mutex = mutex;
|
||||||
|
self->data.self = self;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_session_tcp_destruct (HevObject *base)
|
||||||
|
{
|
||||||
|
HevSocks5SessionTCP *self = HEV_SOCKS5_SESSION_TCP (base);
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 session tcp destruct", self);
|
||||||
|
|
||||||
|
hev_task_mutex_lock (self->mutex);
|
||||||
|
if (self->pcb) {
|
||||||
|
tcp_recv (self->pcb, NULL);
|
||||||
|
tcp_sent (self->pcb, NULL);
|
||||||
|
tcp_err (self->pcb, NULL);
|
||||||
|
tcp_abort (self->pcb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->queue)
|
||||||
|
pbuf_free (self->queue);
|
||||||
|
hev_task_mutex_unlock (self->mutex);
|
||||||
|
|
||||||
|
HEV_SOCKS5_CLIENT_TCP_TYPE->destruct (base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
hev_socks5_session_tcp_iface (HevObject *base, void *type)
|
||||||
|
{
|
||||||
|
if (type == HEV_SOCKS5_SESSION_TYPE) {
|
||||||
|
HevSocks5SessionTCPClass *klass = HEV_OBJECT_GET_CLASS (base);
|
||||||
|
return &klass->session;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HEV_SOCKS5_CLIENT_TCP_TYPE->iface (base, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
HevObjectClass *
|
||||||
|
hev_socks5_session_tcp_class (void)
|
||||||
|
{
|
||||||
|
static HevSocks5SessionTCPClass klass;
|
||||||
|
HevSocks5SessionTCPClass *kptr = &klass;
|
||||||
|
HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr);
|
||||||
|
|
||||||
|
if (!okptr->name) {
|
||||||
|
HevSocks5Class *skptr;
|
||||||
|
HevSocks5SessionIface *siptr;
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
ptr = HEV_SOCKS5_CLIENT_TCP_TYPE;
|
||||||
|
memcpy (kptr, ptr, sizeof (HevSocks5ClientTCPClass));
|
||||||
|
|
||||||
|
okptr->name = "HevSocks5SessionTCP";
|
||||||
|
okptr->destruct = hev_socks5_session_tcp_destruct;
|
||||||
|
okptr->iface = hev_socks5_session_tcp_iface;
|
||||||
|
|
||||||
|
skptr = HEV_SOCKS5_CLASS (kptr);
|
||||||
|
skptr->binder = hev_socks5_session_bind;
|
||||||
|
|
||||||
|
siptr = &kptr->session;
|
||||||
|
siptr->splicer = hev_socks5_session_tcp_splice;
|
||||||
|
siptr->get_task = hev_socks5_session_tcp_get_task;
|
||||||
|
siptr->set_task = hev_socks5_session_tcp_set_task;
|
||||||
|
siptr->get_node = hev_socks5_session_tcp_get_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return okptr;
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-session-tcp.h
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2017 - 2023 hev
|
||||||
|
Description : Socks5 Session TCP
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_SESSION_TCP_H__
|
||||||
|
#define __HEV_SOCKS5_SESSION_TCP_H__
|
||||||
|
|
||||||
|
#include <hev-ring-buffer.h>
|
||||||
|
#include <hev-socks5-client-tcp.h>
|
||||||
|
|
||||||
|
#include "hev-socks5-session.h"
|
||||||
|
|
||||||
|
#define HEV_SOCKS5_SESSION_TCP(p) ((HevSocks5SessionTCP *)p)
|
||||||
|
#define HEV_SOCKS5_SESSION_TCP_CLASS(p) ((HevSocks5SessionTCPClass *)p)
|
||||||
|
#define HEV_SOCKS5_SESSION_TCP_TYPE (hev_socks5_session_tcp_class ())
|
||||||
|
|
||||||
|
typedef struct _HevSocks5SessionTCP HevSocks5SessionTCP;
|
||||||
|
typedef struct _HevSocks5SessionTCPClass HevSocks5SessionTCPClass;
|
||||||
|
|
||||||
|
struct _HevSocks5SessionTCP
|
||||||
|
{
|
||||||
|
HevSocks5ClientTCP base;
|
||||||
|
|
||||||
|
HevSocks5SessionData data;
|
||||||
|
|
||||||
|
struct pbuf *queue;
|
||||||
|
struct tcp_pcb *pcb;
|
||||||
|
HevTaskMutex *mutex;
|
||||||
|
HevRingBuffer *buffer;
|
||||||
|
int pcb_eof;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5SessionTCPClass
|
||||||
|
{
|
||||||
|
HevSocks5ClientTCPClass base;
|
||||||
|
|
||||||
|
HevSocks5SessionIface session;
|
||||||
|
};
|
||||||
|
|
||||||
|
HevObjectClass *hev_socks5_session_tcp_class (void);
|
||||||
|
|
||||||
|
int hev_socks5_session_tcp_construct (HevSocks5SessionTCP *self,
|
||||||
|
struct tcp_pcb *pcb, HevTaskMutex *mutex);
|
||||||
|
|
||||||
|
HevSocks5SessionTCP *hev_socks5_session_tcp_new (struct tcp_pcb *pcb,
|
||||||
|
HevTaskMutex *mutex);
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_SESSION_TCP_H__ */
|
||||||
425
app/src/main/cpp/hev-socks5-tunnel/src/hev-socks5-session-udp.c
Normal file
425
app/src/main/cpp/hev-socks5-tunnel/src/hev-socks5-session-udp.c
Normal file
@ -0,0 +1,425 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-session-udp.c
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2017 - 2023 hev
|
||||||
|
Description : Socks5 Session UDP
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <lwip/udp.h>
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
#include <hev-task-io.h>
|
||||||
|
#include <hev-task-io-socket.h>
|
||||||
|
#include <hev-task-mutex.h>
|
||||||
|
#include <hev-memory-allocator.h>
|
||||||
|
#include <hev-socks5-udp.h>
|
||||||
|
#include <hev-socks5-misc.h>
|
||||||
|
|
||||||
|
#include "hev-utils.h"
|
||||||
|
#include "hev-config.h"
|
||||||
|
#include "hev-logger.h"
|
||||||
|
#include "hev-compiler.h"
|
||||||
|
#include "hev-config-const.h"
|
||||||
|
#include "hev-socks5-tunnel.h"
|
||||||
|
|
||||||
|
#include "hev-socks5-session-udp.h"
|
||||||
|
|
||||||
|
typedef struct _HevSocks5UDPFrame HevSocks5UDPFrame;
|
||||||
|
|
||||||
|
struct _HevSocks5UDPFrame
|
||||||
|
{
|
||||||
|
HevListNode node;
|
||||||
|
HevSocks5Addr addr;
|
||||||
|
struct pbuf *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
task_io_yielder (HevTaskYieldType type, void *data)
|
||||||
|
{
|
||||||
|
HevSocks5 *self = data;
|
||||||
|
HevListNode *node;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (self->type == HEV_SOCKS5_TYPE_UDP_IN_UDP) {
|
||||||
|
ssize_t res;
|
||||||
|
char buf;
|
||||||
|
|
||||||
|
res = recv (self->fd, &buf, sizeof (buf), 0);
|
||||||
|
if ((res == 0) || ((res < 0) && (errno != EAGAIN))) {
|
||||||
|
hev_socks5_set_timeout (self, 0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_socks5_task_io_yielder (type, data);
|
||||||
|
node = hev_socks5_session_get_node (HEV_SOCKS5_SESSION (self));
|
||||||
|
hev_socks5_tunnel_update_session (node);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_session_udp_fwd_f (HevSocks5SessionUDP *self, unsigned int num)
|
||||||
|
{
|
||||||
|
HevSocks5UDPMsg msgv[num];
|
||||||
|
HevSocks5UDPFrame *frame;
|
||||||
|
HevListNode *node;
|
||||||
|
struct pbuf *buf;
|
||||||
|
int i, res;
|
||||||
|
|
||||||
|
res = self->frames;
|
||||||
|
if (res <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
res = (res > num) ? num : res;
|
||||||
|
node = hev_list_first (&self->frame_list);
|
||||||
|
for (i = 0; i < res; i++) {
|
||||||
|
frame = container_of (node, HevSocks5UDPFrame, node);
|
||||||
|
node = hev_list_node_next (node);
|
||||||
|
buf = frame->data;
|
||||||
|
|
||||||
|
msgv[i].buf = buf->payload;
|
||||||
|
msgv[i].len = buf->len;
|
||||||
|
msgv[i].addr = &frame->addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_socks5_udp_sendmmsg (HEV_SOCKS5_UDP (self), msgv, res);
|
||||||
|
if (res <= 0) {
|
||||||
|
LOG_D ("%p socks5 session udp fwd f send", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < res; i++) {
|
||||||
|
node = hev_list_first (&self->frame_list);
|
||||||
|
frame = container_of (node, HevSocks5UDPFrame, node);
|
||||||
|
buf = frame->data;
|
||||||
|
|
||||||
|
hev_list_del (&self->frame_list, node);
|
||||||
|
hev_free (frame);
|
||||||
|
pbuf_free (buf);
|
||||||
|
self->frames--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_session_udp_fwd_b (HevSocks5SessionUDP *self, unsigned int num)
|
||||||
|
{
|
||||||
|
char buf[UDP_BUF_SIZE * num];
|
||||||
|
HevSocks5UDPMsg msgv[num];
|
||||||
|
int i, res;
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
msgv[i].buf = buf + UDP_BUF_SIZE * i;
|
||||||
|
msgv[i].len = UDP_BUF_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_socks5_udp_recvmmsg (HEV_SOCKS5_UDP (self), msgv, num, 1);
|
||||||
|
if (res <= 0) {
|
||||||
|
if (res == -1 && errno == EAGAIN)
|
||||||
|
return 0;
|
||||||
|
LOG_D ("%p socks5 session udp fwd b recv", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < res; i++) {
|
||||||
|
ip_addr_t saddr;
|
||||||
|
struct pbuf *b;
|
||||||
|
uint16_t port;
|
||||||
|
err_t err;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (self->addr && self->port) {
|
||||||
|
ip_2_ip4 (&saddr)->addr = self->addr;
|
||||||
|
port = self->port;
|
||||||
|
} else {
|
||||||
|
ret = hev_socks5_addr_into_lwip (msgv[i].addr, &saddr, &port);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_D ("%p socks5 session udp fwd b addr", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b = pbuf_alloc_reference (msgv[i].buf, msgv[i].len, PBUF_REF);
|
||||||
|
if (!b) {
|
||||||
|
LOG_D ("%p socks5 session udp fwd b buf", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
hev_task_mutex_lock (self->mutex);
|
||||||
|
err = udp_sendfrom (self->pcb, b, &saddr, port);
|
||||||
|
hev_task_mutex_unlock (self->mutex);
|
||||||
|
|
||||||
|
pbuf_free (b);
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
LOG_D ("%p socks5 session udp fwd b send", self);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
udp_recv_handler (void *arg, struct udp_pcb *pcb, struct pbuf *p,
|
||||||
|
const ip_addr_t *addr, u16_t port)
|
||||||
|
{
|
||||||
|
HevSocks5SessionUDP *self = arg;
|
||||||
|
HevSocks5UDPFrame *frame;
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
|
hev_socks5_session_terminate (HEV_SOCKS5_SESSION (self));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->frames > UDP_POOL_SIZE) {
|
||||||
|
pbuf_free (p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame = hev_malloc (sizeof (HevSocks5UDPFrame));
|
||||||
|
if (!frame) {
|
||||||
|
pbuf_free (p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame->data = p;
|
||||||
|
memset (&frame->node, 0, sizeof (frame->node));
|
||||||
|
hev_socks5_addr_from_lwip (&frame->addr, &pcb->local_ip, pcb->local_port);
|
||||||
|
|
||||||
|
if (frame->addr.atype == HEV_SOCKS5_ADDR_TYPE_NAME) {
|
||||||
|
self->addr = ip_2_ip4 (&pcb->local_ip)->addr;
|
||||||
|
self->port = pcb->local_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->frames++;
|
||||||
|
hev_list_add_tail (&self->frame_list, &frame->node);
|
||||||
|
hev_task_wakeup (self->data.task);
|
||||||
|
}
|
||||||
|
|
||||||
|
HevSocks5SessionUDP *
|
||||||
|
hev_socks5_session_udp_new (struct udp_pcb *pcb, HevTaskMutex *mutex)
|
||||||
|
{
|
||||||
|
HevSocks5SessionUDP *self;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
self = hev_malloc0 (sizeof (HevSocks5SessionUDP));
|
||||||
|
if (!self)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
res = hev_socks5_session_udp_construct (self, pcb, mutex);
|
||||||
|
if (res < 0) {
|
||||||
|
hev_free (self);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 session udp new", self);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t
|
||||||
|
hev_socks5_addr_get_port (const HevSocks5Addr *addr)
|
||||||
|
{
|
||||||
|
uint16_t port = 0;
|
||||||
|
|
||||||
|
switch (addr->atype) {
|
||||||
|
case HEV_SOCKS5_ADDR_TYPE_IPV4:
|
||||||
|
port = addr->ipv4.port;
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_ADDR_TYPE_IPV6:
|
||||||
|
port = addr->ipv6.port;
|
||||||
|
break;
|
||||||
|
case HEV_SOCKS5_ADDR_TYPE_NAME:
|
||||||
|
memcpy (&port, addr->domain.addr + addr->domain.len, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
hev_socks5_session_udp_set_upstream_addr (HevSocks5Client *base,
|
||||||
|
HevSocks5Addr *addr)
|
||||||
|
{
|
||||||
|
HevConfigServer *srv = hev_config_get_socks5_server ();
|
||||||
|
HevSocks5ClientClass *ckptr;
|
||||||
|
|
||||||
|
if (srv->udp_in_udp && srv->udp_addr[0]) {
|
||||||
|
uint16_t port = hev_socks5_addr_get_port (addr);
|
||||||
|
hev_socks5_addr_from_name (addr, srv->udp_addr, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
ckptr = HEV_SOCKS5_CLIENT_CLASS (HEV_SOCKS5_CLIENT_UDP_TYPE);
|
||||||
|
return ckptr->set_upstream_addr (base, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hev_socks5_session_udp_splice (HevSocks5Session *base)
|
||||||
|
{
|
||||||
|
HevSocks5SessionUDP *self = HEV_SOCKS5_SESSION_UDP (base);
|
||||||
|
HevTask *task = hev_task_self ();
|
||||||
|
int res_f = 1, res_b = 1;
|
||||||
|
int num;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 session udp splice", self);
|
||||||
|
|
||||||
|
num = hev_config_get_misc_udp_copy_buffer_nums ();
|
||||||
|
fd = hev_socks5_udp_get_fd (HEV_SOCKS5_UDP (self));
|
||||||
|
if (hev_task_mod_fd (task, fd, POLLIN | POLLOUT) < 0)
|
||||||
|
hev_task_add_fd (task, fd, POLLIN | POLLOUT);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
HevTaskYieldType type;
|
||||||
|
|
||||||
|
if (res_f >= 0)
|
||||||
|
res_f = hev_socks5_session_udp_fwd_f (self, num);
|
||||||
|
if (res_b >= 0)
|
||||||
|
res_b = hev_socks5_session_udp_fwd_b (self, num);
|
||||||
|
|
||||||
|
if (res_f > 0 || res_b > 0)
|
||||||
|
type = HEV_TASK_YIELD;
|
||||||
|
else if ((res_f & res_b) == 0)
|
||||||
|
type = HEV_TASK_WAITIO;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (task_io_yielder (type, self))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static HevTask *
|
||||||
|
hev_socks5_session_udp_get_task (HevSocks5Session *base)
|
||||||
|
{
|
||||||
|
HevSocks5SessionUDP *self = HEV_SOCKS5_SESSION_UDP (base);
|
||||||
|
|
||||||
|
return self->data.task;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hev_socks5_session_udp_set_task (HevSocks5Session *base, HevTask *task)
|
||||||
|
{
|
||||||
|
HevSocks5SessionUDP *self = HEV_SOCKS5_SESSION_UDP (base);
|
||||||
|
|
||||||
|
self->data.task = task;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HevListNode *
|
||||||
|
hev_socks5_session_udp_get_node (HevSocks5Session *base)
|
||||||
|
{
|
||||||
|
HevSocks5SessionUDP *self = HEV_SOCKS5_SESSION_UDP (base);
|
||||||
|
|
||||||
|
return &self->data.node;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_session_udp_construct (HevSocks5SessionUDP *self,
|
||||||
|
struct udp_pcb *pcb, HevTaskMutex *mutex)
|
||||||
|
{
|
||||||
|
HevConfigServer *srv = hev_config_get_socks5_server ();
|
||||||
|
int type;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (srv->udp_in_udp)
|
||||||
|
type = HEV_SOCKS5_TYPE_UDP_IN_UDP;
|
||||||
|
else
|
||||||
|
type = HEV_SOCKS5_TYPE_UDP_IN_TCP;
|
||||||
|
|
||||||
|
res = hev_socks5_client_udp_construct (&self->base, type);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 session udp construct", self);
|
||||||
|
|
||||||
|
HEV_OBJECT (self)->klass = HEV_SOCKS5_SESSION_UDP_TYPE;
|
||||||
|
|
||||||
|
udp_recv (pcb, udp_recv_handler, self);
|
||||||
|
|
||||||
|
self->pcb = pcb;
|
||||||
|
self->mutex = mutex;
|
||||||
|
self->data.self = self;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_session_udp_destruct (HevObject *base)
|
||||||
|
{
|
||||||
|
HevSocks5SessionUDP *self = HEV_SOCKS5_SESSION_UDP (base);
|
||||||
|
HevListNode *node;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 session udp destruct", self);
|
||||||
|
|
||||||
|
node = hev_list_first (&self->frame_list);
|
||||||
|
while (node) {
|
||||||
|
HevSocks5UDPFrame *frame;
|
||||||
|
|
||||||
|
frame = container_of (node, HevSocks5UDPFrame, node);
|
||||||
|
node = hev_list_node_next (node);
|
||||||
|
pbuf_free (frame->data);
|
||||||
|
hev_free (frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
hev_task_mutex_lock (self->mutex);
|
||||||
|
if (self->pcb) {
|
||||||
|
udp_recv (self->pcb, NULL, NULL);
|
||||||
|
udp_remove (self->pcb);
|
||||||
|
}
|
||||||
|
hev_task_mutex_unlock (self->mutex);
|
||||||
|
|
||||||
|
HEV_SOCKS5_CLIENT_UDP_TYPE->destruct (base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
hev_socks5_session_udp_iface (HevObject *base, void *type)
|
||||||
|
{
|
||||||
|
if (type == HEV_SOCKS5_SESSION_TYPE) {
|
||||||
|
HevSocks5SessionUDPClass *klass = HEV_OBJECT_GET_CLASS (base);
|
||||||
|
return &klass->session;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HEV_SOCKS5_CLIENT_UDP_TYPE->iface (base, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
HevObjectClass *
|
||||||
|
hev_socks5_session_udp_class (void)
|
||||||
|
{
|
||||||
|
static HevSocks5SessionUDPClass klass;
|
||||||
|
HevSocks5SessionUDPClass *kptr = &klass;
|
||||||
|
HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr);
|
||||||
|
|
||||||
|
if (!okptr->name) {
|
||||||
|
HevSocks5Class *skptr;
|
||||||
|
HevSocks5ClientClass *ckptr;
|
||||||
|
HevSocks5SessionIface *siptr;
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
ptr = HEV_SOCKS5_CLIENT_UDP_TYPE;
|
||||||
|
memcpy (kptr, ptr, sizeof (HevSocks5ClientUDPClass));
|
||||||
|
|
||||||
|
okptr->name = "HevSocks5SessionUDP";
|
||||||
|
okptr->destruct = hev_socks5_session_udp_destruct;
|
||||||
|
okptr->iface = hev_socks5_session_udp_iface;
|
||||||
|
|
||||||
|
skptr = HEV_SOCKS5_CLASS (kptr);
|
||||||
|
skptr->binder = hev_socks5_session_bind;
|
||||||
|
|
||||||
|
ckptr = HEV_SOCKS5_CLIENT_CLASS (kptr);
|
||||||
|
ckptr->set_upstream_addr = hev_socks5_session_udp_set_upstream_addr;
|
||||||
|
|
||||||
|
siptr = &kptr->session;
|
||||||
|
siptr->splicer = hev_socks5_session_udp_splice;
|
||||||
|
siptr->get_task = hev_socks5_session_udp_get_task;
|
||||||
|
siptr->set_task = hev_socks5_session_udp_set_task;
|
||||||
|
siptr->get_node = hev_socks5_session_udp_get_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return okptr;
|
||||||
|
}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-session-udp.h
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2017 - 2023 hev
|
||||||
|
Description : Socks5 Session UDP
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_SESSION_UDP_H__
|
||||||
|
#define __HEV_SOCKS5_SESSION_UDP_H__
|
||||||
|
|
||||||
|
#include <hev-socks5-client-udp.h>
|
||||||
|
|
||||||
|
#include "hev-socks5-session.h"
|
||||||
|
|
||||||
|
#define HEV_SOCKS5_SESSION_UDP(p) ((HevSocks5SessionUDP *)p)
|
||||||
|
#define HEV_SOCKS5_SESSION_UDP_CLASS(p) ((HevSocks5SessionUDPClass *)p)
|
||||||
|
#define HEV_SOCKS5_SESSION_UDP_TYPE (hev_socks5_session_udp_class ())
|
||||||
|
|
||||||
|
typedef struct _HevSocks5SessionUDP HevSocks5SessionUDP;
|
||||||
|
typedef struct _HevSocks5SessionUDPClass HevSocks5SessionUDPClass;
|
||||||
|
|
||||||
|
struct _HevSocks5SessionUDP
|
||||||
|
{
|
||||||
|
HevSocks5ClientUDP base;
|
||||||
|
|
||||||
|
HevSocks5SessionData data;
|
||||||
|
|
||||||
|
HevList frame_list;
|
||||||
|
struct udp_pcb *pcb;
|
||||||
|
HevTaskMutex *mutex;
|
||||||
|
int frames;
|
||||||
|
int addr;
|
||||||
|
int port;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5SessionUDPClass
|
||||||
|
{
|
||||||
|
HevSocks5ClientUDPClass base;
|
||||||
|
|
||||||
|
HevSocks5SessionIface session;
|
||||||
|
};
|
||||||
|
|
||||||
|
HevObjectClass *hev_socks5_session_udp_class (void);
|
||||||
|
|
||||||
|
int hev_socks5_session_udp_construct (HevSocks5SessionUDP *self,
|
||||||
|
struct udp_pcb *pcb, HevTaskMutex *mutex);
|
||||||
|
|
||||||
|
HevSocks5SessionUDP *hev_socks5_session_udp_new (struct udp_pcb *pcb,
|
||||||
|
HevTaskMutex *mutex);
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_SESSION_UDP_H__ */
|
||||||
113
app/src/main/cpp/hev-socks5-tunnel/src/hev-socks5-session.c
Normal file
113
app/src/main/cpp/hev-socks5-tunnel/src/hev-socks5-session.c
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-session.c
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2017 - 2023 hev
|
||||||
|
Description : Socks5 Session
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "hev-utils.h"
|
||||||
|
#include "hev-logger.h"
|
||||||
|
#include "hev-config.h"
|
||||||
|
#include "hev-socks5-client.h"
|
||||||
|
|
||||||
|
#include "hev-socks5-session.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_session_run (HevSocks5Session *self)
|
||||||
|
{
|
||||||
|
HevSocks5SessionIface *iface;
|
||||||
|
HevConfigServer *srv;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 session run", self);
|
||||||
|
|
||||||
|
srv = hev_config_get_socks5_server ();
|
||||||
|
|
||||||
|
res = hev_socks5_client_connect (HEV_SOCKS5_CLIENT (self), srv->addr,
|
||||||
|
srv->port);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_I ("%p socks5 session connect", self);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (srv->user && srv->pass) {
|
||||||
|
hev_socks5_client_set_auth (HEV_SOCKS5_CLIENT (self), srv->user,
|
||||||
|
srv->pass);
|
||||||
|
LOG_D ("%p socks5 client auth %s:%s", self, srv->user, srv->pass);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_socks5_client_handshake (HEV_SOCKS5_CLIENT (self), srv->pipeline);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_I ("%p socks5 session handshake", self);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
iface = HEV_OBJECT_GET_IFACE (self, HEV_SOCKS5_SESSION_TYPE);
|
||||||
|
iface->splicer (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_session_terminate (HevSocks5Session *self)
|
||||||
|
{
|
||||||
|
HevSocks5SessionIface *iface;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 session terminate", self);
|
||||||
|
|
||||||
|
iface = HEV_OBJECT_GET_IFACE (self, HEV_SOCKS5_SESSION_TYPE);
|
||||||
|
hev_socks5_set_timeout (HEV_SOCKS5 (self), 0);
|
||||||
|
hev_task_wakeup (iface->get_task (self));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_session_set_task (HevSocks5Session *self, HevTask *task)
|
||||||
|
{
|
||||||
|
HevSocks5SessionIface *iface;
|
||||||
|
|
||||||
|
iface = HEV_OBJECT_GET_IFACE (self, HEV_SOCKS5_SESSION_TYPE);
|
||||||
|
iface->set_task (self, task);
|
||||||
|
}
|
||||||
|
|
||||||
|
HevListNode *
|
||||||
|
hev_socks5_session_get_node (HevSocks5Session *self)
|
||||||
|
{
|
||||||
|
HevSocks5SessionIface *iface;
|
||||||
|
|
||||||
|
iface = HEV_OBJECT_GET_IFACE (self, HEV_SOCKS5_SESSION_TYPE);
|
||||||
|
return iface->get_node (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_session_bind (HevSocks5 *self, int fd, const struct sockaddr *dest)
|
||||||
|
{
|
||||||
|
HevConfigServer *srv;
|
||||||
|
unsigned int mark;
|
||||||
|
|
||||||
|
LOG_D ("%p socks5 session bind", self);
|
||||||
|
|
||||||
|
srv = hev_config_get_socks5_server ();
|
||||||
|
mark = srv->mark;
|
||||||
|
|
||||||
|
if (mark) {
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = set_sock_mark (fd, mark);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_sock_tcp_fastopen (fd, srv->fastopen);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
hev_socks5_session_iface (void)
|
||||||
|
{
|
||||||
|
static char type;
|
||||||
|
|
||||||
|
return &type;
|
||||||
|
}
|
||||||
51
app/src/main/cpp/hev-socks5-tunnel/src/hev-socks5-session.h
Normal file
51
app/src/main/cpp/hev-socks5-tunnel/src/hev-socks5-session.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-session.h
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2017 - 2023 hev
|
||||||
|
Description : Socks5 Session
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_SESSION_H__
|
||||||
|
#define __HEV_SOCKS5_SESSION_H__
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
|
||||||
|
#include "hev-list.h"
|
||||||
|
|
||||||
|
#define HEV_SOCKS5_SESSION(p) ((HevSocks5Session *)p)
|
||||||
|
#define HEV_SOCKS5_SESSION_IFACE(p) ((HevSocks5SessionIface *)p)
|
||||||
|
#define HEV_SOCKS5_SESSION_TYPE (hev_socks5_session_iface ())
|
||||||
|
|
||||||
|
typedef void HevSocks5Session;
|
||||||
|
typedef struct _HevSocks5SessionData HevSocks5SessionData;
|
||||||
|
typedef struct _HevSocks5SessionIface HevSocks5SessionIface;
|
||||||
|
|
||||||
|
struct _HevSocks5SessionData
|
||||||
|
{
|
||||||
|
HevListNode node;
|
||||||
|
HevTask *task;
|
||||||
|
HevSocks5Session *self;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _HevSocks5SessionIface
|
||||||
|
{
|
||||||
|
void (*splicer) (HevSocks5Session *self);
|
||||||
|
HevTask *(*get_task) (HevSocks5Session *self);
|
||||||
|
void (*set_task) (HevSocks5Session *self, HevTask *task);
|
||||||
|
HevListNode *(*get_node) (HevSocks5Session *self);
|
||||||
|
};
|
||||||
|
|
||||||
|
void *hev_socks5_session_iface (void);
|
||||||
|
|
||||||
|
void hev_socks5_session_run (HevSocks5Session *self);
|
||||||
|
void hev_socks5_session_terminate (HevSocks5Session *self);
|
||||||
|
|
||||||
|
void hev_socks5_session_set_task (HevSocks5Session *self, HevTask *task);
|
||||||
|
HevListNode *hev_socks5_session_get_node (HevSocks5Session *self);
|
||||||
|
|
||||||
|
int hev_socks5_session_bind (HevSocks5 *self, int fd,
|
||||||
|
const struct sockaddr *dest);
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_SESSION_H__ */
|
||||||
727
app/src/main/cpp/hev-socks5-tunnel/src/hev-socks5-tunnel.c
Normal file
727
app/src/main/cpp/hev-socks5-tunnel/src/hev-socks5-tunnel.c
Normal file
@ -0,0 +1,727 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-tunnel.c
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2019 - 2025 hev
|
||||||
|
Description : Socks5 Tunnel
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#include <lwip/tcp.h>
|
||||||
|
#include <lwip/udp.h>
|
||||||
|
#include <lwip/nd6.h>
|
||||||
|
#include <lwip/netif.h>
|
||||||
|
#include <lwip/ip4_frag.h>
|
||||||
|
#include <lwip/ip6_frag.h>
|
||||||
|
#include <lwip/priv/tcp_priv.h>
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
#include <hev-task-io.h>
|
||||||
|
#include <hev-task-mutex.h>
|
||||||
|
#include <hev-task-system.h>
|
||||||
|
#include <hev-memory-allocator.h>
|
||||||
|
|
||||||
|
#include "hev-exec.h"
|
||||||
|
#include "hev-config.h"
|
||||||
|
#include "hev-logger.h"
|
||||||
|
#include "hev-tunnel.h"
|
||||||
|
#include "hev-compiler.h"
|
||||||
|
#include "hev-mapped-dns.h"
|
||||||
|
#include "hev-config-const.h"
|
||||||
|
#include "hev-socks5-session-tcp.h"
|
||||||
|
#include "hev-socks5-session-udp.h"
|
||||||
|
|
||||||
|
#include "hev-socks5-tunnel.h"
|
||||||
|
|
||||||
|
static int run;
|
||||||
|
static int tun_fd = -1;
|
||||||
|
static int tun_fd_local;
|
||||||
|
static int session_count;
|
||||||
|
static int event_fds[2] = { -1, -1 };
|
||||||
|
|
||||||
|
static size_t stat_tx_packets;
|
||||||
|
static size_t stat_rx_packets;
|
||||||
|
static size_t stat_tx_bytes;
|
||||||
|
static size_t stat_rx_bytes;
|
||||||
|
|
||||||
|
static struct netif netif;
|
||||||
|
static struct tcp_pcb *tcp;
|
||||||
|
static struct udp_pcb *udp;
|
||||||
|
|
||||||
|
static HevTaskMutex mutex;
|
||||||
|
static HevTask *task_event;
|
||||||
|
static HevTask *task_lwip_io;
|
||||||
|
static HevTask *task_lwip_timer;
|
||||||
|
static HevList session_set;
|
||||||
|
|
||||||
|
static int
|
||||||
|
task_io_yielder (HevTaskYieldType type, void *data)
|
||||||
|
{
|
||||||
|
hev_task_yield (type);
|
||||||
|
|
||||||
|
return run ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static err_t
|
||||||
|
netif_output_handler (struct netif *netif, struct pbuf *p)
|
||||||
|
{
|
||||||
|
ssize_t s;
|
||||||
|
|
||||||
|
s = hev_tunnel_write (tun_fd, p);
|
||||||
|
if (s <= 0) {
|
||||||
|
if (errno == EAGAIN)
|
||||||
|
return ERR_WOULDBLOCK;
|
||||||
|
LOG_W ("socks5 tunnel write");
|
||||||
|
return ERR_IF;
|
||||||
|
}
|
||||||
|
|
||||||
|
stat_rx_packets++;
|
||||||
|
stat_rx_bytes += s;
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static err_t
|
||||||
|
netif_output_v4_handler (struct netif *netif, struct pbuf *p,
|
||||||
|
const ip4_addr_t *ipaddr)
|
||||||
|
{
|
||||||
|
return netif_output_handler (netif, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static err_t
|
||||||
|
netif_output_v6_handler (struct netif *netif, struct pbuf *p,
|
||||||
|
const ip6_addr_t *ipaddr)
|
||||||
|
{
|
||||||
|
return netif_output_handler (netif, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static err_t
|
||||||
|
netif_init_handler (struct netif *netif)
|
||||||
|
{
|
||||||
|
netif->output = netif_output_v4_handler;
|
||||||
|
netif->output_ip6 = netif_output_v6_handler;
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hev_socks5_tunnel_insert_session (HevListNode *node)
|
||||||
|
{
|
||||||
|
HevSocks5SessionData *sd;
|
||||||
|
int max_session_count;
|
||||||
|
|
||||||
|
hev_list_add_tail (&session_set, node);
|
||||||
|
session_count++;
|
||||||
|
|
||||||
|
max_session_count = hev_config_get_misc_max_session_count ();
|
||||||
|
if (!max_session_count || session_count < max_session_count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
node = hev_list_first (&session_set);
|
||||||
|
sd = container_of (node, HevSocks5SessionData, node);
|
||||||
|
hev_socks5_session_terminate (sd->self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hev_socks5_tunnel_delete_session (HevListNode *node)
|
||||||
|
{
|
||||||
|
hev_list_del (&session_set, node);
|
||||||
|
session_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_tunnel_update_session (HevListNode *node)
|
||||||
|
{
|
||||||
|
int max_session_count;
|
||||||
|
|
||||||
|
max_session_count = hev_config_get_misc_max_session_count ();
|
||||||
|
if (!max_session_count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
hev_list_del (&session_set, node);
|
||||||
|
hev_list_add_tail (&session_set, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hev_socks5_session_task_entry (void *data)
|
||||||
|
{
|
||||||
|
HevSocks5Session *s = data;
|
||||||
|
|
||||||
|
hev_socks5_session_run (s);
|
||||||
|
|
||||||
|
hev_socks5_tunnel_delete_session (hev_socks5_session_get_node (s));
|
||||||
|
hev_object_unref (HEV_OBJECT (s));
|
||||||
|
}
|
||||||
|
|
||||||
|
static err_t
|
||||||
|
tcp_accept_handler (void *arg, struct tcp_pcb *pcb, err_t err)
|
||||||
|
{
|
||||||
|
HevSocks5SessionTCP *tcp;
|
||||||
|
HevListNode *node;
|
||||||
|
int stack_size;
|
||||||
|
HevTask *task;
|
||||||
|
|
||||||
|
if (err != ERR_OK)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (!run)
|
||||||
|
return ERR_RST;
|
||||||
|
|
||||||
|
tcp = hev_socks5_session_tcp_new (pcb, &mutex);
|
||||||
|
if (!tcp)
|
||||||
|
return ERR_MEM;
|
||||||
|
|
||||||
|
stack_size = hev_config_get_misc_task_stack_size ();
|
||||||
|
task = hev_task_new (stack_size);
|
||||||
|
if (!task) {
|
||||||
|
hev_object_unref (HEV_OBJECT (tcp));
|
||||||
|
return ERR_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
hev_socks5_session_set_task (HEV_SOCKS5_SESSION (tcp), task);
|
||||||
|
node = hev_socks5_session_get_node (HEV_SOCKS5_SESSION (tcp));
|
||||||
|
hev_socks5_tunnel_insert_session (node);
|
||||||
|
hev_task_run (task, hev_socks5_session_task_entry, tcp);
|
||||||
|
hev_task_wakeup (task_lwip_timer);
|
||||||
|
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dns_recv_handler (void *arg, struct udp_pcb *pcb, struct pbuf *p,
|
||||||
|
const ip_addr_t *addr, u16_t port)
|
||||||
|
{
|
||||||
|
HevMappedDNS *dns = arg;
|
||||||
|
struct pbuf *b;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
LOG_D ("%p mapped dns handle", dns);
|
||||||
|
|
||||||
|
b = pbuf_alloc (PBUF_TRANSPORT, UDP_BUF_SIZE, PBUF_RAM);
|
||||||
|
if (!b)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
res = hev_mapped_dns_handle (dns, p->payload, p->len, b->payload, b->len);
|
||||||
|
if (res < 0)
|
||||||
|
goto free;
|
||||||
|
|
||||||
|
b->len = res;
|
||||||
|
b->tot_len = res;
|
||||||
|
udp_sendfrom (pcb, b, &pcb->local_ip, pcb->local_port);
|
||||||
|
|
||||||
|
free:
|
||||||
|
pbuf_free (b);
|
||||||
|
exit:
|
||||||
|
pbuf_free (p);
|
||||||
|
udp_recv (pcb, NULL, NULL);
|
||||||
|
udp_remove (pcb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
udp_recv_handler (void *arg, struct udp_pcb *pcb, struct pbuf *p,
|
||||||
|
const ip_addr_t *addr, u16_t port)
|
||||||
|
{
|
||||||
|
HevSocks5SessionUDP *udp;
|
||||||
|
HevListNode *node;
|
||||||
|
HevMappedDNS *dns;
|
||||||
|
int stack_size;
|
||||||
|
HevTask *task;
|
||||||
|
|
||||||
|
if (!run) {
|
||||||
|
udp_remove (pcb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dns = hev_mapped_dns_get ();
|
||||||
|
if (dns && addr->type == IPADDR_TYPE_V4) {
|
||||||
|
int faddr = hev_config_get_mapdns_address ();
|
||||||
|
int fport = hev_config_get_mapdns_port ();
|
||||||
|
if (fport == port && faddr == ip_2_ip4 (addr)->addr) {
|
||||||
|
udp_recv (pcb, dns_recv_handler, dns);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
udp = hev_socks5_session_udp_new (pcb, &mutex);
|
||||||
|
if (!udp) {
|
||||||
|
udp_remove (pcb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stack_size = hev_config_get_misc_task_stack_size ();
|
||||||
|
task = hev_task_new (stack_size);
|
||||||
|
if (!task) {
|
||||||
|
hev_object_unref (HEV_OBJECT (udp));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hev_socks5_session_set_task (HEV_SOCKS5_SESSION (udp), task);
|
||||||
|
node = hev_socks5_session_get_node (HEV_SOCKS5_SESSION (udp));
|
||||||
|
hev_socks5_tunnel_insert_session (node);
|
||||||
|
hev_task_run (task, hev_socks5_session_task_entry, udp);
|
||||||
|
hev_task_wakeup (task_lwip_timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
event_task_entry (void *data)
|
||||||
|
{
|
||||||
|
HevListNode *node;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
LOG_D ("socks5 tunnel event task run");
|
||||||
|
|
||||||
|
hev_task_add_fd (task_event, event_fds[0], POLLIN);
|
||||||
|
|
||||||
|
hev_task_io_read (event_fds[0], &val, sizeof (val), NULL, NULL);
|
||||||
|
|
||||||
|
run = 0;
|
||||||
|
node = hev_list_first (&session_set);
|
||||||
|
for (; node; node = hev_list_node_next (node)) {
|
||||||
|
HevSocks5SessionData *sd;
|
||||||
|
|
||||||
|
sd = container_of (node, HevSocks5SessionData, node);
|
||||||
|
hev_socks5_session_terminate (sd->self);
|
||||||
|
}
|
||||||
|
|
||||||
|
hev_task_join (task_lwip_io);
|
||||||
|
hev_task_join (task_lwip_timer);
|
||||||
|
hev_task_del_fd (task_event, event_fds[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lwip_io_task_entry (void *data)
|
||||||
|
{
|
||||||
|
const unsigned int mtu = hev_config_get_tunnel_mtu ();
|
||||||
|
|
||||||
|
LOG_D ("socks5 tunnel lwip task run");
|
||||||
|
|
||||||
|
hev_tunnel_add_task (tun_fd, task_lwip_io);
|
||||||
|
|
||||||
|
for (; run;) {
|
||||||
|
struct pbuf *buf;
|
||||||
|
|
||||||
|
buf = hev_tunnel_read (tun_fd, mtu, task_io_yielder, NULL);
|
||||||
|
if (!buf)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
stat_tx_packets++;
|
||||||
|
stat_tx_bytes += buf->tot_len;
|
||||||
|
|
||||||
|
hev_task_mutex_lock (&mutex);
|
||||||
|
if (netif.input (buf, &netif) != ERR_OK)
|
||||||
|
pbuf_free (buf);
|
||||||
|
hev_task_mutex_unlock (&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
hev_tunnel_del_task (tun_fd, task_lwip_io);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lwip_timer_task_entry (void *data)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
LOG_D ("socks5 tunnel timer task run");
|
||||||
|
|
||||||
|
for (i = 1; run; i++) {
|
||||||
|
hev_task_mutex_lock (&mutex);
|
||||||
|
tcp_tmr ();
|
||||||
|
|
||||||
|
if ((i & 3) == 0) {
|
||||||
|
#if IP_REASSEMBLY
|
||||||
|
ip_reass_tmr ();
|
||||||
|
#endif
|
||||||
|
#if LWIP_IPV6
|
||||||
|
nd6_tmr ();
|
||||||
|
#if LWIP_IPV6_REASS
|
||||||
|
ip6_reass_tmr ();
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
hev_task_mutex_unlock (&mutex);
|
||||||
|
|
||||||
|
if (hev_list_first (&session_set))
|
||||||
|
hev_task_sleep (TCP_TMR_INTERVAL);
|
||||||
|
else
|
||||||
|
hev_task_yield (HEV_TASK_WAITIO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
tunnel_init (int extern_tun_fd)
|
||||||
|
{
|
||||||
|
const char *script_path, *name, *ipv4, *ipv6;
|
||||||
|
int multi_queue, res;
|
||||||
|
unsigned int mtu;
|
||||||
|
|
||||||
|
if (extern_tun_fd >= 0) {
|
||||||
|
int nonblock = 1;
|
||||||
|
|
||||||
|
res = ioctl (extern_tun_fd, FIONBIO, (char *)&nonblock);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_E ("socks5 tunnel non-blocking");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tun_fd = extern_tun_fd;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = hev_config_get_tunnel_name ();
|
||||||
|
multi_queue = hev_config_get_tunnel_multi_queue ();
|
||||||
|
tun_fd = hev_tunnel_open (name, multi_queue);
|
||||||
|
if (tun_fd < 0) {
|
||||||
|
LOG_E ("socks5 tunnel open (%s)", strerror (errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mtu = hev_config_get_tunnel_mtu ();
|
||||||
|
res = hev_tunnel_set_mtu (mtu);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_E ("socks5 tunnel mtu");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ipv4 = hev_config_get_tunnel_ipv4_address ();
|
||||||
|
if (ipv4) {
|
||||||
|
res = hev_tunnel_set_ipv4 (ipv4, 32);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_E ("socks5 tunnel ipv4");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ipv6 = hev_config_get_tunnel_ipv6_address ();
|
||||||
|
if (ipv6) {
|
||||||
|
res = hev_tunnel_set_ipv6 (ipv6, 128);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_E ("socks5 tunnel ipv6");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res = hev_tunnel_set_state (1);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_E ("socks5 tunnel state");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
script_path = hev_config_get_tunnel_post_up_script ();
|
||||||
|
if (script_path)
|
||||||
|
hev_exec_run (script_path, hev_tunnel_get_name (),
|
||||||
|
hev_tunnel_get_index (), 0);
|
||||||
|
|
||||||
|
tun_fd_local = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
tunnel_fini (void)
|
||||||
|
{
|
||||||
|
const char *script_path;
|
||||||
|
|
||||||
|
if (!tun_fd_local)
|
||||||
|
return;
|
||||||
|
|
||||||
|
script_path = hev_config_get_tunnel_pre_down_script ();
|
||||||
|
if (script_path)
|
||||||
|
hev_exec_run (script_path, hev_tunnel_get_name (),
|
||||||
|
hev_tunnel_get_index (), 1);
|
||||||
|
|
||||||
|
hev_tunnel_close (tun_fd);
|
||||||
|
tun_fd_local = 0;
|
||||||
|
tun_fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
gateway_init (void)
|
||||||
|
{
|
||||||
|
ip4_addr_t addr4, mask, gw;
|
||||||
|
ip6_addr_t addr6;
|
||||||
|
|
||||||
|
netif_add_noaddr (&netif, NULL, netif_init_handler, ip_input);
|
||||||
|
|
||||||
|
ip4_addr_set_loopback (&addr4);
|
||||||
|
ip4_addr_set_any (&mask);
|
||||||
|
ip4_addr_set_any (&gw);
|
||||||
|
netif_set_addr (&netif, &addr4, &mask, &gw);
|
||||||
|
|
||||||
|
ip6_addr_set_loopback (&addr6);
|
||||||
|
netif_add_ip6_address (&netif, &addr6, NULL);
|
||||||
|
|
||||||
|
netif_set_up (&netif);
|
||||||
|
netif_set_link_up (&netif);
|
||||||
|
netif_set_default (&netif);
|
||||||
|
netif_set_flags (&netif, NETIF_FLAG_PRETEND_TCP);
|
||||||
|
|
||||||
|
tcp = tcp_new_ip_type (IPADDR_TYPE_ANY);
|
||||||
|
tcp_bind_netif (tcp, &netif);
|
||||||
|
tcp_bind (tcp, NULL, 0);
|
||||||
|
tcp = tcp_listen (tcp);
|
||||||
|
tcp_accept (tcp, tcp_accept_handler);
|
||||||
|
|
||||||
|
udp = udp_new_ip_type (IPADDR_TYPE_ANY);
|
||||||
|
udp_bind_netif (udp, &netif);
|
||||||
|
udp_bind (udp, NULL, 0);
|
||||||
|
udp_recv (udp, udp_recv_handler, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gateway_fini (void)
|
||||||
|
{
|
||||||
|
udp_remove (udp);
|
||||||
|
tcp_close (tcp);
|
||||||
|
netif_remove (&netif);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
event_task_init (void)
|
||||||
|
{
|
||||||
|
int nonblock = 1;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = socketpair (PF_LOCAL, SOCK_STREAM, 0, event_fds);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_E ("socks5 tunnel event");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = ioctl (event_fds[0], FIONBIO, (char *)&nonblock);
|
||||||
|
if (res < 0) {
|
||||||
|
LOG_E ("socks5 tunnel event nonblock");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
task_event = hev_task_new (-1);
|
||||||
|
if (!task_event) {
|
||||||
|
LOG_E ("socks5 tunnel task event");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
event_task_fini (void)
|
||||||
|
{
|
||||||
|
if (task_event) {
|
||||||
|
hev_task_unref (task_event);
|
||||||
|
task_event = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event_fds[0] >= 0) {
|
||||||
|
close (event_fds[0]);
|
||||||
|
event_fds[0] = -1;
|
||||||
|
}
|
||||||
|
if (event_fds[1] >= 0) {
|
||||||
|
close (event_fds[1]);
|
||||||
|
event_fds[1] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lwip_io_task_init (void)
|
||||||
|
{
|
||||||
|
task_lwip_io = hev_task_new (-1);
|
||||||
|
if (!task_lwip_io) {
|
||||||
|
LOG_E ("socks5 tunnel task lwip");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
hev_task_set_priority (task_lwip_io, 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lwip_io_task_fini (void)
|
||||||
|
{
|
||||||
|
if (task_lwip_io) {
|
||||||
|
hev_task_unref (task_lwip_io);
|
||||||
|
task_lwip_io = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lwip_timer_task_init (void)
|
||||||
|
{
|
||||||
|
task_lwip_timer = hev_task_new (-1);
|
||||||
|
if (!task_lwip_timer) {
|
||||||
|
LOG_E ("socks5 tunnel task timer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
hev_task_set_priority (task_lwip_timer, 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lwip_timer_task_fini (void)
|
||||||
|
{
|
||||||
|
if (task_lwip_timer) {
|
||||||
|
hev_task_unref (task_lwip_timer);
|
||||||
|
task_lwip_timer = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mapped_dns_init (void)
|
||||||
|
{
|
||||||
|
HevMappedDNS *dns;
|
||||||
|
int cache_size;
|
||||||
|
int network;
|
||||||
|
int netmask;
|
||||||
|
|
||||||
|
network = hev_config_get_mapdns_network ();
|
||||||
|
netmask = hev_config_get_mapdns_netmask ();
|
||||||
|
cache_size = hev_config_get_mapdns_cache_size ();
|
||||||
|
|
||||||
|
if (!cache_size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
dns = hev_mapped_dns_new (network, netmask, cache_size);
|
||||||
|
if (!dns)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
hev_mapped_dns_put (dns);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mapped_dns_fini (void)
|
||||||
|
{
|
||||||
|
HevMappedDNS *dns;
|
||||||
|
|
||||||
|
dns = hev_mapped_dns_get ();
|
||||||
|
if (dns) {
|
||||||
|
hev_object_unref (HEV_OBJECT (dns));
|
||||||
|
hev_mapped_dns_put (NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_tunnel_init (int tun_fd)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
LOG_D ("socks5 tunnel init");
|
||||||
|
|
||||||
|
res = tunnel_init (tun_fd);
|
||||||
|
if (res < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
res = gateway_init ();
|
||||||
|
if (res < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
res = event_task_init ();
|
||||||
|
if (res < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
res = lwip_io_task_init ();
|
||||||
|
if (res < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
res = lwip_timer_task_init ();
|
||||||
|
if (res < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
res = mapped_dns_init ();
|
||||||
|
if (res < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
signal (SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
|
hev_task_mutex_init (&mutex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
hev_socks5_tunnel_fini ();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_tunnel_fini (void)
|
||||||
|
{
|
||||||
|
LOG_D ("socks5 tunnel fini");
|
||||||
|
|
||||||
|
mapped_dns_fini ();
|
||||||
|
lwip_timer_task_fini ();
|
||||||
|
lwip_io_task_fini ();
|
||||||
|
event_task_fini ();
|
||||||
|
gateway_fini ();
|
||||||
|
tunnel_fini ();
|
||||||
|
|
||||||
|
stat_tx_packets = 0;
|
||||||
|
stat_rx_packets = 0;
|
||||||
|
stat_tx_bytes = 0;
|
||||||
|
stat_rx_bytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_socks5_tunnel_run (void)
|
||||||
|
{
|
||||||
|
LOG_D ("socks5 tunnel run");
|
||||||
|
|
||||||
|
task_event = hev_task_ref (task_event);
|
||||||
|
hev_task_run (task_event, event_task_entry, NULL);
|
||||||
|
|
||||||
|
task_lwip_io = hev_task_ref (task_lwip_io);
|
||||||
|
hev_task_run (task_lwip_io, lwip_io_task_entry, NULL);
|
||||||
|
|
||||||
|
task_lwip_timer = hev_task_ref (task_lwip_timer);
|
||||||
|
hev_task_run (task_lwip_timer, lwip_timer_task_entry, NULL);
|
||||||
|
|
||||||
|
run = 1;
|
||||||
|
hev_task_system_run ();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_tunnel_stop (void)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
LOG_D ("socks5 tunnel stop");
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
fd = READ_ONCE (event_fds[1]);
|
||||||
|
if (fd >= 0)
|
||||||
|
break;
|
||||||
|
/* Wait for async initialization */
|
||||||
|
usleep (100 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = write (fd, &res, 1);
|
||||||
|
assert (res > 0 && "socks5 tunnel write event");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_socks5_tunnel_stats (size_t *tx_packets, size_t *tx_bytes,
|
||||||
|
size_t *rx_packets, size_t *rx_bytes)
|
||||||
|
{
|
||||||
|
LOG_D ("socks5 tunnel stats");
|
||||||
|
|
||||||
|
if (tx_packets)
|
||||||
|
*tx_packets = stat_tx_packets;
|
||||||
|
|
||||||
|
if (tx_bytes)
|
||||||
|
*tx_bytes = stat_tx_bytes;
|
||||||
|
|
||||||
|
if (rx_packets)
|
||||||
|
*rx_packets = stat_rx_packets;
|
||||||
|
|
||||||
|
if (rx_bytes)
|
||||||
|
*rx_bytes = stat_rx_bytes;
|
||||||
|
}
|
||||||
26
app/src/main/cpp/hev-socks5-tunnel/src/hev-socks5-tunnel.h
Normal file
26
app/src/main/cpp/hev-socks5-tunnel/src/hev-socks5-tunnel.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-socks5-tunnel.h
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2019 - 2023 hev
|
||||||
|
Description : Socks5 Tunnel
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_SOCKS5_TUNNEL_H__
|
||||||
|
#define __HEV_SOCKS5_TUNNEL_H__
|
||||||
|
|
||||||
|
#include "hev-list.h"
|
||||||
|
|
||||||
|
int hev_socks5_tunnel_init (int tun_fd);
|
||||||
|
void hev_socks5_tunnel_fini (void);
|
||||||
|
|
||||||
|
int hev_socks5_tunnel_run (void);
|
||||||
|
void hev_socks5_tunnel_stop (void);
|
||||||
|
|
||||||
|
void hev_socks5_tunnel_stats (size_t *tx_packets, size_t *tx_bytes,
|
||||||
|
size_t *rx_packets, size_t *rx_bytes);
|
||||||
|
|
||||||
|
void hev_socks5_tunnel_update_session (HevListNode *node);
|
||||||
|
|
||||||
|
#endif /* __HEV_SOCKS5_TUNNEL_H__ */
|
||||||
242
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel-freebsd.c
Normal file
242
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel-freebsd.c
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-tunnel-freebsd.c
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2023 hev
|
||||||
|
Description : Tunnel on FreeBSD
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__FreeBSD__)
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <net/if_tun.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/in_var.h>
|
||||||
|
#include <netinet6/nd6.h>
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
#include <hev-task-io.h>
|
||||||
|
|
||||||
|
#include "hev-tunnel.h"
|
||||||
|
|
||||||
|
static char tun_name[IFNAMSIZ];
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_open (const char *name, int multi_queue)
|
||||||
|
{
|
||||||
|
struct ifreq ifr;
|
||||||
|
char buf[256];
|
||||||
|
int res;
|
||||||
|
int sfd;
|
||||||
|
int tfd;
|
||||||
|
|
||||||
|
snprintf (buf, sizeof (buf), "/dev/%s", name);
|
||||||
|
tfd = hev_task_io_open (buf, O_RDWR);
|
||||||
|
if (tfd >= 0)
|
||||||
|
goto succ;
|
||||||
|
|
||||||
|
tfd = hev_task_io_open ("/dev/tun", O_RDWR);
|
||||||
|
if (tfd < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
res = ioctl (tfd, TUNGIFNAME, (void *)&ifr);
|
||||||
|
if (res < 0)
|
||||||
|
goto fail_close;
|
||||||
|
|
||||||
|
sfd = socket (AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (sfd < 0)
|
||||||
|
goto fail_close;
|
||||||
|
|
||||||
|
strncpy (buf, name, sizeof (buf) - 1);
|
||||||
|
ifr.ifr_data = buf;
|
||||||
|
res = ioctl (sfd, SIOCSIFNAME, (void *)&ifr);
|
||||||
|
close (sfd);
|
||||||
|
if (res < 0)
|
||||||
|
goto fail_close;
|
||||||
|
|
||||||
|
succ:
|
||||||
|
strncpy (tun_name, name, IFNAMSIZ - 1);
|
||||||
|
return tfd;
|
||||||
|
|
||||||
|
fail_close:
|
||||||
|
close (tfd);
|
||||||
|
fail:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_tunnel_close (int fd)
|
||||||
|
{
|
||||||
|
struct ifreq ifr = { 0 };
|
||||||
|
|
||||||
|
close (fd);
|
||||||
|
|
||||||
|
fd = socket (AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memcpy (ifr.ifr_name, tun_name, IFNAMSIZ);
|
||||||
|
ioctl (fd, SIOCIFDESTROY, (void *)&ifr);
|
||||||
|
|
||||||
|
close (fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_set_mtu (int mtu)
|
||||||
|
{
|
||||||
|
int fd, res = -1;
|
||||||
|
struct ifreq ifr = { .ifr_mtu = mtu };
|
||||||
|
|
||||||
|
fd = socket (AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
memcpy (ifr.ifr_name, tun_name, IFNAMSIZ);
|
||||||
|
res = ioctl (fd, SIOCSIFMTU, (void *)&ifr);
|
||||||
|
|
||||||
|
close (fd);
|
||||||
|
exit:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_set_state (int state)
|
||||||
|
{
|
||||||
|
struct ifreq ifr = { 0 };
|
||||||
|
int res = -1;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = socket (AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
memcpy (ifr.ifr_name, tun_name, IFNAMSIZ);
|
||||||
|
res = ioctl (fd, SIOCGIFFLAGS, (void *)&ifr);
|
||||||
|
if (res < 0)
|
||||||
|
goto exit_close;
|
||||||
|
|
||||||
|
if (state)
|
||||||
|
ifr.ifr_flags |= IFF_UP;
|
||||||
|
else
|
||||||
|
ifr.ifr_flags &= ~IFF_UP;
|
||||||
|
res = ioctl (fd, SIOCSIFFLAGS, (void *)&ifr);
|
||||||
|
|
||||||
|
exit_close:
|
||||||
|
close (fd);
|
||||||
|
exit:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_set_ipv4 (const char *addr, unsigned int prefix)
|
||||||
|
{
|
||||||
|
struct ifaliasreq ifra = { 0 };
|
||||||
|
struct sockaddr_in *pa;
|
||||||
|
int res = -1;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = socket (AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
strcpy (ifra.ifra_name, tun_name);
|
||||||
|
|
||||||
|
pa = (struct sockaddr_in *)&ifra.ifra_addr;
|
||||||
|
pa->sin_len = sizeof (ifra.ifra_addr);
|
||||||
|
pa->sin_family = AF_INET;
|
||||||
|
res = inet_pton (AF_INET, addr, &pa->sin_addr);
|
||||||
|
if (!res)
|
||||||
|
goto exit_close;
|
||||||
|
|
||||||
|
memcpy (&ifra.ifra_broadaddr, &ifra.ifra_addr, sizeof (ifra.ifra_addr));
|
||||||
|
|
||||||
|
pa = (struct sockaddr_in *)&ifra.ifra_mask;
|
||||||
|
pa->sin_len = sizeof (ifra.ifra_addr);
|
||||||
|
pa->sin_family = AF_INET;
|
||||||
|
pa->sin_addr.s_addr = htonl (((unsigned int)(-1)) << (32 - prefix));
|
||||||
|
|
||||||
|
res = ioctl (fd, SIOCAIFADDR, &ifra);
|
||||||
|
|
||||||
|
exit_close:
|
||||||
|
close (fd);
|
||||||
|
exit:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_set_ipv6 (const char *addr, unsigned int prefix)
|
||||||
|
{
|
||||||
|
struct in6_aliasreq ifra = { .ifra_lifetime = { 0, 0, ND6_INFINITE_LIFETIME,
|
||||||
|
ND6_INFINITE_LIFETIME } };
|
||||||
|
uint8_t *bytes;
|
||||||
|
int res = -1;
|
||||||
|
int fd;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
fd = socket (AF_INET6, SOCK_DGRAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
strcpy (ifra.ifra_name, tun_name);
|
||||||
|
|
||||||
|
ifra.ifra_addr.sin6_len = sizeof (ifra.ifra_addr);
|
||||||
|
ifra.ifra_addr.sin6_family = AF_INET6;
|
||||||
|
res = inet_pton (AF_INET6, addr, &ifra.ifra_addr.sin6_addr);
|
||||||
|
if (!res)
|
||||||
|
goto exit_close;
|
||||||
|
|
||||||
|
ifra.ifra_prefixmask.sin6_len = sizeof (ifra.ifra_prefixmask);
|
||||||
|
ifra.ifra_prefixmask.sin6_family = AF_INET6;
|
||||||
|
bytes = (uint8_t *)&ifra.ifra_prefixmask.sin6_addr;
|
||||||
|
memset (bytes, 0xFF, 16);
|
||||||
|
bytes[prefix / 8] <<= prefix % 8;
|
||||||
|
prefix += prefix % 8;
|
||||||
|
for (i = prefix / 8; i < 16; i++)
|
||||||
|
bytes[i] = 0;
|
||||||
|
|
||||||
|
res = ioctl (fd, SIOCAIFADDR_IN6, &ifra);
|
||||||
|
|
||||||
|
exit_close:
|
||||||
|
close (fd);
|
||||||
|
exit:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
hev_tunnel_get_name (void)
|
||||||
|
{
|
||||||
|
return tun_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
hev_tunnel_get_index (void)
|
||||||
|
{
|
||||||
|
static char tun_index[16];
|
||||||
|
unsigned int index;
|
||||||
|
|
||||||
|
index = if_nametoindex (tun_name);
|
||||||
|
snprintf (tun_index, sizeof (tun_index) - 1, "%d", index);
|
||||||
|
return tun_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_add_task (int fd, HevTask *task)
|
||||||
|
{
|
||||||
|
return hev_task_add_fd (task, fd, POLLIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_tunnel_del_task (int fd, HevTask *task)
|
||||||
|
{
|
||||||
|
hev_task_del_fd (task, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __FreeBSD__ */
|
||||||
13
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel-freebsd.h
Normal file
13
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel-freebsd.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-tunnel-freebsd.h
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2023 - 2025 hev
|
||||||
|
Description : Tunnel on FreeBSD
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_TUNNEL_FREEBSD_H__
|
||||||
|
#define __HEV_TUNNEL_FREEBSD_H__
|
||||||
|
|
||||||
|
#endif /* __HEV_TUNNEL_FREEBSD_H__ */
|
||||||
213
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel-linux.c
Normal file
213
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel-linux.c
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-tunnel-linux.c
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2019 - 2023 hev
|
||||||
|
Description : Tunnel on Linux
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <linux/ipv6.h>
|
||||||
|
#include <linux/if_tun.h>
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
#include <hev-task-io.h>
|
||||||
|
|
||||||
|
#include "hev-tunnel.h"
|
||||||
|
|
||||||
|
static char tun_name[IFNAMSIZ];
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_open (const char *name, int multi_queue)
|
||||||
|
{
|
||||||
|
struct ifreq ifr = { 0 };
|
||||||
|
int res = -1;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = hev_task_io_open ("/dev/net/tun", O_RDWR);
|
||||||
|
if (fd < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
|
||||||
|
if (multi_queue)
|
||||||
|
ifr.ifr_flags |= IFF_MULTI_QUEUE;
|
||||||
|
if (name)
|
||||||
|
strncpy (ifr.ifr_name, name, IFNAMSIZ - 1);
|
||||||
|
|
||||||
|
res = ioctl (fd, TUNSETIFF, (void *)&ifr);
|
||||||
|
if (res < 0)
|
||||||
|
goto exit_close;
|
||||||
|
|
||||||
|
memcpy (tun_name, ifr.ifr_name, IFNAMSIZ);
|
||||||
|
return fd;
|
||||||
|
|
||||||
|
exit_close:
|
||||||
|
close (fd);
|
||||||
|
exit:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_tunnel_close (int fd)
|
||||||
|
{
|
||||||
|
close (fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_set_mtu (int mtu)
|
||||||
|
{
|
||||||
|
int fd, res = -1;
|
||||||
|
struct ifreq ifr = { .ifr_mtu = mtu };
|
||||||
|
|
||||||
|
fd = socket (AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
memcpy (ifr.ifr_name, tun_name, IFNAMSIZ);
|
||||||
|
res = ioctl (fd, SIOCSIFMTU, (void *)&ifr);
|
||||||
|
|
||||||
|
close (fd);
|
||||||
|
exit:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_set_state (int state)
|
||||||
|
{
|
||||||
|
struct ifreq ifr = { 0 };
|
||||||
|
int res = -1;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = socket (AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
memcpy (ifr.ifr_name, tun_name, IFNAMSIZ);
|
||||||
|
res = ioctl (fd, SIOCGIFFLAGS, (void *)&ifr);
|
||||||
|
if (res < 0)
|
||||||
|
goto exit_close;
|
||||||
|
|
||||||
|
if (state)
|
||||||
|
ifr.ifr_flags |= IFF_UP;
|
||||||
|
else
|
||||||
|
ifr.ifr_flags &= ~IFF_UP;
|
||||||
|
res = ioctl (fd, SIOCSIFFLAGS, (void *)&ifr);
|
||||||
|
|
||||||
|
exit_close:
|
||||||
|
close (fd);
|
||||||
|
exit:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_set_ipv4 (const char *addr, unsigned int prefix)
|
||||||
|
{
|
||||||
|
struct ifreq ifr = { 0 };
|
||||||
|
struct sockaddr_in *pa;
|
||||||
|
int res = -1;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = socket (AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
memcpy (ifr.ifr_name, tun_name, IFNAMSIZ);
|
||||||
|
|
||||||
|
pa = (struct sockaddr_in *)&ifr.ifr_addr;
|
||||||
|
pa->sin_family = AF_INET;
|
||||||
|
res = inet_pton (AF_INET, addr, &pa->sin_addr);
|
||||||
|
if (!res)
|
||||||
|
goto exit_close;
|
||||||
|
res = ioctl (fd, SIOCSIFADDR, (void *)&ifr);
|
||||||
|
if (res < 0)
|
||||||
|
goto exit_close;
|
||||||
|
|
||||||
|
pa = (struct sockaddr_in *)&ifr.ifr_netmask;
|
||||||
|
pa->sin_family = AF_INET;
|
||||||
|
pa->sin_addr.s_addr = htonl (((unsigned int)(-1)) << (32 - prefix));
|
||||||
|
res = ioctl (fd, SIOCSIFNETMASK, (void *)&ifr);
|
||||||
|
if ((res < 0) && (errno == EEXIST))
|
||||||
|
res = 0;
|
||||||
|
|
||||||
|
exit_close:
|
||||||
|
close (fd);
|
||||||
|
exit:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_set_ipv6 (const char *addr, unsigned int prefix)
|
||||||
|
{
|
||||||
|
struct in6_ifreq ifr6 = { 0 };
|
||||||
|
struct ifreq ifr = { 0 };
|
||||||
|
int res = -1;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = socket (AF_INET6, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
memcpy (ifr.ifr_name, tun_name, IFNAMSIZ);
|
||||||
|
res = ioctl (fd, SIOCGIFINDEX, (void *)&ifr);
|
||||||
|
if (res < 0)
|
||||||
|
goto exit_close;
|
||||||
|
|
||||||
|
ifr6.ifr6_prefixlen = prefix;
|
||||||
|
ifr6.ifr6_ifindex = ifr.ifr_ifindex;
|
||||||
|
res = inet_pton (AF_INET6, addr, &ifr6.ifr6_addr);
|
||||||
|
if (!res)
|
||||||
|
goto exit_close;
|
||||||
|
res = ioctl (fd, SIOCSIFADDR, (void *)&ifr6);
|
||||||
|
if ((res < 0) && (errno == EEXIST))
|
||||||
|
res = 0;
|
||||||
|
|
||||||
|
exit_close:
|
||||||
|
close (fd);
|
||||||
|
exit:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
hev_tunnel_get_name (void)
|
||||||
|
{
|
||||||
|
return tun_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
hev_tunnel_get_index (void)
|
||||||
|
{
|
||||||
|
static char tun_index[16];
|
||||||
|
unsigned int index;
|
||||||
|
|
||||||
|
index = if_nametoindex (tun_name);
|
||||||
|
snprintf (tun_index, sizeof (tun_index) - 1, "%d", index);
|
||||||
|
return tun_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_add_task (int fd, HevTask *task)
|
||||||
|
{
|
||||||
|
return hev_task_add_fd (task, fd, POLLIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_tunnel_del_task (int fd, HevTask *task)
|
||||||
|
{
|
||||||
|
hev_task_del_fd (task, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __linux__ */
|
||||||
13
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel-linux.h
Normal file
13
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel-linux.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-tunnel-linux.h
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2023 - 2025 hev
|
||||||
|
Description : Tunnel on Linux
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_TUNNEL_LINUX_H__
|
||||||
|
#define __HEV_TUNNEL_LINUX_H__
|
||||||
|
|
||||||
|
#endif /* __HEV_TUNNEL_LINUX_H__ */
|
||||||
259
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel-macos.c
Normal file
259
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel-macos.c
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-tunnel-macos.c
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2023 hev
|
||||||
|
Description : Tunnel on MacOS
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__APPLE__) || defined(__MACH__)
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <TargetConditionals.h>
|
||||||
|
|
||||||
|
#if TARGET_OS_OSX
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/in_var.h>
|
||||||
|
#include <netinet6/nd6.h>
|
||||||
|
#include <net/if_utun.h>
|
||||||
|
#include <sys/sys_domain.h>
|
||||||
|
#include <sys/kern_control.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
#include <hev-task-io.h>
|
||||||
|
|
||||||
|
#include "hev-tunnel.h"
|
||||||
|
|
||||||
|
static char tun_name[IFNAMSIZ];
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_open (const char *name, int multi_queue)
|
||||||
|
{
|
||||||
|
#if TARGET_OS_OSX
|
||||||
|
socklen_t len = IFNAMSIZ;
|
||||||
|
struct sockaddr_ctl sc;
|
||||||
|
struct ctl_info ci;
|
||||||
|
int nonblock = 1;
|
||||||
|
int res = -1;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
memset (&ci, 0, sizeof (ci));
|
||||||
|
strncpy (ci.ctl_name, UTUN_CONTROL_NAME, sizeof (ci.ctl_name));
|
||||||
|
|
||||||
|
fd = socket (PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
|
||||||
|
if (fd < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
res = ioctl (fd, CTLIOCGINFO, &ci);
|
||||||
|
if (res < 0)
|
||||||
|
goto exit_close;
|
||||||
|
|
||||||
|
sc.sc_id = ci.ctl_id;
|
||||||
|
sc.sc_len = sizeof (sc);
|
||||||
|
sc.sc_family = AF_SYSTEM;
|
||||||
|
sc.ss_sysaddr = AF_SYS_CONTROL;
|
||||||
|
sc.sc_unit = 0;
|
||||||
|
|
||||||
|
res = sscanf (name, "utun%u", &sc.sc_unit);
|
||||||
|
if (res > 0)
|
||||||
|
sc.sc_unit += 1;
|
||||||
|
|
||||||
|
res = connect (fd, (struct sockaddr *)&sc, sizeof (sc));
|
||||||
|
if (res < 0)
|
||||||
|
goto exit_close;
|
||||||
|
|
||||||
|
res = ioctl (fd, FIONBIO, (char *)&nonblock);
|
||||||
|
if (res < 0)
|
||||||
|
goto exit_close;
|
||||||
|
|
||||||
|
res = getsockopt (fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, tun_name, &len);
|
||||||
|
if (res < 0)
|
||||||
|
goto exit_close;
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
|
||||||
|
exit_close:
|
||||||
|
close (fd);
|
||||||
|
exit:
|
||||||
|
return res;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_tunnel_close (int fd)
|
||||||
|
{
|
||||||
|
close (fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_set_mtu (int mtu)
|
||||||
|
{
|
||||||
|
struct ifreq ifr = { .ifr_mtu = mtu };
|
||||||
|
int res = -1;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = socket (AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
memcpy (ifr.ifr_name, tun_name, IFNAMSIZ);
|
||||||
|
res = ioctl (fd, SIOCSIFMTU, (void *)&ifr);
|
||||||
|
|
||||||
|
close (fd);
|
||||||
|
exit:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_set_state (int state)
|
||||||
|
{
|
||||||
|
struct ifreq ifr = { 0 };
|
||||||
|
int res = -1;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = socket (AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
memcpy (ifr.ifr_name, tun_name, IFNAMSIZ);
|
||||||
|
res = ioctl (fd, SIOCGIFFLAGS, (void *)&ifr);
|
||||||
|
if (res < 0)
|
||||||
|
goto exit_close;
|
||||||
|
|
||||||
|
if (state)
|
||||||
|
ifr.ifr_flags |= IFF_UP;
|
||||||
|
else
|
||||||
|
ifr.ifr_flags &= ~IFF_UP;
|
||||||
|
res = ioctl (fd, SIOCSIFFLAGS, (void *)&ifr);
|
||||||
|
|
||||||
|
exit_close:
|
||||||
|
close (fd);
|
||||||
|
exit:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_set_ipv4 (const char *addr, unsigned int prefix)
|
||||||
|
{
|
||||||
|
#if TARGET_OS_OSX
|
||||||
|
struct ifaliasreq ifra = { 0 };
|
||||||
|
struct sockaddr_in *pa;
|
||||||
|
int res = -1;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = socket (AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
strcpy (ifra.ifra_name, tun_name);
|
||||||
|
|
||||||
|
pa = (struct sockaddr_in *)&ifra.ifra_addr;
|
||||||
|
pa->sin_len = sizeof (ifra.ifra_addr);
|
||||||
|
pa->sin_family = AF_INET;
|
||||||
|
res = inet_pton (AF_INET, addr, &pa->sin_addr);
|
||||||
|
if (!res)
|
||||||
|
goto exit_close;
|
||||||
|
|
||||||
|
memcpy (&ifra.ifra_broadaddr, &ifra.ifra_addr, sizeof (ifra.ifra_addr));
|
||||||
|
|
||||||
|
pa = (struct sockaddr_in *)&ifra.ifra_mask;
|
||||||
|
pa->sin_len = sizeof (ifra.ifra_addr);
|
||||||
|
pa->sin_family = AF_INET;
|
||||||
|
pa->sin_addr.s_addr = htonl (((unsigned int)(-1)) << (32 - prefix));
|
||||||
|
|
||||||
|
res = ioctl (fd, SIOCAIFADDR, &ifra);
|
||||||
|
|
||||||
|
exit_close:
|
||||||
|
close (fd);
|
||||||
|
exit:
|
||||||
|
return res;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_set_ipv6 (const char *addr, unsigned int prefix)
|
||||||
|
{
|
||||||
|
#if TARGET_OS_OSX
|
||||||
|
struct in6_aliasreq ifra = { .ifra_lifetime = { 0, 0, ND6_INFINITE_LIFETIME,
|
||||||
|
ND6_INFINITE_LIFETIME } };
|
||||||
|
uint8_t *bytes;
|
||||||
|
int res = -1;
|
||||||
|
int fd;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
fd = socket (AF_INET6, SOCK_DGRAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
strcpy (ifra.ifra_name, tun_name);
|
||||||
|
|
||||||
|
ifra.ifra_addr.sin6_len = sizeof (ifra.ifra_addr);
|
||||||
|
ifra.ifra_addr.sin6_family = AF_INET6;
|
||||||
|
res = inet_pton (AF_INET6, addr, &ifra.ifra_addr.sin6_addr);
|
||||||
|
if (!res)
|
||||||
|
goto exit_close;
|
||||||
|
|
||||||
|
ifra.ifra_prefixmask.sin6_len = sizeof (ifra.ifra_prefixmask);
|
||||||
|
ifra.ifra_prefixmask.sin6_family = AF_INET6;
|
||||||
|
bytes = (uint8_t *)&ifra.ifra_prefixmask.sin6_addr;
|
||||||
|
memset (bytes, 0xFF, 16);
|
||||||
|
bytes[prefix / 8] <<= prefix % 8;
|
||||||
|
prefix += prefix % 8;
|
||||||
|
for (i = prefix / 8; i < 16; i++)
|
||||||
|
bytes[i] = 0;
|
||||||
|
|
||||||
|
res = ioctl (fd, SIOCAIFADDR_IN6, &ifra);
|
||||||
|
|
||||||
|
exit_close:
|
||||||
|
close (fd);
|
||||||
|
exit:
|
||||||
|
return res;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
hev_tunnel_get_name (void)
|
||||||
|
{
|
||||||
|
return tun_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
hev_tunnel_get_index (void)
|
||||||
|
{
|
||||||
|
static char tun_index[16];
|
||||||
|
unsigned int index;
|
||||||
|
|
||||||
|
index = if_nametoindex (tun_name);
|
||||||
|
snprintf (tun_index, sizeof (tun_index) - 1, "%d", index);
|
||||||
|
return tun_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_add_task (int fd, HevTask *task)
|
||||||
|
{
|
||||||
|
return hev_task_add_fd (task, fd, POLLIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_tunnel_del_task (int fd, HevTask *task)
|
||||||
|
{
|
||||||
|
hev_task_del_fd (task, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __APPLE__ || __MACH__ */
|
||||||
76
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel-macos.h
Normal file
76
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel-macos.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-tunnel-macos.h
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2023 - 2025 hev
|
||||||
|
Description : Tunnel on MacOS
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_TUNNEL_MACOS_H__
|
||||||
|
#define __HEV_TUNNEL_MACOS_H__
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
static inline struct pbuf *
|
||||||
|
hev_tunnel_read (int fd, int mtu, HevTaskIOYielder yielder, void *yielder_data)
|
||||||
|
{
|
||||||
|
struct iovec iov[2];
|
||||||
|
struct pbuf *buf;
|
||||||
|
uint32_t type;
|
||||||
|
ssize_t s;
|
||||||
|
|
||||||
|
buf = pbuf_alloc (PBUF_RAW, mtu, PBUF_RAM);
|
||||||
|
if (!buf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
iov[0].iov_base = &type;
|
||||||
|
iov[0].iov_len = sizeof (type);
|
||||||
|
iov[1].iov_base = buf->payload;
|
||||||
|
iov[1].iov_len = buf->len;
|
||||||
|
|
||||||
|
s = hev_task_io_readv (fd, iov, 2, yielder, yielder_data);
|
||||||
|
if (s <= (ssize_t)sizeof (type)) {
|
||||||
|
pbuf_free (buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf->tot_len = s - sizeof (type);
|
||||||
|
buf->len = s - sizeof (type);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ssize_t
|
||||||
|
hev_tunnel_write (int fd, struct pbuf *buf)
|
||||||
|
{
|
||||||
|
struct iovec iov[512];
|
||||||
|
struct pbuf *p = buf;
|
||||||
|
uint32_t type = 0;
|
||||||
|
ssize_t res;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
iov[0].iov_base = &type;
|
||||||
|
iov[0].iov_len = sizeof (type);
|
||||||
|
|
||||||
|
for (i = 1; p && (i < 512); p = p->next) {
|
||||||
|
iov[i].iov_base = p->payload;
|
||||||
|
iov[i].iov_len = p->len;
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (!type && p->len) {
|
||||||
|
if (((*(uint8_t *)p->payload >> 4) & 0xF) == 4)
|
||||||
|
type = htonl (AF_INET);
|
||||||
|
else
|
||||||
|
type = htonl (AF_INET6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res = writev (fd, iov, i);
|
||||||
|
if (res <= (ssize_t)sizeof (type))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __HEV_TUNNEL_MACOS_H__ */
|
||||||
225
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel-netbsd.c
Normal file
225
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel-netbsd.c
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-tunnel-netbsd.c
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2025 hev
|
||||||
|
Description : Tunnel on NetBSD
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__NetBSD__)
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <net/if_tun.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/in_var.h>
|
||||||
|
#include <netinet6/nd6.h>
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
#include <hev-task-io.h>
|
||||||
|
|
||||||
|
#include "hev-tunnel.h"
|
||||||
|
|
||||||
|
static char tun_name[IFNAMSIZ];
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_open (const char *name, int multi_queue)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
int one = 1;
|
||||||
|
int res;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
snprintf (buf, sizeof (buf), "/dev/%s", name);
|
||||||
|
fd = hev_task_io_open (buf, O_RDWR);
|
||||||
|
if (fd < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
res = ioctl (fd, FIONBIO, (char *)&one);
|
||||||
|
if (res < 0)
|
||||||
|
goto fail_close;
|
||||||
|
|
||||||
|
strncpy (tun_name, name, IFNAMSIZ - 1);
|
||||||
|
return fd;
|
||||||
|
|
||||||
|
fail_close:
|
||||||
|
close (fd);
|
||||||
|
fail:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_tunnel_close (int fd)
|
||||||
|
{
|
||||||
|
struct ifreq ifr = { 0 };
|
||||||
|
|
||||||
|
close (fd);
|
||||||
|
|
||||||
|
fd = socket (AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memcpy (ifr.ifr_name, tun_name, IFNAMSIZ);
|
||||||
|
ioctl (fd, SIOCIFDESTROY, (void *)&ifr);
|
||||||
|
|
||||||
|
close (fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_set_mtu (int mtu)
|
||||||
|
{
|
||||||
|
int fd, res = -1;
|
||||||
|
struct ifreq ifr = { .ifr_mtu = mtu };
|
||||||
|
|
||||||
|
fd = socket (AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
memcpy (ifr.ifr_name, tun_name, IFNAMSIZ);
|
||||||
|
res = ioctl (fd, SIOCSIFMTU, (void *)&ifr);
|
||||||
|
|
||||||
|
close (fd);
|
||||||
|
exit:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_set_state (int state)
|
||||||
|
{
|
||||||
|
struct ifreq ifr = { 0 };
|
||||||
|
int res = -1;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = socket (AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
memcpy (ifr.ifr_name, tun_name, IFNAMSIZ);
|
||||||
|
res = ioctl (fd, SIOCGIFFLAGS, (void *)&ifr);
|
||||||
|
if (res < 0)
|
||||||
|
goto exit_close;
|
||||||
|
|
||||||
|
if (state)
|
||||||
|
ifr.ifr_flags |= IFF_UP;
|
||||||
|
else
|
||||||
|
ifr.ifr_flags &= ~IFF_UP;
|
||||||
|
res = ioctl (fd, SIOCSIFFLAGS, (void *)&ifr);
|
||||||
|
|
||||||
|
exit_close:
|
||||||
|
close (fd);
|
||||||
|
exit:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_set_ipv4 (const char *addr, unsigned int prefix)
|
||||||
|
{
|
||||||
|
struct ifaliasreq ifra = { 0 };
|
||||||
|
struct sockaddr_in *pa;
|
||||||
|
int res = -1;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = socket (AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
strcpy (ifra.ifra_name, tun_name);
|
||||||
|
|
||||||
|
pa = (struct sockaddr_in *)&ifra.ifra_addr;
|
||||||
|
pa->sin_len = sizeof (ifra.ifra_addr);
|
||||||
|
pa->sin_family = AF_INET;
|
||||||
|
res = inet_pton (AF_INET, addr, &pa->sin_addr);
|
||||||
|
if (!res)
|
||||||
|
goto exit_close;
|
||||||
|
|
||||||
|
memcpy (&ifra.ifra_broadaddr, &ifra.ifra_addr, sizeof (ifra.ifra_addr));
|
||||||
|
|
||||||
|
pa = (struct sockaddr_in *)&ifra.ifra_mask;
|
||||||
|
pa->sin_len = sizeof (ifra.ifra_addr);
|
||||||
|
pa->sin_family = AF_INET;
|
||||||
|
pa->sin_addr.s_addr = htonl (((unsigned int)(-1)) << (32 - prefix));
|
||||||
|
|
||||||
|
res = ioctl (fd, SIOCAIFADDR, &ifra);
|
||||||
|
|
||||||
|
exit_close:
|
||||||
|
close (fd);
|
||||||
|
exit:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_set_ipv6 (const char *addr, unsigned int prefix)
|
||||||
|
{
|
||||||
|
struct in6_aliasreq ifra = { .ifra_lifetime = { 0, 0, ND6_INFINITE_LIFETIME,
|
||||||
|
ND6_INFINITE_LIFETIME } };
|
||||||
|
uint8_t *bytes;
|
||||||
|
int res = -1;
|
||||||
|
int fd;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
fd = socket (AF_INET6, SOCK_DGRAM, 0);
|
||||||
|
if (fd < 0)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
strcpy (ifra.ifra_name, tun_name);
|
||||||
|
|
||||||
|
ifra.ifra_addr.sin6_len = sizeof (ifra.ifra_addr);
|
||||||
|
ifra.ifra_addr.sin6_family = AF_INET6;
|
||||||
|
res = inet_pton (AF_INET6, addr, &ifra.ifra_addr.sin6_addr);
|
||||||
|
if (!res)
|
||||||
|
goto exit_close;
|
||||||
|
|
||||||
|
ifra.ifra_prefixmask.sin6_len = sizeof (ifra.ifra_prefixmask);
|
||||||
|
ifra.ifra_prefixmask.sin6_family = AF_INET6;
|
||||||
|
bytes = (uint8_t *)&ifra.ifra_prefixmask.sin6_addr;
|
||||||
|
memset (bytes, 0xFF, 16);
|
||||||
|
bytes[prefix / 8] <<= prefix % 8;
|
||||||
|
prefix += prefix % 8;
|
||||||
|
for (i = prefix / 8; i < 16; i++)
|
||||||
|
bytes[i] = 0;
|
||||||
|
|
||||||
|
res = ioctl (fd, SIOCAIFADDR_IN6, &ifra);
|
||||||
|
|
||||||
|
exit_close:
|
||||||
|
close (fd);
|
||||||
|
exit:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
hev_tunnel_get_name (void)
|
||||||
|
{
|
||||||
|
return tun_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
hev_tunnel_get_index (void)
|
||||||
|
{
|
||||||
|
static char tun_index[16];
|
||||||
|
unsigned int index;
|
||||||
|
|
||||||
|
index = if_nametoindex (tun_name);
|
||||||
|
snprintf (tun_index, sizeof (tun_index) - 1, "%d", index);
|
||||||
|
return tun_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_add_task (int fd, HevTask *task)
|
||||||
|
{
|
||||||
|
return hev_task_add_fd (task, fd, POLLIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_tunnel_del_task (int fd, HevTask *task)
|
||||||
|
{
|
||||||
|
hev_task_del_fd (task, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __NetBSD__ */
|
||||||
13
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel-netbsd.h
Normal file
13
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel-netbsd.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-tunnel-netbsd.h
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2025 hev
|
||||||
|
Description : Tunnel on NetBSD
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_TUNNEL_NETBSD_H__
|
||||||
|
#define __HEV_TUNNEL_NETBSD_H__
|
||||||
|
|
||||||
|
#endif /* __HEV_TUNNEL_NETBSD_H__ */
|
||||||
214
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel-windows.c
Normal file
214
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel-windows.c
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-tunnel-windows.c
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2025 hev
|
||||||
|
Description : Tunnel on Windows
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__MSYS__)
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include <hev-task.h>
|
||||||
|
#include <hev-task-io.h>
|
||||||
|
#include <hev-memory-allocator.h>
|
||||||
|
|
||||||
|
#include "hev-wintun.h"
|
||||||
|
|
||||||
|
#include "hev-tunnel.h"
|
||||||
|
|
||||||
|
typedef struct _HevPBuf HevPBuf;
|
||||||
|
|
||||||
|
struct _HevPBuf
|
||||||
|
{
|
||||||
|
struct pbuf_custom base;
|
||||||
|
void *mem;
|
||||||
|
};
|
||||||
|
|
||||||
|
static HevWinTun *wintun;
|
||||||
|
static HevWinTunAdapter *adapter;
|
||||||
|
static HevWinTunSession *session;
|
||||||
|
static char tun_name[IFNAMSIZ];
|
||||||
|
|
||||||
|
static void
|
||||||
|
hev_pbuf_free (struct pbuf *p)
|
||||||
|
{
|
||||||
|
HevPBuf *buf = (HevPBuf *)p;
|
||||||
|
|
||||||
|
hev_wintun_session_release (session, buf->mem);
|
||||||
|
hev_free (buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_open (const char *name, int multi_queue)
|
||||||
|
{
|
||||||
|
wintun = hev_wintun_open ();
|
||||||
|
if (!wintun)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
adapter = hev_wintun_adapter_create (name);
|
||||||
|
if (!adapter)
|
||||||
|
goto free;
|
||||||
|
|
||||||
|
strncpy (tun_name, name, IFNAMSIZ - 1);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
free:
|
||||||
|
hev_wintun_close (wintun);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_tunnel_close (int fd)
|
||||||
|
{
|
||||||
|
if (session)
|
||||||
|
hev_wintun_session_stop (session);
|
||||||
|
hev_wintun_adapter_close (adapter);
|
||||||
|
hev_wintun_close (wintun);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_set_mtu (int mtu)
|
||||||
|
{
|
||||||
|
return hev_wintun_adapter_set_mtu (adapter, mtu);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_set_state (int state)
|
||||||
|
{
|
||||||
|
if (state) {
|
||||||
|
session = hev_wintun_session_start (adapter);
|
||||||
|
if (!session)
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
if (session) {
|
||||||
|
hev_wintun_session_stop (session);
|
||||||
|
session = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_set_ipv4 (const char *addr, unsigned int prefix)
|
||||||
|
{
|
||||||
|
char ipv4[4];
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = inet_pton (AF_INET, addr, ipv4);
|
||||||
|
if (!res)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return hev_wintun_adapter_set_ipv4 (adapter, ipv4, prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_set_ipv6 (const char *addr, unsigned int prefix)
|
||||||
|
{
|
||||||
|
char ipv6[16];
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = inet_pton (AF_INET6, addr, ipv6);
|
||||||
|
if (!res)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return hev_wintun_adapter_set_ipv6 (adapter, ipv6, prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
hev_tunnel_get_name (void)
|
||||||
|
{
|
||||||
|
return tun_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
hev_tunnel_get_index (void)
|
||||||
|
{
|
||||||
|
static char tun_index[16];
|
||||||
|
int index;
|
||||||
|
|
||||||
|
index = hev_wintun_adapter_get_index (adapter);
|
||||||
|
if (index < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
snprintf (tun_index, sizeof (tun_index) - 1, "%d", index);
|
||||||
|
return tun_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hev_tunnel_add_task (int fd, HevTask *task)
|
||||||
|
{
|
||||||
|
void *handle = hev_wintun_session_get_read_wait_event (session);
|
||||||
|
return hev_task_add_whandle (task, handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_tunnel_del_task (int fd, HevTask *task)
|
||||||
|
{
|
||||||
|
void *handle = hev_wintun_session_get_read_wait_event (session);
|
||||||
|
hev_task_del_whandle (task, handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pbuf *
|
||||||
|
hev_tunnel_read (int fd, int mtu, HevTaskIOYielder yielder, void *yielder_data)
|
||||||
|
{
|
||||||
|
HevPBuf *buf;
|
||||||
|
void *packet;
|
||||||
|
int spin = 0;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
retry:
|
||||||
|
packet = hev_wintun_session_receive (session, &size);
|
||||||
|
if (!packet) {
|
||||||
|
if (hev_wintun_get_last_error () == HEV_WINTUN_EAGAIN) {
|
||||||
|
if (spin++ < 1000) {
|
||||||
|
hev_task_yield (HEV_TASK_YIELD);
|
||||||
|
} else if (yielder) {
|
||||||
|
if (yielder (HEV_TASK_WAITIO, yielder_data))
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
hev_task_yield (HEV_TASK_WAITIO);
|
||||||
|
}
|
||||||
|
goto retry;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = hev_malloc (sizeof (HevPBuf));
|
||||||
|
if (!buf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
buf->mem = packet;
|
||||||
|
buf->base.custom_free_function = hev_pbuf_free;
|
||||||
|
pbuf_alloced_custom (PBUF_RAW, size, PBUF_RAM, &buf->base, packet, size);
|
||||||
|
|
||||||
|
return &buf->base.pbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
hev_tunnel_write (int fd, struct pbuf *buf)
|
||||||
|
{
|
||||||
|
struct pbuf *p = buf;
|
||||||
|
void *packet;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
packet = hev_wintun_session_allocate (session, p->tot_len);
|
||||||
|
if (!packet)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (size = 0; p; p = p->next) {
|
||||||
|
memcpy (packet + size, p->payload, p->len);
|
||||||
|
size += p->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
hev_wintun_session_send (session, packet);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __MSYS__ */
|
||||||
17
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel-windows.h
Normal file
17
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel-windows.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-tunnel-windows.h
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2025 hev
|
||||||
|
Description : Tunnel on Windows
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_TUNNEL_WINDOWS_H__
|
||||||
|
#define __HEV_TUNNEL_WINDOWS_H__
|
||||||
|
|
||||||
|
struct pbuf *hev_tunnel_read (int fd, int mtu, HevTaskIOYielder yielder,
|
||||||
|
void *yielder_data);
|
||||||
|
ssize_t hev_tunnel_write (int fd, struct pbuf *buf);
|
||||||
|
|
||||||
|
#endif /* __HEV_TUNNEL_WINDOWS_H__ */
|
||||||
93
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel.h
Normal file
93
app/src/main/cpp/hev-socks5-tunnel/src/hev-tunnel.h
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-tunnel.h
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2023 - 2025 hev
|
||||||
|
Description : Tunnel
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_TUNNEL_H__
|
||||||
|
#define __HEV_TUNNEL_H__
|
||||||
|
|
||||||
|
#include <lwip/pbuf.h>
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
#include "hev-tunnel-linux.h"
|
||||||
|
#endif /* __linux__ */
|
||||||
|
|
||||||
|
#if defined(__FreeBSD__)
|
||||||
|
#include "hev-tunnel-freebsd.h"
|
||||||
|
#endif /* __FreeBSD__ */
|
||||||
|
|
||||||
|
#if defined(__NetBSD__)
|
||||||
|
#include "hev-tunnel-netbsd.h"
|
||||||
|
#endif /* __NetBSD__ */
|
||||||
|
|
||||||
|
#if defined(__APPLE__) || defined(__MACH__)
|
||||||
|
#include "hev-tunnel-macos.h"
|
||||||
|
#endif /* __APPLE__ || __MACH__ */
|
||||||
|
|
||||||
|
#if defined(__MSYS__)
|
||||||
|
#include "hev-tunnel-windows.h"
|
||||||
|
#endif /* __MSYS__ */
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
|
||||||
|
static inline struct pbuf *
|
||||||
|
hev_tunnel_read (int fd, int mtu, HevTaskIOYielder yielder, void *yielder_data)
|
||||||
|
{
|
||||||
|
struct pbuf *buf;
|
||||||
|
ssize_t s;
|
||||||
|
|
||||||
|
buf = pbuf_alloc (PBUF_RAW, mtu, PBUF_RAM);
|
||||||
|
if (!buf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
s = hev_task_io_read (fd, buf->payload, buf->len, yielder, yielder_data);
|
||||||
|
if (s <= 0) {
|
||||||
|
pbuf_free (buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf->tot_len = s;
|
||||||
|
buf->len = s;
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline ssize_t
|
||||||
|
hev_tunnel_write (int fd, struct pbuf *buf)
|
||||||
|
{
|
||||||
|
struct iovec iov[512];
|
||||||
|
struct pbuf *p = buf;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!p->next)
|
||||||
|
return write (fd, p->payload, p->len);
|
||||||
|
|
||||||
|
for (i = 0; p && (i < 512); p = p->next) {
|
||||||
|
iov[i].iov_base = p->payload;
|
||||||
|
iov[i].iov_len = p->len;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return writev (fd, iov, i);
|
||||||
|
}
|
||||||
|
#endif /* defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) */
|
||||||
|
|
||||||
|
int hev_tunnel_open (const char *name, int multi_queue);
|
||||||
|
void hev_tunnel_close (int fd);
|
||||||
|
|
||||||
|
int hev_tunnel_set_mtu (int mtu);
|
||||||
|
int hev_tunnel_set_state (int state);
|
||||||
|
|
||||||
|
int hev_tunnel_set_ipv4 (const char *addr, unsigned int prefix);
|
||||||
|
int hev_tunnel_set_ipv6 (const char *addr, unsigned int prefix);
|
||||||
|
|
||||||
|
const char *hev_tunnel_get_name (void);
|
||||||
|
const char *hev_tunnel_get_index (void);
|
||||||
|
|
||||||
|
int hev_tunnel_add_task (int fd, HevTask *task);
|
||||||
|
void hev_tunnel_del_task (int fd, HevTask *task);
|
||||||
|
|
||||||
|
#endif /* __HEV_TUNNEL_H__ */
|
||||||
106
app/src/main/cpp/hev-socks5-tunnel/src/misc/hev-compiler.h
Normal file
106
app/src/main/cpp/hev-socks5-tunnel/src/misc/hev-compiler.h
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-compiler.h
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2019 - 2023 hev
|
||||||
|
Description : Compiler
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_COMPILER_H__
|
||||||
|
#define __HEV_COMPILER_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ALIGN_UP(addr, align) \
|
||||||
|
((addr + (typeof (addr))align - 1) & ~((typeof (addr))align - 1))
|
||||||
|
|
||||||
|
#define ALIGN_DOWN(addr, align) ((addr) & ~((typeof (addr))align - 1))
|
||||||
|
|
||||||
|
#ifndef ARRAY_SIZE
|
||||||
|
#define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef EXPORT_SYMBOL
|
||||||
|
#define EXPORT_SYMBOL __attribute__ ((visibility ("default")))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define barrier() __asm__ __volatile__ ("" : : : "memory")
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
__read_once_size (void *dst, const volatile void *src, int size)
|
||||||
|
{
|
||||||
|
switch (size) {
|
||||||
|
case sizeof (char):
|
||||||
|
*(char *)dst = *(volatile char *)src;
|
||||||
|
break;
|
||||||
|
case sizeof (short):
|
||||||
|
*(short *)dst = *(volatile short *)src;
|
||||||
|
break;
|
||||||
|
case sizeof (int):
|
||||||
|
*(int *)dst = *(volatile int *)src;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
barrier ();
|
||||||
|
__builtin_memcpy ((void *)dst, (const void *)src, size);
|
||||||
|
barrier ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
__write_once_size (volatile void *dst, const void *src, int size)
|
||||||
|
{
|
||||||
|
switch (size) {
|
||||||
|
case sizeof (char):
|
||||||
|
*(volatile char *)dst = *(char *)src;
|
||||||
|
break;
|
||||||
|
case sizeof (short):
|
||||||
|
*(volatile short *)dst = *(short *)src;
|
||||||
|
break;
|
||||||
|
case sizeof (int):
|
||||||
|
*(volatile int *)dst = *(int *)src;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
barrier ();
|
||||||
|
__builtin_memcpy ((void *)dst, (const void *)src, size);
|
||||||
|
barrier ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define READ_ONCE(x) \
|
||||||
|
({ \
|
||||||
|
union \
|
||||||
|
{ \
|
||||||
|
typeof (x) __val; \
|
||||||
|
char __c[1]; \
|
||||||
|
} __u; \
|
||||||
|
__read_once_size (__u.__c, &(x), sizeof (x)); \
|
||||||
|
__u.__val; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define WRITE_ONCE(x, val) \
|
||||||
|
({ \
|
||||||
|
union \
|
||||||
|
{ \
|
||||||
|
typeof (x) __val; \
|
||||||
|
char __c[1]; \
|
||||||
|
} __u = { .__val = (typeof (x))(val) }; \
|
||||||
|
__write_once_size (&(x), __u.__c, sizeof (x)); \
|
||||||
|
__u.__val; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#ifndef container_of
|
||||||
|
#define container_of(ptr, type, member) \
|
||||||
|
({ \
|
||||||
|
void *__mptr = (void *)(ptr); \
|
||||||
|
((type *)(__mptr - offsetof (type, member))); \
|
||||||
|
})
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __HEV_COMPILER_H__ */
|
||||||
61
app/src/main/cpp/hev-socks5-tunnel/src/misc/hev-exec.c
Normal file
61
app/src/main/cpp/hev-socks5-tunnel/src/misc/hev-exec.c
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-exec.c
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2023 hev
|
||||||
|
Description : Exec
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#include <Availability.h>
|
||||||
|
#include <AvailabilityMacros.h>
|
||||||
|
#include <TargetConditionals.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "hev-logger.h"
|
||||||
|
|
||||||
|
#include "hev-exec.h"
|
||||||
|
|
||||||
|
#if TARGET_OS_TV
|
||||||
|
void
|
||||||
|
hev_exec_run (const char *script_path, const char *tun_name,
|
||||||
|
const char *tun_index, int wait)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static void
|
||||||
|
signal_handler (int signum)
|
||||||
|
{
|
||||||
|
waitpid (-1, NULL, WNOHANG);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hev_exec_run (const char *script_path, const char *tun_name,
|
||||||
|
const char *tun_index, int wait)
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
signal (SIGCHLD, signal_handler);
|
||||||
|
|
||||||
|
pid = fork ();
|
||||||
|
if (pid < 0) {
|
||||||
|
LOG_E ("exec fork");
|
||||||
|
return;
|
||||||
|
} else if (pid != 0) {
|
||||||
|
if (wait)
|
||||||
|
waitpid (pid, NULL, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
execl (script_path, script_path, tun_name, tun_index, NULL);
|
||||||
|
|
||||||
|
LOG_E ("exec %s %s %s", script_path, tun_name, tun_index);
|
||||||
|
exit (-1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
16
app/src/main/cpp/hev-socks5-tunnel/src/misc/hev-exec.h
Normal file
16
app/src/main/cpp/hev-socks5-tunnel/src/misc/hev-exec.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
============================================================================
|
||||||
|
Name : hev-exec.h
|
||||||
|
Author : hev <r@hev.cc>
|
||||||
|
Copyright : Copyright (c) 2023 - 2025 hev
|
||||||
|
Description : Exec
|
||||||
|
============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __HEV_EXEC_H__
|
||||||
|
#define __HEV_EXEC_H__
|
||||||
|
|
||||||
|
void hev_exec_run (const char *script_path, const char *tun_name,
|
||||||
|
const char *tun_index, int wait);
|
||||||
|
|
||||||
|
#endif /* __HEV_EXEC_H__ */
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user