Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4817539ca2 | ||
|
|
03c857536d | ||
|
|
14038cd152 | ||
|
|
935314a1c5 | ||
|
|
7263bf11a4 | ||
|
|
e766ae2244 | ||
|
|
f3ed157145 | ||
|
|
eb0d5ceccc | ||
|
|
2ffbf4c56f | ||
|
|
9ee3bab7e0 | ||
|
|
70a7317a1e | ||
|
|
43caaa684f | ||
|
|
586c5e2ae4 | ||
|
|
416d93062f | ||
|
|
66ceed8607 | ||
|
|
a073f850d6 | ||
|
|
6ab4540726 | ||
|
|
9e59201596 | ||
|
|
b9a33cf1db | ||
|
|
bae5e9d06b | ||
|
|
455aa15f18 |
+3
-4
@@ -14,6 +14,7 @@ gen_*
|
||||
*.class
|
||||
*.o
|
||||
local.sbt
|
||||
.deps
|
||||
|
||||
#Intellij IDEA
|
||||
*.iml
|
||||
@@ -26,8 +27,6 @@ out/
|
||||
#NDK
|
||||
src/main/obj
|
||||
src/main/libs
|
||||
src/main/assets/armeabi
|
||||
src/main/assets/armeabi-v7a
|
||||
src/main/assets/x86
|
||||
src/main/assets/api-16/
|
||||
src/main/assets/armeabi-v7a/*
|
||||
src/main/assets/x86/*
|
||||
jni/Application.mk
|
||||
|
||||
@@ -24,3 +24,9 @@
|
||||
path = src/main/jni/pdnsd
|
||||
url = https://github.com/shadowsocks/pdnsd.git
|
||||
branch = shadowsocks-android
|
||||
[submodule "kcptun/kcptun"]
|
||||
path = kcptun/kcptun
|
||||
url = https://github.com/shadowsocks/kcptun
|
||||
[submodule "kcptun/go"]
|
||||
path = kcptun/go
|
||||
url = https://github.com/shadowsocks/go
|
||||
|
||||
@@ -31,6 +31,7 @@ install:
|
||||
- ./travis-ci/setup.sh
|
||||
- export NDK_CCACHE=ccache
|
||||
- export ARCH=`uname -m`
|
||||
- export GOROOT_BOOTSTRAP=$HOME/.android/go
|
||||
- export ANDROID_NDK_HOME=$HOME/.android/android-ndk-r12b
|
||||
- export ANDROID_HOME=$HOME/.android/android-sdk-linux
|
||||
- export PATH=${ANDROID_NDK_HOME}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${PATH}
|
||||
|
||||
@@ -12,6 +12,7 @@ A [shadowsocks](http://shadowsocks.org) client for Android, written in Scala.
|
||||
|
||||
* JDK 1.8
|
||||
* SBT 0.13.0+
|
||||
* GO 1.4+
|
||||
* Android SDK r25+
|
||||
* Android NDK r12b+
|
||||
|
||||
@@ -19,6 +20,7 @@ A [shadowsocks](http://shadowsocks.org) client for Android, written in Scala.
|
||||
|
||||
* Set environment variable `ANDROID_HOME` to `/path/to/android-sdk`
|
||||
* Set environment variable `ANDROID_NDK_HOME` to `/path/to/android-ndk`
|
||||
* Set environment variable `GOROOT_BOOTSTRAP` to `/path/to/go`
|
||||
* Create your key following the instructions at https://developer.android.com/studio/publish/app-signing.html
|
||||
* Put your key in ~/.keystore
|
||||
* Create `local.properties` from `local.properties.example` with your own key information
|
||||
@@ -26,33 +28,11 @@ A [shadowsocks](http://shadowsocks.org) client for Android, written in Scala.
|
||||
|
||||
```bash
|
||||
git submodule update --init
|
||||
|
||||
|
||||
# Build the App
|
||||
sbt native-build clean android:package-release
|
||||
```
|
||||
|
||||
#### BUILD on Mac OS X (with HomeBrew)
|
||||
|
||||
* Install Android SDK and NDK by run `brew install android-ndk android-sdk`
|
||||
* Add `export ANDROID_HOME=/usr/local/Cellar/android-sdk/$version` to your .bashrc , then reopen the shell to load it.
|
||||
* Add `export ANDROID_NDK_HOME=/usr/local/Cellar/android-ndk/$version` to your .bashrc , then reopen the shell to load it.
|
||||
* echo "y" | android update sdk --filter tools,platform-tools,build-tools-23.0.2,android-23,extra-google-m2repository --no-ui -a
|
||||
* echo "y" | android update sdk --filter extra-android-m2repository --no-ui --no-https -a
|
||||
* Create your key following the instructions at http://developer.android.com/guide/publishing/app-signing.html#cert
|
||||
* Put your key in ~/.keystore
|
||||
* Create `local.properties` from `local.properties.example` with your own key information .
|
||||
* Invoke the building like this
|
||||
|
||||
```bash
|
||||
git submodule update --init
|
||||
|
||||
# Build native binaries
|
||||
./build.sh
|
||||
|
||||
# Build the apk
|
||||
sbt clean android:package-release
|
||||
```
|
||||
|
||||
## OPEN SOURCE LICENSES
|
||||
|
||||
* shadowsocks-libev: [GPLv3](https://github.com/shadowsocks/shadowsocks-libev/blob/master/LICENSE)
|
||||
@@ -62,6 +42,7 @@ A [shadowsocks](http://shadowsocks.org) client for Android, written in Scala.
|
||||
* pdnsd: [GPLv3](https://github.com/shadowsocks/shadowsocks-android/blob/master/src/main/jni/pdnsd/COPYING)
|
||||
* libev: [GPLv2](https://github.com/shadowsocks/shadowsocks-android/blob/master/src/main/jni/libev/LICENSE)
|
||||
* libevent: [BSD](https://github.com/shadowsocks/libevent/blob/master/LICENSE)
|
||||
* kcptun: [MIT](https://github.com/xtaci/kcptun)
|
||||
|
||||
### LICENSE
|
||||
|
||||
|
||||
@@ -39,9 +39,9 @@ libraryDependencies ++= Seq(
|
||||
"net.glxn.qrgen" % "android" % "2.0",
|
||||
"com.google.android.gms" % "play-services-ads" % "9.2.1",
|
||||
"com.google.android.gms" % "play-services-analytics" % "9.2.1",
|
||||
"com.android.support" % "design" % "24.0.0",
|
||||
"com.android.support" % "gridlayout-v7" % "24.0.0",
|
||||
"com.android.support" % "cardview-v7" % "24.0.0",
|
||||
"com.android.support" % "design" % "24.1.0",
|
||||
"com.android.support" % "gridlayout-v7" % "24.1.0",
|
||||
"com.android.support" % "cardview-v7" % "24.1.0",
|
||||
"com.github.jorgecastilloprz" % "fabprogresscircle" % "1.01",
|
||||
"com.j256.ormlite" % "ormlite-android" % "4.48",
|
||||
"com.twofortyfouram" % "android-plugin-api-for-locale" % "1.0.2",
|
||||
@@ -55,6 +55,8 @@ proguardCache in Android := Seq()
|
||||
|
||||
proguardOptions in Android ++= Seq(
|
||||
"-keep class com.github.shadowsocks.System { *; }",
|
||||
"-dontwarn com.google.android.gms.**",
|
||||
"-keep class com.google.android.gms.**",
|
||||
"-dontnote com.google.android.gms.internal.**",
|
||||
"-dontnote com.j256.ormlite.**",
|
||||
"-dontnote me.dm7.barcodescannerview.**",
|
||||
|
||||
@@ -4,21 +4,25 @@ function try () {
|
||||
"$@" || exit -1
|
||||
}
|
||||
|
||||
try pushd src/main
|
||||
|
||||
# Build
|
||||
#try $ANDROID_NDK_HOME/ndk-build clean
|
||||
# Build native binaries
|
||||
pushd src/main
|
||||
try $ANDROID_NDK_HOME/ndk-build -j8
|
||||
|
||||
# copy executables
|
||||
rm -rf assets/armeabi-v7a
|
||||
rm -rf assets/x86
|
||||
mkdir -p assets/armeabi-v7a
|
||||
mkdir -p assets/x86
|
||||
|
||||
#copy executables
|
||||
for app in pdnsd redsocks ss-local ss-tunnel tun2socks
|
||||
do
|
||||
echo $app
|
||||
try mv libs/armeabi-v7a/$app assets/armeabi-v7a/
|
||||
try mv libs/x86/$app assets/x86/
|
||||
done
|
||||
popd
|
||||
|
||||
try popd
|
||||
# Build kcptun
|
||||
pushd kcptun
|
||||
try ./make.bash
|
||||
popd
|
||||
|
||||
Submodule
+1
Submodule kcptun/go added at f3e7e7b69f
Submodule
+1
Submodule kcptun/kcptun added at eced3949b2
Executable
+65
@@ -0,0 +1,65 @@
|
||||
#!/bin/bash
|
||||
|
||||
function try () {
|
||||
"$@" || exit -1
|
||||
}
|
||||
|
||||
[ -z "$ANDROID_NDK_HOME" ] && ANDROID_NDK_HOME=~/android-ndk-r12b
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
DEPS=$DIR/.deps
|
||||
ANDROID_ARM_TOOLCHAIN=$DEPS/android-toolchain-16-arm
|
||||
ANDROID_X86_TOOLCHAIN=$DEPS/android-toolchain-16-x86
|
||||
|
||||
ANDROID_ARM_CC=$ANDROID_ARM_TOOLCHAIN/bin/arm-linux-androideabi-gcc
|
||||
ANDROID_ARM_STRIP=$ANDROID_ARM_TOOLCHAIN/bin/arm-linux-androideabi-strip
|
||||
|
||||
ANDROID_X86_CC=$ANDROID_X86_TOOLCHAIN/bin/i686-linux-android-gcc
|
||||
ANDROID_X86_STRIP=$ANDROID_X86_TOOLCHAIN/bin/i686-linux-android-strip
|
||||
|
||||
|
||||
if [ ! -d "$DEPS" ]; then
|
||||
mkdir -p $DEPS
|
||||
fi
|
||||
|
||||
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 16 --install-dir $ANDROID_ARM_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 16 --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=$DEPS
|
||||
export PATH=$GOROOT/bin:$PATH
|
||||
|
||||
pushd kcptun/client
|
||||
|
||||
echo "Get dependences for kcptun"
|
||||
go get
|
||||
|
||||
echo "Cross compile kcptun for arm"
|
||||
try env CGO_ENABLED=1 CC=$ANDROID_ARM_CC GOOS=android GOARCH=arm GOARM=7 go build
|
||||
try $ANDROID_ARM_STRIP client
|
||||
try mv client $DIR/../src/main/assets/armeabi-v7a/kcptun
|
||||
|
||||
echo "Cross compile kcptun for x86"
|
||||
try env CGO_ENABLED=1 CC=$ANDROID_X86_CC GOOS=android GOARCH=386 go build
|
||||
try $ANDROID_X86_STRIP client
|
||||
try mv client $DIR/../src/main/assets/x86/kcptun
|
||||
popd
|
||||
|
||||
echo "Successfully build kcptun"
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
addSbtPlugin("org.scala-android" % "sbt-android" % "1.6.8")
|
||||
addSbtPlugin("org.scala-android" % "sbt-android" % "1.6.10")
|
||||
|
||||
addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.1.10")
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools" package="com.github.shadowsocks"
|
||||
android:versionCode="141"
|
||||
android:versionName="2.10.8">
|
||||
android:versionCode="144"
|
||||
android:versionName="3.0.2">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
|
||||
@@ -296,6 +296,7 @@ along with this program. If not, see <a href="http://www.gnu.org/licenses/">http
|
||||
<li>pdnsd: <a href="https://github.com/shadowsocks/shadowsocks-android/blob/master/src/main/jni/pdnsd/COPYING">GPLv3</a></li>
|
||||
<li>libev: <a href="https://github.com/shadowsocks/libevent/blob/shadowsocks-android/LICENSE">GPLv2</a></li>
|
||||
<li>libevent: <a href="https://github.com/shadowsocks/shadowsocks-android/blob/master/src/main/jni/libevent/LICENSE">BSD</a></li>
|
||||
<li>kcptun: <a href="https://github.com/xtaci/kcptun/commits/master/LICENSE.md">MIT</a></li>
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
|
||||
Submodule src/main/jni/shadowsocks-libev updated: d4aabcb40b...915047e957
@@ -134,4 +134,11 @@
|
||||
<!-- status -->
|
||||
<string name="sent">Отправлено:</string>
|
||||
<string name="received">Получено:</string>
|
||||
|
||||
<!-- kcp -->
|
||||
<string name="kcp_summary">Включить Shadowsocks над KCPTUN</string>
|
||||
<string name="kcp_port">KCP порт</string>
|
||||
<string name="kcp_port_summary">%d (KCPTUN омер порта удалённого сервера)</string>
|
||||
<string name="kcpcli">KCP параметры</string>
|
||||
<string name="kcpcli_summary">Командная строка KCPTUN</string>
|
||||
</resources>
|
||||
|
||||
@@ -134,4 +134,11 @@
|
||||
<string name="sent">发送:</string>
|
||||
<string name="received">接收:</string>
|
||||
|
||||
<!-- kcp -->
|
||||
<string name="kcp_summary">启用 KCP 协议</string>
|
||||
<string name="kcp_port">KCP 端口</string>
|
||||
<string name="kcp_port_summary">%d(远端 KCPTUN 服务器的端口号)</string>
|
||||
<string name="kcpcli">KCP 参数</string>
|
||||
<string name="kcpcli_summary">KCPTUN 的命令行参数</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -136,4 +136,11 @@
|
||||
<string name="sent">傳送:</string>
|
||||
<string name="received">接收:</string>
|
||||
|
||||
<!-- kcp -->
|
||||
<string name="kcp_summary">啟用 KCP 協定</string>
|
||||
<string name="kcp_port">KCP 連接埠</string>
|
||||
<string name="kcp_port_summary">%d(遠端 KCPTUN 伺服器的連接埠號碼)</string>
|
||||
<string name="kcpcli">KCP 參數</string>
|
||||
<string name="kcpcli_summary">KCPTUN 的命令行參數</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -139,4 +139,12 @@
|
||||
<!-- status -->
|
||||
<string name="sent">Sent:</string>
|
||||
<string name="received">Received:</string>
|
||||
|
||||
<!-- kcp -->
|
||||
<string name="kcp" translatable="false">KCP</string>
|
||||
<string name="kcp_summary">Enable Shadowsocks over KCP</string>
|
||||
<string name="kcp_port">KCP Port</string>
|
||||
<string name="kcp_port_summary">%d (port number of the remote KCPTUN server)</string>
|
||||
<string name="kcpcli">KCP Parameters (CLI)</string>
|
||||
<string name="kcpcli_summary">The command line of KCPTUN</string>
|
||||
</resources>
|
||||
|
||||
@@ -77,6 +77,31 @@
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="@string/kcp">
|
||||
|
||||
<SwitchPreference
|
||||
android:key="kcp"
|
||||
android:persistent="false"
|
||||
android:summary="@string/kcp_summary"
|
||||
android:title="@string/kcp"/>
|
||||
|
||||
<com.github.shadowsocks.preferences.NumberPickerPreference
|
||||
app:min="1"
|
||||
app:max="65535"
|
||||
android:key="kcpPort"
|
||||
android:persistent="false"
|
||||
android:summary="@string/kcp_port_summary"
|
||||
android:title="@string/kcp_port"/>
|
||||
|
||||
<com.github.shadowsocks.preferences.SummaryEditTextPreference
|
||||
android:key="kcpcli"
|
||||
android:persistent="false"
|
||||
android:summary="@string/kcpcli_summary"
|
||||
android:title="@string/kcpcli"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/misc_cat">
|
||||
|
||||
<SwitchPreference
|
||||
|
||||
@@ -43,10 +43,12 @@ import java.util.{Timer, TimerTask}
|
||||
|
||||
import android.app.Service
|
||||
import android.content.{BroadcastReceiver, Context, Intent, IntentFilter}
|
||||
import android.net.ConnectivityManager
|
||||
import android.os.{Handler, RemoteCallbackList}
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
|
||||
import com.github.kevinsawicki.http.HttpRequest
|
||||
import com.github.shadowsocks.aidl.{IShadowsocksService, IShadowsocksServiceCallback}
|
||||
import com.github.shadowsocks.utils._
|
||||
@@ -71,6 +73,16 @@ trait BaseService extends Service {
|
||||
}
|
||||
var closeReceiverRegistered: Boolean = _
|
||||
|
||||
var kcptunProcess: GuardedProcess = _
|
||||
private val networkReceiver: BroadcastReceiver = (context: Context, intent: Intent) => {
|
||||
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE).asInstanceOf[ConnectivityManager]
|
||||
val activeNetwork = cm.getActiveNetworkInfo()
|
||||
val isConnected = activeNetwork != null && activeNetwork.isConnected()
|
||||
|
||||
if (isConnected && profile.kcp && kcptunProcess != null) kcptunProcess.restart()
|
||||
}
|
||||
var networkReceiverRegistered: Boolean = _
|
||||
|
||||
val binder = new IShadowsocksService.Stub {
|
||||
override def getState: Int = {
|
||||
state
|
||||
@@ -162,6 +174,14 @@ trait BaseService extends Service {
|
||||
closeReceiverRegistered = true
|
||||
}
|
||||
|
||||
if (profile.kcp && !networkReceiverRegistered) {
|
||||
// register network change receiver
|
||||
val filter = new IntentFilter()
|
||||
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION)
|
||||
registerReceiver(networkReceiver, filter)
|
||||
networkReceiverRegistered = true
|
||||
}
|
||||
|
||||
app.track(getClass.getSimpleName, "start")
|
||||
|
||||
changeState(State.CONNECTING)
|
||||
@@ -177,6 +197,10 @@ trait BaseService extends Service {
|
||||
unregisterReceiver(closeReceiver)
|
||||
closeReceiverRegistered = false
|
||||
}
|
||||
if (networkReceiverRegistered) {
|
||||
unregisterReceiver(networkReceiver)
|
||||
networkReceiverRegistered = false
|
||||
}
|
||||
|
||||
// Make sure update total traffic when stopping the runner
|
||||
updateTrafficTotal(TrafficMonitor.txTotal, TrafficMonitor.rxTotal)
|
||||
|
||||
@@ -56,6 +56,7 @@ class GuardedProcess(cmd: Seq[String]) extends Process {
|
||||
@volatile private var guardThread: Thread = _
|
||||
@volatile private var isDestroyed: Boolean = _
|
||||
@volatile private var process: Process = _
|
||||
@volatile private var isRestart = false
|
||||
|
||||
def start(onRestartCallback: () => Unit = null): GuardedProcess = {
|
||||
val semaphore = new Semaphore(1)
|
||||
@@ -76,9 +77,13 @@ class GuardedProcess(cmd: Seq[String]) extends Process {
|
||||
semaphore.release
|
||||
process.waitFor
|
||||
|
||||
if (currentTimeMillis - startTime < 1000) {
|
||||
Log.w(TAG, "process exit too fast, stop guard: " + cmd)
|
||||
isDestroyed = true
|
||||
if (isRestart) {
|
||||
isRestart = false
|
||||
} else {
|
||||
if (currentTimeMillis - startTime < 1000) {
|
||||
Log.w(TAG, "process exit too fast, stop guard: " + cmd)
|
||||
isDestroyed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
@@ -108,6 +113,11 @@ class GuardedProcess(cmd: Seq[String]) extends Process {
|
||||
}
|
||||
}
|
||||
|
||||
def restart() {
|
||||
isRestart = true
|
||||
process.destroy()
|
||||
}
|
||||
|
||||
def exitValue: Int = throw new UnsupportedOperationException
|
||||
def getErrorStream: InputStream = throw new UnsupportedOperationException
|
||||
def getInputStream: InputStream = throw new UnsupportedOperationException
|
||||
|
||||
@@ -94,7 +94,7 @@ object Shadowsocks {
|
||||
private final val TAG = "Shadowsocks"
|
||||
private final val REQUEST_CONNECT = 1
|
||||
private val EXECUTABLES = Array(Executable.PDNSD, Executable.REDSOCKS, Executable.SS_TUNNEL, Executable.SS_LOCAL,
|
||||
Executable.TUN2SOCKS)
|
||||
Executable.TUN2SOCKS, Executable.KCPTUN)
|
||||
}
|
||||
|
||||
class Shadowsocks extends AppCompatActivity with ServiceBoundContext {
|
||||
@@ -286,7 +286,7 @@ class Shadowsocks extends AppCompatActivity with ServiceBoundContext {
|
||||
def crashRecovery() {
|
||||
val cmd = new ArrayBuffer[String]()
|
||||
|
||||
for (task <- Array("ss-local", "ss-tunnel", "pdnsd", "redsocks", "tun2socks")) {
|
||||
for (task <- Array("ss-local", "ss-tunnel", "pdnsd", "redsocks", "tun2socks", "kcptun")) {
|
||||
cmd.append("killall %s".formatLocal(Locale.ENGLISH, task))
|
||||
cmd.append("rm -f %1$s/%2$s-nat.conf %1$s/%2$s-vpn.conf"
|
||||
.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir, task))
|
||||
@@ -481,7 +481,7 @@ class Shadowsocks extends AppCompatActivity with ServiceBoundContext {
|
||||
private def updatePreferenceScreen(profile: Profile) {
|
||||
if (profile.host == "198.199.101.152") if (adView == null) {
|
||||
adView = new AdView(this)
|
||||
adView.setAdUnitId("ca-app-pub-9097031975646651/7760346322")
|
||||
adView.setAdUnitId("ca-app-pub-4984938374218635/1433320509")
|
||||
adView.setAdSize(AdSize.SMART_BANNER)
|
||||
preferences.getView.asInstanceOf[ViewGroup].addView(adView, 1)
|
||||
adView.loadAd(new AdRequest.Builder().build())
|
||||
|
||||
@@ -84,9 +84,15 @@ class ShadowsocksNatService extends BaseService {
|
||||
})
|
||||
}
|
||||
|
||||
val conf = ConfigUtils
|
||||
val conf = if (profile.kcp) {
|
||||
ConfigUtils
|
||||
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, "127.0.0.1", profile.localPort + 90, profile.localPort,
|
||||
profile.password, profile.method, 600)
|
||||
} else {
|
||||
ConfigUtils
|
||||
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, profile.host, profile.remotePort, profile.localPort,
|
||||
profile.password, profile.method, 600)
|
||||
}
|
||||
Utils.printToFile(new File(getApplicationInfo.dataDir + "/ss-local-nat.conf"))(p => {
|
||||
p.println(conf)
|
||||
})
|
||||
@@ -109,10 +115,23 @@ class ShadowsocksNatService extends BaseService {
|
||||
sslocalProcess = new GuardedProcess(cmd).start()
|
||||
}
|
||||
|
||||
def startTunnel() {
|
||||
def startKcptunDaemon() {
|
||||
|
||||
val cmd = new ArrayBuffer[String]
|
||||
cmd += (getApplicationInfo.dataDir + "/kcptun"
|
||||
, "-r", profile.host + ":" + profile.kcpPort
|
||||
, "-l", "127.0.0.1:" + (profile.localPort + 90)
|
||||
, profile.kcpcli)
|
||||
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" "))
|
||||
|
||||
kcptunProcess = new GuardedProcess(cmd.mkString(" ").split(" ").toSeq).start()
|
||||
}
|
||||
|
||||
def startDNSTunnel() {
|
||||
if (profile.udpdns) {
|
||||
val conf = ConfigUtils
|
||||
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, profile.host, profile.remotePort, 8153,
|
||||
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, profile.host, profile.remotePort, profile.localPort + 53,
|
||||
profile.password, profile.method, 10)
|
||||
Utils.printToFile(new File(getApplicationInfo.dataDir + "/ss-tunnel-nat.conf"))(p => {
|
||||
p.println(conf)
|
||||
@@ -123,11 +142,10 @@ class ShadowsocksNatService extends BaseService {
|
||||
, "-t" , "10"
|
||||
, "-b" , "127.0.0.1"
|
||||
, "-L" , "8.8.8.8:53"
|
||||
, "-l" , (profile.localPort + 53).toString
|
||||
, "-P" , getApplicationInfo.dataDir
|
||||
, "-c" , getApplicationInfo.dataDir + "/ss-tunnel-nat.conf")
|
||||
|
||||
cmd += ("-l" , "8153")
|
||||
|
||||
if (profile.auth) cmd += "-A"
|
||||
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" "))
|
||||
@@ -135,18 +153,23 @@ class ShadowsocksNatService extends BaseService {
|
||||
sstunnelProcess = new GuardedProcess(cmd).start()
|
||||
|
||||
} else {
|
||||
val conf = ConfigUtils
|
||||
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, profile.host, profile.remotePort, 8163,
|
||||
val conf = if (profile.kcp) {
|
||||
ConfigUtils
|
||||
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, "127.0.0.1", profile.localPort + 90,
|
||||
profile.localPort + 63, profile.password, profile.method, 10)
|
||||
} else {
|
||||
ConfigUtils
|
||||
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, profile.host, profile.remotePort, profile.localPort + 63,
|
||||
profile.password, profile.method, 10)
|
||||
}
|
||||
Utils.printToFile(new File(getApplicationInfo.dataDir + "/ss-tunnel-nat.conf"))(p => {
|
||||
p.println(conf)
|
||||
})
|
||||
val cmdBuf = new ArrayBuffer[String]
|
||||
cmdBuf += (getApplicationInfo.dataDir + "/ss-tunnel"
|
||||
, "-u"
|
||||
, "-t" , "10"
|
||||
, "-b" , "127.0.0.1"
|
||||
, "-l" , "8163"
|
||||
, "-l" , (profile.localPort + 63).toString
|
||||
, "-L" , "8.8.8.8:53"
|
||||
, "-P", getApplicationInfo.dataDir
|
||||
, "-c" , getApplicationInfo.dataDir + "/ss-tunnel-nat.conf")
|
||||
@@ -163,10 +186,10 @@ class ShadowsocksNatService extends BaseService {
|
||||
|
||||
val conf = if (profile.route == Route.BYPASS_CHN || profile.route == Route.BYPASS_LAN_CHN) {
|
||||
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
|
||||
"127.0.0.1", 8153, getBlackList, 8163, "")
|
||||
"127.0.0.1", profile.localPort + 53, getBlackList, profile.localPort + 63, "")
|
||||
} else {
|
||||
ConfigUtils.PDNSD_LOCAL.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
|
||||
"127.0.0.1", 8153, 8163, "")
|
||||
"127.0.0.1", profile.localPort + 53, profile.localPort + 63, "")
|
||||
}
|
||||
|
||||
Utils.printToFile(new File(getApplicationInfo.dataDir + "/pdnsd-nat.conf"))(p => {
|
||||
@@ -194,10 +217,13 @@ class ShadowsocksNatService extends BaseService {
|
||||
/** Called when the activity is first created. */
|
||||
def handleConnection {
|
||||
|
||||
startTunnel()
|
||||
if (!profile.udpdns) startDnsDaemon()
|
||||
startDNSTunnel()
|
||||
startRedsocksDaemon()
|
||||
startShadowsocksDaemon()
|
||||
|
||||
if (!profile.udpdns) startDnsDaemon()
|
||||
if (profile.kcp) startKcptunDaemon()
|
||||
|
||||
setupIptables()
|
||||
|
||||
}
|
||||
@@ -212,6 +238,10 @@ class ShadowsocksNatService extends BaseService {
|
||||
}
|
||||
|
||||
def killProcesses() {
|
||||
if (kcptunProcess != null) {
|
||||
kcptunProcess.destroy()
|
||||
kcptunProcess = null
|
||||
}
|
||||
if (sslocalProcess != null) {
|
||||
sslocalProcess.destroy()
|
||||
sslocalProcess = null
|
||||
@@ -247,7 +277,8 @@ class ShadowsocksNatService extends BaseService {
|
||||
init_sb.append(cmd_bypass.replace("-p tcp -d 0.0.0.0", "-m owner --uid-owner " + myUid))
|
||||
init_sb.append(cmd_bypass.replace("-d 0.0.0.0", "--dport 53"))
|
||||
|
||||
init_sb.append("iptables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to-destination 127.0.0.1:8153")
|
||||
init_sb.append("iptables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to-destination 127.0.0.1:"
|
||||
+ (profile.localPort + 53))
|
||||
|
||||
if (!profile.proxyApps || profile.bypass) {
|
||||
http_sb.append(CMD_IPTABLES_DNAT_ADD_SOCKS)
|
||||
|
||||
@@ -18,7 +18,7 @@ object ShadowsocksSettings {
|
||||
// Constants
|
||||
private final val TAG = "ShadowsocksSettings"
|
||||
private val PROXY_PREFS = Array(Key.name, Key.host, Key.remotePort, Key.localPort, Key.password, Key.method,
|
||||
Key.auth)
|
||||
Key.auth, Key.kcp, Key.kcpPort, Key.kcpcli)
|
||||
private val FEATURE_PREFS = Array(Key.route, Key.proxyApps, Key.udpdns, Key.ipv6)
|
||||
|
||||
// Helper functions
|
||||
@@ -36,8 +36,10 @@ object ShadowsocksSettings {
|
||||
}
|
||||
|
||||
def updateSummaryEditTextPreference(pref: Preference, value: String) {
|
||||
pref.setSummary(value)
|
||||
pref.asInstanceOf[SummaryEditTextPreference].setText(value)
|
||||
if (value != null) {
|
||||
pref.setSummary(value)
|
||||
pref.asInstanceOf[SummaryEditTextPreference].setText(value)
|
||||
}
|
||||
}
|
||||
|
||||
def updateSwitchPreference(pref: Preference, value: Boolean) {
|
||||
@@ -57,6 +59,9 @@ object ShadowsocksSettings {
|
||||
case Key.udpdns => updateSwitchPreference(pref, profile.udpdns)
|
||||
case Key.auth => updateSwitchPreference(pref, profile.auth)
|
||||
case Key.ipv6 => updateSwitchPreference(pref, profile.ipv6)
|
||||
case Key.kcp => updateSwitchPreference(pref, profile.kcp)
|
||||
case Key.kcpPort => updateNumberPickerPreference(pref, profile.kcpPort)
|
||||
case Key.kcpcli => updateSummaryEditTextPreference(pref, profile.kcpcli)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,6 +108,19 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan
|
||||
app.profileManager.updateProfile(profile)
|
||||
})
|
||||
|
||||
findPreference(Key.kcp).setOnPreferenceChangeListener((_, value) => {
|
||||
profile.kcp = value.asInstanceOf[Boolean]
|
||||
app.profileManager.updateProfile(profile)
|
||||
})
|
||||
findPreference(Key.kcpPort).setOnPreferenceChangeListener((_, value) => {
|
||||
profile.kcpPort = value.asInstanceOf[Int]
|
||||
app.profileManager.updateProfile(profile)
|
||||
})
|
||||
findPreference(Key.kcpcli).setOnPreferenceChangeListener((_, value) => {
|
||||
profile.kcpcli = value.asInstanceOf[String]
|
||||
app.profileManager.updateProfile(profile)
|
||||
})
|
||||
|
||||
isProxyApps = findPreference(Key.proxyApps).asInstanceOf[SwitchPreference]
|
||||
isProxyApps.setOnPreferenceClickListener(_ => {
|
||||
startActivity(new Intent(activity, classOf[AppManager]))
|
||||
|
||||
@@ -46,7 +46,7 @@ final class ShadowsocksTileService extends TileService with ServiceBoundContext
|
||||
}
|
||||
}
|
||||
|
||||
override def onServiceConnected = callback.stateChanged(bgService.getState, null)
|
||||
override def onServiceConnected() = callback.stateChanged(bgService.getState, null)
|
||||
|
||||
override def onCreate {
|
||||
super.onCreate
|
||||
@@ -66,9 +66,9 @@ final class ShadowsocksTileService extends TileService with ServiceBoundContext
|
||||
detachService // just in case the user switches to NAT mode, also saves battery
|
||||
}
|
||||
|
||||
override def onClick = if (isLocked) unlockAndRun(toggle) else toggle()
|
||||
override def onClick() = if (isLocked) unlockAndRun(toggle) else toggle()
|
||||
|
||||
private def toggle() = bgService.getState match {
|
||||
private def toggle() = if (bgService != null) bgService.getState match {
|
||||
case State.STOPPED => Utils.startSsService(this)
|
||||
case State.CONNECTED => Utils.stopSsService(this)
|
||||
case _ => // ignore
|
||||
|
||||
@@ -109,6 +109,10 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
}
|
||||
|
||||
def killProcesses() {
|
||||
if (kcptunProcess != null) {
|
||||
kcptunProcess.destroy()
|
||||
kcptunProcess = null
|
||||
}
|
||||
if (sslocalProcess != null) {
|
||||
sslocalProcess.destroy()
|
||||
sslocalProcess = null
|
||||
@@ -177,18 +181,65 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
def handleConnection: Boolean = {
|
||||
|
||||
val fd = startVpn()
|
||||
if (!sendFd(fd)) return false
|
||||
|
||||
if (profile.kcp) {
|
||||
startKcptunDaemon()
|
||||
}
|
||||
|
||||
startShadowsocksDaemon()
|
||||
|
||||
if (profile.udpdns && profile.kcp) {
|
||||
startShadowsocksUDPDaemon()
|
||||
}
|
||||
|
||||
if (!profile.udpdns) {
|
||||
startDnsDaemon()
|
||||
startDnsTunnel()
|
||||
}
|
||||
|
||||
val fd = startVpn()
|
||||
sendFd(fd)
|
||||
true
|
||||
}
|
||||
|
||||
def startKcptunDaemon() {
|
||||
val cmd = new ArrayBuffer[String]
|
||||
cmd += (getApplicationInfo.dataDir + "/kcptun"
|
||||
, "-r", profile.host + ":" + profile.kcpPort
|
||||
, "-l", "127.0.0.1:" + (profile.localPort + 90)
|
||||
, "--path", getApplicationInfo.dataDir + "/protect_path"
|
||||
, profile.kcpcli)
|
||||
|
||||
if (BuildConfig.DEBUG)
|
||||
Log.d(TAG, cmd.mkString(" "))
|
||||
|
||||
kcptunProcess = new GuardedProcess(cmd.mkString(" ").split(" ").toSeq).start()
|
||||
}
|
||||
|
||||
def startShadowsocksUDPDaemon() {
|
||||
val conf = ConfigUtils
|
||||
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, profile.host, profile.remotePort, profile.localPort,
|
||||
profile.password, profile.method, 600)
|
||||
Utils.printToFile(new File(getApplicationInfo.dataDir + "/ss-local-udp-vpn.conf"))(p => {
|
||||
p.println(conf)
|
||||
})
|
||||
|
||||
val cmd = new ArrayBuffer[String]
|
||||
cmd += (getApplicationInfo.dataDir + "/ss-local", "-V", "-U"
|
||||
, "-b", "127.0.0.1"
|
||||
, "-t", "600"
|
||||
, "-P", getApplicationInfo.dataDir
|
||||
, "-c", getApplicationInfo.dataDir + "/ss-local-udp-vpn.conf")
|
||||
|
||||
if (profile.auth) cmd += "-A"
|
||||
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" "))
|
||||
|
||||
sstunnelProcess = new GuardedProcess(cmd).start()
|
||||
}
|
||||
|
||||
def startShadowsocksDaemon() {
|
||||
|
||||
if (profile.route != Route.ALL) {
|
||||
val acl: Array[Array[String]] = profile.route match {
|
||||
case Route.BYPASS_LAN => Array(getResources.getStringArray(R.array.private_route))
|
||||
@@ -201,15 +252,21 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
})
|
||||
}
|
||||
|
||||
val conf = ConfigUtils
|
||||
val conf = if (profile.kcp) {
|
||||
ConfigUtils
|
||||
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, "127.0.0.1", profile.localPort + 90, profile.localPort,
|
||||
profile.password, profile.method, 600)
|
||||
} else {
|
||||
ConfigUtils
|
||||
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, profile.host, profile.remotePort, profile.localPort,
|
||||
profile.password, profile.method, 600)
|
||||
}
|
||||
Utils.printToFile(new File(getApplicationInfo.dataDir + "/ss-local-vpn.conf"))(p => {
|
||||
p.println(conf)
|
||||
})
|
||||
|
||||
val cmd = new ArrayBuffer[String]
|
||||
cmd += (getApplicationInfo.dataDir + "/ss-local", "-V", "-u"
|
||||
cmd += (getApplicationInfo.dataDir + "/ss-local", "-V"
|
||||
, "-b", "127.0.0.1"
|
||||
, "-t", "600"
|
||||
, "-P", getApplicationInfo.dataDir
|
||||
@@ -217,6 +274,8 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
|
||||
if (profile.auth) cmd += "-A"
|
||||
|
||||
if (profile.udpdns && !profile.kcp) cmd += "-u"
|
||||
|
||||
if (profile.route != Route.ALL) {
|
||||
cmd += "--acl"
|
||||
cmd += (getApplicationInfo.dataDir + "/acl.list")
|
||||
@@ -228,19 +287,23 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
}
|
||||
|
||||
def startDnsTunnel() = {
|
||||
val conf = ConfigUtils
|
||||
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, profile.host, profile.remotePort, 8163,
|
||||
val conf = if (profile.kcp) {
|
||||
ConfigUtils
|
||||
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, "127.0.0.1", profile.localPort + 90, profile.localPort + 63,
|
||||
profile.password, profile.method, 10)
|
||||
} else {
|
||||
ConfigUtils
|
||||
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, profile.host, profile.remotePort, profile.localPort + 63,
|
||||
profile.password, profile.method, 10)
|
||||
}
|
||||
Utils.printToFile(new File(getApplicationInfo.dataDir + "/ss-tunnel-vpn.conf"))(p => {
|
||||
p.println(conf)
|
||||
})
|
||||
val cmd = new ArrayBuffer[String]
|
||||
cmd += (getApplicationInfo.dataDir + "/ss-tunnel"
|
||||
, "-V"
|
||||
, "-u"
|
||||
, "-t", "10"
|
||||
, "-b", "127.0.0.1"
|
||||
, "-l", "8163"
|
||||
, "-L", "8.8.8.8:53"
|
||||
, "-P", getApplicationInfo.dataDir
|
||||
, "-c", getApplicationInfo.dataDir + "/ss-tunnel-vpn.conf")
|
||||
@@ -257,10 +320,10 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
val conf = {
|
||||
if (profile.route == Route.BYPASS_CHN || profile.route == Route.BYPASS_LAN_CHN) {
|
||||
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
|
||||
"0.0.0.0", 8153, getBlackList, 8163, ipv6)
|
||||
"0.0.0.0", profile.localPort + 53, getBlackList, profile.localPort + 63, ipv6)
|
||||
} else {
|
||||
ConfigUtils.PDNSD_LOCAL.formatLocal(Locale.ENGLISH, getApplicationInfo.dataDir,
|
||||
"0.0.0.0", 8153, 8163, ipv6)
|
||||
"0.0.0.0", profile.localPort + 53, profile.localPort + 63, ipv6)
|
||||
}
|
||||
}
|
||||
Utils.printToFile(new File(getApplicationInfo.dataDir + "/pdnsd-vpn.conf"))(p => {
|
||||
@@ -354,7 +417,8 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
if (profile.udpdns)
|
||||
cmd += " --enable-udprelay"
|
||||
else
|
||||
cmd += " --dnsgw %s:8153".formatLocal(Locale.ENGLISH, PRIVATE_VLAN.formatLocal(Locale.ENGLISH, "1"))
|
||||
cmd += " --dnsgw %s:%d".formatLocal(Locale.ENGLISH, PRIVATE_VLAN.formatLocal(Locale.ENGLISH, "1"),
|
||||
profile.localPort + 53)
|
||||
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, cmd)
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ object DBHelper {
|
||||
}
|
||||
|
||||
class DBHelper(val context: Context)
|
||||
extends OrmLiteSqliteOpenHelper(context, DBHelper.PROFILE, null, 16) {
|
||||
extends OrmLiteSqliteOpenHelper(context, DBHelper.PROFILE, null, 18) {
|
||||
import DBHelper._
|
||||
|
||||
lazy val profileDao: Dao[Profile, Int] = getDao(classOf[Profile])
|
||||
@@ -125,6 +125,15 @@ class DBHelper(val context: Context)
|
||||
if (oldVersion < 16) {
|
||||
profileDao.executeRawNoArgs("UPDATE `profile` SET route = 'bypass-lan-china' WHERE route = 'bypass-china'")
|
||||
}
|
||||
|
||||
if (oldVersion < 17) {
|
||||
profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN kcp SMALLINT;")
|
||||
profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN kcpcli VARCHAR;")
|
||||
}
|
||||
|
||||
if (oldVersion < 18) {
|
||||
profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN kcpPort INTEGER;")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +99,15 @@ class Profile {
|
||||
@DatabaseField
|
||||
var userOrder: Long = _
|
||||
|
||||
@DatabaseField
|
||||
var kcp: Boolean = false
|
||||
|
||||
@DatabaseField
|
||||
var kcpPort: Int = 8399
|
||||
|
||||
@DatabaseField
|
||||
var kcpcli: String = ""
|
||||
|
||||
override def toString = "ss://" + Base64.encodeToString("%s%s:%s@%s:%d".formatLocal(Locale.ENGLISH,
|
||||
method, if (auth) "-auth" else "", password, host, remotePort).getBytes, Base64.NO_PADDING | Base64.NO_WRAP)
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ object Executable {
|
||||
val SS_LOCAL = "ss-local"
|
||||
val SS_TUNNEL = "ss-tunnel"
|
||||
val TUN2SOCKS = "tun2socks"
|
||||
val KCPTUN = "kcptun"
|
||||
}
|
||||
|
||||
object ConfigUtils {
|
||||
@@ -166,6 +167,10 @@ object Key {
|
||||
val localPort = "localPortNum"
|
||||
|
||||
val profileTip = "profileTip"
|
||||
|
||||
val kcp = "kcp"
|
||||
val kcpPort = "kcpPort"
|
||||
val kcpcli = "kcpcli"
|
||||
}
|
||||
|
||||
object State {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
export ARCH=`uname -m`
|
||||
export GOROOT_BOOTSTRAP=$HOME/.android/go
|
||||
export ANDROID_NDK_HOME=$HOME/.android/android-ndk-r12b
|
||||
export ANDROID_HOME=$HOME/.android/android-sdk-linux
|
||||
export PATH=${ANDROID_NDK_HOME}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools:${PATH}
|
||||
@@ -21,5 +22,13 @@ if [ ! -d "$ANDROID_NDK_HOME" ]; then
|
||||
popd
|
||||
fi
|
||||
|
||||
if [ ! -d "$GOROOT_BOOTSTRAP" ]; then
|
||||
mkdir -p $GOROOT_BOOTSTRAP
|
||||
pushd $HOME/.android
|
||||
wget https://storage.googleapis.com/golang/go1.6.3.linux-amd64.tar.gz
|
||||
tar xf go1.6.3.linux-amd64.tar.gz
|
||||
popd
|
||||
fi
|
||||
|
||||
( sleep 5 && while [ 1 ]; do sleep 1; echo y; done ) | android update sdk --filter tools,platform-tools,build-tools-24.0.0,android-23,android-24,extra-google-m2repository --no-ui -a
|
||||
( sleep 5 && while [ 1 ]; do sleep 1; echo y; done ) | android update sdk --filter extra-android-m2repository --no-ui -a
|
||||
|
||||
Reference in New Issue
Block a user