diff --git a/core/src/main/java/com/github/shadowsocks/bg/ProxyInstance.kt b/core/src/main/java/com/github/shadowsocks/bg/ProxyInstance.kt
index 4882a3fe58..c032df80e2 100644
--- a/core/src/main/java/com/github/shadowsocks/bg/ProxyInstance.kt
+++ b/core/src/main/java/com/github/shadowsocks/bg/ProxyInstance.kt
@@ -64,6 +64,7 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
}
private var configFile: File? = null
+ private var socks5AuthFile: File? = null
var trafficMonitor: TrafficMonitor? = null
val plugin by lazy { PluginManager.init(PluginConfiguration(profile.plugin ?: "")) }
@@ -86,6 +87,7 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
}
config.put("dns", "unix://local_dns_path")
config.put("mode", mode)
+ val socksPassword = DataStore.socksPassword
config.put("locals", JSONArray().apply {
// local SOCKS5 proxy
put(JSONObject().apply {
@@ -94,6 +96,7 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
put("local_udp_address", DataStore.listenAddress)
put("local_udp_port", DataStore.portProxy)
put("mode", mode)
+ if (socksPassword.isNotEmpty()) put("socks5_auth_config_path", "socks5_auth")
})
// local DNS proxy
@@ -114,6 +117,22 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
})
configFile.writeText(config.toString())
+ // write SOCKS5 auth config file if password protection is enabled
+ if (socksPassword.isNotEmpty()) {
+ val authFile = File(configFile.parentFile ?: configFile.canonicalFile.parentFile, "socks5_auth")
+ socks5AuthFile = authFile
+ authFile.writeText(JSONObject().apply {
+ put("password", JSONObject().apply {
+ put("users", JSONArray().apply {
+ put(JSONObject().apply {
+ put("user_name", "shadowsocks")
+ put("password", socksPassword)
+ })
+ })
+ })
+ }.toString())
+ }
+
// build the command line
val cmd = arrayListOf(
File((service as Context).applicationInfo.nativeLibraryDir, Executable.SS_LOCAL).absolutePath,
@@ -143,5 +162,7 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
trafficMonitor = null
configFile?.delete() // remove old config possibly in device storage
configFile = null
+ socks5AuthFile?.delete()
+ socks5AuthFile = null
}
}
diff --git a/core/src/main/java/com/github/shadowsocks/bg/VpnService.kt b/core/src/main/java/com/github/shadowsocks/bg/VpnService.kt
index 5716d1fc09..17c58d7020 100644
--- a/core/src/main/java/com/github/shadowsocks/bg/VpnService.kt
+++ b/core/src/main/java/com/github/shadowsocks/bg/VpnService.kt
@@ -214,6 +214,13 @@ class VpnService : BaseVpnService(), BaseService.Interface {
"--sock-path", "sock_path",
"--dnsgw", "127.0.0.1:${DataStore.portLocalDns}",
"--loglevel", "warning")
+ val socksPassword = DataStore.socksPassword
+ if (socksPassword.isNotEmpty()) {
+ cmd += "--username"
+ cmd += "shadowsocks"
+ cmd += "--password"
+ cmd += socksPassword
+ }
if (profile.ipv6) {
cmd += "--netif-ip6addr"
cmd += PRIVATE_VLAN6_ROUTER
diff --git a/core/src/main/java/com/github/shadowsocks/preference/DataStore.kt b/core/src/main/java/com/github/shadowsocks/preference/DataStore.kt
index 5f3a772bf4..44dac24343 100644
--- a/core/src/main/java/com/github/shadowsocks/preference/DataStore.kt
+++ b/core/src/main/java/com/github/shadowsocks/preference/DataStore.kt
@@ -76,6 +76,9 @@ object DataStore : OnPreferenceDataStoreChangeListener {
var portTransproxy: Int
get() = getLocalPort(Key.portTransproxy, 8200)
set(value) = publicStore.putString(Key.portTransproxy, value.toString())
+ var socksPassword: String
+ get() = publicStore.getString(Key.socksPassword) ?: ""
+ set(value) = publicStore.putString(Key.socksPassword, value)
/**
* Initialize settings that have complicated default values.
diff --git a/core/src/main/java/com/github/shadowsocks/utils/Constants.kt b/core/src/main/java/com/github/shadowsocks/utils/Constants.kt
index 52b6de20ec..0644672ad3 100644
--- a/core/src/main/java/com/github/shadowsocks/utils/Constants.kt
+++ b/core/src/main/java/com/github/shadowsocks/utils/Constants.kt
@@ -40,6 +40,7 @@ object Key {
const val portProxy = "portProxy"
const val portLocalDns = "portLocalDns"
const val portTransproxy = "portTransproxy"
+ const val socksPassword = "socksPassword"
const val route = "route"
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index 04ed7d9d67..87071c002e 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -14,6 +14,8 @@
SOCKS5 proxy port
Local DNS port
Transproxy port
+ SOCKS5 proxy password
+ Set a password to protect the local SOCKS5 proxy from unauthorized use
Remote DNS
%1$s↑\t%2$s↓
diff --git a/mobile/src/main/java/com/github/shadowsocks/GlobalSettingsPreferenceFragment.kt b/mobile/src/main/java/com/github/shadowsocks/GlobalSettingsPreferenceFragment.kt
index cc7ac91647..2b503a6696 100644
--- a/mobile/src/main/java/com/github/shadowsocks/GlobalSettingsPreferenceFragment.kt
+++ b/mobile/src/main/java/com/github/shadowsocks/GlobalSettingsPreferenceFragment.kt
@@ -59,6 +59,7 @@ class GlobalSettingsPreferenceFragment : PreferenceFragmentCompat() {
portLocalDns.setOnBindEditTextListener(EditTextPreferenceModifiers.Port)
val portTransproxy = findPreference(Key.portTransproxy)!!
portTransproxy.setOnBindEditTextListener(EditTextPreferenceModifiers.Port)
+ val socksPassword = findPreference(Key.socksPassword)!!
val onServiceModeChange = Preference.OnPreferenceChangeListener { _, newValue ->
portTransproxy.isEnabled = newValue as String? == Key.modeTransproxy
true
@@ -68,6 +69,7 @@ class GlobalSettingsPreferenceFragment : PreferenceFragmentCompat() {
serviceMode.isEnabled = stopped
portProxy.isEnabled = stopped
portLocalDns.isEnabled = stopped
+ socksPassword.isEnabled = stopped
if (stopped) onServiceModeChange.onPreferenceChange(serviceMode, DataStore.serviceMode) else {
portTransproxy.isEnabled = false
}
diff --git a/mobile/src/main/res/xml/pref_global.xml b/mobile/src/main/res/xml/pref_global.xml
index 9a4808d8b3..29b3369332 100644
--- a/mobile/src/main/res/xml/pref_global.xml
+++ b/mobile/src/main/res/xml/pref_global.xml
@@ -34,4 +34,10 @@
app:key="portTransproxy"
app:title="@string/port_transproxy"
app:useSimpleSummaryProvider="true"/>
+
diff --git a/tv/src/main/java/com/github/shadowsocks/tv/MainPreferenceFragment.kt b/tv/src/main/java/com/github/shadowsocks/tv/MainPreferenceFragment.kt
index 198245f728..46a26c548a 100644
--- a/tv/src/main/java/com/github/shadowsocks/tv/MainPreferenceFragment.kt
+++ b/tv/src/main/java/com/github/shadowsocks/tv/MainPreferenceFragment.kt
@@ -56,6 +56,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
private lateinit var portProxy: EditTextPreference
private lateinit var portLocalDns: EditTextPreference
private lateinit var portTransproxy: EditTextPreference
+ private lateinit var socksPassword: EditTextPreference
private val onServiceModeChange = Preference.OnPreferenceChangeListener { _, newValue ->
portTransproxy.isEnabled = newValue as String? == Key.modeTransproxy
true
@@ -101,6 +102,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
shareOverLan.isEnabled = stopped
portProxy.isEnabled = stopped
portLocalDns.isEnabled = stopped
+ socksPassword.isEnabled = stopped
if (stopped) onServiceModeChange.onPreferenceChange(serviceMode, DataStore.serviceMode) else {
portTransproxy.isEnabled = false
}
@@ -141,6 +143,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragmentCompat(), ShadowsocksCo
portLocalDns.setOnBindEditTextListener(EditTextPreferenceModifiers.Port)
portTransproxy = findPreference(Key.portTransproxy)!!
portTransproxy.setOnBindEditTextListener(EditTextPreferenceModifiers.Port)
+ socksPassword = findPreference(Key.socksPassword)!!
serviceMode.onPreferenceChangeListener = onServiceModeChange
findPreference(Key.about)!!.summary = getString(R.string.about_title, BuildConfig.VERSION_NAME)
diff --git a/tv/src/main/res/xml/pref_main.xml b/tv/src/main/res/xml/pref_main.xml
index 1e60152712..67e8dc963d 100644
--- a/tv/src/main/res/xml/pref_main.xml
+++ b/tv/src/main/res/xml/pref_main.xml
@@ -48,6 +48,11 @@
app:key="portTransproxy"
app:title="@string/port_transproxy"
app:useSimpleSummaryProvider="true"/>
+