diff --git a/src/main/aidl/com/github/shadowsocks/aidl/Config.java b/src/main/aidl/com/github/shadowsocks/aidl/Config.java
index cade941d..08f34367 100644
--- a/src/main/aidl/com/github/shadowsocks/aidl/Config.java
+++ b/src/main/aidl/com/github/shadowsocks/aidl/Config.java
@@ -11,6 +11,7 @@ public class Config implements Parcelable {
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";
@@ -34,7 +35,7 @@ public class Config implements Parcelable {
};
public Config(boolean isGlobalProxy, boolean isGFWList, boolean isBypassApps,
- boolean isTrafficStat, boolean isUdpDns, boolean isAuth, 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;
@@ -42,6 +43,7 @@ public class Config implements Parcelable {
this.isTrafficStat = isTrafficStat;
this.isUdpDns = isUdpDns;
this.isAuth = isAuth;
+ this.isIpv6 = isIpv6;
this.profileName = profileName;
this.proxy = proxy;
this.sitekey = sitekey;
@@ -63,6 +65,7 @@ public class Config implements Parcelable {
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();
@@ -84,6 +87,7 @@ public class Config implements Parcelable {
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);
diff --git a/src/main/res/values-zh/strings.xml b/src/main/res/values-zh/strings.xml
index 37e343cb..c9457d6f 100755
--- a/src/main/res/values-zh/strings.xml
+++ b/src/main/res/values-zh/strings.xml
@@ -80,6 +80,9 @@
一次性认证
启用一次性认证(实验性)
+ IPv6 路由
+ 向远程服务器转发 IPv6 流量
+
为影梭添加此配置文件?
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 4120a152..04dc3487 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -25,12 +25,14 @@
Feature Settings
+ IPv6 Route
+ Redirect IPv6 traffic to remote
One-time Authentication
Enable one-time authentication (Experimental)
HTTP Proxy
Local HTTP Proxy
DNS Proxy
- Redirect DNS queries to remote server
+ Redirect DNS queries to remote
CHN Route
Bypass all sites located in China
diff --git a/src/main/res/xml/pref_all.xml b/src/main/res/xml/pref_all.xml
index e9085e50..f6471c9a 100644
--- a/src/main/res/xml/pref_all.xml
+++ b/src/main/res/xml/pref_all.xml
@@ -58,6 +58,12 @@
android:summary="@string/route_list_summary"
android:title="@string/route_list">
+
+
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 _ =>
}
}
diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala
index 68dc32b8..d950f395 100644
--- a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala
+++ b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala
@@ -271,10 +271,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 => {
diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala
index 2e1b3cfc..2714ae35 100644
--- a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala
+++ b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala
@@ -65,6 +65,7 @@ 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
@@ -344,15 +345,16 @@ class ShadowsocksVpnService extends VpnService with BaseService {
}
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 => {
@@ -375,9 +377,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)
@@ -433,7 +438,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"
diff --git a/src/main/scala/com/github/shadowsocks/database/DBHelper.scala b/src/main/scala/com/github/shadowsocks/database/DBHelper.scala
index fd08afb8..3943e600 100644
--- a/src/main/scala/com/github/shadowsocks/database/DBHelper.scala
+++ b/src/main/scala/com/github/shadowsocks/database/DBHelper.scala
@@ -51,7 +51,7 @@ object DBHelper {
}
class DBHelper(val context: Context)
- extends OrmLiteSqliteOpenHelper(context, DBHelper.PROFILE, null, 10) {
+ extends OrmLiteSqliteOpenHelper(context, DBHelper.PROFILE, null, 11) {
lazy val profileDao: Dao[Profile, Int] = getDao(classOf[Profile])
@@ -69,6 +69,8 @@ class DBHelper(val context: Context)
profileDao.executeRaw("ALTER TABLE `profile` ADD COLUMN route VARCHAR;")
} else if (oldVersion < 10) {
profileDao.executeRaw("ALTER TABLE `profile` ADD COLUMN auth SMALLINT;")
+ } else if (oldVersion < 11) {
+ profileDao.executeRaw("ALTER TABLE `profile` ADD COLUMN ipv6 SMALLINT;")
} else {
profileDao.executeRaw("DROP TABLE IF EXISTS 'profile';")
onCreate(database, connectionSource)
diff --git a/src/main/scala/com/github/shadowsocks/database/Profile.scala b/src/main/scala/com/github/shadowsocks/database/Profile.scala
index 4b444d26..19d48932 100644
--- a/src/main/scala/com/github/shadowsocks/database/Profile.scala
+++ b/src/main/scala/com/github/shadowsocks/database/Profile.scala
@@ -93,6 +93,9 @@ class Profile {
@DatabaseField
var auth: Boolean = false
+ @DatabaseField
+ var ipv6: Boolean = false
+
@DatabaseField(dataType = DataType.LONG_STRING)
var individual: String = ""
diff --git a/src/main/scala/com/github/shadowsocks/database/ProfileManager.scala b/src/main/scala/com/github/shadowsocks/database/ProfileManager.scala
index f70973f9..e792786f 100644
--- a/src/main/scala/com/github/shadowsocks/database/ProfileManager.scala
+++ b/src/main/scala/com/github/shadowsocks/database/ProfileManager.scala
@@ -123,6 +123,7 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) {
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)
@@ -148,6 +149,7 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) {
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")
diff --git a/src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala b/src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala
index 57319974..4de1efa5 100644
--- a/src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala
+++ b/src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala
@@ -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,7 @@ object ConfigUtils {
| label = "local-server";
| ip = 127.0.0.1;
| port = %d;
- | reject = ::/0;
+ | %s
| reject_policy = negate;
| reject_recursively = on;
|}
@@ -242,7 +242,7 @@ object ConfigUtils {
val method = proxy(3).trim
new Config(config.isGlobalProxy, config.isGFWList, config.isBypassApps, config.isTrafficStat,
- config.isUdpDns, config.isAuth, 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)
}
@@ -253,6 +253,7 @@ object ConfigUtils {
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")
@@ -274,7 +275,7 @@ object ConfigUtils {
}
val proxiedAppString = settings.getString(Key.proxied, "")
- new Config(isGlobalProxy, isGFWList, isBypassApps, isTrafficStat, isUdpDns, isAuth, profileName, proxy,
+ new Config(isGlobalProxy, isGFWList, isBypassApps, isTrafficStat, isUdpDns, isAuth, isIpv6, profileName, proxy,
sitekey, encMethod, proxiedAppString, route, remotePort, localPort)
}
}
diff --git a/src/main/scala/com/github/shadowsocks/utils/Constants.scala b/src/main/scala/com/github/shadowsocks/utils/Constants.scala
index 389c3d66..83ab3cfb 100644
--- a/src/main/scala/com/github/shadowsocks/utils/Constants.scala
+++ b/src/main/scala/com/github/shadowsocks/utils/Constants.scala
@@ -80,6 +80,7 @@ object Key {
val isTrafficStat = "isTrafficStat"
val isUdpDns = "isUdpDns"
val isAuth= "isAuth"
+ val isIpv6= "isIpv6"
val proxy = "proxy"
val sitekey = "sitekey"