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