Unverified Commit f7083025 authored by Max Lv's avatar Max Lv Committed by GitHub

Merge pull request #1698 from Mygod/underlying

Actually use underlying network
parents 75bc9334 74e2935f
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
package="com.github.shadowsocks" package="com.github.shadowsocks"
android:installLocation="internalOnly"> 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.INTERNET"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.NFC" /> <uses-permission android:name="android.permission.NFC" />
......
...@@ -21,9 +21,11 @@ ...@@ -21,9 +21,11 @@
package com.github.shadowsocks.bg package com.github.shadowsocks.bg
import android.app.Service import android.app.Service
import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.net.LocalSocket import android.net.*
import android.os.Build
import android.os.IBinder import android.os.IBinder
import android.os.ParcelFileDescriptor import android.os.ParcelFileDescriptor
import android.util.Log import android.util.Log
...@@ -50,6 +52,21 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface { ...@@ -50,6 +52,21 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
private const val PRIVATE_VLAN6 = "fdfe:dcba:9876::%s" private const val PRIVATE_VLAN6 = "fdfe:dcba:9876::%s"
private val getInt: Method = FileDescriptor::class.java.getDeclaredMethod("getInt$") 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") { private inner class ProtectWorker : LocalSocketListener("ShadowsocksVpnThread") {
...@@ -59,13 +76,22 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface { ...@@ -59,13 +76,22 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
var success = false var success = false
try { try {
socket.inputStream.read() socket.inputStream.read()
val fds = socket.ancillaryFileDescriptors val fd = socket.ancillaryFileDescriptors!!.single()!!
if (fds.isEmpty()) return val fdInt = getInt.invoke(fd) as Int
val fd = getInt.invoke(fds.first()) as Int try {
success = protect(fd) val network = underlyingNetwork
JniHelper.close(fd) // Trick to close file decriptor 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) { } catch (e: Exception) {
Log.e(tag, "Error when protect socket", e) Log.e(tag, "Error when receiving ancillary fd", e)
app.track(e) app.track(e)
} }
try { try {
...@@ -89,6 +115,26 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface { ...@@ -89,6 +115,26 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
private var conn: ParcelFileDescriptor? = null private var conn: ParcelFileDescriptor? = null
private var worker: ProtectWorker? = null private var worker: ProtectWorker? = null
private var tun2socksProcess: GuardedProcess? = 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) { override fun onBind(intent: Intent): IBinder? = when (intent.action) {
SERVICE_INTERFACE -> super<BaseVpnService>.onBind(intent) SERVICE_INTERFACE -> super<BaseVpnService>.onBind(intent)
...@@ -98,6 +144,10 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface { ...@@ -98,6 +144,10 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
override fun onRevoke() = stopRunner(true) override fun onRevoke() = stopRunner(true)
override fun killProcesses() { override fun killProcesses() {
if (listeningForDefaultNetwork) {
connectivity.unregisterNetworkCallback(defaultNetworkCallback)
listeningForDefaultNetwork = false
}
worker?.stopThread() worker?.stopThread()
worker = null worker = null
super.killProcesses() super.killProcesses()
...@@ -179,6 +229,10 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface { ...@@ -179,6 +229,10 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
this.conn = conn this.conn = conn
val fd = conn.fd 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, val cmd = arrayListOf(File(applicationInfo.nativeLibraryDir, Executable.TUN2SOCKS).absolutePath,
"--netif-ipaddr", PRIVATE_VLAN.format(Locale.ENGLISH, "2"), "--netif-ipaddr", PRIVATE_VLAN.format(Locale.ENGLISH, "2"),
"--netif-netmask", "255.255.255.0", "--netif-netmask", "255.255.255.0",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment