Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ class FileManager(private val application: Application, private val prefs: Prefe
prefs.apps ?: emptySet()
)
preferencesMap[Preferences.BYPASS_LAN] = prefs.bypassLan
preferencesMap[Preferences.USE_XRAY_TUN] = prefs.useXrayTun
preferencesMap[Preferences.USE_TEMPLATE] = prefs.useTemplate
preferencesMap[Preferences.HTTP_PROXY_ENABLED] = prefs.httpProxyEnabled
preferencesMap[Preferences.CONFIG_FILES_ORDER] = prefs.configFilesOrder
Expand Down Expand Up @@ -764,4 +765,4 @@ class FileManager(private val application: Application, private val prefs: Prefe
companion object {
const val TAG = "FileManager"
}
}
}
9 changes: 8 additions & 1 deletion app/src/main/kotlin/com/simplexray/an/prefs/Preferences.kt
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,12 @@ class Preferences(context: Context) {
setValueInProvider(DISABLE_VPN, value)
}

var useXrayTun: Boolean
get() = getBooleanPref(USE_XRAY_TUN, false)
set(value) {
setValueInProvider(USE_XRAY_TUN, value)
}

val tunnelMtu: Int
get() = 8500

Expand Down Expand Up @@ -333,6 +339,7 @@ class Preferences(context: Context) {
const val CUSTOM_GEOSITE_IMPORTED: String = "CustomGeositeImported"
const val CONFIG_FILES_ORDER: String = "ConfigFilesOrder"
const val DISABLE_VPN: String = "DisableVpn"
const val USE_XRAY_TUN: String = "UseXrayTun"
const val CONNECTIVITY_TEST_TARGET: String = "ConnectivityTestTarget"
const val CONNECTIVITY_TEST_TIMEOUT: String = "ConnectivityTestTimeout"
const val GEOIP_URL: String = "GeoipUrl"
Expand All @@ -343,4 +350,4 @@ class Preferences(context: Context) {
const val THEME: String = "Theme"
private const val TAG = "Preferences"
}
}
}
77 changes: 53 additions & 24 deletions app/src/main/kotlin/com/simplexray/an/service/TProxyService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ class TProxyService : VpnService() {
successIntent.setPackage(application.packageName)
sendBroadcast(successIntent)

@Suppress("SameParameterValue") val channelName = "nosocks"
@Suppress("SameParameterValue") val channelName = "xray"
initNotificationChannel(channelName)
createNotification(channelName)

Expand Down Expand Up @@ -189,13 +189,17 @@ class TProxyService : VpnService() {
prefs.apiAddress = "127.$octet2.$octet3.$octet4"
Log.d(TAG, "Randomized API address: ${prefs.apiAddress}")

val processBuilder = getProcessBuilder(xrayPath)
val processBuilder = getProcessBuilder(xrayPath, prefs)
currentProcess = processBuilder.start()
this.xrayProcess = currentProcess

Log.d(TAG, "Writing config to xray stdin from: $selectedConfigPath")
val injectedConfigContent =
val injectedConfigContent = if (prefs.useXrayTun && tunFd != null) {
// Inject TUN inbound into config when using native TUN
ConfigUtils.injectStatsService(prefs, configContent)
} else {
ConfigUtils.injectStatsService(prefs, configContent)
}
currentProcess.outputStream.use { os ->
os.write(injectedConfigContent.toByteArray())
os.flush()
Expand Down Expand Up @@ -236,19 +240,29 @@ class TProxyService : VpnService() {
}
}

private fun getProcessBuilder(xrayPath: String): ProcessBuilder {
private fun getProcessBuilder(xrayPath: String, prefs: Preferences): ProcessBuilder {
val filesDir = applicationContext.filesDir
val command: MutableList<String> = mutableListOf(xrayPath)
val processBuilder = ProcessBuilder(command)
val environment = processBuilder.environment()
environment["XRAY_LOCATION_ASSET"] = filesDir.path

// Pass TUN FD to Xray when using native TUN mode
if (prefs.useXrayTun && tunFd != null) {
val tunFdValue = tunFd?.fd
if (tunFdValue != null) {
environment["XRAY_TUN_FD"] = tunFdValue.toString()
Log.d(TAG, "Passed TUN FD ($tunFdValue) to Xray process via environment variable")
}
}

processBuilder.directory(filesDir)
processBuilder.redirectErrorStream(true)
return processBuilder
}

private fun stopXray() {
Log.d(TAG, "stopXray called with keepExecutorAlive=" + false)
Log.d(TAG, "stopXray called")
serviceScope.cancel()
Log.d(TAG, "CoroutineScope cancelled.")

Expand All @@ -266,33 +280,45 @@ class TProxyService : VpnService() {
val builder = getVpnBuilder(prefs)
tunFd = builder.establish()
if (tunFd == null) {
Log.e(TAG, "Failed to establish VPN")
stopXray()
return
}
val tproxyFile = File(cacheDir, "tproxy.conf")
try {
tproxyFile.createNewFile()
FileOutputStream(tproxyFile, false).use { fos ->
val tproxyConf = getTproxyConf(prefs)
fos.write(tproxyConf.toByteArray())

Log.d(TAG, "VPN service established. TUN FD: ${tunFd?.fd}")

// Use Xray native TUN or hev-tun2sock based on preference
if (prefs.useXrayTun) {
Log.d(TAG, "Using Xray native TUN inbound mode")
// TUN FD will be passed via environment variable in getProcessBuilder
} else {
Log.d(TAG, "Using hev-socks5-tunnel (legacy mode)")
val tproxyFile = File(cacheDir, "tproxy.conf")
try {
tproxyFile.createNewFile()
FileOutputStream(tproxyFile, false).use { fos ->
val tproxyConf = getTproxyConf(prefs)
fos.write(tproxyConf.toByteArray())
}
} catch (e: IOException) {
Log.e(TAG, "Error creating tproxy config: ${e.message}")
stopXray()
return
}
tunFd?.fd?.let { fd ->
TProxyStartService(tproxyFile.absolutePath, fd)
Log.d(TAG, "hev-tun2sock service started with FD: $fd")
} ?: run {
Log.e(TAG, "tunFd is null after establish()")
stopXray()
return
}
} catch (e: IOException) {
Log.e(TAG, e.toString())
stopXray()
return
}
tunFd?.fd?.let { fd ->
TProxyStartService(tproxyFile.absolutePath, fd)
} ?: run {
Log.e(TAG, "tunFd is null after establish()")
stopXray()
return
}

val successIntent = Intent(ACTION_START)
successIntent.setPackage(application.packageName)
sendBroadcast(successIntent)
@Suppress("SameParameterValue") val channelName = "socks5"
@Suppress("SameParameterValue") val channelName = "xray"
initNotificationChannel(channelName)
createNotification(channelName)
}
Expand Down Expand Up @@ -348,7 +374,10 @@ class TProxyService : VpnService() {
tunFd = null
}
stopForeground(Service.STOP_FOREGROUND_REMOVE)
TProxyStopService()
val prefs = Preferences(this)
if (!prefs.useXrayTun) {
TProxyStopService()
}
}
exit()
}
Expand Down
14 changes: 14 additions & 0 deletions app/src/main/kotlin/com/simplexray/an/ui/screens/SettingsScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,20 @@ fun SettingsScreen(
}
)

ListItem(
headlineContent = { Text(stringResource(R.string.tun_mode_title)) },
supportingContent = { Text(stringResource(R.string.tun_mode_summary)) },
trailingContent = {
Switch(
checked = settingsState.switches.useXrayTun,
onCheckedChange = {
mainViewModel.setUseXrayTun(it)
},
enabled = !vpnDisabled
)
}
)

PreferenceCategoryTitle(stringResource(R.string.rule_files_category_title))

ListItem(
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class MainViewModel(application: Application) :
httpProxyEnabled = prefs.httpProxyEnabled,
bypassLanEnabled = prefs.bypassLan,
disableVpn = prefs.disableVpn,
useXrayTun = prefs.useXrayTun,
themeMode = prefs.theme
),
info = InfoStates(
Expand Down Expand Up @@ -192,6 +193,7 @@ class MainViewModel(application: Application) :
httpProxyEnabled = prefs.httpProxyEnabled,
bypassLanEnabled = prefs.bypassLan,
disableVpn = prefs.disableVpn,
useXrayTun = prefs.useXrayTun, // ADD THIS LINE
themeMode = prefs.theme
),
info = _settingsState.value.info.copy(
Expand Down Expand Up @@ -471,6 +473,14 @@ class MainViewModel(application: Application) :
}
}

fun setUseXrayTun(enabled: Boolean = false) {
prefs.useXrayTun = enabled
_settingsState.value = _settingsState.value.copy(
switches = _settingsState.value.switches.copy(useXrayTun = enabled)
)
Log.d(TAG, "Xray TUN mode: ${if (enabled) "native" else "hev-tun2sock"}")
}

fun updateDnsIpv4(ipv4Addr: String): Boolean {
val matcher = IPV4_PATTERN.matcher(ipv4Addr)
return if (matcher.matches()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ data class SwitchStates(
val httpProxyEnabled: Boolean,
val bypassLanEnabled: Boolean,
val disableVpn: Boolean,
val useXrayTun: Boolean,
val themeMode: ThemeMode
)

Expand Down Expand Up @@ -42,4 +43,4 @@ data class SettingsState(
val files: FileStates,
val connectivityTestTarget: InputFieldState,
val connectivityTestTimeout: InputFieldState
)
)
2 changes: 2 additions & 0 deletions app/src/main/res/values-id/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,6 @@
<string name="theme_dark">Gelap</string>
<string name="auto">Otomatis</string>
<string name="socks_user">"Pengguna SOCKS "</string>
<string name="tun_mode_title">Mode TUN Asli</string>
<string name="tun_mode_summary">Gunakan inbound TUN asli Xray atau hev-tun2sock</string>
</resources>
2 changes: 2 additions & 0 deletions app/src/main/res/values-ru-rRU/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,6 @@
<string name="theme_dark">Тёмная</string>
<string name="auto">Автоматически</string>
<string name="socks_user">Пользователь SOCKS</string>
<string name="tun_mode_title">Нативный режим TUN</string>
<string name="tun_mode_summary">Используйте встроенный TUN входящий Xray или hev-tun2sock</string>
</resources>
4 changes: 3 additions & 1 deletion app/src/main/res/values-zh/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,6 @@
<string name="theme_dark">深色</string>
<string name="auto">自动</string>
<string name="socks_user">SOCKS 用户</string>
</resources>
<string name="tun_mode_title">原生TUN模式</string>
<string name="tun_mode_summary">使用Xray原生TUN入站或hev-tun2sock</string>
</resources>
4 changes: 3 additions & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,6 @@
<string name="theme_light">Light</string>
<string name="theme_dark">Dark</string>
<string name="auto">Auto</string>
</resources>
<string name="tun_mode_title">Native TUN Mode</string>
<string name="tun_mode_summary">Use Xray native TUN inbound or hev-tun2sock</string>
</resources>
Loading