Skip to content

Commit 8ecb293

Browse files
committed
feat: add TUN2SOCKS(root) mode and unify root runtime
1 parent f66cead commit 8ecb293

93 files changed

Lines changed: 3281 additions & 1688 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,51 @@
11
# AsteriskNG
22

3-
An Xray client for Android, powered by [Xray-core](https://github.com/XTLS/Xray-core) and [AndroidLibXrayLite](https://github.com/2dust/AndroidLibXrayLite).
3+
An Xray client for Android, powered by [Xray-core](https://github.com/XTLS/Xray-core), [AndroidLibXrayLite](https://github.com/2dust/AndroidLibXrayLite), and [hev-socks5-tunnel](https://github.com/heiher/hev-socks5-tunnel).
44

5-
### Telegram Channel
5+
## Telegram Channel
66

77
[Asterisk4Magisk](https://t.me/Asterisk4Magisk)
88

9-
### Features
9+
## Features
1010

11-
- VPN Service and TPROXY(ROOT) run modes
11+
- VPN Service, TPROXY(ROOT), and TUN2SOCKS(ROOT) run modes
1212
- VMess, VLESS, Trojan, Shadowsocks, Socks, HTTP, Hysteria2, WireGuard, strategy group, and chain proxy
13-
- Subscription groups, QR code import, latency testing, and per-app proxy
14-
- Resource file management for `geoip.dat`, `geosite.dat`, and Xray-core
13+
- Subscription groups, QR code import, latency testing, and app proxy modes
14+
- Resource file management for `geoip.dat`, `geosite.dat`, and the Xray executable
15+
- ROOT start-on-boot script generation through Magisk `service.d`
1516
- MIUIX Compose UI
1617

17-
### Usage
18+
## Run Modes
1819

19-
#### Geoip and Geosite
20+
### VPN Service
2021

21-
- `geoip.dat` and `geosite.dat` are stored in the app private `files/xray` directory, commonly `/data/user/0/org.asterisk.zcc.ang/files/xray`.
22-
- Resource files can be updated in the app from [Loyalsoldier/v2ray-rules-dat](https://github.com/Loyalsoldier/v2ray-rules-dat), [v2fly/geoip](https://github.com/v2fly/geoip) and [v2fly/domain-list-community](https://github.com/v2fly/domain-list-community), or [Chocolate4U/Iran-v2ray-rules](https://github.com/Chocolate4U/Iran-v2ray-rules).
23-
- Third-party `geoip.dat` and `geosite.dat` files can be imported manually from Resource management.
24-
- Xray-core can also be replaced manually with an `xray` executable file or a zip archive containing `xray`.
22+
- Works without root permission.
23+
- Uses Android `VpnService`.
24+
- Suitable for normal Android app-level VPN usage.
2525

26-
#### Run Mode
26+
### TPROXY(ROOT)
2727

28-
- VPN Service mode works without root permission and uses Android `VpnService`.
29-
- TPROXY mode requires ROOT permission and uses the local Xray executable with iptables rules.
30-
- Start on boot can generate a Magisk `service.d` script for TPROXY mode.
28+
- Requires root permission.
29+
- Runs the local Xray executable directly with libsu.
30+
- Uses iptables and policy routing for transparent proxy traffic.
31+
- Uses the configured transparent proxy port as the Xray inbound.
3132

32-
### Development guide
33+
### TUN2SOCKS(ROOT)
34+
35+
- Requires root permission.
36+
- Runs the local Xray executable directly with libsu.
37+
- Uses `hev-socks5-tunnel` to create the fixed TUN device `asterisk0`.
38+
- Uses Xray's local SOCKS5 inbound as the tunnel target.
39+
- Shares most ROOT routing and app proxy behavior with TPROXY, but routes traffic through the TUN device instead of Xray's TPROXY inbound.
40+
41+
## Resource Files
42+
43+
- Runtime files are stored in the app private `files/xray` directory, commonly `/data/user/0/org.asterisk.zcc.ang/files/xray`.
44+
- The bundled Xray executable is restored from native libraries and can be replaced manually with an `xray` executable file or a zip archive containing `xray`.
45+
- `geoip.dat` and `geosite.dat` can be restored from bundled assets, updated from online sources, or replaced manually.
46+
- Built-in update sources include [Loyalsoldier/v2ray-rules-dat](https://github.com/Loyalsoldier/v2ray-rules-dat), [v2fly/geoip](https://github.com/v2fly/geoip), [v2fly/domain-list-community](https://github.com/v2fly/domain-list-community), and [Chocolate4U/Iran-v2ray-rules](https://github.com/Chocolate4U/Iran-v2ray-rules).
47+
48+
## Development
3349

3450
Open the project root in Android Studio, or build it with Gradle wrapper:
3551

@@ -43,21 +59,34 @@ On macOS or Linux:
4359
./gradlew assembleDebug
4460
```
4561

46-
The build downloads the bundled Xray-core asset and compiles the native `setuidgid` helper. If Gradle cannot find Android NDK, set `ndk.dir` in `local.properties`, set `ANDROID_NDK_HOME`, or install an NDK under the Android SDK.
62+
The build:
63+
64+
- uses the Android SDK and NDK
65+
- downloads or prepares the bundled Xray-core asset
66+
- builds the native `setuidgid` helper
67+
- packages native runtime components for `arm64-v8a`, `armeabi-v7a`, `x86`, and `x86_64`
68+
69+
If Gradle cannot find Android NDK, set `ndk.dir` in `local.properties`, set `ANDROID_NDK_HOME`, or install an NDK under the Android SDK.
70+
71+
## WSA
4772

4873
For WSA, VPN permission can be granted with:
4974

5075
```bash
5176
appops set org.asterisk.zcc.ang ACTIVATE_VPN allow
5277
```
53-
### License
78+
79+
## License
5480

5581
[GPL-3.0](LICENSE)
5682

57-
### Credits
83+
## Credits
5884

5985
- [@XTLS/Xray-core](https://github.com/XTLS/Xray-core)
6086
- [@2dust/AndroidLibXrayLite](https://github.com/2dust/AndroidLibXrayLite)
87+
- [@heiher/hev-socks5-tunnel](https://github.com/heiher/hev-socks5-tunnel)
88+
- [@topjohnwu/libsu](https://github.com/topjohnwu/libsu)
89+
- [@compose-miuix-ui/miuix](https://github.com/compose-miuix-ui/miuix)
6190
- [@2dust/v2rayNG](https://github.com/2dust/v2rayNG)
6291
- [@Loyalsoldier/v2ray-rules-dat](https://github.com/Loyalsoldier/v2ray-rules-dat)
6392
- [@v2fly/geoip](https://github.com/v2fly/geoip)

app/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ plugins {
88

99
val generatedSrcDir: Provider<Directory> = layout.buildDirectory.dir("generated/projectInfo")
1010
val generatedXrayCoreJniLibsDir: Provider<Directory> = layout.buildDirectory.dir("generated/xrayCoreJniLibs")
11+
val generatedHevSocks5TunnelJniLibsDir: Provider<Directory> = layout.buildDirectory.dir("generated/hevSocks5TunnelJniLibs")
1112

1213
android {
1314
namespace = "app"
@@ -132,6 +133,7 @@ val generateProjectInfo by tasks.registering(GenerateProjectInfoTask::class) {
132133
versionCode.set(getGitVersionCode())
133134
xrayCoreVersion.set(ProjectConfig.XRAY_CORE_VERSION)
134135
androidLibXrayLiteVersion.set(ProjectConfig.ANDROID_LIB_XRAY_LITE_VERSION)
136+
hevSocks5TunnelVersion.set(ProjectConfig.HEV_SOCKS5_TUNNEL_VERSION)
135137
outputDirectory.set(generatedSrcDir.map { it.dir("kotlin") })
136138
}
137139

@@ -141,6 +143,7 @@ androidComponents {
141143
task.outputDirectory
142144
}
143145
variant.sources.jniLibs?.addStaticSourceDirectory("build/generated/xrayCoreJniLibs")
146+
variant.sources.jniLibs?.addStaticSourceDirectory("build/generated/hevSocks5TunnelJniLibs")
144147
}
145148
}
146149

app/src/main/assets/aboutlibraries.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,19 @@
9191
"Apache-2.0"
9292
]
9393
},
94+
{
95+
"uniqueId": "github:heiher/hev-socks5-tunnel",
96+
"artifactVersion": "2.15.0",
97+
"name": "hev-socks5-tunnel",
98+
"description": "A tun2socks tunnel that forwards TUN traffic to a SOCKS5 server.",
99+
"website": "https://github.com/heiher/hev-socks5-tunnel",
100+
"scm": {
101+
"url": "https://github.com/heiher/hev-socks5-tunnel"
102+
},
103+
"licenses": [
104+
"MIT"
105+
]
106+
},
94107
{
95108
"uniqueId": "org.jetbrains.kotlin:kotlin-stdlib",
96109
"artifactVersion": "2.3.21",

app/src/main/kotlin/app/App.kt

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ import androidx.compose.ui.unit.dp
1515
import app.effects.ProxyStatusSynchronizer
1616
import app.effects.ResourceFileSynchronizer
1717
import app.effects.SubscriptionAutoUpdater
18-
import app.effects.TproxyBootScriptSynchronizer
18+
import app.effects.RootBootScriptSynchronizer
19+
import app.effects.Tun2SocksRuntimeFileSynchronizer
1920
import features.logs.AndroidAccessLogRepository
2021
import features.logs.AndroidCoreLogRepository
2122
import features.logs.AndroidLogcatRepository
@@ -28,7 +29,7 @@ import features.resources.ResourceFileUseCase
2829
import features.settings.locale.ProvideAppLanguage
2930
import features.settings.locale.RecreateActivityOnAppLanguageChange
3031
import features.settings.usecase.SwitchRunModeUseCase
31-
import features.settings.usecase.TproxyBootScriptUseCase
32+
import features.settings.usecase.RootBootScriptUseCase
3233
import features.subscription.runtime.AndroidSubscriptionFetcher
3334
import system.AndroidNetworkInterfaceProvider
3435
import system.AndroidPackageProvider
@@ -89,17 +90,18 @@ fun App(
8990
requestVpnPermission = requestVpnPermission,
9091
)
9192
}
92-
val tproxyBootScriptUseCase = remember(appContext, rootAccess) {
93-
TproxyBootScriptUseCase(
93+
val rootBootScriptUseCase = remember(appContext, rootAccess) {
94+
RootBootScriptUseCase(
9495
context = appContext,
9596
rootAccess = rootAccess,
9697
)
9798
}
98-
val switchRunModeUseCase = remember(proxyEngine, rootAccess, tproxyBootScriptUseCase) {
99+
val switchRunModeUseCase = remember(proxyEngine, rootAccess, rootBootScriptUseCase) {
99100
SwitchRunModeUseCase(
101+
context = appContext,
100102
proxyEngine = proxyEngine,
101103
rootAccess = rootAccess,
102-
tproxyBootScriptUseCase = tproxyBootScriptUseCase,
104+
rootBootScriptUseCase = rootBootScriptUseCase,
103105
)
104106
}
105107
val proxyServiceUseCase = remember(proxyEngine) {
@@ -121,7 +123,7 @@ fun App(
121123
proxyLatencyTester,
122124
proxyServiceUseCase,
123125
switchRunModeUseCase,
124-
tproxyBootScriptUseCase,
126+
rootBootScriptUseCase,
125127
tipNotifier,
126128
logFileCreator,
127129
) {
@@ -139,7 +141,7 @@ fun App(
139141
proxyLatencyTester = proxyLatencyTester,
140142
proxyServiceUseCase = proxyServiceUseCase,
141143
switchRunModeUseCase = switchRunModeUseCase,
142-
tproxyBootScriptUseCase = tproxyBootScriptUseCase,
144+
rootBootScriptUseCase = rootBootScriptUseCase,
143145
tipNotifier = tipNotifier,
144146
logFileCreator = logFileCreator,
145147
coreLogRepository = AndroidCoreLogRepository,
@@ -166,9 +168,13 @@ fun App(
166168
subscriptionFetcher = subscriptionFetcher,
167169
updateAppState = updateAppState,
168170
)
169-
TproxyBootScriptSynchronizer(
171+
RootBootScriptSynchronizer(
172+
stateStore = stateStore,
173+
rootBootScriptUseCase = rootBootScriptUseCase,
174+
)
175+
Tun2SocksRuntimeFileSynchronizer(
176+
context = appContext,
170177
stateStore = stateStore,
171-
tproxyBootScriptUseCase = tproxyBootScriptUseCase,
172178
)
173179

174180
ProvideAppLanguage(languageMode = chromeState.languageMode) {

app/src/main/kotlin/app/AppServices.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import features.proxy.server.usecase.ProxyServerImportFileUseCase
1212
import features.proxy.server.usecase.ProxyServiceUseCase
1313
import features.resources.ResourceFileUseCase
1414
import features.settings.usecase.SwitchRunModeUseCase
15-
import features.settings.usecase.TproxyBootScriptUseCase
15+
import features.settings.usecase.RootBootScriptUseCase
1616
import features.subscription.runtime.AndroidSubscriptionFetcher
1717
import kotlinx.coroutines.CoroutineScope
1818
import system.AndroidNetworkInterfaceProvider
@@ -35,7 +35,7 @@ internal data class AppServices(
3535
val proxyLatencyTester: AndroidProxyLatencyTester,
3636
val proxyServiceUseCase: ProxyServiceUseCase,
3737
val switchRunModeUseCase: SwitchRunModeUseCase,
38-
val tproxyBootScriptUseCase: TproxyBootScriptUseCase,
38+
val rootBootScriptUseCase: RootBootScriptUseCase,
3939
val tipNotifier: AndroidToastTipNotifier,
4040
val logFileCreator: suspend (String) -> Uri?,
4141
val coreLogRepository: CoreLogRepository,

app/src/main/kotlin/app/AppState.kt

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ package app
66
import app.modes.ColorModeSystem
77
import app.modes.LanguageModeSystem
88
import app.modes.ProxyAppListModeGlobal
9+
import app.modes.RunModeTun2Socks
910
import app.modes.RunModeTproxy
1011
import app.modes.RunModeVpnService
11-
import engine.tproxy.DefaultTproxyHttpPort
12+
import engine.root.DefaultRootHttpProxyPort
13+
import engine.tun2socks.DefaultTun2SocksProxyPort
1214
import engine.tproxy.DefaultTproxyPort
13-
import engine.tproxy.DefaultTproxySocks5Port
1415
import engine.vpn.VpnDefaults
1516
import engine.xray.DefaultDirectDnsDomains
1617
import engine.xray.DefaultFragmentInterval
@@ -44,10 +45,10 @@ data class AppState(
4445
val localProxyUsername: String = "",
4546
val localProxyPassword: String = "",
4647
val enableVpnAppendHttpProxy: Boolean = false,
47-
val vpnMtu: String = VpnDefaults.MTU.toString(),
48-
val vpnDefaultDns: String = VpnDefaults.IPV4_DNS,
49-
val vpnIpv4Cidr: String = VpnDefaults.IPV4_CIDR,
50-
val vpnIpv6Cidr: String = VpnDefaults.IPV6_CIDR,
48+
val tunMtu: String = VpnDefaults.MTU.toString(),
49+
val tunDefaultDns: String = VpnDefaults.IPV4_DNS,
50+
val tunIpv4Cidr: String = VpnDefaults.IPV4_CIDR,
51+
val tunIpv6Cidr: String = VpnDefaults.IPV6_CIDR,
5152

5253
val proxyServers: List<ProxyServerState> = emptyList(),
5354
val nextProxyServerId: Int = 10,
@@ -90,11 +91,11 @@ data class AppState(
9091
val dnsHosts: List<String> = emptyList(),
9192

9293
val transparentProxyPort: String = DefaultTproxyPort.toString(),
93-
val enableTproxyBootScript: Boolean = false,
94+
val enableRootBootScript: Boolean = false,
9495
val enableSocks5Proxy: Boolean = false,
95-
val socks5ProxyPort: String = DefaultTproxySocks5Port.toString(),
96+
val socks5ProxyPort: String = DefaultTun2SocksProxyPort.toString(),
9697
val enableHttpProxy: Boolean = false,
97-
val httpProxyPort: String = DefaultTproxyHttpPort.toString(),
98+
val httpProxyPort: String = DefaultRootHttpProxyPort.toString(),
9899

99100
val externalInterfaces: List<String> = emptyList(),
100101
val ignoredInterfaces: List<String> = emptyList(),
@@ -105,7 +106,7 @@ data class AppState(
105106
)
106107

107108
val AppState.effectiveLocalDnsEnabled: Boolean
108-
get() = runMode == RunModeTproxy || enableVpnLocalDns
109+
get() = runMode == RunModeTproxy || runMode == RunModeTun2Socks || enableVpnLocalDns
109110

110111
val AppState.effectiveFakeDnsEnabled: Boolean
111112
get() = effectiveLocalDnsEnabled && enableFakeDns

app/src/main/kotlin/app/effects/ProxyStatusSynchronizer.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package app.effects
66
import androidx.compose.runtime.Composable
77
import androidx.compose.runtime.LaunchedEffect
88
import app.AppState
9+
import app.modes.RunModeTun2Socks
910
import app.modes.RunModeTproxy
1011
import data.AndroidAppStateStore
1112
import engine.proxy.AndroidProxyEngine
@@ -18,7 +19,7 @@ internal fun ProxyStatusSynchronizer(
1819
) {
1920
LaunchedEffect(stateStore, proxyEngine) {
2021
val currentState = stateStore.state.value
21-
if (currentState.runMode != RunModeTproxy && !currentState.proxyRunning) {
22+
if (currentState.runMode != RunModeTproxy && currentState.runMode != RunModeTun2Socks && !currentState.proxyRunning) {
2223
return@LaunchedEffect
2324
}
2425
val status = runCatching { proxyEngine.status(currentState.runMode) }.getOrNull() ?: return@LaunchedEffect

0 commit comments

Comments
 (0)