implement per-app VPN for Android 5.0
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.github.shadowsocks"
|
||||
android:versionCode="75"
|
||||
android:versionName="2.3.0">
|
||||
android:versionCode="76"
|
||||
android:versionName="2.3.1">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
|
||||
@@ -89,8 +89,9 @@ object AppManager {
|
||||
case a => {
|
||||
val uid = a.uid
|
||||
val userName = uid.toString
|
||||
val packageName = a.packageName
|
||||
val proxied = proxiedApps.binarySearch(userName) >= 0
|
||||
new ProxiedApp(uid, userName, proxied)
|
||||
new ProxiedApp(uid, packageName, proxied)
|
||||
}
|
||||
}.toArray
|
||||
}
|
||||
|
||||
@@ -766,7 +766,7 @@ class Shadowsocks
|
||||
if (pref != null) {
|
||||
if (Seq(Key.isGlobalProxy, Key.isTrafficStat, Key.proxyedApps)
|
||||
.contains(name)) {
|
||||
pref.setEnabled(enabled && !isVpnEnabled)
|
||||
pref.setEnabled(enabled && (!isVpnEnabled || Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP))
|
||||
} else {
|
||||
pref.setEnabled(enabled)
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ import com.google.android.gms.analytics.HitBuilders
|
||||
import org.apache.commons.net.util.SubnetUtils
|
||||
import org.apache.http.conn.util.InetAddressUtils
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
import scala.concurrent.ops._
|
||||
|
||||
@@ -66,6 +67,8 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
|
||||
val PRIVATE_VLAN = "26.26.26.%s"
|
||||
|
||||
val AF_INET6 = 10
|
||||
|
||||
var conn: ParcelFileDescriptor = null
|
||||
var notificationManager: NotificationManager = null
|
||||
var receiver: BroadcastReceiver = null
|
||||
@@ -88,7 +91,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
, "-l" , config.localPort.toString
|
||||
, "-k" , config.sitekey
|
||||
, "-m" , config.encMethod
|
||||
, "-f" , (Path.BASE + "ss-local.pid"))
|
||||
, "-f" , Path.BASE + "ss-local.pid")
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" "))
|
||||
Core.sslocal(cmd.toArray)
|
||||
}
|
||||
@@ -126,11 +129,36 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
.addAddress(PRIVATE_VLAN.format("1"), 24)
|
||||
.addDnsServer("8.8.8.8")
|
||||
|
||||
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
|
||||
builder.allowFamily(AF_INET6)
|
||||
|
||||
if (config.isBypassApps) {
|
||||
builder.addDisallowedApplication(this.getPackageName)
|
||||
}
|
||||
|
||||
if (!config.isGlobalProxy) {
|
||||
val apps = AppManager.getProxiedApps(this, config.proxiedAppString)
|
||||
val uidSet: mutable.HashSet[String] = new mutable.HashSet[String]
|
||||
for (app <- apps) {
|
||||
if (app.proxied) {
|
||||
uidSet.add(app.name)
|
||||
}
|
||||
}
|
||||
for (uid <- uidSet) {
|
||||
if (!config.isBypassApps) {
|
||||
builder.addAllowedApplication(uid)
|
||||
} else {
|
||||
builder.addDisallowedApplication(uid)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (InetAddressUtils.isIPv6Address(config.proxy)) {
|
||||
builder.addRoute("0.0.0.0", 0)
|
||||
} else if (config.isGFWList) {
|
||||
val gfwList = {
|
||||
if (Build.VERSION.SDK_INT == 19) {
|
||||
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
|
||||
getResources.getStringArray(R.array.simple_list)
|
||||
} else {
|
||||
getResources.getStringArray(R.array.gfw_list)
|
||||
|
||||
Reference in New Issue
Block a user