diff --git a/.github/issue_template.md b/.github/issue_template.md index bc91020f..9edc0c99 100644 --- a/.github/issue_template.md +++ b/.github/issue_template.md @@ -29,7 +29,8 @@ _Put an `x` inside the [ ] that applies._ * [ ] IPv6 route * [ ] Per-App Proxy * [ ] Bypass mode -* [ ] UDP Forwarding +* Remote DNS: 8.8.8.8 +* [ ] DNS Forwarding * Plugin configuration (if applicable): * [ ] Auto Connect * [ ] TCP Fast Open diff --git a/.gitignore b/.gitignore index 87b1bdf9..5edaaac3 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,15 @@ local.sbt mobile/src/main/libs mobile/src/main/obj mobile/src/main/jni/overture + +mobile/src/overture/.deps +mobile/src/overture/bin +mobile/src/overture/pkg + +mobile/src/overture/src/github.com/Sirupsen +mobile/src/overture/src/github.com/mattn +mobile/src/overture/src/github.com/miekg +mobile/src/overture/src/github.com/shawn1m +mobile/src/overture/src/github.com/tools +mobile/src/overture/src/golang.org +mobile/src/overture/src/gopkg.in diff --git a/.gitmodules b/.gitmodules index 8dafbfc2..092ed998 100644 --- a/.gitmodules +++ b/.gitmodules @@ -33,6 +33,9 @@ [submodule "mobile/src/main/jni/libudns"] path = mobile/src/main/jni/libudns url = https://github.com/shadowsocks/libudns.git -[submodule "mobile/src/overture"] - path = mobile/src/overture - url = https://github.com/shadowsocks/overture-android.git +[submodule "mobile/src/overture/go"] + path = mobile/src/overture/go + url = https://github.com/shadowsocks/go.git +[submodule "mobile/src/overture/src/github.com/shadowsocks/overture"] + path = mobile/src/overture/src/github.com/shadowsocks/overture + url = https://github.com/shadowsocks/overture.git diff --git a/.jvmopts b/.jvmopts index 269d07af..598e353f 100644 --- a/.jvmopts +++ b/.jvmopts @@ -1,4 +1,3 @@ --XX:MaxPermSize=512m -Xms1g -Xmx3g -Xss2m diff --git a/build.sbt b/build.sbt index 9256082c..32e3ca64 100644 --- a/build.sbt +++ b/build.sbt @@ -1,5 +1,5 @@ lazy val commonSettings = Seq( - scalaVersion := "2.11.8", + scalaVersion := "2.11.9", dexMaxHeap := "4g", organization := "com.github.shadowsocks", @@ -11,7 +11,7 @@ lazy val commonSettings = Seq( scalacOptions ++= "-target:jvm-1.7" :: "-Xexperimental" :: Nil, ndkArgs := "-j" :: java.lang.Runtime.getRuntime.availableProcessors.toString :: Nil, - proguardVersion := "5.3.2", + proguardVersion := "5.3.3", proguardCache := Seq(), shrinkResources := true, diff --git a/mobile/build.sbt b/mobile/build.sbt index 65fe2d6c..c15fde9d 100644 --- a/mobile/build.sbt +++ b/mobile/build.sbt @@ -2,8 +2,8 @@ enablePlugins(AndroidApp) android.useSupportVectors name := "shadowsocks" -version := "4.1.3" -versionCode := Some(183) +version := "4.1.4" +versionCode := Some(184) proguardOptions ++= "-keep class com.github.shadowsocks.JniHelper { *; }" :: @@ -13,29 +13,29 @@ proguardOptions ++= "-dontwarn org.xbill.**" :: Nil -val playServicesVersion = "10.2.0" +val playServicesVersion = "10.2.1" resolvers += Resolver.jcenterRepo libraryDependencies ++= "com.futuremind.recyclerfastscroll" % "fastscroll" % "0.2.5" :: - "com.evernote" % "android-job" % "1.1.7" :: + "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 :: "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.1.7" :: + "com.mikepenz" % "fastadapter" % "2.5.0" :: "com.mikepenz" % "iconics-core" % "2.8.2" :: - "com.mikepenz" % "materialdrawer" % "5.8.2" :: + "com.mikepenz" % "materialdrawer" % "5.9.0" :: "com.mikepenz" % "materialize" % "1.0.1" :: "com.squareup.okhttp3" % "okhttp" % "3.6.0" :: "com.twofortyfouram" % "android-plugin-api-for-locale" % "1.0.2" :: "dnsjava" % "dnsjava" % "2.1.8" :: - "eu.chainfire" % "libsuperuser" % "1.0.0.201608240809" :: + "eu.chainfire" % "libsuperuser" % "1.0.0.201704021214" :: "net.glxn.qrgen" % "android" % "2.0" :: Nil -lazy val goBuild = TaskKey[Unit]("go-build", "Build go and kcptun") +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 { case 0 => // Success! diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml index 23ed5dc6..ca21e907 100644 --- a/mobile/src/main/res/values/strings.xml +++ b/mobile/src/main/res/values/strings.xml @@ -4,8 +4,7 @@ Shadowsocks Toggle - - Misc + Profile Switch to another profile or add new profiles NAT mode (deprecated) @@ -54,7 +53,7 @@ Toggling requires ROOT permission Unsupported kernel version: %s < 3.7.1 DNS Forwarding - Force to forward DNS packets to remote + Forward all DNS requests to remote Shadowsocks started. diff --git a/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala b/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala index f5e6fdb1..e84e7a6a 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala @@ -25,6 +25,8 @@ import java.net.InetAddress import java.util import java.util.concurrent.TimeUnit import java.util.{Timer, TimerTask} +import java.net.InetAddress +import java.net.Inet6Address import android.app.Service import android.content.{BroadcastReceiver, Context, Intent, IntentFilter} @@ -124,6 +126,7 @@ trait BaseService extends Service { } else true 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 @@ -329,6 +332,13 @@ 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)) @@ -355,14 +365,17 @@ 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", profile.remoteDns))) + .put("AlternativeDNS", new JSONArray().put(makeDns("Alternative", + buildRemoteDns(profile.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", profile.remoteDns))) + .put("AlternativeDNS", new JSONArray().put(makeDns("Alternative", + buildRemoteDns(profile.remoteDns.trim)))) case _ => config - .put("PrimaryDNS", new JSONArray().put(makeDns("Primary", profile.remoteDns))) + .put("PrimaryDNS", new JSONArray().put(makeDns("Primary", + buildRemoteDns(profile.remoteDns.trim)))) .put("AlternativeDNS", new JSONArray().put(makeDns("Alternative", "208.67.222.222"))) } IOUtils.writeString(new File(getFilesDir, file), config.toString) diff --git a/mobile/src/main/scala/com/github/shadowsocks/ProfilesFragment.scala b/mobile/src/main/scala/com/github/shadowsocks/ProfilesFragment.scala index 0fd3efa2..81fc22cf 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/ProfilesFragment.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/ProfilesFragment.scala @@ -352,15 +352,21 @@ final class ProfilesFragment extends ToolbarFragment with Toolbar.OnMenuItemClic def onMenuItemClick(item: MenuItem): Boolean = item.getItemId match { case R.id.action_scan_qr_code => + def installScanner() = { + Toast.makeText(getActivity, R.string.add_profile_scanner_not_installed, Toast.LENGTH_LONG).show() + try startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=tw.com.quickmark"))) catch { + case exc: ActivityNotFoundException => exc.printStackTrace() + } + } try startActivityForResult(new Intent("com.google.zxing.client.android.SCAN") .addCategory(Intent.CATEGORY_DEFAULT) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_DOCUMENT), REQUEST_SCAN_QR_CODE) catch { - case _: ActivityNotFoundException => - Toast.makeText(getActivity, R.string.add_profile_scanner_not_installed, Toast.LENGTH_LONG).show() - try startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=tw.com.quickmark"))) catch { - case exc: ActivityNotFoundException => exc.printStackTrace() - } + case _: ActivityNotFoundException => installScanner() + case e: SecurityException => + e.printStackTrace() + app.track(e) + installScanner() } true case R.id.action_import => diff --git a/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala index 3ba848a5..ef105f73 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala @@ -204,7 +204,7 @@ class ShadowsocksNatService extends BaseService { AclSyncJob.schedule(profile.route) changeState(State.CONNECTED) - notification = new ShadowsocksNotification(this, profile.getName, true) + notification = new ShadowsocksNotification(this, profile.name, true) } override def stopRunner(stopService: Boolean, msg: String = null) { diff --git a/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala index 1efe035f..8812c447 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala @@ -22,6 +22,8 @@ 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 @@ -138,7 +140,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { if (profile.route != Acl.ALL && profile.route != Acl.CUSTOM_RULES) AclSyncJob.schedule(profile.route) - notification = new ShadowsocksNotification(this, profile.getName) + notification = new ShadowsocksNotification(this, profile.name) } /** Called when the activity is first created. */ @@ -189,7 +191,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { .setMtu(VPN_MTU) .addAddress(PRIVATE_VLAN.formatLocal(Locale.ENGLISH, "1"), 24) - builder.addDnsServer(profile.remoteDns.trim) + builder.addDnsServer("8.8.8.8") // It's fake DNS for tun2socks, not the real remote DNS if (profile.ipv6) { builder.addAddress(PRIVATE_VLAN6.formatLocal(Locale.ENGLISH, "1"), 126) @@ -221,7 +223,11 @@ class ShadowsocksVpnService extends VpnService with BaseService { val subnet = Subnet.fromString(cidr) builder.addRoute(subnet.address.getHostAddress, subnet.prefixSize) }) - builder.addRoute(profile.remoteDns.trim, 32) + val addr = InetAddress.getByName(profile.remoteDns.trim) + if (addr.isInstanceOf[Inet6Address]) + builder.addRoute(addr, 128) + else if (addr.isInstanceOf[InetAddress]) + builder.addRoute(addr, 32) } conn = builder.establish() diff --git a/mobile/src/overture b/mobile/src/overture deleted file mode 160000 index 862ce347..00000000 --- a/mobile/src/overture +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 862ce347e19483fdd6f0a5c84f173c2efdc7d920 diff --git a/mobile/src/overture/go b/mobile/src/overture/go new file mode 160000 index 00000000..86036dcc --- /dev/null +++ b/mobile/src/overture/go @@ -0,0 +1 @@ +Subproject commit 86036dcce8fc7e2bd772969e6af56776cc9d8d53 diff --git a/mobile/src/overture/make.bash b/mobile/src/overture/make.bash new file mode 100755 index 00000000..bf008d15 --- /dev/null +++ b/mobile/src/overture/make.bash @@ -0,0 +1,82 @@ +#!/bin/bash + +function try () { +"$@" || exit -1 +} + +[ -z "$ANDROID_NDK_HOME" ] && ANDROID_NDK_HOME=~/android-ndk-r12b + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +MIN_API=$1 +TARGET=$DIR/../main/jni/overture +DEPS=$DIR/.deps + +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_STRIP=$ANDROID_ARM_TOOLCHAIN/bin/arm-linux-androideabi-strip + +ANDROID_ARM64_CC=$ANDROID_ARM64_TOOLCHAIN/bin/aarch64-linux-android-gcc +ANDROID_ARM64_STRIP=$ANDROID_ARM64_TOOLCHAIN/bin/aarch64-linux-android-strip + +ANDROID_X86_CC=$ANDROID_X86_TOOLCHAIN/bin/i686-linux-android-gcc +ANDROID_X86_STRIP=$ANDROID_X86_TOOLCHAIN/bin/i686-linux-android-strip + +try mkdir -p $DEPS $TARGET/armeabi-v7a $TARGET/x86 $TARGET/arm64-v8a + +if [ ! -d "$ANDROID_ARM_TOOLCHAIN" ]; then + echo "Make standalone toolchain for ARM arch" + $ANDROID_NDK_HOME/build/tools/make_standalone_toolchain.py --arch arm \ + --api $MIN_API --install-dir $ANDROID_ARM_TOOLCHAIN +fi + +if [ ! -d "$ANDROID_ARM64_TOOLCHAIN" ]; then + echo "Make standalone toolchain for ARM64 arch" + $ANDROID_NDK_HOME/build/tools/make_standalone_toolchain.py --arch arm64 \ + --api 21 --install-dir $ANDROID_ARM64_TOOLCHAIN +fi + +if [ ! -d "$ANDROID_X86_TOOLCHAIN" ]; then + echo "Make standalone toolchain for X86 arch" + $ANDROID_NDK_HOME/build/tools/make_standalone_toolchain.py --arch x86 \ + --api $MIN_API --install-dir $ANDROID_X86_TOOLCHAIN +fi + +if [ ! -d "$DIR/go/bin" ]; then + echo "Build the custom go" + + pushd $DIR/go/src + try ./make.bash + popd +fi + +export GOROOT=$DIR/go +export GOPATH=$DIR +export PATH=$GOROOT/bin:$GOPATH/bin:$PATH + +echo "Get dependences for overture" +go get -u github.com/tools/godep + +pushd $GOPATH/src/github.com/shadowsocks/overture/main +godep restore + +echo "Cross compile overture for arm" +try env CGO_ENABLED=1 CC=$ANDROID_ARM_CC GOOS=android GOARCH=arm GOARM=7 go build -ldflags="-s -w" +try $ANDROID_ARM_STRIP main +try mv main $TARGET/armeabi-v7a/liboverture.so + +echo "Cross compile overture for arm64" +try env CGO_ENABLED=1 CC=$ANDROID_ARM64_CC GOOS=android GOARCH=arm64 go build -ldflags="-s -w" +try $ANDROID_ARM64_STRIP main +try mv main $TARGET/arm64-v8a/liboverture.so + +echo "Cross compile overture for x86" +try env CGO_ENABLED=1 CC=$ANDROID_X86_CC GOOS=android GOARCH=386 go build -ldflags="-s -w" +try $ANDROID_X86_STRIP main +try mv main $TARGET/x86/liboverture.so + +popd + +echo "Successfully build overture" diff --git a/mobile/src/overture/src/github.com/shadowsocks/overture b/mobile/src/overture/src/github.com/shadowsocks/overture new file mode 160000 index 00000000..7263b82d --- /dev/null +++ b/mobile/src/overture/src/github.com/shadowsocks/overture @@ -0,0 +1 @@ +Subproject commit 7263b82d2eba2e28d70766aed36ffbc7cf0e1451 diff --git a/project/plugins.sbt b/project/plugins.sbt index f48545c8..2bf0931c 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,4 +1,4 @@ -addSbtPlugin("org.scala-android" % "sbt-android" % "1.7.6") +addSbtPlugin("org.scala-android" % "sbt-android" % "1.7.7") addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.1.10")