Replace tun2socks with hev-socks5-tunnel (#94)

This commit is contained in:
dovecoteescapee 2024-08-18 22:02:46 +03:00 committed by GitHub
parent 26463ae30f
commit 31d75606bc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 145 additions and 161 deletions

1
.gitignore vendored
View File

@ -14,3 +14,4 @@
.externalNativeBuild .externalNativeBuild
.cxx .cxx
local.properties local.properties
/app/src/main/jniLibs

8
.gitmodules vendored
View File

@ -1,6 +1,6 @@
[submodule "app/libs/tun2socks"] [submodule "hev-socks5-tunnel"]
path = app/libs/tun2socks path = app/src/main/jni/hev-socks5-tunnel
url = https://github.com/dovecoteescapee/tun2socks.git url = https://github.com/heiher/hev-socks5-tunnel.git
[submodule "app/src/main/cpp/byedpi"] [submodule "byedpi"]
path = app/src/main/cpp/byedpi path = app/src/main/cpp/byedpi
url = https://github.com/hufrea/byedpi.git url = https://github.com/hufrea/byedpi.git

View File

@ -2,7 +2,11 @@
<project version="4"> <project version="4">
<component name="VcsDirectoryMappings"> <component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" /> <mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="$PROJECT_DIR$/app/libs/tun2socks" vcs="Git" />
<mapping directory="$PROJECT_DIR$/app/src/main/cpp/byedpi" vcs="Git" /> <mapping directory="$PROJECT_DIR$/app/src/main/cpp/byedpi" vcs="Git" />
<mapping directory="$PROJECT_DIR$/app/src/main/jni/hev-socks5-tunnel" vcs="Git" />
<mapping directory="$PROJECT_DIR$/app/src/main/jni/hev-socks5-tunnel/src/core" vcs="Git" />
<mapping directory="$PROJECT_DIR$/app/src/main/jni/hev-socks5-tunnel/third-part/hev-task-system" vcs="Git" />
<mapping directory="$PROJECT_DIR$/app/src/main/jni/hev-socks5-tunnel/third-part/lwip" vcs="Git" />
<mapping directory="$PROJECT_DIR$/app/src/main/jni/hev-socks5-tunnel/third-part/yaml" vcs="Git" />
</component> </component>
</project> </project>

View File

@ -1,5 +1,3 @@
import com.android.build.gradle.internal.tasks.factory.dependsOn
plugins { plugins {
id("com.android.application") id("com.android.application")
id("org.jetbrains.kotlin.android") id("org.jetbrains.kotlin.android")
@ -13,10 +11,17 @@ android {
applicationId = "io.github.dovecoteescapee.byedpi" applicationId = "io.github.dovecoteescapee.byedpi"
minSdk = 21 minSdk = 21
targetSdk = 34 targetSdk = 34
versionCode = 7 versionCode = 8
versionName = "1.0.2" versionName = "1.1.0-beta"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
ndk {
abiFilters.add("armeabi-v7a")
abiFilters.add("arm64-v8a")
abiFilters.add("x86")
abiFilters.add("x86_64")
}
} }
buildFeatures { buildFeatures {
@ -61,8 +66,6 @@ android {
} }
dependencies { dependencies {
implementation(files("libs/tun2socks.aar"))
implementation("androidx.fragment:fragment-ktx:1.8.2") implementation("androidx.fragment:fragment-ktx:1.8.2")
implementation("androidx.core:core-ktx:1.13.1") implementation("androidx.core:core-ktx:1.13.1")
implementation("androidx.appcompat:appcompat:1.7.0") implementation("androidx.appcompat:appcompat:1.7.0")
@ -77,75 +80,25 @@ dependencies {
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1") androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
} }
abstract class BaseTun2SocksTask : DefaultTask() { tasks.register<Exec>("runNdkBuild") {
@get:InputDirectory
val tun2socksDir: File
get() = project.file("libs/tun2socks")
@get:OutputFile
val tun2socksOutput: File
get() = project.file("libs/tun2socks.aar")
@Internal
protected fun isUpToDate(): Boolean {
if (tun2socksOutput.exists()) {
val lastModified = tun2socksOutput.lastModified()
return !tun2socksDir.walkTopDown().any {
it.isFile && it.lastModified() > lastModified
}
}
return false
}
}
abstract class GetGomobileBind : BaseTun2SocksTask() {
@TaskAction
fun getBind() {
if (isUpToDate()) {
logger.lifecycle("No changes detected, skipping getBind.")
return
}
project.exec {
workingDir = tun2socksDir
commandLine("go", "get", "golang.org/x/mobile/bind")
}
}
}
abstract class BuildTun2Socks : BaseTun2SocksTask() {
@TaskAction
fun buildTun2Socks() {
if (isUpToDate()) {
logger.lifecycle("No changes detected, skipping buildTun2Socks.")
return
}
project.exec {
workingDir = tun2socksDir
commandLine(
"gomobile", "bind",
"-target", "android",
"-androidapi", "21",
"-o", tun2socksOutput,
"-trimpath",
"./engine"
)
}
}
}
val getGomobileBind = tasks.register<GetGomobileBind>("getGomobileBind") {
group = "build" group = "build"
description = "Get gomobile bind for compiling tun2socks"
val ndkDir = android.ndkDirectory
executable = if (System.getProperty("os.name").startsWith("Windows", ignoreCase = true)) {
"$ndkDir\\ndk-build.cmd"
} else {
"$ndkDir/ndk-build"
}
setArgs(listOf(
"NDK_PROJECT_PATH=build/intermediates/ndkBuild",
"NDK_LIBS_OUT=src/main/jniLibs",
"APP_BUILD_SCRIPT=src/main/jni/Android.mk",
"NDK_APPLICATION_MK=src/main/jni/Application.mk"
))
println("Command: $commandLine")
} }
val buildTun2Socks = tasks.register<BuildTun2Socks>("buildTun2Socks") { tasks.preBuild {
group = "build" dependsOn("runNdkBuild")
description = "Build tun2socks for Android" }
dependsOn(getGomobileBind)
}
tasks.preBuild.dependsOn(buildTun2Socks)

@ -1 +0,0 @@
Subproject commit e083dafcf534d85e7fce86b3d48ee5c7a63c604e

View File

@ -1,53 +1,14 @@
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html.
# For more examples on how to use CMake, see https://github.com/android/ndk-samples.
# Sets the minimum CMake version required for this project.
cmake_minimum_required(VERSION 3.22.1) cmake_minimum_required(VERSION 3.22.1)
# Declares the project name. The project name can be accessed via ${ PROJECT_NAME}, project(byedpi_native)
# Since this is the top level CMakeLists.txt, the project name is also accessible
# with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level
# build script scope).
project("byedpi")
# Creates and names a library, sets it as either STATIC file(GLOB BYE_DPI_SRC byedpi/*.c)
# or SHARED, and provides the relative paths to its source code. list(REMOVE_ITEM BYE_DPI_SRC ${CMAKE_CURRENT_SOURCE_DIR}/byedpi/win_service.c)
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
#
# In this top level CMakeLists.txt, ${CMAKE_PROJECT_NAME} is used to define
# the target library name; in the sub-module's CMakeLists.txt, ${PROJECT_NAME}
# is preferred for the same purpose.
#
# In order to load a library into your app from Java/Kotlin, you must call
# System.loadLibrary() and pass the name of the library defined here;
# for GameActivity/NativeActivity derived applications, the same library name must be
# used in the AndroidManifest.xml file.
add_library(${CMAKE_PROJECT_NAME} SHARED
# List C/C++ source files with relative paths to this CMakeLists.txt.
byedpi/conev.c
byedpi/desync.c
byedpi/extend.c
byedpi/packets.c
byedpi/proxy.c
byedpi/main.c
byedpi/mpool.c
native-lib.c
utils.c
)
include_directories("byedpi") add_library(byedpi SHARED ${BYE_DPI_SRC} native-lib.c utils.c)
target_include_directories(byedpi PRIVATE byedpi)
set(CMAKE_C_FLAGS "-std=c99 -O2 -D_XOPEN_SOURCE=500") target_compile_options(byedpi PRIVATE -std=c99 -O2 -D_XOPEN_SOURCE=500)
target_compile_definitions(byedpi PRIVATE ANDROID_APP)
add_compile_definitions(ANDROID_APP) target_link_libraries(byedpi PRIVATE android log)
# Specifies libraries CMake should link to your target library. You
# can link libraries from various origins, such as libraries defined in this
# build script, prebuilt third-party libraries, or Android system libraries.
target_link_libraries(${CMAKE_PROJECT_NAME}
# List libraries link to the target library
android
log
)

View File

@ -8,9 +8,6 @@ import android.os.Build
import android.os.ParcelFileDescriptor import android.os.ParcelFileDescriptor
import android.util.Log import android.util.Log
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import engine.Engine
import engine.Key
import io.github.dovecoteescapee.byedpi.BuildConfig
import io.github.dovecoteescapee.byedpi.R import io.github.dovecoteescapee.byedpi.R
import io.github.dovecoteescapee.byedpi.activities.MainActivity import io.github.dovecoteescapee.byedpi.activities.MainActivity
import io.github.dovecoteescapee.byedpi.core.ByeDpiProxy import io.github.dovecoteescapee.byedpi.core.ByeDpiProxy
@ -23,11 +20,12 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.File
class ByeDpiVpnService : LifecycleVpnService() { class ByeDpiVpnService : LifecycleVpnService() {
private val proxy = ByeDpiProxy() private val byeDpiProxy = ByeDpiProxy()
private var proxyJob: Job? = null private var proxyJob: Job? = null
private var vpn: ParcelFileDescriptor? = null private var tunFd: ParcelFileDescriptor? = null
private val mutex = Mutex() private val mutex = Mutex()
private var stopping: Boolean = false private var stopping: Boolean = false
@ -138,7 +136,7 @@ class ByeDpiVpnService : LifecycleVpnService() {
val preferences = getByeDpiPreferences() val preferences = getByeDpiPreferences()
proxyJob = lifecycleScope.launch(Dispatchers.IO) { proxyJob = lifecycleScope.launch(Dispatchers.IO) {
val code = proxy.startProxy(preferences) val code = byeDpiProxy.startProxy(preferences)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
if (code != 0) { if (code != 0) {
@ -164,7 +162,7 @@ class ByeDpiVpnService : LifecycleVpnService() {
return return
} }
proxy.stopProxy() byeDpiProxy.stopProxy()
proxyJob?.join() ?: throw IllegalStateException("ProxyJob field null") proxyJob?.join() ?: throw IllegalStateException("ProxyJob field null")
proxyJob = null proxyJob = null
@ -174,7 +172,7 @@ class ByeDpiVpnService : LifecycleVpnService() {
private fun startTun2Socks() { private fun startTun2Socks() {
Log.i(TAG, "Starting tun2socks") Log.i(TAG, "Starting tun2socks")
if (vpn != null) { if (tunFd != null) {
throw IllegalStateException("VPN field not null") throw IllegalStateException("VPN field not null")
} }
@ -182,22 +180,49 @@ class ByeDpiVpnService : LifecycleVpnService() {
val port = sharedPreferences.getString("byedpi_proxy_port", null)?.toInt() ?: 1080 val port = sharedPreferences.getString("byedpi_proxy_port", null)?.toInt() ?: 1080
val dns = sharedPreferences.getStringNotNull("dns_ip", "1.1.1.1") val dns = sharedPreferences.getStringNotNull("dns_ip", "1.1.1.1")
val tun2socksConfig = """
| misc:
| task-stack-size: 81920
| socks5:
| mtu: 8500
| address: 127.0.0.1
| port: $port
| udp: udp
""".trimMargin("| ")
val configPath = try {
File.createTempFile("config", "tmp", cacheDir).apply {
writeText(tun2socksConfig)
}
} catch (e: Exception) {
Log.e(TAG, "Failed to create config file", e)
throw e
}
val vpn = createBuilder(dns).establish() val vpn = createBuilder(dns).establish()
?: throw IllegalStateException("VPN connection failed") ?: throw IllegalStateException("VPN connection failed")
this.vpn = vpn this.tunFd = vpn
// val fd = vpn.detachFd()
Engine.insert(createKey(vpn.fd, port)) Log.d(TAG, "Native tun2socks start")
Engine.start() TProxyService.TProxyStartService(configPath.absolutePath, vpn.fd)
Log.i(TAG, "Tun2Socks started") Log.i(TAG, "Tun2Socks started")
} }
private fun stopTun2Socks() { private fun stopTun2Socks() {
Log.i(TAG, "Stopping tun2socks") Log.i(TAG, "Stopping tun2socks")
// Engine.stop() // sometimes crashes with fdsan
vpn?.close() ?: Log.w(TAG, "VPN not running") // Is engine close sockets? TProxyService.TProxyStopService()
vpn = null Log.d(TAG, "Native tun2socks stopped done")
tunFd?.close() ?: Log.w(TAG, "VPN not running")
tunFd = null
try {
File(cacheDir, "config.tmp").delete()
} catch (e: SecurityException) {
Log.e(TAG, "Failed to delete config file", e)
}
Log.i(TAG, "Tun2socks stopped") Log.i(TAG, "Tun2socks stopped")
} }
@ -212,6 +237,7 @@ class ByeDpiVpnService : LifecycleVpnService() {
setStatus( setStatus(
when (newStatus) { when (newStatus) {
ServiceStatus.Connected -> AppStatus.Running ServiceStatus.Connected -> AppStatus.Running
ServiceStatus.Disconnected, ServiceStatus.Disconnected,
ServiceStatus.Failed -> { ServiceStatus.Failed -> {
proxyJob = null proxyJob = null
@ -261,23 +287,8 @@ class ByeDpiVpnService : LifecycleVpnService() {
builder.setMetered(false) builder.setMetered(false)
} }
builder.addDisallowedApplication("io.github.dovecoteescapee.byedpi") builder.addDisallowedApplication(applicationContext.packageName)
return builder return builder
} }
private fun createKey(fd: Int, port: Int): Key = Key().apply {
mark = 0
mtu = 0
device = "fd://${fd}"
setInterface("")
logLevel = if (BuildConfig.DEBUG) "debug" else "info"
proxy = "socks5://127.0.0.1:$port"
restAPI = ""
tcpSendBufferSize = ""
tcpReceiveBufferSize = ""
tcpModerateReceiveBuffer = false
}
} }

View File

@ -9,7 +9,7 @@ import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ServiceLifecycleDispatcher import androidx.lifecycle.ServiceLifecycleDispatcher
/** /**
* Based on @link [androidx.lifecycle.LifecycleService] * Based on [androidx.lifecycle.LifecycleService]
*/ */
open class LifecycleVpnService : VpnService(), LifecycleOwner { open class LifecycleVpnService : VpnService(), LifecycleOwner {
@Suppress("LeakingThis") @Suppress("LeakingThis")
@ -28,10 +28,10 @@ open class LifecycleVpnService : VpnService(), LifecycleOwner {
} }
@Deprecated("Deprecated in Java") @Deprecated("Deprecated in Java")
@Suppress("DEPRECATION")
@CallSuper @CallSuper
override fun onStart(intent: Intent?, startId: Int) { override fun onStart(intent: Intent?, startId: Int) {
dispatcher.onServicePreSuperOnStart() dispatcher.onServicePreSuperOnStart()
@Suppress("DEPRECATION")
super.onStart(intent, startId) super.onStart(intent, startId)
} }

View File

@ -0,0 +1,17 @@
package io.github.dovecoteescapee.byedpi.services
object TProxyService {
init {
System.loadLibrary("hev-socks5-tunnel")
}
@JvmStatic
external fun TProxyStartService(configPath: String, fd: Int)
@JvmStatic
external fun TProxyStopService()
@JvmStatic
@Suppress("unused")
external fun TProxyGetStats(): LongArray
}

View File

@ -0,0 +1,16 @@
# Copyright (C) 2023 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
include $(call all-subdir-makefiles)

View File

@ -0,0 +1,21 @@
# Copyright (C) 2023 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
APP_OPTIM := release
APP_PLATFORM := android-21
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
APP_CFLAGS := -O3 -DPKGNAME=io/github/dovecoteescapee/byedpi/services
APP_CPPFLAGS := -O3 -std=c++11
NDK_TOOLCHAIN_VERSION := clang

@ -0,0 +1 @@
Subproject commit 677bb4530cfc867cd44d88d298960c8d8d9fbfad