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")