From 9a724cd0634139afb048ec99fe3211c89d0011af Mon Sep 17 00:00:00 2001 From: Max Lv Date: Sun, 16 Nov 2014 21:35:54 +0800 Subject: [PATCH] fix #148 --- .../com/github/shadowsocks/aidl/Config.java | 6 +- src/main/res/values-zh/strings.xml | 8 + src/main/res/values/arrays.xml | 46 ++++- src/main/res/values/strings.xml | 2 + src/main/res/xml/pref_all.xml | 14 +- .../com/github/shadowsocks/Shadowsocks.scala | 6 +- .../shadowsocks/ShadowsocksNatService.scala | 36 ++-- .../shadowsocks/ShadowsocksVpnService.scala | 172 +++++++++++------- .../shadowsocks/database/DBHelper.scala | 5 +- .../github/shadowsocks/database/Profile.scala | 3 + .../shadowsocks/database/ProfileManager.scala | 10 +- .../preferences/SummaryListPreference.scala | 2 +- .../shadowsocks/utils/ConfigUtils.scala | 6 +- .../github/shadowsocks/utils/Constants.scala | 7 + 14 files changed, 206 insertions(+), 117 deletions(-) diff --git a/src/main/aidl/com/github/shadowsocks/aidl/Config.java b/src/main/aidl/com/github/shadowsocks/aidl/Config.java index f0afc982..96060b1b 100644 --- a/src/main/aidl/com/github/shadowsocks/aidl/Config.java +++ b/src/main/aidl/com/github/shadowsocks/aidl/Config.java @@ -14,6 +14,7 @@ public class Config implements Parcelable { public String profileName = "Untitled"; public String proxy = "127.0.0.1"; public String sitekey = "null"; + public String route = "all"; public String encMethod = "rc4"; public String proxiedAppString = ""; @@ -33,7 +34,7 @@ public class Config implements Parcelable { public Config(boolean isGlobalProxy, boolean isGFWList, boolean isBypassApps, boolean isTrafficStat, boolean isUdpDns, String profileName, String proxy, String sitekey, - String encMethod, String proxiedAppString, int remotePort, int localPort) { + String encMethod, String proxiedAppString, String route, int remotePort, int localPort) { this.isGlobalProxy = isGlobalProxy; this.isGFWList = isGFWList; this.isBypassApps = isBypassApps; @@ -44,6 +45,7 @@ public class Config implements Parcelable { this.sitekey = sitekey; this.encMethod = encMethod; this.proxiedAppString = proxiedAppString; + this.route = route; this.remotePort = remotePort; this.localPort = localPort; } @@ -63,6 +65,7 @@ public class Config implements Parcelable { sitekey = in.readString(); encMethod = in.readString(); proxiedAppString = in.readString(); + route = in.readString(); remotePort = in.readInt(); localPort = in.readInt(); } @@ -82,6 +85,7 @@ public class Config implements Parcelable { out.writeString(sitekey); out.writeString(encMethod); out.writeString(proxiedAppString); + out.writeString(route); out.writeInt(remotePort); out.writeInt(localPort); } diff --git a/src/main/res/values-zh/strings.xml b/src/main/res/values-zh/strings.xml index a32266fe..2d4b5e81 100755 --- a/src/main/res/values-zh/strings.xml +++ b/src/main/res/values-zh/strings.xml @@ -25,6 +25,8 @@ 重定向 DNS 查询到远程服务器 国内路由 绕过所有位于中国的网站 + 路由 + 绕过指定路由列表中的地址 全局代理 设置系统代理 局部代理 @@ -76,4 +78,10 @@ 手动设置 + + 全局 + 绕过局域网地址 + 绕过局域网及中国大陆地址 + + diff --git a/src/main/res/values/arrays.xml b/src/main/res/values/arrays.xml index b2c4579c..0d9b3011 100644 --- a/src/main/res/values/arrays.xml +++ b/src/main/res/values/arrays.xml @@ -38,7 +38,36 @@ seed-cfb - + + All + Bypass LAN + Bypass LAN & China + + + + all + bypass-lan + bypass-china + + + + 0.0.0.0/8 + 10.0.0.0/8 + 100.64.0.0/10 + 127.0.0.0/8 + 169.254.0.0/16 + 172.16.0.0/12 + 192.0.0.0/29 + 192.0.2.0/24 + 192.88.99.0/24 + 192.168.0.0/16 + 198.18.0.0/15 + 198.51.100.0/24 + 203.0.113.0/24 + 224.0.0.0/3 + + + 1.0.0.0/8 2.0.0.0/7 4.0.0.0/6 @@ -162,7 +191,10 @@ 208.0.0.0/4 - + + 10.0.0.0/8 + 172.16.0.0/12 + 192.168.0.0/16 1.0.1.0/24 1.0.2.0/23 1.0.8.0/21 @@ -222,7 +254,6 @@ 1.192.0.0/13 1.202.0.0/15 1.204.0.0/14 - 10.0.0.0/8 14.0.0.0/21 14.0.12.0/22 14.1.0.0/22 @@ -1924,7 +1955,6 @@ 171.116.0.0/14 171.120.0.0/13 171.208.0.0/12 - 172.16.0.0/12 175.0.0.0/12 175.16.0.0/13 175.24.0.0/14 @@ -2028,7 +2058,6 @@ 183.184.0.0/13 183.192.0.0/10 192.124.154.0/24 - 192.168.0.0/16 192.188.170.0/24 202.0.100.0/23 202.0.122.0/23 @@ -3970,9 +3999,8 @@ 223.255.252.0/23 - + 0.0.0.0/7 - 10.0.0.0/8 14.0.0.0/8 27.0.0.0/8 36.0.0.0/8 @@ -4017,7 +4045,7 @@ 220.0.0.0/6 - + 1.0.0.0/23 1.0.4.0/22 1.0.16.0/20 @@ -8507,7 +8535,7 @@ 223.255.254.0/23 - + 1.0.0.0/15 1.2.0.0/16 1.4.0.0/14 diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index f9ee2beb..b18e2897 100755 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -32,6 +32,8 @@ CHN Route Bypass all sites located in China + Route + Bypass IP addresses in the route list Global Proxy Set up system-wide proxy diff --git a/src/main/res/xml/pref_all.xml b/src/main/res/xml/pref_all.xml index c59f3054..4b3bbe8b 100644 --- a/src/main/res/xml/pref_all.xml +++ b/src/main/res/xml/pref_all.xml @@ -48,12 +48,14 @@ - - + + updateSummaryEditTextPreference(pref, profile.localPort.toString) case Key.sitekey => updatePasswordEditTextPreference(pref, profile.password) case Key.encMethod => updateListPreference(pref, profile.method) - case Key.isGFWList => updateCheckBoxPreference(pref, profile.chnroute) + case Key.route => updateListPreference(pref, profile.route) case Key.isGlobalProxy => updateCheckBoxPreference(pref, profile.global) case Key.isUdpDns => updateCheckBoxPreference(pref, profile.udpdns) case _ => diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala index f76cfb45..bfbf4f1b 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala @@ -93,19 +93,14 @@ class ShadowsocksNatService extends Service with BaseService { private lazy val application = getApplication.asInstanceOf[ShadowsocksApplication] - def isACLEnabled: Boolean = { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - true - } else { - false - } - } - def startShadowsocksDaemon() { - if (isACLEnabled && config.isGFWList) { - val chn_list: Array[String] = getResources.getStringArray(R.array.chn_list_full) - ConfigUtils.printToFile(new File(Path.BASE + "chn.acl"))(p => { - chn_list.foreach(item => p.println(item)) + if (config.route != Route.ALL) { + val acl: Array[String] = config.route match { + case Route.BYPASS_LAN => getResources.getStringArray(R.array.private_route) + case Route.BYPASS_CHN => getResources.getStringArray(R.array.chn_route_full) + } + ConfigUtils.printToFile(new File(Path.BASE + "acl.list"))(p => { + acl.foreach(item => p.println(item)) }) } @@ -117,11 +112,11 @@ class ShadowsocksNatService extends Service 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 (config.isGFWList && isACLEnabled) { + if (config.route != Route.ALL) { cmd += "--acl" - cmd += (Path.BASE + "chn.acl") + cmd += (Path.BASE + "acl.list") } if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" ")) @@ -140,7 +135,7 @@ class ShadowsocksNatService extends Service with BaseService { , "-p" , config.remotePort.toString , "-k" , config.sitekey , "-m" , config.encMethod - , "-f" , (Path.BASE + "ss-tunnel.pid")) + , "-f" , Path.BASE + "ss-tunnel.pid") if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" ")) Core.sstunnel(cmd.toArray) } else { @@ -298,15 +293,6 @@ class ShadowsocksNatService extends Service with BaseService { init_sb.append(cmd_bypass.replace("0.0.0.0", "127.0.0.1")) init_sb.append(cmd_bypass.replace("-d 0.0.0.0", "-m owner --uid-owner " + myUid)) - if (config.isGFWList) { - if (!isACLEnabled) - { - val chn_list: Array[String] = getResources.getStringArray(R.array.chn_list) - for (item <- chn_list) { - init_sb.append(cmd_bypass.replace("0.0.0.0", item)) - } - } - } if (hasRedirectSupport) { init_sb .append(Utils.getIptables + " -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to " diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala index a7821f8f..e9d6d0cb 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala @@ -64,7 +64,6 @@ class ShadowsocksVpnService extends VpnService with BaseService { val TAG = "ShadowsocksVpnService" val VPN_MTU = 1500 - val PRIVATE_VLAN = "26.26.26.%s" var conn: ParcelFileDescriptor = null @@ -88,28 +87,47 @@ class ShadowsocksVpnService extends VpnService with BaseService { info.isInRange(config.proxy) } + def isPrivateA(a: Int): Boolean = { + if (a == 10 || a == 192 || a == 172) { + true + } else { + false + } + } + + def isPrivateB(a: Int, b: Int): Boolean = { + if (a == 10 || (a == 192 && b == 168) || (a == 172 && b >= 16 && b < 32)) { + true + } else { + false + } + } + def startShadowsocksDaemon() { - if (isLollipopOrAbove && config.isGFWList) { - val chn_list: Array[String] = getResources.getStringArray(R.array.chn_list_full) - ConfigUtils.printToFile(new File(Path.BASE + "chn.acl"))(p => { - chn_list.foreach(item => p.println(item)) + if (isLollipopOrAbove && config.route != Route.ALL) { + val acl: Array[String] = config.route match { + case Route.BYPASS_LAN => getResources.getStringArray(R.array.private_route) + case Route.BYPASS_CHN => getResources.getStringArray(R.array.chn_route_full) + } + ConfigUtils.printToFile(new File(Path.BASE + "acl.list"))(p => { + acl.foreach(item => p.println(item)) }) } val cmd = new ArrayBuffer[String] - cmd += ("ss-local" , "-u" - , "-b" , "127.0.0.1" - , "-s" , config.proxy - , "-p" , config.remotePort.toString - , "-l" , config.localPort.toString - , "-k" , config.sitekey - , "-m" , config.encMethod - , "-f" , Path.BASE + "ss-local.pid") + cmd +=("ss-local", "-u" + , "-b", "127.0.0.1" + , "-s", config.proxy + , "-p", config.remotePort.toString + , "-l", config.localPort.toString + , "-k", config.sitekey + , "-m", config.encMethod + , "-f", Path.BASE + "ss-local.pid") - if (config.isGFWList && isLollipopOrAbove) { + if (isLollipopOrAbove && config.route != Route.ALL) { cmd += "--acl" - cmd += (Path.BASE + "chn.acl") + cmd += (Path.BASE + "acl.list") } if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" ")) @@ -118,15 +136,15 @@ class ShadowsocksVpnService extends VpnService with BaseService { def startDnsTunnel() = { val cmd = new ArrayBuffer[String] - cmd += ("ss-tunnel" - , "-b" , "127.0.0.1" - , "-l" , "8163" - , "-L" , "8.8.8.8:53" - , "-s" , config.proxy - , "-p" , config.remotePort.toString - , "-k" , config.sitekey - , "-m" , config.encMethod - , "-f" , Path.BASE + "ss-tunnel.pid") + cmd +=("ss-tunnel" + , "-b", "127.0.0.1" + , "-l", "8163" + , "-L", "8.8.8.8:53" + , "-s", config.proxy + , "-p", config.remotePort.toString + , "-k", config.sitekey + , "-m", config.encMethod + , "-f", Path.BASE + "ss-tunnel.pid") if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" ")) Core.sstunnel(cmd.toArray) } @@ -195,52 +213,76 @@ class ShadowsocksVpnService extends VpnService with BaseService { if (InetAddressUtils.isIPv6Address(config.proxy)) { builder.addRoute("0.0.0.0", 0) - } else if (!isLollipopOrAbove && config.isGFWList) { - val gfwList = { - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { - getResources.getStringArray(R.array.simple_list) - } else { - getResources.getStringArray(R.array.gfw_list) - } - } - gfwList.foreach(cidr => { - val net = new SubnetUtils(cidr) - if (!isByass(net)) { - val addr = cidr.split('/') - builder.addRoute(addr(0), addr(1).toInt) - } - }) } else { - if (isLollipopOrAbove) { - val privateList = getResources.getStringArray(R.array.private_list) - privateList.foreach(cidr => { - val addr = cidr.split('/') - builder.addRoute(addr(0), addr(1).toInt) - }) - } else { - for (i <- 1 to 223) { - if (i != 26 && i != 127) { - val addr = i.toString + ".0.0.0" - val cidr = addr + "/8" - val net = new SubnetUtils(cidr) + if (!isLollipopOrAbove) { + config.route match { + case Route.ALL => + for (i <- 1 to 223) { + if (i != 26 && i != 127) { + val addr = i.toString + ".0.0.0" + val cidr = addr + "/8" + val net = new SubnetUtils(cidr) - if (!isByass(net)) { - if (!InetAddress.getByName(addr).isSiteLocalAddress) { - builder.addRoute(addr, 8) - } - } else { - for (j <- 0 to 255) { - val subAddr = i.toString + "." + j.toString + ".0.0" - val subCidr = subAddr + "/16" - val subNet = new SubnetUtils(subCidr) - if (!isByass(subNet)) { - if (!InetAddress.getByName(subAddr).isSiteLocalAddress) { - builder.addRoute(subAddr, 16) + if (!isByass(net)) { + builder.addRoute(addr, 8) + } else { + for (j <- 0 to 255) { + val subAddr = i.toString + "." + j.toString + ".0.0" + val subCidr = subAddr + "/16" + val subNet = new SubnetUtils(subCidr) + if (!isByass(subNet)) { + builder.addRoute(subAddr, 16) + } } } } } - } + case Route.BYPASS_LAN => + for (i <- 1 to 223) { + if (i != 26 && i != 127) { + val addr = i.toString + ".0.0.0" + val cidr = addr + "/8" + val net = new SubnetUtils(cidr) + + if (!isByass(net) && !isPrivateA(i)) { + builder.addRoute(addr, 8) + } else { + for (j <- 0 to 255) { + val subAddr = i.toString + "." + j.toString + ".0.0" + val subCidr = subAddr + "/16" + val subNet = new SubnetUtils(subCidr) + if (!isByass(subNet) && !isPrivateB(i, j)) { + builder.addRoute(subAddr, 16) + } + } + } + } + } + case Route.BYPASS_CHN => + val list = { + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { + getResources.getStringArray(R.array.simple_route) + } else { + getResources.getStringArray(R.array.gfw_route) + } + } + list.foreach(cidr => { + val net = new SubnetUtils(cidr) + if (!isByass(net)) { + val addr = cidr.split('/') + builder.addRoute(addr(0), addr(1).toInt) + } + }) + } + } else { + if (config.route == Route.ALL) { + builder.addRoute("0.0.0.0", 0) + } else { + val privateList = getResources.getStringArray(R.array.bypass_private_route) + privateList.foreach(cidr => { + val addr = cidr.split('/') + builder.addRoute(addr(0), addr(1).toInt) + }) } } } @@ -440,6 +482,8 @@ class ShadowsocksVpnService extends VpnService with BaseService { } override def getTag = TAG + override def getServiceMode = Mode.VPN + override def getContext = getBaseContext } diff --git a/src/main/scala/com/github/shadowsocks/database/DBHelper.scala b/src/main/scala/com/github/shadowsocks/database/DBHelper.scala index 736dfb62..946bcb51 100644 --- a/src/main/scala/com/github/shadowsocks/database/DBHelper.scala +++ b/src/main/scala/com/github/shadowsocks/database/DBHelper.scala @@ -51,7 +51,7 @@ object DBHelper { } class DBHelper(val context: Context) - extends OrmLiteSqliteOpenHelper(context, DBHelper.PROFILE, null, 8) { + extends OrmLiteSqliteOpenHelper(context, DBHelper.PROFILE, null, 9) { lazy val profileDao: Dao[Profile, Int] = getDao(classOf[Profile]) @@ -64,6 +64,9 @@ class DBHelper(val context: Context) if (oldVersion != newVersion) { if (oldVersion < 8) { profileDao.executeRaw("ALTER TABLE `profile` ADD COLUMN udpdns SMALLINT;") + profileDao.executeRaw("ALTER TABLE `profile` ADD COLUMN route VARCHAR;") + } else if (oldVersion < 9) { + profileDao.executeRaw("ALTER TABLE `profile` ADD COLUMN route VARCHAR;") } else { profileDao.executeRaw("DROP TABLE IF EXISTS 'profile';") onCreate(database, connectionSource) diff --git a/src/main/scala/com/github/shadowsocks/database/Profile.scala b/src/main/scala/com/github/shadowsocks/database/Profile.scala index 14d3b8ee..b2f0e9b1 100644 --- a/src/main/scala/com/github/shadowsocks/database/Profile.scala +++ b/src/main/scala/com/github/shadowsocks/database/Profile.scala @@ -66,6 +66,9 @@ class Profile { @DatabaseField var date: String = "" + @DatabaseField + var route: String = "" + @DatabaseField var upload: Int = 0 diff --git a/src/main/scala/com/github/shadowsocks/database/ProfileManager.scala b/src/main/scala/com/github/shadowsocks/database/ProfileManager.scala index 602a04af..34e2d3fd 100644 --- a/src/main/scala/com/github/shadowsocks/database/ProfileManager.scala +++ b/src/main/scala/com/github/shadowsocks/database/ProfileManager.scala @@ -77,7 +77,7 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) { } catch { case ex: Exception => Log.e(Shadowsocks.TAG, "getProfile", ex) - return None + None } } @@ -130,6 +130,7 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) { edit.putString(Key.localPort, profile.localPort.toString) edit.putString(Key.proxied, profile.individual) edit.putInt(Key.profileId, profile.id) + edit.putString(Key.route, profile.route) edit.commit() profile @@ -149,19 +150,18 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) { profile.host = settings.getString(Key.proxy, "127.0.0.1") profile.password = settings.getString(Key.sitekey, "default") profile.method = settings.getString(Key.encMethod, "table") + profile.route = settings.getString(Key.route, "all") profile.remotePort = try { Integer.valueOf(settings.getString(Key.remotePort, "1984")) } catch { - case ex: NumberFormatException => { + case ex: NumberFormatException => 1984 - } } profile.localPort = try { Integer.valueOf(settings.getString(Key.localPort, "1984")) } catch { - case ex: NumberFormatException => { + case ex: NumberFormatException => 1984 - } } profile.individual = settings.getString(Key.proxied, "") diff --git a/src/main/scala/com/github/shadowsocks/preferences/SummaryListPreference.scala b/src/main/scala/com/github/shadowsocks/preferences/SummaryListPreference.scala index d4759d2d..f1007766 100644 --- a/src/main/scala/com/github/shadowsocks/preferences/SummaryListPreference.scala +++ b/src/main/scala/com/github/shadowsocks/preferences/SummaryListPreference.scala @@ -48,7 +48,7 @@ class SummaryListPreference(context: Context, attrs: AttributeSet) override def setValue(text: String) { super.setValue(text) - setSummary(text.toUpperCase) + setSummary(getEntry) } override def setSummary(summary: CharSequence) { diff --git a/src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala b/src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala index 9dc9f706..0ee5d488 100644 --- a/src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala +++ b/src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala @@ -198,7 +198,7 @@ object ConfigUtils { val method = proxy(3).trim new Config(config.isGlobalProxy, config.isGFWList, config.isBypassApps, config.isTrafficStat, - config.isUdpDns, config.profileName, host, password, method, config.proxiedAppString, port, + config.isUdpDns, config.profileName, host, password, method, config.proxiedAppString, config.route, port, config.localPort) } @@ -213,6 +213,8 @@ object ConfigUtils { val proxy = settings.getString(Key.proxy, "127.0.0.1") val sitekey = settings.getString(Key.sitekey, "default") val encMethod = settings.getString(Key.encMethod, "table") + val route = settings.getString(Key.route, "all") + val remotePort: Int = try { settings.getString(Key.remotePort, "1984").toInt } catch { @@ -228,6 +230,6 @@ object ConfigUtils { val proxiedAppString = settings.getString(Key.proxied, "") new Config(isGlobalProxy, isGFWList, isBypassApps, isTrafficStat, isUdpDns, profileName, proxy, - sitekey, encMethod, proxiedAppString, remotePort, localPort) + sitekey, encMethod, proxiedAppString, route, remotePort, localPort) } } diff --git a/src/main/scala/com/github/shadowsocks/utils/Constants.scala b/src/main/scala/com/github/shadowsocks/utils/Constants.scala index d42b51a7..679cec50 100644 --- a/src/main/scala/com/github/shadowsocks/utils/Constants.scala +++ b/src/main/scala/com/github/shadowsocks/utils/Constants.scala @@ -68,6 +68,7 @@ object Key { val isRoot = "isRoot" val status = "status" val proxyedApps = "proxyedApps" + val route = "route" val isRunning = "isRunning" val isAutoConnect = "isAutoConnect" @@ -110,3 +111,9 @@ object Action { val UPDATE_FRAGMENT = "com.github.shadowsocks.ACTION_UPDATE_FRAGMENT" val UPDATE_PREFS = "com.github.shadowsocks.ACTION_UPDATE_PREFS" } + +object Route { + val ALL = "all" + val BYPASS_LAN = "bypass-lan" + val BYPASS_CHN = "bypass-china" +}