Merge pull request #1698 from Mygod/underlying
Actually use underlying network
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
package="com.github.shadowsocks"
|
||||
android:installLocation="internalOnly">
|
||||
|
||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.NFC" />
|
||||
|
||||
@@ -21,9 +21,11 @@
|
||||
package com.github.shadowsocks.bg
|
||||
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.LocalSocket
|
||||
import android.net.*
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.os.ParcelFileDescriptor
|
||||
import android.util.Log
|
||||
@@ -50,6 +52,21 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
|
||||
private const val PRIVATE_VLAN6 = "fdfe:dcba:9876::%s"
|
||||
|
||||
private val getInt: Method = FileDescriptor::class.java.getDeclaredMethod("getInt$")
|
||||
|
||||
/**
|
||||
* Unfortunately registerDefaultNetworkCallback is going to return VPN interface since Android P DP1:
|
||||
* https://android.googlesource.com/platform/frameworks/base/+/dda156ab0c5d66ad82bdcf76cda07cbc0a9c8a2e
|
||||
*
|
||||
* This makes doing a requestNetwork with REQUEST necessary so that we don't get ALL possible networks that
|
||||
* satisfies default network capabilities but only THE default network. Unfortunately we need to have
|
||||
* android.permission.CHANGE_NETWORK_STATE to be able to call requestNetwork.
|
||||
*
|
||||
* Source: https://android.googlesource.com/platform/frameworks/base/+/2df4c7d/services/core/java/com/android/server/ConnectivityService.java#887
|
||||
*/
|
||||
private val defaultNetworkRequest = NetworkRequest.Builder()
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
|
||||
.build()
|
||||
}
|
||||
|
||||
private inner class ProtectWorker : LocalSocketListener("ShadowsocksVpnThread") {
|
||||
@@ -59,13 +76,22 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
|
||||
var success = false
|
||||
try {
|
||||
socket.inputStream.read()
|
||||
val fds = socket.ancillaryFileDescriptors
|
||||
if (fds.isEmpty()) return
|
||||
val fd = getInt.invoke(fds.first()) as Int
|
||||
success = protect(fd)
|
||||
JniHelper.close(fd) // Trick to close file decriptor
|
||||
val fd = socket.ancillaryFileDescriptors!!.single()!!
|
||||
val fdInt = getInt.invoke(fd) as Int
|
||||
try {
|
||||
val network = underlyingNetwork
|
||||
success = if (network != null && Build.VERSION.SDK_INT >= 23) {
|
||||
network.bindSocket(fd)
|
||||
true
|
||||
} else protect(fdInt)
|
||||
} catch (e: Exception) {
|
||||
Log.e(tag, "Error when protect socket", e)
|
||||
app.track(e)
|
||||
} finally {
|
||||
JniHelper.close(fdInt) // Trick to close file decriptor
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(tag, "Error when protect socket", e)
|
||||
Log.e(tag, "Error when receiving ancillary fd", e)
|
||||
app.track(e)
|
||||
}
|
||||
try {
|
||||
@@ -89,6 +115,26 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
|
||||
private var conn: ParcelFileDescriptor? = null
|
||||
private var worker: ProtectWorker? = null
|
||||
private var tun2socksProcess: GuardedProcess? = null
|
||||
private var underlyingNetwork: Network? = null
|
||||
set(value) {
|
||||
if (Build.VERSION.SDK_INT >= 22) setUnderlyingNetworks(if (value == null) null else arrayOf(value))
|
||||
field = value
|
||||
}
|
||||
|
||||
private val connectivity by lazy { getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager }
|
||||
private val defaultNetworkCallback = object : ConnectivityManager.NetworkCallback() {
|
||||
override fun onAvailable(network: Network) {
|
||||
underlyingNetwork = network
|
||||
}
|
||||
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities?) {
|
||||
// it's a good idea to refresh capabilities
|
||||
underlyingNetwork = network
|
||||
}
|
||||
override fun onLost(network: Network) {
|
||||
underlyingNetwork = null
|
||||
}
|
||||
}
|
||||
private var listeningForDefaultNetwork = false
|
||||
|
||||
override fun onBind(intent: Intent): IBinder? = when (intent.action) {
|
||||
SERVICE_INTERFACE -> super<BaseVpnService>.onBind(intent)
|
||||
@@ -98,6 +144,10 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
|
||||
override fun onRevoke() = stopRunner(true)
|
||||
|
||||
override fun killProcesses() {
|
||||
if (listeningForDefaultNetwork) {
|
||||
connectivity.unregisterNetworkCallback(defaultNetworkCallback)
|
||||
listeningForDefaultNetwork = false
|
||||
}
|
||||
worker?.stopThread()
|
||||
worker = null
|
||||
super.killProcesses()
|
||||
@@ -179,6 +229,10 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
|
||||
this.conn = conn
|
||||
val fd = conn.fd
|
||||
|
||||
// we want REQUEST here instead of LISTEN
|
||||
connectivity.requestNetwork(defaultNetworkRequest, defaultNetworkCallback)
|
||||
listeningForDefaultNetwork = true
|
||||
|
||||
val cmd = arrayListOf(File(applicationInfo.nativeLibraryDir, Executable.TUN2SOCKS).absolutePath,
|
||||
"--netif-ipaddr", PRIVATE_VLAN.format(Locale.ENGLISH, "2"),
|
||||
"--netif-netmask", "255.255.255.0",
|
||||
|
||||
Reference in New Issue
Block a user