diff --git a/service/src/main/java/com/github/kr328/clash/service/TunService.kt b/service/src/main/java/com/github/kr328/clash/service/TunService.kt index 5faa13b..3b05506 100644 --- a/service/src/main/java/com/github/kr328/clash/service/TunService.kt +++ b/service/src/main/java/com/github/kr328/clash/service/TunService.kt @@ -2,6 +2,7 @@ package com.github.kr328.clash.service import android.content.Intent import android.net.VpnService +import android.os.Process import com.github.kr328.clash.service.clash.ClashRuntime import com.github.kr328.clash.service.clash.module.* import com.github.kr328.clash.service.settings.ServiceSettings @@ -13,11 +14,7 @@ import kotlinx.coroutines.launch class TunService : VpnService(), CoroutineScope by MainScope() { companion object { - // from https://github.com/shadowsocks/shadowsocks-android/blob/master/core/src/main/java/com/github/shadowsocks/bg/VpnService.kt private const val VPN_MTU = 9000 - private const val PRIVATE_VLAN4_SUBNET = 30 - private const val PRIVATE_VLAN4_CLIENT = "172.31.255.253" - private const val PRIVATE_VLAN4_MIRROR = "172.31.255.254" private const val PRIVATE_VLAN_DNS = "198.18.0.1" private const val VLAN_ANY = "0.0.0.0/0" } @@ -106,14 +103,18 @@ class TunService : VpnService(), CoroutineScope by MainScope() { } private inner class TunConfigure(private val settings: ServiceSettings) : TunModule.Configure { + private val network = generateTunNetwork() + override val builder: Builder get() = Builder() override val mtu: Int get() = VPN_MTU - override val gateway: String - get() = "$PRIVATE_VLAN4_CLIENT/$PRIVATE_VLAN4_SUBNET" - override val mirror: String - get() = PRIVATE_VLAN4_MIRROR + override val gateway: String = network.copyOf().apply { + this[3] = (this[3] + 1).toByte() + }.asAddressString("/30") + override val mirror: String = network.copyOf().apply { + this[3] = (this[3] + 2).toByte() + }.asAddressString() override val route: List get() { return if (settings.get(ServiceSettings.BYPASS_PRIVATE_NETWORK)) @@ -141,6 +142,29 @@ class TunService : VpnService(), CoroutineScope by MainScope() { override fun onCreateTunFailure() { stopSelfForReason("Start VPN rejected by the system") } + + private fun generateTunNetwork(): ByteArray { + val result = ByteArray(4) + + // 18 bit namespace + val offset = UserUtils.currentUserId % 0x40000 + val network = (0x3FFFF - offset) shl 2 + + result[0] = (172 or (network shr 24) and 0xFF).toByte() + result[1] = (16 or (network shr 16) and 0xFF).toByte() + result[2] = (0 or (network shr 8) and 0xFF).toByte() + result[3] = (0 or (network shr 0) and 0xFF).toByte() + + return result + } + + private fun ByteArray.asAddressString(suffix: String = ""): String { + return "${this[0].toUnsignedString()}.${this[1].toUnsignedString()}.${this[2].toUnsignedString()}.${this[3].toUnsignedString()}$suffix" + } + + private fun Byte.toUnsignedString(): String { + return (this.toInt() and 0xFF).toString() + } } private fun stopSelfForReason(reason: String?) { diff --git a/service/src/main/java/com/github/kr328/clash/service/clash/module/TunModule.kt b/service/src/main/java/com/github/kr328/clash/service/clash/module/TunModule.kt index 9a9004f..2cc09f0 100644 --- a/service/src/main/java/com/github/kr328/clash/service/clash/module/TunModule.kt +++ b/service/src/main/java/com/github/kr328/clash/service/clash/module/TunModule.kt @@ -5,6 +5,7 @@ import android.net.VpnService import android.os.Build import com.github.kr328.clash.common.Global import com.github.kr328.clash.common.ids.PendingIds +import com.github.kr328.clash.common.utils.Log import com.github.kr328.clash.core.Clash import com.github.kr328.clash.service.util.parseCIDR import kotlinx.coroutines.Dispatchers @@ -33,6 +34,8 @@ class TunModule(private val service: VpnService) : Module() { val builder = c.builder + Log.i("Tun start at ${c.gateway}, mirror at ${c.mirror}") + parseCIDR(c.gateway).let { builder.addAddress(it.ip, it.prefix) } diff --git a/service/src/main/java/com/github/kr328/clash/service/util/UserUtils.kt b/service/src/main/java/com/github/kr328/clash/service/util/UserUtils.kt new file mode 100644 index 0000000..8d2a0e9 --- /dev/null +++ b/service/src/main/java/com/github/kr328/clash/service/util/UserUtils.kt @@ -0,0 +1,10 @@ +package com.github.kr328.clash.service.util + +import android.os.Process + +object UserUtils { + private const val PER_USER_RANGE: Int = 100000 + + val currentUserId: Int + get() = Process.myUid() / PER_USER_RANGE +} \ No newline at end of file