Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5bce2ca8b6 | ||
|
|
58c613b365 | ||
|
|
446a71db93 | ||
|
|
a3b2357d72 | ||
|
|
8d456e3d64 | ||
|
|
4ff77701be | ||
|
|
78e7175f7d | ||
|
|
0d03a09682 | ||
|
|
62745de01b | ||
|
|
bb81fe1339 | ||
|
|
66d70f1545 | ||
|
|
ff0ddd5979 | ||
|
|
bf3933bf2e | ||
|
|
d111bc8282 | ||
|
|
a57c06e304 | ||
|
|
3605e18db2 | ||
|
|
1ad8297278 | ||
|
|
458f49d345 | ||
|
|
6b9b7b6749 | ||
|
|
d542bafb7d | ||
|
|
bbb62be458 | ||
|
|
b272d7ab71 | ||
|
|
09d53033cb | ||
|
|
496c809186 | ||
|
|
b58ffb7a95 | ||
|
|
3512542043 | ||
|
|
0c940c8860 | ||
|
|
00253ea3f6 | ||
|
|
d836aafe40 | ||
|
|
60360e6a19 | ||
|
|
5939f2776c | ||
|
|
0cecc62035 | ||
|
|
7a6fbaca15 | ||
|
|
2a3ffd768c | ||
|
|
33b775ea5e | ||
|
|
0be4d39606 | ||
|
|
ee7e4c9711 | ||
|
|
c1c8ff309c | ||
|
|
8724bf325f | ||
|
|
20395ede5f | ||
|
|
336fa3b775 | ||
|
|
11bfef423a | ||
|
|
6e0534b00f | ||
|
|
bf960f1a64 | ||
|
|
b1e01d2158 | ||
|
|
f344eb783c | ||
|
|
5f6effba09 | ||
|
|
97cfd1f869 |
@@ -1,15 +1,19 @@
|
||||
import android.Keys._
|
||||
|
||||
import android.Dependencies.{apklib,aar}
|
||||
|
||||
android.Plugin.androidBuild
|
||||
|
||||
platformTarget in Android := "android-21"
|
||||
platformTarget in Android := "android-23"
|
||||
|
||||
name := "shadowsocks"
|
||||
|
||||
scalaVersion := "2.11.7"
|
||||
|
||||
compileOrder in Compile := CompileOrder.JavaThenScala
|
||||
|
||||
javacOptions ++= Seq("-source", "1.6", "-target", "1.6")
|
||||
|
||||
scalacOptions ++= Seq("-target:jvm-1.6", "-Xexperimental")
|
||||
|
||||
ndkJavah in Android := List()
|
||||
|
||||
ndkBuild in Android := List()
|
||||
@@ -22,25 +26,20 @@ resolvers += "JRAF" at "http://JRAF.org/static/maven/2"
|
||||
|
||||
libraryDependencies ++= Seq(
|
||||
"dnsjava" % "dnsjava" % "2.1.7",
|
||||
"com.github.kevinsawicki" % "http-request" % "5.6",
|
||||
"com.github.kevinsawicki" % "http-request" % "6.0",
|
||||
"commons-net" % "commons-net" % "3.3",
|
||||
"com.google.zxing" % "android-integration" % "3.1.0"
|
||||
)
|
||||
|
||||
libraryDependencies ++= Seq(
|
||||
"com.joanzapata.android" % "android-iconify" % "1.0.9",
|
||||
"com.google.zxing" % "android-integration" % "3.1.0",
|
||||
"com.joanzapata.android" % "android-iconify" % "1.0.11",
|
||||
"net.glxn.qrgen" % "android" % "2.0",
|
||||
"net.simonvt.menudrawer" % "menudrawer" % "3.0.6",
|
||||
"com.google.android.gms" % "play-services-base" % "6.5.87",
|
||||
"com.google.android.gms" % "play-services-ads" % "6.5.87",
|
||||
"com.android.support" % "support-v4" % "21.0.3"
|
||||
)
|
||||
|
||||
libraryDependencies ++= Seq(
|
||||
"com.google.android.gms" % "play-services-base" % "8.1.0",
|
||||
"com.google.android.gms" % "play-services-ads" % "8.1.0",
|
||||
"com.google.android.gms" % "play-services-analytics" % "8.1.0",
|
||||
"com.android.support" % "support-v4" % "23.0.1",
|
||||
"com.github.mrengineer13" % "snackbar" % "0.5.0",
|
||||
"com.nostra13.universalimageloader" % "universal-image-loader" % "1.8.4",
|
||||
"com.j256.ormlite" % "ormlite-core" % "4.47",
|
||||
"com.j256.ormlite" % "ormlite-android" % "4.47"
|
||||
"com.j256.ormlite" % "ormlite-core" % "4.48",
|
||||
"com.j256.ormlite" % "ormlite-android" % "4.48"
|
||||
)
|
||||
|
||||
proguardOptions in Android ++= Seq("-keep class android.support.v4.app.** { *; }",
|
||||
@@ -52,5 +51,6 @@ proguardOptions in Android ++= Seq("-keep class android.support.v4.app.** { *; }
|
||||
"-keep class * extends com.j256.ormlite.** { *; }",
|
||||
"-keep class com.joanzapata.** { *; }",
|
||||
"-keepattributes *Annotation*",
|
||||
"-dontwarn com.google.android.gms.internal.zzhu",
|
||||
"-dontwarn org.xbill.**",
|
||||
"-dontwarn com.actionbarsherlock.**")
|
||||
|
||||
+13
-11
@@ -10,14 +10,14 @@ import IPy
|
||||
|
||||
def main():
|
||||
china_list_set = IPy.IPSet()
|
||||
# for line in sys.stdin:
|
||||
# line_params = line.split("|")
|
||||
# if len(line_params) < 5 or line_params[2] != "ipv4" or line_params[1] != "CN":
|
||||
# continue
|
||||
# ip_addr = line_params[3]
|
||||
# ip_length = float(line_params[4])
|
||||
# ip_mask = 32 - int(math.ceil(math.log(ip_length, 2)))
|
||||
# china_list_set.add(IPy.IP("%s/%d" % (ip_addr, ip_mask)))
|
||||
for line in sys.stdin:
|
||||
line_params = line.split("|")
|
||||
if len(line_params) < 5 or line_params[2] != "ipv4" or line_params[1] != "CN":
|
||||
continue
|
||||
ip_addr = line_params[3]
|
||||
ip_length = float(line_params[4])
|
||||
ip_mask = 32 - int(math.ceil(math.log(ip_length, 2)))
|
||||
china_list_set.add(IPy.IP("%s/%d" % (ip_addr, ip_mask)))
|
||||
|
||||
# 添加内网地址
|
||||
internal_list = IPy.IPSet(map(IPy.IP, [
|
||||
@@ -41,11 +41,13 @@ def main():
|
||||
]))
|
||||
china_list_set += internal_list
|
||||
|
||||
all = china_list_set
|
||||
|
||||
# 取反
|
||||
all = IPy.IPSet([IPy.IP("0.0.0.0/0")])
|
||||
# all = IPy.IPSet([IPy.IP("0.0.0.0/0")])
|
||||
# 剔除所有孤立的C段
|
||||
for ip in china_list_set:
|
||||
all.discard(ip)
|
||||
# for ip in china_list_set:
|
||||
# all.discard(ip)
|
||||
|
||||
# filter = itertools.ifilter(lambda x: len(x) <= 65536, all)
|
||||
# for ip in filter:
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
resolvers += Resolver.url("scalasbt releases", new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-snapshots"))(Resolver.ivyStylePatterns)
|
||||
|
||||
addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.4.8")
|
||||
addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.5.6")
|
||||
|
||||
resolvers += "Sonatype snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/"
|
||||
|
||||
|
||||
@@ -1,102 +1,107 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.github.shadowsocks"
|
||||
android:versionCode="115"
|
||||
android:versionName="2.7.7">
|
||||
package="com.github.shadowsocks"
|
||||
android:versionCode="120"
|
||||
android:versionName="2.8.3">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_SUPERUSER"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_SUPERUSER"/>
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.touchscreen"
|
||||
android:required="false"/>
|
||||
<uses-feature
|
||||
android:name="android.hardware.touchscreen"
|
||||
android:required="false"/>
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="16"
|
||||
android:targetSdkVersion="21"/>
|
||||
<uses-sdk
|
||||
android:minSdkVersion="16"
|
||||
android:targetSdkVersion="23"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:name=".ShadowsocksApplication"
|
||||
android:hardwareAccelerated="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:backupAgent=".ShadowsocksBackupAgent"
|
||||
android:label="@string/app_name">
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:name=".ShadowsocksApplication"
|
||||
android:hardwareAccelerated="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:backupAgent=".ShadowsocksBackupAgent"
|
||||
android:label="@string/app_name">
|
||||
|
||||
<meta-data android:name="com.google.android.gms.version"
|
||||
android:value="@integer/google_play_services_version"/>
|
||||
<meta-data android:name="com.google.android.backup.api_key"
|
||||
android:value="AEdPqrEAAAAI_zVxZthz2HDuz9toTvkYvL0L5GA-OjeUIfBeXg"/>
|
||||
<meta-data android:name="com.google.android.gms.version"
|
||||
android:value="@integer/google_play_services_version"/>
|
||||
<meta-data android:name="com.google.android.backup.api_key"
|
||||
android:value="AEdPqrEAAAAI_zVxZthz2HDuz9toTvkYvL0L5GA-OjeUIfBeXg"/>
|
||||
|
||||
<activity
|
||||
android:name="com.google.android.gms.ads.AdActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"/>
|
||||
<activity
|
||||
android:name="com.google.android.gms.ads.AdActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"/>
|
||||
|
||||
<activity
|
||||
android:name=".Shadowsocks"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Shadowsocks"
|
||||
android:launchMode="singleTask">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".Shadowsocks"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Shadowsocks"
|
||||
android:launchMode="singleTask">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".ParserActivity"
|
||||
android:theme="@style/PopupTheme"
|
||||
android:launchMode="singleTask">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
<data android:scheme="ss"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ParserActivity"
|
||||
android:theme="@style/PopupTheme"
|
||||
android:launchMode="singleTask">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
<data android:scheme="ss"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".ShadowsocksRunnerActivity"
|
||||
android:theme="@android:style/Theme.NoDisplay"
|
||||
android:launchMode="singleTask">
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ShadowsocksRunnerActivity"
|
||||
android:theme="@android:style/Theme.NoDisplay"
|
||||
android:launchMode="singleTask">
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".AppManager"
|
||||
android:theme="@style/Theme.AppManager"
|
||||
android:label="@string/app_name"
|
||||
android:parentActivityName=".Shadowsocks">
|
||||
<intent-filter>
|
||||
<action android:name="com.github.shadowsocks.AppManager"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".AppManager"
|
||||
android:theme="@style/Theme.AppManager"
|
||||
android:label="@string/app_name"
|
||||
android:parentActivityName=".Shadowsocks">
|
||||
<intent-filter>
|
||||
<action android:name="com.github.shadowsocks.AppManager"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name=".ShadowsocksNatService"
|
||||
android:process=":nat"
|
||||
android:exported="false">
|
||||
</service>
|
||||
<service
|
||||
android:name=".ShadowsocksRunnerService"
|
||||
android:exported="false">
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".ShadowsocksVpnService"
|
||||
android:process=":vpn"
|
||||
android:label="@string/app_name"
|
||||
android:permission="android.permission.BIND_VPN_SERVICE"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.net.VpnService"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
<service
|
||||
android:name=".ShadowsocksNatService"
|
||||
android:process=":nat"
|
||||
android:exported="false">
|
||||
</service>
|
||||
|
||||
<receiver android:name=".ShadowsocksReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
<action android:name="com.github.shadowsocks.ACTION_UPDATE_STATE"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<service
|
||||
android:name=".ShadowsocksVpnService"
|
||||
android:process=":vpn"
|
||||
android:label="@string/app_name"
|
||||
android:permission="android.permission.BIND_VPN_SERVICE"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.net.VpnService"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
</application>
|
||||
<receiver android:name=".ShadowsocksReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
<action android:name="com.github.shadowsocks.ACTION_UPDATE_STATE"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -10,6 +10,8 @@ public class Config implements Parcelable {
|
||||
public boolean isBypassApps = false;
|
||||
public boolean isTrafficStat = false;
|
||||
public boolean isUdpDns = false;
|
||||
public boolean isAuth = false;
|
||||
public boolean isIpv6 = false;
|
||||
|
||||
public String profileName = "Untitled";
|
||||
public String proxy = "127.0.0.1";
|
||||
@@ -33,13 +35,15 @@ public class Config implements Parcelable {
|
||||
};
|
||||
|
||||
public Config(boolean isGlobalProxy, boolean isGFWList, boolean isBypassApps,
|
||||
boolean isTrafficStat, boolean isUdpDns, String profileName, String proxy, String sitekey,
|
||||
boolean isTrafficStat, boolean isUdpDns, boolean isAuth, boolean isIpv6, String profileName, String proxy, String sitekey,
|
||||
String encMethod, String proxiedAppString, String route, int remotePort, int localPort) {
|
||||
this.isGlobalProxy = isGlobalProxy;
|
||||
this.isGFWList = isGFWList;
|
||||
this.isBypassApps = isBypassApps;
|
||||
this.isTrafficStat = isTrafficStat;
|
||||
this.isUdpDns = isUdpDns;
|
||||
this.isAuth = isAuth;
|
||||
this.isIpv6 = isIpv6;
|
||||
this.profileName = profileName;
|
||||
this.proxy = proxy;
|
||||
this.sitekey = sitekey;
|
||||
@@ -60,6 +64,8 @@ public class Config implements Parcelable {
|
||||
isBypassApps = in.readInt() == 1;
|
||||
isTrafficStat = in.readInt() == 1;
|
||||
isUdpDns = in.readInt() == 1;
|
||||
isAuth = in.readInt() == 1;
|
||||
isIpv6 = in.readInt() == 1;
|
||||
profileName = in.readString();
|
||||
proxy = in.readString();
|
||||
sitekey = in.readString();
|
||||
@@ -80,6 +86,8 @@ public class Config implements Parcelable {
|
||||
out.writeInt(isBypassApps ? 1 : 0);
|
||||
out.writeInt(isTrafficStat ? 1 : 0);
|
||||
out.writeInt(isUdpDns ? 1 : 0);
|
||||
out.writeInt(isAuth ? 1 : 0);
|
||||
out.writeInt(isIpv6 ? 1 : 0);
|
||||
out.writeString(profileName);
|
||||
out.writeString(proxy);
|
||||
out.writeString(sitekey);
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.util;
|
||||
|
||||
/**
|
||||
* Math routines similar to those found in {@link java.lang.Math}.
|
||||
*
|
||||
* <p>Historically these methods were faster than the equivalent double-based
|
||||
* {@link java.lang.Math} methods. On versions of Android with a JIT they
|
||||
* became slower and have since been re-implemented to wrap calls to
|
||||
* {@link java.lang.Math}. {@link java.lang.Math} should be used in
|
||||
* preference.
|
||||
*
|
||||
* @deprecated Use {@link java.lang.Math} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class FloatMath {
|
||||
|
||||
/** Prevents instantiation. */
|
||||
private FloatMath() {}
|
||||
|
||||
/**
|
||||
* Returns the float conversion of the most positive (i.e. closest to
|
||||
* positive infinity) integer value which is less than the argument.
|
||||
*
|
||||
* @param value to be converted
|
||||
* @return the floor of value
|
||||
*/
|
||||
public static float floor(float value) {
|
||||
return (float) Math.floor(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the float conversion of the most negative (i.e. closest to
|
||||
* negative infinity) integer value which is greater than the argument.
|
||||
*
|
||||
* @param value to be converted
|
||||
* @return the ceiling of value
|
||||
*/
|
||||
public static float ceil(float value) {
|
||||
return (float) Math.ceil(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the closest float approximation of the sine of the argument.
|
||||
*
|
||||
* @param angle to compute the cosine of, in radians
|
||||
* @return the sine of angle
|
||||
*/
|
||||
public static float sin(float angle) {
|
||||
return (float) Math.sin(angle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the closest float approximation of the cosine of the argument.
|
||||
*
|
||||
* @param angle to compute the cosine of, in radians
|
||||
* @return the cosine of angle
|
||||
*/
|
||||
public static float cos(float angle) {
|
||||
return (float) Math.cos(angle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the closest float approximation of the square root of the
|
||||
* argument.
|
||||
*
|
||||
* @param value to compute sqrt of
|
||||
* @return the square root of value
|
||||
*/
|
||||
public static float sqrt(float value) {
|
||||
return (float) Math.sqrt(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the closest float approximation of the raising "e" to the power
|
||||
* of the argument.
|
||||
*
|
||||
* @param value to compute the exponential of
|
||||
* @return the exponential of value
|
||||
*/
|
||||
public static float exp(float value) {
|
||||
return (float) Math.exp(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the closest float approximation of the result of raising {@code
|
||||
* x} to the power of {@code y}.
|
||||
*
|
||||
* @param x the base of the operation.
|
||||
* @param y the exponent of the operation.
|
||||
* @return {@code x} to the power of {@code y}.
|
||||
*/
|
||||
public static float pow(float x, float y) {
|
||||
return (float) Math.pow(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code sqrt(}<i>{@code x}</i><sup>{@code 2}</sup>{@code +} <i>
|
||||
* {@code y}</i><sup>{@code 2}</sup>{@code )}.
|
||||
*
|
||||
* @param x a float number
|
||||
* @param y a float number
|
||||
* @return the hypotenuse
|
||||
*/
|
||||
public static float hypot(float x, float y) {
|
||||
return (float) Math.hypot(x, y);
|
||||
}
|
||||
}
|
||||
@@ -1772,6 +1772,9 @@ err_t listener_accept_func (void *arg, struct tcp_pcb *newpcb, err_t err)
|
||||
// set client not closed
|
||||
client->client_closed = 0;
|
||||
|
||||
// enable TCP_NODELAY
|
||||
tcp_nagle_disable(client->pcb);
|
||||
|
||||
// setup handler argument
|
||||
tcp_arg(client->pcb, client);
|
||||
|
||||
|
||||
Submodule src/main/jni/shadowsocks-libev updated: e3ed222360...095aa7490c
@@ -77,6 +77,12 @@
|
||||
<string name="udp_dns">UDP 转发</string>
|
||||
<string name="udp_dns_summary">由远程服务器转发 UDP 协议的数据包</string>
|
||||
|
||||
<string name="onetime_auth">一次性认证</string>
|
||||
<string name="onetime_auth_summary">启用一次性认证(实验性)</string>
|
||||
|
||||
<string name="ipv6">IPv6 路由</string>
|
||||
<string name="ipv6_summary">向远程服务器转发 IPv6 流量</string>
|
||||
|
||||
<!-- profile -->
|
||||
<string name="add_profile_dialog">为影梭添加此配置文件?</string>
|
||||
<string-array name="add_profile_methods">
|
||||
|
||||
@@ -321,6 +321,10 @@
|
||||
<item>43.239.0.0/19</item>
|
||||
<item>43.239.32.0/20</item>
|
||||
<item>43.239.48.0/22</item>
|
||||
<item>43.239.116.0/22</item>
|
||||
<item>43.239.120.0/22</item>
|
||||
<item>43.239.172.0/22</item>
|
||||
<item>43.239.176.0/22</item>
|
||||
<item>43.240.0.0/22</item>
|
||||
<item>43.240.48.0/22</item>
|
||||
<item>43.240.56.0/21</item>
|
||||
@@ -384,6 +388,8 @@
|
||||
<item>43.246.0.0/18</item>
|
||||
<item>43.246.64.0/19</item>
|
||||
<item>43.246.96.0/22</item>
|
||||
<item>43.246.212.0/22</item>
|
||||
<item>43.246.228.0/22</item>
|
||||
<item>43.247.4.0/22</item>
|
||||
<item>43.247.8.0/22</item>
|
||||
<item>43.247.44.0/22</item>
|
||||
@@ -505,6 +511,170 @@
|
||||
<item>43.255.232.0/22</item>
|
||||
<item>43.255.244.0/22</item>
|
||||
<item>45.64.112.0/23</item>
|
||||
<item>45.112.132.0/22</item>
|
||||
<item>45.112.188.0/22</item>
|
||||
<item>45.112.208.0/20</item>
|
||||
<item>45.112.228.0/22</item>
|
||||
<item>45.112.232.0/21</item>
|
||||
<item>45.113.12.0/22</item>
|
||||
<item>45.113.16.0/20</item>
|
||||
<item>45.113.40.0/22</item>
|
||||
<item>45.113.52.0/22</item>
|
||||
<item>45.113.56.0/22</item>
|
||||
<item>45.113.72.0/22</item>
|
||||
<item>45.113.108.0/22</item>
|
||||
<item>45.113.144.0/21</item>
|
||||
<item>45.113.168.0/22</item>
|
||||
<item>45.113.176.0/22</item>
|
||||
<item>45.113.184.0/22</item>
|
||||
<item>45.113.200.0/21</item>
|
||||
<item>45.113.208.0/20</item>
|
||||
<item>45.113.228.0/22</item>
|
||||
<item>45.113.240.0/22</item>
|
||||
<item>45.113.252.0/22</item>
|
||||
<item>45.114.0.0/22</item>
|
||||
<item>45.114.12.0/22</item>
|
||||
<item>45.114.32.0/22</item>
|
||||
<item>45.114.40.0/22</item>
|
||||
<item>45.114.52.0/22</item>
|
||||
<item>45.114.96.0/22</item>
|
||||
<item>45.114.104.0/22</item>
|
||||
<item>45.114.136.0/22</item>
|
||||
<item>45.114.196.0/22</item>
|
||||
<item>45.114.200.0/22</item>
|
||||
<item>45.114.228.0/22</item>
|
||||
<item>45.114.236.0/22</item>
|
||||
<item>45.114.252.0/22</item>
|
||||
<item>45.115.44.0/22</item>
|
||||
<item>45.115.100.0/22</item>
|
||||
<item>45.115.120.0/22</item>
|
||||
<item>45.115.132.0/22</item>
|
||||
<item>45.115.144.0/22</item>
|
||||
<item>45.115.156.0/22</item>
|
||||
<item>45.115.164.0/22</item>
|
||||
<item>45.115.200.0/22</item>
|
||||
<item>45.115.212.0/22</item>
|
||||
<item>45.115.216.0/22</item>
|
||||
<item>45.115.228.0/22</item>
|
||||
<item>45.115.236.0/22</item>
|
||||
<item>45.115.244.0/22</item>
|
||||
<item>45.115.248.0/22</item>
|
||||
<item>45.116.12.0/22</item>
|
||||
<item>45.116.16.0/21</item>
|
||||
<item>45.116.24.0/22</item>
|
||||
<item>45.116.32.0/21</item>
|
||||
<item>45.116.52.0/22</item>
|
||||
<item>45.116.60.0/22</item>
|
||||
<item>45.116.64.0/22</item>
|
||||
<item>45.116.96.0/21</item>
|
||||
<item>45.116.140.0/22</item>
|
||||
<item>45.116.152.0/22</item>
|
||||
<item>45.116.208.0/22</item>
|
||||
<item>45.117.8.0/22</item>
|
||||
<item>45.117.20.0/22</item>
|
||||
<item>45.117.40.0/22</item>
|
||||
<item>45.117.68.0/22</item>
|
||||
<item>45.117.124.0/22</item>
|
||||
<item>45.117.252.0/22</item>
|
||||
<item>45.119.52.0/22</item>
|
||||
<item>45.119.60.0/22</item>
|
||||
<item>45.119.64.0/21</item>
|
||||
<item>45.119.72.0/22</item>
|
||||
<item>45.119.104.0/22</item>
|
||||
<item>45.119.116.0/22</item>
|
||||
<item>45.119.160.0/22</item>
|
||||
<item>45.119.232.0/22</item>
|
||||
<item>45.120.100.0/22</item>
|
||||
<item>45.120.140.0/22</item>
|
||||
<item>45.120.156.0/22</item>
|
||||
<item>45.120.164.0/22</item>
|
||||
<item>45.120.220.0/22</item>
|
||||
<item>45.120.240.0/22</item>
|
||||
<item>45.121.20.0/22</item>
|
||||
<item>45.121.52.0/22</item>
|
||||
<item>45.121.64.0/21</item>
|
||||
<item>45.121.72.0/22</item>
|
||||
<item>45.121.92.0/22</item>
|
||||
<item>45.121.96.0/22</item>
|
||||
<item>45.121.104.0/22</item>
|
||||
<item>45.121.172.0/22</item>
|
||||
<item>45.121.176.0/22</item>
|
||||
<item>45.121.212.0/22</item>
|
||||
<item>45.121.240.0/20</item>
|
||||
<item>45.122.0.0/19</item>
|
||||
<item>45.122.32.0/21</item>
|
||||
<item>45.122.40.0/22</item>
|
||||
<item>45.122.60.0/22</item>
|
||||
<item>45.122.64.0/19</item>
|
||||
<item>45.122.96.0/20</item>
|
||||
<item>45.122.112.0/21</item>
|
||||
<item>45.122.160.0/19</item>
|
||||
<item>45.122.192.0/20</item>
|
||||
<item>45.122.208.0/21</item>
|
||||
<item>45.122.216.0/22</item>
|
||||
<item>45.123.28.0/22</item>
|
||||
<item>45.123.32.0/21</item>
|
||||
<item>45.123.44.0/22</item>
|
||||
<item>45.123.48.0/20</item>
|
||||
<item>45.123.64.0/20</item>
|
||||
<item>45.123.80.0/21</item>
|
||||
<item>45.123.88.0/22</item>
|
||||
<item>45.123.120.0/22</item>
|
||||
<item>45.123.128.0/21</item>
|
||||
<item>45.123.136.0/22</item>
|
||||
<item>45.123.148.0/22</item>
|
||||
<item>45.123.152.0/21</item>
|
||||
<item>45.123.164.0/22</item>
|
||||
<item>45.123.168.0/21</item>
|
||||
<item>45.123.176.0/21</item>
|
||||
<item>45.123.184.0/22</item>
|
||||
<item>45.123.204.0/22</item>
|
||||
<item>45.123.212.0/22</item>
|
||||
<item>45.123.224.0/19</item>
|
||||
<item>45.124.0.0/22</item>
|
||||
<item>45.124.20.0/22</item>
|
||||
<item>45.124.28.0/22</item>
|
||||
<item>45.124.32.0/21</item>
|
||||
<item>45.124.44.0/22</item>
|
||||
<item>45.124.68.0/22</item>
|
||||
<item>45.124.76.0/22</item>
|
||||
<item>45.124.80.0/22</item>
|
||||
<item>45.124.100.0/22</item>
|
||||
<item>45.124.124.0/22</item>
|
||||
<item>45.124.172.0/22</item>
|
||||
<item>45.124.176.0/22</item>
|
||||
<item>45.124.208.0/22</item>
|
||||
<item>45.124.248.0/21</item>
|
||||
<item>45.125.12.0/22</item>
|
||||
<item>45.125.16.0/22</item>
|
||||
<item>45.125.24.0/21</item>
|
||||
<item>45.125.32.0/22</item>
|
||||
<item>45.125.44.0/22</item>
|
||||
<item>45.125.52.0/22</item>
|
||||
<item>45.125.56.0/22</item>
|
||||
<item>45.125.76.0/22</item>
|
||||
<item>45.125.80.0/20</item>
|
||||
<item>45.125.96.0/21</item>
|
||||
<item>45.125.104.0/22</item>
|
||||
<item>45.125.136.0/22</item>
|
||||
<item>45.126.48.0/21</item>
|
||||
<item>45.126.100.0/22</item>
|
||||
<item>45.126.108.0/22</item>
|
||||
<item>45.126.112.0/21</item>
|
||||
<item>45.126.120.0/22</item>
|
||||
<item>45.126.212.0/22</item>
|
||||
<item>45.126.220.0/22</item>
|
||||
<item>45.127.8.0/21</item>
|
||||
<item>45.127.36.0/22</item>
|
||||
<item>45.127.96.0/22</item>
|
||||
<item>45.127.116.0/22</item>
|
||||
<item>45.127.124.0/22</item>
|
||||
<item>45.127.128.0/22</item>
|
||||
<item>45.127.144.0/21</item>
|
||||
<item>45.127.156.0/22</item>
|
||||
<item>45.127.216.0/22</item>
|
||||
<item>47.92.0.0/14</item>
|
||||
<item>47.96.0.0/11</item>
|
||||
<item>49.4.0.0/14</item>
|
||||
<item>49.51.0.0/16</item>
|
||||
<item>49.52.0.0/14</item>
|
||||
@@ -547,6 +717,7 @@
|
||||
<item>59.107.0.0/16</item>
|
||||
<item>59.108.0.0/14</item>
|
||||
<item>59.151.0.0/17</item>
|
||||
<item>59.153.4.0/22</item>
|
||||
<item>59.155.0.0/16</item>
|
||||
<item>59.172.0.0/14</item>
|
||||
<item>59.191.0.0/17</item>
|
||||
@@ -692,6 +863,7 @@
|
||||
<item>103.8.156.0/22</item>
|
||||
<item>103.8.200.0/21</item>
|
||||
<item>103.8.220.0/22</item>
|
||||
<item>103.9.8.0/22</item>
|
||||
<item>103.9.152.0/22</item>
|
||||
<item>103.9.248.0/21</item>
|
||||
<item>103.10.0.0/22</item>
|
||||
@@ -803,7 +975,6 @@
|
||||
<item>103.30.96.0/22</item>
|
||||
<item>103.30.148.0/22</item>
|
||||
<item>103.30.200.0/22</item>
|
||||
<item>103.30.216.0/22</item>
|
||||
<item>103.30.228.0/22</item>
|
||||
<item>103.30.236.0/22</item>
|
||||
<item>103.31.0.0/22</item>
|
||||
@@ -818,6 +989,10 @@
|
||||
<item>103.35.0.0/19</item>
|
||||
<item>103.35.32.0/20</item>
|
||||
<item>103.35.48.0/22</item>
|
||||
<item>103.35.104.0/22</item>
|
||||
<item>103.35.116.0/22</item>
|
||||
<item>103.35.200.0/22</item>
|
||||
<item>103.35.220.0/22</item>
|
||||
<item>103.36.20.0/22</item>
|
||||
<item>103.36.28.0/22</item>
|
||||
<item>103.36.36.0/22</item>
|
||||
@@ -1004,6 +1179,159 @@
|
||||
<item>103.50.224.0/20</item>
|
||||
<item>103.50.240.0/21</item>
|
||||
<item>103.50.248.0/22</item>
|
||||
<item>103.52.40.0/22</item>
|
||||
<item>103.52.72.0/21</item>
|
||||
<item>103.52.80.0/21</item>
|
||||
<item>103.52.96.0/21</item>
|
||||
<item>103.52.104.0/22</item>
|
||||
<item>103.52.160.0/21</item>
|
||||
<item>103.52.172.0/22</item>
|
||||
<item>103.52.176.0/22</item>
|
||||
<item>103.52.184.0/22</item>
|
||||
<item>103.52.196.0/22</item>
|
||||
<item>103.53.4.0/22</item>
|
||||
<item>103.53.64.0/21</item>
|
||||
<item>103.53.92.0/22</item>
|
||||
<item>103.53.100.0/22</item>
|
||||
<item>103.53.124.0/22</item>
|
||||
<item>103.53.128.0/20</item>
|
||||
<item>103.53.144.0/22</item>
|
||||
<item>103.53.160.0/22</item>
|
||||
<item>103.53.180.0/22</item>
|
||||
<item>103.53.204.0/22</item>
|
||||
<item>103.53.208.0/22</item>
|
||||
<item>103.53.216.0/22</item>
|
||||
<item>103.53.236.0/22</item>
|
||||
<item>103.53.248.0/22</item>
|
||||
<item>103.54.8.0/22</item>
|
||||
<item>103.54.48.0/22</item>
|
||||
<item>103.54.60.0/22</item>
|
||||
<item>103.54.160.0/21</item>
|
||||
<item>103.54.212.0/22</item>
|
||||
<item>103.54.228.0/22</item>
|
||||
<item>103.54.240.0/22</item>
|
||||
<item>103.55.24.0/22</item>
|
||||
<item>103.55.80.0/22</item>
|
||||
<item>103.55.120.0/22</item>
|
||||
<item>103.55.152.0/22</item>
|
||||
<item>103.55.172.0/22</item>
|
||||
<item>103.55.204.0/22</item>
|
||||
<item>103.55.208.0/22</item>
|
||||
<item>103.55.228.0/22</item>
|
||||
<item>103.55.236.0/22</item>
|
||||
<item>103.55.240.0/22</item>
|
||||
<item>103.56.8.0/22</item>
|
||||
<item>103.56.16.0/21</item>
|
||||
<item>103.56.32.0/22</item>
|
||||
<item>103.56.52.0/22</item>
|
||||
<item>103.56.56.0/21</item>
|
||||
<item>103.56.72.0/21</item>
|
||||
<item>103.56.100.0/22</item>
|
||||
<item>103.56.104.0/22</item>
|
||||
<item>103.56.140.0/22</item>
|
||||
<item>103.56.152.0/22</item>
|
||||
<item>103.56.184.0/22</item>
|
||||
<item>103.56.200.0/22</item>
|
||||
<item>103.56.216.0/22</item>
|
||||
<item>103.57.12.0/22</item>
|
||||
<item>103.57.52.0/22</item>
|
||||
<item>103.57.56.0/22</item>
|
||||
<item>103.57.76.0/22</item>
|
||||
<item>103.57.108.0/22</item>
|
||||
<item>103.57.136.0/22</item>
|
||||
<item>103.57.196.0/22</item>
|
||||
<item>103.58.24.0/22</item>
|
||||
<item>103.58.182.0/23</item>
|
||||
<item>103.59.76.0/22</item>
|
||||
<item>103.59.100.0/22</item>
|
||||
<item>103.59.112.0/20</item>
|
||||
<item>103.59.128.0/22</item>
|
||||
<item>103.59.148.0/22</item>
|
||||
<item>103.59.164.0/22</item>
|
||||
<item>103.59.216.0/22</item>
|
||||
<item>103.60.32.0/22</item>
|
||||
<item>103.60.44.0/22</item>
|
||||
<item>103.60.164.0/22</item>
|
||||
<item>103.60.228.0/22</item>
|
||||
<item>103.60.236.0/22</item>
|
||||
<item>103.61.60.0/22</item>
|
||||
<item>103.61.104.0/22</item>
|
||||
<item>103.61.140.0/22</item>
|
||||
<item>103.61.152.0/21</item>
|
||||
<item>103.61.160.0/22</item>
|
||||
<item>103.61.172.0/22</item>
|
||||
<item>103.61.176.0/22</item>
|
||||
<item>103.61.184.0/21</item>
|
||||
<item>103.62.24.0/22</item>
|
||||
<item>103.62.52.0/22</item>
|
||||
<item>103.62.72.0/21</item>
|
||||
<item>103.62.80.0/21</item>
|
||||
<item>103.62.88.0/22</item>
|
||||
<item>103.62.96.0/19</item>
|
||||
<item>103.62.128.0/21</item>
|
||||
<item>103.62.156.0/22</item>
|
||||
<item>103.62.160.0/19</item>
|
||||
<item>103.62.192.0/22</item>
|
||||
<item>103.62.204.0/22</item>
|
||||
<item>103.62.208.0/20</item>
|
||||
<item>103.62.224.0/22</item>
|
||||
<item>103.63.32.0/19</item>
|
||||
<item>103.63.64.0/20</item>
|
||||
<item>103.63.80.0/21</item>
|
||||
<item>103.63.88.0/22</item>
|
||||
<item>103.63.140.0/22</item>
|
||||
<item>103.63.144.0/22</item>
|
||||
<item>103.63.152.0/22</item>
|
||||
<item>103.63.160.0/20</item>
|
||||
<item>103.63.176.0/21</item>
|
||||
<item>103.63.184.0/22</item>
|
||||
<item>103.63.192.0/20</item>
|
||||
<item>103.63.208.0/22</item>
|
||||
<item>103.63.240.0/20</item>
|
||||
<item>103.192.0.0/19</item>
|
||||
<item>103.192.48.0/21</item>
|
||||
<item>103.192.56.0/22</item>
|
||||
<item>103.192.84.0/22</item>
|
||||
<item>103.192.88.0/21</item>
|
||||
<item>103.192.96.0/20</item>
|
||||
<item>103.192.112.0/22</item>
|
||||
<item>103.192.128.0/20</item>
|
||||
<item>103.192.144.0/22</item>
|
||||
<item>103.192.164.0/22</item>
|
||||
<item>103.192.188.0/22</item>
|
||||
<item>103.192.208.0/21</item>
|
||||
<item>103.192.216.0/22</item>
|
||||
<item>103.192.252.0/22</item>
|
||||
<item>103.193.40.0/21</item>
|
||||
<item>103.193.120.0/21</item>
|
||||
<item>103.193.140.0/22</item>
|
||||
<item>103.193.144.0/21</item>
|
||||
<item>103.193.160.0/22</item>
|
||||
<item>103.193.188.0/22</item>
|
||||
<item>103.193.192.0/22</item>
|
||||
<item>103.193.212.0/22</item>
|
||||
<item>103.193.216.0/21</item>
|
||||
<item>103.193.224.0/20</item>
|
||||
<item>103.193.240.0/22</item>
|
||||
<item>103.194.16.0/22</item>
|
||||
<item>103.194.230.0/23</item>
|
||||
<item>103.195.104.0/22</item>
|
||||
<item>103.195.112.0/22</item>
|
||||
<item>103.195.136.0/22</item>
|
||||
<item>103.195.148.0/22</item>
|
||||
<item>103.195.152.0/22</item>
|
||||
<item>103.195.160.0/22</item>
|
||||
<item>103.195.192.0/22</item>
|
||||
<item>103.196.60.0/22</item>
|
||||
<item>103.196.64.0/22</item>
|
||||
<item>103.196.72.0/22</item>
|
||||
<item>103.196.88.0/21</item>
|
||||
<item>103.196.96.0/22</item>
|
||||
<item>103.196.168.0/22</item>
|
||||
<item>103.196.184.0/22</item>
|
||||
<item>103.196.204.0/22</item>
|
||||
<item>103.197.180.0/22</item>
|
||||
<item>103.197.228.0/22</item>
|
||||
<item>103.224.40.0/21</item>
|
||||
<item>103.224.60.0/22</item>
|
||||
<item>103.224.80.0/22</item>
|
||||
@@ -1082,6 +1410,7 @@
|
||||
<item>103.234.128.0/22</item>
|
||||
<item>103.234.172.0/22</item>
|
||||
<item>103.234.180.0/22</item>
|
||||
<item>103.234.244.0/22</item>
|
||||
<item>103.235.16.0/22</item>
|
||||
<item>103.235.48.0/22</item>
|
||||
<item>103.235.56.0/21</item>
|
||||
@@ -1096,6 +1425,11 @@
|
||||
<item>103.236.0.0/18</item>
|
||||
<item>103.236.64.0/19</item>
|
||||
<item>103.236.96.0/22</item>
|
||||
<item>103.236.120.0/22</item>
|
||||
<item>103.236.184.0/22</item>
|
||||
<item>103.236.220.0/22</item>
|
||||
<item>103.236.232.0/22</item>
|
||||
<item>103.236.240.0/20</item>
|
||||
<item>103.237.0.0/20</item>
|
||||
<item>103.237.24.0/21</item>
|
||||
<item>103.237.68.0/22</item>
|
||||
@@ -1866,6 +2200,7 @@
|
||||
<item>150.115.0.0/16</item>
|
||||
<item>150.121.0.0/16</item>
|
||||
<item>150.122.0.0/16</item>
|
||||
<item>150.129.136.0/22</item>
|
||||
<item>150.129.152.0/22</item>
|
||||
<item>150.129.192.0/22</item>
|
||||
<item>150.129.216.0/22</item>
|
||||
@@ -1936,6 +2271,7 @@
|
||||
<item>166.111.0.0/16</item>
|
||||
<item>167.139.0.0/16</item>
|
||||
<item>167.189.0.0/16</item>
|
||||
<item>167.220.244.0/22</item>
|
||||
<item>168.160.0.0/16</item>
|
||||
<item>169.254.0.0/16</item>
|
||||
<item>171.8.0.0/13</item>
|
||||
@@ -2307,6 +2643,8 @@
|
||||
<item>202.122.128.0/24</item>
|
||||
<item>202.122.132.0/24</item>
|
||||
<item>202.123.96.0/20</item>
|
||||
<item>202.123.116.0/22</item>
|
||||
<item>202.123.120.0/22</item>
|
||||
<item>202.124.16.0/21</item>
|
||||
<item>202.124.24.0/22</item>
|
||||
<item>202.125.112.0/20</item>
|
||||
@@ -2388,6 +2726,8 @@
|
||||
<item>202.172.0.0/22</item>
|
||||
<item>202.173.0.0/22</item>
|
||||
<item>202.173.8.0/21</item>
|
||||
<item>202.173.112.0/22</item>
|
||||
<item>202.173.120.0/22</item>
|
||||
<item>202.173.224.0/19</item>
|
||||
<item>202.174.64.0/20</item>
|
||||
<item>202.176.224.0/19</item>
|
||||
@@ -3363,7 +3703,6 @@
|
||||
<item>210.26.0.0/15</item>
|
||||
<item>210.28.0.0/14</item>
|
||||
<item>210.32.0.0/12</item>
|
||||
<item>210.48.136.0/21</item>
|
||||
<item>210.51.0.0/16</item>
|
||||
<item>210.52.0.0/15</item>
|
||||
<item>210.56.192.0/19</item>
|
||||
@@ -3408,6 +3747,7 @@
|
||||
<item>220.112.0.0/14</item>
|
||||
<item>220.152.128.0/17</item>
|
||||
<item>220.154.0.0/15</item>
|
||||
<item>220.158.240.0/22</item>
|
||||
<item>220.160.0.0/11</item>
|
||||
<item>220.192.0.0/12</item>
|
||||
<item>220.231.0.0/18</item>
|
||||
|
||||
@@ -25,10 +25,14 @@
|
||||
|
||||
<!-- feature category -->
|
||||
<string name="feature_cat">Feature Settings</string>
|
||||
<string name="ipv6">IPv6 Route</string>
|
||||
<string name="ipv6_summary">Redirect IPv6 traffic to remote</string>
|
||||
<string name="onetime_auth">One-time Authentication</string>
|
||||
<string name="onetime_auth_summary">Enable one-time authentication (Experimental)</string>
|
||||
<string name="http_proxy">HTTP Proxy</string>
|
||||
<string name="http_proxy_summary">Local HTTP Proxy</string>
|
||||
<string name="dns_proxy">DNS Proxy</string>
|
||||
<string name="dns_proxy_summary">Redirect DNS queries to remote server</string>
|
||||
<string name="dns_proxy_summary">Redirect DNS queries to remote</string>
|
||||
<string name="auto_set_gfwlist">CHN Route</string>
|
||||
<string name="auto_set_gfwlist_summary">Bypass all sites located in China
|
||||
</string>
|
||||
@@ -46,7 +50,7 @@
|
||||
<string name="traffic_stat">Traffic Stats</string>
|
||||
<string name="traffic_stat_summary">Show traffic stats in notification bar</string>
|
||||
<string name="udp_dns">UDP Forwarding</string>
|
||||
<string name="udp_dns_summary">Forward UDP packets to remote server</string>
|
||||
<string name="udp_dns_summary">Forward UDP packets to remote</string>
|
||||
|
||||
<!-- notification category -->
|
||||
<string name="forward_success">Shadowsocks started.</string>
|
||||
|
||||
@@ -58,6 +58,12 @@
|
||||
android:summary="@string/route_list_summary"
|
||||
android:title="@string/route_list">
|
||||
</com.github.shadowsocks.preferences.SummaryListPreference>
|
||||
<CheckBoxPreference
|
||||
android:key="isIpv6"
|
||||
android:defaultValue="false"
|
||||
android:summary="@string/ipv6_summary"
|
||||
android:title="@string/ipv6">
|
||||
</CheckBoxPreference>
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="true"
|
||||
android:key="isGlobalProxy"
|
||||
@@ -78,6 +84,12 @@
|
||||
android:summary="@string/udp_dns_summary"
|
||||
android:title="@string/udp_dns">
|
||||
</CheckBoxPreference>
|
||||
<CheckBoxPreference
|
||||
android:key="isAuth"
|
||||
android:defaultValue="false"
|
||||
android:summary="@string/onetime_auth_summary"
|
||||
android:title="@string/onetime_auth">
|
||||
</CheckBoxPreference>
|
||||
<CheckBoxPreference
|
||||
android:key="isAutoConnect"
|
||||
android:summary="@string/auto_connect_summary"
|
||||
|
||||
@@ -65,7 +65,8 @@ import com.nostra13.universalimageloader.core.{DisplayImageOptions, ImageLoader,
|
||||
import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer
|
||||
import com.github.shadowsocks.utils.{Utils, Scheme, Key}
|
||||
|
||||
import scala.concurrent.ops._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.Future
|
||||
import scala.language.implicitConversions
|
||||
|
||||
case class ProxiedApp(uid: Int, name: String, packageName: String, var proxied: Boolean)
|
||||
@@ -267,9 +268,8 @@ class AppManager extends Activity with OnCheckedChangeListener with OnClickListe
|
||||
}
|
||||
|
||||
protected override def onCreateOptionsMenu(menu: Menu): Boolean = {
|
||||
val inflater = getMenuInflater()
|
||||
inflater.inflate(R.menu.app_manager_menu, menu)
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
getMenuInflater.inflate(R.menu.app_manager_menu, menu)
|
||||
super.onCreateOptionsMenu(menu)
|
||||
}
|
||||
|
||||
protected override def onCreate(savedInstanceState: Bundle) {
|
||||
@@ -277,7 +277,7 @@ class AppManager extends Activity with OnCheckedChangeListener with OnClickListe
|
||||
|
||||
handler = new Handler()
|
||||
|
||||
val actionBar = getActionBar()
|
||||
val actionBar = getActionBar
|
||||
actionBar.setTitle(R.string.proxied_help)
|
||||
actionBar.setDisplayHomeAsUpEnabled(true)
|
||||
actionBar.setDisplayShowHomeEnabled(false)
|
||||
@@ -297,11 +297,8 @@ class AppManager extends Activity with OnCheckedChangeListener with OnClickListe
|
||||
|
||||
val bypassSwitch = findViewById(R.id.bypassSwitch).asInstanceOf[Switch]
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext)
|
||||
bypassSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener {
|
||||
def onCheckedChanged(button: CompoundButton, checked: Boolean) {
|
||||
prefs.edit().putBoolean(Key.isBypassApps, checked).commit()
|
||||
}
|
||||
})
|
||||
bypassSwitch.setOnCheckedChangeListener((button: CompoundButton, checked: Boolean) =>
|
||||
prefs.edit().putBoolean(Key.isBypassApps, checked).commit())
|
||||
bypassSwitch.setChecked(prefs.getBoolean(Key.isBypassApps, false))
|
||||
|
||||
appListView = findViewById(R.id.applistview).asInstanceOf[ListView]
|
||||
@@ -309,7 +306,7 @@ class AppManager extends Activity with OnCheckedChangeListener with OnClickListe
|
||||
|
||||
protected override def onResume() {
|
||||
super.onResume()
|
||||
spawn {
|
||||
Future {
|
||||
handler.post(loadStartRunnable)
|
||||
if (!appsLoaded) loadApps()
|
||||
handler.post(loadFinishRunnable)
|
||||
|
||||
@@ -39,13 +39,11 @@
|
||||
|
||||
package com.github.shadowsocks
|
||||
|
||||
import android.os.{Handler, RemoteCallbackList}
|
||||
import com.github.shadowsocks.aidl.{Config, IShadowsocksService, IShadowsocksServiceCallback}
|
||||
import com.github.shadowsocks.utils.{Path, State}
|
||||
import java.io.{IOException, FileNotFoundException, FileReader, BufferedReader}
|
||||
import android.util.Log
|
||||
import android.app.Notification
|
||||
import android.content.Context
|
||||
import android.os.{Handler, RemoteCallbackList}
|
||||
import com.github.shadowsocks.aidl.{Config, IShadowsocksService, IShadowsocksServiceCallback}
|
||||
import com.github.shadowsocks.utils.State
|
||||
|
||||
trait BaseService {
|
||||
|
||||
@@ -100,10 +98,10 @@ trait BaseService {
|
||||
def getTag: String
|
||||
def getContext: Context
|
||||
|
||||
def getCallbackCount(): Int = {
|
||||
def getCallbackCount: Int = {
|
||||
callbackCount
|
||||
}
|
||||
def getState(): Int = {
|
||||
def getState: Int = {
|
||||
state
|
||||
}
|
||||
def changeState(s: Int) {
|
||||
@@ -112,23 +110,19 @@ trait BaseService {
|
||||
|
||||
protected def changeState(s: Int, msg: String) {
|
||||
val handler = new Handler(getContext.getMainLooper)
|
||||
handler.post(new Runnable {
|
||||
override def run() {
|
||||
if (state != s) {
|
||||
if (callbackCount > 0) {
|
||||
val n = callbacks.beginBroadcast()
|
||||
for (i <- 0 to n - 1) {
|
||||
try {
|
||||
callbacks.getBroadcastItem(i).stateChanged(s, msg)
|
||||
} catch {
|
||||
case _: Exception => // Ignore
|
||||
}
|
||||
}
|
||||
callbacks.finishBroadcast()
|
||||
handler.post(() => if (state != s) {
|
||||
if (callbackCount > 0) {
|
||||
val n = callbacks.beginBroadcast()
|
||||
for (i <- 0 to n - 1) {
|
||||
try {
|
||||
callbacks.getBroadcastItem(i).stateChanged(s, msg)
|
||||
} catch {
|
||||
case _: Exception => // Ignore
|
||||
}
|
||||
state = s
|
||||
}
|
||||
callbacks.finishBroadcast()
|
||||
}
|
||||
state = s
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -39,15 +39,15 @@
|
||||
|
||||
package com.github.shadowsocks
|
||||
|
||||
import android.os.{Message, Handler, Bundle}
|
||||
import android.app.{ProgressDialog, AlertDialog, Activity}
|
||||
import android.content.{Intent, DialogInterface}
|
||||
import com.github.shadowsocks.database.{ProfileManager, Profile}
|
||||
import com.github.shadowsocks.utils.{Parser, Action}
|
||||
import android.preference.PreferenceManager
|
||||
import android.view.WindowManager
|
||||
import android.app.{Activity, AlertDialog, ProgressDialog}
|
||||
import android.content.DialogInterface
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.{Bundle, Handler, Message}
|
||||
import android.preference.PreferenceManager
|
||||
import android.view.WindowManager
|
||||
import com.github.shadowsocks.database.{Profile, ProfileManager}
|
||||
import com.github.shadowsocks.utils.Parser
|
||||
|
||||
class ParserActivity extends Activity {
|
||||
override def onCreate(savedInstanceState: Bundle) {
|
||||
@@ -57,21 +57,17 @@ class ParserActivity extends Activity {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.add_profile_dialog)
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
||||
override def onClick(dialog: DialogInterface, id: Int) {
|
||||
.setPositiveButton(R.string.yes, ((dialog: DialogInterface, id: Int) => {
|
||||
Parser.parse(data) match {
|
||||
case Some(profile) => addProfile(profile)
|
||||
case _ => // ignore
|
||||
}
|
||||
dialog.dismiss()
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
|
||||
override def onClick(dialog: DialogInterface, id: Int) {
|
||||
}): DialogInterface.OnClickListener)
|
||||
.setNegativeButton(R.string.no, ((dialog: DialogInterface, id: Int) => {
|
||||
dialog.dismiss()
|
||||
finish()
|
||||
}
|
||||
})
|
||||
}): DialogInterface.OnClickListener)
|
||||
.setMessage(data)
|
||||
.create()
|
||||
.show()
|
||||
@@ -91,15 +87,13 @@ class ParserActivity extends Activity {
|
||||
|
||||
val h = showProgress(getString(R.string.loading))
|
||||
|
||||
h.postDelayed(new Runnable {
|
||||
def run() {
|
||||
val profileManager =
|
||||
new ProfileManager(PreferenceManager.getDefaultSharedPreferences(getBaseContext),
|
||||
getApplication.asInstanceOf[ShadowsocksApplication].dbHelper)
|
||||
profileManager.createOrUpdateProfile(profile)
|
||||
profileManager.reload(profile.id)
|
||||
h.sendEmptyMessage(0)
|
||||
}
|
||||
h.postDelayed(() => {
|
||||
val profileManager =
|
||||
new ProfileManager(PreferenceManager.getDefaultSharedPreferences(getBaseContext),
|
||||
getApplication.asInstanceOf[ShadowsocksApplication].dbHelper)
|
||||
profileManager.createOrUpdateProfile(profile)
|
||||
profileManager.reload(profile.id)
|
||||
h.sendEmptyMessage(0)
|
||||
}, 600)
|
||||
}
|
||||
|
||||
|
||||
@@ -38,10 +38,9 @@
|
||||
*/
|
||||
package com.github.shadowsocks
|
||||
|
||||
import java.io.{ByteArrayInputStream, ByteArrayOutputStream, FileOutputStream, IOException, InputStream, OutputStream}
|
||||
import java.util
|
||||
import java.io.{OutputStream, InputStream, ByteArrayInputStream, ByteArrayOutputStream, IOException, FileOutputStream}
|
||||
import java.util.Locale
|
||||
import java.lang.Math
|
||||
|
||||
import android.app.backup.BackupManager
|
||||
import android.app.{Activity, AlertDialog, ProgressDialog}
|
||||
@@ -52,8 +51,8 @@ import android.graphics.{Bitmap, Color, Typeface}
|
||||
import android.net.{Uri, VpnService}
|
||||
import android.os._
|
||||
import android.preference._
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.util.{DisplayMetrics, Log}
|
||||
import android.view.View.OnLongClickListener
|
||||
import android.view._
|
||||
import android.webkit.{WebView, WebViewClient}
|
||||
import android.widget._
|
||||
@@ -65,15 +64,15 @@ import com.github.shadowsocks.utils._
|
||||
import com.google.android.gms.ads.{AdRequest, AdSize, AdView}
|
||||
import com.google.android.gms.analytics.HitBuilders
|
||||
import com.google.zxing.integration.android.IntentIntegrator
|
||||
import com.nostra13.universalimageloader.core.download.BaseImageDownloader
|
||||
import net.simonvt.menudrawer.MenuDrawer
|
||||
import com.joanzapata.android.iconify.Iconify
|
||||
import com.joanzapata.android.iconify.Iconify.IconValue
|
||||
import com.joanzapata.android.iconify.IconDrawable
|
||||
import com.joanzapata.android.iconify.Iconify.IconValue
|
||||
import com.nostra13.universalimageloader.core.download.BaseImageDownloader
|
||||
import net.glxn.qrgen.android.QRCode
|
||||
import net.simonvt.menudrawer.MenuDrawer
|
||||
|
||||
import scala.collection.mutable.{ArrayBuffer, ListBuffer}
|
||||
import scala.concurrent.ops._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.Future
|
||||
|
||||
class ProfileIconDownloader(context: Context, connectTimeout: Int, readTimeout: Int)
|
||||
extends BaseImageDownloader(context, connectTimeout, readTimeout) {
|
||||
@@ -127,7 +126,7 @@ object Shadowsocks {
|
||||
val PROXY_PREFS = Array(Key.profileName, Key.proxy, Key.remotePort, Key.localPort, Key.sitekey,
|
||||
Key.encMethod)
|
||||
val FEATRUE_PREFS = Array(Key.route, Key.isGlobalProxy, Key.proxyedApps,
|
||||
Key.isUdpDns, Key.isAutoConnect)
|
||||
Key.isUdpDns, Key.isAuth, Key.isIpv6, Key.isAutoConnect)
|
||||
|
||||
val EXECUTABLES = Array(Executable.PDNSD, Executable.REDSOCKS, Executable.SS_TUNNEL, Executable.SS_LOCAL, Executable.TUN2SOCKS)
|
||||
|
||||
@@ -166,6 +165,8 @@ object Shadowsocks {
|
||||
case Key.route => updateListPreference(pref, profile.route)
|
||||
case Key.isGlobalProxy => updateCheckBoxPreference(pref, profile.global)
|
||||
case Key.isUdpDns => updateCheckBoxPreference(pref, profile.udpdns)
|
||||
case Key.isAuth => updateCheckBoxPreference(pref, profile.auth)
|
||||
case Key.isIpv6 => updateCheckBoxPreference(pref, profile.ipv6)
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
@@ -222,7 +223,7 @@ class Shadowsocks
|
||||
|
||||
if (!status.getBoolean(getVersionName, false)) {
|
||||
status.edit.putBoolean(getVersionName, true).commit()
|
||||
recovery();
|
||||
recovery()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +249,7 @@ class Shadowsocks
|
||||
|
||||
private lazy val application = getApplication.asInstanceOf[ShadowsocksApplication]
|
||||
|
||||
var handler: Handler = null
|
||||
var handler = new Handler()
|
||||
|
||||
def isSinglePane: Boolean = {
|
||||
if (singlePane == -1) {
|
||||
@@ -268,11 +269,7 @@ class Shadowsocks
|
||||
switchButton.setChecked(checked)
|
||||
if (switchButton.isEnabled) {
|
||||
switchButton.setEnabled(false)
|
||||
handler.postDelayed(new Runnable {
|
||||
override def run() {
|
||||
switchButton.setEnabled(true)
|
||||
}
|
||||
}, 1000)
|
||||
handler.postDelayed(() => switchButton.setEnabled(true), 1000)
|
||||
}
|
||||
switchButton.setOnCheckedChangeListener(this)
|
||||
}
|
||||
@@ -394,7 +391,7 @@ class Shadowsocks
|
||||
changeSwitch(checked = false)
|
||||
}
|
||||
|
||||
def isReady(): Boolean = {
|
||||
def isReady: Boolean = {
|
||||
if (!checkText(Key.proxy)) return false
|
||||
if (!checkText(Key.sitekey)) return false
|
||||
if (!checkNumber(Key.localPort, low = false)) return false
|
||||
@@ -405,7 +402,7 @@ class Shadowsocks
|
||||
|
||||
def prepareStartService() {
|
||||
showProgress(R.string.connecting)
|
||||
spawn {
|
||||
Future {
|
||||
if (isVpnEnabled) {
|
||||
val intent = VpnService.prepare(this)
|
||||
if (intent != null) {
|
||||
@@ -432,11 +429,7 @@ class Shadowsocks
|
||||
}
|
||||
if (switchButton.isEnabled) {
|
||||
switchButton.setEnabled(false)
|
||||
handler.postDelayed(new Runnable {
|
||||
override def run() {
|
||||
switchButton.setEnabled(true)
|
||||
}
|
||||
}, 1000)
|
||||
handler.postDelayed(() => switchButton.setEnabled(true), 1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -477,8 +470,6 @@ class Shadowsocks
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
handler = new Handler()
|
||||
|
||||
addPreferencesFromResource(R.xml.pref_all)
|
||||
|
||||
// Update the profile
|
||||
@@ -522,28 +513,26 @@ class Shadowsocks
|
||||
getActionBar.setDisplayShowTitleEnabled(false)
|
||||
getActionBar.setDisplayShowCustomEnabled(true)
|
||||
if (Utils.isLollipopOrAbove) {
|
||||
getWindow.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
||||
getWindow.setStatusBarColor(getResources().getColor(R.color.grey3));
|
||||
getWindow.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
|
||||
getWindow.setStatusBarColor(ContextCompat.getColor(this, R.color.grey3))
|
||||
getActionBar.setDisplayHomeAsUpEnabled(true)
|
||||
getActionBar.setHomeAsUpIndicator(R.drawable.ic_drawer)
|
||||
} else {
|
||||
getActionBar.setIcon(R.drawable.ic_stat_shadowsocks)
|
||||
}
|
||||
title.setOnLongClickListener(new OnLongClickListener {
|
||||
override def onLongClick(v: View): Boolean = {
|
||||
if (Utils.isLollipopOrAbove && bgService != null
|
||||
&& (bgService.getState == State.INIT || bgService.getState == State.STOPPED)) {
|
||||
val natEnabled = status.getBoolean(Key.isNAT, false)
|
||||
status.edit().putBoolean(Key.isNAT, !natEnabled).commit()
|
||||
if (!natEnabled) {
|
||||
Toast.makeText(getBaseContext, R.string.enable_nat, Toast.LENGTH_LONG).show()
|
||||
} else {
|
||||
Toast.makeText(getBaseContext, R.string.disable_nat, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
true
|
||||
title.setOnLongClickListener((v: View) => {
|
||||
if (Utils.isLollipopOrAbove && bgService != null
|
||||
&& (bgService.getState == State.INIT || bgService.getState == State.STOPPED)) {
|
||||
val natEnabled = status.getBoolean(Key.isNAT, false)
|
||||
status.edit().putBoolean(Key.isNAT, !natEnabled).commit()
|
||||
if (!natEnabled) {
|
||||
Toast.makeText(getBaseContext, R.string.enable_nat, Toast.LENGTH_LONG).show()
|
||||
} else {
|
||||
false
|
||||
Toast.makeText(getBaseContext, R.string.disable_nat, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
|
||||
@@ -551,13 +540,11 @@ class Shadowsocks
|
||||
registerReceiver(preferenceReceiver, new IntentFilter(Action.UPDATE_PREFS))
|
||||
|
||||
// Bind to the service
|
||||
spawn {
|
||||
Future {
|
||||
val isRoot = (!Utils.isLollipopOrAbove || status.getBoolean(Key.isNAT, false)) && Console.isRoot
|
||||
handler.post(new Runnable {
|
||||
override def run() {
|
||||
status.edit.putBoolean(Key.isRoot, isRoot).commit()
|
||||
attachService()
|
||||
}
|
||||
handler.post(() => {
|
||||
status.edit.putBoolean(Key.isRoot, isRoot).commit()
|
||||
attachService()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -613,29 +600,23 @@ class Shadowsocks
|
||||
val builder = new AlertDialog.Builder(this)
|
||||
builder
|
||||
.setTitle(R.string.add_profile)
|
||||
.setItems(R.array.add_profile_methods, new DialogInterface.OnClickListener() {
|
||||
def onClick(dialog: DialogInterface, which: Int) {
|
||||
which match {
|
||||
case 0 =>
|
||||
dialog.dismiss()
|
||||
val h = showProgress(R.string.loading)
|
||||
h.postDelayed(new Runnable() {
|
||||
def run() {
|
||||
val integrator = new IntentIntegrator(Shadowsocks.this)
|
||||
val list = new java.util.ArrayList(IntentIntegrator.TARGET_ALL_KNOWN)
|
||||
list.add("tw.com.quickmark")
|
||||
integrator.setTargetApplications(list)
|
||||
integrator.initiateScan()
|
||||
h.sendEmptyMessage(0)
|
||||
}
|
||||
}, 600)
|
||||
case 1 =>
|
||||
dialog.dismiss()
|
||||
addProfile(id)
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
})
|
||||
.setItems(R.array.add_profile_methods, ((dialog: DialogInterface, which: Int) => which match {
|
||||
case 0 =>
|
||||
dialog.dismiss()
|
||||
val h = showProgress(R.string.loading)
|
||||
h.postDelayed(() => {
|
||||
val integrator = new IntentIntegrator(Shadowsocks.this)
|
||||
val list = new java.util.ArrayList(IntentIntegrator.TARGET_ALL_KNOWN)
|
||||
list.add("tw.com.quickmark")
|
||||
integrator.setTargetApplications(list)
|
||||
integrator.initiateScan()
|
||||
h.sendEmptyMessage(0)
|
||||
}, 600)
|
||||
case 1 =>
|
||||
dialog.dismiss()
|
||||
addProfile(id)
|
||||
case _ =>
|
||||
}): DialogInterface.OnClickListener)
|
||||
builder.create().show()
|
||||
}
|
||||
|
||||
@@ -644,17 +625,15 @@ class Shadowsocks
|
||||
|
||||
val h = showProgress(R.string.loading)
|
||||
|
||||
handler.postDelayed(new Runnable {
|
||||
def run() {
|
||||
currentProfile = {
|
||||
profileManager.getProfile(settings.getInt(Key.profileId, -1)) getOrElse currentProfile
|
||||
}
|
||||
menuAdapter.updateList(getMenuList, currentProfile.id)
|
||||
|
||||
updatePreferenceScreen()
|
||||
|
||||
h.sendEmptyMessage(0)
|
||||
handler.postDelayed(() => {
|
||||
currentProfile = {
|
||||
profileManager.getProfile(settings.getInt(Key.profileId, -1)) getOrElse currentProfile
|
||||
}
|
||||
menuAdapter.updateList(getMenuList, currentProfile.id)
|
||||
|
||||
updatePreferenceScreen()
|
||||
|
||||
h.sendEmptyMessage(0)
|
||||
}, 600)
|
||||
}
|
||||
|
||||
@@ -663,17 +642,15 @@ class Shadowsocks
|
||||
|
||||
val h = showProgress(R.string.loading)
|
||||
|
||||
handler.postDelayed(new Runnable {
|
||||
def run() {
|
||||
currentProfile = profile
|
||||
profileManager.createOrUpdateProfile(currentProfile)
|
||||
profileManager.reload(currentProfile.id)
|
||||
menuAdapter.updateList(getMenuList, currentProfile.id)
|
||||
handler.postDelayed(() => {
|
||||
currentProfile = profile
|
||||
profileManager.createOrUpdateProfile(currentProfile)
|
||||
profileManager.reload(currentProfile.id)
|
||||
menuAdapter.updateList(getMenuList, currentProfile.id)
|
||||
|
||||
updatePreferenceScreen()
|
||||
updatePreferenceScreen()
|
||||
|
||||
h.sendEmptyMessage(0)
|
||||
}
|
||||
h.sendEmptyMessage(0)
|
||||
}, 600)
|
||||
}
|
||||
|
||||
@@ -682,16 +659,14 @@ class Shadowsocks
|
||||
|
||||
val h = showProgress(R.string.loading)
|
||||
|
||||
handler.postDelayed(new Runnable {
|
||||
def run() {
|
||||
currentProfile = profileManager.reload(id)
|
||||
profileManager.save()
|
||||
menuAdapter.updateList(getMenuList, currentProfile.id)
|
||||
handler.postDelayed(() => {
|
||||
currentProfile = profileManager.reload(id)
|
||||
profileManager.save()
|
||||
menuAdapter.updateList(getMenuList, currentProfile.id)
|
||||
|
||||
updatePreferenceScreen()
|
||||
updatePreferenceScreen()
|
||||
|
||||
h.sendEmptyMessage(0)
|
||||
}
|
||||
h.sendEmptyMessage(0)
|
||||
}, 600)
|
||||
}
|
||||
|
||||
@@ -700,16 +675,14 @@ class Shadowsocks
|
||||
|
||||
val h = showProgress(R.string.loading)
|
||||
|
||||
handler.postDelayed(new Runnable {
|
||||
def run() {
|
||||
currentProfile = profileManager.reload(id)
|
||||
menuAdapter.setActiveId(id)
|
||||
menuAdapter.notifyDataSetChanged()
|
||||
handler.postDelayed(() => {
|
||||
currentProfile = profileManager.reload(id)
|
||||
menuAdapter.setActiveId(id)
|
||||
menuAdapter.notifyDataSetChanged()
|
||||
|
||||
updatePreferenceScreen()
|
||||
updatePreferenceScreen()
|
||||
|
||||
h.sendEmptyMessage(0)
|
||||
}
|
||||
h.sendEmptyMessage(0)
|
||||
}, 600)
|
||||
}
|
||||
|
||||
@@ -718,20 +691,18 @@ class Shadowsocks
|
||||
|
||||
val profile = profileManager.getProfile(id)
|
||||
|
||||
if (!profile.isDefined) return false
|
||||
if (profile.isEmpty) return false
|
||||
|
||||
new AlertDialog.Builder(this)
|
||||
.setMessage(String.format(Locale.ENGLISH, getString(R.string.remove_profile), profile.get.name))
|
||||
.setCancelable(false)
|
||||
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
|
||||
override def onClick(dialog: DialogInterface, i: Int) = dialog.cancel()
|
||||
})
|
||||
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
||||
override def onClick(dialog: DialogInterface, i: Int) {
|
||||
.setNegativeButton(R.string.no,
|
||||
((dialog: DialogInterface, i: Int) => dialog.cancel()): DialogInterface.OnClickListener)
|
||||
.setPositiveButton(R.string.yes, ((dialog: DialogInterface, i: Int) => {
|
||||
profileManager.delProfile(id)
|
||||
val profileId = {
|
||||
val profiles = profileManager.getAllProfiles.getOrElse(List[Profile]())
|
||||
if (profiles.isEmpty) -1 else profiles(0).id
|
||||
if (profiles.isEmpty) -1 else profiles.head.id
|
||||
}
|
||||
currentProfile = profileManager.load(profileId)
|
||||
menuAdapter.updateList(getMenuList, currentProfile.id)
|
||||
@@ -739,8 +710,7 @@ class Shadowsocks
|
||||
updatePreferenceScreen()
|
||||
|
||||
dialog.dismiss()
|
||||
}
|
||||
})
|
||||
}): DialogInterface.OnClickListener)
|
||||
.create()
|
||||
.show()
|
||||
|
||||
@@ -899,10 +869,7 @@ class Shadowsocks
|
||||
deattachService()
|
||||
unregisterReceiver(preferenceReceiver)
|
||||
new BackupManager(this).dataChanged()
|
||||
if (handler != null) {
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
handler = null
|
||||
}
|
||||
handler.removeCallbacksAndMessages(null)
|
||||
}
|
||||
|
||||
def copyToSystem() {
|
||||
@@ -937,16 +904,14 @@ class Shadowsocks
|
||||
private def recovery() {
|
||||
serviceStop()
|
||||
val h = showProgress(R.string.recovering)
|
||||
spawn {
|
||||
Future {
|
||||
reset()
|
||||
h.sendEmptyMessage(0)
|
||||
}
|
||||
}
|
||||
|
||||
private def dp2px(dp: Int): Int = {
|
||||
val displayMetrics = getBaseContext.getResources.getDisplayMetrics()
|
||||
Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT))
|
||||
}
|
||||
private def dp2px(dp: Int): Int =
|
||||
Math.round(dp * (getBaseContext.getResources.getDisplayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT))
|
||||
|
||||
private def showQrCode() {
|
||||
val image = new ImageView(this)
|
||||
@@ -958,11 +923,8 @@ class Shadowsocks
|
||||
|
||||
new AlertDialog.Builder(this)
|
||||
.setCancelable(true)
|
||||
.setNegativeButton(getString(R.string.close), new DialogInterface.OnClickListener() {
|
||||
override def onClick(dialog: DialogInterface, id: Int) {
|
||||
dialog.cancel()
|
||||
}
|
||||
})
|
||||
.setNegativeButton(getString(R.string.close),
|
||||
((dialog: DialogInterface, id: Int) => dialog.cancel()): DialogInterface.OnClickListener)
|
||||
.setView(image)
|
||||
.create()
|
||||
.show()
|
||||
@@ -970,7 +932,7 @@ class Shadowsocks
|
||||
|
||||
private def flushDnsCache() {
|
||||
val h = showProgress(R.string.flushing)
|
||||
spawn {
|
||||
Future {
|
||||
Utils.toggleAirplaneMode(getBaseContext)
|
||||
h.sendEmptyMessage(0)
|
||||
}
|
||||
@@ -1073,11 +1035,8 @@ class Shadowsocks
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(getString(R.string.about_title).formatLocal(Locale.ENGLISH, versionName))
|
||||
.setCancelable(false)
|
||||
.setNegativeButton(getString(R.string.ok_iknow), new DialogInterface.OnClickListener() {
|
||||
override def onClick(dialog: DialogInterface, id: Int) {
|
||||
dialog.cancel()
|
||||
}
|
||||
})
|
||||
.setNegativeButton(getString(R.string.ok_iknow),
|
||||
((dialog: DialogInterface, id: Int) => dialog.cancel()): DialogInterface.OnClickListener)
|
||||
.setView(web)
|
||||
.create()
|
||||
.show()
|
||||
@@ -1092,46 +1051,42 @@ class Shadowsocks
|
||||
}
|
||||
|
||||
def onStateChanged(s: Int, m: String) {
|
||||
handler.post(new Runnable {
|
||||
override def run() {
|
||||
if (state != s) {
|
||||
state = s
|
||||
state match {
|
||||
case State.CONNECTING =>
|
||||
if (progressDialog == null) {
|
||||
progressDialog = ProgressDialog
|
||||
.show(Shadowsocks.this, "", getString(R.string.connecting), true, true)
|
||||
progressTag = R.string.connecting
|
||||
}
|
||||
setPreferenceEnabled(enabled = false)
|
||||
case State.CONNECTED =>
|
||||
if (progressTag == R.string.connecting) {
|
||||
clearDialog()
|
||||
}
|
||||
changeSwitch(checked = true)
|
||||
setPreferenceEnabled(enabled = false)
|
||||
case State.STOPPED =>
|
||||
if (progressTag == R.string.stopping) {
|
||||
clearDialog()
|
||||
}
|
||||
changeSwitch(checked = false)
|
||||
if (m != null) {
|
||||
new SnackBar.Builder(Shadowsocks.this)
|
||||
.withMessage(getString(R.string.vpn_error).formatLocal(Locale.ENGLISH, m))
|
||||
.withActionMessageId(R.string.error)
|
||||
.withStyle(SnackBar.Style.ALERT)
|
||||
.withDuration(SnackBar.LONG_SNACK)
|
||||
.show()
|
||||
}
|
||||
setPreferenceEnabled(enabled = true)
|
||||
case State.STOPPING =>
|
||||
if (progressDialog == null) {
|
||||
progressDialog = ProgressDialog
|
||||
.show(Shadowsocks.this, "", getString(R.string.stopping), true, true)
|
||||
progressTag = R.string.stopping
|
||||
}
|
||||
handler.post(() => if (state != s) {
|
||||
state = s
|
||||
state match {
|
||||
case State.CONNECTING =>
|
||||
if (progressDialog == null) {
|
||||
progressDialog = ProgressDialog
|
||||
.show(Shadowsocks.this, "", getString(R.string.connecting), true, true)
|
||||
progressTag = R.string.connecting
|
||||
}
|
||||
setPreferenceEnabled(enabled = false)
|
||||
case State.CONNECTED =>
|
||||
if (progressTag == R.string.connecting) {
|
||||
clearDialog()
|
||||
}
|
||||
changeSwitch(checked = true)
|
||||
setPreferenceEnabled(enabled = false)
|
||||
case State.STOPPED =>
|
||||
if (progressTag == R.string.stopping || progressTag == R.string.connecting) {
|
||||
clearDialog()
|
||||
}
|
||||
changeSwitch(checked = false)
|
||||
if (m != null) {
|
||||
new SnackBar.Builder(Shadowsocks.this)
|
||||
.withMessage(getString(R.string.vpn_error).formatLocal(Locale.ENGLISH, m))
|
||||
.withActionMessageId(R.string.error)
|
||||
.withStyle(SnackBar.Style.ALERT)
|
||||
.withDuration(SnackBar.LONG_SNACK)
|
||||
.show()
|
||||
}
|
||||
setPreferenceEnabled(enabled = true)
|
||||
case State.STOPPING =>
|
||||
if (progressDialog == null) {
|
||||
progressDialog = ProgressDialog
|
||||
.show(Shadowsocks.this, "", getString(R.string.stopping), true, true)
|
||||
progressTag = R.string.stopping
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -47,7 +47,6 @@ import com.github.shadowsocks.database.DBHelper
|
||||
import com.github.shadowsocks.utils.Utils
|
||||
import com.google.android.gms.analytics.GoogleAnalytics
|
||||
import com.google.android.gms.common.api.ResultCallback
|
||||
import com.google.android.gms.tagmanager.Container.FunctionCallMacroCallback
|
||||
import com.google.android.gms.tagmanager.{ContainerHolder, TagManager}
|
||||
|
||||
class ShadowsocksApplication extends Application {
|
||||
@@ -66,14 +65,13 @@ class ShadowsocksApplication extends Application {
|
||||
}
|
||||
containerHolder = holder
|
||||
val container = holder.getContainer
|
||||
container.registerFunctionCallMacroCallback(SIG_FUNC, new FunctionCallMacroCallback {
|
||||
override def getValue(functionName: String, parameters: util.Map[String, AnyRef]): AnyRef = {
|
||||
container.registerFunctionCallMacroCallback(SIG_FUNC,
|
||||
(functionName: String, parameters: util.Map[String, AnyRef]) => {
|
||||
if (functionName == SIG_FUNC) {
|
||||
Utils.getSignature(getApplicationContext)
|
||||
}
|
||||
null
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
pending.setResultCallback(callback, 2, TimeUnit.SECONDS)
|
||||
|
||||
@@ -41,6 +41,7 @@ package com.github.shadowsocks
|
||||
|
||||
import java.io.File
|
||||
import java.lang.reflect.{InvocationTargetException, Method}
|
||||
import java.net.{Inet6Address, InetAddress}
|
||||
import java.util.Locale
|
||||
|
||||
import android.app._
|
||||
@@ -54,11 +55,11 @@ import android.widget.Toast
|
||||
import com.github.shadowsocks.aidl.Config
|
||||
import com.github.shadowsocks.utils._
|
||||
import com.google.android.gms.analytics.HitBuilders
|
||||
import org.apache.http.conn.util.InetAddressUtils
|
||||
|
||||
import scala.collection._
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
import scala.concurrent.ops._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.Future
|
||||
|
||||
class ShadowsocksNatService extends Service with BaseService {
|
||||
|
||||
@@ -68,25 +69,13 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
val CMD_IPTABLES_DNAT_ADD_SOCKS = " -t nat -A OUTPUT -p tcp " +
|
||||
"-j DNAT --to-destination 127.0.0.1:8123"
|
||||
|
||||
private val mStartForegroundSignature = Array[Class[_]](classOf[Int], classOf[Notification])
|
||||
private val mStopForegroundSignature = Array[Class[_]](classOf[Boolean])
|
||||
private val mSetForegroundSignature = Array[Class[_]](classOf[Boolean])
|
||||
private val mSetForegroundArgs = new Array[AnyRef](1)
|
||||
private val mStartForegroundArgs = new Array[AnyRef](2)
|
||||
private val mStopForegroundArgs = new Array[AnyRef](1)
|
||||
|
||||
var lockReceiver: BroadcastReceiver = null
|
||||
var closeReceiver: BroadcastReceiver = null
|
||||
var connReceiver: BroadcastReceiver = null
|
||||
var notificationManager: NotificationManager = null
|
||||
var config: Config = null
|
||||
var apps: Array[ProxiedApp] = null
|
||||
val myUid = Process.myUid()
|
||||
|
||||
private var mSetForeground: Method = null
|
||||
private var mStartForeground: Method = null
|
||||
private var mStopForeground: Method = null
|
||||
|
||||
private lazy val application = getApplication.asInstanceOf[ShadowsocksApplication]
|
||||
|
||||
private val dnsAddressCache = new SparseArray[String]
|
||||
@@ -172,11 +161,7 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
|
||||
def initConnectionReceiver() {
|
||||
val filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
|
||||
connReceiver = new BroadcastReceiver {
|
||||
override def onReceive(context: Context, intent: Intent) = {
|
||||
setupDns()
|
||||
}
|
||||
}
|
||||
connReceiver = (context: Context, intent: Intent) => setupDns()
|
||||
registerReceiver(connReceiver, filter)
|
||||
}
|
||||
|
||||
@@ -193,7 +178,7 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
|
||||
val conf = ConfigUtils
|
||||
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, config.proxy, config.remotePort, config.localPort,
|
||||
config.sitekey, config.encMethod, 10)
|
||||
config.sitekey, config.encMethod, 600)
|
||||
ConfigUtils.printToFile(new File(Path.BASE + "ss-local-nat.conf"))(p => {
|
||||
p.println(conf)
|
||||
})
|
||||
@@ -205,6 +190,8 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
, "-c" , Path.BASE + "ss-local-nat.conf"
|
||||
, "-f" , Path.BASE + "ss-local-nat.pid")
|
||||
|
||||
if (config.isAuth) cmd += "-A"
|
||||
|
||||
if (config.route != Route.ALL) {
|
||||
cmd += "--acl"
|
||||
cmd += (Path.BASE + "acl.list")
|
||||
@@ -233,6 +220,8 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
|
||||
cmd += ("-l" , "8153")
|
||||
|
||||
if (config.isAuth) cmd += "-A"
|
||||
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" "))
|
||||
|
||||
Console.runCommand(cmd.mkString(" "))
|
||||
@@ -254,6 +243,8 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
, "-c" , Path.BASE + "ss-tunnel-nat.conf"
|
||||
, "-f" , Path.BASE + "ss-tunnel-nat.pid")
|
||||
|
||||
if (config.isAuth) cmdBuf += "-A"
|
||||
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, cmdBuf.mkString(" "))
|
||||
Console.runCommand(cmdBuf.mkString(" "))
|
||||
}
|
||||
@@ -265,10 +256,10 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
val reject = ConfigUtils.getRejectList(getContext, application)
|
||||
val blackList = ConfigUtils.getBlackList(getContext, application)
|
||||
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, "127.0.0.1", 8153,
|
||||
Path.BASE + "pdnsd-nat.pid", reject, blackList, 8163)
|
||||
Path.BASE + "pdnsd-nat.pid", reject, blackList, 8163, "")
|
||||
} else {
|
||||
ConfigUtils.PDNSD_LOCAL.formatLocal(Locale.ENGLISH, "127.0.0.1", 8153,
|
||||
Path.BASE + "pdnsd-nat.pid", 8163)
|
||||
Path.BASE + "pdnsd-nat.pid", 8163, "")
|
||||
}
|
||||
|
||||
ConfigUtils.printToFile(new File(Path.BASE + "pdnsd-nat.conf"))(p => {
|
||||
@@ -318,17 +309,6 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
true
|
||||
}
|
||||
|
||||
def invokeMethod(method: Method, args: Array[AnyRef]) {
|
||||
try {
|
||||
method.invoke(this, mStartForegroundArgs: _*)
|
||||
} catch {
|
||||
case e: InvocationTargetException =>
|
||||
Log.w(TAG, "Unable to invoke method", e)
|
||||
case e: IllegalAccessException =>
|
||||
Log.w(TAG, "Unable to invoke method", e)
|
||||
}
|
||||
}
|
||||
|
||||
def notifyForegroundAlert(title: String, info: String, visible: Boolean) {
|
||||
val openIntent = new Intent(this, classOf[Shadowsocks])
|
||||
openIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
|
||||
@@ -352,7 +332,7 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
else
|
||||
builder.setPriority(NotificationCompat.PRIORITY_MIN)
|
||||
|
||||
startForegroundCompat(1, builder.build)
|
||||
startForeground(1, builder.build)
|
||||
}
|
||||
|
||||
def onBind(intent: Intent): IBinder = {
|
||||
@@ -366,29 +346,7 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
|
||||
override def onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
ConfigUtils.refresh(this)
|
||||
|
||||
notificationManager = this
|
||||
.getSystemService(Context.NOTIFICATION_SERVICE)
|
||||
.asInstanceOf[NotificationManager]
|
||||
try {
|
||||
mStartForeground = getClass.getMethod("startForeground", mStartForegroundSignature: _*)
|
||||
mStopForeground = getClass.getMethod("stopForeground", mStopForegroundSignature: _*)
|
||||
} catch {
|
||||
case e: NoSuchMethodException =>
|
||||
mStartForeground = {
|
||||
mStopForeground = null
|
||||
mStopForeground
|
||||
}
|
||||
}
|
||||
try {
|
||||
mSetForeground = getClass.getMethod("setForeground", mSetForegroundSignature: _*)
|
||||
} catch {
|
||||
case e: NoSuchMethodException =>
|
||||
throw new IllegalStateException(
|
||||
"OS doesn't have Service.startForeground OR Service.setForeground!")
|
||||
}
|
||||
}
|
||||
|
||||
def killProcesses() {
|
||||
@@ -424,7 +382,7 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
init_sb.append(Utils.getIptables + " -t nat -F OUTPUT")
|
||||
|
||||
val cmd_bypass = Utils.getIptables + CMD_IPTABLES_RETURN
|
||||
if (!InetAddressUtils.isIPv6Address(config.proxy.toUpperCase)) {
|
||||
if (!InetAddress.getByName(config.proxy.toUpperCase).isInstanceOf[Inet6Address]) {
|
||||
init_sb.append(cmd_bypass.replace("-p tcp -d 0.0.0.0", "-d " + config.proxy))
|
||||
}
|
||||
init_sb.append(cmd_bypass.replace("-p tcp -d 0.0.0.0", "-d 127.0.0.1"))
|
||||
@@ -459,44 +417,6 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
Console.runRootCommand(http_sb.toArray)
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a wrapper around the new startForeground method, using the older
|
||||
* APIs if it is not available.
|
||||
*/
|
||||
def startForegroundCompat(id: Int, notification: Notification) {
|
||||
if (mStartForeground != null) {
|
||||
mStartForegroundArgs(0) = int2Integer(id)
|
||||
mStartForegroundArgs(1) = notification
|
||||
invokeMethod(mStartForeground, mStartForegroundArgs)
|
||||
return
|
||||
}
|
||||
mSetForegroundArgs(0) = boolean2Boolean(x = true)
|
||||
invokeMethod(mSetForeground, mSetForegroundArgs)
|
||||
notificationManager.notify(id, notification)
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a wrapper around the new stopForeground method, using the older
|
||||
* APIs if it is not available.
|
||||
*/
|
||||
def stopForegroundCompat(id: Int) {
|
||||
if (mStopForeground != null) {
|
||||
mStopForegroundArgs(0) = boolean2Boolean(x = true)
|
||||
try {
|
||||
mStopForeground.invoke(this, mStopForegroundArgs: _*)
|
||||
} catch {
|
||||
case e: InvocationTargetException =>
|
||||
Log.w(TAG, "Unable to invoke stopForeground", e)
|
||||
case e: IllegalAccessException =>
|
||||
Log.w(TAG, "Unable to invoke stopForeground", e)
|
||||
}
|
||||
return
|
||||
}
|
||||
notificationManager.cancel(id)
|
||||
mSetForegroundArgs(0) = boolean2Boolean(x = false)
|
||||
invokeMethod(mSetForeground, mSetForegroundArgs)
|
||||
}
|
||||
|
||||
override def startRunner(c: Config) {
|
||||
|
||||
config = c
|
||||
@@ -505,11 +425,9 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
val filter = new IntentFilter()
|
||||
filter.addAction(Intent.ACTION_SHUTDOWN)
|
||||
filter.addAction(Action.CLOSE)
|
||||
closeReceiver = new BroadcastReceiver() {
|
||||
def onReceive(context: Context, intent: Intent) {
|
||||
Toast.makeText(context, R.string.stopping, Toast.LENGTH_SHORT).show()
|
||||
stopRunner()
|
||||
}
|
||||
closeReceiver = (context: Context, intent: Intent) => {
|
||||
Toast.makeText(context, R.string.stopping, Toast.LENGTH_SHORT).show()
|
||||
stopRunner()
|
||||
}
|
||||
registerReceiver(closeReceiver, filter)
|
||||
|
||||
@@ -518,26 +436,22 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
screenFilter.addAction(Intent.ACTION_SCREEN_ON)
|
||||
screenFilter.addAction(Intent.ACTION_SCREEN_OFF)
|
||||
screenFilter.addAction(Intent.ACTION_USER_PRESENT)
|
||||
lockReceiver = new BroadcastReceiver() {
|
||||
def onReceive(context: Context, intent: Intent) {
|
||||
if (getState == State.CONNECTED) {
|
||||
val action = intent.getAction
|
||||
if (action == Intent.ACTION_SCREEN_OFF) {
|
||||
notifyForegroundAlert(getString(R.string.forward_success),
|
||||
getString(R.string.service_running).formatLocal(Locale.ENGLISH, config.profileName), false)
|
||||
} else if (action == Intent.ACTION_SCREEN_ON) {
|
||||
val keyGuard = getSystemService(Context.KEYGUARD_SERVICE).asInstanceOf[KeyguardManager]
|
||||
if (!keyGuard.inKeyguardRestrictedInputMode) {
|
||||
notifyForegroundAlert(getString(R.string.forward_success),
|
||||
getString(R.string.service_running).formatLocal(Locale.ENGLISH, config.profileName), true)
|
||||
}
|
||||
} else if (action == Intent.ACTION_USER_PRESENT) {
|
||||
notifyForegroundAlert(getString(R.string.forward_success),
|
||||
getString(R.string.service_running).formatLocal(Locale.ENGLISH, config.profileName), true)
|
||||
}
|
||||
}
|
||||
lockReceiver = (context: Context, intent: Intent) => if (getState == State.CONNECTED) {
|
||||
val action = intent.getAction
|
||||
if (action == Intent.ACTION_SCREEN_OFF) {
|
||||
notifyForegroundAlert(getString(R.string.forward_success),
|
||||
getString(R.string.service_running).formatLocal(Locale.ENGLISH, config.profileName), false)
|
||||
} else if (action == Intent.ACTION_SCREEN_ON) {
|
||||
val keyGuard = getSystemService(Context.KEYGUARD_SERVICE).asInstanceOf[KeyguardManager]
|
||||
if (!keyGuard.inKeyguardRestrictedInputMode) {
|
||||
notifyForegroundAlert(getString(R.string.forward_success),
|
||||
getString(R.string.service_running).formatLocal(Locale.ENGLISH, config.profileName), true)
|
||||
}
|
||||
} else if (action == Intent.ACTION_USER_PRESENT) {
|
||||
notifyForegroundAlert(getString(R.string.forward_success),
|
||||
getString(R.string.service_running).formatLocal(Locale.ENGLISH, config.profileName), true)
|
||||
}
|
||||
}
|
||||
registerReceiver(lockReceiver, screenFilter)
|
||||
}
|
||||
|
||||
@@ -550,7 +464,7 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
|
||||
changeState(State.CONNECTING)
|
||||
|
||||
spawn {
|
||||
Future {
|
||||
|
||||
if (config.proxy == "198.199.101.152") {
|
||||
val holder = application.containerHolder
|
||||
@@ -570,8 +484,7 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
killProcesses()
|
||||
|
||||
var resolved: Boolean = false
|
||||
if (!InetAddressUtils.isIPv4Address(config.proxy) &&
|
||||
!InetAddressUtils.isIPv6Address(config.proxy)) {
|
||||
if (!Utils.isNumeric(config.proxy)) {
|
||||
Utils.resolve(config.proxy, enableIPv6 = true) match {
|
||||
case Some(a) =>
|
||||
config.proxy = a
|
||||
@@ -631,7 +544,7 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
stopSelf()
|
||||
}
|
||||
|
||||
stopForegroundCompat(1)
|
||||
stopForeground(true)
|
||||
|
||||
// change the state
|
||||
changeState(State.STOPPED)
|
||||
|
||||
@@ -65,10 +65,15 @@ class ShadowsocksReceiver extends BroadcastReceiver {
|
||||
val isAutoConnect: Boolean = settings.getBoolean(Key.isAutoConnect, false)
|
||||
val isInstalled: Boolean = status.getBoolean(versionName, false)
|
||||
if (isAutoConnect && isInstalled) {
|
||||
val intent = new Intent(context, classOf[ShadowsocksRunnerActivity])
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
context.startActivity(intent)
|
||||
if (Utils.isLollipopOrAbove) {
|
||||
val intent = new Intent(context, classOf[ShadowsocksRunnerService])
|
||||
context.startService(intent)
|
||||
} else {
|
||||
val intent = new Intent(context, classOf[ShadowsocksRunnerActivity])
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,11 +57,7 @@ class ShadowsocksRunnerActivity extends Activity {
|
||||
val connection = new ServiceConnection {
|
||||
override def onServiceConnected(name: ComponentName, service: IBinder) {
|
||||
bgService = IShadowsocksService.Stub.asInterface(service)
|
||||
handler.postDelayed(new Runnable() {
|
||||
override def run() {
|
||||
if (bgService != null) startBackgroundService()
|
||||
}
|
||||
}, 1000)
|
||||
handler.postDelayed(() => if (bgService != null) startBackgroundService(), 1000)
|
||||
}
|
||||
override def onServiceDisconnected(name: ComponentName) {
|
||||
bgService = null
|
||||
@@ -122,11 +118,9 @@ class ShadowsocksRunnerActivity extends Activity {
|
||||
val locked = km.inKeyguardRestrictedInputMode
|
||||
if (locked) {
|
||||
val filter = new IntentFilter(Intent.ACTION_USER_PRESENT)
|
||||
receiver = new BroadcastReceiver() {
|
||||
override def onReceive(context: Context, intent: Intent) {
|
||||
if (intent.getAction == Intent.ACTION_USER_PRESENT) {
|
||||
attachService()
|
||||
}
|
||||
receiver = (context: Context, intent: Intent) => {
|
||||
if (intent.getAction == Intent.ACTION_USER_PRESENT) {
|
||||
attachService()
|
||||
}
|
||||
}
|
||||
registerReceiver(receiver, filter)
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Shadowsocks - A shadowsocks client for Android
|
||||
* Copyright (C) 2014 <max.c.lv@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* ___====-_ _-====___
|
||||
* _--^^^#####// \\#####^^^--_
|
||||
* _-^##########// ( ) \\##########^-_
|
||||
* -############// |\^^/| \\############-
|
||||
* _/############// (@::@) \\############\_
|
||||
* /#############(( \\// ))#############\
|
||||
* -###############\\ (oo) //###############-
|
||||
* -#################\\ / VV \ //#################-
|
||||
* -###################\\/ \//###################-
|
||||
* _#/|##########/\######( /\ )######/\##########|\#_
|
||||
* |/ |#/\#/\#/\/ \#/\##\ | | /##/\#/ \/\#/\#/\#| \|
|
||||
* ` |/ V V ` V \#\| | | |/#/ V ' V V \| '
|
||||
* ` ` ` ` / | | | | \ ' ' ' '
|
||||
* ( | | | | )
|
||||
* __\ | | | | /__
|
||||
* (vvv(VVV)(VVV)vvv)
|
||||
*
|
||||
* HERE BE DRAGONS
|
||||
*
|
||||
*/
|
||||
|
||||
package com.github.shadowsocks
|
||||
|
||||
import android.app.Service
|
||||
import android.content._
|
||||
import android.net.VpnService
|
||||
import android.os._
|
||||
import android.preference.PreferenceManager
|
||||
import com.github.shadowsocks.aidl.IShadowsocksService
|
||||
import com.github.shadowsocks.utils._
|
||||
|
||||
class ShadowsocksRunnerService extends Service {
|
||||
|
||||
private lazy val settings = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
private lazy val status = getSharedPreferences(Key.status, Context.MODE_PRIVATE)
|
||||
|
||||
val handler = new Handler()
|
||||
val connection = new ServiceConnection {
|
||||
override def onServiceConnected(name: ComponentName, service: IBinder) {
|
||||
bgService = IShadowsocksService.Stub.asInterface(service)
|
||||
handler.postDelayed(() => if (bgService != null) startBackgroundService(), 1000)
|
||||
}
|
||||
override def onServiceDisconnected(name: ComponentName) {
|
||||
bgService = null
|
||||
}
|
||||
}
|
||||
|
||||
// Variables
|
||||
var vpnEnabled = -1
|
||||
var bgService: IShadowsocksService = null
|
||||
|
||||
def isVpnEnabled: Boolean = {
|
||||
if (vpnEnabled < 0) {
|
||||
vpnEnabled = if ((!Utils.isLollipopOrAbove || status.getBoolean(Key.isNAT, false)) && Console.isRoot) {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
if (vpnEnabled == 1) true else false
|
||||
}
|
||||
|
||||
override def onBind(intent: Intent): IBinder = {
|
||||
null
|
||||
}
|
||||
|
||||
def startBackgroundService() {
|
||||
if (isVpnEnabled) {
|
||||
val intent = VpnService.prepare(ShadowsocksRunnerService.this)
|
||||
if (intent == null) {
|
||||
if (bgService != null) {
|
||||
bgService.start(ConfigUtils.load(settings))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bgService.start(ConfigUtils.load(settings))
|
||||
}
|
||||
stopSelf()
|
||||
}
|
||||
|
||||
def attachService() {
|
||||
if (bgService == null) {
|
||||
val s = if (!isVpnEnabled) classOf[ShadowsocksNatService] else classOf[ShadowsocksVpnService]
|
||||
val intent = new Intent(this, s)
|
||||
intent.setAction(Action.SERVICE)
|
||||
bindService(intent, connection, Context.BIND_AUTO_CREATE)
|
||||
startService(new Intent(this, s))
|
||||
}
|
||||
}
|
||||
|
||||
def deattachService() {
|
||||
if (bgService != null) {
|
||||
unbindService(connection)
|
||||
bgService = null
|
||||
}
|
||||
}
|
||||
|
||||
override def onCreate() {
|
||||
super.onCreate()
|
||||
attachService()
|
||||
}
|
||||
|
||||
override def onDestroy() {
|
||||
super.onDestroy()
|
||||
deattachService()
|
||||
}
|
||||
}
|
||||
@@ -47,17 +47,18 @@ import android.content._
|
||||
import android.content.pm.{PackageInfo, PackageManager}
|
||||
import android.net.VpnService
|
||||
import android.os._
|
||||
import android.support.v4.app.NotificationCompat
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import com.github.shadowsocks.aidl.Config
|
||||
import com.github.shadowsocks.utils._
|
||||
import com.google.android.gms.analytics.HitBuilders
|
||||
import org.apache.commons.net.util.SubnetUtils
|
||||
import org.apache.http.conn.util.InetAddressUtils
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.collection.mutable.ArrayBuffer
|
||||
import scala.concurrent.ops._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.Future
|
||||
|
||||
class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
|
||||
@@ -65,12 +66,12 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
val TAG = "ShadowsocksVpnService"
|
||||
val VPN_MTU = 1500
|
||||
val PRIVATE_VLAN = "26.26.26.%s"
|
||||
val PRIVATE_VLAN6 = "fdfe:dcba:9876::%s"
|
||||
var conn: ParcelFileDescriptor = null
|
||||
var notificationManager: NotificationManager = null
|
||||
var receiver: BroadcastReceiver = null
|
||||
var apps: Array[ProxiedApp] = null
|
||||
var config: Config = null
|
||||
var vpnThread: ShadowsocksVpnThread = null
|
||||
var closeReceiver: BroadcastReceiver = null
|
||||
|
||||
def isByass(net: SubnetUtils): Boolean = {
|
||||
val info = net.getInfo
|
||||
@@ -103,15 +104,34 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
null
|
||||
}
|
||||
|
||||
def notifyForegroundAlert(title: String, info: String, visible: Boolean) {
|
||||
val openIntent = new Intent(this, classOf[Shadowsocks])
|
||||
val contentIntent = PendingIntent.getActivity(this, 0, openIntent, 0)
|
||||
val closeIntent = new Intent(Action.CLOSE)
|
||||
val actionIntent = PendingIntent.getBroadcast(this, 0, closeIntent, 0)
|
||||
val builder = new NotificationCompat.Builder(this)
|
||||
|
||||
builder
|
||||
.setWhen(0)
|
||||
.setTicker(title)
|
||||
.setContentTitle(getString(R.string.app_name))
|
||||
.setContentText(info)
|
||||
.setContentIntent(contentIntent)
|
||||
.setSmallIcon(R.drawable.ic_stat_shadowsocks)
|
||||
.addAction(android.R.drawable.ic_menu_close_clear_cancel, getString(R.string.stop),
|
||||
actionIntent)
|
||||
|
||||
if (visible)
|
||||
builder.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
else
|
||||
builder.setPriority(NotificationCompat.PRIORITY_MIN)
|
||||
|
||||
startForeground(1, builder.build)
|
||||
}
|
||||
|
||||
override def onCreate() {
|
||||
|
||||
super.onCreate()
|
||||
|
||||
ConfigUtils.refresh(this)
|
||||
|
||||
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE)
|
||||
.asInstanceOf[NotificationManager]
|
||||
|
||||
}
|
||||
|
||||
override def onRevoke() {
|
||||
@@ -125,6 +145,8 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
vpnThread = null
|
||||
}
|
||||
|
||||
stopForeground(true)
|
||||
|
||||
// channge the state
|
||||
changeState(State.STOPPING)
|
||||
|
||||
@@ -149,10 +171,10 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
stopSelf()
|
||||
}
|
||||
|
||||
// clean up the context
|
||||
if (receiver != null) {
|
||||
unregisterReceiver(receiver)
|
||||
receiver = null
|
||||
// clean up recevier
|
||||
if (closeReceiver != null) {
|
||||
unregisterReceiver(closeReceiver)
|
||||
closeReceiver = null
|
||||
}
|
||||
|
||||
// channge the state
|
||||
@@ -189,6 +211,16 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
|
||||
config = c
|
||||
|
||||
// register close receiver
|
||||
val filter = new IntentFilter()
|
||||
filter.addAction(Intent.ACTION_SHUTDOWN)
|
||||
filter.addAction(Action.CLOSE)
|
||||
closeReceiver = (context: Context, intent: Intent) => {
|
||||
Toast.makeText(context, R.string.stopping, Toast.LENGTH_SHORT).show()
|
||||
stopRunner()
|
||||
}
|
||||
registerReceiver(closeReceiver, filter)
|
||||
|
||||
// ensure the VPNService is prepared
|
||||
if (VpnService.prepare(this) != null) {
|
||||
val i = new Intent(this, classOf[ShadowsocksRunnerActivity])
|
||||
@@ -204,20 +236,9 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
.setLabel(getVersionName)
|
||||
.build())
|
||||
|
||||
// register close receiver
|
||||
val filter = new IntentFilter()
|
||||
filter.addAction(Intent.ACTION_SHUTDOWN)
|
||||
receiver = new BroadcastReceiver {
|
||||
def onReceive(p1: Context, p2: Intent) {
|
||||
Toast.makeText(p1, R.string.stopping, Toast.LENGTH_SHORT)
|
||||
stopRunner()
|
||||
}
|
||||
}
|
||||
registerReceiver(receiver, filter)
|
||||
|
||||
changeState(State.CONNECTING)
|
||||
|
||||
spawn {
|
||||
Future {
|
||||
if (config.proxy == "198.199.101.152") {
|
||||
val holder = getApplication.asInstanceOf[ShadowsocksApplication].containerHolder
|
||||
try {
|
||||
@@ -237,8 +258,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
|
||||
// Resolve the server address
|
||||
var resolved: Boolean = false
|
||||
if (!InetAddressUtils.isIPv4Address(config.proxy) &&
|
||||
!InetAddressUtils.isIPv6Address(config.proxy)) {
|
||||
if (!Utils.isNumeric(config.proxy)) {
|
||||
Utils.resolve(config.proxy, enableIPv6 = true) match {
|
||||
case Some(addr) =>
|
||||
config.proxy = addr
|
||||
@@ -250,6 +270,8 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
}
|
||||
|
||||
if (resolved && handleConnection) {
|
||||
notifyForegroundAlert(getString(R.string.forward_success),
|
||||
getString(R.string.service_running).formatLocal(Locale.ENGLISH, config.profileName), false)
|
||||
changeState(State.CONNECTED)
|
||||
} else {
|
||||
changeState(State.STOPPED, getString(R.string.service_failed))
|
||||
@@ -296,18 +318,20 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
|
||||
val conf = ConfigUtils
|
||||
.SHADOWSOCKS.formatLocal(Locale.ENGLISH, config.proxy, config.remotePort, config.localPort,
|
||||
config.sitekey, config.encMethod, 10)
|
||||
config.sitekey, config.encMethod, 600)
|
||||
ConfigUtils.printToFile(new File(Path.BASE + "ss-local-vpn.conf"))(p => {
|
||||
p.println(conf)
|
||||
})
|
||||
|
||||
val cmd = new ArrayBuffer[String]
|
||||
cmd +=(Path.BASE + "ss-local", "-V", "-u"
|
||||
cmd += (Path.BASE + "ss-local", "-V", "-u"
|
||||
, "-b", "127.0.0.1"
|
||||
, "-t", "600"
|
||||
, "-c", Path.BASE + "ss-local-vpn.conf"
|
||||
, "-f", Path.BASE + "ss-local-vpn.pid")
|
||||
|
||||
if (config.isAuth) cmd += "-A"
|
||||
|
||||
if (config.route != Route.ALL) {
|
||||
cmd += "--acl"
|
||||
cmd += (Path.BASE + "acl.list")
|
||||
@@ -325,7 +349,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
p.println(conf)
|
||||
})
|
||||
val cmd = new ArrayBuffer[String]
|
||||
cmd +=(Path.BASE + "ss-tunnel"
|
||||
cmd += (Path.BASE + "ss-tunnel"
|
||||
, "-V"
|
||||
, "-u"
|
||||
, "-t", "10"
|
||||
@@ -335,20 +359,23 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
, "-c", Path.BASE + "ss-tunnel-vpn.conf"
|
||||
, "-f", Path.BASE + "ss-tunnel-vpn.pid")
|
||||
|
||||
if (config.isAuth) cmd += "-A"
|
||||
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" "))
|
||||
Console.runCommand(cmd.mkString(" "))
|
||||
}
|
||||
|
||||
def startDnsDaemon() {
|
||||
val ipv6 = if (config.isIpv6) "" else "reject = ::/0;"
|
||||
val conf = {
|
||||
if (config.route == Route.BYPASS_CHN) {
|
||||
val reject = ConfigUtils.getRejectList(getContext, application)
|
||||
val blackList = ConfigUtils.getBlackList(getContext, application)
|
||||
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, "0.0.0.0", 8153,
|
||||
Path.BASE + "pdnsd-vpn.pid", reject, blackList, 8163)
|
||||
Path.BASE + "pdnsd-vpn.pid", reject, blackList, 8163, ipv6)
|
||||
} else {
|
||||
ConfigUtils.PDNSD_LOCAL.formatLocal(Locale.ENGLISH, "0.0.0.0", 8153,
|
||||
Path.BASE + "pdnsd-vpn.pid", 8163)
|
||||
Path.BASE + "pdnsd-vpn.pid", 8163, ipv6)
|
||||
}
|
||||
}
|
||||
ConfigUtils.printToFile(new File(Path.BASE + "pdnsd-vpn.conf"))(p => {
|
||||
@@ -371,9 +398,12 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
.addAddress(PRIVATE_VLAN.formatLocal(Locale.ENGLISH, "1"), 24)
|
||||
.addDnsServer("8.8.8.8")
|
||||
|
||||
if (Utils.isLollipopOrAbove) {
|
||||
if (config.isIpv6) {
|
||||
builder.addAddress(PRIVATE_VLAN6.formatLocal(Locale.ENGLISH, "1"), 126)
|
||||
builder.addRoute("::", 0)
|
||||
}
|
||||
|
||||
builder.allowFamily(android.system.OsConstants.AF_INET6)
|
||||
if (Utils.isLollipopOrAbove) {
|
||||
|
||||
if (!config.isGlobalProxy) {
|
||||
val apps = AppManager.getProxiedApps(this, config.proxiedAppString)
|
||||
@@ -429,7 +459,12 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
+ "--tunmtu %d "
|
||||
+ "--loglevel 3 "
|
||||
+ "--pid %stun2socks-vpn.pid")
|
||||
.formatLocal(Locale.ENGLISH, PRIVATE_VLAN.formatLocal(Locale.ENGLISH, "2"), config.localPort, fd, VPN_MTU, Path.BASE)
|
||||
.formatLocal(Locale.ENGLISH,
|
||||
PRIVATE_VLAN.formatLocal(Locale.ENGLISH, "2"),
|
||||
config.localPort, fd, VPN_MTU, Path.BASE)
|
||||
|
||||
if (config.isIpv6)
|
||||
cmd += " --netif-ip6addr " + PRIVATE_VLAN6.formatLocal(Locale.ENGLISH, "2")
|
||||
|
||||
if (config.isUdpDns)
|
||||
cmd += " --enable-udprelay"
|
||||
@@ -440,7 +475,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
|
||||
Console.runCommand(cmd)
|
||||
|
||||
return fd
|
||||
fd
|
||||
}
|
||||
|
||||
override def stopBackgroundService() {
|
||||
|
||||
@@ -93,35 +93,34 @@ class ShadowsocksVpnThread(vpnService: ShadowsocksVpnService) extends Thread {
|
||||
try {
|
||||
val socket = serverSocket.accept()
|
||||
|
||||
pool.execute(new Runnable {
|
||||
override def run() {
|
||||
try {
|
||||
val input = socket.getInputStream
|
||||
val output = socket.getOutputStream
|
||||
pool.execute(() => {
|
||||
try {
|
||||
val input = socket.getInputStream
|
||||
val output = socket.getOutputStream
|
||||
|
||||
input.read()
|
||||
input.read()
|
||||
|
||||
val fds = socket.getAncillaryFileDescriptors
|
||||
val fds = socket.getAncillaryFileDescriptors
|
||||
|
||||
if (fds.length > 0) {
|
||||
var ret = false
|
||||
if (fds.nonEmpty) {
|
||||
var ret = false
|
||||
|
||||
val getInt = classOf[FileDescriptor].getDeclaredMethod("getInt$")
|
||||
val fd = getInt.invoke(fds(0)).asInstanceOf[Int]
|
||||
ret = vpnService.protect(fd)
|
||||
val getInt = classOf[FileDescriptor].getDeclaredMethod("getInt$")
|
||||
val fd = getInt.invoke(fds(0)).asInstanceOf[Int]
|
||||
ret = vpnService.protect(fd)
|
||||
|
||||
// Trick to close file decriptor
|
||||
System.jniclose(fd)
|
||||
// Trick to close file decriptor
|
||||
System.jniclose(fd)
|
||||
|
||||
if (ret) {
|
||||
output.write(0)
|
||||
} else {
|
||||
output.write(1)
|
||||
}
|
||||
|
||||
input.close()
|
||||
output.close()
|
||||
if (ret) {
|
||||
output.write(0)
|
||||
} else {
|
||||
output.write(1)
|
||||
}
|
||||
|
||||
input.close()
|
||||
output.close()
|
||||
}
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
Log.e(TAG, "Error when protect socket", e)
|
||||
@@ -134,12 +133,11 @@ class ShadowsocksVpnThread(vpnService: ShadowsocksVpnService) extends Thread {
|
||||
case _: Exception => // ignore
|
||||
}
|
||||
|
||||
}})
|
||||
})
|
||||
} catch {
|
||||
case e: IOException => {
|
||||
case e: IOException =>
|
||||
Log.e(TAG, "Error when accept socket", e)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ object DBHelper {
|
||||
}
|
||||
|
||||
class DBHelper(val context: Context)
|
||||
extends OrmLiteSqliteOpenHelper(context, DBHelper.PROFILE, null, 9) {
|
||||
extends OrmLiteSqliteOpenHelper(context, DBHelper.PROFILE, null, 11) {
|
||||
|
||||
lazy val profileDao: Dao[Profile, Int] = getDao(classOf[Profile])
|
||||
|
||||
@@ -62,14 +62,23 @@ class DBHelper(val context: Context)
|
||||
def onUpgrade(database: SQLiteDatabase, connectionSource: ConnectionSource, oldVersion: Int,
|
||||
newVersion: Int) {
|
||||
if (oldVersion != newVersion) {
|
||||
if (oldVersion < 8) {
|
||||
profileDao.executeRaw("ALTER TABLE `profile` ADD COLUMN udpdns SMALLINT;")
|
||||
profileDao.executeRaw("ALTER TABLE `profile` ADD COLUMN route VARCHAR;")
|
||||
} else if (oldVersion < 9) {
|
||||
profileDao.executeRaw("ALTER TABLE `profile` ADD COLUMN route VARCHAR;")
|
||||
} else {
|
||||
if (oldVersion < 7) {
|
||||
profileDao.executeRaw("DROP TABLE IF EXISTS 'profile';")
|
||||
onCreate(database, connectionSource)
|
||||
} else {
|
||||
if (oldVersion < 8) {
|
||||
profileDao.executeRaw("ALTER TABLE `profile` ADD COLUMN udpdns SMALLINT;")
|
||||
profileDao.executeRaw("ALTER TABLE `profile` ADD COLUMN route VARCHAR;")
|
||||
}
|
||||
if (oldVersion < 9) {
|
||||
profileDao.executeRaw("ALTER TABLE `profile` ADD COLUMN route VARCHAR;")
|
||||
}
|
||||
if (oldVersion < 10) {
|
||||
profileDao.executeRaw("ALTER TABLE `profile` ADD COLUMN auth SMALLINT;")
|
||||
}
|
||||
if (oldVersion < 11) {
|
||||
profileDao.executeRaw("ALTER TABLE `profile` ADD COLUMN ipv6 SMALLINT;")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,14 +40,10 @@
|
||||
package com.github.shadowsocks.database
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.BaseAdapter
|
||||
import android.widget.TextView
|
||||
import android.graphics.drawable.Drawable
|
||||
import com.github.shadowsocks.{R}
|
||||
import android.view.View.{OnLongClickListener, OnClickListener}
|
||||
import android.view.{LayoutInflater, View, ViewGroup}
|
||||
import android.widget.{BaseAdapter, TextView}
|
||||
import com.github.shadowsocks.R
|
||||
|
||||
abstract class Item {
|
||||
def id: Int
|
||||
@@ -147,17 +143,13 @@ class MenuAdapter(context: Context, var items: List[Any]) extends BaseAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
tv.setOnClickListener(new OnClickListener {
|
||||
def onClick(view: View) {
|
||||
val item = view.getTag(R.id.mdItem).asInstanceOf[Item]
|
||||
item.click(item.id)
|
||||
}
|
||||
tv.setOnClickListener((view: View) => {
|
||||
val item = view.getTag(R.id.mdItem).asInstanceOf[Item]
|
||||
item.click(item.id)
|
||||
})
|
||||
tv.setOnLongClickListener(new OnLongClickListener {
|
||||
def onLongClick(view: View): Boolean = {
|
||||
val item = view.getTag(R.id.mdItem).asInstanceOf[Item]
|
||||
item.longClick(item.id)
|
||||
}
|
||||
tv.setOnLongClickListener((view: View) => {
|
||||
val item = view.getTag(R.id.mdItem).asInstanceOf[Item]
|
||||
item.longClick(item.id)
|
||||
})
|
||||
|
||||
v.setTag(R.id.mdItem, value)
|
||||
|
||||
@@ -90,6 +90,12 @@ class Profile {
|
||||
@DatabaseField
|
||||
var udpdns: Boolean = false
|
||||
|
||||
@DatabaseField
|
||||
var auth: Boolean = false
|
||||
|
||||
@DatabaseField
|
||||
var ipv6: Boolean = false
|
||||
|
||||
@DatabaseField(dataType = DataType.LONG_STRING)
|
||||
var individual: String = ""
|
||||
|
||||
|
||||
@@ -39,9 +39,9 @@
|
||||
|
||||
package com.github.shadowsocks.database
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.util.Log
|
||||
import com.github.shadowsocks._
|
||||
import android.content.{SharedPreferences, Context}
|
||||
import com.github.shadowsocks.utils.Key
|
||||
|
||||
class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) {
|
||||
@@ -122,6 +122,8 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) {
|
||||
edit.putBoolean(Key.isBypassApps, profile.bypass)
|
||||
edit.putBoolean(Key.isTrafficStat, profile.traffic)
|
||||
edit.putBoolean(Key.isUdpDns, profile.udpdns)
|
||||
edit.putBoolean(Key.isAuth, profile.auth)
|
||||
edit.putBoolean(Key.isIpv6, profile.ipv6)
|
||||
edit.putString(Key.profileName, profile.name)
|
||||
edit.putString(Key.proxy, profile.host)
|
||||
edit.putString(Key.sitekey, profile.password)
|
||||
@@ -146,6 +148,8 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) {
|
||||
profile.bypass = settings.getBoolean(Key.isBypassApps, false)
|
||||
profile.traffic = settings.getBoolean(Key.isTrafficStat, false)
|
||||
profile.udpdns = settings.getBoolean(Key.isUdpDns, false)
|
||||
profile.auth = settings.getBoolean(Key.isAuth, false)
|
||||
profile.ipv6 = settings.getBoolean(Key.isIpv6, false)
|
||||
profile.name = settings.getString(Key.profileName, "default")
|
||||
profile.host = settings.getString(Key.proxy, "127.0.0.1")
|
||||
profile.password = settings.getString(Key.sitekey, "default")
|
||||
|
||||
@@ -82,7 +82,7 @@ object ConfigUtils {
|
||||
| label = "local";
|
||||
| ip = 127.0.0.1;
|
||||
| port = %d;
|
||||
| reject = ::/0;
|
||||
| %s
|
||||
| reject_policy = negate;
|
||||
| reject_recursively = on;
|
||||
| timeout = 5;
|
||||
@@ -174,7 +174,9 @@ object ConfigUtils {
|
||||
| label = "local-server";
|
||||
| ip = 127.0.0.1;
|
||||
| port = %d;
|
||||
| timeout = 3;
|
||||
| %s
|
||||
| reject_policy = negate;
|
||||
| reject_recursively = on;
|
||||
|}
|
||||
|
|
||||
|rr {
|
||||
@@ -231,8 +233,8 @@ object ConfigUtils {
|
||||
.readTimeout(2000)
|
||||
.send("sig="+sig)
|
||||
.body
|
||||
val proxies = util.Random.shuffle(list.split('|').toSeq).toSeq
|
||||
val proxy = proxies(0).split(':')
|
||||
val proxies = util.Random.shuffle(list.split('|').toSeq)
|
||||
val proxy = proxies.head.split(':')
|
||||
|
||||
val host = proxy(0).trim
|
||||
val port = proxy(1).trim.toInt
|
||||
@@ -240,7 +242,7 @@ object ConfigUtils {
|
||||
val method = proxy(3).trim
|
||||
|
||||
new Config(config.isGlobalProxy, config.isGFWList, config.isBypassApps, config.isTrafficStat,
|
||||
config.isUdpDns, config.profileName, host, password, method, config.proxiedAppString, config.route, port,
|
||||
config.isUdpDns, config.isAuth, config.isIpv6, config.profileName, host, password, method, config.proxiedAppString, config.route, port,
|
||||
config.localPort)
|
||||
}
|
||||
|
||||
@@ -250,6 +252,8 @@ object ConfigUtils {
|
||||
val isBypassApps = settings.getBoolean(Key.isBypassApps, false)
|
||||
val isTrafficStat = settings.getBoolean(Key.isTrafficStat, false)
|
||||
val isUdpDns = settings.getBoolean(Key.isUdpDns, false)
|
||||
val isAuth = settings.getBoolean(Key.isAuth, false)
|
||||
val isIpv6 = settings.getBoolean(Key.isIpv6, false)
|
||||
|
||||
val profileName = settings.getString(Key.profileName, "default")
|
||||
val proxy = settings.getString(Key.proxy, "127.0.0.1")
|
||||
@@ -271,7 +275,7 @@ object ConfigUtils {
|
||||
}
|
||||
val proxiedAppString = settings.getString(Key.proxied, "")
|
||||
|
||||
new Config(isGlobalProxy, isGFWList, isBypassApps, isTrafficStat, isUdpDns, profileName, proxy,
|
||||
new Config(isGlobalProxy, isGFWList, isBypassApps, isTrafficStat, isUdpDns, isAuth, isIpv6, profileName, proxy,
|
||||
sitekey, encMethod, proxiedAppString, route, remotePort, localPort)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,10 +39,11 @@
|
||||
|
||||
package com.github.shadowsocks.utils
|
||||
|
||||
import eu.chainfire.libsuperuser.Shell
|
||||
import eu.chainfire.libsuperuser.Shell.{OnCommandResultListener, SU, Builder}
|
||||
import java.util
|
||||
|
||||
import eu.chainfire.libsuperuser.Shell
|
||||
import eu.chainfire.libsuperuser.Shell.{Builder, SU}
|
||||
|
||||
object Console {
|
||||
|
||||
private def openShell(): Shell.Interactive = {
|
||||
@@ -68,14 +69,8 @@ object Console {
|
||||
|
||||
def runCommand(commands: Array[String]) {
|
||||
val shell = openShell()
|
||||
shell.addCommand(commands, 0, new OnCommandResultListener {
|
||||
override def onCommandResult(commandCode: Int, exitCode: Int,
|
||||
output: util.List[String]) {
|
||||
if (exitCode < 0) {
|
||||
shell.close()
|
||||
}
|
||||
}
|
||||
})
|
||||
shell.addCommand(commands, 0, ((commandCode: Int, exitCode: Int, output: util.List[String]) =>
|
||||
if (exitCode < 0) shell.close()): Shell.OnCommandResultListener)
|
||||
shell.waitForIdle()
|
||||
shell.close()
|
||||
}
|
||||
@@ -90,17 +85,14 @@ object Console {
|
||||
}
|
||||
val shell = openRootShell(context)
|
||||
val sb = new StringBuilder
|
||||
shell.addCommand(commands, 0, new OnCommandResultListener {
|
||||
override def onCommandResult(commandCode: Int, exitCode: Int,
|
||||
output: util.List[String]) {
|
||||
if (exitCode < 0) {
|
||||
shell.close()
|
||||
} else {
|
||||
import scala.collection.JavaConversions._
|
||||
output.foreach(line => sb.append(line).append('\n'))
|
||||
}
|
||||
shell.addCommand(commands, 0, ((commandCode: Int, exitCode: Int, output: util.List[String]) => {
|
||||
if (exitCode < 0) {
|
||||
shell.close()
|
||||
} else {
|
||||
import scala.collection.JavaConversions._
|
||||
output.foreach(line => sb.append(line).append('\n'))
|
||||
}
|
||||
})
|
||||
}): Shell.OnCommandResultListener)
|
||||
if (shell.waitForIdle()) {
|
||||
shell.close()
|
||||
sb.toString()
|
||||
|
||||
@@ -79,6 +79,8 @@ object Key {
|
||||
val isBypassApps = "isBypassApps"
|
||||
val isTrafficStat = "isTrafficStat"
|
||||
val isUdpDns = "isUdpDns"
|
||||
val isAuth= "isAuth"
|
||||
val isIpv6= "isIpv6"
|
||||
|
||||
val proxy = "proxy"
|
||||
val sitekey = "sitekey"
|
||||
|
||||
@@ -47,11 +47,8 @@ import android.util.{Log, Base64}
|
||||
object Parser {
|
||||
val TAG = "ShadowParser"
|
||||
|
||||
def generate (profile: Profile): String = {
|
||||
val path = "%s:%s@%s:%d".formatLocal(Locale.ENGLISH,
|
||||
profile.method, profile.password, profile.host, profile.remotePort)
|
||||
return "ss://" + Base64.encodeToString(path.getBytes, Base64.NO_PADDING)
|
||||
}
|
||||
def generate (profile: Profile): String = "ss://" + Base64.encodeToString("%s:%s@%s:%d".formatLocal(Locale.ENGLISH,
|
||||
profile.method, profile.password, profile.host, profile.remotePort).getBytes, Base64.NO_PADDING)
|
||||
|
||||
def parse (data: String): Option[Profile] = {
|
||||
try {
|
||||
|
||||
@@ -38,22 +38,21 @@
|
||||
*/
|
||||
package com.github.shadowsocks.utils
|
||||
|
||||
import android.content.{Intent, Context}
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.drawable.{BitmapDrawable, Drawable}
|
||||
import android.util.{Base64, Log}
|
||||
import java.io._
|
||||
import java.net.{UnknownHostException, InetAddress, NetworkInterface}
|
||||
import org.apache.http.conn.util.InetAddressUtils
|
||||
import org.xbill.DNS._
|
||||
import android.graphics._
|
||||
import java.net._
|
||||
import java.security.MessageDigest
|
||||
|
||||
import android.app.ActivityManager
|
||||
import android.content.pm.{ApplicationInfo, PackageManager}
|
||||
import android.content.{Context, Intent}
|
||||
import android.graphics._
|
||||
import android.graphics.drawable.{BitmapDrawable, Drawable}
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import scala.Some
|
||||
import java.security.MessageDigest
|
||||
import com.github.shadowsocks.{BuildConfig}
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.util.{Base64, Log}
|
||||
import com.github.shadowsocks.BuildConfig
|
||||
import org.xbill.DNS._
|
||||
|
||||
|
||||
object Utils {
|
||||
@@ -147,6 +146,7 @@ object Utils {
|
||||
// + "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false\n")
|
||||
}
|
||||
|
||||
//noinspection ScalaDeprecation
|
||||
private def toggleBelowApiLevel17(context: Context) {
|
||||
// Android 4.2 below
|
||||
Settings.System.putInt(context.getContentResolver, Settings.System.AIRPLANE_MODE_ON, 1)
|
||||
@@ -198,7 +198,7 @@ object Utils {
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
case e: Exception => None
|
||||
case e: Exception =>
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -233,6 +233,9 @@ object Utils {
|
||||
None
|
||||
}
|
||||
|
||||
private lazy val isNumericMethod = classOf[InetAddress].getMethod("isNumeric", classOf[String])
|
||||
def isNumeric(address: String): Boolean = isNumericMethod.invoke(null, address).asInstanceOf[Boolean]
|
||||
|
||||
/**
|
||||
* Get local IPv4 address
|
||||
*/
|
||||
@@ -245,9 +248,8 @@ object Utils {
|
||||
while (addrs.hasMoreElements) {
|
||||
val addr = addrs.nextElement()
|
||||
if (!addr.isLoopbackAddress && !addr.isLinkLocalAddress) {
|
||||
val sAddr = addr.getHostAddress.toUpperCase
|
||||
if (InetAddressUtils.isIPv4Address(sAddr)) {
|
||||
return Some(sAddr)
|
||||
if (addr.isInstanceOf[Inet4Address]) {
|
||||
return Some(addr.getHostAddress.toUpperCase)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -271,8 +273,7 @@ object Utils {
|
||||
while (addrs.hasMoreElements) {
|
||||
val addr = addrs.nextElement()
|
||||
if (!addr.isLoopbackAddress && !addr.isLinkLocalAddress) {
|
||||
val sAddr = addr.getHostAddress.toUpperCase
|
||||
if (InetAddressUtils.isIPv6Address(sAddr)) {
|
||||
if (addr.isInstanceOf[Inet6Address]) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "IPv6 address detected")
|
||||
return true
|
||||
}
|
||||
@@ -338,7 +339,7 @@ object Utils {
|
||||
|
||||
def getAppIcon(c: Context, packageName: String): Drawable = {
|
||||
val pm: PackageManager = c.getPackageManager
|
||||
val icon: Drawable = c.getResources.getDrawable(android.R.drawable.sym_def_app_icon)
|
||||
val icon: Drawable = ContextCompat.getDrawable(c, android.R.drawable.sym_def_app_icon)
|
||||
try {
|
||||
pm.getApplicationIcon(packageName)
|
||||
} catch {
|
||||
@@ -348,7 +349,7 @@ object Utils {
|
||||
|
||||
def getAppIcon(c: Context, uid: Int): Drawable = {
|
||||
val pm: PackageManager = c.getPackageManager
|
||||
val icon: Drawable = c.getResources.getDrawable(android.R.drawable.sym_def_app_icon)
|
||||
val icon: Drawable = ContextCompat.getDrawable(c, android.R.drawable.sym_def_app_icon)
|
||||
val packages: Array[String] = pm.getPackagesForUid(uid)
|
||||
if (packages != null) {
|
||||
if (packages.length >= 1) {
|
||||
|
||||
Reference in New Issue
Block a user