diff --git a/README.md b/README.md index a873cccd..f2ea0345 100644 --- a/README.md +++ b/README.md @@ -47,13 +47,13 @@ Translators can go to [POEditor](https://poeditor.com/join/project/u5VHO9vhSf) t diff --git a/build.sbt b/build.sbt index 1a8dceea..946d7cf2 100644 --- a/build.sbt +++ b/build.sbt @@ -10,6 +10,7 @@ lazy val commonSettings = Seq( javacOptions ++= "-source" :: "1.7" :: "-target" :: "1.7" :: Nil, scalacOptions ++= "-target:jvm-1.7" :: "-Xexperimental" :: Nil, ndkArgs := "-j" :: java.lang.Runtime.getRuntime.availableProcessors.toString :: Nil, + ndkAbiFilter := Seq("armeabi-v7a", "arm64-v8a", "x86"), proguardVersion := "5.3.3", proguardCache := Seq(), diff --git a/mobile/build.sbt b/mobile/build.sbt index c15fde9d..bdb07c66 100644 --- a/mobile/build.sbt +++ b/mobile/build.sbt @@ -1,40 +1,57 @@ enablePlugins(AndroidApp) +enablePlugins(AndroidGms) + android.useSupportVectors name := "shadowsocks" -version := "4.1.4" -versionCode := Some(184) +version := "4.1.7" +versionCode := Some(187) proguardOptions ++= - "-keep class com.github.shadowsocks.JniHelper { *; }" :: "-dontwarn com.google.android.gms.internal.**" :: "-dontwarn com.j256.ormlite.**" :: + "-dontwarn okhttp3.**" :: "-dontwarn okio.**" :: "-dontwarn org.xbill.**" :: + "-keep class com.github.shadowsocks.JniHelper { *; }" :: Nil -val playServicesVersion = "10.2.1" +val playServicesVersion = "10.2.6" resolvers += Resolver.jcenterRepo libraryDependencies ++= "com.futuremind.recyclerfastscroll" % "fastscroll" % "0.2.5" :: - "com.evernote" % "android-job" % "1.1.9" :: + "com.evernote" % "android-job" % "1.1.10" :: "com.github.jorgecastilloprz" % "fabprogresscircle" % "1.01" :: "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.0" :: - "com.mikepenz" % "iconics-core" % "2.8.2" :: - "com.mikepenz" % "materialdrawer" % "5.9.0" :: + "com.mikepenz" % "fastadapter" % "2.5.2" :: + "com.mikepenz" % "iconics-core" % "2.8.4" :: + "com.mikepenz" % "materialdrawer" % "5.9.1" :: "com.mikepenz" % "materialize" % "1.0.1" :: - "com.squareup.okhttp3" % "okhttp" % "3.6.0" :: + "com.squareup.okhttp3" % "okhttp" % "3.8.0" :: "com.twofortyfouram" % "android-plugin-api-for-locale" % "1.0.2" :: "dnsjava" % "dnsjava" % "2.1.8" :: "eu.chainfire" % "libsuperuser" % "1.0.0.201704021214" :: "net.glxn.qrgen" % "android" % "2.0" :: Nil +packagingOptions := PackagingOptions(excludes = + "META-INF/maven/com.squareup.okio/okio/pom.properties" :: + "META-INF/maven/com.squareup.okio/okio/pom.xml" :: + "META-INF/maven/com.squareup.okhttp3/okhttp/pom.properties" :: + "META-INF/maven/com.squareup.okhttp3/okhttp/pom.xml" :: + Nil) + +lazy val goClean = TaskKey[Unit]("go-clean", "Clean go build dependencies") +goClean := { + IO.delete(baseDirectory(base => base / "src/overture/.deps").value) + IO.delete(baseDirectory(base => base / "src/main/jni/overture").value) +} + lazy val goBuild = TaskKey[Unit]("go-build", "Build go and overture") goBuild := { Process(Seq("mobile/src/overture/make.bash", minSdkVersion.value)) ! streams.value.log match { diff --git a/mobile/google-services.json b/mobile/google-services.json new file mode 100644 index 00000000..0fa9e0cf --- /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/assets/pages/about.html b/mobile/src/main/assets/pages/about.html index fa7441fc..5020f9ef 100644 --- a/mobile/src/main/assets/pages/about.html +++ b/mobile/src/main/assets/pages/about.html @@ -291,13 +291,13 @@ along with this program. If not, see http diff --git a/mobile/src/main/jni/Android.mk b/mobile/src/main/jni/Android.mk index 90dcdf52..548fe90f 100755 --- a/mobile/src/main/jni/Android.mk +++ b/mobile/src/main/jni/Android.mk @@ -257,7 +257,7 @@ SHADOWSOCKS_SOURCES := local.c \ LOCAL_MODULE := ss-local LOCAL_SRC_FILES := $(addprefix shadowsocks-libev/src/, $(SHADOWSOCKS_SOURCES)) LOCAL_CFLAGS := -Wall -O2 -fno-strict-aliasing -DMODULE_LOCAL \ - -DUSE_CRYPTO_MBEDTLS -DANDROID -DHAVE_CONFIG_H \ + -DUSE_CRYPTO_MBEDTLS -DHAVE_CONFIG_H \ -DCONNECT_IN_PROGRESS=EINPROGRESS \ -I$(LOCAL_PATH)/include/shadowsocks-libev \ -I$(LOCAL_PATH)/include \ @@ -294,7 +294,7 @@ SHADOWSOCKS_SOURCES := tunnel.c \ LOCAL_MODULE := ss-tunnel LOCAL_SRC_FILES := $(addprefix shadowsocks-libev/src/, $(SHADOWSOCKS_SOURCES)) LOCAL_CFLAGS := -Wall -O2 -fno-strict-aliasing -DMODULE_TUNNEL \ - -DUSE_CRYPTO_MBEDTLS -DANDROID -DHAVE_CONFIG_H -DSSTUNNEL_JNI \ + -DUSE_CRYPTO_MBEDTLS -DHAVE_CONFIG_H -DSSTUNNEL_JNI \ -DCONNECT_IN_PROGRESS=EINPROGRESS \ -I$(LOCAL_PATH)/libancillary \ -I$(LOCAL_PATH)/include \ diff --git a/mobile/src/main/jni/badvpn b/mobile/src/main/jni/badvpn index 057ed9f3..e5abe704 160000 --- a/mobile/src/main/jni/badvpn +++ b/mobile/src/main/jni/badvpn @@ -1 +1 @@ -Subproject commit 057ed9f36490a9dccd5e7337fabcb142dd3afc0d +Subproject commit e5abe7048d5a1dea589e8e26b33e17dd9533c078 diff --git a/mobile/src/main/jni/libev b/mobile/src/main/jni/libev index 981fb847..52134190 160000 --- a/mobile/src/main/jni/libev +++ b/mobile/src/main/jni/libev @@ -1 +1 @@ -Subproject commit 981fb847e1e306bc40460de4a810f63f9bbc7212 +Subproject commit 5213419011ec5de302f8bc1716f348de1fb53b12 diff --git a/mobile/src/main/jni/libevent b/mobile/src/main/jni/libevent index 5d5914f0..359ca847 160000 --- a/mobile/src/main/jni/libevent +++ b/mobile/src/main/jni/libevent @@ -1 +1 @@ -Subproject commit 5d5914f00b8adefd383f66b8b352855ece22a1d7 +Subproject commit 359ca847a649b9c318f9217c0755484d98ecb779 diff --git a/mobile/src/main/jni/redsocks b/mobile/src/main/jni/redsocks index 3bc3f03c..274334f1 160000 --- a/mobile/src/main/jni/redsocks +++ b/mobile/src/main/jni/redsocks @@ -1 +1 @@ -Subproject commit 3bc3f03c182b4c4ea5138eb7bebcaafe7cc0f53b +Subproject commit 274334f14839431ae003774d99c3d1de337afff4 diff --git a/mobile/src/main/jni/shadowsocks-libev b/mobile/src/main/jni/shadowsocks-libev index de0cebb6..72622a3e 160000 --- a/mobile/src/main/jni/shadowsocks-libev +++ b/mobile/src/main/jni/shadowsocks-libev @@ -1 +1 @@ -Subproject commit de0cebb62ef3b7854972f65834af7bb8aceb4bcc +Subproject commit 72622a3e3df0d8b66f005717ecc48264275f453c 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 a17ed043..00000000 Binary files a/mobile/src/main/res/raw/gtm_default_container and /dev/null differ diff --git a/mobile/src/main/res/values-ko/strings.xml b/mobile/src/main/res/values-ko/strings.xml index 21bf407a..c7eab897 100644 --- a/mobile/src/main/res/values-ko/strings.xml +++ b/mobile/src/main/res/values-ko/strings.xml @@ -2,8 +2,7 @@ "켜기/끄기" - -"기타" + "프로필" "다른 프로필로 전환하거나 새 프로필 추가" "NAT 모드 (지원 중단)" @@ -45,4 +44,5 @@ "루트 권한이 필요합니다" "지원하지 않는 버전의 커널입니다: %s < 3.7.1" "DNS 포워딩" +"모든 DNS 요청을 외부로 포워딩 합니다" \ No newline at end of file diff --git a/mobile/src/main/res/values-ru/strings.xml b/mobile/src/main/res/values-ru/strings.xml index db707e85..30d47daf 100644 --- a/mobile/src/main/res/values-ru/strings.xml +++ b/mobile/src/main/res/values-ru/strings.xml @@ -2,22 +2,28 @@ "Подключение" - -"Разное" + "Профиль" "Переключить на другой профиль или добавить новые" "Режим NAT (не рекомендуется)" "Использовать режим NAT вместо VPN. Требует ROOT прав." -"Отправлено: \t\t\t\t\t%3$s\t↑\t%1$s/s +"Удалённый DNS" +"Отправлено: \t%3$s\t↑\t%1$s/s Получено: \t%4$s\t↓\t%2$s/s" " %1$s↑\t%2$s↓" "%1$s/s↑\t%2$s/s↓" -"Проверить подключение" + +"байт" +"байта" +"байт" +"байт" + +"Проверить соединение" "Проверка…" -"Успешно: %dms задержка" -"Сбой проверки интернет подключения: %s" -"Интернет Недоступен" +"Успешно: задержка %d мс" +"Сбой проверки интернет-соединения: %s" +"Интернет недоступен" "Код ошибки: #%d" @@ -30,7 +36,7 @@ "IPv6 Маршрут" -"Перенаправлять IPv6 траффик на удалённый сервер" +"Перенаправлять трафик IPv6 на удалённый сервер" "Маршрут" "Список GFW" "Прокси для выбранных приложений" @@ -42,22 +48,23 @@ "Запускать Shadowsocks при включении" "Переключение требует наличия ROOT прав" "Неподдерживаемая версия ядра: %s < 3.7.1" -"Проброс DNS" -"Пробрасывать DNS пакеты на удалённый сервер" +"Перенаправление DNS" +"Перенаправлять все DNS-запросы на удалённый сервер" "Shadowsocks запущен." "Неправильное имя сервера" "Ошибка при подключении к удалённому серверу" -"ВНИМАНИЕ:режим NAT не работает в Android 5.0" +"ВНИМАНИЕ: режим NAT не рекомендуется, начиная с Android 5.0" "Режим NAT требует наличия ROOT прав" "Переключить на режим VPN" "Остановить" "Останавливается…" -"Сбой запуска VPN сервиса. Требуется перезагрузка Вашего устройства." +"Не удалось запустить службу VPN. Возможно, требуется перезагрузить ваше устройство." "Закрыть" +"Пожалуйста, выберите профиль" "Прокси/Пароль не должны быть пустыми" "Подключить" "Сброс…" @@ -69,6 +76,7 @@ "Сброс" "О приложении" "Shadowsocks %s" +"Изменить" "Поделиться" "Добавить Профиль" "Применить настройки для всех профилей" @@ -78,19 +86,26 @@ "Сбой экспорта." "Успешный импорт!" "Сбой импорта." + + +"Настройка профиля" +"Удалить" +"Вы уверены, что хотите удалить этот профиль?" +"QR-код/NFC" "Добавить этот Профиль Shadowsocks?" -"Сканировать QR код" -"Настройка вручную" +"Сканировать QR-код" +"Ручные настройки" +"Пожалуйста, установите любое ZXing-совместимое приложение для сканирования QR-кодов." -"Удалён" -"%d элементы удалены" -"%d элементы удалены" -"%d элементы удалены" +"Удалено" +"Удалено %d элемента" +"Удалено %d элементов" +"Удалено %d элементов" "Вернуть" -"Запустить сервисStart the service" +"Запустить службу" "Подключиться к текущему серверу" "Подключиться к %s" "Переключить на %s" @@ -99,10 +114,30 @@ "Отправлено:" "Получено:" +"Соединение..." +"Подключено, нажмите для проверки соединения" +"Подключено" +"Не подключено" + + +"Пользовательские правила" +"Выделение..." +"Добавить правило..." +"Редактировать правило" "Все" -"Обход LAN" -"Обходной Китай" -"Обход LAN и Китай" +"Все, кроме LAN" +"Все, кроме Китая" +"Все, кроме LAN и Китая" "Список Китай" "Установить прокси для выбранных приложений" +"Подсеть/Регулярное выражение (PCRE) имени хоста" +"Доменное имя и все его поддомены" + + +"Плагин" +"Настроить..." +"Отключён" +"Неизвестный плагин %s" +"Предупреждение: этот плагин получен из недоверенного источника." +"Плагин: %s" \ No newline at end of file diff --git a/mobile/src/main/res/values-zh-rTW/strings.xml b/mobile/src/main/res/values-zh-rTW/strings.xml index e7c8c5bc..9e01852e 100644 --- a/mobile/src/main/res/values-zh-rTW/strings.xml +++ b/mobile/src/main/res/values-zh-rTW/strings.xml @@ -2,8 +2,7 @@ "切換" - -"其他" + "設定檔" "切換至其他設定檔或新增新設定檔" "NAT 模式 (已過時)" @@ -124,4 +123,12 @@ "為已選擇的應用程式設定 Proxy" "子網路/主機名稱 PCRE 模式" "網域及其所有子網域" - \ No newline at end of file + + +"插件" +"配置..." +"未啟用" +"未知插件 %s" +"警告:該插件似乎不是來自一個已知的可信任源。" +"插件: %s" + diff --git a/mobile/src/main/res/xml/default_configs.xml b/mobile/src/main/res/xml/default_configs.xml new file mode 100644 index 00000000..2f71ea5e --- /dev/null +++ b/mobile/src/main/res/xml/default_configs.xml @@ -0,0 +1,7 @@ + + + + proxy_url + https://www.socks123.pw/get.php + + diff --git a/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala b/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala index e84e7a6a..b9a8ac02 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} @@ -127,12 +126,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 sig = Utils.getSignature(this) + if (profile.host == "198.199.101.152") { val client = new OkHttpClient.Builder() .dns(hostname => Utils.resolve(hostname, enableIPv6 = false) match { case Some(ip) => util.Arrays.asList(InetAddress.getByName(ip)) @@ -143,10 +138,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() @@ -277,7 +272,6 @@ trait BaseService extends Service { override def onCreate() { super.onCreate() - app.refreshContainerHolder() app.updateAssets() } @@ -302,23 +296,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) @@ -332,16 +315,9 @@ 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)) + .put("BindAddress", "127.0.0.1:" + (profile.localPort + 53)) .put("RedirectIPv6Record", true) .put("DomainBase64Decode", true) .put("HostsFile", "hosts") @@ -350,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 @@ -359,24 +338,25 @@ 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().put(makeDns("Alternative", - buildRemoteDns(profile.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().put(makeDns("Alternative", - buildRemoteDns(profile.remoteDns.trim)))) + .put("AlternativeDNS", remoteDns) 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", remoteDns) + // 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/GuardedProcess.scala b/mobile/src/main/scala/com/github/shadowsocks/GuardedProcess.scala index bdd6cd7c..5953d372 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/GuardedProcess.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/GuardedProcess.scala @@ -33,9 +33,9 @@ import com.github.shadowsocks.ShadowsocksApplication.app import scala.collection.JavaConversions._ import scala.collection.immutable.Stream -class StreamLogger(is: InputStream, tag: String) extends Thread { +class StreamLogger(is: InputStream, tag: String, logger: (String, String) => Int) extends Thread { override def run(): Unit = autoClose(new BufferedReader(new InputStreamReader(is)))(br => - try Stream.continually(br.readLine()).takeWhile(_ != null).foreach(Log.i(tag, _)) catch { + try Stream.continually(br.readLine()).takeWhile(_ != null).foreach(logger(tag, _)) catch { case _: IOException => }) } @@ -68,8 +68,8 @@ class GuardedProcess(cmd: String*) { .directory(app.getFilesDir) .start() - val is = process.getInputStream - new StreamLogger(is, TAG).start() + new StreamLogger(process.getInputStream(), TAG, Log.i).start() + new StreamLogger(process.getErrorStream(), TAG, Log.e).start() if (callback == null) callback = onRestartCallback else callback() diff --git a/mobile/src/main/scala/com/github/shadowsocks/MainActivity.scala b/mobile/src/main/scala/com/github/shadowsocks/MainActivity.scala index 01ca9687..61211364 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/MainActivity.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/MainActivity.scala @@ -390,7 +390,7 @@ class MainActivity extends Activity with ServiceBoundContext with Drawer.OnDrawe protected override def onResume() { super.onResume() - app.refreshContainerHolder() + app.remoteConfig.fetch() 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 4b533e85..96840c4b 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 @@ -39,8 +37,8 @@ import com.github.shadowsocks.database.{DBHelper, Profile, ProfileManager} import com.github.shadowsocks.utils.CloseUtils._ import com.github.shadowsocks.utils._ 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.FirebaseApp +import com.google.firebase.remoteconfig.FirebaseRemoteConfig import com.j256.ormlite.logger.LocalLog import eu.chainfire.libsuperuser.Shell @@ -61,8 +59,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 +146,16 @@ 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.setDefaults(R.xml.default_configs) + remoteConfig.fetch().addOnCompleteListener(task => 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/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala index ef105f73..d5855834 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(",").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 8812c447..81ac83ee 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 @@ -145,7 +143,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { /** Called when the activity is first created. */ def handleConnection() { - + startShadowsocksDaemon() if (!profile.udpdns) { @@ -216,18 +214,17 @@ class ShadowsocksVpnService extends VpnService with BaseService { } } - if (profile.route == Acl.ALL || profile.route == Acl.BYPASS_CHN) { + if (profile.route == Acl.ALL + || profile.route == Acl.BYPASS_CHN + || profile.route == Acl.CUSTOM_RULES) { builder.addRoute("0.0.0.0", 0) } else { getResources.getStringArray(R.array.bypass_private_route).foreach(cidr => { 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(",").map(dns => Utils.parseNumericAddress(dns.trim)).foreach(dns => + builder.addRoute(dns, dns.getAddress.length << 3)) } conn = builder.establish() @@ -250,7 +247,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { cmd += "--enable-udprelay" if (!profile.udpdns) - cmd += ("--dnsgw", "%s:%d".formatLocal(Locale.ENGLISH, PRIVATE_VLAN.formatLocal(Locale.ENGLISH, "1"), + cmd += ("--dnsgw", "%s:%d".formatLocal(Locale.ENGLISH, "127.0.0.1", profile.localPort + 53)) tun2socksProcess = new GuardedProcess(cmd: _*).start(() => sendFd(fd)) diff --git a/mobile/src/main/scala/com/github/shadowsocks/acl/AclSyncJob.scala b/mobile/src/main/scala/com/github/shadowsocks/acl/AclSyncJob.scala index 54129aef..c532039c 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/acl/AclSyncJob.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/acl/AclSyncJob.scala @@ -34,6 +34,7 @@ import scala.io.Source */ object AclSyncJob { final val TAG = "AclSyncJob" + final val MAX_RESCHEDULE = 3 def schedule(route: String): Int = new JobRequest.Builder(AclSyncJob.TAG + ':' + route) .setExecutionWindow(TimeUnit.SECONDS.toMillis(10), TimeUnit.DAYS.toMillis(28)) @@ -54,7 +55,7 @@ class AclSyncJob(route: String) extends Job { } catch { case e: IOException => e.printStackTrace() - Result.RESCHEDULE + if (params.getFailureCount < AclSyncJob.MAX_RESCHEDULE) Result.RESCHEDULE else Result.FAILURE case e: Exception => // unknown failures, probably shouldn't retry e.printStackTrace() Result.FAILURE 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 a97f6f25..266703fb 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() diff --git a/mobile/src/overture/go b/mobile/src/overture/go index 86036dcc..26db64c7 160000 --- a/mobile/src/overture/go +++ b/mobile/src/overture/go @@ -1 +1 @@ -Subproject commit 86036dcce8fc7e2bd772969e6af56776cc9d8d53 +Subproject commit 26db64c76604b35e756f593d8ce25da5a83af6b6 diff --git a/mobile/src/overture/make.bash b/mobile/src/overture/make.bash index bf008d15..36242a77 100755 --- a/mobile/src/overture/make.bash +++ b/mobile/src/overture/make.bash @@ -4,7 +4,7 @@ function try () { "$@" || exit -1 } -[ -z "$ANDROID_NDK_HOME" ] && ANDROID_NDK_HOME=~/android-ndk-r12b +[ -z "$ANDROID_NDK_HOME" ] && ANDROID_NDK_HOME=$ANDROID_HOME/ndk-bundle DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" MIN_API=$1 @@ -15,13 +15,13 @@ ANDROID_ARM_TOOLCHAIN=$DEPS/android-toolchain-${MIN_API}-arm ANDROID_ARM64_TOOLCHAIN=$DEPS/android-toolchain-21-arm64 ANDROID_X86_TOOLCHAIN=$DEPS/android-toolchain-${MIN_API}-x86 -ANDROID_ARM_CC=$ANDROID_ARM_TOOLCHAIN/bin/arm-linux-androideabi-gcc +ANDROID_ARM_CC=$ANDROID_ARM_TOOLCHAIN/bin/arm-linux-androideabi-clang ANDROID_ARM_STRIP=$ANDROID_ARM_TOOLCHAIN/bin/arm-linux-androideabi-strip -ANDROID_ARM64_CC=$ANDROID_ARM64_TOOLCHAIN/bin/aarch64-linux-android-gcc +ANDROID_ARM64_CC=$ANDROID_ARM64_TOOLCHAIN/bin/aarch64-linux-android-clang ANDROID_ARM64_STRIP=$ANDROID_ARM64_TOOLCHAIN/bin/aarch64-linux-android-strip -ANDROID_X86_CC=$ANDROID_X86_TOOLCHAIN/bin/i686-linux-android-gcc +ANDROID_X86_CC=$ANDROID_X86_TOOLCHAIN/bin/i686-linux-android-clang ANDROID_X86_STRIP=$ANDROID_X86_TOOLCHAIN/bin/i686-linux-android-strip try mkdir -p $DEPS $TARGET/armeabi-v7a $TARGET/x86 $TARGET/arm64-v8a diff --git a/mobile/src/overture/src/github.com/shadowsocks/overture b/mobile/src/overture/src/github.com/shadowsocks/overture index 7263b82d..943e9dcb 160000 --- a/mobile/src/overture/src/github.com/shadowsocks/overture +++ b/mobile/src/overture/src/github.com/shadowsocks/overture @@ -1 +1 @@ -Subproject commit 7263b82d2eba2e28d70766aed36ffbc7cf0e1451 +Subproject commit 943e9dcb62c47e9016b39185c4d92592e05b6fbb diff --git a/plugin/src/main/res/values-ru/strings.xml b/plugin/src/main/res/values-ru/strings.xml index 12b5ce91..0e708a6e 100644 --- a/plugin/src/main/res/values-ru/strings.xml +++ b/plugin/src/main/res/values-ru/strings.xml @@ -6,4 +6,10 @@ "Дополнительные Настройки" + + +"Да" +"Нет" +"Изменения не сохранены. Сохранить?" +"Применить" \ No newline at end of file diff --git a/project/plugins.sbt b/project/plugins.sbt index 2bf0931c..8fd06146 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")