From 93274ffb04180e8496645d25e61689e36c3b3a3e Mon Sep 17 00:00:00 2001 From: Mygod Date: Fri, 14 Apr 2017 00:08:17 +0800 Subject: [PATCH 1/9] Update android-job --- mobile/build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/build.sbt b/mobile/build.sbt index 4fcd627d8e..c15fde9d2e 100644 --- a/mobile/build.sbt +++ b/mobile/build.sbt @@ -17,7 +17,7 @@ val playServicesVersion = "10.2.1" resolvers += Resolver.jcenterRepo libraryDependencies ++= "com.futuremind.recyclerfastscroll" % "fastscroll" % "0.2.5" :: - "com.evernote" % "android-job" % "1.1.8" :: + "com.evernote" % "android-job" % "1.1.9" :: "com.github.jorgecastilloprz" % "fabprogresscircle" % "1.01" :: "com.google.android.gms" % "play-services-ads" % playServicesVersion :: "com.google.android.gms" % "play-services-analytics" % playServicesVersion :: From 85532a6b4826a3fe2803b5a1059b8772f1abf13a Mon Sep 17 00:00:00 2001 From: "V.E.O" Date: Sat, 15 Apr 2017 12:32:14 +0800 Subject: [PATCH 2/9] Add multiple remote dns support and remove alternative dns in global mode (#1217) * Add multiple remote dns support. Remove alternative dns in global mode. * Remove a redundant comment --- .../com/github/shadowsocks/BaseService.scala | 22 ++++++++++++------- .../shadowsocks/ShadowsocksNatService.scala | 2 +- .../shadowsocks/ShadowsocksVpnService.scala | 12 +++++----- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala b/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala index e84e7a6a6e..542d35add7 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala @@ -21,7 +21,6 @@ package com.github.shadowsocks import java.io.{File, IOException} -import java.net.InetAddress import java.util import java.util.concurrent.TimeUnit import java.util.{Timer, TimerTask} @@ -365,18 +364,25 @@ trait BaseService extends Service { makeDns("Primary-1", "119.29.29.29", edns = false), makeDns("Primary-2", "114.114.114.114", edns = false) ))) - .put("AlternativeDNS", new JSONArray().put(makeDns("Alternative", - buildRemoteDns(profile.remoteDns.trim)))) + .put("AlternativeDNS", new JSONArray( + for (remoteDns <- profile.remoteDns.split(",")) + yield makeDns(remoteDns.trim, buildRemoteDns(remoteDns.trim) + ))) .put("IPNetworkFile", "china_ip_list.txt") .put("DomainFile", "gfwlist.txt") case Acl.CHINALIST => config .put("PrimaryDNS", new JSONArray().put(makeDns("Primary", "119.29.29.29"))) - .put("AlternativeDNS", new JSONArray().put(makeDns("Alternative", - buildRemoteDns(profile.remoteDns.trim)))) + .put("AlternativeDNS", new JSONArray( + for (remoteDns <- profile.remoteDns.split(",")) + yield makeDns(remoteDns.trim, buildRemoteDns(remoteDns.trim) + ))) case _ => config - .put("PrimaryDNS", new JSONArray().put(makeDns("Primary", - buildRemoteDns(profile.remoteDns.trim)))) - .put("AlternativeDNS", new JSONArray().put(makeDns("Alternative", "208.67.222.222"))) + .put("PrimaryDNS", new JSONArray( + for (remoteDns <- profile.remoteDns.split(",")) + yield makeDns(remoteDns.trim, buildRemoteDns(remoteDns.trim) + ))) + // no need to setup AlternativeDNS in Acl.ALL/BYPASS_LAN mode + .put("OnlyPrimaryDNS", true) } IOUtils.writeString(new File(getFilesDir, file), config.toString) file diff --git a/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala index ef105f73df..faac923d5a 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala @@ -74,7 +74,7 @@ class ShadowsocksNatService extends BaseService { "-t", "10", "-b", "127.0.0.1", "-l", (profile.localPort + 63).toString, - "-L", profile.remoteDns.trim + ":53", + "-L", profile.remoteDns.split(",")(0).trim + ":53", "-c", buildShadowsocksConfig("ss-tunnel-nat.conf")) if (profile.udpdns) cmd.append("-u") diff --git a/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala index 8812c44763..e3bbdc4775 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala @@ -223,11 +223,13 @@ class ShadowsocksVpnService extends VpnService with BaseService { val subnet = Subnet.fromString(cidr) builder.addRoute(subnet.address.getHostAddress, subnet.prefixSize) }) - val addr = InetAddress.getByName(profile.remoteDns.trim) - if (addr.isInstanceOf[Inet6Address]) - builder.addRoute(addr, 128) - else if (addr.isInstanceOf[InetAddress]) - builder.addRoute(addr, 32) + profile.remoteDns.split(",").foreach(remoteDns => { + val addr = InetAddress.getByName(remoteDns.trim) + if (addr.isInstanceOf[Inet6Address]) + builder.addRoute(addr, 128) + else if (addr.isInstanceOf[InetAddress]) + builder.addRoute(addr, 32) + }) } conn = builder.establish() From 0b88881fa4978e20c3ea0bb6b44bc4d5e045678f Mon Sep 17 00:00:00 2001 From: Max Lv Date: Thu, 20 Apr 2017 14:10:09 +0800 Subject: [PATCH 3/9] Update shadowsocks-libev --- mobile/src/main/jni/shadowsocks-libev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/src/main/jni/shadowsocks-libev b/mobile/src/main/jni/shadowsocks-libev index de0cebb62e..aaff27ed4d 160000 --- a/mobile/src/main/jni/shadowsocks-libev +++ b/mobile/src/main/jni/shadowsocks-libev @@ -1 +1 @@ -Subproject commit de0cebb62ef3b7854972f65834af7bb8aceb4bcc +Subproject commit aaff27ed4d7a084d74259561e8da3c925c2d8034 From 6df8f14fb26c466145d0eda940f25dbe00f38df1 Mon Sep 17 00:00:00 2001 From: Max Lv Date: Sun, 23 Apr 2017 21:49:01 +0800 Subject: [PATCH 4/9] Refine server name resolving --- mobile/build.sbt | 4 ++-- mobile/src/main/res/raw/gtm_default_container | Bin 80465 -> 80471 bytes .../com/github/shadowsocks/utils/Utils.scala | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mobile/build.sbt b/mobile/build.sbt index c15fde9d2e..15a7b4d8d8 100644 --- a/mobile/build.sbt +++ b/mobile/build.sbt @@ -2,8 +2,8 @@ enablePlugins(AndroidApp) android.useSupportVectors name := "shadowsocks" -version := "4.1.4" -versionCode := Some(184) +version := "4.1.5" +versionCode := Some(185) proguardOptions ++= "-keep class com.github.shadowsocks.JniHelper { *; }" :: diff --git a/mobile/src/main/res/raw/gtm_default_container b/mobile/src/main/res/raw/gtm_default_container index a17ed04377a815c53d83840db2af2c8ce60f6c72..e20bf5c914df53b5f1b61a698f4ee7783f950ce8 100644 GIT binary patch delta 84 zcmcckh2{DemJJomDry{zLh>0UB?ZM+`ugSN<$A^W$=St*M#g#t<@)KVC3*!J13fCSu&g$ex&&Qk0*W(!t2MfRS+pBLe_)Od8Sv diff --git a/mobile/src/main/scala/com/github/shadowsocks/utils/Utils.scala b/mobile/src/main/scala/com/github/shadowsocks/utils/Utils.scala index a97f6f25f5..266703fbf5 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/utils/Utils.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/utils/Utils.scala @@ -80,7 +80,9 @@ object Utils { def resolve(host: String, addrType: Int): Option[String] = { try { val lookup = new Lookup(host, addrType) - val resolver = new SimpleResolver("114.114.114.114") + val resolver = new SimpleResolver("208.67.220.220") + resolver.setTCP(true) + resolver.setPort(443) resolver.setTimeout(5) lookup.setResolver(resolver) val result = lookup.run() From 6636cf815db3039571e2879a5ae41d9dfd5502d0 Mon Sep 17 00:00:00 2001 From: Max Lv Date: Sun, 23 Apr 2017 23:11:44 +0800 Subject: [PATCH 5/9] Replace tag manager with firebase config --- mobile/build.sbt | 4 ++ mobile/google-services.json | 50 ++++++++++++++++++ mobile/src/main/res/raw/gtm_default_container | Bin 80471 -> 0 bytes .../com/github/shadowsocks/BaseService.scala | 20 ++----- .../com/github/shadowsocks/MainActivity.scala | 1 - .../shadowsocks/ShadowsocksApplication.scala | 44 ++++++--------- project/plugins.sbt | 2 + 7 files changed, 77 insertions(+), 44 deletions(-) create mode 100644 mobile/google-services.json delete mode 100644 mobile/src/main/res/raw/gtm_default_container diff --git a/mobile/build.sbt b/mobile/build.sbt index 15a7b4d8d8..4f219da4a9 100644 --- a/mobile/build.sbt +++ b/mobile/build.sbt @@ -1,4 +1,6 @@ enablePlugins(AndroidApp) +enablePlugins(AndroidGms) + android.useSupportVectors name := "shadowsocks" @@ -19,6 +21,8 @@ libraryDependencies ++= "com.futuremind.recyclerfastscroll" % "fastscroll" % "0.2.5" :: "com.evernote" % "android-job" % "1.1.9" :: "com.github.jorgecastilloprz" % "fabprogresscircle" % "1.01" :: + "com.google.firebase" % "firebase-core" % playServicesVersion :: + "com.google.firebase" % "firebase-config" % playServicesVersion :: "com.google.android.gms" % "play-services-ads" % playServicesVersion :: "com.google.android.gms" % "play-services-analytics" % playServicesVersion :: "com.google.android.gms" % "play-services-gcm" % playServicesVersion :: diff --git a/mobile/google-services.json b/mobile/google-services.json new file mode 100644 index 0000000000..0fa9e0cfc9 --- /dev/null +++ b/mobile/google-services.json @@ -0,0 +1,50 @@ +{ + "project_info": { + "project_number": "261400168171", + "firebase_url": "https://admob-app-id-3330146721.firebaseio.com", + "project_id": "admob-app-id-3330146721", + "storage_bucket": "admob-app-id-3330146721.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:261400168171:android:dbdd6331c434162f", + "android_client_info": { + "package_name": "com.github.shadowsocks" + } + }, + "oauth_client": [ + { + "client_id": "261400168171-sfik8o3pj7e243583olorh7s5974vab1.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "com.github.shadowsocks", + "certificate_hash": "58a90f84cfe99d4280aec677c9a1292fae131677" + } + }, + { + "client_id": "261400168171-g7aelv5bu012ojr7dod7lq09c9anjimh.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCee3fAad7nb3YsxeUO9mqqHFfAvsSCbVs" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 1, + "other_platform_oauth_client": [] + }, + "ads_service": { + "status": 2 + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/mobile/src/main/res/raw/gtm_default_container b/mobile/src/main/res/raw/gtm_default_container deleted file mode 100644 index e20bf5c914df53b5f1b61a698f4ee7783f950ce8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 80471 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 diff --git a/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala b/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala index 542d35add7..a1a14cf8c0 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala @@ -127,9 +127,8 @@ trait BaseService extends Service { def connect() { profile.name = profile.getName // save original name before it's (possibly) overwritten by IP addresses if (profile.host == "198.199.101.152") { - val holder = app.containerHolder - val container = holder.getContainer - val url = container.getString("proxy_url") + val config = app.remoteConfig + val url = config.getString("proxy_url") val sig = Utils.getSignature(this) val client = new OkHttpClient.Builder() @@ -276,7 +275,7 @@ trait BaseService extends Service { override def onCreate() { super.onCreate() - app.refreshContainerHolder() + app.remoteConfig.fetch() app.updateAssets() } @@ -301,23 +300,12 @@ trait BaseService extends Service { } } - def getBlackList: String = { - val default = getString(R.string.black_list) - try { - val container = app.containerHolder.getContainer - val update = container.getString("black_list_lite") - val list = if (update == null || update.isEmpty) default else update - "exclude = " + list + ";" - } catch { - case _: Exception => "exclude = " + default + ";" - } - } - protected def buildPluginCommandLine(): ArrayBuffer[String] = { val result = ArrayBuffer(pluginPath) if (TcpFastOpen.sendEnabled) result += "--fast-open" result } + protected final def buildShadowsocksConfig(file: String): String = { val config = new JSONObject() .put("server", profile.host) diff --git a/mobile/src/main/scala/com/github/shadowsocks/MainActivity.scala b/mobile/src/main/scala/com/github/shadowsocks/MainActivity.scala index 01ca96870f..7f4745fefb 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/MainActivity.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/MainActivity.scala @@ -390,7 +390,6 @@ class MainActivity extends Activity with ServiceBoundContext with Drawer.OnDrawe protected override def onResume() { super.onResume() - app.refreshContainerHolder() state match { case State.STOPPING | State.CONNECTING => case _ => hideCircle() diff --git a/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala index 4b533e85d6..bfbe0f1705 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala @@ -38,9 +38,12 @@ import com.github.shadowsocks.acl.DonaldTrump import com.github.shadowsocks.database.{DBHelper, Profile, ProfileManager} import com.github.shadowsocks.utils.CloseUtils._ import com.github.shadowsocks.utils._ +import com.google.android.gms.tasks.OnCompleteListener +import com.google.android.gms.tasks.Task import com.google.android.gms.analytics.{GoogleAnalytics, HitBuilders, StandardExceptionParser, Tracker} import com.google.android.gms.common.api.ResultCallback -import com.google.android.gms.tagmanager.{ContainerHolder, TagManager} +import com.google.firebase.remoteconfig.FirebaseRemoteConfig +import com.google.firebase.FirebaseApp import com.j256.ormlite.logger.LocalLog import eu.chainfire.libsuperuser.Shell @@ -61,8 +64,7 @@ object ShadowsocksApplication { class ShadowsocksApplication extends Application { import ShadowsocksApplication._ - final val SIG_FUNC = "getSignature" - var containerHolder: ContainerHolder = _ + lazy val remoteConfig = FirebaseRemoteConfig.getInstance() lazy val tracker: Tracker = GoogleAnalytics.getInstance(this).newTracker(R.xml.tracker) lazy val settings: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(this) lazy val editor: SharedPreferences.Editor = settings.edit @@ -149,35 +151,23 @@ class ShadowsocksApplication extends Application { if (!BuildConfig.DEBUG) java.lang.System.setProperty(LocalLog.LOCAL_LOG_LEVEL_PROPERTY, "ERROR") AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) checkChineseLocale(getResources.getConfiguration) - val tm = TagManager.getInstance(this) - val pending = tm.loadContainerPreferNonDefault("GTM-NT8WS8", R.raw.gtm_default_container) - val callback = new ResultCallback[ContainerHolder] { - override def onResult(holder: ContainerHolder) { - if (!holder.getStatus.isSuccess) { - return - } - containerHolder = holder - val container = holder.getContainer - container.registerFunctionCallMacroCallback(SIG_FUNC, - (functionName: String, parameters: util.Map[String, AnyRef]) => { - if (functionName == SIG_FUNC) { - Utils.getSignature(getApplicationContext) - } - null - }) - } - } - pending.setResultCallback(callback, 2, TimeUnit.SECONDS) + + FirebaseApp.initializeApp(this) + + remoteConfig.fetch(60) + .addOnCompleteListener(new OnCompleteListener[Void]() { + def onComplete(task: Task[Void]) { + if (task.isSuccessful()) { + remoteConfig.activateFetched() + } + } + }) + JobManager.create(this).addJobCreator(DonaldTrump) TcpFastOpen.enabled(settings.getBoolean(Key.tfo, TcpFastOpen.sendEnabled)) } - def refreshContainerHolder() { - val holder = app.containerHolder - if (holder != null) holder.refresh() - } - def crashRecovery() { val cmd = new ArrayBuffer[String]() diff --git a/project/plugins.sbt b/project/plugins.sbt index 2bf0931cc4..8fd06146bd 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -7,3 +7,5 @@ addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.2") addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "1.1") addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") // fot sbt-0.13.5 or higher + +addSbtPlugin("org.scala-android" % "sbt-android-gms" % "0.4") From c082a23c37d078a8c19f223318c2f5978647c075 Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 24 Apr 2017 10:59:44 +0800 Subject: [PATCH 6/9] Update dependencies --- mobile/build.sbt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mobile/build.sbt b/mobile/build.sbt index 4f219da4a9..b38dceb6b9 100644 --- a/mobile/build.sbt +++ b/mobile/build.sbt @@ -28,11 +28,11 @@ libraryDependencies ++= "com.google.android.gms" % "play-services-gcm" % playServicesVersion :: "com.j256.ormlite" % "ormlite-android" % "5.0" :: "com.mikepenz" % "crossfader" % "1.5.0" :: - "com.mikepenz" % "fastadapter" % "2.5.0" :: - "com.mikepenz" % "iconics-core" % "2.8.2" :: + "com.mikepenz" % "fastadapter" % "2.5.2" :: + "com.mikepenz" % "iconics-core" % "2.8.3" :: "com.mikepenz" % "materialdrawer" % "5.9.0" :: "com.mikepenz" % "materialize" % "1.0.1" :: - "com.squareup.okhttp3" % "okhttp" % "3.6.0" :: + "com.squareup.okhttp3" % "okhttp" % "3.7.0" :: "com.twofortyfouram" % "android-plugin-api-for-locale" % "1.0.2" :: "dnsjava" % "dnsjava" % "2.1.8" :: "eu.chainfire" % "libsuperuser" % "1.0.0.201704021214" :: From 9898ab88e0596610d5eed4fd5b2df35740f54e6e Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 24 Apr 2017 11:25:11 +0800 Subject: [PATCH 7/9] Optimize firebase dependencies --- mobile/build.sbt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mobile/build.sbt b/mobile/build.sbt index b38dceb6b9..e467678d47 100644 --- a/mobile/build.sbt +++ b/mobile/build.sbt @@ -21,11 +21,10 @@ libraryDependencies ++= "com.futuremind.recyclerfastscroll" % "fastscroll" % "0.2.5" :: "com.evernote" % "android-job" % "1.1.9" :: "com.github.jorgecastilloprz" % "fabprogresscircle" % "1.01" :: - "com.google.firebase" % "firebase-core" % playServicesVersion :: - "com.google.firebase" % "firebase-config" % playServicesVersion :: "com.google.android.gms" % "play-services-ads" % playServicesVersion :: "com.google.android.gms" % "play-services-analytics" % playServicesVersion :: "com.google.android.gms" % "play-services-gcm" % playServicesVersion :: + "com.google.firebase" % "firebase-config" % playServicesVersion :: "com.j256.ormlite" % "ormlite-android" % "5.0" :: "com.mikepenz" % "crossfader" % "1.5.0" :: "com.mikepenz" % "fastadapter" % "2.5.2" :: From 915b1a74b10cb1a775e69b2213e4a0ae97eb4ccf Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 24 Apr 2017 11:37:28 +0800 Subject: [PATCH 8/9] Refine Firebase code --- .../com/github/shadowsocks/BaseService.scala | 8 ++------ .../shadowsocks/ShadowsocksApplication.scala | 17 ++--------------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala b/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala index a1a14cf8c0..5f7aed152c 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala @@ -127,10 +127,6 @@ trait BaseService extends Service { def connect() { profile.name = profile.getName // save original name before it's (possibly) overwritten by IP addresses if (profile.host == "198.199.101.152") { - val config = app.remoteConfig - val url = config.getString("proxy_url") - val sig = Utils.getSignature(this) - val client = new OkHttpClient.Builder() .dns(hostname => Utils.resolve(hostname, enableIPv6 = false) match { case Some(ip) => util.Arrays.asList(InetAddress.getByName(ip)) @@ -141,10 +137,10 @@ trait BaseService extends Service { .readTimeout(30, TimeUnit.SECONDS) .build() val requestBody = new FormBody.Builder() - .add("sig", sig) + .add("sig", Utils.getSignature(this)) .build() val request = new Request.Builder() - .url(url) + .url(app.remoteConfig.getString("proxy_url")) .post(requestBody) .build() diff --git a/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala index bfbe0f1705..631cadceea 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala @@ -21,9 +21,7 @@ package com.github.shadowsocks import java.io.{File, FileOutputStream, IOException} -import java.util import java.util.Locale -import java.util.concurrent.TimeUnit import android.annotation.SuppressLint import android.app.Application @@ -38,12 +36,9 @@ import com.github.shadowsocks.acl.DonaldTrump import com.github.shadowsocks.database.{DBHelper, Profile, ProfileManager} import com.github.shadowsocks.utils.CloseUtils._ import com.github.shadowsocks.utils._ -import com.google.android.gms.tasks.OnCompleteListener -import com.google.android.gms.tasks.Task import com.google.android.gms.analytics.{GoogleAnalytics, HitBuilders, StandardExceptionParser, Tracker} -import com.google.android.gms.common.api.ResultCallback -import com.google.firebase.remoteconfig.FirebaseRemoteConfig import com.google.firebase.FirebaseApp +import com.google.firebase.remoteconfig.FirebaseRemoteConfig import com.j256.ormlite.logger.LocalLog import eu.chainfire.libsuperuser.Shell @@ -153,15 +148,7 @@ class ShadowsocksApplication extends Application { checkChineseLocale(getResources.getConfiguration) FirebaseApp.initializeApp(this) - - remoteConfig.fetch(60) - .addOnCompleteListener(new OnCompleteListener[Void]() { - def onComplete(task: Task[Void]) { - if (task.isSuccessful()) { - remoteConfig.activateFetched() - } - } - }) + remoteConfig.fetch().addOnCompleteListener(task => if (task.isSuccessful) remoteConfig.activateFetched()) JobManager.create(this).addJobCreator(DonaldTrump) From ea738d17d717dac82486c2b63168430aa801e019 Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 24 Apr 2017 11:51:47 +0800 Subject: [PATCH 9/9] Refine #1217 --- .../com/github/shadowsocks/BaseService.scala | 30 +++++++------------ .../shadowsocks/ShadowsocksNatService.scala | 2 +- .../shadowsocks/ShadowsocksVpnService.scala | 11 ++----- 3 files changed, 13 insertions(+), 30 deletions(-) diff --git a/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala b/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala index 5f7aed152c..439c1c1927 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala @@ -315,13 +315,6 @@ trait BaseService extends Service { file } - private final def buildRemoteDns(remoteDns: String): String = { - val addr = InetAddress.getByName(remoteDns) - if (addr.isInstanceOf[Inet6Address]) - return "[" + remoteDns + "]" - remoteDns - } - protected final def buildOvertureConfig(file: String): String = { val config = new JSONObject() .put("BindAddress", ":" + (profile.localPort + 53)) @@ -333,7 +326,10 @@ trait BaseService extends Service { def makeDns(name: String, address: String, edns: Boolean = true) = { val dns = new JSONObject() .put("Name", name) - .put("Address", address + ":53") + .put("Address", (Utils.parseNumericAddress(address) match { + case _: Inet6Address => '[' + address + ']' + case _ => address + }) + ":53") .put("Timeout", 6) .put("EDNSClientSubnet", new JSONObject().put("Policy", "disable")) if (edns) dns @@ -342,29 +338,23 @@ trait BaseService extends Service { else dns.put("Protocol", "udp") dns } + val remoteDns = new JSONArray(profile.remoteDns.split(",").zipWithIndex.map { + case (dns, i) => makeDns("UserDef-" + i, dns.trim) + }) profile.route match { case Acl.BYPASS_CHN | Acl.BYPASS_LAN_CHN | Acl.GFWLIST | Acl.CUSTOM_RULES => config .put("PrimaryDNS", new JSONArray(Array( makeDns("Primary-1", "119.29.29.29", edns = false), makeDns("Primary-2", "114.114.114.114", edns = false) ))) - .put("AlternativeDNS", new JSONArray( - for (remoteDns <- profile.remoteDns.split(",")) - yield makeDns(remoteDns.trim, buildRemoteDns(remoteDns.trim) - ))) + .put("AlternativeDNS", remoteDns) .put("IPNetworkFile", "china_ip_list.txt") .put("DomainFile", "gfwlist.txt") case Acl.CHINALIST => config .put("PrimaryDNS", new JSONArray().put(makeDns("Primary", "119.29.29.29"))) - .put("AlternativeDNS", new JSONArray( - for (remoteDns <- profile.remoteDns.split(",")) - yield makeDns(remoteDns.trim, buildRemoteDns(remoteDns.trim) - ))) + .put("AlternativeDNS", remoteDns) case _ => config - .put("PrimaryDNS", new JSONArray( - for (remoteDns <- profile.remoteDns.split(",")) - yield makeDns(remoteDns.trim, buildRemoteDns(remoteDns.trim) - ))) + .put("PrimaryDNS", new JSONArray(remoteDns)) // no need to setup AlternativeDNS in Acl.ALL/BYPASS_LAN mode .put("OnlyPrimaryDNS", true) } diff --git a/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala index faac923d5a..d585583450 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala @@ -74,7 +74,7 @@ class ShadowsocksNatService extends BaseService { "-t", "10", "-b", "127.0.0.1", "-l", (profile.localPort + 63).toString, - "-L", profile.remoteDns.split(",")(0).trim + ":53", + "-L", profile.remoteDns.split(",").head.trim + ":53", "-c", buildShadowsocksConfig("ss-tunnel-nat.conf")) if (profile.udpdns) cmd.append("-u") diff --git a/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala index e3bbdc4775..e5e143d49f 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala @@ -22,8 +22,6 @@ package com.github.shadowsocks import java.io.File import java.util.Locale -import java.net.InetAddress -import java.net.Inet6Address import android.content._ import android.content.pm.PackageManager.NameNotFoundException @@ -223,13 +221,8 @@ class ShadowsocksVpnService extends VpnService with BaseService { val subnet = Subnet.fromString(cidr) builder.addRoute(subnet.address.getHostAddress, subnet.prefixSize) }) - profile.remoteDns.split(",").foreach(remoteDns => { - val addr = InetAddress.getByName(remoteDns.trim) - if (addr.isInstanceOf[Inet6Address]) - builder.addRoute(addr, 128) - else if (addr.isInstanceOf[InetAddress]) - builder.addRoute(addr, 32) - }) + profile.remoteDns.split(",").map(dns => Utils.parseNumericAddress(dns.trim)).foreach(dns => + builder.addRoute(dns, dns.getAddress.length << 3)) } conn = builder.establish()