From 80d93a84bdb9fb1bbe6184ed7babca2deb4fefcf Mon Sep 17 00:00:00 2001 From: Mygod Date: Tue, 16 Aug 2016 14:37:21 +0800 Subject: [PATCH] Add support for TCP Fast Open (#809) * Add support for TCP Fast Open * Remove useless echo done line * Check return values before proceeding in TcpFastOpen.enabled --- src/main/res/values-ru/strings.xml | 2 ++ src/main/res/values-zh-rCN/strings.xml | 2 ++ src/main/res/values-zh/strings.xml | 2 ++ src/main/res/values/strings.xml | 2 ++ src/main/res/xml/pref_all.xml | 6 ++++ .../shadowsocks/ShadowsocksNatService.scala | 4 +++ .../shadowsocks/ShadowsocksSettings.scala | 14 +++++++- .../shadowsocks/ShadowsocksVpnService.scala | 4 +++ .../shadowsocks/utils/TcpFastOpen.scala | 36 +++++++++++++++++++ .../com/github/shadowsocks/utils/Utils.scala | 9 +++++ 10 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 src/main/scala/com/github/shadowsocks/utils/TcpFastOpen.scala diff --git a/src/main/res/values-ru/strings.xml b/src/main/res/values-ru/strings.xml index a7e489d0..f9e3c0e9 100644 --- a/src/main/res/values-ru/strings.xml +++ b/src/main/res/values-ru/strings.xml @@ -53,6 +53,8 @@ Включите эту опцию для работы выбранных приложений в обход прокси Авто Подключение Запускать Shadowsocks при включении + Переключение требует наличия ROOT прав + Неподдерживаемая версия ядра: %s < 3.7.1 Проброс UDP Пробрасывать UDP пакеты на удалённый сервер diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml index 2823c53d..cfbaa9bf 100644 --- a/src/main/res/values-zh-rCN/strings.xml +++ b/src/main/res/values-zh-rCN/strings.xml @@ -32,6 +32,8 @@ 启用该选项,以使所选应用程序的流量不经过代理 自动连接 随系统启动后台服务 + 切换需要 ROOT 权限 + 不支持的内核版本:%s < 3.7.1 后台服务已开始运行。 无法连接远程服务器 服务器名无效 diff --git a/src/main/res/values-zh/strings.xml b/src/main/res/values-zh/strings.xml index 2f15dab4..3d26d66a 100644 --- a/src/main/res/values-zh/strings.xml +++ b/src/main/res/values-zh/strings.xml @@ -33,6 +33,8 @@ 啟用此選項,會略過已選擇的應用程式 自動連線 在裝置啟動時啟用 Shadowsocks + 切換需要 ROOT 權限 + 不支持的內核版本:%s < 3.7.1 Shadowsocks 已啟動。 連線至遠端伺服器失敗 伺服器名稱無效 diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index ac007a7d..71bce678 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -59,6 +59,8 @@ Enable this option to bypass selected apps Auto Connect Enable Shadowsocks on startup + Toggling requires ROOT permission + Unsupported kernel version: %s < 3.7.1 UDP Forwarding Forward UDP packets to remote diff --git a/src/main/res/xml/pref_all.xml b/src/main/res/xml/pref_all.xml index 503ca76f..25cbd4a0 100644 --- a/src/main/res/xml/pref_all.xml +++ b/src/main/res/xml/pref_all.xml @@ -110,6 +110,12 @@ android:summary="@string/auto_connect_summary" android:title="@string/auto_connect"/> + + diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala index 6af63b31..dd4cbe17 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala @@ -106,6 +106,8 @@ class ShadowsocksNatService extends BaseService { if (profile.auth) cmd += "-A" + if (TcpFastOpen.sendEnabled) cmd += "--fast-open" + if (profile.route != Route.ALL) { cmd += "--acl" cmd += (getApplicationInfo.dataDir + "/acl.list") @@ -149,6 +151,8 @@ class ShadowsocksNatService extends BaseService { if (profile.auth) cmd += "-A" + if (TcpFastOpen.sendEnabled) cmd += "--fast-open" + if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" ")) sstunnelProcess = new GuardedProcess(cmd).start() diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala index 758b9558..8aec2664 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala @@ -12,7 +12,7 @@ import android.webkit.{WebView, WebViewClient} import com.github.shadowsocks.ShadowsocksApplication.app import com.github.shadowsocks.database.Profile import com.github.shadowsocks.preferences._ -import com.github.shadowsocks.utils.{Key, Utils} +import com.github.shadowsocks.utils.{Key, TcpFastOpen, Utils} object ShadowsocksSettings { // Constants @@ -154,6 +154,18 @@ class ShadowsocksSettings extends PreferenceFragment with OnSharedPreferenceChan } switch.setChecked(BootReceiver.getEnabled(activity)) + val tfo = findPreference("tcp_fastopen").asInstanceOf[SwitchPreference] + tfo.setChecked(TcpFastOpen.sendEnabled) + tfo.setOnPreferenceChangeListener((_, v) => { + val value = v.asInstanceOf[Boolean] + TcpFastOpen.enabled(value) + value == TcpFastOpen.sendEnabled + }) + if (!TcpFastOpen.supported) { + tfo.setEnabled(false) + tfo.setSummary(getString(R.string.tcp_fastopen_summary_unsupported, java.lang.System.getProperty("os.version"))) + } + findPreference("recovery").setOnPreferenceClickListener((preference: Preference) => { app.track(TAG, "reset") activity.recovery() diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala index ee053941..bb136335 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala @@ -236,6 +236,8 @@ class ShadowsocksVpnService extends VpnService with BaseService { if (profile.auth) cmd += "-A" + if (TcpFastOpen.sendEnabled) cmd += "--fast-open" + if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" ")) sstunnelProcess = new GuardedProcess(cmd).start() @@ -312,6 +314,8 @@ class ShadowsocksVpnService extends VpnService with BaseService { if (profile.auth) cmd += "-A" + if (TcpFastOpen.sendEnabled) cmd += "--fast-open" + if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" ")) sstunnelProcess = new GuardedProcess(cmd).start() diff --git a/src/main/scala/com/github/shadowsocks/utils/TcpFastOpen.scala b/src/main/scala/com/github/shadowsocks/utils/TcpFastOpen.scala new file mode 100644 index 00000000..4dca873a --- /dev/null +++ b/src/main/scala/com/github/shadowsocks/utils/TcpFastOpen.scala @@ -0,0 +1,36 @@ +package com.github.shadowsocks.utils + +import java.io.File + +import eu.chainfire.libsuperuser.Shell + +/** + * @author Mygod + */ +object TcpFastOpen { + /** + * Is kernel version >= 3.7.1. + */ + lazy val supported = "^(\\d+)\\.(\\d+)\\.(\\d+)".r.findFirstMatchIn(System.getProperty("os.version")) match { + case Some(m) => + val kernel = m.group(1).toInt + if (kernel < 3) false else if (kernel > 3) true else { + val major = m.group(2).toInt + if (major < 7) false else if (major > 7) true else m.group(3).toInt >= 1 + } + case _ => false + } + + def sendEnabled = { + val file = new File("/proc/sys/net/ipv4/tcp_fastopen") + file.canRead && (Utils.readAllLines(file).toInt & 1) > 0 + } + + def enabled(value: Boolean) = if (supported) { + val fastopen = "sysctl -w net.ipv4.tcp_fastopen=" + (if (value) 3 else 0) + Shell.SU.run(Array( + "mount -o remount,rw /system && " + fastopen + " && echo '#!/system/bin/sh\n" + fastopen + + "' > /etc/init.d/tcp_fastopen && chmod 755 /etc/init.d/tcp_fastopen", + "mount -o remount,ro /system")) + } +} diff --git a/src/main/scala/com/github/shadowsocks/utils/Utils.scala b/src/main/scala/com/github/shadowsocks/utils/Utils.scala index bb7d78d9..374140b6 100644 --- a/src/main/scala/com/github/shadowsocks/utils/Utils.scala +++ b/src/main/scala/com/github/shadowsocks/utils/Utils.scala @@ -38,8 +38,10 @@ */ package com.github.shadowsocks.utils +import java.io.File import java.net._ import java.security.MessageDigest +import java.util.Scanner import android.animation.{Animator, AnimatorListenerAdapter} import android.content.pm.PackageManager @@ -108,6 +110,13 @@ object Utils { }) } + def readAllLines(f: File) = { + val scanner = new Scanner(f) + try { + scanner.useDelimiter("\\Z") + scanner.next() + } finally scanner.close() + } def printToFile(f: java.io.File)(op: java.io.PrintWriter => Unit) { val p = new java.io.PrintWriter(f) try {