diff --git a/.gitignore b/.gitignore index 2cd26960..020b7ea5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,31 +1,8 @@ -classes -bin -gen target local.properties -.classpath -.project -.settings -tests/bin -tests/gen -tests/local.properties -NUL -gen_* -*.class -*.o local.sbt -.deps /proguard-sbt.txt #Intellij IDEA -*.iml -*.ipr -*.iws .idea/ -out/ .d - -#NDK -src/main/obj -src/main/libs -jni/Application.mk diff --git a/README.md b/README.md index 14688f34..bec1e2c9 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,6 @@ A [shadowsocks](http://shadowsocks.org) client for Android, written in Scala. * JDK 1.8 * SBT 0.13.0+ -* Go 1.4+ * Android SDK - Build Tools 25+ - Android Support Repository and Google Repository (see `build.sbt` for version) @@ -53,7 +52,6 @@ Translators can go to [POEditor](https://poeditor.com/join/project/u5VHO9vhSf) t
  • shadowsocks-libev: GPLv3
  • pdnsd: GPLv3
  • libev: GPLv2
  • -
  • kcptun: MIT
  • libsodium: ISC
  • diff --git a/mobile/src/main/assets/pages/about.html b/mobile/src/main/assets/pages/about.html index eb991850..e8d232db 100644 --- a/mobile/src/main/assets/pages/about.html +++ b/mobile/src/main/assets/pages/about.html @@ -298,7 +298,6 @@ along with this program. If not, see http
  • shadowsocks-libev: GPLv3
  • pdnsd: GPLv3
  • libev: GPLv2
  • -
  • kcptun: MIT
  • libsodium: ISC
  • diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml index b14816a5..1aaf2586 100644 --- a/mobile/src/main/res/values/strings.xml +++ b/mobile/src/main/res/values/strings.xml @@ -135,12 +135,6 @@ Connected Not connected - - Enable Shadowsocks over KCP - KCP Port - %d (port number of the remote KCPTUN server) - KCP Parameters (CLI) - Custom rules Selection… diff --git a/mobile/src/main/res/xml/pref_profile.xml b/mobile/src/main/res/xml/pref_profile.xml index 80816c63..6f9af431 100644 --- a/mobile/src/main/res/xml/pref_profile.xml +++ b/mobile/src/main/res/xml/pref_profile.xml @@ -71,26 +71,4 @@ - - - - - - - - - - diff --git a/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala b/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala index 3b532114..59af31ae 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/BaseService.scala @@ -28,7 +28,6 @@ import java.util.{Timer, TimerTask} import android.app.Service import android.content.{BroadcastReceiver, Context, Intent, IntentFilter} -import android.net.ConnectivityManager import android.os.{Handler, IBinder, RemoteCallbackList} import android.text.TextUtils import android.util.Log @@ -49,7 +48,6 @@ trait BaseService extends Service { @volatile protected var profile: Profile = _ case class NameNotResolvedException() extends IOException - case class KcpcliParseException(cause: Throwable) extends Exception(cause) case class NullConnectionException() extends NullPointerException var timer: Timer = _ @@ -67,19 +65,6 @@ trait BaseService extends Service { } var closeReceiverRegistered: Boolean = _ - var kcptunProcess: GuardedProcess = _ - private val networkReceiver: BroadcastReceiver = (context: Context, _: 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) { - restartHanlder.removeCallbacks(null) - restartHanlder.postDelayed(() => if (kcptunProcess != null) kcptunProcess.restart(), 2000) - } - } - var networkReceiverRegistered: Boolean = _ - val binder = new IShadowsocksService.Stub { override def getState: Int = { state @@ -185,14 +170,6 @@ 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) @@ -202,8 +179,6 @@ trait BaseService extends Service { Utils.ThrowableFuture(try connect() catch { case _: NameNotResolvedException => stopRunner(stopService = true, getString(R.string.invalid_server)) - case exc: KcpcliParseException => - stopRunner(stopService = true, getString(R.string.service_failed) + ": " + exc.cause.getMessage) case _: NullConnectionException => stopRunner(stopService = true, getString(R.string.reboot_required)) case exc: Throwable => stopRunner(stopService = true, getString(R.string.service_failed) + ": " + exc.getMessage) @@ -218,10 +193,6 @@ 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) diff --git a/mobile/src/main/scala/com/github/shadowsocks/ProfileConfigFragment.scala b/mobile/src/main/scala/com/github/shadowsocks/ProfileConfigFragment.scala index f558b81f..60b51b98 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/ProfileConfigFragment.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/ProfileConfigFragment.scala @@ -25,13 +25,11 @@ import android.content.{DialogInterface, Intent, SharedPreferences} import android.os.{Build, Bundle, UserManager} import android.support.v14.preference.SwitchPreference import android.support.v7.app.AlertDialog -import android.support.v7.preference.Preference import android.support.v7.widget.Toolbar.OnMenuItemClickListener import android.view.MenuItem import be.mygod.preference.PreferenceFragment import com.github.shadowsocks.ShadowsocksApplication.app import com.github.shadowsocks.database.Profile -import com.github.shadowsocks.preferences.KcpCliPreferenceDialogFragment import com.github.shadowsocks.utils.{Action, Key, Utils} class ProfileConfigFragment extends PreferenceFragment with OnMenuItemClickListener @@ -75,11 +73,6 @@ class ProfileConfigFragment extends PreferenceFragment with OnMenuItemClickListe isProxyApps.setChecked(app.settings.getBoolean(Key.proxyApps, false)) // fetch proxyApps updated by AppManager } - override def onDisplayPreferenceDialog(preference: Preference): Unit = preference.getKey match { - case Key.kcpcli => displayPreferenceDialog(Key.kcpcli, new KcpCliPreferenceDialogFragment()) - case _ => super.onDisplayPreferenceDialog(preference) - } - override def onMenuItemClick(item: MenuItem): Boolean = item.getItemId match { case R.id.action_delete => new AlertDialog.Builder(getActivity) diff --git a/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala index 58ad4139..48a4a366 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala @@ -53,15 +53,10 @@ class ShadowsocksNatService extends BaseService { var su: Shell.Interactive = _ def startShadowsocksDaemon() { - 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 { + 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-nat.conf"))(p => { p.println(conf) }) @@ -85,27 +80,6 @@ class ShadowsocksNatService extends BaseService { sslocalProcess = new GuardedProcess(cmd).start() } - def startKcptunDaemon() { - if (profile.kcpcli == null) profile.kcpcli = "" - - val host = if (profile.host.contains(":")) { - "[" + profile.host + "]" - } else { - profile.host - } - - val cmd = ArrayBuffer[String](getApplicationInfo.nativeLibraryDir + "/libkcptun.so" - , "-r", host + ":" + profile.kcpPort - , "-l", "127.0.0.1:" + (profile.localPort + 90)) - try cmd ++= Utils.translateCommandline(profile.kcpcli) catch { - case exc: Exception => throw KcpcliParseException(exc) - } - - if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" ")) - - kcptunProcess = new GuardedProcess(cmd).start() - } - def startDNSTunnel() { if (profile.udpdns) { val conf = ConfigUtils @@ -130,15 +104,10 @@ class ShadowsocksNatService extends BaseService { sstunnelProcess = new GuardedProcess(cmd).start() } else { - 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 { + val conf = 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) }) @@ -205,7 +174,6 @@ class ShadowsocksNatService extends BaseService { startShadowsocksDaemon() if (!profile.udpdns) startDnsDaemon() - if (profile.kcp) startKcptunDaemon() setupIptables() @@ -221,10 +189,6 @@ class ShadowsocksNatService extends BaseService { } def killProcesses() { - if (kcptunProcess != null) { - kcptunProcess.destroy() - kcptunProcess = null - } if (sslocalProcess != null) { sslocalProcess.destroy() sslocalProcess = null diff --git a/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala index 9218aee5..46b334e9 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala @@ -91,10 +91,6 @@ class ShadowsocksVpnService extends VpnService with BaseService { } def killProcesses() { - if (kcptunProcess != null) { - kcptunProcess.destroy() - kcptunProcess = null - } if (sslocalProcess != null) { sslocalProcess.destroy() sslocalProcess = null @@ -157,76 +153,19 @@ class ShadowsocksVpnService extends VpnService with BaseService { val fd = startVpn() if (!sendFd(fd)) throw new Exception("sendFd failed") - if (profile.kcp) { - startKcptunDaemon() - } - startShadowsocksDaemon() - if (profile.udpdns && profile.kcp) { - startShadowsocksUDPDaemon() - } - if (!profile.udpdns) { startDnsDaemon() startDnsTunnel() } } - def startKcptunDaemon() { - if (profile.kcpcli == null) profile.kcpcli = "" - - val host = if (profile.host.contains(":")) { - "[" + profile.host + "]" - } else { - profile.host - } - - val cmd = ArrayBuffer(getApplicationInfo.nativeLibraryDir + "/libkcptun.so" - , "-r", host + ":" + profile.kcpPort - , "-l", "127.0.0.1:" + (profile.localPort + 90) - , "--path", protectPath) - try cmd ++= Utils.translateCommandline(profile.kcpcli) catch { - case exc: Exception => throw KcpcliParseException(exc) - } - - if (BuildConfig.DEBUG) - Log.d(TAG, cmd.mkString(" ")) - - kcptunProcess = new GuardedProcess(cmd).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 = ArrayBuffer[String](getApplicationInfo.nativeLibraryDir + "/libss-local.so", "-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() { - 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 { + 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-vpn.conf"))(p => { p.println(conf) }) @@ -239,7 +178,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { if (profile.auth) cmd += "-A" - if (profile.udpdns && !profile.kcp) cmd += "-u" + if (profile.udpdns) cmd += "-u" if (profile.route != Acl.ALL) { cmd += "--acl" @@ -254,15 +193,10 @@ class ShadowsocksVpnService extends VpnService with BaseService { } def startDnsTunnel() { - 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 { + val conf = 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) }) diff --git a/mobile/src/main/scala/com/github/shadowsocks/database/DBHelper.scala b/mobile/src/main/scala/com/github/shadowsocks/database/DBHelper.scala index 9e4e55b5..ebbb3e2c 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/database/DBHelper.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/database/DBHelper.scala @@ -46,7 +46,7 @@ object DBHelper { } class DBHelper(val context: Context) - extends OrmLiteSqliteOpenHelper(context, DBHelper.PROFILE, null, 21) { + extends OrmLiteSqliteOpenHelper(context, DBHelper.PROFILE, null, 22) { import DBHelper._ lazy val profileDao: Dao[Profile, Int] = getDao(classOf[Profile]) @@ -115,24 +115,26 @@ class DBHelper(val context: Context) 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 DEFAULT " + - "'--crypt none --mode normal --mtu 1200 --nocomp --dscp 46 --parityshard 0';") - } else if (oldVersion < 20) { - profileDao.executeRawNoArgs("UPDATE `profile` SET kcpcli = '--crypt none --mode normal --mtu 1200 --nocomp " + - "--dscp 46 --parityshard 0' WHERE kcpcli IS NULL;") - } - - if (oldVersion < 18) { - profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN kcpPort INTEGER DEFAULT 8399;") - } else if (oldVersion < 19) { - profileDao.executeRawNoArgs("UPDATE `profile` SET kcpPort = 8399 WHERE kcpPort = 0;") - } - if (oldVersion < 21) { profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN remoteDns VARCHAR DEFAULT '8.8.8.8';") } + + if (oldVersion < 17) { + profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN plugin VARCHAR;") + } else if (oldVersion < 22) { + // upgrade kcptun to SIP003 plugin + profileDao.executeRawNoArgs("BEGIN TRANSACTION;") + profileDao.executeRawNoArgs("ALTER TABLE `profile` RENAME TO `tmp`;") + TableUtils.createTable(connectionSource, classOf[Profile]) + profileDao.executeRawNoArgs( + "INSERT INTO `profile`(id, name, host, localPort, remotePort, password, method, route, proxyApps, bypass," + + " udpdns, auth, ipv6, individual, tx, rx, date, userOrder, plugin) " + + "SELECT id, name, host, localPort, CASE WHEN kcp = 1 THEN kcpPort ELSE remotePort END, password, method, " + + "route, proxyApps, bypass, udpdns, auth, ipv6, individual, tx, rx, date, userOrder, " + + "CASE WHEN kcp = 1 THEN 'kcptun ' || kcpcli ELSE NULL END FROM `tmp`;") + profileDao.executeRawNoArgs("DROP TABLE `tmp`;") + profileDao.executeRawNoArgs("COMMIT;") + } } catch { case ex: Exception => app.track(ex) diff --git a/mobile/src/main/scala/com/github/shadowsocks/database/Profile.scala b/mobile/src/main/scala/com/github/shadowsocks/database/Profile.scala index dac6e203..19ffe4d5 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/database/Profile.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/database/Profile.scala @@ -90,13 +90,7 @@ class Profile { var userOrder: Long = _ @DatabaseField - var kcp: Boolean = _ - - @DatabaseField - var kcpPort: Int = 8399 - - @DatabaseField - var kcpcli: String = "--crypt none --mode normal --mtu 1200 --nocomp --dscp 46 --parityshard 0" + var plugin: String = _ def formattedAddress: String = (if (host.contains(":")) "[%s]:%d" else "%s:%d").format(host, remotePort) def nameIsEmpty: Boolean = name == null || name.isEmpty @@ -123,9 +117,7 @@ class Profile { .putBoolean(Key.auth, auth) .putBoolean(Key.ipv6, ipv6) .putString(Key.individual, individual) - .putBoolean(Key.kcp, kcp) - .putInt(Key.kcpPort, kcpPort) - .putString(Key.kcpcli, kcpcli) + .putString(Key.plugin, plugin) .remove(Key.dirty) def deserialize(pref: SharedPreferences) { // It's assumed that default values are never used, so 0/false/null is always used even if that isn't the case @@ -143,8 +135,6 @@ class Profile { auth = pref.getBoolean(Key.auth, false) ipv6 = pref.getBoolean(Key.ipv6, false) individual = pref.getString(Key.individual, null) - kcp = pref.getBoolean(Key.kcp, false) - kcpPort = pref.getInt(Key.kcpPort, 0) - kcpcli = pref.getString(Key.kcpcli, null) + plugin = pref.getString(Key.plugin, null) } } diff --git a/mobile/src/main/scala/com/github/shadowsocks/preferences/KcpCliPreferenceDialogFragment.scala b/mobile/src/main/scala/com/github/shadowsocks/preferences/KcpCliPreferenceDialogFragment.scala deleted file mode 100644 index 05319d9c..00000000 --- a/mobile/src/main/scala/com/github/shadowsocks/preferences/KcpCliPreferenceDialogFragment.scala +++ /dev/null @@ -1,54 +0,0 @@ -/*******************************************************************************/ -/* */ -/* Copyright (C) 2017 by Max Lv */ -/* Copyright (C) 2017 by Mygod Studio */ -/* */ -/* This program is free software: you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation, either version 3 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program. If not, see . */ -/* */ -/*******************************************************************************/ - -package com.github.shadowsocks.preferences - -import android.app.AlertDialog -import android.content.DialogInterface -import eu.chainfire.libsuperuser.Shell -import be.mygod.preference.EditTextPreferenceDialogFragment - -import scala.collection.JavaConverters._ - -/** - * @author Mygod - */ -class KcpCliPreferenceDialogFragment extends EditTextPreferenceDialogFragment { - override def onPrepareDialogBuilder(builder: AlertDialog.Builder) { - super.onPrepareDialogBuilder(builder) - builder.setNeutralButton("?", ((_, _) => new AlertDialog.Builder(builder.getContext) - .setTitle("?") - .setMessage(Shell.SH.run(builder.getContext.getApplicationInfo.nativeLibraryDir + "/libkcptun.so --help") - .asScala - .dropWhile(line => line != "GLOBAL OPTIONS:") - .drop(1) - .takeWhile(line => line.length() > 3) - .filter(line => - !line.startsWith(" --localaddr ") && - !line.startsWith(" --remoteaddr ") && - !line.startsWith(" --path ") && - !line.startsWith(" --help,") && - !line.startsWith(" --version,")) - .mkString("\n") - .replaceAll(" {2,}", "\n") - .substring(1)) // remove 1st \n - .show()): DialogInterface.OnClickListener) - } -} diff --git a/mobile/src/main/scala/com/github/shadowsocks/utils/Constants.scala b/mobile/src/main/scala/com/github/shadowsocks/utils/Constants.scala index ea504bc0..2b2d1929 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/utils/Constants.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/utils/Constants.scala @@ -26,9 +26,8 @@ object Executable { val SS_LOCAL = "ss-local" val SS_TUNNEL = "ss-tunnel" val TUN2SOCKS = "tun2socks" - val KCPTUN = "kcptun" - val EXECUTABLES = Array(SS_LOCAL, SS_TUNNEL, PDNSD, REDSOCKS, TUN2SOCKS, KCPTUN) + val EXECUTABLES = Array(SS_LOCAL, SS_TUNNEL, PDNSD, REDSOCKS, TUN2SOCKS) } object ConfigUtils { @@ -153,9 +152,7 @@ object Key { val localPort = "localPortNum" val remoteDns = "remoteDns" - val kcp = "kcp" - val kcpPort = "kcpPort" - val kcpcli = "kcpcli" + val plugin = "plugin" val dirty = "profileDirty"