Compare commits

..
24 Commits
Author SHA1 Message Date
Max Lv c21bd74302 Merge branch 'beta' 2017-03-11 18:48:12 +08:00
Max Lv a8822330a3 Bump version 2017-03-11 18:43:03 +08:00
Max Lv 1cf6e4802c Update strings 2017-03-11 18:15:34 +08:00
Max Lv f64014eb7b Always forwording UDP traffic #1156 2017-03-11 15:49:06 +08:00
Mygod 2f6f991e6e Fix literal IPv6 address handling in URIs 2017-03-11 12:33:27 +08:00
Mygod 90e00a3857 Refine README.md 2017-03-11 12:11:52 +08:00
Mygod 712b764a9b Update README.md to reflect changes in sbt-android 2017-03-10 08:55:49 +08:00
Mygod 019f9d30e8 Remove redundant group in legacyPattern 2017-03-10 08:54:03 +08:00
Mygod 9c97dc9bf6 Update README.md to reflect changes in sbt-android 2017-03-09 23:54:48 +08:00
Mygod 7d2e0a515f Remove redundant group in legacyPattern 2017-03-09 20:46:34 +08:00
Mygod 26b68876f4 Update build instructions 2017-03-08 01:03:46 +08:00
Mygod a494f56ce8 Refine #1148 2017-03-08 00:25:05 +08:00
Max Lv a433822d0a Add arm64 support 2017-03-07 10:30:29 +08:00
Max Lv 60d7d90565 Fix a DNS issue with GFWList mode 2017-03-05 16:11:24 +08:00
Max Lv d2ba9493c0 Bump version 2017-03-04 10:26:43 +08:00
Max Lv 0eaece7af9 Remove external IP #1148 2017-03-04 09:56:52 +08:00
Max Lv c920c0daa4 Bump version 2017-02-24 19:37:23 +08:00
Mygod 8e3854b496 Update dependencies 2017-02-24 19:37:23 +08:00
Max Lv ad42167b2e Update shadowsocks-libev 2017-02-24 19:37:23 +08:00
Max Lv 3bf0963c5a Trim remoteDns 2017-02-24 19:37:23 +08:00
Max Lv c3315d35ed Fix #1130 2017-02-24 19:37:23 +08:00
Max Lv 103dc10a0a Update shadowsocks-libev 2017-02-24 19:37:23 +08:00
Max Lv 36c94b8d83 Fix a memory leak 2017-02-24 19:37:22 +08:00
Mygod df72b29302 Fix malformed URL in about.html 2017-02-23 15:17:57 +08:00
17 changed files with 50 additions and 58 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ jdk:
env:
global:
- NDK_VERSION=r12b
- NDK_VERSION=r14
- NDK_CCACHE=ccache
- GOROOT_BOOTSTRAP=$GOROOT
- ANDROID_NDK_HOME=$HOME/.android/android-ndk-${NDK_VERSION}
+5 -3
View File
@@ -12,15 +12,17 @@ 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)
* Android NDK r12b+
- Android NDK r14+
### BUILD
* Set environment variable `ANDROID_HOME` to `/path/to/android-sdk`
* Set environment variable `ANDROID_NDK_HOME` to `/path/to/android-ndk`
* (optional) Set environment variable `ANDROID_NDK_HOME` to `/path/to/android-ndk` (default: `$ANDROID_HOME/ndk-bundle`)
* 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
* Create `mobile/local.properties` from `mobile/local.properties.example` with your own key information
* Invoke the building like this
@@ -29,7 +31,7 @@ A [shadowsocks](http://shadowsocks.org) client for Android, written in Scala.
git submodule update --init --recursive
# Build the App
sbt clean android:package-release
sbt clean go-build android:package-release
```
### TRANSLATE
+2 -2
View File
@@ -2,8 +2,8 @@ enablePlugins(AndroidApp)
android.useSupportVectors
name := "shadowsocks"
version := "4.1.0"
versionCode := Some(180)
version := "4.1.3"
versionCode := Some(183)
proguardOptions ++=
"-keep class com.github.shadowsocks.JniHelper { *; }" ::
+1 -1
View File
@@ -275,7 +275,7 @@ img {
<body>
<p>A <a href="http://shadowsocks.org">Shadowsocks</a> client for Android, written in Scala.</p>
<p>Copyright (C) 2017 by Max Lv <a href="&#x6d;&#97;&#x69;&#108;&#116;&#111;&#x3a;&#x6d;&#97;x&#46;&#99;.&#108;&#118;&#x40;&#103;&#109;&#97;&#x69;&#108;&#46;&#x63;&#x6f;&#109;">&#x6d;&#97;&#x78;.&#x63;&#x2e;&#108;v&#64;&#x67;&#109;&#x61;&#x69;&#108;&#x2e;&#99;&#111;&#109;</a></p>
<p>Copyright (C) 2017 by Mygod Studio <a href="contact-shadowsocks-android@mygod.be">contact-shadowsocks-android@mygod.be</a></p>
<p>Copyright (C) 2017 by Mygod Studio <a href="mailto:contact-shadowsocks-android@mygod.be">contact-shadowsocks-android@mygod.be</a></p>
<p>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
+1 -1
View File
@@ -97,7 +97,7 @@ LIBEVENT_SOURCES := \
LOCAL_MODULE := event
LOCAL_SRC_FILES := $(addprefix libevent/, $(LIBEVENT_SOURCES))
LOCAL_CFLAGS := -O2 -I$(LOCAL_PATH)/libevent \
LOCAL_CFLAGS := -O2 -D_EVENT_HAVE_ARC4RANDOM -I$(LOCAL_PATH)/libevent \
-I$(LOCAL_PATH)/libevent/include \
include $(BUILD_STATIC_LIBRARY)
+1 -1
View File
@@ -1,4 +1,4 @@
APP_ABI := armeabi-v7a x86
APP_ABI := armeabi-v7a arm64-v8a x86
APP_PLATFORM := android-19
APP_STL := stlport_static
NDK_TOOLCHAIN_VERSION := clang
+3 -3
View File
@@ -44,8 +44,8 @@
<string name="auto_connect_summary">"システム起動時にバックグラウンドで本サービスを開始"</string>
<string name="tcp_fastopen_summary">"使用するにはROOT権限が必要"</string>
<string name="tcp_fastopen_summary_unsupported">"ご利用のカーネルバージョンはサポートしておりません:%s &lt; 3.7.1"</string>
<string name="udp_dns">"UDP転送"</string>
<string name="udp_dns_summary">"UDPプロトコルでリモードサーバーにパケットを転送"</string>
<string name="udp_dns">"DNS転送"</string>
<string name="udp_dns_summary">"DNSプロトコルでリモードサーバーにパケットを転送"</string>
<!-- notification category -->
<string name="forward_success">"バックグラウンドでサービスを開始しました"</string>
@@ -138,4 +138,4 @@
<string name="proxied_apps_summary_v21">"選択したアプリにプロキシを設定する"</string>
<string name="acl_rule_templates_generic">"サブネット/ホストネームPCREパターン"</string>
<string name="acl_rule_templates_domain">"ドメイン及びサブドメイン"</string>
</resources>
</resources>
+3 -3
View File
@@ -52,8 +52,8 @@
<string name="auto_connect_summary">"Запускать Shadowsocks при включении"</string>
<string name="tcp_fastopen_summary">"Переключение требует наличия ROOT прав"</string>
<string name="tcp_fastopen_summary_unsupported">"Неподдерживаемая версия ядра: %s &lt; 3.7.1"</string>
<string name="udp_dns">"Проброс UDP"</string>
<string name="udp_dns_summary">"Пробрасывать UDP пакеты на удалённый сервер"</string>
<string name="udp_dns">"Проброс DNS"</string>
<string name="udp_dns_summary">"Пробрасывать DNS пакеты на удалённый сервер"</string>
<!-- notification category -->
<string name="forward_success">"Shadowsocks запущен."</string>
@@ -121,4 +121,4 @@
<string name="route_entry_bypass_lan_chn">"Обход LAN и Китай"</string>
<string name="route_entry_chinalist">"Список Китай"</string>
<string name="proxied_apps_summary_v21">"Установить прокси для выбранных приложений"</string>
</resources>
</resources>
@@ -45,8 +45,8 @@
<string name="auto_connect_summary">"随系统启动后台服务"</string>
<string name="tcp_fastopen_summary">"切换需要 ROOT 权限"</string>
<string name="tcp_fastopen_summary_unsupported">"不支持的内核版本:%s &lt; 3.7.1"</string>
<string name="udp_dns">"UDP 转发"</string>
<string name="udp_dns_summary">"由远程服务器转发 UDP 协议的数据包"</string>
<string name="udp_dns">"DNS 转发"</string>
<string name="udp_dns_summary">"由远程服务器转发 DNS 协议的数据包"</string>
<!-- notification category -->
<string name="forward_success">"后台服务已开始运行。"</string>
@@ -140,4 +140,4 @@
<string name="proxied_apps_summary_v21">"为应用程序分别设置代理"</string>
<string name="acl_rule_templates_generic">"子网/域名 PCRE 正则表达式"</string>
<string name="acl_rule_templates_domain">"域名及其子域名"</string>
</resources>
</resources>
@@ -44,8 +44,8 @@
<string name="auto_connect_summary">"在裝置啟動時啟用 Shadowsocks"</string>
<string name="tcp_fastopen_summary">"切換需要 ROOT 權限"</string>
<string name="tcp_fastopen_summary_unsupported">"不支援的核心版本:%s &lt; 3.7.1"</string>
<string name="udp_dns">"UDP 轉送"</string>
<string name="udp_dns_summary">"向遠端轉送 UDP 封包"</string>
<string name="udp_dns">"DNS 轉送"</string>
<string name="udp_dns_summary">"向遠端轉送 DNS 封包"</string>
<!-- notification category -->
<string name="forward_success">"Shadowsocks 已啟動。"</string>
@@ -139,4 +139,4 @@
<string name="proxied_apps_summary_v21">"為已選擇的應用程式設定 Proxy"</string>
<string name="acl_rule_templates_generic">"子網路/主機名稱 PCRE 模式"</string>
<string name="acl_rule_templates_domain">"網域及其所有子網域"</string>
</resources>
</resources>
+2 -2
View File
@@ -53,8 +53,8 @@
<string name="auto_connect_summary">Enable Shadowsocks on startup</string>
<string name="tcp_fastopen_summary">Toggling requires ROOT permission</string>
<string name="tcp_fastopen_summary_unsupported">Unsupported kernel version: %s &lt; 3.7.1</string>
<string name="udp_dns">UDP Forwarding</string>
<string name="udp_dns_summary">Forward UDP packets to remote</string>
<string name="udp_dns">DNS Forwarding</string>
<string name="udp_dns_summary">Force to forward DNS packets to remote</string>
<!-- notification category -->
<string name="forward_success">Shadowsocks started.</string>
@@ -135,9 +135,9 @@ trait BaseService extends Service {
case Some(ip) => util.Arrays.asList(InetAddress.getByName(ip))
case _ => Dns.SYSTEM.lookup(hostname)
})
.connectTimeout(5, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS)
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
val requestBody = new FormBody.Builder()
.add("sig", sig)
@@ -330,18 +330,6 @@ trait BaseService extends Service {
}
protected final def buildOvertureConfig(file: String): String = {
val url = "http://icanhazip.com"
val client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
val request = new Request.Builder()
.url(url)
.build()
val response = client.newCall(request).execute()
val externalIp = if (response.isSuccessful) response.body.string.trim else ""
val config = new JSONObject()
.put("BindAddress", ":" + (profile.localPort + 53))
.put("RedirectIPv6Record", true)
@@ -354,15 +342,11 @@ trait BaseService extends Service {
.put("Name", name)
.put("Address", address + ":53")
.put("Timeout", 6)
.put("EDNSClientSubnet", new JSONObject().put("Policy", "disable"))
if (edns) dns
.put("Protocol", "tcp")
.put("Socks5Address", "127.0.0.1:" + profile.localPort)
.put("EDNSClientSubnet", new JSONObject()
.put("Policy", "auto")
.put("ExternalIP", externalIp))
else dns
.put("Protocol", "udp")
.put("EDNSClientSubnet", new JSONObject().put("Policy", "disable"))
else dns.put("Protocol", "udp")
dns
}
profile.route match {
@@ -159,13 +159,12 @@ class ShadowsocksVpnService extends VpnService with BaseService {
def startShadowsocksDaemon() {
val cmd = ArrayBuffer[String](getApplicationInfo.nativeLibraryDir + "/libss-local.so",
"-V",
"-u",
"-b", "127.0.0.1",
"-l", profile.localPort.toString,
"-t", "600",
"-c", buildShadowsocksConfig("ss-local-vpn.conf"))
if (profile.udpdns) cmd += "-u"
if (profile.route != Acl.ALL) {
cmd += "--acl"
cmd += Acl.getFile(profile.route).getAbsolutePath
@@ -242,9 +241,9 @@ class ShadowsocksVpnService extends VpnService with BaseService {
if (profile.ipv6)
cmd += ("--netif-ip6addr", PRIVATE_VLAN6.formatLocal(Locale.ENGLISH, "2"))
if (profile.udpdns)
cmd += "--enable-udprelay"
else
cmd += "--enable-udprelay"
if (!profile.udpdns)
cmd += ("--dnsgw", "%s:%d".formatLocal(Locale.ENGLISH, PRIVATE_VLAN.formatLocal(Locale.ENGLISH, "1"),
profile.localPort + 53))
@@ -98,7 +98,8 @@ class Profile {
.scheme("ss")
.encodedAuthority("%s@%s:%d".formatLocal(Locale.ENGLISH,
Base64.encodeToString("%s:%s".formatLocal(Locale.ENGLISH, method, password).getBytes,
Base64.NO_PADDING | Base64.NO_WRAP | Base64.URL_SAFE), host, remotePort))
Base64.NO_PADDING | Base64.NO_WRAP | Base64.URL_SAFE),
if (host.contains(':')) '[' + host + ']' else host, remotePort))
val configuration = new PluginConfiguration(plugin)
if (configuration.selected.nonEmpty)
builder.appendQueryParameter(Key.plugin, configuration.selectedOptions.toString(false))
@@ -20,22 +20,24 @@
package com.github.shadowsocks.utils
import java.net.URI
import android.net.Uri
import android.util.{Base64, Log}
import com.github.shadowsocks.database.Profile
object Parser {
val TAG = "ShadowParser"
private val pattern = "(?i)ss://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]".r
private val pattern = "(?i)ss://[-a-zA-Z0-9+&@#/%?=~_|!:,.;\\[\\]]*[-a-zA-Z0-9+&@#/%=~_|\\[\\]]".r
private val userInfoPattern = "^(.+?):(.*)$".r
private val legacyPattern = "^((.+?):(.*)@(.+?):(\\d+?))$".r
private val legacyPattern = "^(.+?):(.*)@(.+?):(\\d+?)$".r
def findAll(data: CharSequence): Iterator[Profile] =
pattern.findAllMatchIn(if (data == null) "" else data).map(m => {
val uri = Uri.parse(m.matched)
uri.getUserInfo match {
case null => new String(Base64.decode(uri.getHost, Base64.NO_PADDING), "UTF-8") match {
case legacyPattern(_, method, password, host, port) => // legacy uri
case null => val str = new String(Base64.decode(uri.getHost, Base64.NO_PADDING), "UTF-8"); str match {
case legacyPattern(method, password, host, port) => // legacy uri
val profile = new Profile
profile.method = method.toLowerCase
profile.password = password
@@ -54,8 +56,12 @@ object Parser {
val profile = new Profile
profile.method = method
profile.password = password
profile.host = uri.getHost
profile.remotePort = uri.getPort
// bug in Android: https://code.google.com/p/android/issues/detail?id=192855
val javaURI = new URI(m.matched)
profile.host = javaURI.getHost
if (profile.host.headOption.contains('[') && profile.host.lastOption.contains(']'))
profile.host = profile.host.substring(1, profile.host.length - 1)
profile.remotePort = javaURI.getPort
profile.plugin = uri.getQueryParameter(Key.plugin)
profile.name = uri.getFragment
profile